Back to index

libcitadel  8.12
xdgmimemagic.c
Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* xdgmimemagic.: Private file.  Datastructure for storing magic files.
00003  *
00004  * More info can be found at http://www.freedesktop.org/standards/
00005  *
00006  * Copyright (C) 2003  Red Hat, Inc.
00007  * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
00008  *
00009  * Licensed under the Academic Free License version 2.0
00010  * Or under the following terms:
00011  *
00012  * This library is free software; you can redistribute it and/or
00013  * modify it under the terms of the GNU Lesser General Public
00014  * License as published by the Free Software Foundation; either
00015  * version 2 of the License, or (at your option) any later version.
00016  *
00017  * This library is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020  * Lesser General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU Lesser General Public
00023  * License along with this library; if not, write to the
00024  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00025  * Boston, MA 02111-1307, USA.
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <assert.h>
00033 #include "xdgmimemagic.h"
00034 #include "xdgmimeint.h"
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <ctype.h>
00039 #include <errno.h>
00040 #include <limits.h>
00041 
00042 #ifndef       FALSE
00043 #define       FALSE  (0)
00044 #endif
00045 
00046 #ifndef       TRUE
00047 #define       TRUE   (!FALSE)
00048 #endif
00049 
00050 #if !defined getc_unlocked && !defined HAVE_GETC_UNLOCKED
00051 #define getc_unlocked(fp) getc (fp)
00052 #endif
00053 
00054 typedef struct XdgMimeMagicMatch XdgMimeMagicMatch;
00055 typedef struct XdgMimeMagicMatchlet XdgMimeMagicMatchlet;
00056 
00057 typedef enum
00058 {
00059   XDG_MIME_MAGIC_SECTION,
00060   XDG_MIME_MAGIC_MAGIC,
00061   XDG_MIME_MAGIC_ERROR,
00062   XDG_MIME_MAGIC_EOF
00063 } XdgMimeMagicState;
00064 
00065 struct XdgMimeMagicMatch
00066 {
00067   const char *mime_type;
00068   int priority;
00069   XdgMimeMagicMatchlet *matchlet;
00070   XdgMimeMagicMatch *next;
00071 };
00072 
00073 
00074 struct XdgMimeMagicMatchlet
00075 {
00076   int indent;
00077   int offset;
00078   unsigned int value_length;
00079   unsigned char *value;
00080   unsigned char *mask;
00081   unsigned int range_length;
00082   unsigned int word_size;
00083   XdgMimeMagicMatchlet *next;
00084 };
00085 
00086 
00087 struct XdgMimeMagic
00088 {
00089   XdgMimeMagicMatch *match_list;
00090   int max_extent;
00091 };
00092 
00093 static XdgMimeMagicMatch *
00094 _xdg_mime_magic_match_new (void)
00095 {
00096   return calloc (1, sizeof (XdgMimeMagicMatch));
00097 }
00098 
00099 
00100 static XdgMimeMagicMatchlet *
00101 _xdg_mime_magic_matchlet_new (void)
00102 {
00103   XdgMimeMagicMatchlet *matchlet;
00104 
00105   matchlet = malloc (sizeof (XdgMimeMagicMatchlet));
00106 
00107   matchlet->indent = 0;
00108   matchlet->offset = 0;
00109   matchlet->value_length = 0;
00110   matchlet->value = NULL;
00111   matchlet->mask = NULL;
00112   matchlet->range_length = 1;
00113   matchlet->word_size = 1;
00114   matchlet->next = NULL;
00115 
00116   return matchlet;
00117 }
00118 
00119 
00120 static void
00121 _xdg_mime_magic_matchlet_free (XdgMimeMagicMatchlet *mime_magic_matchlet)
00122 {
00123   if (mime_magic_matchlet)
00124     {
00125       if (mime_magic_matchlet->next)
00126        _xdg_mime_magic_matchlet_free (mime_magic_matchlet->next);
00127       if (mime_magic_matchlet->value)
00128        free (mime_magic_matchlet->value);
00129       if (mime_magic_matchlet->mask)
00130        free (mime_magic_matchlet->mask);
00131       free (mime_magic_matchlet);
00132     }
00133 }
00134 
00135 
00136 /* Frees mime_magic_match and the remainder of its list
00137  */
00138 static void
00139 _xdg_mime_magic_match_free (XdgMimeMagicMatch *mime_magic_match)
00140 {
00141   XdgMimeMagicMatch *ptr, *next;
00142 
00143   ptr = mime_magic_match;
00144   while (ptr)
00145     {
00146       next = ptr->next;
00147 
00148       if (ptr->mime_type)
00149        free ((void *) ptr->mime_type);
00150       if (ptr->matchlet)
00151        _xdg_mime_magic_matchlet_free (ptr->matchlet);
00152       free (ptr);
00153 
00154       ptr = next;
00155     }
00156 }
00157 
00158 /* Reads in a hunk of data until a newline character or a '\000' is hit.  The
00159  * returned string is null terminated, and doesn't include the newline.
00160  */
00161 static unsigned char *
00162 _xdg_mime_magic_read_to_newline (FILE *magic_file,
00163                              int  *end_of_file)
00164 {
00165   unsigned char *retval;
00166   int c;
00167   int len, pos;
00168 
00169   len = 128;
00170   pos = 0;
00171   retval = malloc (len);
00172   *end_of_file = FALSE;
00173 
00174   while (TRUE)
00175     {
00176       c = getc_unlocked (magic_file);
00177       if (c == EOF)
00178        {
00179          *end_of_file = TRUE;
00180          break;
00181        }
00182       if (c == '\n' || c == '\000')
00183        break;
00184       retval[pos++] = (unsigned char) c;
00185       if (pos % 128 == 127)
00186        {
00187          len = len + 128;
00188          retval = realloc (retval, len);
00189        }
00190     }
00191 
00192   retval[pos] = '\000';
00193   return retval;
00194 }
00195 
00196 /* Returns the number read from the file, or -1 if no number could be read.
00197  */
00198 static int
00199 _xdg_mime_magic_read_a_number (FILE *magic_file,
00200                             int  *end_of_file)
00201 {
00202   /* LONG_MAX is about 20 characters on my system */
00203 #define MAX_NUMBER_SIZE 30
00204   char number_string[MAX_NUMBER_SIZE + 1];
00205   int pos = 0;
00206   int c;
00207   long retval = -1;
00208 
00209   while (TRUE)
00210     {
00211       c = getc_unlocked (magic_file);
00212 
00213       if (c == EOF)
00214        {
00215          *end_of_file = TRUE;
00216          break;
00217        }
00218       if (! isdigit (c))
00219        {
00220          ungetc (c, magic_file);
00221          break;
00222        }
00223       number_string[pos] = (char) c;
00224       pos++;
00225       if (pos == MAX_NUMBER_SIZE)
00226        break;
00227     }
00228   if (pos > 0)
00229     {
00230       number_string[pos] = '\000';
00231       errno = 0;
00232       retval = strtol (number_string, NULL, 10);
00233 
00234       if ((retval < INT_MIN) || (retval > INT_MAX) || (errno != 0))
00235        return -1;
00236     }
00237 
00238   return retval;
00239 }
00240 
00241 /* Headers are of the format:
00242  * [<priority>:<mime-type>]
00243  */
00244 static XdgMimeMagicState
00245 _xdg_mime_magic_parse_header (FILE *magic_file, XdgMimeMagicMatch *match)
00246 {
00247   int c;
00248   char *buffer;
00249   char *end_ptr;
00250   int end_of_file = 0;
00251 
00252   assert (magic_file != NULL);
00253   assert (match != NULL);
00254 
00255   c = getc_unlocked (magic_file);
00256   if (c == EOF)
00257     return XDG_MIME_MAGIC_EOF;
00258   if (c != '[')
00259     return XDG_MIME_MAGIC_ERROR;
00260 
00261   match->priority = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
00262   if (end_of_file)
00263     return XDG_MIME_MAGIC_EOF;
00264   if (match->priority == -1)
00265     return XDG_MIME_MAGIC_ERROR;
00266 
00267   c = getc_unlocked (magic_file);
00268   if (c == EOF)
00269     return XDG_MIME_MAGIC_EOF;
00270   if (c != ':')
00271     return XDG_MIME_MAGIC_ERROR;
00272 
00273   buffer = (char *)_xdg_mime_magic_read_to_newline (magic_file, &end_of_file);
00274   if (end_of_file)
00275     return XDG_MIME_MAGIC_EOF;
00276 
00277   end_ptr = buffer;
00278   while (*end_ptr != ']' && *end_ptr != '\000' && *end_ptr != '\n')
00279     end_ptr++;
00280   if (*end_ptr != ']')
00281     {
00282       free (buffer);
00283       return XDG_MIME_MAGIC_ERROR;
00284     }
00285   *end_ptr = '\000';
00286 
00287   match->mime_type = strdup (buffer);
00288   free (buffer);
00289 
00290   return XDG_MIME_MAGIC_MAGIC;
00291 }
00292 
00293 static XdgMimeMagicState
00294 _xdg_mime_magic_parse_error (FILE *magic_file)
00295 {
00296   int c;
00297 
00298   while (1)
00299     {
00300       c = getc_unlocked (magic_file);
00301       if (c == EOF)
00302        return XDG_MIME_MAGIC_EOF;
00303       if (c == '\n')
00304        return XDG_MIME_MAGIC_SECTION;
00305     }
00306 }
00307 
00308 /* Headers are of the format:
00309  * [ indent ] ">" start-offset "=" value
00310  * [ "&" mask ] [ "~" word-size ] [ "+" range-length ] "\n"
00311  */
00312 static XdgMimeMagicState
00313 _xdg_mime_magic_parse_magic_line (FILE              *magic_file,
00314                               XdgMimeMagicMatch *match)
00315 {
00316   XdgMimeMagicMatchlet *matchlet;
00317   int c;
00318   int end_of_file;
00319   int indent = 0;
00320   int bytes_read;
00321 
00322   assert (magic_file != NULL);
00323 
00324   /* Sniff the buffer to make sure it's a valid line */
00325   c = getc_unlocked (magic_file);
00326   if (c == EOF)
00327     return XDG_MIME_MAGIC_EOF;
00328   else if (c == '[')
00329     {
00330       ungetc (c, magic_file);
00331       return XDG_MIME_MAGIC_SECTION;
00332     }
00333   else if (c == '\n')
00334     return XDG_MIME_MAGIC_MAGIC;
00335 
00336   /* At this point, it must be a digit or a '>' */
00337   end_of_file = FALSE;
00338   if (isdigit (c))
00339     {
00340       ungetc (c, magic_file);
00341       indent = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
00342       if (end_of_file)
00343        return XDG_MIME_MAGIC_EOF;
00344       if (indent == -1)
00345        return XDG_MIME_MAGIC_ERROR;
00346       c = getc_unlocked (magic_file);
00347       if (c == EOF)
00348        return XDG_MIME_MAGIC_EOF;
00349     }
00350 
00351   if (c != '>')
00352     return XDG_MIME_MAGIC_ERROR;
00353 
00354   matchlet = _xdg_mime_magic_matchlet_new ();
00355   matchlet->indent = indent;
00356   matchlet->offset = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
00357   if (end_of_file)
00358     {
00359       _xdg_mime_magic_matchlet_free (matchlet);
00360       return XDG_MIME_MAGIC_EOF;
00361     }
00362   if (matchlet->offset == -1)
00363     {
00364       _xdg_mime_magic_matchlet_free (matchlet);
00365       return XDG_MIME_MAGIC_ERROR;
00366     }
00367   c = getc_unlocked (magic_file);
00368   if (c == EOF)
00369     {
00370       _xdg_mime_magic_matchlet_free (matchlet);
00371       return XDG_MIME_MAGIC_EOF;
00372     }
00373   else if (c != '=')
00374     {
00375       _xdg_mime_magic_matchlet_free (matchlet);
00376       return XDG_MIME_MAGIC_ERROR;
00377     }
00378 
00379   /* Next two bytes determine how long the value is */
00380   matchlet->value_length = 0;
00381   c = getc_unlocked (magic_file);
00382   if (c == EOF)
00383     {
00384       _xdg_mime_magic_matchlet_free (matchlet);
00385       return XDG_MIME_MAGIC_EOF;
00386     }
00387   matchlet->value_length = c & 0xFF;
00388   matchlet->value_length = matchlet->value_length << 8;
00389 
00390   c = getc_unlocked (magic_file);
00391   if (c == EOF)
00392     {
00393       _xdg_mime_magic_matchlet_free (matchlet);
00394       return XDG_MIME_MAGIC_EOF;
00395     }
00396   matchlet->value_length = matchlet->value_length + (c & 0xFF);
00397 
00398   matchlet->value = malloc (matchlet->value_length);
00399 
00400   /* OOM */
00401   if (matchlet->value == NULL)
00402     {
00403       _xdg_mime_magic_matchlet_free (matchlet);
00404       return XDG_MIME_MAGIC_ERROR;
00405     }
00406   bytes_read = fread (matchlet->value, 1, matchlet->value_length, magic_file);
00407   if (bytes_read != matchlet->value_length)
00408     {
00409       _xdg_mime_magic_matchlet_free (matchlet);
00410       if (feof (magic_file))
00411        return XDG_MIME_MAGIC_EOF;
00412       else
00413        return XDG_MIME_MAGIC_ERROR;
00414     }
00415 
00416   c = getc_unlocked (magic_file);
00417   if (c == '&')
00418     {
00419       matchlet->mask = malloc (matchlet->value_length);
00420       /* OOM */
00421       if (matchlet->mask == NULL)
00422        {
00423          _xdg_mime_magic_matchlet_free (matchlet);
00424          return XDG_MIME_MAGIC_ERROR;
00425        }
00426       bytes_read = fread (matchlet->mask, 1, matchlet->value_length, magic_file);
00427       if (bytes_read != matchlet->value_length)
00428        {
00429          _xdg_mime_magic_matchlet_free (matchlet);
00430          if (feof (magic_file))
00431            return XDG_MIME_MAGIC_EOF;
00432          else
00433            return XDG_MIME_MAGIC_ERROR;
00434        }
00435       c = getc_unlocked (magic_file);
00436     }
00437 
00438   if (c == '~')
00439     {
00440       matchlet->word_size = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
00441       if (end_of_file)
00442        {
00443          _xdg_mime_magic_matchlet_free (matchlet);
00444          return XDG_MIME_MAGIC_EOF;
00445        }
00446       if (matchlet->word_size != 0 &&
00447          matchlet->word_size != 1 &&
00448          matchlet->word_size != 2 &&
00449          matchlet->word_size != 4)
00450        {
00451          _xdg_mime_magic_matchlet_free (matchlet);
00452          return XDG_MIME_MAGIC_ERROR;
00453        }
00454       c = getc_unlocked (magic_file);
00455     }
00456 
00457   if (c == '+')
00458     {
00459       matchlet->range_length = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
00460       if (end_of_file)
00461        {
00462          _xdg_mime_magic_matchlet_free (matchlet);
00463          return XDG_MIME_MAGIC_EOF;
00464        }
00465       if (matchlet->range_length == -1)
00466        {
00467          _xdg_mime_magic_matchlet_free (matchlet);
00468          return XDG_MIME_MAGIC_ERROR;
00469        }
00470       c = getc_unlocked (magic_file);
00471     }
00472 
00473 
00474   if (c == '\n')
00475     {
00476       /* We clean up the matchlet, byte swapping if needed */
00477       if (matchlet->word_size > 1)
00478        {
00479 #if LITTLE_ENDIAN
00480          int i;
00481 #endif
00482          if (matchlet->value_length % matchlet->word_size != 0)
00483            {
00484              _xdg_mime_magic_matchlet_free (matchlet);
00485              return XDG_MIME_MAGIC_ERROR;
00486            }
00487          /* FIXME: need to get this defined in a <config.h> style file */
00488 #if LITTLE_ENDIAN
00489          for (i = 0; i < matchlet->value_length; i = i + matchlet->word_size)
00490            {
00491              if (matchlet->word_size == 2)
00492               *((xdg_uint16_t *) matchlet->value + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->value + i)));
00493              else if (matchlet->word_size == 4)
00494               *((xdg_uint32_t *) matchlet->value + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->value + i)));
00495              if (matchlet->mask)
00496               {
00497                 if (matchlet->word_size == 2)
00498                   *((xdg_uint16_t *) matchlet->mask + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->mask + i)));
00499                 else if (matchlet->word_size == 4)
00500                   *((xdg_uint32_t *) matchlet->mask + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->mask + i)));
00501 
00502               }
00503            }
00504 #endif
00505        }
00506 
00507       matchlet->next = match->matchlet;
00508       match->matchlet = matchlet;
00509 
00510 
00511       return XDG_MIME_MAGIC_MAGIC;
00512     }
00513 
00514   _xdg_mime_magic_matchlet_free (matchlet);
00515   if (c == EOF)
00516     return XDG_MIME_MAGIC_EOF;
00517 
00518   return XDG_MIME_MAGIC_ERROR;
00519 }
00520 
00521 static int
00522 _xdg_mime_magic_matchlet_compare_to_data (XdgMimeMagicMatchlet *matchlet,
00523                                      const void           *data,
00524                                      size_t                len)
00525 {
00526   int i, j;
00527   for (i = matchlet->offset; i < matchlet->offset + matchlet->range_length; i++)
00528     {
00529       int valid_matchlet = TRUE;
00530 
00531       if (i + matchlet->value_length > len)
00532        return FALSE;
00533 
00534       if (matchlet->mask)
00535        {
00536          for (j = 0; j < matchlet->value_length; j++)
00537            {
00538              if ((matchlet->value[j] & matchlet->mask[j]) !=
00539                 ((((unsigned char *) data)[j + i]) & matchlet->mask[j]))
00540               {
00541                 valid_matchlet = FALSE;
00542                 break;
00543               }
00544            }
00545        }
00546       else
00547        {
00548          for (j = 0; j <  matchlet->value_length; j++)
00549            {
00550              if (matchlet->value[j] != ((unsigned char *) data)[j + i])
00551               {
00552                 valid_matchlet = FALSE;
00553                 break;
00554               }
00555            }
00556        }
00557       if (valid_matchlet)
00558        return TRUE;
00559     }
00560   return FALSE;
00561 }
00562 
00563 static int
00564 _xdg_mime_magic_matchlet_compare_level (XdgMimeMagicMatchlet *matchlet,
00565                                    const void           *data,
00566                                    size_t                len,
00567                                    int                   indent)
00568 {
00569   while ((matchlet != NULL) && (matchlet->indent == indent))
00570     {
00571       if (_xdg_mime_magic_matchlet_compare_to_data (matchlet, data, len))
00572        {
00573          if ((matchlet->next == NULL) ||
00574              (matchlet->next->indent <= indent))
00575            return TRUE;
00576 
00577          if (_xdg_mime_magic_matchlet_compare_level (matchlet->next,
00578                                                 data,
00579                                                 len,
00580                                                 indent + 1))
00581            return TRUE;
00582        }
00583 
00584       do
00585        {
00586          matchlet = matchlet->next;
00587        }
00588       while (matchlet && matchlet->indent > indent);
00589     }
00590 
00591   return FALSE;
00592 }
00593 
00594 static int
00595 _xdg_mime_magic_match_compare_to_data (XdgMimeMagicMatch *match,
00596                                    const void        *data,
00597                                    size_t             len)
00598 {
00599   return _xdg_mime_magic_matchlet_compare_level (match->matchlet, data, len, 0);
00600 }
00601 
00602 static void
00603 _xdg_mime_magic_insert_match (XdgMimeMagic      *mime_magic,
00604                            XdgMimeMagicMatch *match)
00605 {
00606   XdgMimeMagicMatch *list;
00607 
00608   if (mime_magic->match_list == NULL)
00609     {
00610       mime_magic->match_list = match;
00611       return;
00612     }
00613 
00614   if (match->priority > mime_magic->match_list->priority)
00615     {
00616       match->next = mime_magic->match_list;
00617       mime_magic->match_list = match;
00618       return;
00619     }
00620 
00621   list = mime_magic->match_list;
00622   while (list->next != NULL)
00623     {
00624       if (list->next->priority < match->priority)
00625        {
00626          match->next = list->next;
00627          list->next = match;
00628          return;
00629        }
00630       list = list->next;
00631     }
00632   list->next = match;
00633   match->next = NULL;
00634 }
00635 
00636 XdgMimeMagic *
00637 _xdg_mime_magic_new (void)
00638 {
00639   return calloc (1, sizeof (XdgMimeMagic));
00640 }
00641 
00642 void
00643 _xdg_mime_magic_free (XdgMimeMagic *mime_magic)
00644 {
00645   if (mime_magic) {
00646     _xdg_mime_magic_match_free (mime_magic->match_list);
00647     free (mime_magic);
00648   }
00649 }
00650 
00651 int
00652 _xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic)
00653 {
00654   return mime_magic->max_extent;
00655 }
00656 
00657 const char *
00658 _xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
00659                           const void   *data,
00660                           size_t        len,
00661                              const char   *mime_types[],
00662                              int           n_mime_types)
00663 {
00664   XdgMimeMagicMatch *match;
00665   const char *mime_type;
00666   int n;
00667   int priority;
00668   int had_match;
00669 
00670   mime_type = NULL;
00671   priority = 0;
00672   had_match = 0;
00673   for (match = mime_magic->match_list; match; match = match->next)
00674     {
00675       if (_xdg_mime_magic_match_compare_to_data (match, data, len))
00676        {
00677          if (!had_match || match->priority > priority ||
00678              (mime_type != NULL && _xdg_mime_mime_type_subclass (match->mime_type, mime_type)))
00679            {
00680              mime_type = match->mime_type;
00681              priority = match->priority;
00682            }
00683          else if (had_match && match->priority == priority &&
00684                  !_xdg_mime_mime_type_subclass (mime_type, match->mime_type))
00685            /* multiple unrelated patterns with the same priority matched,
00686             * so we can't tell what type this is. */
00687            mime_type = NULL;
00688 
00689          had_match = 1;
00690        }
00691       else 
00692        {
00693          for (n = 0; n < n_mime_types; n++)
00694            {
00695              if (mime_types[n] && 
00696                 _xdg_mime_mime_type_equal (mime_types[n], match->mime_type))
00697               mime_types[n] = NULL;
00698            }
00699        }
00700     }
00701 
00702   if (mime_type == NULL)
00703     {
00704       for (n = 0; n < n_mime_types; n++)
00705        {
00706          if (mime_types[n])
00707            mime_type = mime_types[n];
00708        }
00709     }
00710 
00711   return mime_type;
00712 }
00713 
00714 static void
00715 _xdg_mime_update_mime_magic_extents (XdgMimeMagic *mime_magic)
00716 {
00717   XdgMimeMagicMatch *match;
00718   int max_extent = 0;
00719 
00720   for (match = mime_magic->match_list; match; match = match->next)
00721     {
00722       XdgMimeMagicMatchlet *matchlet;
00723 
00724       for (matchlet = match->matchlet; matchlet; matchlet = matchlet->next)
00725        {
00726          int extent;
00727 
00728          extent = matchlet->value_length + matchlet->offset + matchlet->range_length;
00729          if (max_extent < extent)
00730            max_extent = extent;
00731        }
00732     }
00733 
00734   mime_magic->max_extent = max_extent;
00735 }
00736 
00737 static XdgMimeMagicMatchlet *
00738 _xdg_mime_magic_matchlet_mirror (XdgMimeMagicMatchlet *matchlets)
00739 {
00740   XdgMimeMagicMatchlet *new_list;
00741   XdgMimeMagicMatchlet *tmp;
00742 
00743   if ((matchlets == NULL) || (matchlets->next == NULL))
00744     return matchlets;
00745 
00746   new_list = NULL;
00747   tmp = matchlets;
00748   while (tmp != NULL)
00749     {
00750       XdgMimeMagicMatchlet *matchlet;
00751 
00752       matchlet = tmp;
00753       tmp = tmp->next;
00754       matchlet->next = new_list;
00755       new_list = matchlet;
00756     }
00757 
00758   return new_list;
00759 
00760 }
00761 
00762 static void
00763 _xdg_mime_magic_read_magic_file (XdgMimeMagic *mime_magic,
00764                              FILE         *magic_file)
00765 {
00766   XdgMimeMagicState state;
00767   XdgMimeMagicMatch *match = NULL; /* Quiet compiler */
00768 
00769   state = XDG_MIME_MAGIC_SECTION;
00770 
00771   while (state != XDG_MIME_MAGIC_EOF)
00772     {
00773       switch (state)
00774        {
00775        case XDG_MIME_MAGIC_SECTION:
00776          match = _xdg_mime_magic_match_new ();
00777          state = _xdg_mime_magic_parse_header (magic_file, match);
00778          if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
00779            _xdg_mime_magic_match_free (match);
00780          break;
00781        case XDG_MIME_MAGIC_MAGIC:
00782          state = _xdg_mime_magic_parse_magic_line (magic_file, match);
00783          if (state == XDG_MIME_MAGIC_SECTION ||
00784              (state == XDG_MIME_MAGIC_EOF && match->mime_type))
00785            {
00786              match->matchlet = _xdg_mime_magic_matchlet_mirror (match->matchlet);
00787              _xdg_mime_magic_insert_match (mime_magic, match);
00788            }
00789          else if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
00790            _xdg_mime_magic_match_free (match);
00791          break;
00792        case XDG_MIME_MAGIC_ERROR:
00793          state = _xdg_mime_magic_parse_error (magic_file);
00794          break;
00795        case XDG_MIME_MAGIC_EOF:
00796        default:
00797          /* Make the compiler happy */
00798          assert (0);
00799        }
00800     }
00801   _xdg_mime_update_mime_magic_extents (mime_magic);
00802 }
00803 
00804 void
00805 _xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
00806                             const char   *file_name)
00807 {
00808   FILE *magic_file;
00809   char header[12];
00810 
00811   magic_file = fopen (file_name, "r");
00812 
00813   if (magic_file == NULL)
00814     return;
00815 
00816   if (fread (header, 1, 12, magic_file) == 12)
00817     {
00818       if (memcmp ("MIME-Magic\0\n", header, 12) == 0)
00819         _xdg_mime_magic_read_magic_file (mime_magic, magic_file);
00820     }
00821 
00822   fclose (magic_file);
00823 }