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.1 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, see <http://www.gnu.org/licenses/>.
20 * Author: Alexander Larsson <alexl@redhat.com>
24 #include <sys/types.h>
28 #include "gcontenttype.h"
29 #include "gthemedicon.h"
36 get_registry_classes_key (const char *subdir
,
37 const wchar_t *key_name
)
48 wc_key
= g_utf8_to_utf16 (subdir
, -1, NULL
, NULL
, NULL
);
49 if (RegOpenKeyExW (HKEY_CLASSES_ROOT
, wc_key
, 0,
50 KEY_QUERY_VALUE
, ®_key
) == ERROR_SUCCESS
&&
51 RegQueryValueExW (reg_key
, key_name
, 0,
52 &key_type
, NULL
, &nbytes
) == ERROR_SUCCESS
&&
53 (key_type
== REG_SZ
|| key_type
== REG_EXPAND_SZ
))
55 wchar_t *wc_temp
= g_new (wchar_t, (nbytes
+1)/2 + 1);
56 RegQueryValueExW (reg_key
, key_name
, 0,
57 &key_type
, (LPBYTE
) wc_temp
, &nbytes
);
58 wc_temp
[nbytes
/2] = '\0';
59 if (key_type
== REG_EXPAND_SZ
)
62 int len
= ExpandEnvironmentStringsW (wc_temp
, dummy
, 1);
65 wchar_t *wc_temp_expanded
= g_new (wchar_t, len
);
66 if (ExpandEnvironmentStringsW (wc_temp
, wc_temp_expanded
, len
) == len
)
67 value_utf8
= g_utf16_to_utf8 (wc_temp_expanded
, -1, NULL
, NULL
, NULL
);
68 g_free (wc_temp_expanded
);
73 value_utf8
= g_utf16_to_utf8 (wc_temp
, -1, NULL
, NULL
, NULL
);
81 RegCloseKey (reg_key
);
87 g_content_type_equals (const gchar
*type1
,
90 char *progid1
, *progid2
;
93 g_return_val_if_fail (type1
!= NULL
, FALSE
);
94 g_return_val_if_fail (type2
!= NULL
, FALSE
);
96 if (g_ascii_strcasecmp (type1
, type2
) == 0)
100 progid1
= get_registry_classes_key (type1
, NULL
);
101 progid2
= get_registry_classes_key (type2
, NULL
);
102 if (progid1
!= NULL
&& progid2
!= NULL
&&
103 strcmp (progid1
, progid2
) == 0)
112 g_content_type_is_a (const gchar
*type
,
113 const gchar
*supertype
)
118 g_return_val_if_fail (type
!= NULL
, FALSE
);
119 g_return_val_if_fail (supertype
!= NULL
, FALSE
);
121 if (g_content_type_equals (type
, supertype
))
125 value_utf8
= get_registry_classes_key (type
, L
"PerceivedType");
126 if (value_utf8
&& strcmp (value_utf8
, supertype
) == 0)
134 g_content_type_is_mime_type (const gchar
*type
,
135 const gchar
*mime_type
)
140 g_return_val_if_fail (type
!= NULL
, FALSE
);
141 g_return_val_if_fail (mime_type
!= NULL
, FALSE
);
143 content_type
= g_content_type_from_mime_type (mime_type
);
144 ret
= g_content_type_is_a (type
, content_type
);
145 g_free (content_type
);
151 g_content_type_is_unknown (const gchar
*type
)
153 g_return_val_if_fail (type
!= NULL
, FALSE
);
155 return strcmp ("*", type
) == 0;
159 g_content_type_get_description (const gchar
*type
)
164 g_return_val_if_fail (type
!= NULL
, NULL
);
166 progid
= get_registry_classes_key (type
, NULL
);
169 description
= get_registry_classes_key (progid
, NULL
);
176 if (g_content_type_is_unknown (type
))
177 return g_strdup (_("Unknown type"));
179 return g_strdup_printf (_("%s filetype"), type
);
183 g_content_type_get_mime_type (const gchar
*type
)
187 g_return_val_if_fail (type
!= NULL
, NULL
);
189 mime
= get_registry_classes_key (type
, L
"Content Type");
192 else if (g_content_type_is_unknown (type
))
193 return g_strdup ("application/octet-stream");
194 else if (*type
== '.')
195 return g_strdup_printf ("application/x-ext-%s", type
+1);
196 else if (strcmp ("inode/directory", type
) == 0)
197 return g_strdup (type
);
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
));
249 /* if no icon found, fall back to standard generic names */
250 if (strcmp (type
, "inode/directory") == 0)
252 else if (g_content_type_can_be_executable (type
))
255 name
= "text-x-generic";
256 g_hash_table_insert (_type_icons
, g_strdup (type
), g_strdup (name
));
258 themed_icon
= g_themed_icon_new (name
);
259 G_UNLOCK (_type_icons
);
261 return G_ICON (themed_icon
);
265 g_content_type_get_symbolic_icon (const gchar
*type
)
267 return g_content_type_get_icon (type
);
271 g_content_type_get_generic_icon_name (const gchar
*type
)
277 g_content_type_can_be_executable (const gchar
*type
)
279 g_return_val_if_fail (type
!= NULL
, FALSE
);
281 if (strcmp (type
, ".exe") == 0 ||
282 strcmp (type
, ".com") == 0 ||
283 strcmp (type
, ".bat") == 0)
286 /* TODO: Also look at PATHEXT, which lists the extensions for
287 * "scripts" in addition to those for true binary executables.
289 * (PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH for me
290 * right now, for instance). And in a sense, all associated file
291 * types are "executable" on Windows... You can just type foo.jpg as
292 * a command name in cmd.exe, and it will run the application
293 * associated with .jpg. Hard to say what this API actually means
301 looks_like_text (const guchar
*data
,
306 for (i
= 0; i
< data_size
; i
++)
309 if (g_ascii_iscntrl (c
) && !g_ascii_isspace (c
) && c
!= '\b')
316 g_content_type_from_mime_type (const gchar
*mime_type
)
318 char *key
, *content_type
;
320 g_return_val_if_fail (mime_type
!= NULL
, NULL
);
322 /* This is a hack to allow directories to have icons in filechooser */
323 if (strcmp ("inode/directory", mime_type
) == 0)
324 return g_strdup (mime_type
);
326 key
= g_strconcat ("MIME\\DataBase\\Content Type\\", mime_type
, NULL
);
327 content_type
= get_registry_classes_key (key
, L
"Extension");
334 g_content_type_guess (const gchar
*filename
,
337 gboolean
*result_uncertain
)
345 if (result_uncertain
)
346 *result_uncertain
= FALSE
;
348 /* our test suite and potentially other code used -1 in the past, which is
349 * not documented and not allowed; guard against that */
350 g_return_val_if_fail (data_size
!= (gsize
) -1, g_strdup ("*"));
354 basename
= g_path_get_basename (filename
);
355 dot
= strrchr (basename
, '.');
357 type
= g_strdup (dot
);
364 if (data
&& looks_like_text (data
, data_size
))
365 return g_strdup (".txt");
367 return g_strdup ("*");
371 g_content_types_get_registered (void)
374 wchar_t keyname
[256];
382 while (RegEnumKeyExW(HKEY_CLASSES_ROOT
,
389 NULL
) == ERROR_SUCCESS
)
391 key_utf8
= g_utf16_to_utf8 (keyname
, -1, NULL
, NULL
, NULL
);
394 if (*key_utf8
== '.')
395 types
= g_list_prepend (types
, key_utf8
);
403 return g_list_reverse (types
);
407 g_content_type_guess_for_tree (GFile
*root
)
409 /* FIXME: implement */