1
/* $Id: thunar-vfs-mime-legacy.c 18843 2005-11-14 14:25:58Z benny $ */
3
* Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Library General Public
7
* License as published by the Free Software Foundation; either
8
* version 2 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Library General Public License for more details.
15
* You should have received a copy of the GNU Library General Public
16
* License along with this library; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
20
* Based on code initially written by Matthias Clasen <mclasen@redhat.com>
21
* for the xdgmime library.
39
#include <thunar-vfs/thunar-vfs-mime-legacy.h>
43
#define THUNAR_VFS_MIME_LEGACY_GLOB(obj) ((ThunarVfsMimeLegacyGlob *) (obj))
44
#define THUNAR_VFS_MIME_LEGACY_SUFFIX(obj) ((ThunarVfsMimeLegacySuffix *) (obj))
48
typedef struct _ThunarVfsMimeLegacyGlob ThunarVfsMimeLegacyGlob;
49
typedef struct _ThunarVfsMimeLegacySuffix ThunarVfsMimeLegacySuffix;
53
static void thunar_vfs_mime_legacy_class_init (ThunarVfsMimeLegacyClass *klass);
54
static void thunar_vfs_mime_legacy_init (ThunarVfsMimeLegacy *legacy);
55
static void thunar_vfs_mime_legacy_finalize (GObject *object);
56
static const gchar *thunar_vfs_mime_legacy_lookup_data (ThunarVfsMimeProvider *provider,
60
static const gchar *thunar_vfs_mime_legacy_lookup_literal (ThunarVfsMimeProvider *provider,
61
const gchar *filename);
62
static const gchar *thunar_vfs_mime_legacy_lookup_suffix (ThunarVfsMimeProvider *provider,
64
gboolean ignore_case);
65
static const gchar *thunar_vfs_mime_legacy_lookup_glob (ThunarVfsMimeProvider *provider,
66
const gchar *filename);
67
static const gchar *thunar_vfs_mime_legacy_lookup_alias (ThunarVfsMimeProvider *provider,
69
static guint thunar_vfs_mime_legacy_lookup_parents (ThunarVfsMimeProvider *provider,
70
const gchar *mime_type,
73
static GList *thunar_vfs_mime_legacy_get_stop_characters (ThunarVfsMimeProvider *provider);
74
static gsize thunar_vfs_mime_legacy_get_max_buffer_extents (ThunarVfsMimeProvider *provider);
75
static void thunar_vfs_mime_legacy_parse_aliases (ThunarVfsMimeLegacy *legacy,
76
const gchar *directory);
77
static gboolean thunar_vfs_mime_legacy_parse_globs (ThunarVfsMimeLegacy *legacy,
78
const gchar *directory);
79
static void thunar_vfs_mime_legacy_parse_subclasses (ThunarVfsMimeLegacy *legacy,
80
const gchar *directory);
84
struct _ThunarVfsMimeLegacyClass
86
ThunarVfsMimeProviderClass __parent__;
89
struct _ThunarVfsMimeLegacy
91
ThunarVfsMimeProvider __parent__;
93
GStringChunk *string_chunk;
94
GMemChunk *suffix_chunk;
95
GMemChunk *glob_chunk;
98
ThunarVfsMimeLegacySuffix *suffixes;
105
struct _ThunarVfsMimeLegacyGlob
107
const gchar *pattern;
108
const gchar *mime_type;
111
struct _ThunarVfsMimeLegacySuffix
113
ThunarVfsMimeLegacySuffix *child;
114
ThunarVfsMimeLegacySuffix *next;
115
const gchar *mime_type;
121
static GObjectClass *thunar_vfs_mime_legacy_parent_class;
126
thunar_vfs_mime_legacy_get_type (void)
128
static GType type = G_TYPE_INVALID;
130
if (G_UNLIKELY (type == G_TYPE_INVALID))
132
static const GTypeInfo info =
134
sizeof (ThunarVfsMimeLegacyClass),
137
(GClassInitFunc) thunar_vfs_mime_legacy_class_init,
140
sizeof (ThunarVfsMimeLegacy),
142
(GInstanceInitFunc) thunar_vfs_mime_legacy_init,
146
type = g_type_register_static (THUNAR_VFS_TYPE_MIME_PROVIDER,
147
"ThunarVfsMimeLegacy", &info, 0);
156
thunar_vfs_mime_legacy_class_init (ThunarVfsMimeLegacyClass *klass)
158
ThunarVfsMimeProviderClass *thunarvfs_mime_provider_class;
159
GObjectClass *gobject_class;
161
thunar_vfs_mime_legacy_parent_class = g_type_class_peek_parent (klass);
163
gobject_class = G_OBJECT_CLASS (klass);
164
gobject_class->finalize = thunar_vfs_mime_legacy_finalize;
166
thunarvfs_mime_provider_class = THUNAR_VFS_MIME_PROVIDER_CLASS (klass);
167
thunarvfs_mime_provider_class->lookup_data = thunar_vfs_mime_legacy_lookup_data;
168
thunarvfs_mime_provider_class->lookup_literal = thunar_vfs_mime_legacy_lookup_literal;
169
thunarvfs_mime_provider_class->lookup_suffix = thunar_vfs_mime_legacy_lookup_suffix;
170
thunarvfs_mime_provider_class->lookup_glob = thunar_vfs_mime_legacy_lookup_glob;
171
thunarvfs_mime_provider_class->lookup_alias = thunar_vfs_mime_legacy_lookup_alias;
172
thunarvfs_mime_provider_class->lookup_parents = thunar_vfs_mime_legacy_lookup_parents;
173
thunarvfs_mime_provider_class->get_stop_characters = thunar_vfs_mime_legacy_get_stop_characters;
174
thunarvfs_mime_provider_class->get_max_buffer_extents = thunar_vfs_mime_legacy_get_max_buffer_extents;
180
thunar_vfs_mime_legacy_init (ThunarVfsMimeLegacy *legacy)
182
legacy->string_chunk = g_string_chunk_new (1024);
183
legacy->glob_chunk = g_mem_chunk_create (ThunarVfsMimeLegacyGlob, 32, G_ALLOC_ONLY);
184
legacy->suffix_chunk = g_mem_chunk_create (ThunarVfsMimeLegacySuffix, 128, G_ALLOC_ONLY);
186
legacy->literals = g_hash_table_new (g_str_hash, g_str_equal);
188
legacy->aliases = g_hash_table_new (g_str_hash, g_str_equal);
189
legacy->parents = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_list_free);
195
thunar_vfs_mime_legacy_finalize (GObject *object)
197
ThunarVfsMimeLegacy *legacy = THUNAR_VFS_MIME_LEGACY (object);
199
/* free parents hash table */
200
g_hash_table_destroy (legacy->parents);
202
/* free aliases hash table */
203
g_hash_table_destroy (legacy->aliases);
205
/* free the list of globs */
206
g_list_free (legacy->globs);
208
/* free literals hash table */
209
g_hash_table_destroy (legacy->literals);
212
g_string_chunk_free (legacy->string_chunk);
213
g_mem_chunk_destroy (legacy->suffix_chunk);
214
g_mem_chunk_destroy (legacy->glob_chunk);
216
(*G_OBJECT_CLASS (thunar_vfs_mime_legacy_parent_class)->finalize) (object);
222
thunar_vfs_mime_legacy_lookup_data (ThunarVfsMimeProvider *provider,
233
thunar_vfs_mime_legacy_lookup_literal (ThunarVfsMimeProvider *provider,
234
const gchar *filename)
236
return g_hash_table_lookup (THUNAR_VFS_MIME_LEGACY (provider)->literals, filename);
241
static ThunarVfsMimeLegacySuffix*
242
suffix_insert (ThunarVfsMimeLegacy *legacy,
243
ThunarVfsMimeLegacySuffix *suffix_node,
244
const gchar *pattern,
245
const gchar *mime_type)
247
ThunarVfsMimeLegacySuffix *previous;
248
ThunarVfsMimeLegacySuffix *node;
249
gboolean found_node = FALSE;
252
character = g_utf8_get_char (pattern);
254
if (suffix_node == NULL || character < suffix_node->character)
256
node = g_chunk_new0 (ThunarVfsMimeLegacySuffix, legacy->suffix_chunk);
257
node->next = suffix_node;
258
node->character = character;
261
else if (character == suffix_node->character)
267
for (previous = suffix_node, node = previous->next; node != NULL; previous = node, node = node->next)
269
if (character < node->character)
271
node = g_chunk_new0 (ThunarVfsMimeLegacySuffix, legacy->suffix_chunk);
272
node->next = previous->next;
273
node->character = character;
274
previous->next = node;
278
else if (character == node->character)
287
node = g_chunk_new0 (ThunarVfsMimeLegacySuffix, legacy->suffix_chunk);
288
node->next = previous->next;
289
node->character = character;
290
previous->next = node;
294
pattern = g_utf8_next_char (pattern);
295
if (G_UNLIKELY (*pattern == '\0'))
296
node->mime_type = mime_type;
298
node->child = suffix_insert (legacy, node->child, pattern, mime_type);
306
suffix_lookup (ThunarVfsMimeLegacySuffix *suffix_node,
307
const gchar *filename,
308
gboolean ignore_case)
310
ThunarVfsMimeLegacySuffix *node;
313
if (G_UNLIKELY (suffix_node == NULL))
316
character = g_utf8_get_char (filename);
317
if (G_UNLIKELY (ignore_case))
318
character = g_unichar_tolower (character);
320
for (node = suffix_node; node != NULL && character >= node->character; node = node->next)
321
if (character == node->character)
323
filename = g_utf8_next_char (filename);
324
if (*filename == '\0')
325
return node->mime_type;
327
return suffix_lookup (node->child, filename, ignore_case);
336
thunar_vfs_mime_legacy_lookup_suffix (ThunarVfsMimeProvider *provider,
338
gboolean ignore_case)
340
return suffix_lookup (THUNAR_VFS_MIME_LEGACY (provider)->suffixes, suffix, ignore_case);
346
thunar_vfs_mime_legacy_lookup_glob (ThunarVfsMimeProvider *provider,
347
const gchar *filename)
351
for (lp = THUNAR_VFS_MIME_LEGACY (provider)->globs; lp != NULL; lp = lp->next)
352
if (fnmatch (THUNAR_VFS_MIME_LEGACY_GLOB (lp->data)->pattern, filename, 0) == 0)
353
return THUNAR_VFS_MIME_LEGACY_GLOB (lp->data)->mime_type;
361
thunar_vfs_mime_legacy_lookup_alias (ThunarVfsMimeProvider *provider,
364
return g_hash_table_lookup (THUNAR_VFS_MIME_LEGACY (provider)->aliases, alias);
370
thunar_vfs_mime_legacy_lookup_parents (ThunarVfsMimeProvider *provider,
371
const gchar *mime_type,
378
/* determine the known parents for the MIME-type */
379
lp = g_hash_table_lookup (THUNAR_VFS_MIME_LEGACY (provider)->parents, mime_type);
380
for (; lp != NULL && n < max_parents; lp = lp->next, ++n, ++parents)
389
thunar_vfs_mime_legacy_get_stop_characters (ThunarVfsMimeProvider *provider)
391
ThunarVfsMimeLegacySuffix *node;
392
GList *stopchars = NULL;
394
for (node = THUNAR_VFS_MIME_LEGACY (provider)->suffixes; node != NULL; node = node->next)
395
if (node->character < 128u)
396
stopchars = g_list_prepend (stopchars, GUINT_TO_POINTER (node->character));
404
thunar_vfs_mime_legacy_get_max_buffer_extents (ThunarVfsMimeProvider *provider)
412
thunar_vfs_mime_legacy_parse_aliases (ThunarVfsMimeLegacy *legacy,
413
const gchar *directory)
422
/* try to open the "aliases" file */
423
path = g_build_filename (directory, "aliases", NULL);
424
fp = fopen (path, "r");
427
/* check if we succeed */
428
if (G_UNLIKELY (fp == NULL))
431
/* parse all aliases */
432
while (fgets (line, sizeof (line), fp) != NULL)
434
/* skip whitespace/comments */
435
for (lp = line; g_ascii_isspace (*lp); ++lp);
436
if (G_UNLIKELY (*lp == '\0' || *lp == '#'))
439
/* extract the alias name */
440
for (alias = lp; *lp != '\0' && !g_ascii_isspace (*lp); ++lp);
441
if (G_UNLIKELY (*lp == '\0' || alias == lp))
445
/* skip whitespace */
446
for (; G_UNLIKELY (g_ascii_isspace (*lp)); ++lp);
447
if (G_UNLIKELY (*lp == '\0'))
450
/* extract the MIME-type name */
451
for (name = lp; *lp != '\0' && *lp != '\n' && *lp != '\r'; ++lp);
452
if (G_UNLIKELY (name == lp))
456
/* insert the alias into the string chunk */
457
alias = g_string_chunk_insert_const (legacy->string_chunk, alias);
459
/* insert the MIME-type name into the string chunk */
460
name = g_string_chunk_insert_const (legacy->string_chunk, name);
462
/* insert the association into the aliases hash table */
463
g_hash_table_insert (legacy->aliases, alias, name);
472
thunar_vfs_mime_legacy_parse_globs (ThunarVfsMimeLegacy *legacy,
473
const gchar *directory)
475
ThunarVfsMimeLegacyGlob *glob;
483
/* try to open the "globs" file */
484
path = g_build_filename (directory, "globs", NULL);
485
fp = fopen (path, "r");
488
/* cannot continue */
489
if (G_UNLIKELY (fp == NULL))
492
/* parse all globs */
493
while (fgets (line, sizeof (line), fp) != NULL)
495
/* skip whitespace/comments */
496
for (lp = line; g_ascii_isspace (*lp); ++lp);
497
if (*lp == '\0' || *lp == '#')
500
/* extract the MIME-type name */
501
for (name = lp; *lp != '\0' && *lp != ':'; ++lp);
502
if (*lp == '\0' || name == lp)
505
/* extract the pattern */
506
for (*lp = '\0', pattern = ++lp; *lp != '\0' && *lp != '\n' && *lp != '\r'; ++lp);
508
if (*pattern == '\0')
511
/* insert the name into the string chunk */
512
name = g_string_chunk_insert_const (legacy->string_chunk, name);
514
/* determine the type of the pattern */
515
if (strpbrk (pattern, "*?[") == NULL)
517
g_hash_table_insert (legacy->literals, g_string_chunk_insert (legacy->string_chunk, pattern), name);
519
else if (pattern[0] == '*' && pattern[1] == '.' && strpbrk (pattern + 2, "*?[") == NULL)
521
legacy->suffixes = suffix_insert (legacy, legacy->suffixes, pattern + 1, name);
525
glob = g_chunk_new (ThunarVfsMimeLegacyGlob, legacy->glob_chunk);
526
glob->pattern = g_string_chunk_insert (legacy->string_chunk, pattern);
527
glob->mime_type = name;
528
legacy->globs = g_list_append (legacy->globs, glob);
540
thunar_vfs_mime_legacy_parse_subclasses (ThunarVfsMimeLegacy *legacy,
541
const gchar *directory)
551
/* try to open the "subclasses" file */
552
path = g_build_filename (directory, "subclasses", NULL);
553
fp = fopen (path, "r");
556
/* check if we succeed */
557
if (G_UNLIKELY (fp == NULL))
560
/* parse all subclasses */
561
while (fgets (line, sizeof (line), fp) != NULL)
563
/* skip whitespace/comments */
564
for (lp = line; g_ascii_isspace (*lp); ++lp);
565
if (G_UNLIKELY (*lp == '\0' || *lp == '#'))
568
/* extract the subclass name */
569
for (subclass = lp; *lp != '\0' && !g_ascii_isspace (*lp); ++lp);
570
if (G_UNLIKELY (*lp == '\0' || subclass == lp))
574
/* skip whitespace */
575
for (; G_UNLIKELY (g_ascii_isspace (*lp)); ++lp);
576
if (G_UNLIKELY (*lp == '\0'))
579
/* extract the MIME-type name */
580
for (name = lp; *lp != '\0' && *lp != '\n' && *lp != '\r'; ++lp);
581
if (G_UNLIKELY (name == lp))
585
/* insert the subclass into the string chunk */
586
subclass = g_string_chunk_insert_const (legacy->string_chunk, subclass);
588
/* insert the MIME-type name into the string chunk */
589
name = g_string_chunk_insert_const (legacy->string_chunk, name);
591
/* add the MIME-type name to the list of parents for the subclass */
592
parents = g_hash_table_lookup (legacy->parents, subclass);
593
if (G_UNLIKELY (parents != NULL))
594
parents = g_list_copy (parents);
595
parents = g_list_append (parents, name);
596
g_hash_table_insert (legacy->parents, subclass, parents);
605
* thunar_vfs_mime_legacy_new:
606
* @directory : an XDG mime base directory.
608
* Allocates a new #ThunarVfsMimeLegacy for @directory and
609
* returns the instance on success, or %NULL on error.
611
* The caller is responsible to free the returned instance
612
* using g_object_unref().
614
* Return value: the newly allocated #ThunarVfsMimeLegacy
615
* instance or %NULL on error.
617
ThunarVfsMimeProvider*
618
thunar_vfs_mime_legacy_new (const gchar *directory)
620
ThunarVfsMimeLegacy *legacy;
622
/* allocate the new object */
623
legacy = g_object_new (THUNAR_VFS_TYPE_MIME_LEGACY, NULL);
625
/* try to parse the globs file */
626
if (!thunar_vfs_mime_legacy_parse_globs (legacy, directory))
628
g_object_unref (legacy);
632
/* parse the aliases file (optional) */
633
thunar_vfs_mime_legacy_parse_aliases (legacy, directory);
635
/* parse the subclasses file (optional) */
636
thunar_vfs_mime_legacy_parse_subclasses (legacy, directory);
639
return THUNAR_VFS_MIME_PROVIDER (legacy);