Index: base/third_party/xdg_mime/xdgmimecache.c |
=================================================================== |
--- base/third_party/xdg_mime/xdgmimecache.c (revision 150109) |
+++ base/third_party/xdg_mime/xdgmimecache.c (working copy) |
@@ -25,13 +25,12 @@ |
*/ |
#ifdef HAVE_CONFIG_H |
-#include "config.h" |
+#include <config.h> |
#endif |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
-#include <ctype.h> |
#include <fcntl.h> |
#include <unistd.h> |
@@ -45,7 +44,7 @@ |
#ifdef HAVE_MMAP |
#include <sys/mman.h> |
#else |
-#warning Building xdgmime without MMAP support. Binary "mime.info" cache files will not be used. |
+#warning Building xdgmime without MMAP support. Binary "mime.cache" files will not be used. |
#endif |
#include <sys/stat.h> |
@@ -75,11 +74,13 @@ |
#endif |
#define MAJOR_VERSION 1 |
-#define MINOR_VERSION 1 |
+#define MINOR_VERSION_MIN 1 |
+#define MINOR_VERSION_MAX 2 |
struct _XdgMimeCache |
{ |
int ref_count; |
+ int minor; |
size_t size; |
char *buffer; |
@@ -118,6 +119,7 @@ |
int fd = -1; |
struct stat st; |
char *buffer = NULL; |
+ int minor; |
/* Open the file and map it into memory */ |
fd = open (file_name, O_RDONLY|_O_BINARY, 0); |
@@ -133,9 +135,11 @@ |
if (buffer == MAP_FAILED) |
goto done; |
+ minor = GET_UINT16 (buffer, 2); |
/* Verify version */ |
if (GET_UINT16 (buffer, 0) != MAJOR_VERSION || |
- GET_UINT16 (buffer, 2) != MINOR_VERSION) |
+ (minor < MINOR_VERSION_MIN || |
+ minor > MINOR_VERSION_MAX)) |
{ |
munmap (buffer, st.st_size); |
@@ -143,6 +147,7 @@ |
} |
cache = (XdgMimeCache *) malloc (sizeof (XdgMimeCache)); |
+ cache->minor = minor; |
cache->ref_count = 1; |
cache->buffer = buffer; |
cache->size = st.st_size; |
@@ -170,7 +175,7 @@ |
int i, j; |
- for (i = range_start; i <= range_start + range_length; i++) |
+ for (i = range_start; i < range_start + range_length; i++) |
{ |
int valid_matchlet = TRUE; |
@@ -191,16 +196,9 @@ |
} |
else |
{ |
- for (j = 0; j < data_length; j++) |
- { |
- if (((unsigned char *)cache->buffer)[data_offset + j] != ((unsigned char *) data)[j + i]) |
- { |
- valid_matchlet = FALSE; |
- break; |
- } |
- } |
+ valid_matchlet = memcmp(cache->buffer + data_offset, data + i, data_length) == 0; |
} |
- |
+ |
if (valid_matchlet) |
return TRUE; |
} |
@@ -357,7 +355,8 @@ |
static int |
cache_glob_lookup_literal (const char *file_name, |
const char *mime_types[], |
- int n_mime_types) |
+ int n_mime_types, |
+ int case_sensitive_check) |
{ |
const char *ptr; |
int i, min, max, mid, cmp; |
@@ -378,17 +377,25 @@ |
offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid); |
ptr = cache->buffer + offset; |
cmp = strcmp (ptr, file_name); |
- |
+ |
if (cmp < 0) |
min = mid + 1; |
else if (cmp > 0) |
max = mid - 1; |
else |
{ |
- offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 4); |
- mime_types[0] = (const char *)(cache->buffer + offset); |
- |
- return 1; |
+ int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 8); |
+ int case_sensitive = weight & 0x100; |
+ weight = weight & 0xff; |
+ |
+ if (case_sensitive_check || !case_sensitive) |
+ { |
+ offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 4); |
+ mime_types[0] = (const char *)(cache->buffer + offset); |
+ |
+ return 1; |
+ } |
+ return 0; |
} |
} |
} |
@@ -399,7 +406,8 @@ |
static int |
cache_glob_lookup_fnmatch (const char *file_name, |
MimeWeight mime_types[], |
- int n_mime_types) |
+ int n_mime_types, |
+ int case_sensitive_check) |
{ |
const char *mime_type; |
const char *ptr; |
@@ -419,15 +427,19 @@ |
xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j); |
xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 4); |
int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 8); |
+ int case_sensitive = weight & 0x100; |
+ weight = weight & 0xff; |
ptr = cache->buffer + offset; |
mime_type = cache->buffer + mimetype_offset; |
- |
- /* FIXME: Not UTF-8 safe */ |
- if (fnmatch (ptr, file_name, 0) == 0) |
+ if (case_sensitive_check || !case_sensitive) |
{ |
- mime_types[n].mime = mime_type; |
- mime_types[n].weight = weight; |
- n++; |
+ /* FIXME: Not UTF-8 safe */ |
+ if (fnmatch (ptr, file_name, 0) == 0) |
+ { |
+ mime_types[n].mime = mime_type; |
+ mime_types[n].weight = weight; |
+ n++; |
+ } |
} |
} |
@@ -444,7 +456,7 @@ |
xdg_uint32_t offset, |
const char *file_name, |
int len, |
- int ignore_case, |
+ int case_sensitive_check, |
MimeWeight mime_types[], |
int n_mime_types) |
{ |
@@ -454,12 +466,11 @@ |
xdg_uint32_t n_children; |
xdg_uint32_t child_offset; |
int weight; |
+ int case_sensitive; |
int min, max, mid, n, i; |
character = file_name[len - 1]; |
- if (ignore_case) |
- character = tolower (character); |
assert (character != 0); |
@@ -485,7 +496,7 @@ |
n = cache_glob_node_lookup_suffix (cache, |
n_children, child_offset, |
file_name, len, |
- ignore_case, |
+ case_sensitive_check, |
mime_types, |
n_mime_types); |
} |
@@ -500,10 +511,15 @@ |
mimetype_offset = GET_UINT32 (cache->buffer, child_offset + 12 * i + 4); |
weight = GET_UINT32 (cache->buffer, child_offset + 12 * i + 8); |
+ case_sensitive = weight & 0x100; |
+ weight = weight & 0xff; |
- mime_types[n].mime = cache->buffer + mimetype_offset; |
- mime_types[n].weight = weight; |
- n++; |
+ if (case_sensitive_check || !case_sensitive) |
+ { |
+ mime_types[n].mime = cache->buffer + mimetype_offset; |
+ mime_types[n].weight = weight; |
+ n++; |
+ } |
i++; |
} |
} |
@@ -548,9 +564,25 @@ |
const MimeWeight *aa = (const MimeWeight *)a; |
const MimeWeight *bb = (const MimeWeight *)b; |
- return aa->weight - bb->weight; |
+ return bb->weight - aa->weight; |
} |
+#define ISUPPER(c) ((c) >= 'A' && (c) <= 'Z') |
+static char * |
+ascii_tolower (const char *str) |
+{ |
+ char *p, *lower; |
+ |
+ lower = strdup (str); |
+ p = lower; |
+ while (*p != 0) |
+ { |
+ char c = *p; |
+ *p++ = ISUPPER (c) ? c - 'A' + 'a' : c; |
+ } |
+ return lower; |
+} |
+ |
static int |
cache_glob_lookup_file_name (const char *file_name, |
const char *mime_types[], |
@@ -561,24 +593,41 @@ |
int n_mimes = 10; |
int i; |
int len; |
- |
+ char *lower_case; |
+ |
assert (file_name != NULL && n_mime_types > 0); |
/* First, check the literals */ |
- n = cache_glob_lookup_literal (file_name, mime_types, n_mime_types); |
+ |
+ lower_case = ascii_tolower (file_name); |
+ |
+ n = cache_glob_lookup_literal (lower_case, mime_types, n_mime_types, FALSE); |
if (n > 0) |
- return n; |
+ { |
+ free (lower_case); |
+ return n; |
+ } |
+ n = cache_glob_lookup_literal (file_name, mime_types, n_mime_types, TRUE); |
+ if (n > 0) |
+ { |
+ free (lower_case); |
+ return n; |
+ } |
+ |
len = strlen (file_name); |
- n = cache_glob_lookup_suffix (file_name, len, FALSE, mimes, n_mimes); |
- |
+ n = cache_glob_lookup_suffix (lower_case, len, FALSE, mimes, n_mimes); |
if (n == 0) |
n = cache_glob_lookup_suffix (file_name, len, TRUE, mimes, n_mimes); |
- |
+ |
/* Last, try fnmatch */ |
if (n == 0) |
- n = cache_glob_lookup_fnmatch (file_name, mimes, n_mimes); |
+ n = cache_glob_lookup_fnmatch (lower_case, mimes, n_mimes, FALSE); |
+ if (n == 0) |
+ n = cache_glob_lookup_fnmatch (file_name, mimes, n_mimes, TRUE); |
+ free (lower_case); |
+ |
qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight); |
if (n_mime_types < n) |
@@ -639,18 +688,28 @@ |
if (result_prio) |
*result_prio = priority; |
- |
+ |
if (priority > 0) |
- return mime_type; |
+ { |
+ /* Pick glob-result R where mime_type inherits from R */ |
+ for (n = 0; n < n_mime_types; n++) |
+ { |
+ if (mime_types[n] && _xdg_mime_cache_mime_type_subclass(mime_types[n], mime_type)) |
+ return mime_types[n]; |
+ } |
+ /* Return magic match */ |
+ return mime_type; |
+ } |
+ |
+ /* Pick first glob result, as fallback */ |
for (n = 0; n < n_mime_types; n++) |
{ |
- |
if (mime_types[n]) |
- return mime_types[n]; |
+ return mime_types[n]; |
} |
- return XDG_MIME_TYPE_UNKNOWN; |
+ return NULL; |
} |
const char * |
@@ -695,6 +754,9 @@ |
statbuf = &buf; |
} |
+ if (statbuf->st_size == 0) |
+ return XDG_MIME_TYPE_EMPTY; |
+ |
if (!S_ISREG (statbuf->st_mode)) |
return XDG_MIME_TYPE_UNKNOWN; |
@@ -724,6 +786,9 @@ |
mime_type = cache_get_mime_type_for_data (data, bytes_read, NULL, |
mime_types, n); |
+ if (!mime_type) |
+ mime_type = _xdg_binary_or_text_fallback(data, bytes_read); |
+ |
free (data); |
fclose (file); |