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, 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_unknown (const gchar
*type
)
136 g_return_val_if_fail (type
!= NULL
, FALSE
);
138 return strcmp ("*", type
) == 0;
142 g_content_type_get_description (const gchar
*type
)
147 g_return_val_if_fail (type
!= NULL
, NULL
);
149 progid
= get_registry_classes_key (type
, NULL
);
152 description
= get_registry_classes_key (progid
, NULL
);
159 if (g_content_type_is_unknown (type
))
160 return g_strdup (_("Unknown type"));
162 return g_strdup_printf (_("%s filetype"), type
);
166 g_content_type_get_mime_type (const gchar
*type
)
170 g_return_val_if_fail (type
!= NULL
, NULL
);
172 mime
= get_registry_classes_key (type
, L
"Content Type");
175 else if (g_content_type_is_unknown (type
))
176 return g_strdup ("application/octet-stream");
177 else if (*type
== '.')
178 return g_strdup_printf ("application/x-ext-%s", type
+1);
179 else if (strcmp ("inode/directory", type
) == 0)
180 return g_strdup (type
);
181 /* TODO: Map "image" to "image/ *", etc? */
183 return g_strdup ("application/octet-stream");
186 G_LOCK_DEFINE_STATIC (_type_icons
);
187 static GHashTable
*_type_icons
= NULL
;
190 g_content_type_get_icon (const gchar
*type
)
195 g_return_val_if_fail (type
!= NULL
, NULL
);
197 /* In the Registry icons are the default value of
198 HKEY_CLASSES_ROOT\<progid>\DefaultIcon with typical values like:
200 REG_EXPAND_SZ: %SystemRoot%\System32\Wscript.exe,3
201 REG_SZ: shimgvw.dll,3
203 G_LOCK (_type_icons
);
205 _type_icons
= g_hash_table_new (g_str_hash
, g_str_equal
);
206 name
= g_hash_table_lookup (_type_icons
, type
);
207 if (!name
&& type
[0] == '.')
209 /* double lookup by extension */
210 gchar
*key
= get_registry_classes_key (type
, NULL
);
212 key
= g_strconcat (type
+1, "file\\DefaultIcon", NULL
);
215 gchar
*key2
= g_strconcat (key
, "\\DefaultIcon", NULL
);
219 name
= get_registry_classes_key (key
, NULL
);
220 if (name
&& strcmp (name
, "%1") == 0)
226 g_hash_table_insert (_type_icons
, g_strdup (type
), g_strdup (name
));
232 /* if no icon found, fall back to standard generic names */
233 if (strcmp (type
, "inode/directory") == 0)
235 else if (g_content_type_can_be_executable (type
))
238 name
= "text-x-generic";
239 g_hash_table_insert (_type_icons
, g_strdup (type
), g_strdup (name
));
241 themed_icon
= g_themed_icon_new (name
);
242 G_UNLOCK (_type_icons
);
244 return G_ICON (themed_icon
);
248 g_content_type_get_symbolic_icon (const gchar
*type
)
250 return g_content_type_get_icon (type
);
254 g_content_type_get_generic_icon_name (const gchar
*type
)
260 g_content_type_can_be_executable (const gchar
*type
)
262 g_return_val_if_fail (type
!= NULL
, FALSE
);
264 if (strcmp (type
, ".exe") == 0 ||
265 strcmp (type
, ".com") == 0 ||
266 strcmp (type
, ".bat") == 0)
269 /* TODO: Also look at PATHEXT, which lists the extensions for
270 * "scripts" in addition to those for true binary executables.
272 * (PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH for me
273 * right now, for instance). And in a sense, all associated file
274 * types are "executable" on Windows... You can just type foo.jpg as
275 * a command name in cmd.exe, and it will run the application
276 * associated with .jpg. Hard to say what this API actually means
284 looks_like_text (const guchar
*data
,
289 for (i
= 0; i
< data_size
; i
++)
292 if (g_ascii_iscntrl (c
) && !g_ascii_isspace (c
) && c
!= '\b')
299 g_content_type_from_mime_type (const gchar
*mime_type
)
301 char *key
, *content_type
;
303 g_return_val_if_fail (mime_type
!= NULL
, NULL
);
305 /* This is a hack to allow directories to have icons in filechooser */
306 if (strcmp ("inode/directory", mime_type
) == 0)
307 return g_strdup (mime_type
);
309 key
= g_strconcat ("MIME\\DataBase\\Content Type\\", mime_type
, NULL
);
310 content_type
= get_registry_classes_key (key
, L
"Extension");
317 g_content_type_guess (const gchar
*filename
,
320 gboolean
*result_uncertain
)
328 if (result_uncertain
)
329 *result_uncertain
= FALSE
;
331 /* our test suite and potentially other code used -1 in the past, which is
332 * not documented and not allowed; guard against that */
333 g_return_val_if_fail (data_size
!= (gsize
) -1, g_strdup ("*"));
337 basename
= g_path_get_basename (filename
);
338 dot
= strrchr (basename
, '.');
340 type
= g_strdup (dot
);
347 if (data
&& looks_like_text (data
, data_size
))
348 return g_strdup (".txt");
350 return g_strdup ("*");
354 g_content_types_get_registered (void)
357 wchar_t keyname
[256];
365 while (RegEnumKeyExW(HKEY_CLASSES_ROOT
,
372 NULL
) == ERROR_SUCCESS
)
374 key_utf8
= g_utf16_to_utf8 (keyname
, -1, NULL
, NULL
, NULL
);
377 if (*key_utf8
== '.')
378 types
= g_list_prepend (types
, key_utf8
);
386 return g_list_reverse (types
);
390 g_content_type_guess_for_tree (GFile
*root
)
392 /* FIXME: implement */