nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ |
2 | |||
3 | /* GIO - GLib Input, Output and Streaming Library |
||
4 | * |
||
5 | * Copyright (C) 2006-2007 Red Hat, Inc. |
||
6 | * |
||
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. |
||
11 | * |
||
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. |
||
16 | * |
||
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/>. |
||
19 | * |
||
20 | * Author: Alexander Larsson <alexl@redhat.com> |
||
21 | */ |
||
22 | |||
23 | #include "config.h" |
||
24 | #include <sys/types.h> |
||
25 | #include <stdlib.h> |
||
26 | #include <string.h> |
||
27 | #include <stdio.h> |
||
28 | #include "gcontenttype.h" |
||
29 | #include "gthemedicon.h" |
||
30 | #include "gicon.h" |
||
31 | #include "glibintl.h" |
||
32 | |||
33 | #include <windows.h> |
||
34 | |||
35 | static char * |
||
36 | get_registry_classes_key (const char *subdir, |
||
37 | const wchar_t *key_name) |
||
38 | { |
||
39 | wchar_t *wc_key; |
||
40 | HKEY reg_key = NULL; |
||
41 | DWORD key_type; |
||
42 | DWORD nbytes; |
||
43 | char *value_utf8; |
||
44 | |||
45 | value_utf8 = NULL; |
||
46 | |||
47 | nbytes = 0; |
||
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)) |
||
54 | { |
||
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) |
||
60 | { |
||
61 | wchar_t dummy[1]; |
||
62 | int len = ExpandEnvironmentStringsW (wc_temp, dummy, 1); |
||
63 | if (len > 0) |
||
64 | { |
||
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); |
||
69 | } |
||
70 | } |
||
71 | else |
||
72 | { |
||
73 | value_utf8 = g_utf16_to_utf8 (wc_temp, -1, NULL, NULL, NULL); |
||
74 | } |
||
75 | g_free (wc_temp); |
||
76 | |||
77 | } |
||
78 | g_free (wc_key); |
||
79 | |||
80 | if (reg_key != NULL) |
||
81 | RegCloseKey (reg_key); |
||
82 | |||
83 | return value_utf8; |
||
84 | } |
||
85 | |||
86 | gboolean |
||
87 | g_content_type_equals (const gchar *type1, |
||
88 | const gchar *type2) |
||
89 | { |
||
90 | char *progid1, *progid2; |
||
91 | gboolean res; |
||
92 | |||
93 | g_return_val_if_fail (type1 != NULL, FALSE); |
||
94 | g_return_val_if_fail (type2 != NULL, FALSE); |
||
95 | |||
96 | if (g_ascii_strcasecmp (type1, type2) == 0) |
||
97 | return TRUE; |
||
98 | |||
99 | res = FALSE; |
||
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) |
||
104 | res = TRUE; |
||
105 | g_free (progid1); |
||
106 | g_free (progid2); |
||
107 | |||
108 | return res; |
||
109 | } |
||
110 | |||
111 | gboolean |
||
112 | g_content_type_is_a (const gchar *type, |
||
113 | const gchar *supertype) |
||
114 | { |
||
115 | gboolean res; |
||
116 | char *value_utf8; |
||
117 | |||
118 | g_return_val_if_fail (type != NULL, FALSE); |
||
119 | g_return_val_if_fail (supertype != NULL, FALSE); |
||
120 | |||
121 | if (g_content_type_equals (type, supertype)) |
||
122 | return TRUE; |
||
123 | |||
124 | res = FALSE; |
||
125 | value_utf8 = get_registry_classes_key (type, L"PerceivedType"); |
||
126 | if (value_utf8 && strcmp (value_utf8, supertype) == 0) |
||
127 | res = TRUE; |
||
128 | g_free (value_utf8); |
||
129 | |||
130 | return res; |
||
131 | } |
||
132 | |||
133 | gboolean |
||
134 | g_content_type_is_unknown (const gchar *type) |
||
135 | { |
||
136 | g_return_val_if_fail (type != NULL, FALSE); |
||
137 | |||
138 | return strcmp ("*", type) == 0; |
||
139 | } |
||
140 | |||
141 | gchar * |
||
142 | g_content_type_get_description (const gchar *type) |
||
143 | { |
||
144 | char *progid; |
||
145 | char *description; |
||
146 | |||
147 | g_return_val_if_fail (type != NULL, NULL); |
||
148 | |||
149 | progid = get_registry_classes_key (type, NULL); |
||
150 | if (progid) |
||
151 | { |
||
152 | description = get_registry_classes_key (progid, NULL); |
||
153 | g_free (progid); |
||
154 | |||
155 | if (description) |
||
156 | return description; |
||
157 | } |
||
158 | |||
159 | if (g_content_type_is_unknown (type)) |
||
160 | return g_strdup (_("Unknown type")); |
||
161 | |||
162 | return g_strdup_printf (_("%s filetype"), type); |
||
163 | } |
||
164 | |||
165 | gchar * |
||
166 | g_content_type_get_mime_type (const gchar *type) |
||
167 | { |
||
168 | char *mime; |
||
169 | |||
170 | g_return_val_if_fail (type != NULL, NULL); |
||
171 | |||
172 | mime = get_registry_classes_key (type, L"Content Type"); |
||
173 | if (mime) |
||
174 | return mime; |
||
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? */ |
||
182 | |||
183 | return g_strdup ("application/octet-stream"); |
||
184 | } |
||
185 | |||
186 | G_LOCK_DEFINE_STATIC (_type_icons); |
||
187 | static GHashTable *_type_icons = NULL; |
||
188 | |||
189 | GIcon * |
||
190 | g_content_type_get_icon (const gchar *type) |
||
191 | { |
||
192 | GIcon *themed_icon; |
||
193 | char *name = NULL; |
||
194 | |||
195 | g_return_val_if_fail (type != NULL, NULL); |
||
196 | |||
197 | /* In the Registry icons are the default value of |
||
198 | HKEY_CLASSES_ROOT\<progid>\DefaultIcon with typical values like: |
||
199 | <type>: <value> |
||
200 | REG_EXPAND_SZ: %SystemRoot%\System32\Wscript.exe,3 |
||
201 | REG_SZ: shimgvw.dll,3 |
||
202 | */ |
||
203 | G_LOCK (_type_icons); |
||
204 | if (!_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] == '.') |
||
208 | { |
||
209 | /* double lookup by extension */ |
||
210 | gchar *key = get_registry_classes_key (type, NULL); |
||
211 | if (!key) |
||
212 | key = g_strconcat (type+1, "file\\DefaultIcon", NULL); |
||
213 | else |
||
214 | { |
||
215 | gchar *key2 = g_strconcat (key, "\\DefaultIcon", NULL); |
||
216 | g_free (key); |
||
217 | key = key2; |
||
218 | } |
||
219 | name = get_registry_classes_key (key, NULL); |
||
220 | if (name && strcmp (name, "%1") == 0) |
||
221 | { |
||
222 | g_free (name); |
||
223 | name = NULL; |
||
224 | } |
||
225 | if (name) |
||
226 | g_hash_table_insert (_type_icons, g_strdup (type), g_strdup (name)); |
||
227 | g_free (key); |
||
228 | } |
||
229 | |||
230 | if (!name) |
||
231 | { |
||
232 | /* if no icon found, fall back to standard generic names */ |
||
233 | if (strcmp (type, "inode/directory") == 0) |
||
234 | name = "folder"; |
||
235 | else if (g_content_type_can_be_executable (type)) |
||
236 | name = "system-run"; |
||
237 | else |
||
238 | name = "text-x-generic"; |
||
239 | g_hash_table_insert (_type_icons, g_strdup (type), g_strdup (name)); |
||
240 | } |
||
241 | themed_icon = g_themed_icon_new (name); |
||
242 | G_UNLOCK (_type_icons); |
||
243 | |||
244 | return G_ICON (themed_icon); |
||
245 | } |
||
246 | |||
247 | GIcon * |
||
248 | g_content_type_get_symbolic_icon (const gchar *type) |
||
249 | { |
||
250 | return g_content_type_get_icon (type); |
||
251 | } |
||
252 | |||
253 | gchar * |
||
254 | g_content_type_get_generic_icon_name (const gchar *type) |
||
255 | { |
||
256 | return NULL; |
||
257 | } |
||
258 | |||
259 | gboolean |
||
260 | g_content_type_can_be_executable (const gchar *type) |
||
261 | { |
||
262 | g_return_val_if_fail (type != NULL, FALSE); |
||
263 | |||
264 | if (strcmp (type, ".exe") == 0 || |
||
265 | strcmp (type, ".com") == 0 || |
||
266 | strcmp (type, ".bat") == 0) |
||
267 | return TRUE; |
||
268 | |||
269 | /* TODO: Also look at PATHEXT, which lists the extensions for |
||
270 | * "scripts" in addition to those for true binary executables. |
||
271 | * |
||
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 |
||
277 | * with "executable". |
||
278 | */ |
||
279 | |||
280 | return FALSE; |
||
281 | } |
||
282 | |||
283 | static gboolean |
||
284 | looks_like_text (const guchar *data, |
||
285 | gsize data_size) |
||
286 | { |
||
287 | gsize i; |
||
288 | guchar c; |
||
289 | for (i = 0; i < data_size; i++) |
||
290 | { |
||
291 | c = data[i]; |
||
292 | if (g_ascii_iscntrl (c) && !g_ascii_isspace (c) && c != '\b') |
||
293 | return FALSE; |
||
294 | } |
||
295 | return TRUE; |
||
296 | } |
||
297 | |||
298 | gchar * |
||
299 | g_content_type_from_mime_type (const gchar *mime_type) |
||
300 | { |
||
301 | char *key, *content_type; |
||
302 | |||
303 | g_return_val_if_fail (mime_type != NULL, NULL); |
||
304 | |||
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); |
||
308 | |||
309 | key = g_strconcat ("MIME\\DataBase\\Content Type\\", mime_type, NULL); |
||
310 | content_type = get_registry_classes_key (key, L"Extension"); |
||
311 | g_free (key); |
||
312 | |||
313 | return content_type; |
||
314 | } |
||
315 | |||
316 | gchar * |
||
317 | g_content_type_guess (const gchar *filename, |
||
318 | const guchar *data, |
||
319 | gsize data_size, |
||
320 | gboolean *result_uncertain) |
||
321 | { |
||
322 | char *basename; |
||
323 | char *type; |
||
324 | char *dot; |
||
325 | |||
326 | type = NULL; |
||
327 | |||
328 | if (result_uncertain) |
||
329 | *result_uncertain = FALSE; |
||
330 | |||
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 ("*")); |
||
334 | |||
335 | if (filename) |
||
336 | { |
||
337 | basename = g_path_get_basename (filename); |
||
338 | dot = strrchr (basename, '.'); |
||
339 | if (dot) |
||
340 | type = g_strdup (dot); |
||
341 | g_free (basename); |
||
342 | } |
||
343 | |||
344 | if (type) |
||
345 | return type; |
||
346 | |||
347 | if (data && looks_like_text (data, data_size)) |
||
348 | return g_strdup (".txt"); |
||
349 | |||
350 | return g_strdup ("*"); |
||
351 | } |
||
352 | |||
353 | GList * |
||
354 | g_content_types_get_registered (void) |
||
355 | { |
||
356 | DWORD index; |
||
357 | wchar_t keyname[256]; |
||
358 | DWORD key_len; |
||
359 | char *key_utf8; |
||
360 | GList *types; |
||
361 | |||
362 | types = NULL; |
||
363 | index = 0; |
||
364 | key_len = 256; |
||
365 | while (RegEnumKeyExW(HKEY_CLASSES_ROOT, |
||
366 | index, |
||
367 | keyname, |
||
368 | &key_len, |
||
369 | NULL, |
||
370 | NULL, |
||
371 | NULL, |
||
372 | NULL) == ERROR_SUCCESS) |
||
373 | { |
||
374 | key_utf8 = g_utf16_to_utf8 (keyname, -1, NULL, NULL, NULL); |
||
375 | if (key_utf8) |
||
376 | { |
||
377 | if (*key_utf8 == '.') |
||
378 | types = g_list_prepend (types, key_utf8); |
||
379 | else |
||
380 | g_free (key_utf8); |
||
381 | } |
||
382 | index++; |
||
383 | key_len = 256; |
||
384 | } |
||
385 | |||
386 | return g_list_reverse (types); |
||
387 | } |
||
388 | |||
389 | gchar ** |
||
390 | g_content_type_guess_for_tree (GFile *root) |
||
391 | { |
||
392 | /* FIXME: implement */ |
||
393 | return NULL; |
||
394 | } |