diff --git a/ChangeLog b/ChangeLog index 848765a347fbea7c99db53681abba4d2ee44e4cc..4e06c4e80c5d1e875cadb19ec17f8953821bf2b3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2006-03-07 Benedikt Meurer <benny@xfce.org> + + * thunar-vfs/thunar-vfs-mime-legacy.c: Implement magic handling for + the legacy backend (shared-mime-info <= 0.16). Bug #1106. + 2006-03-07 Benedikt Meurer <benny@xfce.org> * thunar-vfs/thunar-vfs-xfer.c: Automatically give write permissions to diff --git a/thunar-vfs/thunar-vfs-mime-legacy.c b/thunar-vfs/thunar-vfs-mime-legacy.c index d35436a4cf6a9f3c9ff72f1ecc9ef24962a51af0..f039aa96ee503ae99f75880e6517714f4f61c9b7 100644 --- a/thunar-vfs/thunar-vfs-mime-legacy.c +++ b/thunar-vfs/thunar-vfs-mime-legacy.c @@ -1,6 +1,6 @@ /* $Id$ */ /*- - * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org> + * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,13 +25,22 @@ #include <config.h> #endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif #ifdef HAVE_FNMATCH_H #include <fnmatch.h> #endif +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif #ifdef HAVE_MEMORY_H #include <memory.h> #endif #include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif #ifdef HAVE_STRING_H #include <string.h> #endif @@ -41,44 +50,57 @@ -#define THUNAR_VFS_MIME_LEGACY_GLOB(obj) ((ThunarVfsMimeLegacyGlob *) (obj)) -#define THUNAR_VFS_MIME_LEGACY_SUFFIX(obj) ((ThunarVfsMimeLegacySuffix *) (obj)) - - - -typedef struct _ThunarVfsMimeLegacyGlob ThunarVfsMimeLegacyGlob; -typedef struct _ThunarVfsMimeLegacySuffix ThunarVfsMimeLegacySuffix; - - - -static void thunar_vfs_mime_legacy_class_init (ThunarVfsMimeLegacyClass *klass); -static void thunar_vfs_mime_legacy_init (ThunarVfsMimeLegacy *legacy); -static void thunar_vfs_mime_legacy_finalize (GObject *object); -static const gchar *thunar_vfs_mime_legacy_lookup_data (ThunarVfsMimeProvider *provider, - gconstpointer data, - gsize length, - gint *priority); -static const gchar *thunar_vfs_mime_legacy_lookup_literal (ThunarVfsMimeProvider *provider, - const gchar *filename); -static const gchar *thunar_vfs_mime_legacy_lookup_suffix (ThunarVfsMimeProvider *provider, - const gchar *suffix, - gboolean ignore_case); -static const gchar *thunar_vfs_mime_legacy_lookup_glob (ThunarVfsMimeProvider *provider, - const gchar *filename); -static const gchar *thunar_vfs_mime_legacy_lookup_alias (ThunarVfsMimeProvider *provider, - const gchar *alias); -static guint thunar_vfs_mime_legacy_lookup_parents (ThunarVfsMimeProvider *provider, - const gchar *mime_type, - gchar **parents, - guint max_parents); -static GList *thunar_vfs_mime_legacy_get_stop_characters (ThunarVfsMimeProvider *provider); -static gsize thunar_vfs_mime_legacy_get_max_buffer_extents (ThunarVfsMimeProvider *provider); -static void thunar_vfs_mime_legacy_parse_aliases (ThunarVfsMimeLegacy *legacy, - const gchar *directory); -static gboolean thunar_vfs_mime_legacy_parse_globs (ThunarVfsMimeLegacy *legacy, - const gchar *directory); -static void thunar_vfs_mime_legacy_parse_subclasses (ThunarVfsMimeLegacy *legacy, - const gchar *directory); +#define THUNAR_VFS_MIME_LEGACY_GLOB(obj) ((ThunarVfsMimeLegacyGlob *) (obj)) +#define THUNAR_VFS_MIME_LEGACY_SUFFIX(obj) ((ThunarVfsMimeLegacySuffix *) (obj)) +#define THUNAR_VFS_MIME_LEGACY_MATCH(obj) ((ThunarVfsMimeLegacyMatch *) (obj)) +#define THUNAR_VFS_MIME_LEGACY_MATCHLET(obj) ((ThunarVfsMimeLegacyMatchlet *) (obj)) + + + +typedef struct _ThunarVfsMimeLegacyGlob ThunarVfsMimeLegacyGlob; +typedef struct _ThunarVfsMimeLegacySuffix ThunarVfsMimeLegacySuffix; +typedef struct _ThunarVfsMimeLegacyMatch ThunarVfsMimeLegacyMatch; +typedef struct _ThunarVfsMimeLegacyMatchlet ThunarVfsMimeLegacyMatchlet; +typedef enum _ThunarVfsMimeLegacyMagic ThunarVfsMimeLegacyMagic; + + + +static void thunar_vfs_mime_legacy_class_init (ThunarVfsMimeLegacyClass *klass); +static void thunar_vfs_mime_legacy_init (ThunarVfsMimeLegacy *legacy); +static void thunar_vfs_mime_legacy_finalize (GObject *object); +static const gchar *thunar_vfs_mime_legacy_lookup_data (ThunarVfsMimeProvider *provider, + gconstpointer data, + gsize length, + gint *priority); +static const gchar *thunar_vfs_mime_legacy_lookup_literal (ThunarVfsMimeProvider *provider, + const gchar *filename); +static const gchar *thunar_vfs_mime_legacy_lookup_suffix (ThunarVfsMimeProvider *provider, + const gchar *suffix, + gboolean ignore_case); +static const gchar *thunar_vfs_mime_legacy_lookup_glob (ThunarVfsMimeProvider *provider, + const gchar *filename); +static const gchar *thunar_vfs_mime_legacy_lookup_alias (ThunarVfsMimeProvider *provider, + const gchar *alias); +static guint thunar_vfs_mime_legacy_lookup_parents (ThunarVfsMimeProvider *provider, + const gchar *mime_type, + gchar **parents, + guint max_parents); +static GList *thunar_vfs_mime_legacy_get_stop_characters (ThunarVfsMimeProvider *provider); +static gsize thunar_vfs_mime_legacy_get_max_buffer_extents (ThunarVfsMimeProvider *provider); +static void thunar_vfs_mime_legacy_parse_aliases (ThunarVfsMimeLegacy *legacy, + const gchar *directory); +static gboolean thunar_vfs_mime_legacy_parse_globs (ThunarVfsMimeLegacy *legacy, + const gchar *directory); +static void thunar_vfs_mime_legacy_parse_subclasses (ThunarVfsMimeLegacy *legacy, + const gchar *directory); +static void thunar_vfs_mime_legacy_parse_magic (ThunarVfsMimeLegacy *legacy, + const gchar *directory); +static ThunarVfsMimeLegacyMagic thunar_vfs_mime_legacy_parse_magic_header (ThunarVfsMimeLegacy *legacy, + ThunarVfsMimeLegacyMatch *match, + FILE *fp); +static ThunarVfsMimeLegacyMagic thunar_vfs_mime_legacy_parse_magic_line (ThunarVfsMimeLegacy *legacy, + ThunarVfsMimeLegacyMatch *match, + FILE *fp); @@ -94,6 +116,8 @@ struct _ThunarVfsMimeLegacy GStringChunk *string_chunk; GMemChunk *suffix_chunk; GMemChunk *glob_chunk; + GMemChunk *match_chunk; + GMemChunk *matchlet_chunk; GHashTable *literals; ThunarVfsMimeLegacySuffix *suffixes; @@ -101,6 +125,9 @@ struct _ThunarVfsMimeLegacy GHashTable *aliases; GHashTable *parents; + + GList *matches; + gsize max_buffer_extents; }; struct _ThunarVfsMimeLegacyGlob @@ -117,6 +144,32 @@ struct _ThunarVfsMimeLegacySuffix gunichar character; }; +struct _ThunarVfsMimeLegacyMatch +{ + const gchar *mime_type; + gint priority; + GList *matchlets; +}; + +struct _ThunarVfsMimeLegacyMatchlet +{ + gint indent; + gint offset; + guint value_length; + guchar *value; + guchar *mask; + guint range_length; + guint word_size; +}; + +enum _ThunarVfsMimeLegacyMagic +{ + THUNAR_VFS_MIME_LEGACY_MAGIC_SECTION, + THUNAR_VFS_MIME_LEGACY_MAGIC_MAGIC, + THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR, + THUNAR_VFS_MIME_LEGACY_MAGIC_EOF, +}; + static GObjectClass *thunar_vfs_mime_legacy_parent_class; @@ -183,6 +236,8 @@ thunar_vfs_mime_legacy_init (ThunarVfsMimeLegacy *legacy) legacy->string_chunk = g_string_chunk_new (1024); legacy->glob_chunk = g_mem_chunk_create (ThunarVfsMimeLegacyGlob, 32, G_ALLOC_ONLY); legacy->suffix_chunk = g_mem_chunk_create (ThunarVfsMimeLegacySuffix, 128, G_ALLOC_ONLY); + legacy->match_chunk = g_mem_chunk_create (ThunarVfsMimeLegacyMatch, 16, G_ALLOC_ONLY); + legacy->matchlet_chunk = g_mem_chunk_create (ThunarVfsMimeLegacyMatchlet, 32, G_ALLOC_ONLY); legacy->literals = g_hash_table_new (g_str_hash, g_str_equal); @@ -196,6 +251,12 @@ static void thunar_vfs_mime_legacy_finalize (GObject *object) { ThunarVfsMimeLegacy *legacy = THUNAR_VFS_MIME_LEGACY (object); + GList *lp; + + /* free match and matchlet lists */ + for (lp = legacy->matches; lp != NULL; lp = lp->next) + g_list_free (THUNAR_VFS_MIME_LEGACY_MATCH (lp->data)->matchlets); + g_list_free (legacy->matches); /* free parents hash table */ g_hash_table_destroy (legacy->parents); @@ -213,18 +274,103 @@ thunar_vfs_mime_legacy_finalize (GObject *object) g_string_chunk_free (legacy->string_chunk); g_mem_chunk_destroy (legacy->suffix_chunk); g_mem_chunk_destroy (legacy->glob_chunk); + g_mem_chunk_destroy (legacy->match_chunk); + g_mem_chunk_destroy (legacy->matchlet_chunk); (*G_OBJECT_CLASS (thunar_vfs_mime_legacy_parent_class)->finalize) (object); } +static gboolean +tvml_matchlet_compare_to_data (ThunarVfsMimeLegacyMatchlet *matchlet, + gconstpointer data, + gsize length) +{ + gboolean valid_matchlet; + gint i, j; + + for (i = matchlet->offset; i < matchlet->offset + matchlet->range_length; i++) + { + valid_matchlet = TRUE; + + if (i + matchlet->value_length > length) + return FALSE; + + if (matchlet->mask) + { + for (j = 0; j < matchlet->value_length; j++) + if ((matchlet->value[j] & matchlet->mask[j]) != ((((const guchar *) data)[j + i]) & matchlet->mask[j])) + { + valid_matchlet = FALSE; + break; + } + } + else + { + for (j = 0; j < matchlet->value_length; j++) + if (matchlet->value[j] != ((const guchar *) data)[j + i]) + { + valid_matchlet = FALSE; + break; + } + } + + if (valid_matchlet) + return TRUE; + } + + return FALSE; +} + + + +static gboolean +tvml_matchlet_compare_level (GList *matchlet_list, + gconstpointer data, + gsize length, + gint indent) +{ + while (matchlet_list != NULL && THUNAR_VFS_MIME_LEGACY_MATCHLET (matchlet_list->data)->indent == indent) + { + if (tvml_matchlet_compare_to_data (matchlet_list->data, data, length)) + { + if (matchlet_list->next == NULL || THUNAR_VFS_MIME_LEGACY_MATCHLET (matchlet_list->next->data)->indent <= indent) + return TRUE; + + if (tvml_matchlet_compare_level (matchlet_list->next, data, length, indent + 1)) + return TRUE; + } + + do + { + matchlet_list = matchlet_list->next; + } + while (matchlet_list != NULL && THUNAR_VFS_MIME_LEGACY_MATCHLET (matchlet_list->data)->indent > indent); + } + + return FALSE; +} + + + static const gchar* thunar_vfs_mime_legacy_lookup_data (ThunarVfsMimeProvider *provider, gconstpointer data, gsize length, gint *priority) { + ThunarVfsMimeLegacy *legacy = THUNAR_VFS_MIME_LEGACY (provider); + GList *lp; + + for (lp = legacy->matches; lp != NULL; lp = lp->next) + if (tvml_matchlet_compare_level (THUNAR_VFS_MIME_LEGACY_MATCH (lp->data)->matchlets, data, length, 0)) + { + if (G_LIKELY (priority != NULL)) + *priority = THUNAR_VFS_MIME_LEGACY_MATCH (lp->data)->priority; + return THUNAR_VFS_MIME_LEGACY_MATCH (lp->data)->mime_type; + } + return NULL; } @@ -404,7 +550,7 @@ thunar_vfs_mime_legacy_get_stop_characters (ThunarVfsMimeProvider *provider) static gsize thunar_vfs_mime_legacy_get_max_buffer_extents (ThunarVfsMimeProvider *provider) { - return 0; + return THUNAR_VFS_MIME_LEGACY (provider)->max_buffer_extents; } @@ -602,6 +748,402 @@ thunar_vfs_mime_legacy_parse_subclasses (ThunarVfsMimeLegacy *legacy, +static gint +thunar_vfs_mime_legacy_match_compare (gconstpointer a, + gconstpointer b) +{ + return (-1) * (THUNAR_VFS_MIME_LEGACY_MATCH (a)->priority - THUNAR_VFS_MIME_LEGACY_MATCH (b)->priority); +} + + + +static void +thunar_vfs_mime_legacy_parse_magic (ThunarVfsMimeLegacy *legacy, + const gchar *directory) +{ + ThunarVfsMimeLegacyMatch *match = NULL; + ThunarVfsMimeLegacyMagic state; + gchar header[12]; + gchar *path; + GList *lp; + FILE *fp; + gint c; + gint n; + + /* try to open the "magic" file */ + path = g_build_filename (directory, "magic", NULL); + fp = fopen (path, "r"); + g_free (path); + + /* check if we succeed */ + if (G_UNLIKELY (fp == NULL)) + return; + + /* check the header */ + if (fread (header, 1, 12, fp) == 12 && memcmp ("MIME-Magic\0\n", header, 12) == 0) + { + /* parse the file */ + for (state = THUNAR_VFS_MIME_LEGACY_MAGIC_SECTION; state != THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; ) + { + switch (state) + { + case THUNAR_VFS_MIME_LEGACY_MAGIC_SECTION: + match = g_chunk_new0 (ThunarVfsMimeLegacyMatch, legacy->match_chunk); + state = thunar_vfs_mime_legacy_parse_magic_header (legacy, match, fp); + if (state == THUNAR_VFS_MIME_LEGACY_MAGIC_EOF || state == THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR) + match = NULL; + break; + + case THUNAR_VFS_MIME_LEGACY_MAGIC_MAGIC: + state = thunar_vfs_mime_legacy_parse_magic_line (legacy, match, fp); + if ((state == THUNAR_VFS_MIME_LEGACY_MAGIC_EOF && match->mime_type != NULL) + || (state == THUNAR_VFS_MIME_LEGACY_MAGIC_SECTION)) + { + /* determine new max buffer extents */ + for (lp = match->matchlets; lp != NULL; lp = lp->next) + { + /* calculate matchlet extent */ + n = THUNAR_VFS_MIME_LEGACY_MATCHLET (lp->data)->value_length + + THUNAR_VFS_MIME_LEGACY_MATCHLET (lp->data)->range_length + + THUNAR_VFS_MIME_LEGACY_MATCHLET (lp->data)->offset; + + /* check if new max */ + if (n > legacy->max_buffer_extents) + legacy->max_buffer_extents = n; + } + + /* add to internal match list */ + legacy->matches = g_list_insert_sorted (legacy->matches, match, thunar_vfs_mime_legacy_match_compare); + } + else if (state == THUNAR_VFS_MIME_LEGACY_MAGIC_EOF || state == THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR) + match = NULL; + break; + + case THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR: + for (;;) + { + c = getc_unlocked (fp); + if (c == EOF) + { + state = THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + break; + } + else if (c == '\n') + { + state = THUNAR_VFS_MIME_LEGACY_MAGIC_SECTION; + break; + } + } + break; + + default: + /* should never be reached */ + g_assert_not_reached (); + } + } + } + + /* close the file */ + fclose (fp); +} + + + +/* Reads in a hunk of data until a newline character or a '\000' is hit. The + * returned string is null terminated, and doesn't include the newline. + */ +static guchar* +tvml_read_to_newline (FILE *fp, + gboolean *eof) +{ + guchar *retval; + gint len = 128; + gint pos = 0; + gint c; + + retval = g_malloc (len); + *eof = FALSE; + + for (;;) + { + c = getc_unlocked (fp); + if (c == EOF) + { + *eof = TRUE; + break; + } + else if (c == '\n' || c == '\0') + break; + + retval[pos++] = (guchar) c; + if (pos % 128 == 127) + { + len = len + 128; + retval = g_realloc (retval, len); + } + } + + retval[pos] = '\0'; + return retval; +} + + + +/* Returns the number read from the file, or -1 if no number could be read. + */ +static glong +tvml_read_a_number (FILE *fp, + gboolean *eof) +{ + gchar number_string[64]; + glong retval = -1; + gint pos = 0; + gint c; + + *eof = FALSE; + + for (;;) + { + c = getc_unlocked (fp); + if (c == EOF) + { + *eof = TRUE; + break; + } + else if (!g_ascii_isdigit (c)) + { + ungetc (c, fp); + break; + } + + number_string[pos] = (gchar) c; + pos++; + if (pos == sizeof (number_string) - 1) + break; + } + + if (G_LIKELY (pos > 0)) + { + number_string[pos] = '\0'; + errno = 0; + retval = strtol (number_string, NULL, 10); + + if ((retval < INT_MIN) || (retval > INT_MAX) || (errno != 0)) + return -1; + } + + return retval; +} + + + +static ThunarVfsMimeLegacyMagic +thunar_vfs_mime_legacy_parse_magic_header (ThunarVfsMimeLegacy *legacy, + ThunarVfsMimeLegacyMatch *match, + FILE *fp) +{ + /* Headers are of the format: + * [<priority>:<mime-type>] + */ + + gboolean eof = FALSE; + gchar *buffer; + gchar *bp; + gint c; + + c = getc_unlocked (fp); + if (c == EOF) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + else if (c != '[') + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + + match->priority = tvml_read_a_number (fp, &eof); + if (G_UNLIKELY (eof)) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + else if (match->priority == -1) + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + + c = getc_unlocked (fp); + if (c == EOF) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + else if (c != ':') + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + + buffer = (gchar *) tvml_read_to_newline (fp, &eof); + if (G_UNLIKELY (eof)) + { + g_free (buffer); + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + } + + for (bp = buffer; *bp != ']' && *bp != '\0' && *bp != '\n'; ++bp) + ; + if (*bp != ']') + { + g_free (buffer); + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + } + *bp = '\0'; + + match->mime_type = g_string_chunk_insert_const (legacy->string_chunk, buffer); + g_free (buffer); + + return THUNAR_VFS_MIME_LEGACY_MAGIC_MAGIC; +} + + + +static ThunarVfsMimeLegacyMagic +thunar_vfs_mime_legacy_parse_magic_line (ThunarVfsMimeLegacy *legacy, + ThunarVfsMimeLegacyMatch *match, + FILE *fp) +{ + /* Lines are of the format: + * [ indent ] ">" start-offset "=" value + * [ "&" mask ] [ "~" word-size ] [ "+" range-length ] "\n" + */ + + ThunarVfsMimeLegacyMatchlet *matchlet; + gboolean eof = FALSE; + gchar *buffer; + gint bytes_read; + gint indent = 0; + gint c, i; + + /* sniff the buffer to make sure it's a valid line */ + c = getc_unlocked (fp); + if (c == EOF) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + else if (c == '[') + { + ungetc (c, fp); + return THUNAR_VFS_MIME_LEGACY_MAGIC_SECTION; + } + else if (c == '\n') + return THUNAR_VFS_MIME_LEGACY_MAGIC_MAGIC; + + /* At this point, it must be a digit or a '>' */ + if (g_ascii_isdigit (c)) + { + ungetc (c, fp); + indent = tvml_read_a_number (fp, &eof); + if (G_UNLIKELY (eof)) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + else if (G_UNLIKELY (indent == -1)) + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + c = getc_unlocked (fp); + if (c == EOF) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + } + + if (c != '>') + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + + matchlet = g_chunk_new0 (ThunarVfsMimeLegacyMatchlet, legacy->matchlet_chunk); + matchlet->indent = indent; + matchlet->range_length = 1; + matchlet->word_size = 1; + matchlet->offset = tvml_read_a_number (fp, &eof); + + if (G_UNLIKELY (eof)) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + else if (matchlet->offset == -1) + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + + c = getc_unlocked (fp); + if (c == EOF) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + else if (c != '=') + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + + /* Next two bytes determine how long the value is */ + c = getc_unlocked (fp); + if (c == EOF) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + matchlet->value_length = (c & 0xFF) << 8; + + c = getc_unlocked (fp); + if (c == EOF) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + matchlet->value_length += (c & 0xFF); + + buffer = g_alloca (matchlet->value_length); + bytes_read = fread (buffer, 1, matchlet->value_length, fp); + if (bytes_read != matchlet->value_length) + return feof (fp) ? THUNAR_VFS_MIME_LEGACY_MAGIC_EOF : THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + matchlet->value = g_string_chunk_insert_len (legacy->string_chunk, buffer, matchlet->value_length); + + c = getc_unlocked (fp); + if (c == '&') + { + /* reuse previously allocated buffer, as it's also value_length size */ + bytes_read = fread (buffer, 1, matchlet->value_length, fp); + if (bytes_read != matchlet->value_length) + return feof (fp) ? THUNAR_VFS_MIME_LEGACY_MAGIC_EOF : THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + + matchlet->mask = g_string_chunk_insert_len (legacy->string_chunk, buffer, matchlet->value_length); + + c = getc_unlocked (fp); + } + + if (c == '~') + { + matchlet->word_size = tvml_read_a_number (fp, &eof); + if (G_UNLIKELY (eof)) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + if (matchlet->word_size != 0 && matchlet->word_size != 1 && matchlet->word_size != 2 && matchlet->word_size != 4) + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + c = getc_unlocked (fp); + } + + if (c == '+') + { + matchlet->range_length = tvml_read_a_number (fp, &eof); + if (G_UNLIKELY (eof)) + return THUNAR_VFS_MIME_LEGACY_MAGIC_EOF; + else if (matchlet->range_length == -1) + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + c = getc_unlocked (fp); + } + + if (c == '\n') + { + /* We clean up the matchlet, byte swapping if needed */ + if (matchlet->word_size > 1) + { + if (matchlet->value_length % matchlet->word_size != 0) + return THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; + + if (G_BYTE_ORDER != G_BIG_ENDIAN) + { + for (i = 0; i < matchlet->value_length; i += matchlet->word_size) + { + if (matchlet->word_size == 2) + *((guint16 *) matchlet->value + i) = GUINT16_FROM_BE (*((guint16 *) (matchlet->value + i))); + else if (matchlet->word_size == 4) + *((guint32 *) matchlet->value + i) = GUINT32_FROM_BE (*((guint32 *) (matchlet->value + i))); + if (matchlet->mask) + { + if (matchlet->word_size == 2) + *((guint16 *) matchlet->mask + i) = GUINT16_FROM_BE (*((guint16 *) (matchlet->mask + i))); + else if (matchlet->word_size == 4) + *((guint32 *) matchlet->mask + i) = GUINT32_FROM_BE (*((guint32 *) (matchlet->mask + i))); + + } + } + } + } + + match->matchlets = g_list_append (match->matchlets, matchlet); + + return THUNAR_VFS_MIME_LEGACY_MAGIC_MAGIC; + } + + return (c == EOF) ? THUNAR_VFS_MIME_LEGACY_MAGIC_EOF : THUNAR_VFS_MIME_LEGACY_MAGIC_ERROR; +} + + + /** * thunar_vfs_mime_legacy_new: * @directory : an XDG mime base directory. @@ -636,6 +1178,9 @@ thunar_vfs_mime_legacy_new (const gchar *directory) /* parse the subclasses file (optional) */ thunar_vfs_mime_legacy_parse_subclasses (legacy, directory); + /* parse the magic file (optional) */ + thunar_vfs_mime_legacy_parse_magic (legacy, directory); + /* we got it */ return THUNAR_VFS_MIME_PROVIDER (legacy); }