Coverage Report

Created: 2025-06-13 06:55

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