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