Hit.cs: Remove FIXME by using binary search while searching properties.
[beagle.git] / chooser-fu / xdgmime.c
blobcbcd328a2d4ebe9138a5da3e246007f4ab34be34
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* xdgmime.c: XDG Mime Spec mime resolver. Based on version 0.11 of the spec.
4 * More info can be found at http://www.freedesktop.org/standards/
5 *
6 * Copyright (C) 2003 Red Hat, Inc.
7 * Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu>
9 * Licensed under the Academic Free License version 2.0
10 * Or under the following terms:
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the
24 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
28 #ifdef CONFIG_H
29 #include <config.h>
30 #endif
31 #include "xdgmime.h"
32 #include "xdgmimeint.h"
33 #include "xdgmimeglob.h"
34 #include "xdgmimemagic.h"
35 #include <stdio.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <unistd.h>
41 static int initted = 0;
42 static XdgGlobHash *global_hash = NULL;
43 static XdgMimeMagic *global_magic = NULL;
44 const char *xdg_mime_type_unknown = "application/octet-stream";
46 static void
47 _xdg_mime_init_from_directory (const char *directory)
49 char *file_name;
51 file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
52 strcpy (file_name, directory);
53 strcat (file_name, "/mime/globs");
54 _xdg_mime_glob_read_from_file (global_hash, file_name);
55 free (file_name);
57 file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
58 strcpy (file_name, directory);
59 strcat (file_name, "/mime/magic");
60 _xdg_mime_magic_read_from_file (global_magic, file_name);
61 free (file_name);
64 static void
65 xdg_mime_init (void)
67 if (initted == 0)
69 const char *xdg_data_home;
70 const char *xdg_data_dirs;
71 const char *ptr;
73 global_hash = _xdg_glob_hash_new ();
74 global_magic = _xdg_mime_magic_new ();
76 /* We look for globs and magic files based upon the XDG Base Directory
77 * Specification
79 xdg_data_home = getenv ("XDG_DATA_HOME");
80 if (xdg_data_home)
82 _xdg_mime_init_from_directory (xdg_data_home);
84 else
86 const char *home;
88 home = getenv ("HOME");
89 if (home != NULL)
91 char *guessed_xdg_home;
93 guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/") + 1);
94 strcpy (guessed_xdg_home, home);
95 strcat (guessed_xdg_home, "/.local/share/");
96 _xdg_mime_init_from_directory (guessed_xdg_home);
97 free (guessed_xdg_home);
101 xdg_data_dirs = getenv ("XDG_DATA_DIRS");
102 if (xdg_data_dirs == NULL)
103 xdg_data_dirs = "/usr/local/share/:/usr/share/";
105 ptr = xdg_data_dirs;
107 while (*ptr != '\000')
109 const char *end_ptr;
110 char *dir;
111 int len;
113 end_ptr = ptr;
114 while (*end_ptr != ':' && *end_ptr != '\000')
115 end_ptr ++;
117 if (end_ptr == ptr)
119 ptr++;
120 continue;
123 if (*end_ptr == ':')
124 len = end_ptr - ptr;
125 else
126 len = end_ptr - ptr + 1;
127 dir = malloc (len + 1);
128 strncpy (dir, ptr, len);
129 dir[len] = '\0';
130 _xdg_mime_init_from_directory (dir);
131 free (dir);
133 ptr = end_ptr;
135 initted = 1;
139 const char *
140 xdg_mime_get_mime_type_for_data (const void *data,
141 size_t len)
143 const char *mime_type;
145 xdg_mime_init ();
147 mime_type = _xdg_mime_magic_lookup_data (global_magic, data, len);
149 if (mime_type)
150 return mime_type;
152 return XDG_MIME_TYPE_UNKNOWN;
155 const char *
156 xdg_mime_get_mime_type_for_file (const char *file_name)
158 const char *mime_type;
159 FILE *file;
160 unsigned char *data;
161 int max_extent;
162 int bytes_read;
163 struct stat statbuf;
164 const char *base_name;
166 if (file_name == NULL)
167 return NULL;
168 if (! _xdg_utf8_validate (file_name))
169 return NULL;
171 xdg_mime_init ();
173 base_name = _xdg_get_base_name (file_name);
174 mime_type = xdg_mime_get_mime_type_from_file_name (base_name);
176 if (mime_type != XDG_MIME_TYPE_UNKNOWN)
177 return mime_type;
179 if (stat (file_name, &statbuf) != 0)
180 return XDG_MIME_TYPE_UNKNOWN;
182 if (!S_ISREG (statbuf.st_mode))
183 return XDG_MIME_TYPE_UNKNOWN;
185 /* FIXME: Need to make sure that max_extent isn't totally broken. This could
186 * be large and need getting from a stream instead of just reading it all
187 * in. */
188 max_extent = _xdg_mime_magic_get_buffer_extents (global_magic);
189 data = malloc (max_extent);
190 if (data == NULL)
191 return XDG_MIME_TYPE_UNKNOWN;
193 file = fopen (file_name, "r");
194 if (file == NULL)
196 free (data);
197 return XDG_MIME_TYPE_UNKNOWN;
200 bytes_read = fread (data, 1, max_extent, file);
201 if (ferror (file))
203 free (data);
204 fclose (file);
205 return XDG_MIME_TYPE_UNKNOWN;
208 mime_type = _xdg_mime_magic_lookup_data (global_magic, data, bytes_read);
210 free (data);
211 fclose (file);
213 if (mime_type)
214 return mime_type;
216 return XDG_MIME_TYPE_UNKNOWN;
219 const char *
220 xdg_mime_get_mime_type_from_file_name (const char *file_name)
222 const char *mime_type;
224 xdg_mime_init ();
226 mime_type = _xdg_glob_hash_lookup_file_name (global_hash, file_name);
227 if (mime_type)
228 return mime_type;
229 else
230 return XDG_MIME_TYPE_UNKNOWN;
234 xdg_mime_is_valid_mime_type (const char *mime_type)
236 /* FIXME: We should make this a better test
238 return _xdg_utf8_validate (mime_type);
241 void
242 xdg_mime_shutdown (void)
244 /* FIXME: Need to make this (and the whole library) thread safe */
245 if (initted)
247 _xdg_glob_hash_free (global_hash);
248 global_hash = NULL;
250 _xdg_mime_magic_free (global_magic);
251 global_magic = NULL;
253 initted = 0;
258 xdg_mime_get_max_buffer_extents (void)
260 xdg_mime_init ();
262 return _xdg_mime_magic_get_buffer_extents (global_magic);