1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3 /* GIO - GLib Input, Output and Streaming Library
5 * Copyright (C) 2006-2007 Red Hat, Inc.
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.
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.
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.
22 * Author: Alexander Larsson <alexl@redhat.com>
26 #include <sys/types.h>
30 #include "gcontenttypeprivate.h"
31 #include "gthemedicon.h"
34 #include "gfileenumerator.h"
35 #include "gfileinfo.h"
40 * SECTION:gcontenttype
41 * @short_description: Platform-specific content typing
44 * A content type is a platform specific string that defines the type
45 * of a file. On UNIX it is a <ulink url="http://www.wikipedia.org/wiki/Internet_media_type">mime type</ulink> like "text/plain" or "image/png".
46 * On Win32 it is an extension string like ".doc", ".txt" or a perceived
47 * string like "audio". Such strings can be looked up in the registry at
56 get_registry_classes_key (const char *subdir
,
57 const wchar_t *key_name
)
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
, ®_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
))
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
)
82 int len
= ExpandEnvironmentStringsW (wc_temp
, dummy
, 1);
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
);
93 value_utf8
= g_utf16_to_utf8 (wc_temp
, -1, NULL
, NULL
, NULL
);
101 RegCloseKey (reg_key
);
107 g_content_type_equals (const gchar
*type1
,
110 char *progid1
, *progid2
;
113 g_return_val_if_fail (type1
!= NULL
, FALSE
);
114 g_return_val_if_fail (type2
!= NULL
, FALSE
);
116 if (g_ascii_strcasecmp (type1
, type2
) == 0)
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)
132 g_content_type_is_a (const gchar
*type
,
133 const gchar
*supertype
)
138 g_return_val_if_fail (type
!= NULL
, FALSE
);
139 g_return_val_if_fail (supertype
!= NULL
, FALSE
);
141 if (g_content_type_equals (type
, supertype
))
145 value_utf8
= get_registry_classes_key (type
, L
"PerceivedType");
146 if (value_utf8
&& strcmp (value_utf8
, supertype
) == 0)
154 g_content_type_is_unknown (const gchar
*type
)
156 g_return_val_if_fail (type
!= NULL
, FALSE
);
158 return strcmp ("*", type
) == 0;
162 g_content_type_get_description (const gchar
*type
)
167 g_return_val_if_fail (type
!= NULL
, NULL
);
169 progid
= get_registry_classes_key (type
, NULL
);
172 description
= get_registry_classes_key (progid
, NULL
);
179 if (g_content_type_is_unknown (type
))
180 return g_strdup (_("Unknown type"));
181 return g_strdup_printf (_("%s filetype"), type
);
185 g_content_type_get_mime_type (const gchar
*type
)
189 g_return_val_if_fail (type
!= NULL
, NULL
);
191 mime
= get_registry_classes_key (type
, L
"Content Type");
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? */
200 return g_strdup ("application/octet-stream");
203 G_LOCK_DEFINE_STATIC (_type_icons
);
204 static GHashTable
*_type_icons
= NULL
;
207 g_content_type_get_icon (const gchar
*type
)
212 g_return_val_if_fail (type
!= NULL
, NULL
);
214 /* In the Registry icons are the default value of
215 HKEY_CLASSES_ROOT\<progid>\DefaultIcon with typical values like:
217 REG_EXPAND_SZ: %SystemRoot%\System32\Wscript.exe,3
218 REG_SZ: shimgvw.dll,3
220 G_LOCK (_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] == '.')
226 /* double lookup by extension */
227 gchar
*key
= get_registry_classes_key (type
, NULL
);
229 key
= g_strconcat (type
+1, "file\\DefaultIcon", NULL
);
232 gchar
*key2
= g_strconcat (key
, "\\DefaultIcon", NULL
);
236 name
= get_registry_classes_key (key
, NULL
);
237 if (name
&& strcmp (name
, "%1") == 0)
243 g_hash_table_insert (_type_icons
, g_strdup (type
), g_strdup (name
));
247 /* icon-name similar to how it was with gtk-2-12 */
250 themed_icon
= g_themed_icon_new (name
);
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
);
260 G_UNLOCK (_type_icons
);
262 return G_ICON (themed_icon
);
266 g_content_type_can_be_executable (const gchar
*type
)
268 g_return_val_if_fail (type
!= NULL
, FALSE
);
270 if (strcmp (type
, ".exe") == 0 ||
271 strcmp (type
, ".com") == 0 ||
272 strcmp (type
, ".bat") == 0)
275 /* TODO: Also look at PATHEXT, which lists the extensions for
276 * "scripts" in addition to those for true binary executables.
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
290 looks_like_text (const guchar
*data
,
295 for (i
= 0; i
< data_size
; i
++)
298 if (g_ascii_iscntrl (c
) && !g_ascii_isspace (c
) && c
!= '\b')
305 g_content_type_from_mime_type (const gchar
*mime_type
)
307 char *key
, *content_type
;
309 g_return_val_if_fail (mime_type
!= NULL
, NULL
);
311 key
= g_strconcat ("MIME\\DataBase\\Content Type\\", mime_type
, NULL
);
312 content_type
= get_registry_classes_key (key
, L
"Extension");
319 g_content_type_guess (const gchar
*filename
,
322 gboolean
*result_uncertain
)
330 if (result_uncertain
)
331 *result_uncertain
= FALSE
;
335 basename
= g_path_get_basename (filename
);
336 dot
= strrchr (basename
, '.');
338 type
= g_strdup (dot
);
345 if (data
&& looks_like_text (data
, data_size
))
346 return g_strdup (".txt");
348 return g_strdup ("*");
352 g_content_types_get_registered (void)
355 wchar_t keyname
[256];
363 while (RegEnumKeyExW(HKEY_CLASSES_ROOT
,
370 NULL
) == ERROR_SUCCESS
)
372 key_utf8
= g_utf16_to_utf8 (keyname
, -1, NULL
, NULL
, NULL
);
375 if (*key_utf8
== '.')
376 types
= g_list_prepend (types
, key_utf8
);
384 return g_list_reverse (types
);
388 g_content_type_guess_for_tree (GFile
*root
)
390 /* FIXME: implement */
394 #else /* !G_OS_WIN32 - Unix specific version */
398 #define XDG_PREFIX _gio_xdg
399 #include "xdgmime/xdgmime.h"
401 /* We lock this mutex whenever we modify global state in this module. */
402 G_LOCK_DEFINE_STATIC (gio_xdgmime
);
405 _g_unix_content_type_get_sniff_len (void)
409 G_LOCK (gio_xdgmime
);
410 size
= xdg_mime_get_max_buffer_extents ();
411 G_UNLOCK (gio_xdgmime
);
417 _g_unix_content_type_unalias (const gchar
*type
)
421 G_LOCK (gio_xdgmime
);
422 res
= g_strdup (xdg_mime_unalias_mime_type (type
));
423 G_UNLOCK (gio_xdgmime
);
429 _g_unix_content_type_get_parents (const gchar
*type
)
436 array
= g_ptr_array_new ();
438 G_LOCK (gio_xdgmime
);
440 umime
= xdg_mime_unalias_mime_type (type
);
442 g_ptr_array_add (array
, g_strdup (umime
));
444 parents
= xdg_mime_list_mime_parents (umime
);
445 for (i
= 0; parents
&& parents
[i
] != NULL
; i
++)
446 g_ptr_array_add (array
, g_strdup (parents
[i
]));
450 G_UNLOCK (gio_xdgmime
);
452 g_ptr_array_add (array
, NULL
);
454 return (gchar
**)g_ptr_array_free (array
, FALSE
);
458 * g_content_type_equals:
459 * @type1: a content type string
460 * @type2: a content type string
462 * Compares two content types for equality.
464 * Returns: %TRUE if the two strings are identical or equivalent,
468 g_content_type_equals (const gchar
*type1
,
473 g_return_val_if_fail (type1
!= NULL
, FALSE
);
474 g_return_val_if_fail (type2
!= NULL
, FALSE
);
476 G_LOCK (gio_xdgmime
);
477 res
= xdg_mime_mime_type_equal (type1
, type2
);
478 G_UNLOCK (gio_xdgmime
);
484 * g_content_type_is_a:
485 * @type: a content type string
486 * @supertype: a content type string
488 * Determines if @type is a subset of @supertype.
490 * Returns: %TRUE if @type is a kind of @supertype,
494 g_content_type_is_a (const gchar
*type
,
495 const gchar
*supertype
)
499 g_return_val_if_fail (type
!= NULL
, FALSE
);
500 g_return_val_if_fail (supertype
!= NULL
, FALSE
);
502 G_LOCK (gio_xdgmime
);
503 res
= xdg_mime_mime_type_subclass (type
, supertype
);
504 G_UNLOCK (gio_xdgmime
);
510 * g_content_type_is_unknown:
511 * @type: a content type string
513 * Checks if the content type is the generic "unknown" type.
514 * On UNIX this is the "application/octet-stream" mimetype,
515 * while on win32 it is "*".
517 * Returns: %TRUE if the type is the unknown type.
520 g_content_type_is_unknown (const gchar
*type
)
522 g_return_val_if_fail (type
!= NULL
, FALSE
);
524 return strcmp (XDG_MIME_TYPE_UNKNOWN
, type
) == 0;
530 MIME_TAG_TYPE_COMMENT
535 int current_lang_level
;
536 int comment_lang_level
;
542 language_level (const char *lang
)
544 const char * const *lang_list
;
547 /* The returned list is sorted from most desirable to least
548 desirable and always contains the default locale "C". */
549 lang_list
= g_get_language_names ();
551 for (i
= 0; lang_list
[i
]; i
++)
552 if (strcmp (lang_list
[i
], lang
) == 0)
559 mime_info_start_element (GMarkupParseContext
*context
,
560 const gchar
*element_name
,
561 const gchar
**attribute_names
,
562 const gchar
**attribute_values
,
568 MimeParser
*parser
= user_data
;
570 if (strcmp (element_name
, "comment") == 0)
573 for (i
= 0; attribute_names
[i
]; i
++)
574 if (strcmp (attribute_names
[i
], "xml:lang") == 0)
576 lang
= attribute_values
[i
];
580 parser
->current_lang_level
= language_level (lang
);
581 parser
->current_type
= MIME_TAG_TYPE_COMMENT
;
584 parser
->current_type
= MIME_TAG_TYPE_OTHER
;
588 mime_info_end_element (GMarkupParseContext
*context
,
589 const gchar
*element_name
,
593 MimeParser
*parser
= user_data
;
595 parser
->current_type
= MIME_TAG_TYPE_OTHER
;
599 mime_info_text (GMarkupParseContext
*context
,
605 MimeParser
*parser
= user_data
;
607 if (parser
->current_type
== MIME_TAG_TYPE_COMMENT
&&
608 parser
->current_lang_level
> parser
->comment_lang_level
)
610 g_free (parser
->comment
);
611 parser
->comment
= g_strndup (text
, text_len
);
612 parser
->comment_lang_level
= parser
->current_lang_level
;
617 load_comment_for_mime_helper (const char *dir
,
618 const char *basename
)
620 GMarkupParseContext
*context
;
621 char *filename
, *data
;
624 MimeParser parse_data
= {0};
625 GMarkupParser parser
= {
626 mime_info_start_element
,
627 mime_info_end_element
,
631 filename
= g_build_filename (dir
, "mime", basename
, NULL
);
633 res
= g_file_get_contents (filename
, &data
, &len
, NULL
);
638 context
= g_markup_parse_context_new (&parser
, 0, &parse_data
, NULL
);
639 res
= g_markup_parse_context_parse (context
, data
, len
, NULL
);
641 g_markup_parse_context_free (context
);
646 return parse_data
.comment
;
651 load_comment_for_mime (const char *mimetype
)
653 const char * const* dirs
;
658 basename
= g_strdup_printf ("%s.xml", mimetype
);
660 comment
= load_comment_for_mime_helper (g_get_user_data_dir (), basename
);
667 dirs
= g_get_system_data_dirs ();
669 for (i
= 0; dirs
[i
] != NULL
; i
++)
671 comment
= load_comment_for_mime_helper (dirs
[i
], basename
);
680 return g_strdup_printf (_("%s type"), mimetype
);
684 * g_content_type_get_description:
685 * @type: a content type string
687 * Gets the human readable description of the content type.
689 * Returns: a short description of the content type @type. Free the
690 * returned string with g_free()
693 g_content_type_get_description (const gchar
*type
)
695 static GHashTable
*type_comment_cache
= NULL
;
698 g_return_val_if_fail (type
!= NULL
, NULL
);
700 G_LOCK (gio_xdgmime
);
701 type
= xdg_mime_unalias_mime_type (type
);
703 if (type_comment_cache
== NULL
)
704 type_comment_cache
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_free
);
706 comment
= g_hash_table_lookup (type_comment_cache
, type
);
707 comment
= g_strdup (comment
);
708 G_UNLOCK (gio_xdgmime
);
713 comment
= load_comment_for_mime (type
);
715 G_LOCK (gio_xdgmime
);
716 g_hash_table_insert (type_comment_cache
,
719 G_UNLOCK (gio_xdgmime
);
725 * g_content_type_get_mime_type:
726 * @type: a content type string
728 * Gets the mime type for the content type, if one is registered.
730 * Returns: (allow-none): the registered mime type for the given @type,
731 * or %NULL if unknown.
734 g_content_type_get_mime_type (const char *type
)
736 g_return_val_if_fail (type
!= NULL
, NULL
);
738 return g_strdup (type
);
742 * g_content_type_get_icon:
743 * @type: a content type string
745 * Gets the icon for a content type.
747 * Returns: (transfer full): #GIcon corresponding to the content type. Free the returned
748 * object with g_object_unref()
751 g_content_type_get_icon (const gchar
*type
)
753 char *mimetype_icon
, *generic_mimetype_icon
, *q
;
754 char *xdg_mimetype_icon
, *legacy_mimetype_icon
;
755 char *xdg_mimetype_generic_icon
;
761 g_return_val_if_fail (type
!= NULL
, NULL
);
763 G_LOCK (gio_xdgmime
);
764 xdg_mimetype_icon
= g_strdup (xdg_mime_get_icon (type
));
765 xdg_mimetype_generic_icon
= g_strdup (xdg_mime_get_generic_icon (type
));
766 G_UNLOCK (gio_xdgmime
);
768 mimetype_icon
= g_strdup (type
);
770 while ((q
= strchr (mimetype_icon
, '/')) != NULL
)
773 p
= strchr (type
, '/');
775 p
= type
+ strlen (type
);
777 /* Not all icons have migrated to the new icon theme spec, look for old names too */
778 legacy_mimetype_icon
= g_strconcat ("gnome-mime-", mimetype_icon
, NULL
);
780 generic_mimetype_icon
= g_malloc (p
- type
+ strlen ("-x-generic") + 1);
781 memcpy (generic_mimetype_icon
, type
, p
- type
);
782 memcpy (generic_mimetype_icon
+ (p
- type
), "-x-generic", strlen ("-x-generic"));
783 generic_mimetype_icon
[(p
- type
) + strlen ("-x-generic")] = 0;
785 if (xdg_mimetype_icon
)
786 icon_names
[n
++] = xdg_mimetype_icon
;
788 icon_names
[n
++] = mimetype_icon
;
789 icon_names
[n
++] = legacy_mimetype_icon
;
791 if (xdg_mimetype_generic_icon
)
792 icon_names
[n
++] = xdg_mimetype_generic_icon
;
794 icon_names
[n
++] = generic_mimetype_icon
;
796 themed_icon
= g_themed_icon_new_from_names (icon_names
, n
);
798 g_free (xdg_mimetype_icon
);
799 g_free (xdg_mimetype_generic_icon
);
800 g_free (mimetype_icon
);
801 g_free (legacy_mimetype_icon
);
802 g_free (generic_mimetype_icon
);
808 * g_content_type_can_be_executable:
809 * @type: a content type string
811 * Checks if a content type can be executable. Note that for instance
812 * things like text files can be executables (i.e. scripts and batch files).
814 * Returns: %TRUE if the file type corresponds to a type that
815 * can be executable, %FALSE otherwise.
818 g_content_type_can_be_executable (const gchar
*type
)
820 g_return_val_if_fail (type
!= NULL
, FALSE
);
822 if (g_content_type_is_a (type
, "application/x-executable") ||
823 g_content_type_is_a (type
, "text/plain"))
830 looks_like_text (const guchar
*data
, gsize data_size
)
835 for (i
= 0; i
< data_size
; i
++)
839 if (g_ascii_iscntrl (c
) &&
840 !g_ascii_isspace (c
) &&
848 * g_content_type_from_mime_type:
849 * @mime_type: a mime type string
851 * Tries to find a content type based on the mime type name.
853 * Returns: (allow-none): Newly allocated string with content type
854 * or %NULL. Free with g_free()
859 g_content_type_from_mime_type (const gchar
*mime_type
)
863 g_return_val_if_fail (mime_type
!= NULL
, NULL
);
865 G_LOCK (gio_xdgmime
);
866 /* mime type and content type are same on unixes */
867 umime
= g_strdup (xdg_mime_unalias_mime_type (mime_type
));
868 G_UNLOCK (gio_xdgmime
);
874 * g_content_type_guess:
875 * @filename: (allow-none): a string, or %NULL
876 * @data: (allow-none) (array length=data_size): a stream of data, or %NULL
877 * @data_size: the size of @data
878 * @result_uncertain: (allow-none) (out): return location for the certainty
879 * of the result, or %NULL
881 * Guesses the content type based on example data. If the function is
882 * uncertain, @result_uncertain will be set to %TRUE. Either @filename
883 * or @data may be %NULL, in which case the guess will be based solely
884 * on the other argument.
886 * Returns: a string indicating a guessed content type for the
887 * given data. Free with g_free()
890 g_content_type_guess (const gchar
*filename
,
893 gboolean
*result_uncertain
)
896 const char *name_mimetypes
[10], *sniffed_mimetype
;
899 int n_name_mimetypes
;
903 n_name_mimetypes
= 0;
904 sniffed_mimetype
= XDG_MIME_TYPE_UNKNOWN
;
906 if (result_uncertain
)
907 *result_uncertain
= FALSE
;
909 G_LOCK (gio_xdgmime
);
913 i
= strlen (filename
);
914 if (filename
[i
- 1] == '/')
916 name_mimetypes
[0] = "inode/directory";
917 name_mimetypes
[1] = NULL
;
918 n_name_mimetypes
= 1;
919 if (result_uncertain
)
920 *result_uncertain
= TRUE
;
924 basename
= g_path_get_basename (filename
);
925 n_name_mimetypes
= xdg_mime_get_mime_types_from_file_name (basename
, name_mimetypes
, 10);
930 /* Got an extension match, and no conflicts. This is it. */
931 if (n_name_mimetypes
== 1)
933 G_UNLOCK (gio_xdgmime
);
934 return g_strdup (name_mimetypes
[0]);
939 sniffed_mimetype
= xdg_mime_get_mime_type_for_data (data
, data_size
, &sniffed_prio
);
940 if (sniffed_mimetype
== XDG_MIME_TYPE_UNKNOWN
&&
942 looks_like_text (data
, data_size
))
943 sniffed_mimetype
= "text/plain";
945 /* For security reasons we don't ever want to sniff desktop files
946 * where we know the filename and it doesn't have a .desktop extension.
947 * This is because desktop files allow executing any application and
948 * we don't want to make it possible to hide them looking like something
951 if (filename
!= NULL
&&
952 strcmp (sniffed_mimetype
, "application/x-desktop") == 0)
953 sniffed_mimetype
= "text/plain";
956 if (n_name_mimetypes
== 0)
958 if (sniffed_mimetype
== XDG_MIME_TYPE_UNKNOWN
&&
960 *result_uncertain
= TRUE
;
962 mimetype
= g_strdup (sniffed_mimetype
);
967 if (sniffed_mimetype
!= XDG_MIME_TYPE_UNKNOWN
)
969 if (sniffed_prio
>= 80) /* High priority sniffing match, use that */
970 mimetype
= g_strdup (sniffed_mimetype
);
973 /* There are conflicts between the name matches and we
974 * have a sniffed type, use that as a tie breaker.
976 for (i
= 0; i
< n_name_mimetypes
; i
++)
978 if ( xdg_mime_mime_type_subclass (name_mimetypes
[i
], sniffed_mimetype
))
980 /* This nametype match is derived from (or the same as)
981 * the sniffed type). This is probably it.
983 mimetype
= g_strdup (name_mimetypes
[i
]);
990 if (mimetype
== NULL
)
992 /* Conflicts, and sniffed type was no help or not there.
993 * Guess on the first one
995 mimetype
= g_strdup (name_mimetypes
[0]);
996 if (result_uncertain
)
997 *result_uncertain
= TRUE
;
1001 G_UNLOCK (gio_xdgmime
);
1007 enumerate_mimetypes_subdir (const char *dir
,
1009 GHashTable
*mimetypes
)
1018 while ((ent
= readdir (d
)) != NULL
)
1020 if (g_str_has_suffix (ent
->d_name
, ".xml"))
1022 mimetype
= g_strdup_printf ("%s/%.*s", prefix
, (int) strlen (ent
->d_name
) - 4, ent
->d_name
);
1023 g_hash_table_replace (mimetypes
, mimetype
, NULL
);
1031 enumerate_mimetypes_dir (const char *dir
,
1032 GHashTable
*mimetypes
)
1039 mimedir
= g_build_filename (dir
, "mime", NULL
);
1041 d
= opendir (mimedir
);
1044 while ((ent
= readdir (d
)) != NULL
)
1046 if (strcmp (ent
->d_name
, "packages") != 0)
1048 name
= g_build_filename (mimedir
, ent
->d_name
, NULL
);
1049 if (g_file_test (name
, G_FILE_TEST_IS_DIR
))
1050 enumerate_mimetypes_subdir (name
, ent
->d_name
, mimetypes
);
1061 * g_content_types_get_registered:
1063 * Gets a list of strings containing all the registered content types
1064 * known to the system. The list and its data should be freed using
1066 * g_list_foreach (list, g_free, NULL);
1067 * g_list_free (list);
1070 * Returns: (element-type utf8) (transfer full): #GList of the registered content types
1073 g_content_types_get_registered (void)
1075 const char * const* dirs
;
1076 GHashTable
*mimetypes
;
1077 GHashTableIter iter
;
1082 mimetypes
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
1084 enumerate_mimetypes_dir (g_get_user_data_dir (), mimetypes
);
1085 dirs
= g_get_system_data_dirs ();
1087 for (i
= 0; dirs
[i
] != NULL
; i
++)
1088 enumerate_mimetypes_dir (dirs
[i
], mimetypes
);
1091 g_hash_table_iter_init (&iter
, mimetypes
);
1092 while (g_hash_table_iter_next (&iter
, &key
, NULL
))
1094 l
= g_list_prepend (l
, key
);
1095 g_hash_table_iter_steal (&iter
);
1098 g_hash_table_destroy (mimetypes
);
1104 /* tree magic data */
1105 static GList
*tree_matches
= NULL
;
1106 static gboolean need_reload
= FALSE
;
1108 G_LOCK_DEFINE_STATIC (gio_treemagic
);
1114 guint match_case
: 1;
1115 guint executable
: 1;
1116 guint non_empty
: 1;
1131 tree_matchlet_free (TreeMatchlet
*matchlet
)
1133 g_list_foreach (matchlet
->matches
, (GFunc
)tree_matchlet_free
, NULL
);
1134 g_list_free (matchlet
->matches
);
1135 g_free (matchlet
->path
);
1136 g_free (matchlet
->mimetype
);
1137 g_slice_free (TreeMatchlet
, matchlet
);
1141 tree_match_free (TreeMatch
*match
)
1143 g_list_foreach (match
->matches
, (GFunc
)tree_matchlet_free
, NULL
);
1144 g_list_free (match
->matches
);
1145 g_free (match
->contenttype
);
1146 g_slice_free (TreeMatch
, match
);
1150 parse_header (gchar
*line
)
1156 len
= strlen (line
);
1158 if (line
[0] != '[' || line
[len
- 1] != ']')
1162 s
= strchr (line
, ':');
1164 match
= g_slice_new0 (TreeMatch
);
1165 match
->priority
= atoi (line
+ 1);
1166 match
->contenttype
= g_strdup (s
+ 1);
1171 static TreeMatchlet
*
1172 parse_match_line (gchar
*line
,
1176 TreeMatchlet
*matchlet
;
1180 matchlet
= g_slice_new0 (TreeMatchlet
);
1189 *depth
= atoi (line
);
1190 s
= strchr (line
, '>');
1193 p
= strchr (s
, '"');
1196 matchlet
->path
= g_strdup (s
);
1198 parts
= g_strsplit (s
, ",", 0);
1199 if (strcmp (parts
[0], "=file") == 0)
1200 matchlet
->type
= G_FILE_TYPE_REGULAR
;
1201 else if (strcmp (parts
[0], "=directory") == 0)
1202 matchlet
->type
= G_FILE_TYPE_DIRECTORY
;
1203 else if (strcmp (parts
[0], "=link") == 0)
1204 matchlet
->type
= G_FILE_TYPE_SYMBOLIC_LINK
;
1206 matchlet
->type
= G_FILE_TYPE_UNKNOWN
;
1207 for (i
= 1; parts
[i
]; i
++)
1209 if (strcmp (parts
[i
], "executable") == 0)
1210 matchlet
->executable
= 1;
1211 else if (strcmp (parts
[i
], "match-case") == 0)
1212 matchlet
->match_case
= 1;
1213 else if (strcmp (parts
[i
], "non-empty") == 0)
1214 matchlet
->non_empty
= 1;
1215 else if (strcmp (parts
[i
], "on-disc") == 0)
1216 matchlet
->on_disc
= 1;
1218 matchlet
->mimetype
= g_strdup (parts
[i
]);
1227 cmp_match (gconstpointer a
, gconstpointer b
)
1229 const TreeMatch
*aa
= (const TreeMatch
*)a
;
1230 const TreeMatch
*bb
= (const TreeMatch
*)b
;
1232 return bb
->priority
- aa
->priority
;
1236 insert_match (TreeMatch
*match
)
1238 tree_matches
= g_list_insert_sorted (tree_matches
, match
, cmp_match
);
1242 insert_matchlet (TreeMatch
*match
,
1243 TreeMatchlet
*matchlet
,
1247 match
->matches
= g_list_append (match
->matches
, matchlet
);
1253 last
= g_list_last (match
->matches
);
1256 tree_matchlet_free (matchlet
);
1257 g_warning ("can't insert tree matchlet at depth %d", depth
);
1261 m
= (TreeMatchlet
*) last
->data
;
1264 last
= g_list_last (m
->matches
);
1267 tree_matchlet_free (matchlet
);
1268 g_warning ("can't insert tree matchlet at depth %d", depth
);
1272 m
= (TreeMatchlet
*) last
->data
;
1274 m
->matches
= g_list_append (m
->matches
, matchlet
);
1279 read_tree_magic_from_directory (const gchar
*prefix
)
1287 TreeMatchlet
*matchlet
;
1290 filename
= g_build_filename (prefix
, "mime", "treemagic", NULL
);
1292 if (g_file_get_contents (filename
, &text
, &len
, NULL
))
1294 if (strcmp (text
, "MIME-TreeMagic") == 0)
1296 lines
= g_strsplit (text
+ strlen ("MIME-TreeMagic") + 2, "\n", 0);
1298 for (i
= 0; lines
[i
] && lines
[i
][0]; i
++)
1300 if (lines
[i
][0] == '[')
1302 match
= parse_header (lines
[i
]);
1303 insert_match (match
);
1307 matchlet
= parse_match_line (lines
[i
], &depth
);
1308 insert_matchlet (match
, matchlet
, depth
);
1315 g_warning ("%s: header not found, skipping\n", filename
);
1325 xdg_mime_reload (void *user_data
)
1331 tree_magic_shutdown (void)
1333 g_list_foreach (tree_matches
, (GFunc
)tree_match_free
, NULL
);
1334 g_list_free (tree_matches
);
1335 tree_matches
= NULL
;
1339 tree_magic_init (void)
1341 static gboolean initialized
= FALSE
;
1343 const gchar
* const * dirs
;
1350 xdg_mime_register_reload_callback (xdg_mime_reload
, NULL
, NULL
);
1356 need_reload
= FALSE
;
1358 tree_magic_shutdown ();
1360 dir
= g_get_user_data_dir ();
1361 read_tree_magic_from_directory (dir
);
1362 dirs
= g_get_system_data_dirs ();
1363 for (i
= 0; dirs
[i
]; i
++)
1364 read_tree_magic_from_directory (dirs
[i
]);
1368 /* a filtering enumerator */
1374 gboolean ignore_case
;
1376 gchar
**case_components
;
1377 GFileEnumerator
**enumerators
;
1382 component_match (Enumerator
*e
,
1386 gchar
*case_folded
, *key
;
1389 if (strcmp (name
, e
->components
[depth
]) == 0)
1392 if (!e
->ignore_case
)
1395 case_folded
= g_utf8_casefold (name
, -1);
1396 key
= g_utf8_collate_key (case_folded
, -1);
1398 found
= strcmp (key
, e
->case_components
[depth
]) == 0;
1400 g_free (case_folded
);
1407 next_match_recurse (Enumerator
*e
,
1416 if (e
->enumerators
[depth
] == NULL
)
1420 file
= next_match_recurse (e
, depth
- 1);
1423 e
->children
[depth
] = file
;
1424 e
->enumerators
[depth
] = g_file_enumerate_children (file
,
1425 G_FILE_ATTRIBUTE_STANDARD_NAME
,
1426 G_FILE_QUERY_INFO_NONE
,
1431 if (e
->enumerators
[depth
] == NULL
)
1435 while ((info
= g_file_enumerator_next_file (e
->enumerators
[depth
], NULL
, NULL
)))
1437 name
= g_file_info_get_name (info
);
1438 if (component_match (e
, depth
, name
))
1440 file
= g_file_get_child (e
->children
[depth
], name
);
1441 g_object_unref (info
);
1444 g_object_unref (info
);
1447 g_object_unref (e
->enumerators
[depth
]);
1448 e
->enumerators
[depth
] = NULL
;
1449 g_object_unref (e
->children
[depth
]);
1450 e
->children
[depth
] = NULL
;
1455 enumerator_next (Enumerator
*e
)
1457 return next_match_recurse (e
, e
->depth
- 1);
1461 enumerator_new (GFile
*root
,
1463 gboolean ignore_case
)
1469 e
= g_new0 (Enumerator
, 1);
1470 e
->path
= g_strdup (path
);
1471 e
->ignore_case
= ignore_case
;
1473 e
->components
= g_strsplit (e
->path
, G_DIR_SEPARATOR_S
, -1);
1474 e
->depth
= g_strv_length (e
->components
);
1477 e
->case_components
= g_new0 (char *, e
->depth
+ 1);
1478 for (i
= 0; e
->components
[i
]; i
++)
1480 case_folded
= g_utf8_casefold (e
->components
[i
], -1);
1481 e
->case_components
[i
] = g_utf8_collate_key (case_folded
, -1);
1482 g_free (case_folded
);
1486 e
->children
= g_new0 (GFile
*, e
->depth
);
1487 e
->children
[0] = g_object_ref (root
);
1488 e
->enumerators
= g_new0 (GFileEnumerator
*, e
->depth
);
1489 e
->enumerators
[0] = g_file_enumerate_children (root
,
1490 G_FILE_ATTRIBUTE_STANDARD_NAME
,
1491 G_FILE_QUERY_INFO_NONE
,
1499 enumerator_free (Enumerator
*e
)
1503 for (i
= 0; i
< e
->depth
; i
++)
1505 if (e
->enumerators
[i
])
1506 g_object_unref (e
->enumerators
[i
]);
1508 g_object_unref (e
->children
[i
]);
1511 g_free (e
->enumerators
);
1512 g_free (e
->children
);
1513 g_strfreev (e
->components
);
1514 if (e
->case_components
)
1515 g_strfreev (e
->case_components
);
1521 matchlet_match (TreeMatchlet
*matchlet
,
1531 e
= enumerator_new (root
, matchlet
->path
, !matchlet
->match_case
);
1535 file
= enumerator_next (e
);
1538 enumerator_free (e
);
1542 if (matchlet
->mimetype
)
1543 attrs
= G_FILE_ATTRIBUTE_STANDARD_TYPE
","
1544 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE
","
1545 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE
;
1547 attrs
= G_FILE_ATTRIBUTE_STANDARD_TYPE
","
1548 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE
;
1549 info
= g_file_query_info (file
,
1551 G_FILE_QUERY_INFO_NONE
,
1558 if (matchlet
->type
!= G_FILE_TYPE_UNKNOWN
&&
1559 g_file_info_get_file_type (info
) != matchlet
->type
)
1562 if (matchlet
->executable
&&
1563 !g_file_info_get_attribute_boolean (info
, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE
))
1569 if (result
&& matchlet
->non_empty
)
1571 GFileEnumerator
*child_enum
;
1572 GFileInfo
*child_info
;
1574 child_enum
= g_file_enumerate_children (file
,
1575 G_FILE_ATTRIBUTE_STANDARD_NAME
,
1576 G_FILE_QUERY_INFO_NONE
,
1582 child_info
= g_file_enumerator_next_file (child_enum
, NULL
, NULL
);
1584 g_object_unref (child_info
);
1587 g_object_unref (child_enum
);
1593 if (result
&& matchlet
->mimetype
)
1595 if (strcmp (matchlet
->mimetype
, g_file_info_get_content_type (info
)) != 0)
1599 g_object_unref (info
);
1600 g_object_unref (file
);
1604 enumerator_free (e
);
1606 if (!matchlet
->matches
)
1609 for (l
= matchlet
->matches
; l
; l
= l
->next
)
1611 TreeMatchlet
*submatchlet
;
1613 submatchlet
= l
->data
;
1614 if (matchlet_match (submatchlet
, root
))
1622 match_match (TreeMatch
*match
,
1628 for (l
= match
->matches
; l
; l
= l
->next
)
1630 TreeMatchlet
*matchlet
= l
->data
;
1631 if (matchlet_match (matchlet
, root
))
1633 g_ptr_array_add (types
, g_strdup (match
->contenttype
));
1640 * g_content_type_guess_for_tree:
1641 * @root: the root of the tree to guess a type for
1643 * Tries to guess the type of the tree with root @root, by
1644 * looking at the files it contains. The result is an array
1645 * of content types, with the best guess coming first.
1647 * The types returned all have the form x-content/foo, e.g.
1648 * x-content/audio-cdda (for audio CDs) or x-content/image-dcf
1649 * (for a camera memory card). See the <ulink url="http://www.freedesktop.org/wiki/Specifications/shared-mime-info-spec">shared-mime-info</ulink>
1650 * specification for more on x-content types.
1652 * This function is useful in the implementation of
1653 * g_mount_guess_content_type().
1655 * Returns: (transfer full) (array zero-terminated=1): an %NULL-terminated
1656 * array of zero or more content types, or %NULL. Free with g_strfreev()
1661 g_content_type_guess_for_tree (GFile
*root
)
1666 types
= g_ptr_array_new ();
1668 G_LOCK (gio_treemagic
);
1671 for (l
= tree_matches
; l
; l
= l
->next
)
1673 TreeMatch
*match
= l
->data
;
1674 match_match (match
, root
, types
);
1677 G_UNLOCK (gio_treemagic
);
1679 g_ptr_array_add (types
, NULL
);
1681 return (gchar
**)g_ptr_array_free (types
, FALSE
);
1684 #endif /* Unix version */