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>
29 #include "gcontenttypeprivate.h"
30 #include "gthemedicon.h"
36 * SECTION:gcontenttype
37 * @short_description: Platform-specific content typing
40 * A content type is a platform specific string that defines the type
41 * of a file. On unix it is a mime type, on win32 it is an extension string
42 * like ".doc", ".txt" or a percieved string like "audio". Such strings
43 * can be looked up in the registry at HKEY_CLASSES_ROOT.
51 get_registry_classes_key (const char *subdir,
52 const wchar_t *key_name)
63 wc_key = g_utf8_to_utf16 (subdir, -1, NULL, NULL, NULL);
64 if (RegOpenKeyExW (HKEY_CLASSES_ROOT, wc_key, 0,
65 KEY_QUERY_VALUE, ®_key) == ERROR_SUCCESS &&
66 RegQueryValueExW (reg_key, key_name, 0,
67 &key_type, NULL, &nbytes) == ERROR_SUCCESS &&
70 wchar_t *wc_temp = g_new (wchar_t, (nbytes+1)/2 + 1);
71 RegQueryValueExW (reg_key, key_name, 0,
72 &key_type, (LPBYTE) wc_temp, &nbytes);
73 wc_temp[nbytes/2] = '\0';
74 value_utf8 = g_utf16_to_utf8 (wc_temp, -1, NULL, NULL, NULL);
80 RegCloseKey (reg_key);
86 g_content_type_equals (const char *type1,
89 char *progid1, *progid2;
92 g_return_val_if_fail (type1 != NULL, FALSE);
93 g_return_val_if_fail (type2 != NULL, FALSE);
95 if (g_ascii_strcasecmp (type1, type2) == 0)
99 progid1 = get_registry_classes_key (type1, NULL);
100 progid2 = get_registry_classes_key (type2, NULL);
101 if (progid1 != NULL && progid2 != NULL &&
102 strcmp (progid1, progid2) == 0)
111 g_content_type_is_a (const char *type,
112 const char *supertype)
117 g_return_val_if_fail (type != NULL, FALSE);
118 g_return_val_if_fail (supertype != NULL, FALSE);
120 if (g_content_type_equals (type, supertype))
124 value_utf8 = get_registry_classes_key (type, L"PerceivedType");
125 if (value_utf8 && strcmp (value_utf8, supertype) == 0)
133 g_content_type_is_unknown (const char *type)
135 g_return_val_if_fail (type != NULL, FALSE);
137 return strcmp ("*", type) == 0;
141 g_content_type_get_description (const char *type)
146 g_return_val_if_fail (type != NULL, NULL);
148 progid = get_registry_classes_key (type, NULL);
151 description = get_registry_classes_key (progid, NULL);
158 if (g_content_type_is_unknown (type))
159 return g_strdup (_("Unknown type"));
160 return g_strdup_printf (_("%s filetype"), type);
164 g_content_type_get_mime_type (const char *type)
168 g_return_val_if_fail (type != NULL, NULL);
170 mime = get_registry_classes_key (type, L"Content Type");
173 else if (g_content_type_is_unknown (type))
174 return g_strdup ("application/octet-stream");
175 else if (*type == '.')
176 return g_strdup_printf ("application/x-ext-%s", type+1);
177 /* TODO: Map "image" to "image/ *", etc? */
179 return g_strdup ("application/octet-stream");
183 g_content_type_get_icon (const char *type)
185 g_return_val_if_fail (type != NULL, NULL);
187 /* TODO: How do we represent icons???
188 In the registry they are the default value of
189 HKEY_CLASSES_ROOT\<progid>\DefaultIcon with typical values like:
191 REG_EXPAND_SZ: %SystemRoot%\System32\Wscript.exe,3
192 REG_SZ: shimgvw.dll,3
198 g_content_type_can_be_executable (const char *type)
200 g_return_val_if_fail (type != NULL, FALSE);
202 if (strcmp (type, ".exe") == 0 ||
203 strcmp (type, ".com") == 0 ||
204 strcmp (type, ".bat") == 0)
210 looks_like_text (const guchar *data,
215 for (i = 0; i < data_size; i++)
218 if (g_ascii_iscntrl (c) && !g_ascii_isspace (c))
225 g_content_type_guess (const char *filename,
228 gboolean *result_uncertain)
238 basename = g_path_get_basename (filename);
239 dot = strrchr (basename, '.');
241 type = g_strdup (dot);
248 if (data && looks_like_text (data, data_size))
249 return g_strdup (".txt");
251 return g_strdup ("*");
255 g_content_types_get_registered (void)
258 wchar_t keyname[256];
266 while (RegEnumKeyExW(HKEY_CLASSES_ROOT,
273 NULL) == ERROR_SUCCESS)
275 key_utf8 = g_utf16_to_utf8 (keyname, -1, NULL, NULL, NULL);
278 if (*key_utf8 == '.')
279 types = g_list_prepend (types, key_utf8);
287 return g_list_reverse (types);
290 #else /* !G_OS_WIN32 - Unix specific version */
294 #define XDG_PREFIX _gio_xdg
295 #include "xdgmime/xdgmime.h"
297 /* We lock this mutex whenever we modify global state in this module. */
298 G_LOCK_DEFINE_STATIC (gio_xdgmime);
301 _g_unix_content_type_get_sniff_len (void)
305 G_LOCK (gio_xdgmime);
306 size = xdg_mime_get_max_buffer_extents ();
307 G_UNLOCK (gio_xdgmime);
313 _g_unix_content_type_unalias (const char *type)
317 G_LOCK (gio_xdgmime);
318 res = g_strdup (xdg_mime_unalias_mime_type (type));
319 G_UNLOCK (gio_xdgmime);
325 _g_unix_content_type_get_parents (const char *type)
332 array = g_ptr_array_new ();
334 G_LOCK (gio_xdgmime);
336 umime = xdg_mime_unalias_mime_type (type);
338 g_ptr_array_add (array, g_strdup (umime));
340 parents = xdg_mime_list_mime_parents (umime);
341 for (i = 0; parents && parents[i] != NULL; i++)
342 g_ptr_array_add (array, g_strdup (parents[i]));
346 G_UNLOCK (gio_xdgmime);
348 g_ptr_array_add (array, NULL);
350 return (char **)g_ptr_array_free (array, FALSE);
354 * g_content_type_equals:
355 * @type1: a content type string.
356 * @type2: a content type string.
358 * Compares two content types for equality.
360 * Returns: %TRUE if the two strings are identical or equivalent,
364 g_content_type_equals (const char *type1,
369 g_return_val_if_fail (type1 != NULL, FALSE);
370 g_return_val_if_fail (type2 != NULL, FALSE);
372 G_LOCK (gio_xdgmime);
373 res = xdg_mime_mime_type_equal (type1, type2);
374 G_UNLOCK (gio_xdgmime);
380 * g_content_type_is_a:
381 * @type: a content type string.
382 * @supertype: a string.
384 * Determines if @type is a subset of @supertype.
386 * Returns: %TRUE if @type is a kind of @supertype,
390 g_content_type_is_a (const char *type,
391 const char *supertype)
395 g_return_val_if_fail (type != NULL, FALSE);
396 g_return_val_if_fail (supertype != NULL, FALSE);
398 G_LOCK (gio_xdgmime);
399 res = xdg_mime_mime_type_subclass (type, supertype);
400 G_UNLOCK (gio_xdgmime);
406 * g_content_type_is_unknown:
407 * @type: a content type string.
409 * Checks if the content type is the generic "unknown" type.
410 * On unix this is the "application/octet-stream" mimetype,
411 * while on win32 it is "*".
413 * Returns: %TRUE if the type is the unknown type.
416 g_content_type_is_unknown (const char *type)
418 g_return_val_if_fail (type != NULL, FALSE);
420 return strcmp (XDG_MIME_TYPE_UNKNOWN, type) == 0;
426 MIME_TAG_TYPE_COMMENT
431 int current_lang_level;
432 int comment_lang_level;
438 language_level (const char *lang)
440 const char * const *lang_list;
443 /* The returned list is sorted from most desirable to least
444 desirable and always contains the default locale "C". */
445 lang_list = g_get_language_names ();
447 for (i = 0; lang_list[i]; i++)
448 if (strcmp (lang_list[i], lang) == 0)
455 mime_info_start_element (GMarkupParseContext *context,
456 const gchar *element_name,
457 const gchar **attribute_names,
458 const gchar **attribute_values,
464 MimeParser *parser = user_data;
466 if (strcmp (element_name, "comment") == 0)
469 for (i = 0; attribute_names[i]; i++)
470 if (strcmp (attribute_names[i], "xml:lang") == 0)
472 lang = attribute_values[i];
476 parser->current_lang_level = language_level (lang);
477 parser->current_type = MIME_TAG_TYPE_COMMENT;
480 parser->current_type = MIME_TAG_TYPE_OTHER;
485 mime_info_end_element (GMarkupParseContext *context,
486 const gchar *element_name,
490 MimeParser *parser = user_data;
492 parser->current_type = MIME_TAG_TYPE_OTHER;
496 mime_info_text (GMarkupParseContext *context,
502 MimeParser *parser = user_data;
504 if (parser->current_type == MIME_TAG_TYPE_COMMENT &&
505 parser->current_lang_level > parser->comment_lang_level)
507 g_free (parser->comment);
508 parser->comment = g_strndup (text, text_len);
509 parser->comment_lang_level = parser->current_lang_level;
514 load_comment_for_mime_helper (const char *dir,
515 const char *basename)
517 GMarkupParseContext *context;
518 char *filename, *data;
521 MimeParser parse_data = {0};
522 GMarkupParser parser = {
523 mime_info_start_element,
524 mime_info_end_element,
528 filename = g_build_filename (dir, "mime", basename, NULL);
530 res = g_file_get_contents (filename, &data, &len, NULL);
535 context = g_markup_parse_context_new (&parser, 0, &parse_data, NULL);
536 res = g_markup_parse_context_parse (context, data, len, NULL);
538 g_markup_parse_context_free (context);
543 return parse_data.comment;
548 load_comment_for_mime (const char *mimetype)
550 const char * const* dirs;
555 basename = g_strdup_printf ("%s.xml", mimetype);
557 comment = load_comment_for_mime_helper (g_get_user_data_dir (), basename);
564 dirs = g_get_system_data_dirs ();
566 for (i = 0; dirs[i] != NULL; i++)
568 comment = load_comment_for_mime_helper (dirs[i], basename);
577 return g_strdup_printf (_("%s type"), mimetype);
581 * g_content_type_get_description:
582 * @type: a content type string.
584 * Gets the human readable description of the content type.
586 * Returns: a short description of the content type @type.
589 g_content_type_get_description (const char *type)
591 static GHashTable *type_comment_cache = NULL;
594 g_return_val_if_fail (type != NULL, NULL);
596 G_LOCK (gio_xdgmime);
597 type = xdg_mime_unalias_mime_type (type);
599 if (type_comment_cache == NULL)
600 type_comment_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
602 comment = g_hash_table_lookup (type_comment_cache, type);
603 comment = g_strdup (comment);
604 G_UNLOCK (gio_xdgmime);
609 comment = load_comment_for_mime (type);
611 G_LOCK (gio_xdgmime);
612 g_hash_table_insert (type_comment_cache,
615 G_UNLOCK (gio_xdgmime);
621 * g_content_type_get_mime_type:
622 * @type: a content type string.
624 * Gets the mime-type for the content type. If one is registered
626 * Returns: the registered mime-type for the given @type, or NULL if unknown.
629 g_content_type_get_mime_type (const char *type)
631 g_return_val_if_fail (type != NULL, NULL);
633 return g_strdup (type);
637 * g_content_type_get_icon:
638 * @type: a content type string.
640 * Gets the icon for a content type.
642 * Returns: #GIcon corresponding to the content type.
645 g_content_type_get_icon (const char *type)
647 char *mimetype_icon, *generic_mimetype_icon, *p;
649 GThemedIcon *themed_icon;
651 g_return_val_if_fail (type != NULL, NULL);
653 mimetype_icon = g_strdup (type);
655 while ((p = strchr (mimetype_icon, '/')) != NULL)
658 p = strchr (type, '/');
660 p = type + strlen (type);
662 generic_mimetype_icon = g_malloc (p - type + strlen ("-x-generic") + 1);
663 memcpy (generic_mimetype_icon, type, p - type);
664 memcpy (generic_mimetype_icon + (p - type), "-x-generic", strlen ("-x-generic"));
665 generic_mimetype_icon[(p - type) + strlen ("-x-generic")] = 0;
667 icon_names[0] = mimetype_icon;
668 /* Not all icons have migrated to the new icon theme spec, look for old names too */
669 icon_names[1] = g_strconcat ("gnome-mime-", mimetype_icon, NULL);
670 icon_names[2] = generic_mimetype_icon;
672 themed_icon = g_themed_icon_new_from_names (icon_names, 3);
674 g_free (mimetype_icon);
675 g_free (icon_names[1]);
676 g_free (generic_mimetype_icon);
678 return G_ICON (themed_icon);
682 * g_content_type_can_be_executable:
683 * @type: a content type string.
685 * Checks if a content type can be executable. Note that for instance
686 * things like text files can be executables (i.e. scripts and batch files).
688 * Returns: %TRUE if the file type corresponds to a type that
689 * can be executable, %FALSE otherwise.
692 g_content_type_can_be_executable (const char *type)
694 g_return_val_if_fail (type != NULL, FALSE);
696 if (g_content_type_is_a (type, "application/x-executable") ||
697 g_content_type_is_a (type, "text/plain"))
704 looks_like_text (const guchar *data, gsize data_size)
709 for (i = 0; i < data_size; i++)
713 if (g_ascii_iscntrl (c) &&
714 !g_ascii_isspace (c))
721 * g_content_type_guess:
722 * @filename: a string.
723 * @data: a stream of data.
724 * @data_size: the size of @data.
725 * @result_uncertain: a flag indicating the certainty of the
728 * Guesses the content type based on example data. If the function is
729 * uncertain, @result_uncertain will be set to %TRUE.
731 * Returns: a string indicating a guessed content type for the
735 g_content_type_guess (const char *filename,
738 gboolean *result_uncertain)
741 const char *name_mimetypes[10], *sniffed_mimetype;
744 int n_name_mimetypes;
748 n_name_mimetypes = 0;
749 sniffed_mimetype = XDG_MIME_TYPE_UNKNOWN;
751 if (result_uncertain)
752 *result_uncertain = FALSE;
754 G_LOCK (gio_xdgmime);
758 basename = g_path_get_basename (filename);
759 n_name_mimetypes = xdg_mime_get_mime_types_from_file_name (basename, name_mimetypes, 10);
763 /* Got an extension match, and no conflicts. This is it. */
764 if (n_name_mimetypes == 1)
766 G_UNLOCK (gio_xdgmime);
767 return g_strdup (name_mimetypes[0]);
772 sniffed_mimetype = xdg_mime_get_mime_type_for_data (data, data_size, &sniffed_prio);
773 if (sniffed_mimetype == XDG_MIME_TYPE_UNKNOWN &&
775 looks_like_text (data, data_size))
776 sniffed_mimetype = "text/plain";
779 if (n_name_mimetypes == 0)
781 if (sniffed_mimetype == XDG_MIME_TYPE_UNKNOWN &&
783 *result_uncertain = TRUE;
785 mimetype = g_strdup (sniffed_mimetype);
790 if (sniffed_mimetype != XDG_MIME_TYPE_UNKNOWN)
792 if (sniffed_prio >= 80) /* High priority sniffing match, use that */
793 mimetype = g_strdup (sniffed_mimetype);
796 /* There are conflicts between the name matches and we have a sniffed
797 type, use that as a tie breaker. */
799 for (i = 0; i < n_name_mimetypes; i++)
801 if ( xdg_mime_mime_type_subclass (name_mimetypes[i], sniffed_mimetype))
803 /* This nametype match is derived from (or the same as) the sniffed type).
804 This is probably it. */
805 mimetype = g_strdup (name_mimetypes[i]);
812 if (mimetype == NULL)
814 /* Conflicts, and sniffed type was no help or not there. guess on the first one */
815 mimetype = g_strdup (name_mimetypes[0]);
816 if (result_uncertain)
817 *result_uncertain = TRUE;
821 G_UNLOCK (gio_xdgmime);
827 enumerate_mimetypes_subdir (const char *dir,
829 GHashTable *mimetypes)
838 while ((ent = readdir (d)) != NULL)
840 if (g_str_has_suffix (ent->d_name, ".xml"))
842 mimetype = g_strdup_printf ("%s/%.*s", prefix, (int) strlen (ent->d_name) - 4, ent->d_name);
843 g_hash_table_insert (mimetypes, mimetype, NULL);
851 enumerate_mimetypes_dir (const char *dir,
852 GHashTable *mimetypes)
859 mimedir = g_build_filename (dir, "mime", NULL);
861 d = opendir (mimedir);
864 while ((ent = readdir (d)) != NULL)
866 if (strcmp (ent->d_name, "packages") != 0)
868 name = g_build_filename (mimedir, ent->d_name, NULL);
869 if (g_file_test (name, G_FILE_TEST_IS_DIR))
870 enumerate_mimetypes_subdir (name, ent->d_name, mimetypes);
881 * g_content_types_get_registered:
883 * Gets a list of strings containing all the registered content types
884 * known to the system. The list and its data should be freed using
885 * @g_list_foreach(list, g_free, NULL) and @g_list_free(list)
886 * Returns: #GList of the registered content types.
889 g_content_types_get_registered (void)
891 const char * const* dirs;
892 GHashTable *mimetypes;
898 mimetypes = g_hash_table_new (g_str_hash, g_str_equal);
900 enumerate_mimetypes_dir (g_get_user_data_dir (), mimetypes);
901 dirs = g_get_system_data_dirs ();
903 for (i = 0; dirs[i] != NULL; i++)
904 enumerate_mimetypes_dir (dirs[i], mimetypes);
907 g_hash_table_iter_init (&iter, mimetypes);
908 while (g_hash_table_iter_next (&iter, &key, NULL))
909 l = g_list_prepend (l, key);
911 g_hash_table_destroy (mimetypes);
916 #endif /* Unix version */
918 #define __G_CONTENT_TYPE_C__
919 #include "gioaliasdef.c"