OLD | NEW |
1 /* -*- mode: C; c-file-style: "gnu" -*- */ | 1 /* -*- mode: C; c-file-style: "gnu" -*- */ |
2 /* xdgmimealias.c: Private file. mmappable caches for mime data | 2 /* xdgmimealias.c: Private file. mmappable caches for mime data |
3 * | 3 * |
4 * More info can be found at http://www.freedesktop.org/standards/ | 4 * More info can be found at http://www.freedesktop.org/standards/ |
5 * | 5 * |
6 * Copyright (C) 2005 Matthias Clasen <mclasen@redhat.com> | 6 * Copyright (C) 2005 Matthias Clasen <mclasen@redhat.com> |
7 * | 7 * |
8 * Licensed under the Academic Free License version 2.0 | 8 * Licensed under the Academic Free License version 2.0 |
9 * Or under the following terms: | 9 * Or under the following terms: |
10 * | 10 * |
11 * This library is free software; you can redistribute it and/or | 11 * This library is free software; you can redistribute it and/or |
12 * modify it under the terms of the GNU Lesser General Public | 12 * modify it under the terms of the GNU Lesser General Public |
13 * License as published by the Free Software Foundation; either | 13 * License as published by the Free Software Foundation; either |
14 * version 2 of the License, or (at your option) any later version. | 14 * version 2 of the License, or (at your option) any later version. |
15 * | 15 * |
16 * This library is distributed in the hope that it will be useful, | 16 * This library is distributed in the hope that it will be useful, |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
19 * Lesser General Public License for more details. | 19 * Lesser General Public License for more details. |
20 * | 20 * |
21 * You should have received a copy of the GNU Lesser General Public | 21 * You should have received a copy of the GNU Lesser General Public |
22 * License along with this library; if not, write to the | 22 * License along with this library; if not, write to the |
23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
24 * Boston, MA 02111-1307, USA. | 24 * Boston, MA 02111-1307, USA. |
25 */ | 25 */ |
26 | 26 |
27 #ifdef HAVE_CONFIG_H | 27 #ifdef HAVE_CONFIG_H |
28 #include "config.h" | 28 #include <config.h> |
29 #endif | 29 #endif |
30 | 30 |
31 #include <stdio.h> | 31 #include <stdio.h> |
32 #include <stdlib.h> | 32 #include <stdlib.h> |
33 #include <string.h> | 33 #include <string.h> |
34 #include <ctype.h> | |
35 | 34 |
36 #include <fcntl.h> | 35 #include <fcntl.h> |
37 #include <unistd.h> | 36 #include <unistd.h> |
38 #include <fnmatch.h> | 37 #include <fnmatch.h> |
39 #include <assert.h> | 38 #include <assert.h> |
40 | 39 |
41 #include <netinet/in.h> /* for ntohl/ntohs */ | 40 #include <netinet/in.h> /* for ntohl/ntohs */ |
42 | 41 |
43 #define HAVE_MMAP 1 | 42 #define HAVE_MMAP 1 |
44 | 43 |
45 #ifdef HAVE_MMAP | 44 #ifdef HAVE_MMAP |
46 #include <sys/mman.h> | 45 #include <sys/mman.h> |
47 #else | 46 #else |
48 #warning Building xdgmime without MMAP support. Binary "mime.info" cache files w
ill not be used. | 47 #warning Building xdgmime without MMAP support. Binary "mime.cache" files will n
ot be used. |
49 #endif | 48 #endif |
50 | 49 |
51 #include <sys/stat.h> | 50 #include <sys/stat.h> |
52 #include <sys/types.h> | 51 #include <sys/types.h> |
53 | 52 |
54 #include "xdgmimecache.h" | 53 #include "xdgmimecache.h" |
55 #include "xdgmimeint.h" | 54 #include "xdgmimeint.h" |
56 | 55 |
57 #ifndef MAX | 56 #ifndef MAX |
58 #define MAX(a,b) ((a) > (b) ? (a) : (b)) | 57 #define MAX(a,b) ((a) > (b) ? (a) : (b)) |
59 #endif | 58 #endif |
60 | 59 |
61 #ifndef FALSE | 60 #ifndef FALSE |
62 #define FALSE (0) | 61 #define FALSE (0) |
63 #endif | 62 #endif |
64 | 63 |
65 #ifndef TRUE | 64 #ifndef TRUE |
66 #define TRUE (!FALSE) | 65 #define TRUE (!FALSE) |
67 #endif | 66 #endif |
68 | 67 |
69 #ifndef _O_BINARY | 68 #ifndef _O_BINARY |
70 #define _O_BINARY 0 | 69 #define _O_BINARY 0 |
71 #endif | 70 #endif |
72 | 71 |
73 #ifndef MAP_FAILED | 72 #ifndef MAP_FAILED |
74 #define MAP_FAILED ((void *) -1) | 73 #define MAP_FAILED ((void *) -1) |
75 #endif | 74 #endif |
76 | 75 |
77 #define MAJOR_VERSION 1 | 76 #define MAJOR_VERSION 1 |
78 #define MINOR_VERSION 1 | 77 #define MINOR_VERSION_MIN 1 |
| 78 #define MINOR_VERSION_MAX 2 |
79 | 79 |
80 struct _XdgMimeCache | 80 struct _XdgMimeCache |
81 { | 81 { |
82 int ref_count; | 82 int ref_count; |
| 83 int minor; |
83 | 84 |
84 size_t size; | 85 size_t size; |
85 char *buffer; | 86 char *buffer; |
86 }; | 87 }; |
87 | 88 |
88 #define GET_UINT16(cache,offset) (ntohs(*(xdg_uint16_t*)((cache) + (offset)))) | 89 #define GET_UINT16(cache,offset) (ntohs(*(xdg_uint16_t*)((cache) + (offset)))) |
89 #define GET_UINT32(cache,offset) (ntohl(*(xdg_uint32_t*)((cache) + (offset)))) | 90 #define GET_UINT32(cache,offset) (ntohl(*(xdg_uint32_t*)((cache) + (offset)))) |
90 | 91 |
91 XdgMimeCache * | 92 XdgMimeCache * |
92 _xdg_mime_cache_ref (XdgMimeCache *cache) | 93 _xdg_mime_cache_ref (XdgMimeCache *cache) |
(...skipping 18 matching lines...) Expand all Loading... |
111 | 112 |
112 XdgMimeCache * | 113 XdgMimeCache * |
113 _xdg_mime_cache_new_from_file (const char *file_name) | 114 _xdg_mime_cache_new_from_file (const char *file_name) |
114 { | 115 { |
115 XdgMimeCache *cache = NULL; | 116 XdgMimeCache *cache = NULL; |
116 | 117 |
117 #ifdef HAVE_MMAP | 118 #ifdef HAVE_MMAP |
118 int fd = -1; | 119 int fd = -1; |
119 struct stat st; | 120 struct stat st; |
120 char *buffer = NULL; | 121 char *buffer = NULL; |
| 122 int minor; |
121 | 123 |
122 /* Open the file and map it into memory */ | 124 /* Open the file and map it into memory */ |
123 fd = open (file_name, O_RDONLY|_O_BINARY, 0); | 125 fd = open (file_name, O_RDONLY|_O_BINARY, 0); |
124 | 126 |
125 if (fd < 0) | 127 if (fd < 0) |
126 return NULL; | 128 return NULL; |
127 | 129 |
128 if (fstat (fd, &st) < 0 || st.st_size < 4) | 130 if (fstat (fd, &st) < 0 || st.st_size < 4) |
129 goto done; | 131 goto done; |
130 | 132 |
131 buffer = (char *) mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); | 133 buffer = (char *) mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); |
132 | 134 |
133 if (buffer == MAP_FAILED) | 135 if (buffer == MAP_FAILED) |
134 goto done; | 136 goto done; |
135 | 137 |
| 138 minor = GET_UINT16 (buffer, 2); |
136 /* Verify version */ | 139 /* Verify version */ |
137 if (GET_UINT16 (buffer, 0) != MAJOR_VERSION || | 140 if (GET_UINT16 (buffer, 0) != MAJOR_VERSION || |
138 GET_UINT16 (buffer, 2) != MINOR_VERSION) | 141 (minor < MINOR_VERSION_MIN || |
| 142 minor > MINOR_VERSION_MAX)) |
139 { | 143 { |
140 munmap (buffer, st.st_size); | 144 munmap (buffer, st.st_size); |
141 | 145 |
142 goto done; | 146 goto done; |
143 } | 147 } |
144 | 148 |
145 cache = (XdgMimeCache *) malloc (sizeof (XdgMimeCache)); | 149 cache = (XdgMimeCache *) malloc (sizeof (XdgMimeCache)); |
| 150 cache->minor = minor; |
146 cache->ref_count = 1; | 151 cache->ref_count = 1; |
147 cache->buffer = buffer; | 152 cache->buffer = buffer; |
148 cache->size = st.st_size; | 153 cache->size = st.st_size; |
149 | 154 |
150 done: | 155 done: |
151 if (fd != -1) | 156 if (fd != -1) |
152 close (fd); | 157 close (fd); |
153 | 158 |
154 #endif /* HAVE_MMAP */ | 159 #endif /* HAVE_MMAP */ |
155 | 160 |
156 return cache; | 161 return cache; |
157 } | 162 } |
158 | 163 |
159 static int | 164 static int |
160 cache_magic_matchlet_compare_to_data (XdgMimeCache *cache, | 165 cache_magic_matchlet_compare_to_data (XdgMimeCache *cache, |
161 xdg_uint32_t offset, | 166 xdg_uint32_t offset, |
162 const void *data, | 167 const void *data, |
163 size_t len) | 168 size_t len) |
164 { | 169 { |
165 xdg_uint32_t range_start = GET_UINT32 (cache->buffer, offset); | 170 xdg_uint32_t range_start = GET_UINT32 (cache->buffer, offset); |
166 xdg_uint32_t range_length = GET_UINT32 (cache->buffer, offset + 4); | 171 xdg_uint32_t range_length = GET_UINT32 (cache->buffer, offset + 4); |
167 xdg_uint32_t data_length = GET_UINT32 (cache->buffer, offset + 12); | 172 xdg_uint32_t data_length = GET_UINT32 (cache->buffer, offset + 12); |
168 xdg_uint32_t data_offset = GET_UINT32 (cache->buffer, offset + 16); | 173 xdg_uint32_t data_offset = GET_UINT32 (cache->buffer, offset + 16); |
169 xdg_uint32_t mask_offset = GET_UINT32 (cache->buffer, offset + 20); | 174 xdg_uint32_t mask_offset = GET_UINT32 (cache->buffer, offset + 20); |
170 | 175 |
171 int i, j; | 176 int i, j; |
172 | 177 |
173 for (i = range_start; i <= range_start + range_length; i++) | 178 for (i = range_start; i < range_start + range_length; i++) |
174 { | 179 { |
175 int valid_matchlet = TRUE; | 180 int valid_matchlet = TRUE; |
176 | 181 |
177 if (i + data_length > len) | 182 if (i + data_length > len) |
178 return FALSE; | 183 return FALSE; |
179 | 184 |
180 if (mask_offset) | 185 if (mask_offset) |
181 { | 186 { |
182 for (j = 0; j < data_length; j++) | 187 for (j = 0; j < data_length; j++) |
183 { | 188 { |
184 if ((((unsigned char *)cache->buffer)[data_offset + j] & ((unsigne
d char *)cache->buffer)[mask_offset + j]) != | 189 if ((((unsigned char *)cache->buffer)[data_offset + j] & ((unsigne
d char *)cache->buffer)[mask_offset + j]) != |
185 ((((unsigned char *) data)[j + i]) & ((unsigned char *)cache->
buffer)[mask_offset + j])) | 190 ((((unsigned char *) data)[j + i]) & ((unsigned char *)cache->
buffer)[mask_offset + j])) |
186 { | 191 { |
187 valid_matchlet = FALSE; | 192 valid_matchlet = FALSE; |
188 break; | 193 break; |
189 } | 194 } |
190 } | 195 } |
191 } | 196 } |
192 else | 197 else |
193 { | 198 { |
194 » for (j = 0; j < data_length; j++) | 199 » valid_matchlet = memcmp(cache->buffer + data_offset, data + i, data_le
ngth) == 0; |
195 » { | |
196 » if (((unsigned char *)cache->buffer)[data_offset + j] != ((unsigne
d char *) data)[j + i]) | |
197 » » { | |
198 » » valid_matchlet = FALSE; | |
199 » » break; | |
200 » » } | |
201 » } | |
202 } | 200 } |
203 | 201 |
204 if (valid_matchlet) | 202 if (valid_matchlet) |
205 return TRUE; | 203 return TRUE; |
206 } | 204 } |
207 | 205 |
208 return FALSE; | 206 return FALSE; |
209 } | 207 } |
210 | 208 |
211 static int | 209 static int |
212 cache_magic_matchlet_compare (XdgMimeCache *cache, | 210 cache_magic_matchlet_compare (XdgMimeCache *cache, |
213 xdg_uint32_t offset, | 211 xdg_uint32_t offset, |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 } | 348 } |
351 | 349 |
352 typedef struct { | 350 typedef struct { |
353 const char *mime; | 351 const char *mime; |
354 int weight; | 352 int weight; |
355 } MimeWeight; | 353 } MimeWeight; |
356 | 354 |
357 static int | 355 static int |
358 cache_glob_lookup_literal (const char *file_name, | 356 cache_glob_lookup_literal (const char *file_name, |
359 const char *mime_types[], | 357 const char *mime_types[], |
360 » » » int n_mime_types) | 358 » » » int n_mime_types, |
| 359 » » » int case_sensitive_check) |
361 { | 360 { |
362 const char *ptr; | 361 const char *ptr; |
363 int i, min, max, mid, cmp; | 362 int i, min, max, mid, cmp; |
364 | 363 |
365 for (i = 0; _caches[i]; i++) | 364 for (i = 0; _caches[i]; i++) |
366 { | 365 { |
367 XdgMimeCache *cache = _caches[i]; | 366 XdgMimeCache *cache = _caches[i]; |
368 xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 12); | 367 xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 12); |
369 xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset); | 368 xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset); |
370 xdg_uint32_t offset; | 369 xdg_uint32_t offset; |
371 | 370 |
372 min = 0; | 371 min = 0; |
373 max = n_entries - 1; | 372 max = n_entries - 1; |
374 while (max >= min) | 373 while (max >= min) |
375 { | 374 { |
376 mid = (min + max) / 2; | 375 mid = (min + max) / 2; |
377 | 376 |
378 offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid); | 377 offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid); |
379 ptr = cache->buffer + offset; | 378 ptr = cache->buffer + offset; |
380 cmp = strcmp (ptr, file_name); | 379 cmp = strcmp (ptr, file_name); |
381 » | 380 |
382 if (cmp < 0) | 381 if (cmp < 0) |
383 min = mid + 1; | 382 min = mid + 1; |
384 else if (cmp > 0) | 383 else if (cmp > 0) |
385 max = mid - 1; | 384 max = mid - 1; |
386 else | 385 else |
387 { | 386 { |
388 » offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 4
); | 387 » int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid
+ 8); |
389 » mime_types[0] = (const char *)(cache->buffer + offset); | 388 » int case_sensitive = weight & 0x100; |
390 » | 389 » weight = weight & 0xff; |
391 » return 1; | 390 |
| 391 » if (case_sensitive_check || !case_sensitive) |
| 392 » » { |
| 393 » » offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid
+ 4); |
| 394 » » mime_types[0] = (const char *)(cache->buffer + offset); |
| 395 |
| 396 » » return 1; |
| 397 » » } |
| 398 » return 0; |
392 } | 399 } |
393 } | 400 } |
394 } | 401 } |
395 | 402 |
396 return 0; | 403 return 0; |
397 } | 404 } |
398 | 405 |
399 static int | 406 static int |
400 cache_glob_lookup_fnmatch (const char *file_name, | 407 cache_glob_lookup_fnmatch (const char *file_name, |
401 MimeWeight mime_types[], | 408 MimeWeight mime_types[], |
402 » » » int n_mime_types) | 409 » » » int n_mime_types, |
| 410 » » » int case_sensitive_check) |
403 { | 411 { |
404 const char *mime_type; | 412 const char *mime_type; |
405 const char *ptr; | 413 const char *ptr; |
406 | 414 |
407 int i, j, n; | 415 int i, j, n; |
408 | 416 |
409 n = 0; | 417 n = 0; |
410 for (i = 0; _caches[i]; i++) | 418 for (i = 0; _caches[i]; i++) |
411 { | 419 { |
412 XdgMimeCache *cache = _caches[i]; | 420 XdgMimeCache *cache = _caches[i]; |
413 | 421 |
414 xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 20); | 422 xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 20); |
415 xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset); | 423 xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset); |
416 | 424 |
417 for (j = 0; j < n_entries && n < n_mime_types; j++) | 425 for (j = 0; j < n_entries && n < n_mime_types; j++) |
418 { | 426 { |
419 xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12
* j); | 427 xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12
* j); |
420 xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset
+ 4 + 12 * j + 4); | 428 xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset
+ 4 + 12 * j + 4); |
421 int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 8); | 429 int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 8); |
| 430 int case_sensitive = weight & 0x100; |
| 431 weight = weight & 0xff; |
422 ptr = cache->buffer + offset; | 432 ptr = cache->buffer + offset; |
423 mime_type = cache->buffer + mimetype_offset; | 433 mime_type = cache->buffer + mimetype_offset; |
424 | 434 » if (case_sensitive_check || !case_sensitive) |
425 » /* FIXME: Not UTF-8 safe */ | |
426 » if (fnmatch (ptr, file_name, 0) == 0) | |
427 { | 435 { |
428 » mime_types[n].mime = mime_type; | 436 » /* FIXME: Not UTF-8 safe */ |
429 » mime_types[n].weight = weight; | 437 » if (fnmatch (ptr, file_name, 0) == 0) |
430 » n++; | 438 » { |
| 439 » mime_types[n].mime = mime_type; |
| 440 » mime_types[n].weight = weight; |
| 441 » n++; |
| 442 » } |
431 } | 443 } |
432 } | 444 } |
433 | 445 |
434 if (n > 0) | 446 if (n > 0) |
435 return n; | 447 return n; |
436 } | 448 } |
437 | 449 |
438 return 0; | 450 return 0; |
439 } | 451 } |
440 | 452 |
441 static int | 453 static int |
442 cache_glob_node_lookup_suffix (XdgMimeCache *cache, | 454 cache_glob_node_lookup_suffix (XdgMimeCache *cache, |
443 xdg_uint32_t n_entries, | 455 xdg_uint32_t n_entries, |
444 xdg_uint32_t offset, | 456 xdg_uint32_t offset, |
445 const char *file_name, | 457 const char *file_name, |
446 int len, | 458 int len, |
447 » » » int ignore_case, | 459 » » » int case_sensitive_check, |
448 MimeWeight mime_types[], | 460 MimeWeight mime_types[], |
449 int n_mime_types) | 461 int n_mime_types) |
450 { | 462 { |
451 xdg_unichar_t character; | 463 xdg_unichar_t character; |
452 xdg_unichar_t match_char; | 464 xdg_unichar_t match_char; |
453 xdg_uint32_t mimetype_offset; | 465 xdg_uint32_t mimetype_offset; |
454 xdg_uint32_t n_children; | 466 xdg_uint32_t n_children; |
455 xdg_uint32_t child_offset; | 467 xdg_uint32_t child_offset; |
456 int weight; | 468 int weight; |
| 469 int case_sensitive; |
457 | 470 |
458 int min, max, mid, n, i; | 471 int min, max, mid, n, i; |
459 | 472 |
460 character = file_name[len - 1]; | 473 character = file_name[len - 1]; |
461 if (ignore_case) | |
462 character = tolower (character); | |
463 | 474 |
464 assert (character != 0); | 475 assert (character != 0); |
465 | 476 |
466 min = 0; | 477 min = 0; |
467 max = n_entries - 1; | 478 max = n_entries - 1; |
468 while (max >= min) | 479 while (max >= min) |
469 { | 480 { |
470 mid = (min + max) / 2; | 481 mid = (min + max) / 2; |
471 match_char = GET_UINT32 (cache->buffer, offset + 12 * mid); | 482 match_char = GET_UINT32 (cache->buffer, offset + 12 * mid); |
472 if (match_char < character) | 483 if (match_char < character) |
473 min = mid + 1; | 484 min = mid + 1; |
474 else if (match_char > character) | 485 else if (match_char > character) |
475 max = mid - 1; | 486 max = mid - 1; |
476 else | 487 else |
477 { | 488 { |
478 len--; | 489 len--; |
479 n = 0; | 490 n = 0; |
480 n_children = GET_UINT32 (cache->buffer, offset + 12 * mid + 4); | 491 n_children = GET_UINT32 (cache->buffer, offset + 12 * mid + 4); |
481 child_offset = GET_UINT32 (cache->buffer, offset + 12 * mid + 8); | 492 child_offset = GET_UINT32 (cache->buffer, offset + 12 * mid + 8); |
482 | 493 |
483 if (len > 0) | 494 if (len > 0) |
484 { | 495 { |
485 n = cache_glob_node_lookup_suffix (cache, | 496 n = cache_glob_node_lookup_suffix (cache, |
486 n_children, child_offset, | 497 n_children, child_offset, |
487 file_name, len, | 498 file_name, len, |
488 ignore_case, | 499 case_sensitive_check, |
489 mime_types, | 500 mime_types, |
490 n_mime_types); | 501 n_mime_types); |
491 } | 502 } |
492 if (n == 0) | 503 if (n == 0) |
493 { | 504 { |
494 i = 0; | 505 i = 0; |
495 while (n < n_mime_types && i < n_children) | 506 while (n < n_mime_types && i < n_children) |
496 { | 507 { |
497 match_char = GET_UINT32 (cache->buffer, child_offset + 12 * i)
; | 508 match_char = GET_UINT32 (cache->buffer, child_offset + 12 * i)
; |
498 if (match_char != 0) | 509 if (match_char != 0) |
499 break; | 510 break; |
500 | 511 |
501 mimetype_offset = GET_UINT32 (cache->buffer, child_offset + 12
* i + 4); | 512 mimetype_offset = GET_UINT32 (cache->buffer, child_offset + 12
* i + 4); |
502 weight = GET_UINT32 (cache->buffer, child_offset + 12 * i + 8)
; | 513 weight = GET_UINT32 (cache->buffer, child_offset + 12 * i + 8)
; |
| 514 case_sensitive = weight & 0x100; |
| 515 weight = weight & 0xff; |
503 | 516 |
504 » » mime_types[n].mime = cache->buffer + mimetype_offset; | 517 » » if (case_sensitive_check || !case_sensitive) |
505 » » mime_types[n].weight = weight; | 518 » » { |
506 » » n++; | 519 » » mime_types[n].mime = cache->buffer + mimetype_offset; |
| 520 » » mime_types[n].weight = weight; |
| 521 » » n++; |
| 522 » » } |
507 i++; | 523 i++; |
508 } | 524 } |
509 } | 525 } |
510 return n; | 526 return n; |
511 } | 527 } |
512 } | 528 } |
513 return 0; | 529 return 0; |
514 } | 530 } |
515 | 531 |
516 static int | 532 static int |
(...skipping 24 matching lines...) Expand all Loading... |
541 } | 557 } |
542 | 558 |
543 return 0; | 559 return 0; |
544 } | 560 } |
545 | 561 |
546 static int compare_mime_weight (const void *a, const void *b) | 562 static int compare_mime_weight (const void *a, const void *b) |
547 { | 563 { |
548 const MimeWeight *aa = (const MimeWeight *)a; | 564 const MimeWeight *aa = (const MimeWeight *)a; |
549 const MimeWeight *bb = (const MimeWeight *)b; | 565 const MimeWeight *bb = (const MimeWeight *)b; |
550 | 566 |
551 return aa->weight - bb->weight; | 567 return bb->weight - aa->weight; |
| 568 } |
| 569 |
| 570 #define ISUPPER(c)» » ((c) >= 'A' && (c) <= 'Z') |
| 571 static char * |
| 572 ascii_tolower (const char *str) |
| 573 { |
| 574 char *p, *lower; |
| 575 |
| 576 lower = strdup (str); |
| 577 p = lower; |
| 578 while (*p != 0) |
| 579 { |
| 580 char c = *p; |
| 581 *p++ = ISUPPER (c) ? c - 'A' + 'a' : c; |
| 582 } |
| 583 return lower; |
552 } | 584 } |
553 | 585 |
554 static int | 586 static int |
555 cache_glob_lookup_file_name (const char *file_name, | 587 cache_glob_lookup_file_name (const char *file_name, |
556 const char *mime_types[], | 588 const char *mime_types[], |
557 int n_mime_types) | 589 int n_mime_types) |
558 { | 590 { |
559 int n; | 591 int n; |
560 MimeWeight mimes[10]; | 592 MimeWeight mimes[10]; |
561 int n_mimes = 10; | 593 int n_mimes = 10; |
562 int i; | 594 int i; |
563 int len; | 595 int len; |
564 | 596 char *lower_case; |
| 597 |
565 assert (file_name != NULL && n_mime_types > 0); | 598 assert (file_name != NULL && n_mime_types > 0); |
566 | 599 |
567 /* First, check the literals */ | 600 /* First, check the literals */ |
568 n = cache_glob_lookup_literal (file_name, mime_types, n_mime_types); | 601 |
| 602 lower_case = ascii_tolower (file_name); |
| 603 |
| 604 n = cache_glob_lookup_literal (lower_case, mime_types, n_mime_types, FALSE); |
569 if (n > 0) | 605 if (n > 0) |
570 return n; | 606 { |
| 607 free (lower_case); |
| 608 return n; |
| 609 } |
| 610 |
| 611 n = cache_glob_lookup_literal (file_name, mime_types, n_mime_types, TRUE); |
| 612 if (n > 0) |
| 613 { |
| 614 free (lower_case); |
| 615 return n; |
| 616 } |
571 | 617 |
572 len = strlen (file_name); | 618 len = strlen (file_name); |
573 n = cache_glob_lookup_suffix (file_name, len, FALSE, mimes, n_mimes); | 619 n = cache_glob_lookup_suffix (lower_case, len, FALSE, mimes, n_mimes); |
574 | |
575 if (n == 0) | 620 if (n == 0) |
576 n = cache_glob_lookup_suffix (file_name, len, TRUE, mimes, n_mimes); | 621 n = cache_glob_lookup_suffix (file_name, len, TRUE, mimes, n_mimes); |
577 | 622 |
578 /* Last, try fnmatch */ | 623 /* Last, try fnmatch */ |
579 if (n == 0) | 624 if (n == 0) |
580 n = cache_glob_lookup_fnmatch (file_name, mimes, n_mimes); | 625 n = cache_glob_lookup_fnmatch (lower_case, mimes, n_mimes, FALSE); |
| 626 if (n == 0) |
| 627 n = cache_glob_lookup_fnmatch (file_name, mimes, n_mimes, TRUE); |
| 628 |
| 629 free (lower_case); |
581 | 630 |
582 qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight); | 631 qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight); |
583 | 632 |
584 if (n_mime_types < n) | 633 if (n_mime_types < n) |
585 n = n_mime_types; | 634 n = n_mime_types; |
586 | 635 |
587 for (i = 0; i < n; i++) | 636 for (i = 0; i < n; i++) |
588 mime_types[i] = mimes[i].mime; | 637 mime_types[i] = mimes[i].mime; |
589 | 638 |
590 return n; | 639 return n; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
632 mime_types, n_mime_types); | 681 mime_types, n_mime_types); |
633 if (prio > priority) | 682 if (prio > priority) |
634 { | 683 { |
635 priority = prio; | 684 priority = prio; |
636 mime_type = match; | 685 mime_type = match; |
637 } | 686 } |
638 } | 687 } |
639 | 688 |
640 if (result_prio) | 689 if (result_prio) |
641 *result_prio = priority; | 690 *result_prio = priority; |
642 | 691 |
643 if (priority > 0) | 692 if (priority > 0) |
644 return mime_type; | 693 { |
| 694 /* Pick glob-result R where mime_type inherits from R */ |
| 695 for (n = 0; n < n_mime_types; n++) |
| 696 { |
| 697 if (mime_types[n] && _xdg_mime_cache_mime_type_subclass(mime_types[n],
mime_type)) |
| 698 return mime_types[n]; |
| 699 } |
645 | 700 |
| 701 /* Return magic match */ |
| 702 return mime_type; |
| 703 } |
| 704 |
| 705 /* Pick first glob result, as fallback */ |
646 for (n = 0; n < n_mime_types; n++) | 706 for (n = 0; n < n_mime_types; n++) |
647 { | 707 { |
648 | |
649 if (mime_types[n]) | 708 if (mime_types[n]) |
650 » return mime_types[n]; | 709 return mime_types[n]; |
651 } | 710 } |
652 | 711 |
653 return XDG_MIME_TYPE_UNKNOWN; | 712 return NULL; |
654 } | 713 } |
655 | 714 |
656 const char * | 715 const char * |
657 _xdg_mime_cache_get_mime_type_for_data (const void *data, | 716 _xdg_mime_cache_get_mime_type_for_data (const void *data, |
658 size_t len, | 717 size_t len, |
659 int *result_prio) | 718 int *result_prio) |
660 { | 719 { |
661 return cache_get_mime_type_for_data (data, len, result_prio, NULL, 0); | 720 return cache_get_mime_type_for_data (data, len, result_prio, NULL, 0); |
662 } | 721 } |
663 | 722 |
(...skipping 24 matching lines...) Expand all Loading... |
688 return mime_types[0]; | 747 return mime_types[0]; |
689 | 748 |
690 if (!statbuf) | 749 if (!statbuf) |
691 { | 750 { |
692 if (stat (file_name, &buf) != 0) | 751 if (stat (file_name, &buf) != 0) |
693 return XDG_MIME_TYPE_UNKNOWN; | 752 return XDG_MIME_TYPE_UNKNOWN; |
694 | 753 |
695 statbuf = &buf; | 754 statbuf = &buf; |
696 } | 755 } |
697 | 756 |
| 757 if (statbuf->st_size == 0) |
| 758 return XDG_MIME_TYPE_EMPTY; |
| 759 |
698 if (!S_ISREG (statbuf->st_mode)) | 760 if (!S_ISREG (statbuf->st_mode)) |
699 return XDG_MIME_TYPE_UNKNOWN; | 761 return XDG_MIME_TYPE_UNKNOWN; |
700 | 762 |
701 /* FIXME: Need to make sure that max_extent isn't totally broken. This could | 763 /* FIXME: Need to make sure that max_extent isn't totally broken. This could |
702 * be large and need getting from a stream instead of just reading it all | 764 * be large and need getting from a stream instead of just reading it all |
703 * in. */ | 765 * in. */ |
704 max_extent = _xdg_mime_cache_get_max_buffer_extents (); | 766 max_extent = _xdg_mime_cache_get_max_buffer_extents (); |
705 data = malloc (max_extent); | 767 data = malloc (max_extent); |
706 if (data == NULL) | 768 if (data == NULL) |
707 return XDG_MIME_TYPE_UNKNOWN; | 769 return XDG_MIME_TYPE_UNKNOWN; |
708 | 770 |
709 file = fopen (file_name, "r"); | 771 file = fopen (file_name, "r"); |
710 if (file == NULL) | 772 if (file == NULL) |
711 { | 773 { |
712 free (data); | 774 free (data); |
713 return XDG_MIME_TYPE_UNKNOWN; | 775 return XDG_MIME_TYPE_UNKNOWN; |
714 } | 776 } |
715 | 777 |
716 bytes_read = fread (data, 1, max_extent, file); | 778 bytes_read = fread (data, 1, max_extent, file); |
717 if (ferror (file)) | 779 if (ferror (file)) |
718 { | 780 { |
719 free (data); | 781 free (data); |
720 fclose (file); | 782 fclose (file); |
721 return XDG_MIME_TYPE_UNKNOWN; | 783 return XDG_MIME_TYPE_UNKNOWN; |
722 } | 784 } |
723 | 785 |
724 mime_type = cache_get_mime_type_for_data (data, bytes_read, NULL, | 786 mime_type = cache_get_mime_type_for_data (data, bytes_read, NULL, |
725 mime_types, n); | 787 mime_types, n); |
726 | 788 |
| 789 if (!mime_type) |
| 790 mime_type = _xdg_binary_or_text_fallback(data, bytes_read); |
| 791 |
727 free (data); | 792 free (data); |
728 fclose (file); | 793 fclose (file); |
729 | 794 |
730 return mime_type; | 795 return mime_type; |
731 } | 796 } |
732 | 797 |
733 const char * | 798 const char * |
734 _xdg_mime_cache_get_mime_type_from_file_name (const char *file_name) | 799 _xdg_mime_cache_get_mime_type_from_file_name (const char *file_name) |
735 { | 800 { |
736 const char *mime_type; | 801 const char *mime_type; |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
995 xdg_uint32_t list_offset; | 1060 xdg_uint32_t list_offset; |
996 xdg_uint32_t n_entries; | 1061 xdg_uint32_t n_entries; |
997 xdg_uint32_t offset; | 1062 xdg_uint32_t offset; |
998 list_offset = GET_UINT32 (cache->buffer, 16); | 1063 list_offset = GET_UINT32 (cache->buffer, 16); |
999 n_entries = GET_UINT32 (cache->buffer, list_offset); | 1064 n_entries = GET_UINT32 (cache->buffer, list_offset); |
1000 offset = GET_UINT32 (cache->buffer, list_offset + 4); | 1065 offset = GET_UINT32 (cache->buffer, list_offset + 4); |
1001 for (j = 0; j < n_entries; j++) | 1066 for (j = 0; j < n_entries; j++) |
1002 dump_glob_node (cache, offset + 20 * j, 0); | 1067 dump_glob_node (cache, offset + 20 * j, 0); |
1003 } | 1068 } |
1004 } | 1069 } |
OLD | NEW |