Coverage Report

Created: 2025-07-01 07:09

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