Coverage Report

Created: 2025-07-11 07:03

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