• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* xdgmimemagic.: Private file.  Datastructure for storing magic files.
3  *
4  * More info can be found at http://www.freedesktop.org/standards/
5  *
6  * Copyright (C) 2003  Red Hat, Inc.
7  * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
8  *
9  * Licensed under the Academic Free License version 2.0
10  * Or under the following terms:
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include "config.h"
27 
28 #include <assert.h>
29 #include "xdgmimemagic.h"
30 #include "xdgmimeint.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <limits.h>
37 
38 #ifndef	FALSE
39 #define	FALSE	(0)
40 #endif
41 
42 #ifndef	TRUE
43 #define	TRUE	(!FALSE)
44 #endif
45 
46 #if !defined getc_unlocked && !defined HAVE_GETC_UNLOCKED
47 # define getc_unlocked(fp) getc (fp)
48 #endif
49 
50 typedef struct XdgMimeMagicMatch XdgMimeMagicMatch;
51 typedef struct XdgMimeMagicMatchlet XdgMimeMagicMatchlet;
52 
53 typedef enum
54 {
55   XDG_MIME_MAGIC_SECTION,
56   XDG_MIME_MAGIC_MAGIC,
57   XDG_MIME_MAGIC_ERROR,
58   XDG_MIME_MAGIC_EOF
59 } XdgMimeMagicState;
60 
61 struct XdgMimeMagicMatch
62 {
63   const char *mime_type;
64   int priority;
65   XdgMimeMagicMatchlet *matchlet;
66   XdgMimeMagicMatch *next;
67 };
68 
69 
70 struct XdgMimeMagicMatchlet
71 {
72   int indent;
73   int offset;
74   unsigned int value_length;
75   unsigned char *value;
76   unsigned char *mask;
77   unsigned int range_length;
78   unsigned int word_size;
79   XdgMimeMagicMatchlet *next;
80 };
81 
82 
83 struct XdgMimeMagic
84 {
85   XdgMimeMagicMatch *match_list;
86   int max_extent;
87 };
88 
89 static XdgMimeMagicMatch *
_xdg_mime_magic_match_new(void)90 _xdg_mime_magic_match_new (void)
91 {
92   return calloc (1, sizeof (XdgMimeMagicMatch));
93 }
94 
95 
96 static XdgMimeMagicMatchlet *
_xdg_mime_magic_matchlet_new(void)97 _xdg_mime_magic_matchlet_new (void)
98 {
99   XdgMimeMagicMatchlet *matchlet;
100 
101   matchlet = malloc (sizeof (XdgMimeMagicMatchlet));
102 
103   matchlet->indent = 0;
104   matchlet->offset = 0;
105   matchlet->value_length = 0;
106   matchlet->value = NULL;
107   matchlet->mask = NULL;
108   matchlet->range_length = 1;
109   matchlet->word_size = 1;
110   matchlet->next = NULL;
111 
112   return matchlet;
113 }
114 
115 
116 static void
_xdg_mime_magic_matchlet_free(XdgMimeMagicMatchlet * mime_magic_matchlet)117 _xdg_mime_magic_matchlet_free (XdgMimeMagicMatchlet *mime_magic_matchlet)
118 {
119   if (mime_magic_matchlet)
120     {
121       if (mime_magic_matchlet->next)
122 	_xdg_mime_magic_matchlet_free (mime_magic_matchlet->next);
123       if (mime_magic_matchlet->value)
124 	free (mime_magic_matchlet->value);
125       if (mime_magic_matchlet->mask)
126 	free (mime_magic_matchlet->mask);
127       free (mime_magic_matchlet);
128     }
129 }
130 
131 
132 /* Frees mime_magic_match and the remainder of its list
133  */
134 static void
_xdg_mime_magic_match_free(XdgMimeMagicMatch * mime_magic_match)135 _xdg_mime_magic_match_free (XdgMimeMagicMatch *mime_magic_match)
136 {
137   XdgMimeMagicMatch *ptr, *next;
138 
139   ptr = mime_magic_match;
140   while (ptr)
141     {
142       next = ptr->next;
143 
144       if (ptr->mime_type)
145 	free ((void *) ptr->mime_type);
146       if (ptr->matchlet)
147 	_xdg_mime_magic_matchlet_free (ptr->matchlet);
148       free (ptr);
149 
150       ptr = next;
151     }
152 }
153 
154 /* Reads in a hunk of data until a newline character or a '\000' is hit.  The
155  * returned string is null terminated, and doesn't include the newline.
156  */
157 static unsigned char *
_xdg_mime_magic_read_to_newline(FILE * magic_file,int * end_of_file)158 _xdg_mime_magic_read_to_newline (FILE *magic_file,
159 				 int  *end_of_file)
160 {
161   unsigned char *retval;
162   int c;
163   int len, pos;
164 
165   len = 128;
166   pos = 0;
167   retval = malloc (len);
168   *end_of_file = FALSE;
169 
170   while (TRUE)
171     {
172       c = getc_unlocked (magic_file);
173       if (c == EOF)
174 	{
175 	  *end_of_file = TRUE;
176 	  break;
177 	}
178       if (c == '\n' || c == '\000')
179 	break;
180       retval[pos++] = (unsigned char) c;
181       if (pos % 128 == 127)
182 	{
183 	  len = len + 128;
184 	  retval = realloc (retval, len);
185 	}
186     }
187 
188   retval[pos] = '\000';
189   return retval;
190 }
191 
192 /* Returns the number read from the file, or -1 if no number could be read.
193  */
194 static int
_xdg_mime_magic_read_a_number(FILE * magic_file,int * end_of_file)195 _xdg_mime_magic_read_a_number (FILE *magic_file,
196 			       int  *end_of_file)
197 {
198   /* LONG_MAX is about 20 characters on my system */
199 #define MAX_NUMBER_SIZE 30
200   char number_string[MAX_NUMBER_SIZE + 1];
201   int pos = 0;
202   int c;
203   long retval = -1;
204 
205   while (TRUE)
206     {
207       c = getc_unlocked (magic_file);
208 
209       if (c == EOF)
210 	{
211 	  *end_of_file = TRUE;
212 	  break;
213 	}
214       if (! isdigit (c))
215 	{
216 	  ungetc (c, magic_file);
217 	  break;
218 	}
219       number_string[pos] = (char) c;
220       pos++;
221       if (pos == MAX_NUMBER_SIZE)
222 	break;
223     }
224   if (pos > 0)
225     {
226       number_string[pos] = '\000';
227       errno = 0;
228       retval = strtol (number_string, NULL, 10);
229 
230       if ((retval < INT_MIN) || (retval > INT_MAX) || (errno != 0))
231 	return -1;
232     }
233 
234   return retval;
235 }
236 
237 /* Headers are of the format:
238  * [<priority>:<mime-type>]
239  */
240 static XdgMimeMagicState
_xdg_mime_magic_parse_header(FILE * magic_file,XdgMimeMagicMatch * match)241 _xdg_mime_magic_parse_header (FILE *magic_file, XdgMimeMagicMatch *match)
242 {
243   int c;
244   char *buffer;
245   char *end_ptr;
246   int end_of_file = 0;
247 
248   assert (magic_file != NULL);
249   assert (match != NULL);
250 
251   c = getc_unlocked (magic_file);
252   if (c == EOF)
253     return XDG_MIME_MAGIC_EOF;
254   if (c != '[')
255     return XDG_MIME_MAGIC_ERROR;
256 
257   match->priority = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
258   if (end_of_file)
259     return XDG_MIME_MAGIC_EOF;
260   if (match->priority == -1)
261     return XDG_MIME_MAGIC_ERROR;
262 
263   c = getc_unlocked (magic_file);
264   if (c == EOF)
265     return XDG_MIME_MAGIC_EOF;
266   if (c != ':')
267     return XDG_MIME_MAGIC_ERROR;
268 
269   buffer = (char *)_xdg_mime_magic_read_to_newline (magic_file, &end_of_file);
270   if (end_of_file)
271     {
272       free (buffer);
273       return XDG_MIME_MAGIC_EOF;
274     }
275 
276   end_ptr = buffer;
277   while (*end_ptr != ']' && *end_ptr != '\000' && *end_ptr != '\n')
278     end_ptr++;
279   if (*end_ptr != ']')
280     {
281       free (buffer);
282       return XDG_MIME_MAGIC_ERROR;
283     }
284   *end_ptr = '\000';
285 
286   match->mime_type = strdup (buffer);
287   free (buffer);
288 
289   return XDG_MIME_MAGIC_MAGIC;
290 }
291 
292 static XdgMimeMagicState
_xdg_mime_magic_parse_error(FILE * magic_file)293 _xdg_mime_magic_parse_error (FILE *magic_file)
294 {
295   int c;
296 
297   while (1)
298     {
299       c = getc_unlocked (magic_file);
300       if (c == EOF)
301 	return XDG_MIME_MAGIC_EOF;
302       if (c == '\n')
303 	return XDG_MIME_MAGIC_SECTION;
304     }
305 }
306 
307 /* Headers are of the format:
308  * [ indent ] ">" start-offset "=" value
309  * [ "&" mask ] [ "~" word-size ] [ "+" range-length ] "\n"
310  */
311 static XdgMimeMagicState
_xdg_mime_magic_parse_magic_line(FILE * magic_file,XdgMimeMagicMatch * match)312 _xdg_mime_magic_parse_magic_line (FILE              *magic_file,
313 				  XdgMimeMagicMatch *match)
314 {
315   XdgMimeMagicMatchlet *matchlet;
316   int c;
317   int end_of_file;
318   int indent = 0;
319   int bytes_read;
320 
321   assert (magic_file != NULL);
322 
323   /* Sniff the buffer to make sure it's a valid line */
324   c = getc_unlocked (magic_file);
325   if (c == EOF)
326     return XDG_MIME_MAGIC_EOF;
327   else if (c == '[')
328     {
329       ungetc (c, magic_file);
330       return XDG_MIME_MAGIC_SECTION;
331     }
332   else if (c == '\n')
333     return XDG_MIME_MAGIC_MAGIC;
334 
335   /* At this point, it must be a digit or a '>' */
336   end_of_file = FALSE;
337   if (isdigit (c))
338     {
339       ungetc (c, magic_file);
340       indent = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
341       if (end_of_file)
342 	return XDG_MIME_MAGIC_EOF;
343       if (indent == -1)
344 	return XDG_MIME_MAGIC_ERROR;
345       c = getc_unlocked (magic_file);
346       if (c == EOF)
347 	return XDG_MIME_MAGIC_EOF;
348     }
349 
350   if (c != '>')
351     return XDG_MIME_MAGIC_ERROR;
352 
353   matchlet = _xdg_mime_magic_matchlet_new ();
354   matchlet->indent = indent;
355   matchlet->offset = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
356   if (end_of_file)
357     {
358       _xdg_mime_magic_matchlet_free (matchlet);
359       return XDG_MIME_MAGIC_EOF;
360     }
361   if (matchlet->offset == -1)
362     {
363       _xdg_mime_magic_matchlet_free (matchlet);
364       return XDG_MIME_MAGIC_ERROR;
365     }
366   c = getc_unlocked (magic_file);
367   if (c == EOF)
368     {
369       _xdg_mime_magic_matchlet_free (matchlet);
370       return XDG_MIME_MAGIC_EOF;
371     }
372   else if (c != '=')
373     {
374       _xdg_mime_magic_matchlet_free (matchlet);
375       return XDG_MIME_MAGIC_ERROR;
376     }
377 
378   /* Next two bytes determine how long the value is */
379   matchlet->value_length = 0;
380   c = getc_unlocked (magic_file);
381   if (c == EOF)
382     {
383       _xdg_mime_magic_matchlet_free (matchlet);
384       return XDG_MIME_MAGIC_EOF;
385     }
386   matchlet->value_length = c & 0xFF;
387   matchlet->value_length = matchlet->value_length << 8;
388 
389   c = getc_unlocked (magic_file);
390   if (c == EOF)
391     {
392       _xdg_mime_magic_matchlet_free (matchlet);
393       return XDG_MIME_MAGIC_EOF;
394     }
395   matchlet->value_length = matchlet->value_length + (c & 0xFF);
396 
397   matchlet->value = malloc (matchlet->value_length);
398 
399   /* OOM */
400   if (matchlet->value == NULL)
401     {
402       _xdg_mime_magic_matchlet_free (matchlet);
403       return XDG_MIME_MAGIC_ERROR;
404     }
405   bytes_read = fread (matchlet->value, 1, matchlet->value_length, magic_file);
406   if (bytes_read != matchlet->value_length)
407     {
408       _xdg_mime_magic_matchlet_free (matchlet);
409       if (feof (magic_file))
410 	return XDG_MIME_MAGIC_EOF;
411       else
412 	return XDG_MIME_MAGIC_ERROR;
413     }
414 
415   c = getc_unlocked (magic_file);
416   if (c == '&')
417     {
418       matchlet->mask = malloc (matchlet->value_length);
419       /* OOM */
420       if (matchlet->mask == NULL)
421 	{
422 	  _xdg_mime_magic_matchlet_free (matchlet);
423 	  return XDG_MIME_MAGIC_ERROR;
424 	}
425       bytes_read = fread (matchlet->mask, 1, matchlet->value_length, magic_file);
426       if (bytes_read != matchlet->value_length)
427 	{
428 	  _xdg_mime_magic_matchlet_free (matchlet);
429 	  if (feof (magic_file))
430 	    return XDG_MIME_MAGIC_EOF;
431 	  else
432 	    return XDG_MIME_MAGIC_ERROR;
433 	}
434       c = getc_unlocked (magic_file);
435     }
436 
437   if (c == '~')
438     {
439       matchlet->word_size = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
440       if (end_of_file)
441 	{
442 	  _xdg_mime_magic_matchlet_free (matchlet);
443 	  return XDG_MIME_MAGIC_EOF;
444 	}
445       if (matchlet->word_size != 0 &&
446 	  matchlet->word_size != 1 &&
447 	  matchlet->word_size != 2 &&
448 	  matchlet->word_size != 4)
449 	{
450 	  _xdg_mime_magic_matchlet_free (matchlet);
451 	  return XDG_MIME_MAGIC_ERROR;
452 	}
453       c = getc_unlocked (magic_file);
454     }
455 
456   if (c == '+')
457     {
458       matchlet->range_length = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
459       if (end_of_file)
460 	{
461 	  _xdg_mime_magic_matchlet_free (matchlet);
462 	  return XDG_MIME_MAGIC_EOF;
463 	}
464       if (matchlet->range_length == -1)
465 	{
466 	  _xdg_mime_magic_matchlet_free (matchlet);
467 	  return XDG_MIME_MAGIC_ERROR;
468 	}
469       c = getc_unlocked (magic_file);
470     }
471 
472 
473   if (c == '\n')
474     {
475       /* We clean up the matchlet, byte swapping if needed */
476       if (matchlet->word_size > 1)
477 	{
478 #if LITTLE_ENDIAN
479 	  int i;
480 #endif
481 	  if (matchlet->value_length % matchlet->word_size != 0)
482 	    {
483 	      _xdg_mime_magic_matchlet_free (matchlet);
484 	      return XDG_MIME_MAGIC_ERROR;
485 	    }
486 	  /* FIXME: need to get this defined in a <config.h> style file */
487 #if LITTLE_ENDIAN
488 	  for (i = 0; i < matchlet->value_length; i = i + matchlet->word_size)
489 	    {
490 	      if (matchlet->word_size == 2)
491 		*((xdg_uint16_t *) matchlet->value + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->value + i)));
492 	      else if (matchlet->word_size == 4)
493 		*((xdg_uint32_t *) matchlet->value + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->value + i)));
494 	      if (matchlet->mask)
495 		{
496 		  if (matchlet->word_size == 2)
497 		    *((xdg_uint16_t *) matchlet->mask + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->mask + i)));
498 		  else if (matchlet->word_size == 4)
499 		    *((xdg_uint32_t *) matchlet->mask + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->mask + i)));
500 
501 		}
502 	    }
503 #endif
504 	}
505 
506       matchlet->next = match->matchlet;
507       match->matchlet = matchlet;
508 
509 
510       return XDG_MIME_MAGIC_MAGIC;
511     }
512 
513   _xdg_mime_magic_matchlet_free (matchlet);
514   if (c == EOF)
515     return XDG_MIME_MAGIC_EOF;
516 
517   return XDG_MIME_MAGIC_ERROR;
518 }
519 
520 static int
_xdg_mime_magic_matchlet_compare_to_data(XdgMimeMagicMatchlet * matchlet,const void * data,size_t len)521 _xdg_mime_magic_matchlet_compare_to_data (XdgMimeMagicMatchlet *matchlet,
522 					  const void           *data,
523 					  size_t                len)
524 {
525   int i, j;
526   for (i = matchlet->offset; i < matchlet->offset + matchlet->range_length; i++)
527     {
528       int valid_matchlet = TRUE;
529 
530       if (i + matchlet->value_length > len)
531 	return FALSE;
532 
533       if (matchlet->mask)
534 	{
535 	  for (j = 0; j < matchlet->value_length; j++)
536 	    {
537 	      if ((matchlet->value[j] & matchlet->mask[j]) !=
538 		  ((((unsigned char *) data)[j + i]) & matchlet->mask[j]))
539 		{
540 		  valid_matchlet = FALSE;
541 		  break;
542 		}
543 	    }
544 	}
545       else
546 	{
547 	  for (j = 0; j <  matchlet->value_length; j++)
548 	    {
549 	      if (matchlet->value[j] != ((unsigned char *) data)[j + i])
550 		{
551 		  valid_matchlet = FALSE;
552 		  break;
553 		}
554 	    }
555 	}
556       if (valid_matchlet)
557 	return TRUE;
558     }
559   return FALSE;
560 }
561 
562 static int
_xdg_mime_magic_matchlet_compare_level(XdgMimeMagicMatchlet * matchlet,const void * data,size_t len,int indent)563 _xdg_mime_magic_matchlet_compare_level (XdgMimeMagicMatchlet *matchlet,
564 					const void           *data,
565 					size_t                len,
566 					int                   indent)
567 {
568   while ((matchlet != NULL) && (matchlet->indent == indent))
569     {
570       if (_xdg_mime_magic_matchlet_compare_to_data (matchlet, data, len))
571 	{
572 	  if ((matchlet->next == NULL) ||
573 	      (matchlet->next->indent <= indent))
574 	    return TRUE;
575 
576 	  if (_xdg_mime_magic_matchlet_compare_level (matchlet->next,
577 						      data,
578 						      len,
579 						      indent + 1))
580 	    return TRUE;
581 	}
582 
583       do
584 	{
585 	  matchlet = matchlet->next;
586 	}
587       while (matchlet && matchlet->indent > indent);
588     }
589 
590   return FALSE;
591 }
592 
593 static int
_xdg_mime_magic_match_compare_to_data(XdgMimeMagicMatch * match,const void * data,size_t len)594 _xdg_mime_magic_match_compare_to_data (XdgMimeMagicMatch *match,
595 				       const void        *data,
596 				       size_t             len)
597 {
598   return _xdg_mime_magic_matchlet_compare_level (match->matchlet, data, len, 0);
599 }
600 
601 static void
_xdg_mime_magic_insert_match(XdgMimeMagic * mime_magic,XdgMimeMagicMatch * match)602 _xdg_mime_magic_insert_match (XdgMimeMagic      *mime_magic,
603 			      XdgMimeMagicMatch *match)
604 {
605   XdgMimeMagicMatch *list;
606 
607   if (mime_magic->match_list == NULL)
608     {
609       mime_magic->match_list = match;
610       return;
611     }
612 
613   if (match->priority > mime_magic->match_list->priority)
614     {
615       match->next = mime_magic->match_list;
616       mime_magic->match_list = match;
617       return;
618     }
619 
620   list = mime_magic->match_list;
621   while (list->next != NULL)
622     {
623       if (list->next->priority < match->priority)
624 	{
625 	  match->next = list->next;
626 	  list->next = match;
627 	  return;
628 	}
629       list = list->next;
630     }
631   list->next = match;
632   match->next = NULL;
633 }
634 
635 XdgMimeMagic *
_xdg_mime_magic_new(void)636 _xdg_mime_magic_new (void)
637 {
638   return calloc (1, sizeof (XdgMimeMagic));
639 }
640 
641 void
_xdg_mime_magic_free(XdgMimeMagic * mime_magic)642 _xdg_mime_magic_free (XdgMimeMagic *mime_magic)
643 {
644   if (mime_magic) {
645     _xdg_mime_magic_match_free (mime_magic->match_list);
646     free (mime_magic);
647   }
648 }
649 
650 int
_xdg_mime_magic_get_buffer_extents(XdgMimeMagic * mime_magic)651 _xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic)
652 {
653   return mime_magic->max_extent;
654 }
655 
656 const char *
_xdg_mime_magic_lookup_data(XdgMimeMagic * mime_magic,const void * data,size_t len,int * result_prio,const char * mime_types[],int n_mime_types)657 _xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
658 			     const void   *data,
659 			     size_t        len,
660 			     int           *result_prio,
661                              const char   *mime_types[],
662                              int           n_mime_types)
663 {
664   XdgMimeMagicMatch *match;
665   const char *mime_type;
666   int n;
667   int prio;
668 
669   prio = 0;
670   mime_type = NULL;
671   for (match = mime_magic->match_list; match; match = match->next)
672     {
673       if (_xdg_mime_magic_match_compare_to_data (match, data, len))
674 	{
675 	  prio = match->priority;
676 	  mime_type = match->mime_type;
677 	  break;
678 	}
679       else
680 	{
681 	  for (n = 0; n < n_mime_types; n++)
682 	    {
683 	      if (mime_types[n] &&
684 		  _xdg_mime_mime_type_equal (mime_types[n], match->mime_type))
685 		mime_types[n] = NULL;
686 	    }
687 	}
688     }
689 
690   if (mime_type == NULL)
691     {
692       for (n = 0; n < n_mime_types; n++)
693 	{
694 	  if (mime_types[n])
695 	    mime_type = mime_types[n];
696 	}
697     }
698 
699   if (result_prio)
700     *result_prio = prio;
701 
702   return mime_type;
703 }
704 
705 static void
_xdg_mime_update_mime_magic_extents(XdgMimeMagic * mime_magic)706 _xdg_mime_update_mime_magic_extents (XdgMimeMagic *mime_magic)
707 {
708   XdgMimeMagicMatch *match;
709   int max_extent = 0;
710 
711   for (match = mime_magic->match_list; match; match = match->next)
712     {
713       XdgMimeMagicMatchlet *matchlet;
714 
715       for (matchlet = match->matchlet; matchlet; matchlet = matchlet->next)
716 	{
717 	  int extent;
718 
719 	  extent = matchlet->value_length + matchlet->offset + matchlet->range_length;
720 	  if (max_extent < extent)
721 	    max_extent = extent;
722 	}
723     }
724 
725   mime_magic->max_extent = max_extent;
726 }
727 
728 static XdgMimeMagicMatchlet *
_xdg_mime_magic_matchlet_mirror(XdgMimeMagicMatchlet * matchlets)729 _xdg_mime_magic_matchlet_mirror (XdgMimeMagicMatchlet *matchlets)
730 {
731   XdgMimeMagicMatchlet *new_list;
732   XdgMimeMagicMatchlet *tmp;
733 
734   if ((matchlets == NULL) || (matchlets->next == NULL))
735     return matchlets;
736 
737   new_list = NULL;
738   tmp = matchlets;
739   while (tmp != NULL)
740     {
741       XdgMimeMagicMatchlet *matchlet;
742 
743       matchlet = tmp;
744       tmp = tmp->next;
745       matchlet->next = new_list;
746       new_list = matchlet;
747     }
748 
749   return new_list;
750 
751 }
752 
753 static void
_xdg_mime_magic_read_magic_file(XdgMimeMagic * mime_magic,FILE * magic_file)754 _xdg_mime_magic_read_magic_file (XdgMimeMagic *mime_magic,
755 				 FILE         *magic_file)
756 {
757   XdgMimeMagicState state;
758   XdgMimeMagicMatch *match = NULL; /* Quiet compiler */
759 
760   state = XDG_MIME_MAGIC_SECTION;
761 
762   while (state != XDG_MIME_MAGIC_EOF)
763     {
764       switch (state)
765 	{
766 	case XDG_MIME_MAGIC_SECTION:
767 	  match = _xdg_mime_magic_match_new ();
768 	  state = _xdg_mime_magic_parse_header (magic_file, match);
769 	  if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
770 	    _xdg_mime_magic_match_free (match);
771 	  break;
772 	case XDG_MIME_MAGIC_MAGIC:
773 	  state = _xdg_mime_magic_parse_magic_line (magic_file, match);
774 	  if (state == XDG_MIME_MAGIC_SECTION ||
775 	      (state == XDG_MIME_MAGIC_EOF && match->mime_type))
776 	    {
777 	      match->matchlet = _xdg_mime_magic_matchlet_mirror (match->matchlet);
778 	      _xdg_mime_magic_insert_match (mime_magic, match);
779 	    }
780 	  else if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
781 	    _xdg_mime_magic_match_free (match);
782 	  break;
783 	case XDG_MIME_MAGIC_ERROR:
784 	  state = _xdg_mime_magic_parse_error (magic_file);
785 	  break;
786 	case XDG_MIME_MAGIC_EOF:
787 	default:
788 	  /* Make the compiler happy */
789 	  assert (0);
790 	}
791     }
792   _xdg_mime_update_mime_magic_extents (mime_magic);
793 }
794 
795 void
_xdg_mime_magic_read_from_file(XdgMimeMagic * mime_magic,const char * file_name)796 _xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
797 				const char   *file_name)
798 {
799   FILE *magic_file;
800   char header[12];
801 
802   magic_file = fopen (file_name, "r");
803 
804   if (magic_file == NULL)
805     return;
806 
807   if (fread (header, 1, 12, magic_file) == 12)
808     {
809       if (memcmp ("MIME-Magic\0\n", header, 12) == 0)
810         _xdg_mime_magic_read_magic_file (mime_magic, magic_file);
811     }
812 
813   fclose (magic_file);
814 }
815