diff options
Diffstat (limited to 'xdgmimemagic.cpp')
-rw-r--r-- | xdgmimemagic.cpp | 790 |
1 files changed, 0 insertions, 790 deletions
diff --git a/xdgmimemagic.cpp b/xdgmimemagic.cpp deleted file mode 100644 index b906685e..00000000 --- a/xdgmimemagic.cpp +++ /dev/null @@ -1,790 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* xdgmimemagic.: Private file. Datastructure for storing magic files. - * - * More info can be found at http://www.freedesktop.org/standards/ - * - * Copyright (C) 2003 Red Hat, Inc. - * Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu> - * - * Licensed under the Academic Free License version 2.0 - * Or under the following terms: - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include "xdgmimemagic.h" -#include "xdgmimeint.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> -#include <limits.h> - -#ifndef FALSE -#define FALSE (0) -#endif - -#ifndef TRUE -#define TRUE (!FALSE) -#endif - -typedef struct XdgMimeMagicMatch XdgMimeMagicMatch; -typedef struct XdgMimeMagicMatchlet XdgMimeMagicMatchlet; - -typedef enum -{ - XDG_MIME_MAGIC_SECTION, - XDG_MIME_MAGIC_MAGIC, - XDG_MIME_MAGIC_ERROR, - XDG_MIME_MAGIC_EOF -} XdgMimeMagicState; - -struct XdgMimeMagicMatch -{ - const char *mime_type; - int priority; - XdgMimeMagicMatchlet *matchlet; - XdgMimeMagicMatch *next; -}; - - -struct XdgMimeMagicMatchlet -{ - int indent; - int offset; - unsigned int value_length; - unsigned char *value; - unsigned char *mask; - unsigned int range_length; - unsigned int word_size; - XdgMimeMagicMatchlet *next; -}; - - -struct XdgMimeMagic -{ - XdgMimeMagicMatch *match_list; - int max_extent; -}; - -static XdgMimeMagicMatch * -_xdg_mime_magic_match_new(void) -{ - return (XdgMimeMagicMatch *)calloc(1, sizeof(XdgMimeMagicMatch)); -} - - -static XdgMimeMagicMatchlet * -_xdg_mime_magic_matchlet_new(void) -{ - XdgMimeMagicMatchlet *matchlet; - - matchlet = (XdgMimeMagicMatchlet *)malloc(sizeof(XdgMimeMagicMatchlet)); - - matchlet->indent = 0; - matchlet->offset = 0; - matchlet->value_length = 0; - matchlet->value = NULL; - matchlet->mask = NULL; - matchlet->range_length = 1; - matchlet->word_size = 1; - matchlet->next = NULL; - - return matchlet; -} - - -static void -_xdg_mime_magic_matchlet_free(XdgMimeMagicMatchlet *mime_magic_matchlet) -{ - if (mime_magic_matchlet) - { - if (mime_magic_matchlet->next) - _xdg_mime_magic_matchlet_free(mime_magic_matchlet->next); - if (mime_magic_matchlet->value) - free(mime_magic_matchlet->value); - if (mime_magic_matchlet->mask) - free(mime_magic_matchlet->mask); - free(mime_magic_matchlet); - } -} - - -/* Frees mime_magic_match and the remainder of its list - */ -static void -_xdg_mime_magic_match_free(XdgMimeMagicMatch *mime_magic_match) -{ - XdgMimeMagicMatch *ptr, *next; - - ptr = mime_magic_match; - while (ptr) - { - next = ptr->next; - - if (ptr->mime_type) - free((void *) ptr->mime_type); - if (ptr->matchlet) - _xdg_mime_magic_matchlet_free(ptr->matchlet); - free(ptr); - - ptr = next; - } -} - -/* 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 char * -_xdg_mime_magic_read_to_newline(FILE *magic_file, - int *end_of_file) -{ - char *retval; - int c; - int len, pos; - - len = 128; - pos = 0; - retval = (char *)malloc(len); - *end_of_file = FALSE; - - while (TRUE) - { - c = getc_unlocked(magic_file); - if (c == EOF) - { - *end_of_file = TRUE; - break; - } - if (c == '\n' || c == '\000') - break; - retval[pos++] = (char) c; - if (pos % 128 == 127) - { - len = len + 128; - char *tmp = (char *)realloc(retval, len); - if (tmp == NULL) - { - free(retval); - return NULL; - } - retval = tmp; - } - } - - retval[pos] = '\000'; - return retval; -} - -/* Returns the number read from the file, or -1 if no number could be read. - */ -static int -_xdg_mime_magic_read_a_number(FILE *magic_file, - int *end_of_file) -{ - /* LONG_MAX is about 20 characters on my system */ -#define MAX_NUMBER_SIZE 30 - char number_string[MAX_NUMBER_SIZE + 1]; - int pos = 0; - int c; - long retval = -1; - - while (TRUE) - { - c = getc_unlocked(magic_file); - - if (c == EOF) - { - *end_of_file = TRUE; - break; - } - if (! isdigit(c)) - { - ungetc(c, magic_file); - break; - } - number_string[pos] = (char) c; - pos++; - if (pos == MAX_NUMBER_SIZE) - break; - } - if (pos > 0) - { - number_string[pos] = '\000'; - errno = 0; - retval = strtol(number_string, NULL, 10); - - if ((retval < INT_MIN) || (retval > INT_MAX) || (errno != 0)) - return -1; - } - - return retval; -} - -/* Headers are of the format: - * [<priority>:<mime-type>] - */ -static XdgMimeMagicState -_xdg_mime_magic_parse_header(FILE *magic_file, XdgMimeMagicMatch *match) -{ - int c; - char *buffer; - char *end_ptr; - int end_of_file = 0; - - assert(magic_file != NULL); - assert(match != NULL); - - c = getc_unlocked(magic_file); - if (c == EOF) - return XDG_MIME_MAGIC_EOF; - if (c != '[') - return XDG_MIME_MAGIC_ERROR; - - match->priority = _xdg_mime_magic_read_a_number(magic_file, &end_of_file); - if (end_of_file) - return XDG_MIME_MAGIC_EOF; - if (match->priority == -1) - return XDG_MIME_MAGIC_ERROR; - - c = getc_unlocked(magic_file); - if (c == EOF) - return XDG_MIME_MAGIC_EOF; - if (c != ':') - return XDG_MIME_MAGIC_ERROR; - - buffer = _xdg_mime_magic_read_to_newline(magic_file, &end_of_file); - if (end_of_file) - { - free(buffer); - return XDG_MIME_MAGIC_EOF; - } - - end_ptr = buffer; - while (*end_ptr != ']' && *end_ptr != '\000' && *end_ptr != '\n') - end_ptr++; - if (*end_ptr != ']') - { - free(buffer); - return XDG_MIME_MAGIC_ERROR; - } - *end_ptr = '\000'; - - match->mime_type = strdup(buffer); - free(buffer); - - return XDG_MIME_MAGIC_MAGIC; -} - -static XdgMimeMagicState -_xdg_mime_magic_parse_error(FILE *magic_file) -{ - int c; - - while (1) - { - c = getc_unlocked(magic_file); - if (c == EOF) - return XDG_MIME_MAGIC_EOF; - if (c == '\n') - return XDG_MIME_MAGIC_SECTION; - } -} - -/* Headers are of the format: - * [ indent ] ">" start-offset "=" value - * [ "&" mask ] [ "~" word-size ] [ "+" range-length ] "\n" - */ -static XdgMimeMagicState -_xdg_mime_magic_parse_magic_line(FILE *magic_file, - XdgMimeMagicMatch *match) -{ - XdgMimeMagicMatchlet *matchlet; - int c; - int end_of_file; - int indent = 0; - size_t bytes_read; - - assert(magic_file != NULL); - - /* Sniff the buffer to make sure it's a valid line */ - c = getc_unlocked(magic_file); - if (c == EOF) - return XDG_MIME_MAGIC_EOF; - else if (c == '[') - { - ungetc(c, magic_file); - return XDG_MIME_MAGIC_SECTION; - } - else if (c == '\n') - return XDG_MIME_MAGIC_MAGIC; - - /* At this point, it must be a digit or a '>' */ - end_of_file = FALSE; - if (isdigit(c)) - { - ungetc(c, magic_file); - indent = _xdg_mime_magic_read_a_number(magic_file, &end_of_file); - if (end_of_file) - return XDG_MIME_MAGIC_EOF; - if (indent == -1) - return XDG_MIME_MAGIC_ERROR; - c = getc_unlocked(magic_file); - if (c == EOF) - return XDG_MIME_MAGIC_EOF; - } - - if (c != '>') - return XDG_MIME_MAGIC_ERROR; - - matchlet = _xdg_mime_magic_matchlet_new(); - matchlet->indent = indent; - matchlet->offset = _xdg_mime_magic_read_a_number(magic_file, &end_of_file); - if (end_of_file) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_EOF; - } - if (matchlet->offset == -1) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_ERROR; - } - c = getc_unlocked(magic_file); - if (c == EOF) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_EOF; - } - else if (c != '=') - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_ERROR; - } - - /* Next two bytes determine how long the value is */ - matchlet->value_length = 0; - c = getc_unlocked(magic_file); - if (c == EOF) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_EOF; - } - matchlet->value_length = c & 0xFF; - matchlet->value_length = matchlet->value_length << 8; - - c = getc_unlocked(magic_file); - if (c == EOF) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_EOF; - } - matchlet->value_length = matchlet->value_length + (c & 0xFF); - - matchlet->value = (unsigned char *)malloc(matchlet->value_length); - - /* OOM */ - if (matchlet->value == NULL) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_ERROR; - } - bytes_read = fread(matchlet->value, 1, matchlet->value_length, magic_file); - if (bytes_read != matchlet->value_length) - { - _xdg_mime_magic_matchlet_free(matchlet); - if (feof(magic_file)) - return XDG_MIME_MAGIC_EOF; - else - return XDG_MIME_MAGIC_ERROR; - } - - c = getc_unlocked(magic_file); - if (c == '&') - { - matchlet->mask = (unsigned char *)malloc(matchlet->value_length); - /* OOM */ - if (matchlet->mask == NULL) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_ERROR; - } - bytes_read = fread(matchlet->mask, 1, matchlet->value_length, magic_file); - if (bytes_read != matchlet->value_length) - { - _xdg_mime_magic_matchlet_free(matchlet); - if (feof(magic_file)) - return XDG_MIME_MAGIC_EOF; - else - return XDG_MIME_MAGIC_ERROR; - } - c = getc_unlocked(magic_file); - } - - if (c == '~') - { - matchlet->word_size = _xdg_mime_magic_read_a_number(magic_file, &end_of_file); - if (end_of_file) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_EOF; - } - if (matchlet->word_size != 0 && - matchlet->word_size != 1 && - matchlet->word_size != 2 && - matchlet->word_size != 4) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_ERROR; - } - c = getc_unlocked(magic_file); - } - - if (c == '+') - { - matchlet->range_length = _xdg_mime_magic_read_a_number(magic_file, &end_of_file); - if (end_of_file) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_EOF; - } - if (matchlet->range_length == (unsigned int)-1) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_ERROR; - } - c = getc_unlocked(magic_file); - } - - - if (c == '\n') - { - /* We clean up the matchlet, byte swapping if needed */ - if (matchlet->word_size > 1) - { - size_t i; - if (matchlet->value_length % matchlet->word_size != 0) - { - _xdg_mime_magic_matchlet_free(matchlet); - return XDG_MIME_MAGIC_ERROR; - } - /* FIXME: need to get this defined in a <config.h> style file */ -#if LITTLE_ENDIAN - for (i = 0; i < matchlet->value_length; i = i + matchlet->word_size) - { - if (matchlet->word_size == 2) - *((xdg_uint16_t *) matchlet->value + i) = SWAP_BE16_TO_LE16(*((xdg_uint16_t *)(matchlet->value + i))); - else if (matchlet->word_size == 4) - *((xdg_uint32_t *) matchlet->value + i) = SWAP_BE32_TO_LE32(*((xdg_uint32_t *)(matchlet->value + i))); - if (matchlet->mask) - { - if (matchlet->word_size == 2) - *((xdg_uint16_t *) matchlet->mask + i) = SWAP_BE16_TO_LE16(*((xdg_uint16_t *)(matchlet->mask + i))); - else if (matchlet->word_size == 4) - *((xdg_uint32_t *) matchlet->mask + i) = SWAP_BE32_TO_LE32(*((xdg_uint32_t *)(matchlet->mask + i))); - - } - } -#endif - } - - matchlet->next = match->matchlet; - match->matchlet = matchlet; - - - return XDG_MIME_MAGIC_MAGIC; - } - - _xdg_mime_magic_matchlet_free(matchlet); - if (c == EOF) - return XDG_MIME_MAGIC_EOF; - - return XDG_MIME_MAGIC_ERROR; -} - -static int -_xdg_mime_magic_matchlet_compare_to_data(XdgMimeMagicMatchlet *matchlet, - const void *data, - size_t len) -{ - size_t i, j; - - for (i = matchlet->offset; i <= matchlet->offset + matchlet->range_length; i++) - { - int valid_matchlet = TRUE; - - if (i + matchlet->value_length > len) - return FALSE; - - if (matchlet->mask) - { - for (j = 0; j < matchlet->value_length; j++) - { - if ((matchlet->value[j] & matchlet->mask[j]) != - ((((unsigned char *) data)[j + i]) & matchlet->mask[j])) - { - valid_matchlet = FALSE; - break; - } - } - } - else - { - for (j = 0; j < matchlet->value_length; j++) - { - if (matchlet->value[j] != ((unsigned char *) data)[j + i]) - { - valid_matchlet = FALSE; - break; - } - } - } - if (valid_matchlet) - return TRUE; - } - return FALSE; -} - -static int -_xdg_mime_magic_matchlet_compare_level(XdgMimeMagicMatchlet *matchlet, - const void *data, - size_t len, - int indent) -{ - while ((matchlet != NULL) && (matchlet->indent == indent)) - { - if (_xdg_mime_magic_matchlet_compare_to_data(matchlet, data, len)) - { - if ((matchlet->next == NULL) || - (matchlet->next->indent <= indent)) - return TRUE; - - if (_xdg_mime_magic_matchlet_compare_level(matchlet->next, - data, - len, - indent + 1)) - return TRUE; - } - - do - { - matchlet = matchlet->next; - } - while (matchlet && matchlet->indent > indent); - } - - return FALSE; -} - -static int -_xdg_mime_magic_match_compare_to_data(XdgMimeMagicMatch *match, - const void *data, - size_t len) -{ - return _xdg_mime_magic_matchlet_compare_level(match->matchlet, data, len, 0); -} - -static void -_xdg_mime_magic_insert_match(XdgMimeMagic *mime_magic, - XdgMimeMagicMatch *match) -{ - XdgMimeMagicMatch *list; - - if (mime_magic->match_list == NULL) - { - mime_magic->match_list = match; - return; - } - - if (match->priority > mime_magic->match_list->priority) - { - match->next = mime_magic->match_list; - mime_magic->match_list = match; - return; - } - - list = mime_magic->match_list; - while (list->next != NULL) - { - if (list->next->priority < match->priority) - { - match->next = list->next; - list->next = match; - return; - } - list = list->next; - } - list->next = match; - match->next = NULL; -} - -XdgMimeMagic * -_xdg_mime_magic_new(void) -{ - return (XdgMimeMagic *)calloc(1, sizeof(XdgMimeMagic)); -} - -void -_xdg_mime_magic_free(XdgMimeMagic *mime_magic) -{ - if (mime_magic) - { - _xdg_mime_magic_match_free(mime_magic->match_list); - free(mime_magic); - } -} - -int -_xdg_mime_magic_get_buffer_extents(XdgMimeMagic *mime_magic) -{ - return mime_magic->max_extent; -} - -const char * -_xdg_mime_magic_lookup_data(XdgMimeMagic *mime_magic, - const void *data, - size_t len) -{ - XdgMimeMagicMatch *match; - - for (match = mime_magic->match_list; match; match = match->next) - { - if (_xdg_mime_magic_match_compare_to_data(match, data, len)) - { - return match->mime_type; - } - } - - return NULL; -} - -static void -_xdg_mime_update_mime_magic_extents(XdgMimeMagic *mime_magic) -{ - XdgMimeMagicMatch *match; - int max_extent = 0; - - for (match = mime_magic->match_list; match; match = match->next) - { - XdgMimeMagicMatchlet *matchlet; - - for (matchlet = match->matchlet; matchlet; matchlet = matchlet->next) - { - int extent; - - extent = matchlet->value_length + matchlet->offset + matchlet->range_length; - if (max_extent < extent) - max_extent = extent; - } - } - - mime_magic->max_extent = max_extent; -} - -static XdgMimeMagicMatchlet * -_xdg_mime_magic_matchlet_mirror(XdgMimeMagicMatchlet *matchlets) -{ - XdgMimeMagicMatchlet *new_list; - XdgMimeMagicMatchlet *tmp; - - if ((matchlets == NULL) || (matchlets->next == NULL)) - return matchlets; - - new_list = NULL; - tmp = matchlets; - while (tmp != NULL) - { - XdgMimeMagicMatchlet *matchlet; - - matchlet = tmp; - tmp = tmp->next; - matchlet->next = new_list; - new_list = matchlet; - } - - return new_list; - -} - -static void -_xdg_mime_magic_read_magic_file(XdgMimeMagic *mime_magic, - FILE *magic_file) -{ - XdgMimeMagicState state; - XdgMimeMagicMatch *match = NULL; /* Quiet compiler */ - - state = XDG_MIME_MAGIC_SECTION; - - while (state != XDG_MIME_MAGIC_EOF) - { - switch (state) - { - case XDG_MIME_MAGIC_SECTION: - match = _xdg_mime_magic_match_new(); - state = _xdg_mime_magic_parse_header(magic_file, match); - if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR) - _xdg_mime_magic_match_free(match); - break; - case XDG_MIME_MAGIC_MAGIC: - state = _xdg_mime_magic_parse_magic_line(magic_file, match); - if (state == XDG_MIME_MAGIC_SECTION || - (state == XDG_MIME_MAGIC_EOF && match->mime_type)) - { - match->matchlet = _xdg_mime_magic_matchlet_mirror(match->matchlet); - _xdg_mime_magic_insert_match(mime_magic, match); - } - else if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR) - _xdg_mime_magic_match_free(match); - break; - case XDG_MIME_MAGIC_ERROR: - state = _xdg_mime_magic_parse_error(magic_file); - break; - case XDG_MIME_MAGIC_EOF: - default: - /* Make the compiler happy */ - assert(0); - } - } - _xdg_mime_update_mime_magic_extents(mime_magic); -} - -void -_xdg_mime_magic_read_from_file(XdgMimeMagic *mime_magic, - const char *file_name) -{ - FILE *magic_file; - char header[12]; - - /* OK to not use CLO_EXEC here because mimedb is single threaded */ - magic_file = fopen(file_name, "r"); - - if (magic_file == NULL) - return; - - if (fread(header, 1, 12, magic_file) == 12) - { - if (memcmp("MIME-Magic\0\n", header, 12) == 0) - _xdg_mime_magic_read_magic_file(mime_magic, magic_file); - } - - fclose(magic_file); -} |