2005-09-20 23:26:39 +10:00
/* -*- 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
2012-11-18 11:23:22 +01:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
2005-09-20 23:26:39 +10:00
* 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 . , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , 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>
2012-11-18 11:23:22 +01:00
# ifndef FALSE
# define FALSE (0)
2005-09-20 23:26:39 +10:00
# endif
2012-11-18 11:23:22 +01:00
# ifndef TRUE
# define TRUE (!FALSE)
2005-09-20 23:26:39 +10:00
# endif
extern int errno ;
typedef struct XdgMimeMagicMatch XdgMimeMagicMatch ;
typedef struct XdgMimeMagicMatchlet XdgMimeMagicMatchlet ;
typedef enum
{
2012-11-18 16:30:30 -08:00
XDG_MIME_MAGIC_SECTION ,
XDG_MIME_MAGIC_MAGIC ,
XDG_MIME_MAGIC_ERROR ,
XDG_MIME_MAGIC_EOF
2005-09-20 23:26:39 +10:00
} XdgMimeMagicState ;
struct XdgMimeMagicMatch
{
2012-11-18 16:30:30 -08:00
const char * mime_type ;
int priority ;
XdgMimeMagicMatchlet * matchlet ;
XdgMimeMagicMatch * next ;
2005-09-20 23:26:39 +10:00
} ;
struct XdgMimeMagicMatchlet
{
2012-11-18 16:30:30 -08:00
int indent ;
int offset ;
unsigned int value_length ;
unsigned char * value ;
unsigned char * mask ;
unsigned int range_length ;
unsigned int word_size ;
XdgMimeMagicMatchlet * next ;
2005-09-20 23:26:39 +10:00
} ;
struct XdgMimeMagic
{
2012-11-18 16:30:30 -08:00
XdgMimeMagicMatch * match_list ;
int max_extent ;
2005-09-20 23:26:39 +10:00
} ;
static XdgMimeMagicMatch *
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_match_new ( void )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
return ( XdgMimeMagicMatch * ) calloc ( 1 , sizeof ( XdgMimeMagicMatch ) ) ;
2005-09-20 23:26:39 +10:00
}
static XdgMimeMagicMatchlet *
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_new ( void )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
XdgMimeMagicMatchlet * matchlet ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
matchlet = ( XdgMimeMagicMatchlet * ) malloc ( sizeof ( XdgMimeMagicMatchlet ) ) ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
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 ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
return matchlet ;
2005-09-20 23:26:39 +10:00
}
static void
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_free ( XdgMimeMagicMatchlet * mime_magic_matchlet )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
if ( mime_magic_matchlet )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
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 ) ;
2005-09-20 23:26:39 +10:00
}
}
/* Frees mime_magic_match and the remainder of its list
*/
static void
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_match_free ( XdgMimeMagicMatch * mime_magic_match )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
XdgMimeMagicMatch * ptr , * next ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
ptr = mime_magic_match ;
while ( ptr )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
next = ptr - > next ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
if ( ptr - > mime_type )
free ( ( void * ) ptr - > mime_type ) ;
if ( ptr - > matchlet )
_xdg_mime_magic_matchlet_free ( ptr - > matchlet ) ;
free ( ptr ) ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
ptr = next ;
2005-09-20 23:26:39 +10:00
}
}
/* 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 .
*/
2005-12-12 08:28:33 +10:00
static char *
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_read_to_newline ( FILE * magic_file ,
int * end_of_file )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
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 ;
retval = ( char * ) realloc ( retval , len ) ;
}
}
retval [ pos ] = ' \000 ' ;
return retval ;
2005-09-20 23:26:39 +10:00
}
/* Returns the number read from the file, or -1 if no number could be read.
*/
static int
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_read_a_number ( FILE * magic_file ,
int * end_of_file )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
/* LONG_MAX is about 20 characters on my system */
2005-09-20 23:26:39 +10:00
# define MAX_NUMBER_SIZE 30
2012-11-18 16:30:30 -08:00
char number_string [ MAX_NUMBER_SIZE + 1 ] ;
int pos = 0 ;
int c ;
long retval = - 1 ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
while ( TRUE )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
c = getc_unlocked ( magic_file ) ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
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 ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
if ( pos > 0 )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
number_string [ pos ] = ' \000 ' ;
errno = 0 ;
retval = strtol ( number_string , NULL , 10 ) ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
if ( ( retval < INT_MIN ) | | ( retval > INT_MAX ) | | ( errno ! = 0 ) )
return - 1 ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
return retval ;
2005-09-20 23:26:39 +10:00
}
/* Headers are of the format:
* [ < priority > : < mime - type > ]
*/
static XdgMimeMagicState
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_parse_header ( FILE * magic_file , XdgMimeMagicMatch * match )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
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 ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
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 ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
c = getc_unlocked ( magic_file ) ;
if ( c = = EOF )
return XDG_MIME_MAGIC_EOF ;
if ( c ! = ' : ' )
return XDG_MIME_MAGIC_ERROR ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
buffer = _xdg_mime_magic_read_to_newline ( magic_file , & end_of_file ) ;
if ( end_of_file )
return XDG_MIME_MAGIC_EOF ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
end_ptr = buffer ;
while ( * end_ptr ! = ' ] ' & & * end_ptr ! = ' \000 ' & & * end_ptr ! = ' \n ' )
end_ptr + + ;
if ( * end_ptr ! = ' ] ' )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
free ( buffer ) ;
return XDG_MIME_MAGIC_ERROR ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
* end_ptr = ' \000 ' ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
match - > mime_type = strdup ( buffer ) ;
free ( buffer ) ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
return XDG_MIME_MAGIC_MAGIC ;
2005-09-20 23:26:39 +10:00
}
static XdgMimeMagicState
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_parse_error ( FILE * magic_file )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
int c ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
while ( 1 )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
c = getc_unlocked ( magic_file ) ;
if ( c = = EOF )
return XDG_MIME_MAGIC_EOF ;
if ( c = = ' \n ' )
return XDG_MIME_MAGIC_SECTION ;
2005-09-20 23:26:39 +10:00
}
}
/* Headers are of the format:
* [ indent ] " > " start - offset " = " value
* [ " & " mask ] [ " ~ " word - size ] [ " + " range - length ] " \n "
*/
static XdgMimeMagicState
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_parse_magic_line ( FILE * magic_file ,
XdgMimeMagicMatch * match )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
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 ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
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 )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_free ( matchlet ) ;
return XDG_MIME_MAGIC_EOF ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
if ( matchlet - > offset = = - 1 )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_free ( matchlet ) ;
return XDG_MIME_MAGIC_ERROR ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
c = getc_unlocked ( magic_file ) ;
if ( c = = EOF )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_free ( matchlet ) ;
return XDG_MIME_MAGIC_EOF ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
else if ( c ! = ' = ' )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_free ( matchlet ) ;
return XDG_MIME_MAGIC_ERROR ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
/* Next two bytes determine how long the value is */
matchlet - > value_length = 0 ;
c = getc_unlocked ( magic_file ) ;
if ( c = = EOF )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_free ( matchlet ) ;
return XDG_MIME_MAGIC_EOF ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
matchlet - > value_length = c & 0xFF ;
matchlet - > value_length = matchlet - > value_length < < 8 ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
c = getc_unlocked ( magic_file ) ;
if ( c = = EOF )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_free ( matchlet ) ;
return XDG_MIME_MAGIC_EOF ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
matchlet - > value_length = matchlet - > value_length + ( c & 0xFF ) ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
matchlet - > value = ( unsigned char * ) malloc ( matchlet - > value_length ) ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
/* OOM */
if ( matchlet - > value = = NULL )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_free ( matchlet ) ;
2012-11-18 11:23:22 +01:00
return XDG_MIME_MAGIC_ERROR ;
}
2012-11-18 16:30:30 -08:00
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 ) ) ) ;
}
}
2005-09-20 23:26:39 +10:00
# endif
2012-11-18 16:30:30 -08:00
}
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
matchlet - > next = match - > matchlet ;
match - > matchlet = matchlet ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
return XDG_MIME_MAGIC_MAGIC ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_free ( matchlet ) ;
if ( c = = EOF )
return XDG_MIME_MAGIC_EOF ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
return XDG_MIME_MAGIC_ERROR ;
2005-09-20 23:26:39 +10:00
}
static int
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_compare_to_data ( XdgMimeMagicMatchlet * matchlet ,
const void * data ,
size_t len )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
size_t i , j ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
for ( i = matchlet - > offset ; i < = matchlet - > offset + matchlet - > range_length ; i + + )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
int valid_matchlet = TRUE ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
if ( i + matchlet - > value_length > len )
return FALSE ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
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 ;
2005-09-20 23:26:39 +10:00
}
static int
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_compare_level ( XdgMimeMagicMatchlet * matchlet ,
const void * data ,
size_t len ,
int indent )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
while ( ( matchlet ! = NULL ) & & ( matchlet - > indent = = indent ) )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
if ( _xdg_mime_magic_matchlet_compare_to_data ( matchlet , data , len ) )
{
if ( ( matchlet - > next = = NULL ) | |
( matchlet - > next - > indent < = indent ) )
return TRUE ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( _xdg_mime_magic_matchlet_compare_level ( matchlet - > next ,
data ,
len ,
indent + 1 ) )
return TRUE ;
}
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
do
{
matchlet = matchlet - > next ;
}
while ( matchlet & & matchlet - > indent > indent ) ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
return FALSE ;
2005-09-20 23:26:39 +10:00
}
static int
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_match_compare_to_data ( XdgMimeMagicMatch * match ,
const void * data ,
size_t len )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
return _xdg_mime_magic_matchlet_compare_level ( match - > matchlet , data , len , 0 ) ;
2005-09-20 23:26:39 +10:00
}
static void
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_insert_match ( XdgMimeMagic * mime_magic ,
XdgMimeMagicMatch * match )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
XdgMimeMagicMatch * list ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
if ( mime_magic - > match_list = = NULL )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
mime_magic - > match_list = match ;
return ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
if ( match - > priority > mime_magic - > match_list - > priority )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
match - > next = mime_magic - > match_list ;
mime_magic - > match_list = match ;
return ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
list = mime_magic - > match_list ;
while ( list - > next ! = NULL )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
if ( list - > next - > priority < match - > priority )
{
match - > next = list - > next ;
list - > next = match ;
return ;
}
list = list - > next ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
list - > next = match ;
match - > next = NULL ;
2005-09-20 23:26:39 +10:00
}
XdgMimeMagic *
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_new ( void )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
return ( XdgMimeMagic * ) calloc ( 1 , sizeof ( XdgMimeMagic ) ) ;
2005-09-20 23:26:39 +10:00
}
void
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_free ( XdgMimeMagic * mime_magic )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
if ( mime_magic )
{
_xdg_mime_magic_match_free ( mime_magic - > match_list ) ;
free ( mime_magic ) ;
}
2005-09-20 23:26:39 +10:00
}
int
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_get_buffer_extents ( XdgMimeMagic * mime_magic )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
return mime_magic - > max_extent ;
2005-09-20 23:26:39 +10:00
}
const char *
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_lookup_data ( XdgMimeMagic * mime_magic ,
const void * data ,
size_t len )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
XdgMimeMagicMatch * match ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
for ( match = mime_magic - > match_list ; match ; match = match - > next )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
if ( _xdg_mime_magic_match_compare_to_data ( match , data , len ) )
{
return match - > mime_type ;
}
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
return NULL ;
2005-09-20 23:26:39 +10:00
}
static void
2012-11-18 16:30:30 -08:00
_xdg_mime_update_mime_magic_extents ( XdgMimeMagic * mime_magic )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
XdgMimeMagicMatch * match ;
int max_extent = 0 ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
for ( match = mime_magic - > match_list ; match ; match = match - > next )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
XdgMimeMagicMatchlet * matchlet ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
for ( matchlet = match - > matchlet ; matchlet ; matchlet = matchlet - > next )
{
int extent ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
extent = matchlet - > value_length + matchlet - > offset + matchlet - > range_length ;
if ( max_extent < extent )
max_extent = extent ;
}
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
mime_magic - > max_extent = max_extent ;
2005-09-20 23:26:39 +10:00
}
static XdgMimeMagicMatchlet *
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_matchlet_mirror ( XdgMimeMagicMatchlet * matchlets )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
XdgMimeMagicMatchlet * new_list ;
XdgMimeMagicMatchlet * tmp ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
if ( ( matchlets = = NULL ) | | ( matchlets - > next = = NULL ) )
return matchlets ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
new_list = NULL ;
tmp = matchlets ;
while ( tmp ! = NULL )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
XdgMimeMagicMatchlet * matchlet ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
matchlet = tmp ;
tmp = tmp - > next ;
matchlet - > next = new_list ;
new_list = matchlet ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
return new_list ;
2005-09-20 23:26:39 +10:00
}
static void
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_read_magic_file ( XdgMimeMagic * mime_magic ,
FILE * magic_file )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
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 ) ;
2005-09-20 23:26:39 +10:00
}
void
2012-11-18 16:30:30 -08:00
_xdg_mime_magic_read_from_file ( XdgMimeMagic * mime_magic ,
const char * file_name )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
FILE * magic_file ;
char header [ 12 ] ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
/* OK to not use CLO_EXEC here because mimedb is single threaded */
magic_file = fopen ( file_name , " r " ) ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
if ( magic_file = = NULL )
return ;
2005-09-20 23:26:39 +10:00
2012-11-18 16:30:30 -08:00
if ( fread ( header , 1 , 12 , magic_file ) = = 12 )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
if ( memcmp ( " MIME-Magic \0 \n " , header , 12 ) = = 0 )
_xdg_mime_magic_read_magic_file ( mime_magic , magic_file ) ;
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
fclose ( magic_file ) ;
2005-09-20 23:26:39 +10:00
}