summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-08-23 11:59:37 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-08-23 12:04:06 +0900
commit561f8eaa8faebe32b9a03cf9674c147cf0d6d9ab (patch)
tree150e42dcb87333b146e884f6bf72dc5f561e7967
parent56c52311e5590543272b0465a750936475ad28e7 (diff)
efreet - save about 240-300k or so of memory used by efreet mime
so efreet mime was loading a bunch of mime type info files, parsing them on startup and allocating memory to store all this mime info - globs, mimetype strings and more. all a big waste of memory as its allocated on the heap per process where its the SAME data files loaded every time. so make an efreet mime cache file and a tool to create it from mime files. mmap this file with all the hashes/strings in it so all that data is mmaped once in memory and shared between all processes and it is only paged in on demand - as actually read/needed so if your process doesnt need to know about mime stuff.. it wont touch it anyway. this saves about 240-300k or so of memory in my tests. this has not covered the mime MAGIC files which still consume memory and are on the heap. this is more complex so it will take more time to come up with a nice file format for the data that is nicely mmaped etc. @optimize
-rw-r--r--src/Makefile_Efreet.am8
-rw-r--r--src/bin/efreet/.gitignore1
-rw-r--r--src/bin/efreet/efreet_mime_cache_create.c453
-rw-r--r--src/bin/efreet/efreetd_cache.c124
-rw-r--r--src/bin/efreet/efreetd_ipc.c6
-rw-r--r--src/bin/efreet/efreetd_ipc.h1
-rw-r--r--src/examples/elementary/codegen_example_generated.c132
-rw-r--r--src/examples/elementary/codegen_example_generated.h65
-rw-r--r--src/lib/efreet/efreet_cache.c6
-rw-r--r--src/lib/efreet/efreet_mime.c618
-rw-r--r--src/lib/efreet/efreet_private.h2
11 files changed, 843 insertions, 573 deletions
diff --git a/src/Makefile_Efreet.am b/src/Makefile_Efreet.am
index 32d433016d..fe969f935c 100644
--- a/src/Makefile_Efreet.am
+++ b/src/Makefile_Efreet.am
@@ -90,7 +90,8 @@ bin_efreet_efreetd_DEPENDENCIES = @USE_EFREET_INTERNAL_LIBS@
90efreetinternal_bindir=$(libdir)/efreet/$(MODULE_ARCH) 90efreetinternal_bindir=$(libdir)/efreet/$(MODULE_ARCH)
91efreetinternal_bin_PROGRAMS = \ 91efreetinternal_bin_PROGRAMS = \
92bin/efreet/efreet_desktop_cache_create \ 92bin/efreet/efreet_desktop_cache_create \
93bin/efreet/efreet_icon_cache_create 93bin/efreet/efreet_icon_cache_create \
94bin/efreet/efreet_mime_cache_create
94 95
95bin_efreet_efreet_desktop_cache_create_CPPFLAGS = -I$(top_builddir)/src/lib/efl $(EFREET_COMMON_CPPFLAGS) 96bin_efreet_efreet_desktop_cache_create_CPPFLAGS = -I$(top_builddir)/src/lib/efl $(EFREET_COMMON_CPPFLAGS)
96bin_efreet_efreet_desktop_cache_create_LDADD = $(USE_EFREET_BIN_LIBS) 97bin_efreet_efreet_desktop_cache_create_LDADD = $(USE_EFREET_BIN_LIBS)
@@ -102,6 +103,11 @@ bin_efreet_efreet_icon_cache_create_LDADD = $(USE_EFREET_BIN_LIBS)
102bin_efreet_efreet_icon_cache_create_DEPENDENCIES = @USE_EFREET_INTERNAL_LIBS@ 103bin_efreet_efreet_icon_cache_create_DEPENDENCIES = @USE_EFREET_INTERNAL_LIBS@
103bin_efreet_efreet_icon_cache_create_SOURCES = bin/efreet/efreet_icon_cache_create.c 104bin_efreet_efreet_icon_cache_create_SOURCES = bin/efreet/efreet_icon_cache_create.c
104 105
106bin_efreet_efreet_mime_cache_create_CPPFLAGS = -I$(top_builddir)/src/lib/efl $(EFREET_COMMON_CPPFLAGS)
107bin_efreet_efreet_mime_cache_create_LDADD = $(USE_EFREET_BIN_LIBS)
108bin_efreet_efreet_mime_cache_create_DEPENDENCIES = @USE_EFREET_INTERNAL_LIBS@
109bin_efreet_efreet_mime_cache_create_SOURCES = bin/efreet/efreet_mime_cache_create.c
110
105### Unit tests 111### Unit tests
106 112
107if EFL_ENABLE_TESTS 113if EFL_ENABLE_TESTS
diff --git a/src/bin/efreet/.gitignore b/src/bin/efreet/.gitignore
index 76fc57659f..f6ff3d04e7 100644
--- a/src/bin/efreet/.gitignore
+++ b/src/bin/efreet/.gitignore
@@ -1,3 +1,4 @@
1/efreet_desktop_cache_create 1/efreet_desktop_cache_create
2/efreet_icon_cache_create 2/efreet_icon_cache_create
3/efreetd 3/efreetd
4/efreet_mime_cache_create
diff --git a/src/bin/efreet/efreet_mime_cache_create.c b/src/bin/efreet/efreet_mime_cache_create.c
new file mode 100644
index 0000000000..8f8b0a1f88
--- /dev/null
+++ b/src/bin/efreet/efreet_mime_cache_create.c
@@ -0,0 +1,453 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4#include <sys/stat.h>
5#include <fcntl.h>
6#include <unistd.h>
7#include <errno.h>
8#ifdef HAVE_SYS_RESOURCE_H
9#include <sys/time.h>
10#include <sys/resource.h>
11#endif
12#ifdef _WIN32
13# include <winsock2.h>
14#endif
15#include <libgen.h>
16#include <ctype.h>
17
18#include <Eina.h>
19#include <Eet.h>
20#include <Ecore.h>
21#include <Ecore_File.h>
22
23#ifndef O_BINARY
24# define O_BINARY 0
25#endif
26
27#define EFREET_MODULE_LOG_DOM _efreet_mime_cache_log_dom
28static int _efreet_mime_cache_log_dom = -1;
29static Eina_List *extra_dirs = NULL;
30
31static Eina_Hash *mimes = NULL;
32static Eina_Hash *extn_mimes = NULL;
33static Eina_Hash *glob_mimes = NULL;
34static Eina_List *mimes_sorted = NULL;
35static Eina_List *extn_mimes_sorted = NULL;
36static Eina_List *glob_mimes_sorted = NULL;
37
38#include "Efreet.h"
39#include "efreet_private.h"
40#include "efreet_cache_private.h"
41
42static int
43cache_lock_file(void)
44{
45 char file[PATH_MAX];
46 struct flock fl;
47 int lockfd;
48
49 snprintf(file, sizeof(file), "%s/efreet/mime_data.lock", efreet_cache_home_get());
50 lockfd = open(file, O_CREAT | O_BINARY | O_RDWR, S_IRUSR | S_IWUSR);
51 if (lockfd < 0) return -1;
52 efreet_fsetowner(lockfd);
53
54 memset(&fl, 0, sizeof(struct flock));
55 fl.l_type = F_WRLCK;
56 fl.l_whence = SEEK_SET;
57 if (fcntl(lockfd, F_SETLK, &fl) < 0)
58 {
59 INF("LOCKED! You may want to delete %s if this persists", file);
60 close(lockfd);
61 return -1;
62 }
63
64 return lockfd;
65}
66
67static int
68hash_list_sort_insert_cmp(const char *key1, const char *key2)
69{
70 return strcmp(key1, key2);
71}
72
73static Eina_Bool
74hash_list_sort_each(const Eina_Hash *hash EINA_UNUSED, const void *key, void *value EINA_UNUSED, void *data)
75{
76 Eina_List **list = data;
77 *list = eina_list_sorted_insert(*list,
78 EINA_COMPARE_CB(hash_list_sort_insert_cmp),
79 key);
80 return EINA_TRUE;
81}
82
83static void
84hash_list_sort(Eina_Hash *hash, Eina_List **list)
85{
86 eina_hash_foreach(hash, hash_list_sort_each, list);
87}
88
89static void
90etc_mime_types_load(const char *file)
91{
92 int len;
93 char buf[4096], buf2[4096], buf3[4096], *p, *p2;
94 const char *mime;
95 FILE *f = fopen(file, "r");
96
97 if (!f) return;
98 while (fgets(buf, sizeof(buf), f))
99 {
100 // remove newline at end of line string if there
101 buf[sizeof(buf) - 1] = 0;
102 len = strlen(buf);
103 if ((len > 0) && (buf[len - 1] == '\n')) buf[len - 1] = 0;
104 // buf: "# comment"
105 // or
106 // buf: "mime/type"
107 // buf: "mime/type "
108 // buf: "mime/type ext1"
109 // buf: "mime/type ext1 ext2"
110 // buf: "mime/type ext1 ext2 ext3"
111 // ...
112 p = buf;
113 // find first token in line
114 while ((*p) && isspace(*p)) p++;
115 // if comment - skip line
116 if (*p == '#') continue;
117 p2 = p;
118 while ((*p2) && !isspace(*p2)) p2++;
119 // token is between p and p2 (not including p2)
120 strncpy(buf2, p, p2 - p);
121 buf2[p2 - p] = 0;
122 mime = eina_stringshare_add(buf2);
123 // buf2 is now the mime type token
124 eina_hash_del(mimes, buf2, NULL);
125 eina_hash_add(mimes, buf2, mime);
126 // now lookf for all extension tokens;
127 p = p2;
128 // find next token in line
129 while ((*p) && isspace(*p)) p++;
130 while (*p)
131 {
132 // find end of token
133 p2 = p;
134 while ((*p2) && !isspace(*p2)) p2++;
135 // buf3 is now the extension token
136 strncpy(buf3, p, p2 - p);
137 buf3[p2 - p] = 0;
138 eina_hash_del(extn_mimes, buf3, NULL);
139 eina_hash_add(extn_mimes, buf3, mime);
140 // go to next token if any
141 p = p2;
142 while ((*p) && isspace(*p)) p++;
143 }
144 }
145 fclose(f);
146}
147
148static void
149share_mime_globs_load(const char *file)
150{
151 int len;
152 char buf[4096], buf2[4096], buf3[4096], *p, *p2;
153 const char *mime;
154 FILE *f = fopen(file, "r");
155
156 if (!f) return;
157 while (fgets(buf, sizeof(buf), f))
158 {
159 // remove newline at end of line string if there
160 buf[sizeof(buf) - 1] = 0;
161 len = strlen(buf);
162 if ((len > 0) && (buf[len - 1] == '\n')) buf[len - 1] = 0;
163 // buf: "# comment"
164 // or
165 // buf: "mime/type:glob"
166 // ...
167 p = buf;
168 // find first token in line
169 while ((*p) && isspace(*p)) p++;
170 // if comment - skip line
171 if (*p == '#') continue;
172 p2 = p;
173 while ((*p2) && (*p2 != ':')) p2++;
174 // token is between p and p2 (not including p2)
175 strncpy(buf2, p, p2 - p);
176 buf2[p2 - p] = 0;
177 mime = eina_stringshare_add(buf2);
178 // buf2 is now the mime type token
179 eina_hash_del(mimes, buf2, NULL);
180 eina_hash_add(mimes, buf2, mime);
181 // now lookf for all extension tokens;
182 p = p2;
183 // find next token in line
184 while ((*p) && (*p == ':')) p++;
185 // find end of token
186 p2 = p;
187 while ((*p2) && !isspace(*p2)) p2++;
188 // buf3 is now the extension token
189 strncpy(buf3, p, p2 - p);
190 buf3[p2 - p] = 0;
191 // for a shortcut a glob of "*.xxx" is the same as just an ext of "xxx"
192 // so if this is the case then put into the extn mimes not
193 // the globl mimes for speed of lookup later on
194 if ((buf3[0] == '*') && (buf3[1] == '.') &&
195 (!strchr(buf3 + 2, '*')) && (!strchr(buf3 + 2, '?')) &&
196 (!strchr(buf3 + 2, '[')) && (!strchr(buf3 + 2, ']')) &&
197 (!strchr(buf3 + 2, '\\')))
198 {
199 eina_hash_del(extn_mimes, buf3 + 2, NULL);
200 eina_hash_add(extn_mimes, buf3 + 2, mime);
201 }
202 else
203 {
204 eina_hash_del(glob_mimes, buf3, NULL);
205 eina_hash_add(glob_mimes, buf3, mime);
206 }
207 }
208 fclose(f);
209}
210
211static void *
212find_off(const char *str, Eina_List *strlist, Eina_List *offlist)
213{
214 Eina_List *l, *ll;
215 const char *s;
216
217 ll = offlist;
218 EINA_LIST_FOREACH(strlist, l, s)
219 {
220 if (!strcmp(str, s)) return ll->data;
221 ll = ll->next;
222 }
223 return (void *)-1;
224}
225static void
226store_cache(const char *out)
227{
228 char buf[PATH_MAX];
229 FILE *f;
230 size_t mimes_str_len = 0;
231 size_t extn_mimes_str_len = 0;
232 size_t glob_mimes_str_len = 0;
233 size_t str_start;
234 Eina_List *mimes_str_offsets = NULL;
235 Eina_List *extn_mimes_str_offsets = NULL;
236 Eina_List *glob_mimes_str_offsets = NULL;
237 Eina_List *l, *ll;
238 const char *s;
239 void *ptr;
240 unsigned int val;
241
242 snprintf(buf, sizeof(buf), "%s.tmp", out);
243 f = fopen(buf, "wb");
244 if (!f) return;
245 // write file magic - first 16 bytes
246 fwrite("EfrEeT-MiMeS-001", 16, 1, f);
247 // note: all offsets are in bytes from start of file
248 //
249 // "EfrEeT-MiMeS-001" <- magic 16 byte header
250 // [int] <- size of mimes array in number of entries
251 // [int] <- str byte offset of 1st mime string (sorted)
252 // [int] <- str byte offset of 2nd mime string
253 // ...
254 // [int] <- size of extn_mimes array in number of entries
255 // [int] <- str byte offset of 1st extn string (sorted)
256 // [int] <- str byte offset of 1st mime string
257 // [int] <- str byte offset of 2nd extn string
258 // [int] <- str byte offset of 2nd mine string
259 // ...
260 // [int] <- size of globs array in number of entries
261 // [int] <- str byte offset of 1st glob string (sorted)
262 // [int] <- str byte offset of 1st mime string
263 // [int] <- str byte offset of 2nd glob string
264 // [int] <- str byte offset of 2nd mime string
265 // ...
266 // strine1\0string2\0string3\0string4\0....
267 EINA_LIST_FOREACH(mimes_sorted, l, s)
268 {
269 mimes_str_offsets = eina_list_append(mimes_str_offsets,
270 (void *)mimes_str_len);
271 mimes_str_len += strlen(s) + 1;
272 }
273 EINA_LIST_FOREACH(extn_mimes_sorted, l, s)
274 {
275 extn_mimes_str_offsets = eina_list_append(extn_mimes_str_offsets,
276 (void *)extn_mimes_str_len);
277 extn_mimes_str_len += strlen(s) + 1;
278 }
279 EINA_LIST_FOREACH(glob_mimes_sorted, l, s)
280 {
281 glob_mimes_str_offsets = eina_list_append(glob_mimes_str_offsets,
282 (void *)glob_mimes_str_len);
283 glob_mimes_str_len += strlen(s) + 1;
284 }
285
286 str_start = 16 + // magic header
287 sizeof(int) +
288 (eina_list_count(mimes_sorted) * sizeof(int)) +
289 sizeof(int) +
290 (eina_list_count(extn_mimes_sorted) * sizeof(int) * 2) +
291 sizeof(int) +
292 (eina_list_count(glob_mimes_sorted) * sizeof(int) * 2);
293
294 val = eina_list_count(mimes_sorted);
295 fwrite(&val, sizeof(val), 1, f);
296 EINA_LIST_FOREACH(mimes_str_offsets, l, ptr)
297 {
298 val = (int)((long)ptr) + str_start;
299 fwrite(&val, sizeof(val), 1, f);
300 }
301
302 val = eina_list_count(extn_mimes_sorted);
303 fwrite(&val, sizeof(val), 1, f);
304 ll = extn_mimes_sorted;
305 EINA_LIST_FOREACH(extn_mimes_str_offsets, l, ptr)
306 {
307 val = (int)((long)ptr) + str_start + mimes_str_len;
308 fwrite(&val, sizeof(val), 1, f);
309 s = eina_hash_find(extn_mimes, ll->data);
310 ptr = find_off(s, mimes_sorted, mimes_str_offsets);
311 val = (int)((long)ptr) + str_start;
312 fwrite(&val, sizeof(val), 1, f);
313 ll = ll->next;
314 }
315
316 val = eina_list_count(glob_mimes_sorted);
317 fwrite(&val, sizeof(val), 1, f);
318 ll = glob_mimes_sorted;
319 EINA_LIST_FOREACH(glob_mimes_str_offsets, l, ptr)
320 {
321 val = (int)((long)ptr) + str_start + mimes_str_len + extn_mimes_str_len;
322 fwrite(&val, sizeof(val), 1, f);
323 s = eina_hash_find(glob_mimes, ll->data);
324 ptr = find_off(s, mimes_sorted, mimes_str_offsets);
325 val = (int)((long)ptr) + str_start;
326 fwrite(&val, sizeof(val), 1, f);
327 ll = ll->next;
328 }
329 EINA_LIST_FOREACH(mimes_sorted, l, s)
330 {
331 fwrite(s, strlen(s) + 1, 1, f);
332 }
333 EINA_LIST_FOREACH(extn_mimes_sorted, l, s)
334 {
335 fwrite(s, strlen(s) + 1, 1, f);
336 }
337 EINA_LIST_FOREACH(glob_mimes_sorted, l, s)
338 {
339 fwrite(s, strlen(s) + 1, 1, f);
340 }
341 fclose(f);
342 rename(buf, out);
343}
344
345int
346main(int argc, char **argv)
347{
348 char buf[PATH_MAX];
349 const char *s;
350 int i;
351 int ret = -1, lockfd = -1;
352 Eina_List *datadirs, *l;
353
354 if (!eina_init()) goto eina_error;
355 if (!eet_init()) goto eet_error;
356 if (!ecore_init()) goto ecore_error;
357 if (!ecore_file_init()) goto ecore_file_error;
358 if (!efreet_init()) goto efreet_error;
359
360 _efreet_mime_cache_log_dom =
361 eina_log_domain_register("efreet_mime_cache", EFREET_DEFAULT_LOG_COLOR);
362 if (_efreet_mime_cache_log_dom < 0)
363 {
364 EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_mime_cache.");
365 return -1;
366 }
367
368 for (i = 1; i < argc; i++)
369 {
370 if (!strcmp(argv[i], "-v"))
371 eina_log_domain_level_set("efreet_mime_cache", EINA_LOG_LEVEL_DBG);
372 else if ((!strcmp(argv[i], "-h")) ||
373 (!strcmp(argv[i], "-help")) ||
374 (!strcmp(argv[i], "--h")) ||
375 (!strcmp(argv[i], "--help")))
376 {
377 printf("Options:\n");
378 printf(" -v Verbose mode\n");
379 printf(" -d dir1 dir2 Extra dirs\n");
380 exit(0);
381 }
382 else if (!strcmp(argv[i], "-d"))
383 {
384 while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-'))
385 extra_dirs = eina_list_append(extra_dirs, argv[++i]);
386 }
387 }
388 extra_dirs = eina_list_sort(extra_dirs, -1, EINA_COMPARE_CB(strcmp));
389
390 /* create homedir */
391 snprintf(buf, sizeof(buf), "%s/efreet", efreet_cache_home_get());
392 if (!ecore_file_exists(buf))
393 {
394 if (!ecore_file_mkpath(buf)) goto error;
395 efreet_setowner(buf);
396 }
397
398 /* lock process, so that we only run one copy of this program */
399 lockfd = cache_lock_file();
400 if (lockfd == -1) goto error;
401
402 mimes = eina_hash_string_superfast_new(NULL);
403 extn_mimes = eina_hash_string_superfast_new(NULL);
404 glob_mimes = eina_hash_string_superfast_new(NULL);
405
406 etc_mime_types_load("/etc/mime.types");
407 share_mime_globs_load("/usr/share/mime/globs");
408 datadirs = efreet_data_dirs_get();
409 EINA_LIST_FOREACH(datadirs, l, s)
410 {
411 snprintf(buf, sizeof(buf), "%s/mime/globs", s);
412 share_mime_globs_load(buf);
413 }
414 EINA_LIST_FOREACH(extra_dirs, l, s)
415 {
416 snprintf(buf, sizeof(buf), "%s/mime/globs", s);
417 share_mime_globs_load(buf);
418 }
419 snprintf(buf, sizeof(buf), "%s/mime/globs", efreet_data_home_get());
420 share_mime_globs_load(buf);
421 // XXX: load user files and other dirs etc.
422 // XXX: load globs
423
424 hash_list_sort(mimes, &mimes_sorted);
425 hash_list_sort(extn_mimes, &extn_mimes_sorted);
426 hash_list_sort(glob_mimes, &glob_mimes_sorted);
427
428#ifdef WORDS_BIGENDIAN
429 snprintf(buf, sizeof(buf), "%s/efreet/mime_cache_%s.be.dat",
430 efreet_cache_home_get(), efreet_hostname_get());
431#else
432 snprintf(buf, sizeof(buf), "%s/efreet/mime_cache_%s.le.dat",
433 efreet_cache_home_get(), efreet_hostname_get());
434#endif
435 store_cache(buf);
436
437 ret = 0;
438 close(lockfd);
439error:
440 efreet_shutdown();
441efreet_error:
442 ecore_file_shutdown();
443ecore_file_error:
444 ecore_shutdown();
445ecore_error:
446 eet_shutdown();
447eet_error:
448 eina_list_free(extra_dirs);
449 eina_log_domain_unregister(_efreet_mime_cache_log_dom);
450 eina_shutdown();
451eina_error:
452 return ret;
453}
diff --git a/src/bin/efreet/efreetd_cache.c b/src/bin/efreet/efreetd_cache.c
index fefc852dd0..b1ef5e8b81 100644
--- a/src/bin/efreet/efreetd_cache.c
+++ b/src/bin/efreet/efreetd_cache.c
@@ -71,6 +71,13 @@ static Eet_Data_Descriptor *subdir_dir_edd = NULL;
71static Subdir_Cache *subdir_cache = NULL; 71static Subdir_Cache *subdir_cache = NULL;
72static Eina_Bool subdir_need_save = EINA_FALSE; 72static Eina_Bool subdir_need_save = EINA_FALSE;
73 73
74static Eina_Hash *mime_monitors = NULL;
75static Ecore_Timer *mime_update_timer = NULL;
76static Ecore_Exe *mime_cache_exe = NULL;
77
78static void mime_cache_init(void);
79static void mime_cache_shutdown(void);
80
74static void 81static void
75subdir_cache_dir_free(Subdir_Cache_Dir *cd) 82subdir_cache_dir_free(Subdir_Cache_Dir *cd)
76{ 83{
@@ -756,6 +763,10 @@ cache_exe_data_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
756 if ((ev->lines) && (*ev->lines->line == 'c')) update = EINA_TRUE; 763 if ((ev->lines) && (*ev->lines->line == 'c')) update = EINA_TRUE;
757 send_signal_icon_cache_update(update); 764 send_signal_icon_cache_update(update);
758 } 765 }
766 else if (ev->exe == mime_cache_exe)
767 {
768 // XXX: ZZZ: handle stdout here from cache updater... if needed
769 }
759 return ECORE_CALLBACK_RENEW; 770 return ECORE_CALLBACK_RENEW;
760} 771}
761 772
@@ -774,6 +785,11 @@ cache_exe_del_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
774 icon_cache_exe = NULL; 785 icon_cache_exe = NULL;
775 if (icon_queue) cache_icon_update(EINA_FALSE); 786 if (icon_queue) cache_icon_update(EINA_FALSE);
776 } 787 }
788 else if (ev->exe == mime_cache_exe)
789 {
790 mime_cache_exe = NULL;
791 send_signal_mime_cache_build();
792 }
777 return ECORE_CALLBACK_RENEW; 793 return ECORE_CALLBACK_RENEW;
778} 794}
779 795
@@ -838,6 +854,111 @@ cache_desktop_exists(void)
838 return desktop_exists; 854 return desktop_exists;
839} 855}
840 856
857static void
858mime_update_launch(void)
859{
860 char file[PATH_MAX];
861
862 snprintf(file, sizeof(file),
863 "%s/efreet/" MODULE_ARCH "/efreet_mime_cache_create",
864 eina_prefix_lib_get(pfx));
865 mime_cache_exe = ecore_exe_pipe_run(file,
866 ECORE_EXE_PIPE_READ |
867 ECORE_EXE_PIPE_READ_LINE_BUFFERED,
868 NULL);
869}
870
871static Eina_Bool
872mime_update_cache_cb(void *data EINA_UNUSED)
873{
874 mime_update_timer = NULL;
875 if (mime_cache_exe)
876 {
877 ecore_exe_kill(mime_cache_exe);
878 ecore_exe_free(mime_cache_exe);
879 }
880 mime_update_launch();
881 return EINA_FALSE;
882}
883
884static void
885mime_changes_cb(void *data EINA_UNUSED, Ecore_File_Monitor *em EINA_UNUSED,
886 Ecore_File_Event event, const char *path EINA_UNUSED)
887{
888 switch (event)
889 {
890 case ECORE_FILE_EVENT_NONE:
891 /* noop */
892 break;
893
894 case ECORE_FILE_EVENT_CREATED_FILE:
895 case ECORE_FILE_EVENT_DELETED_FILE:
896 case ECORE_FILE_EVENT_MODIFIED:
897 case ECORE_FILE_EVENT_CLOSED:
898 case ECORE_FILE_EVENT_DELETED_DIRECTORY:
899 case ECORE_FILE_EVENT_CREATED_DIRECTORY:
900 case ECORE_FILE_EVENT_DELETED_SELF:
901 mime_cache_shutdown();
902 mime_cache_init();
903 if (mime_update_timer) ecore_timer_del(mime_update_timer);
904 mime_update_timer = ecore_timer_add(0.2, mime_update_cache_cb, NULL);
905 break;
906 }
907}
908
909static void
910mime_cache_init(void)
911{
912 Ecore_File_Monitor *mon;
913 Eina_List *datadirs, *l;
914 const char *s;
915 char buf[PATH_MAX];
916
917 mime_monitors = eina_hash_string_superfast_new(NULL);
918
919 mon = ecore_file_monitor_add("/etc/mime.types", mime_changes_cb, NULL);
920 if (mon) eina_hash_add(mime_monitors, "/etc/mime.types", mon);
921 mon = ecore_file_monitor_add("/usr/share/mime/globs", mime_changes_cb, NULL);
922 if (mon) eina_hash_add(mime_monitors, "/usr/share/mime/globs", mon);
923
924 datadirs = efreet_data_dirs_get();
925 EINA_LIST_FOREACH(datadirs, l, s)
926 {
927 snprintf(buf, sizeof(buf), "%s/mime/globs", s);
928 if (!eina_hash_find(mime_monitors, buf))
929 {
930 mon = ecore_file_monitor_add(buf, mime_changes_cb, NULL);
931 if (mon) eina_hash_add(mime_monitors, buf, mon);
932 }
933 }
934}
935
936static Eina_Bool
937mime_cache_monitor_del(const Eina_Hash *hash EINA_UNUSED,
938 const void *key EINA_UNUSED, void *value,
939 void *data EINA_UNUSED)
940{
941 Ecore_File_Monitor *mon = value;
942 ecore_file_monitor_del(mon);
943 return EINA_TRUE;
944}
945
946static void
947mime_cache_shutdown(void)
948{
949 if (mime_update_timer)
950 {
951 ecore_timer_del(mime_update_timer);
952 mime_update_timer = NULL;
953 }
954 if (mime_monitors)
955 {
956 eina_hash_foreach(mime_monitors, mime_cache_monitor_del, NULL);
957 eina_hash_free(mime_monitors);
958 mime_monitors = NULL;
959 }
960}
961
841Eina_Bool 962Eina_Bool
842cache_init(void) 963cache_init(void)
843{ 964{
@@ -875,6 +996,8 @@ cache_init(void)
875 efreet_cache_update = 0; 996 efreet_cache_update = 0;
876 if (!efreet_init()) goto error; 997 if (!efreet_init()) goto error;
877 subdir_cache_init(); 998 subdir_cache_init();
999 mime_cache_init();
1000 mime_update_launch();
878 read_lists(); 1001 read_lists();
879 /* TODO: Should check if system dirs has changed and handles extra_dirs */ 1002 /* TODO: Should check if system dirs has changed and handles extra_dirs */
880 desktop_system_dirs = efreet_default_dirs_get(efreet_data_home_get(), 1003 desktop_system_dirs = efreet_default_dirs_get(efreet_data_home_get(),
@@ -906,6 +1029,7 @@ cache_shutdown(void)
906 eina_prefix_free(pfx); 1029 eina_prefix_free(pfx);
907 pfx = NULL; 1030 pfx = NULL;
908 1031
1032 mime_cache_shutdown();
909 subdir_cache_shutdown(); 1033 subdir_cache_shutdown();
910 efreet_shutdown(); 1034 efreet_shutdown();
911 1035
diff --git a/src/bin/efreet/efreetd_ipc.c b/src/bin/efreet/efreetd_ipc.c
index 2c483c5a79..533a33bc75 100644
--- a/src/bin/efreet/efreetd_ipc.c
+++ b/src/bin/efreet/efreetd_ipc.c
@@ -190,6 +190,12 @@ send_signal_desktop_cache_build(void)
190 _broadcast(ipc, 1 /* desktop cache build */, 1, NULL, 0); 190 _broadcast(ipc, 1 /* desktop cache build */, 1, NULL, 0);
191} 191}
192 192
193void
194send_signal_mime_cache_build(void)
195{
196 _broadcast(ipc, 4 /* mime cache build */, 1, NULL, 0);
197}
198
193Eina_Bool 199Eina_Bool
194ipc_init(void) 200ipc_init(void)
195{ 201{
diff --git a/src/bin/efreet/efreetd_ipc.h b/src/bin/efreet/efreetd_ipc.h
index 6508f8f7b4..e2b3b5abf1 100644
--- a/src/bin/efreet/efreetd_ipc.h
+++ b/src/bin/efreet/efreetd_ipc.h
@@ -4,6 +4,7 @@
4void send_signal_icon_cache_update(Eina_Bool update); 4void send_signal_icon_cache_update(Eina_Bool update);
5void send_signal_desktop_cache_update(Eina_Bool update); 5void send_signal_desktop_cache_update(Eina_Bool update);
6void send_signal_desktop_cache_build(void); 6void send_signal_desktop_cache_build(void);
7void send_signal_mime_cache_build(void);
7 8
8Eina_Bool ipc_init(void); 9Eina_Bool ipc_init(void);
9Eina_Bool ipc_shutdown(void); 10Eina_Bool ipc_shutdown(void);
diff --git a/src/examples/elementary/codegen_example_generated.c b/src/examples/elementary/codegen_example_generated.c
deleted file mode 100644
index 8ce305ebda..0000000000
--- a/src/examples/elementary/codegen_example_generated.c
+++ /dev/null
@@ -1,132 +0,0 @@
1#include "codegen_example_generated.h"
2
3Evas_Object *
4codegen_example_layout_add(Evas_Object *o, Elm_Theme *th, const char *edje_file)
5{
6 Evas_Object *l;
7
8 if (edje_file)
9 elm_theme_extension_add(th, edje_file);
10 else
11 elm_theme_extension_add(th, "./codegen_example.edj");
12
13 l = elm_layout_add(o);
14 if (!l) return NULL;
15
16 if (!elm_layout_theme_set(l, "example", "mylayout", "default"))
17 {
18 evas_object_del(l);
19 return NULL;
20 }
21
22 return l;
23}
24
25void
26codegen_example_title_set(Evas_Object *o, const char *value)
27{
28 elm_layout_text_set(o, "example/title", value);
29}
30
31const char *
32codegen_example_title_get(const Evas_Object *o)
33{
34 return elm_layout_text_get(o, "example/title");
35}
36
37void
38codegen_example_custom_set(Evas_Object *o, Evas_Object *value)
39{
40 elm_layout_content_set(o, "example/custom", value);
41}
42
43Evas_Object *
44codegen_example_custom_unset(Evas_Object *o)
45{
46 return elm_layout_content_unset(o, "example/custom");
47}
48
49Evas_Object *
50codegen_example_custom_get(const Evas_Object *o)
51{
52 return elm_layout_content_get(o, "example/custom");
53}
54
55Eina_Bool
56codegen_example_box_append(Evas_Object *o, Evas_Object *child)
57{
58 return elm_layout_box_append(o, "example/box", child);
59}
60
61Eina_Bool
62codegen_example_box_prepend(Evas_Object *o, Evas_Object *child)
63{
64 return elm_layout_box_prepend(o, "example/box", child);
65}
66
67Eina_Bool
68codegen_example_box_insert_before(Evas_Object *o, Evas_Object *child, const Evas_Object *reference)
69{
70 return elm_layout_box_insert_before(o, "example/box", child, reference);
71}
72
73Eina_Bool
74codegen_example_box_insert_at(Evas_Object *o, Evas_Object *child, unsigned int pos)
75{
76 return elm_layout_box_insert_at(o, "example/box", child, pos);
77}
78
79Evas_Object *
80codegen_example_box_remove(Evas_Object *o, Evas_Object *child)
81{
82 return elm_layout_box_remove(o, "example/box", child);
83}
84
85Eina_Bool
86codegen_example_box_remove_all(Evas_Object *o, Eina_Bool clear)
87{
88 return elm_layout_box_remove_all(o, "example/box", clear);
89}
90
91Eina_Bool
92codegen_example_table_pack(Evas_Object *o, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan)
93{
94 return elm_layout_table_pack(o, "example/table", child, col, row, colspan, rowspan);
95}
96
97Evas_Object *
98codegen_example_table_unpack(Evas_Object *o, Evas_Object *child)
99{
100 return elm_layout_table_unpack(o, "example/table", child);
101}
102
103Eina_Bool
104codegen_example_table_clear(Evas_Object *o, Eina_Bool clear)
105{
106 return elm_layout_table_clear(o, "example/table", clear);
107}
108
109void
110codegen_example_swallow_grow_emit(Evas_Object *o)
111{
112 elm_layout_signal_emit(o, "button,enlarge", "");
113}
114
115void
116codegen_example_swallow_shrink_emit(Evas_Object *o)
117{
118 elm_layout_signal_emit(o, "button,reduce", "");
119}
120
121void
122codegen_example_size_changed_callback_add(Evas_Object *o, Edje_Signal_Cb func, void *data)
123{
124 elm_layout_signal_callback_add(o, "size,changed", "", func, data);
125}
126
127void
128codegen_example_size_changed_callback_del(Evas_Object *o, Edje_Signal_Cb func)
129{
130 elm_layout_signal_callback_del(o, "size,changed", "", func);
131}
132
diff --git a/src/examples/elementary/codegen_example_generated.h b/src/examples/elementary/codegen_example_generated.h
deleted file mode 100644
index b8fbc4e958..0000000000
--- a/src/examples/elementary/codegen_example_generated.h
+++ /dev/null
@@ -1,65 +0,0 @@
1#ifndef _CODEGEN_EXAMPLE_GENERATED_H
2#define _CODEGEN_EXAMPLE_GENERATED_H
3
4#include <Edje.h>
5#include <Elementary.h>
6#include <Evas.h>
7
8#include <stdlib.h>
9
10/**
11 * @brief Creates the layout object and set the theme
12 * @param o The parent
13 * @param th The theme to add to, or if NULL, the default theme
14 * @param edje_file The path to edj, if NULL it's used the path given
15 * to elementary_codegen
16 */
17Evas_Object *codegen_example_layout_add(Evas_Object *o, Elm_Theme *th, const char *edje_file);
18
19/**
20 * @brief The example title
21 */
22void codegen_example_title_set(Evas_Object *o, const char *value);
23const char *codegen_example_title_get(const Evas_Object *o);
24
25/**
26 * @brief The swallow part
27 */
28void codegen_example_custom_set(Evas_Object *o, Evas_Object *value);
29Evas_Object *codegen_example_custom_unset(Evas_Object *o);
30Evas_Object *codegen_example_custom_get(const Evas_Object *o);
31
32/**
33 * @brief The box part
34 */
35Eina_Bool codegen_example_box_append(Evas_Object *o, Evas_Object *child);
36Eina_Bool codegen_example_box_prepend(Evas_Object *o, Evas_Object *child);
37Eina_Bool codegen_example_box_insert_before(Evas_Object *o, Evas_Object *child, const Evas_Object *reference);
38Eina_Bool codegen_example_box_insert_at(Evas_Object *o, Evas_Object *child, unsigned int pos);
39Evas_Object *codegen_example_box_remove(Evas_Object *o, Evas_Object *child);
40Eina_Bool codegen_example_box_remove_all(Evas_Object *o, Eina_Bool clear);
41
42/**
43 * @brief The table part
44 */
45Eina_Bool codegen_example_table_pack(Evas_Object *o, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan);
46Evas_Object *codegen_example_table_unpack(Evas_Object *o, Evas_Object *child);
47Eina_Bool codegen_example_table_clear(Evas_Object *o, Eina_Bool clear);
48
49/**
50 * @brief Executed when the button enlarges
51 */
52void codegen_example_swallow_grow_emit(Evas_Object *o);
53
54/**
55 * @brief Executed when the button reduces
56 */
57void codegen_example_swallow_shrink_emit(Evas_Object *o);
58
59/**
60 * @brief Emit the signal size,changed
61 */
62void codegen_example_size_changed_callback_add(Evas_Object *o, Edje_Signal_Cb func, void *data);
63void codegen_example_size_changed_callback_del(Evas_Object *o, Edje_Signal_Cb func);
64
65#endif /* _CODEGEN_EXAMPLE_GENERATED_H */
diff --git a/src/lib/efreet/efreet_cache.c b/src/lib/efreet/efreet_cache.c
index f8d5e5ce43..de4ca7440e 100644
--- a/src/lib/efreet/efreet_cache.c
+++ b/src/lib/efreet/efreet_cache.c
@@ -203,6 +203,8 @@ _icon_desktop_cache_update_event_add(int event_type)
203 ecore_event_add(event_type, ev, icon_cache_update_free, l); 203 ecore_event_add(event_type, ev, icon_cache_update_free, l);
204} 204}
205 205
206EAPI void (*_efreet_mime_update_func) (void) = NULL;
207
206static Eina_Bool 208static Eina_Bool
207_cb_server_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) 209_cb_server_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
208{ 210{
@@ -223,6 +225,10 @@ _cb_server_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
223 { 225 {
224 _icon_desktop_cache_update_event_add(EFREET_EVENT_DESKTOP_CACHE_UPDATE); 226 _icon_desktop_cache_update_event_add(EFREET_EVENT_DESKTOP_CACHE_UPDATE);
225 } 227 }
228 else if (e->major == 4) // mime cache update
229 {
230 if (_efreet_mime_update_func) _efreet_mime_update_func();
231 }
226 return ECORE_CALLBACK_DONE; 232 return ECORE_CALLBACK_DONE;
227} 233}
228 234
diff --git a/src/lib/efreet/efreet_mime.c b/src/lib/efreet/efreet_mime.c
index 87ca8ef414..4426b6a130 100644
--- a/src/lib/efreet/efreet_mime.c
+++ b/src/lib/efreet/efreet_mime.c
@@ -32,11 +32,8 @@ static int _efreet_mime_log_dom = -1;
32#include "Efreet_Mime.h" 32#include "Efreet_Mime.h"
33#include "efreet_private.h" 33#include "efreet_private.h"
34 34
35static Eina_List *globs = NULL; /* contains Efreet_Mime_Glob structs */ 35static Eina_List *magics = NULL; // contains Efreet_Mime_Magic structs
36static Eina_List *magics = NULL; /* contains Efreet_Mime_Magic structs */ 36static Eina_Hash *mime_icons = NULL; // contains cache with mime->icons
37static Eina_Hash *wild = NULL; /* contains *.ext and mime.types globs*/
38static Eina_Hash *monitors = NULL; /* contains file monitors */
39static Eina_Hash *mime_icons = NULL; /* contains cache with mime->icons */
40static Eina_Inlist *mime_icons_lru = NULL; 37static Eina_Inlist *mime_icons_lru = NULL;
41static unsigned int _efreet_mime_init_count = 0; 38static unsigned int _efreet_mime_init_count = 0;
42 39
@@ -89,13 +86,6 @@ static enum
89 */ 86 */
90//#define EFREET_MIME_ICONS_DEBUG 87//#define EFREET_MIME_ICONS_DEBUG
91 88
92typedef struct Efreet_Mime_Glob Efreet_Mime_Glob;
93struct Efreet_Mime_Glob
94{
95 const char *glob;
96 const char *mime;
97};
98
99typedef struct Efreet_Mime_Magic Efreet_Mime_Magic; 89typedef struct Efreet_Mime_Magic Efreet_Mime_Magic;
100struct Efreet_Mime_Magic 90struct Efreet_Mime_Magic
101{ 91{
@@ -134,9 +124,6 @@ struct Efreet_Mime_Icon_Entry
134 unsigned int size; 124 unsigned int size;
135}; 125};
136 126
137static int efreet_mime_glob_remove(const char *glob);
138static void efreet_mime_mime_types_load(const char *file);
139static void efreet_mime_shared_mimeinfo_globs_load(const char *file);
140static void efreet_mime_shared_mimeinfo_magic_load(const char *file); 127static void efreet_mime_shared_mimeinfo_magic_load(const char *file);
141static void efreet_mime_shared_mimeinfo_magic_parse(char *data, int size); 128static void efreet_mime_shared_mimeinfo_magic_parse(char *data, int size);
142static const char *efreet_mime_magic_check_priority(const char *file, 129static const char *efreet_mime_magic_check_priority(const char *file,
@@ -145,19 +132,12 @@ static const char *efreet_mime_magic_check_priority(const char *file,
145static int efreet_mime_init_files(void); 132static int efreet_mime_init_files(void);
146static const char *efreet_mime_special_check(const char *file); 133static const char *efreet_mime_special_check(const char *file);
147static const char *efreet_mime_fallback_check(const char *file); 134static const char *efreet_mime_fallback_check(const char *file);
148static void efreet_mime_glob_free(void *data);
149static void efreet_mime_magic_free(void *data); 135static void efreet_mime_magic_free(void *data);
150static void efreet_mime_magic_entry_free(void *data); 136static void efreet_mime_magic_entry_free(void *data);
151static int efreet_mime_glob_match(const char *str, const char *glob); 137static int efreet_mime_glob_match(const char *str, const char *glob);
152static int efreet_mime_glob_case_match(char *str, const char *glob); 138static int efreet_mime_glob_case_match(char *str, const char *glob);
153static int efreet_mime_endian_check(void); 139static int efreet_mime_endian_check(void);
154 140
155static void efreet_mime_monitor_add(const char *file);
156static void efreet_mime_cb_update_file(void *data,
157 Ecore_File_Monitor *monitor,
158 Ecore_File_Event event,
159 const char *path);
160
161static void efreet_mime_icons_flush(double now); 141static void efreet_mime_icons_flush(double now);
162static void efreet_mime_icon_entry_head_free(Efreet_Mime_Icon_Entry_Head *entry); 142static void efreet_mime_icon_entry_head_free(Efreet_Mime_Icon_Entry_Head *entry);
163static void efreet_mime_icon_entry_add(const char *mime, 143static void efreet_mime_icon_entry_add(const char *mime,
@@ -169,6 +149,218 @@ static const char *efreet_mime_icon_entry_find(const char *mime,
169 unsigned int size); 149 unsigned int size);
170static void efreet_mime_icons_debug(void); 150static void efreet_mime_icons_debug(void);
171 151
152
153
154
155
156
157
158
159
160
161
162
163static Eina_File *mimedb = NULL;
164static unsigned char *mimedb_ptr = NULL;
165static size_t mimedb_size = 0;
166
167static void
168_efreet_mimedb_shutdown(void)
169{
170 if (mimedb)
171 {
172 if (mimedb_ptr) eina_file_map_free(mimedb, mimedb_ptr);
173 eina_file_close(mimedb);
174 mimedb = NULL;
175 mimedb_ptr = NULL;
176 mimedb_size = 0;
177 }
178}
179
180static void
181_efreet_mimedb_update(void)
182{
183 char buf[PATH_MAX];
184
185 if (mimedb)
186 {
187 if (mimedb_ptr) eina_file_map_free(mimedb, mimedb_ptr);
188 eina_file_close(mimedb);
189 mimedb = NULL;
190 mimedb_ptr = NULL;
191 mimedb_size = 0;
192 }
193#ifdef WORDS_BIGENDIAN
194 snprintf(buf, sizeof(buf), "%s/efreet/mime_cache_%s.be.dat",
195 efreet_cache_home_get(), efreet_hostname_get());
196#else
197 snprintf(buf, sizeof(buf), "%s/efreet/mime_cache_%s.le.dat",
198 efreet_cache_home_get(), efreet_hostname_get());
199#endif
200 mimedb = eina_file_open(buf, EINA_FALSE);
201 if (mimedb)
202 {
203 mimedb_ptr = eina_file_map_all(mimedb, EINA_FILE_POPULATE);
204 if (mimedb_ptr)
205 {
206 mimedb_size = eina_file_size_get(mimedb);
207 if ((mimedb_size > (16 + 4 + 4 + 4) &&
208 (!strncmp((char *)mimedb_ptr, "EfrEeT-MiMeS-001", 16))))
209 {
210 // load ok - magic fine. more sanity checks?
211 }
212 else
213 {
214 eina_file_map_free(mimedb, mimedb_ptr);
215 mimedb_ptr = NULL;
216 eina_file_close(mimedb);
217 mimedb = NULL;
218 mimedb_size = 0;
219 }
220 }
221 else
222 {
223 eina_file_close(mimedb);
224 mimedb = NULL;
225 }
226 }
227}
228
229static const char *
230_efreet_mimedb_str_get(unsigned int offset)
231{
232 if (offset < (16 + 4 + 4 + 4)) return NULL;
233 if (offset >= mimedb_size) return NULL;
234 return (const char *)(mimedb_ptr + offset);
235}
236
237static unsigned int
238_efreet_mimedb_uint_get(unsigned int index)
239// index is the unit NUMBER AFTER the header
240{
241 unsigned int *ptr;
242 ptr = ((unsigned int *)(mimedb_ptr + 16)) + index;
243 if ((size_t)(((unsigned char *)ptr) - mimedb_ptr) >= (mimedb_size - 4))
244 return 0;
245 return *ptr;
246}
247
248static unsigned int
249_efreet_mimedb_mime_count(void)
250{
251 return _efreet_mimedb_uint_get(0);
252}
253
254/**** currently unused - here for symmetry and future use
255static const char *
256_efreet_mimedb_mime_get(unsigned int num)
257{
258 unsigned int offset = _efreet_mimedb_uint_get
259 (1 + num);
260 return _efreet_mimedb_str_get(offset);
261}
262*/
263
264static unsigned int
265_efreet_mimedb_extn_count(void)
266{
267 return _efreet_mimedb_uint_get(1 + _efreet_mimedb_mime_count());
268}
269
270static const char *
271_efreet_mimedb_extn_get(unsigned int num)
272{
273 unsigned int offset = _efreet_mimedb_uint_get
274 (1 + _efreet_mimedb_mime_count() + 1 + (num * 2));
275 return _efreet_mimedb_str_get(offset);
276}
277
278static const char *
279_efreet_mimedb_extn_mime_get(unsigned int num)
280{
281 unsigned int offset = _efreet_mimedb_uint_get
282 (1 + _efreet_mimedb_mime_count() + 1 + (num * 2) + 1);
283 return _efreet_mimedb_str_get(offset);
284}
285
286static const char *
287_efreet_mimedb_extn_find(const char *extn)
288{
289 unsigned int i, begin, end;
290 const char *s;
291
292 // binary search keys to get value
293 begin = 0;
294 end = _efreet_mimedb_extn_count();
295 i = (begin + end) / 2;
296 for (;;)
297 {
298 s = _efreet_mimedb_extn_get(i);
299 if (s)
300 {
301 int v = strcmp(extn, s);
302 if (v < 0)
303 {
304 end = i;
305 i = (begin + end) / 2;
306 if ((end - begin) == 0) break;
307 }
308 else if (v > 0)
309 {
310 if ((end - begin) > 1)
311 {
312 begin = i;
313 i = (begin + end) / 2;
314 if (i == end) break;
315 }
316 else
317 {
318 if ((end - begin) == 0) break;
319 begin = end;
320 i = end;
321 }
322 }
323 else if (v == 0)
324 return _efreet_mimedb_extn_mime_get(i);
325 }
326 else
327 {
328 break;
329 }
330 }
331 return NULL;
332}
333
334static unsigned int
335_efreet_mimedb_glob_count(void)
336{
337 return _efreet_mimedb_uint_get
338 (1 + _efreet_mimedb_mime_count() +
339 1 + (_efreet_mimedb_extn_count() * 2));
340}
341
342static const char *
343_efreet_mimedb_glob_get(unsigned int num)
344{
345 unsigned int offset = _efreet_mimedb_uint_get
346 (1 + _efreet_mimedb_mime_count() +
347 1 + (_efreet_mimedb_extn_count() * 2) +
348 1 + (num * 2));
349 return _efreet_mimedb_str_get(offset);
350}
351
352static const char *
353_efreet_mimedb_glob_mime_get(unsigned int num)
354{
355 unsigned int offset = _efreet_mimedb_uint_get
356 (1 + _efreet_mimedb_mime_count() +
357 1 + (_efreet_mimedb_extn_count() * 2) +
358 1 + (num * 2) + 1);
359 return _efreet_mimedb_str_get(offset);
360}
361
362/** --------------------------------- **/
363
172EAPI int 364EAPI int
173efreet_mime_init(void) 365efreet_mime_init(void)
174{ 366{
@@ -194,14 +386,15 @@ efreet_mime_init(void)
194 } 386 }
195 387
196 efreet_mime_endianess = efreet_mime_endian_check(); 388 efreet_mime_endianess = efreet_mime_endian_check();
197
198 monitors = eina_hash_string_superfast_new(EINA_FREE_CB(ecore_file_monitor_del));
199
200 efreet_mime_type_cache_clear(); 389 efreet_mime_type_cache_clear();
201 390
391 _efreet_mimedb_update();
392
202 if (!efreet_mime_init_files()) 393 if (!efreet_mime_init_files())
203 goto unregister_log_domain; 394 goto unregister_log_domain;
204 395
396 _efreet_mime_update_func = _efreet_mimedb_update;
397
205 return _efreet_mime_init_count; 398 return _efreet_mime_init_count;
206 399
207unregister_log_domain: 400unregister_log_domain:
@@ -228,6 +421,9 @@ efreet_mime_shutdown(void)
228 if (--_efreet_mime_init_count != 0) 421 if (--_efreet_mime_init_count != 0)
229 return _efreet_mime_init_count; 422 return _efreet_mime_init_count;
230 423
424 _efreet_mimedb_shutdown();
425 _efreet_mime_update_func = NULL;
426
231 efreet_mime_icons_debug(); 427 efreet_mime_icons_debug();
232 428
233 IF_RELEASE(_mime_inode_symlink); 429 IF_RELEASE(_mime_inode_symlink);
@@ -241,10 +437,7 @@ efreet_mime_shutdown(void)
241 IF_RELEASE(_mime_application_octet_stream); 437 IF_RELEASE(_mime_application_octet_stream);
242 IF_RELEASE(_mime_text_plain); 438 IF_RELEASE(_mime_text_plain);
243 439
244 IF_FREE_LIST(globs, efreet_mime_glob_free);
245 IF_FREE_LIST(magics, efreet_mime_magic_free); 440 IF_FREE_LIST(magics, efreet_mime_magic_free);
246 IF_FREE_HASH(monitors);
247 IF_FREE_HASH(wild);
248 IF_FREE_HASH(mime_icons); 441 IF_FREE_HASH(mime_icons);
249 eina_log_domain_unregister(_efreet_mime_log_dom); 442 eina_log_domain_unregister(_efreet_mime_log_dom);
250 _efreet_mime_log_dom = -1; 443 _efreet_mime_log_dom = -1;
@@ -387,11 +580,10 @@ efreet_mime_magic_type_get(const char *file)
387EAPI const char * 580EAPI const char *
388efreet_mime_globs_type_get(const char *file) 581efreet_mime_globs_type_get(const char *file)
389{ 582{
390 Eina_List *l;
391 Efreet_Mime_Glob *g;
392 char *sl, *p; 583 char *sl, *p;
393 const char *s; 584 const char *s, *mime;
394 char *ext, *mime; 585 char *ext;
586 unsigned int i, n;
395 587
396 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); 588 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
397 589
@@ -406,25 +598,27 @@ efreet_mime_globs_type_get(const char *file)
406 while (p) 598 while (p)
407 { 599 {
408 p++; 600 p++;
409 if (p && (mime = eina_hash_find(wild, p))) return mime; 601 if (p && (mime = _efreet_mimedb_extn_find(p))) return mime;
410 p = strchr(p, '.'); 602 p = strchr(p, '.');
411 } 603 }
412 } 604 }
413 605
414 /* Fallback to the other globs if not found */ 606 // Fallback to the other globs if not found
415 EINA_LIST_FOREACH(globs, l, g) 607 n = _efreet_mimedb_glob_count();
608 for (i = 0; i < n; i++)
416 { 609 {
417 if (efreet_mime_glob_match(file, g->glob)) 610 s = _efreet_mimedb_glob_get(i);
418 return g->mime; 611 if (efreet_mime_glob_match(file, s))
612 return _efreet_mimedb_glob_mime_get(i);
419 } 613 }
420
421 ext = alloca(strlen(file) + 1); 614 ext = alloca(strlen(file) + 1);
422 for (s = file, p = ext; *s; s++, p++) *p = tolower(*s); 615 for (s = file, p = ext; *s; s++, p++) *p = tolower(*s);
423 *p = 0; 616 *p = 0;
424 EINA_LIST_FOREACH(globs, l, g) 617 for (i = 0; i < n; i++)
425 { 618 {
426 if (efreet_mime_glob_case_match(ext, g->glob)) 619 s = _efreet_mimedb_glob_get(i);
427 return g->mime; 620 if (efreet_mime_glob_case_match(ext, s))
621 return _efreet_mimedb_glob_mime_get(i);
428 } 622 }
429 return NULL; 623 return NULL;
430} 624}
@@ -457,72 +651,6 @@ efreet_mime_endian_check(void)
457 651
458/** 652/**
459 * @internal 653 * @internal
460 * @param file File to monitor
461 * @return Returns no value.
462 * @brief Creates a new file monitor if we aren't already monitoring the
463 * given file
464 */
465static void
466efreet_mime_monitor_add(const char *file)
467{
468 Ecore_File_Monitor *fm = NULL;
469
470 /* if this is already in our hash then we're already monitoring so no
471 * reason to re-monitor */
472 if (eina_hash_find(monitors, file))
473 return;
474
475 if ((fm = ecore_file_monitor_add(file, efreet_mime_cb_update_file, NULL)))
476 {
477 eina_hash_del(monitors, file, NULL);
478 eina_hash_add(monitors, file, fm);
479 }
480}
481
482/**
483 * @internal
484 * @param datadirs List of XDG data dirs
485 * @param datahome Path to XDG data home directory
486 * @return Returns no value
487 * @brief Read all glob files in XDG data/home dirs.
488 * Also reads the /etc/mime.types file.
489 */
490static void
491efreet_mime_load_globs(Eina_List *datadirs, const char *datahome)
492{
493 Eina_List *l;
494 char buf[4096];
495 const char *datadir = NULL;
496
497 IF_FREE_HASH(wild);
498 wild = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
499 while (globs)
500 {
501 efreet_mime_glob_free(eina_list_data_get(globs));
502 globs = eina_list_remove_list(globs, globs);
503 }
504
505 /*
506 * This is here for legacy reasons. It is mentioned briefly
507 * in the spec and seems to still be quite valid. It is
508 * loaded first so the globs files will override anything
509 * in here.
510 */
511 efreet_mime_mime_types_load("/etc/mime.types");
512
513 datadir = datahome;
514 snprintf(buf, sizeof(buf), "%s/mime/globs", datadir);
515 efreet_mime_shared_mimeinfo_globs_load(buf);
516
517 EINA_LIST_FOREACH(datadirs, l, datadir)
518 {
519 snprintf(buf, sizeof(buf), "%s/mime/globs", datadir);
520 efreet_mime_shared_mimeinfo_globs_load(buf);
521 }
522}
523
524/**
525 * @internal
526 * @param datadirs List of XDG data dirs 654 * @param datadirs List of XDG data dirs
527 * @param datahome Path to XDG data home directory 655 * @param datahome Path to XDG data home directory
528 * @return Returns no value 656 * @return Returns no value
@@ -554,39 +682,6 @@ efreet_mime_load_magics(Eina_List *datadirs, const char *datahome)
554 682
555/** 683/**
556 * @internal 684 * @internal
557 * @param data Data pointer passed to monitor_add
558 * @param monitor Ecore_File_Monitor associated with this event
559 * @param event The type of event
560 * @param path Path to the file that was updated
561 * @return Returns no value
562 * @brief Callback for all file monitors. Just reloads the appropriate
563 * list depending on which file changed. If it was a magic file
564 * only the magic list is updated. If it was a glob file or /etc/mime.types,
565 * the globs are updated.
566 */
567static void
568efreet_mime_cb_update_file(void *data EINA_UNUSED,
569 Ecore_File_Monitor *monitor EINA_UNUSED,
570 Ecore_File_Event event EINA_UNUSED,
571 const char *path)
572{
573 Eina_List *datadirs = NULL;
574 const char *datahome = NULL;
575
576 if (!(datahome = efreet_data_home_get()))
577 return;
578
579 if (!(datadirs = efreet_data_dirs_get()))
580 return;
581
582 if (strstr(path, "magic"))
583 efreet_mime_load_magics(datadirs, datahome);
584 else
585 efreet_mime_load_globs(datadirs, datahome);
586}
587
588/**
589 * @internal
590 * @param datadirs List of XDG data dirs 685 * @param datadirs List of XDG data dirs
591 * @param datahome Path to XDG data home directory 686 * @param datahome Path to XDG data home directory
592 * @return Returns 1 on success, 0 on failure 687 * @return Returns 1 on success, 0 on failure
@@ -595,10 +690,8 @@ efreet_mime_cb_update_file(void *data EINA_UNUSED,
595static int 690static int
596efreet_mime_init_files(void) 691efreet_mime_init_files(void)
597{ 692{
598 Eina_List *l;
599 Eina_List *datadirs = NULL; 693 Eina_List *datadirs = NULL;
600 char buf[PATH_MAX]; 694 const char *datahome;
601 const char *datahome, *datadir = NULL;
602 695
603 if (!(datahome = efreet_data_home_get())) 696 if (!(datahome = efreet_data_home_get()))
604 return 0; 697 return 0;
@@ -606,32 +699,15 @@ efreet_mime_init_files(void)
606 if (!(datadirs = efreet_data_dirs_get())) 699 if (!(datadirs = efreet_data_dirs_get()))
607 return 0; 700 return 0;
608 701
609 /*
610 * Add our file monitors
611 * We watch the directories so we can watch for new files
612 */
613 datadir = datahome;
614 snprintf(buf, sizeof(buf), "%s/mime", datadir);
615 efreet_mime_monitor_add(buf);
616
617 EINA_LIST_FOREACH(datadirs, l, datadir)
618 {
619 snprintf(buf, sizeof(buf), "%s/mime", datadir);
620 efreet_mime_monitor_add(buf);
621 }
622 efreet_mime_monitor_add("/etc/mime.types");
623
624 /* Load our mime information */
625 efreet_mime_load_globs(datadirs, datahome);
626 efreet_mime_load_magics(datadirs, datahome); 702 efreet_mime_load_magics(datadirs, datahome);
627 703
628 _mime_inode_symlink = eina_stringshare_add("inode/symlink"); 704 _mime_inode_symlink = eina_stringshare_add("inode/symlink");
629 _mime_inode_fifo = eina_stringshare_add("inode/fifo"); 705 _mime_inode_fifo = eina_stringshare_add("inode/fifo");
630 _mime_inode_chardevice = eina_stringshare_add("inode/chardevice"); 706 _mime_inode_chardevice = eina_stringshare_add("inode/chardevice");
631 _mime_inode_blockdevice = eina_stringshare_add("inode/blockdevice"); 707 _mime_inode_blockdevice = eina_stringshare_add("inode/blockdevice");
632 _mime_inode_socket = eina_stringshare_add("inode/socket"); 708 _mime_inode_socket = eina_stringshare_add("inode/socket");
633 _mime_inode_mountpoint = eina_stringshare_add("inode/mountpoint"); 709 _mime_inode_mountpoint = eina_stringshare_add("inode/mountpoint");
634 _mime_inode_directory = eina_stringshare_add("inode/directory"); 710 _mime_inode_directory = eina_stringshare_add("inode/directory");
635 _mime_application_x_executable = eina_stringshare_add("application/x-executable"); 711 _mime_application_x_executable = eina_stringshare_add("application/x-executable");
636 _mime_application_octet_stream = eina_stringshare_add("application/octet-stream"); 712 _mime_application_octet_stream = eina_stringshare_add("application/octet-stream");
637 _mime_text_plain = eina_stringshare_add("text/plain"); 713 _mime_text_plain = eina_stringshare_add("text/plain");
@@ -781,198 +857,6 @@ efreet_mime_fallback_check(const char *file)
781 857
782/** 858/**
783 * @internal 859 * @internal
784 * @param glob Glob to search for
785 * @return Returns 1 on success, 0 on failure
786 * @brief Removes a glob from the list
787 */
788static int
789efreet_mime_glob_remove(const char *glob)
790{
791 Efreet_Mime_Glob *mime = NULL;
792
793 if ((mime = eina_list_search_unsorted(globs, EINA_COMPARE_CB(strcmp), glob)))
794 {
795 globs = eina_list_remove(globs, mime);
796 IF_RELEASE(mime->glob);
797 IF_RELEASE(mime->mime);
798 FREE(mime);
799 return 1;
800 }
801
802 return 0;
803}
804
805static inline const char *
806efreet_eat_space(const char *head, const Eina_File_Line *ln, Eina_Bool not)
807{
808 if (not)
809 {
810 while (!isspace(*head) && (head < ln->end))
811 head++;
812 }
813 else
814 {
815 while (isspace(*head) && (head < ln->end))
816 head++;
817 }
818
819 return head;
820}
821
822/**
823 * @internal
824 * @param file mime.types file to load
825 * @return Returns no value
826 * @brief Loads values from a mime.types style file
827 * into the globs list.
828 * @note Format:
829 * application/msaccess mdb
830 * application/msword doc dot
831 */
832static void
833efreet_mime_mime_types_load(const char *file)
834{
835 const Eina_File_Line *ln;
836 Eina_Iterator *it;
837 Eina_File *f;
838 const char *head_line;
839 const char *word_start;
840 const char *mimetype;
841
842 EINA_SAFETY_ON_NULL_RETURN(file);
843 f = eina_file_open(file, 0);
844 if (!f) return;
845
846 it = eina_file_map_lines(f);
847 if (it)
848 {
849 Eina_Strbuf *ext;
850
851 ext = eina_strbuf_new();
852
853 EINA_ITERATOR_FOREACH(it, ln)
854 {
855 head_line = efreet_eat_space(ln->start, ln, EINA_FALSE);
856 if (head_line == ln->end) continue ;
857
858 if (*head_line == '#') continue ;
859
860 word_start = head_line;
861 head_line = efreet_eat_space(head_line, ln, EINA_TRUE);
862
863 if (head_line == ln->end) continue ;
864 mimetype = eina_stringshare_add_length(word_start, head_line - word_start);
865 do
866 {
867 head_line = efreet_eat_space(head_line, ln, EINA_FALSE);
868 if (head_line == ln->end) break ;
869
870 word_start = head_line;
871 head_line = efreet_eat_space(head_line, ln, EINA_TRUE);
872
873 eina_strbuf_append_length(ext, word_start, head_line - word_start);
874
875 eina_hash_del(wild,
876 eina_strbuf_string_get(ext),
877 NULL);
878 eina_hash_add(wild,
879 eina_strbuf_string_get(ext),
880 eina_stringshare_ref(mimetype));
881
882 eina_strbuf_reset(ext);
883 }
884 while (head_line < ln->end);
885
886 eina_stringshare_del(mimetype);
887 }
888
889 eina_strbuf_free(ext);
890 eina_iterator_free(it);
891 }
892 eina_file_close(f);
893}
894
895/**
896 * @internal
897 * @param file globs file to load
898 * @return Returns no value
899 * @brief Loads values from a mime.types style file
900 * into the globs list.
901 * @note Format:
902 * text/vnd.wap.wml:*.wml
903 * application/x-7z-compressed:*.7z
904 * application/vnd.corel-draw:*.cdr
905 * text/spreadsheet:*.sylk
906 */
907static void
908efreet_mime_shared_mimeinfo_globs_load(const char *file)
909{
910 FILE *f = NULL;
911 char buf[4096], mimetype[4096], ext[4096], *p, *pp;
912 Efreet_Mime_Glob *mime = NULL;
913
914 f = fopen(file, "rb");
915 if (!f) return;
916
917 while (fgets(buf, sizeof(buf), f))
918 {
919 p = buf;
920 while (isspace(*p) && (*p != 0) && (*p != '\n')) p++;
921
922 if (*p == '#') continue;
923 if ((*p == '\n') || (*p == 0)) continue;
924
925 pp = p;
926 while ((*p != ':') && (*p != 0) && (*p != '\n')) p++;
927
928 if ((*p == '\n') || (*p == 0)) continue;
929 strncpy(mimetype, pp, (p - pp));
930 mimetype[p - pp] = 0;
931 p++;
932 pp = ext;
933
934 while ((*p != 0) && (*p != '\n'))
935 {
936 *pp = *p;
937 pp++;
938 p++;
939 }
940
941 *pp = 0;
942
943 if (ext[0] == '*' && ext[1] == '.')
944 {
945 eina_hash_del(wild, &(ext[2]), NULL);
946 eina_hash_add(wild, &(ext[2]),
947 (void*)eina_stringshare_add(mimetype));
948 }
949 else
950 {
951 mime = NEW(Efreet_Mime_Glob, 1);
952 if (mime)
953 {
954 mime->mime = eina_stringshare_add(mimetype);
955 mime->glob = eina_stringshare_add(ext);
956 if ((!mime->mime) || (!mime->glob))
957 {
958 IF_RELEASE(mime->mime);
959 IF_RELEASE(mime->glob);
960 FREE(mime);
961 }
962 else
963 {
964 efreet_mime_glob_remove(ext);
965 globs = eina_list_append(globs, mime);
966 }
967 }
968 }
969 }
970
971 fclose(f);
972}
973
974/**
975 * @internal
976 * @param in Number to count the digits 860 * @param in Number to count the digits
977 * @return Returns number of digits 861 * @return Returns number of digits
978 * @brief Calculates and returns the number of digits 862 * @brief Calculates and returns the number of digits
@@ -1341,22 +1225,6 @@ efreet_mime_magic_check_priority(const char *file,
1341 * @internal 1225 * @internal
1342 * @param data Data pointer that is being destroyed 1226 * @param data Data pointer that is being destroyed
1343 * @return Returns no value 1227 * @return Returns no value
1344 * @brief Callback for globs destroy
1345 */
1346static void
1347efreet_mime_glob_free(void *data)
1348{
1349 Efreet_Mime_Glob *m = data;
1350
1351 IF_RELEASE(m->mime);
1352 IF_RELEASE(m->glob);
1353 IF_FREE(m);
1354}
1355
1356/**
1357 * @internal
1358 * @param data Data pointer that is being destroyed
1359 * @return Returns no value
1360 * @brief Callback for magics destroy 1228 * @brief Callback for magics destroy
1361 */ 1229 */
1362static void 1230static void
diff --git a/src/lib/efreet/efreet_private.h b/src/lib/efreet/efreet_private.h
index 139754d81a..47d6deae12 100644
--- a/src/lib/efreet/efreet_private.h
+++ b/src/lib/efreet/efreet_private.h
@@ -251,6 +251,8 @@ EAPI void efreet_fsetowner(int fd);
251 251
252EAPI extern int efreet_cache_update; 252EAPI extern int efreet_cache_update;
253 253
254EAPI extern void (*_efreet_mime_update_func) (void);
255
254#undef EAPI 256#undef EAPI
255#define EAPI 257#define EAPI
256 258