~ubuntu-branches/debian/jessie/glib2.0/jessie

« back to all changes in this revision

Viewing changes to gio/xdgmime/xdgmimecache.c

  • Committer: Bazaar Package Importer
  • Author(s): Gustavo Noronha Silva
  • Date: 2009-02-15 13:00:43 UTC
  • mto: (1.4.3 upstream)
  • mto: This revision was merged to the branch mainline in revision 70.
  • Revision ID: james.westby@ubuntu.com-20090215130043-6snh45flhit8oalb
Tags: upstream-2.18.4
ImportĀ upstreamĀ versionĀ 2.18.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
 */
26
26
 
27
27
#ifdef HAVE_CONFIG_H
28
 
#include <config.h>
 
28
#include "config.h"
29
29
#endif
30
30
 
31
31
#include <stdio.h>
32
32
#include <stdlib.h>
33
33
#include <string.h>
 
34
#include <ctype.h>
34
35
 
35
36
#include <fcntl.h>
36
37
#include <unistd.h>
41
42
 
42
43
#ifdef HAVE_MMAP
43
44
#include <sys/mman.h>
 
45
#else
 
46
#warning Building xdgmime without MMAP support. Binary "mime.info" cache files will not be used.
44
47
#endif
45
48
 
46
49
#include <sys/stat.h>
70
73
#endif
71
74
 
72
75
#define MAJOR_VERSION 1
73
 
#define MINOR_VERSION 0
 
76
#define MINOR_VERSION 1
74
77
 
75
78
struct _XdgMimeCache
76
79
{
297
300
          for (n = 0; n < n_mime_types; n++)
298
301
            {
299
302
              if (mime_types[n] && 
300
 
                  xdg_mime_mime_type_equal (mime_types[n], non_match))
 
303
                  _xdg_mime_mime_type_equal (mime_types[n], non_match))
301
304
                mime_types[n] = NULL;
302
305
            }
303
306
        }
344
347
  return NULL;
345
348
}
346
349
 
 
350
typedef struct {
 
351
  const char *mime;
 
352
  int weight;
 
353
} MimeWeight;
 
354
 
347
355
static int
348
356
cache_glob_lookup_literal (const char *file_name,
349
357
                           const char *mime_types[],
365
373
        {
366
374
          mid = (min + max) / 2;
367
375
 
368
 
          offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
 
376
          offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid);
369
377
          ptr = cache->buffer + offset;
370
378
          cmp = strcmp (ptr, file_name);
371
379
          
375
383
            max = mid - 1;
376
384
          else
377
385
            {
378
 
              offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
 
386
              offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 4);
379
387
              mime_types[0] = (const char *)(cache->buffer + offset);
380
388
              
381
389
              return 1;
388
396
 
389
397
static int
390
398
cache_glob_lookup_fnmatch (const char *file_name,
391
 
                           const char *mime_types[],
 
399
                           MimeWeight  mime_types[],
392
400
                           int         n_mime_types)
393
401
{
394
402
  const char *mime_type;
406
414
 
407
415
      for (j = 0; j < n_entries && n < n_mime_types; j++)
408
416
        {
409
 
          xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j);
410
 
          xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j + 4);
 
417
          xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j);
 
418
          xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 4);
 
419
          int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 8);
411
420
          ptr = cache->buffer + offset;
412
421
          mime_type = cache->buffer + mimetype_offset;
413
422
 
414
423
          /* FIXME: Not UTF-8 safe */
415
424
          if (fnmatch (ptr, file_name, 0) == 0)
416
 
            mime_types[n++] = mime_type;
 
425
            {
 
426
              mime_types[n].mime = mime_type;
 
427
              mime_types[n].weight = weight;
 
428
              n++;
 
429
            }
417
430
        }
418
431
 
419
432
      if (n > 0)
424
437
}
425
438
 
426
439
static int
427
 
cache_glob_node_lookup_suffix (XdgMimeCache *cache,
428
 
                               xdg_uint32_t  n_entries,
429
 
                               xdg_uint32_t  offset,
430
 
                               const char   *suffix, 
431
 
                               int           ignore_case,
432
 
                               const char   *mime_types[],
433
 
                               int           n_mime_types)
 
440
cache_glob_node_lookup_suffix (XdgMimeCache  *cache,
 
441
                               xdg_uint32_t   n_entries,
 
442
                               xdg_uint32_t   offset,
 
443
                               const char    *file_name,
 
444
                               int            len,
 
445
                               int            ignore_case,
 
446
                               MimeWeight     mime_types[],
 
447
                               int            n_mime_types)
434
448
{
435
449
  xdg_unichar_t character;
436
450
  xdg_unichar_t match_char;
437
451
  xdg_uint32_t mimetype_offset;
438
452
  xdg_uint32_t n_children;
439
453
  xdg_uint32_t child_offset; 
 
454
  int weight;
440
455
 
441
456
  int min, max, mid, n, i;
442
457
 
443
 
  character = _xdg_utf8_to_ucs4 (suffix);
 
458
  character = file_name[len - 1];
444
459
  if (ignore_case)
445
 
    character = _xdg_ucs4_to_lower (character);
 
460
    character = tolower (character);
 
461
 
 
462
  assert (character != 0);
446
463
 
447
464
  min = 0;
448
465
  max = n_entries - 1;
449
466
  while (max >= min)
450
467
    {
451
468
      mid = (min + max) /  2;
452
 
 
453
 
      match_char = GET_UINT32 (cache->buffer, offset + 16 * mid);
454
 
 
 
469
      match_char = GET_UINT32 (cache->buffer, offset + 12 * mid);
455
470
      if (match_char < character)
456
471
        min = mid + 1;
457
472
      else if (match_char > character)
458
473
        max = mid - 1;
459
474
      else 
460
475
        {
461
 
          suffix = _xdg_utf8_next_char (suffix);
462
 
          if (*suffix == '\0')
463
 
            {
464
 
              mimetype_offset = GET_UINT32 (cache->buffer, offset + 16 * mid + 4);
465
 
              n = 0;
466
 
              if (mimetype_offset)
467
 
                mime_types[n++] = cache->buffer + mimetype_offset;
468
 
              
469
 
              n_children = GET_UINT32 (cache->buffer, offset + 16 * mid + 8);
470
 
              child_offset = GET_UINT32 (cache->buffer, offset + 16 * mid + 12);
 
476
          len--;
 
477
          n = 0;
 
478
          n_children = GET_UINT32 (cache->buffer, offset + 12 * mid + 4);
 
479
          child_offset = GET_UINT32 (cache->buffer, offset + 12 * mid + 8);
 
480
      
 
481
          if (len > 0)
 
482
            {
 
483
              n = cache_glob_node_lookup_suffix (cache, 
 
484
                                                 n_children, child_offset,
 
485
                                                 file_name, len, 
 
486
                                                 ignore_case,
 
487
                                                 mime_types,
 
488
                                                 n_mime_types);
 
489
            }
 
490
          if (n == 0)
 
491
            {
471
492
              i = 0;
472
493
              while (n < n_mime_types && i < n_children)
473
494
                {
474
 
                  match_char = GET_UINT32 (cache->buffer, child_offset + 16 * i);
475
 
                  mimetype_offset = GET_UINT32 (cache->buffer, offset + 16 * i + 4);
 
495
                  match_char = GET_UINT32 (cache->buffer, child_offset + 12 * i);
476
496
                  if (match_char != 0)
477
497
                    break;
478
498
 
479
 
                  mime_types[n++] = cache->buffer + mimetype_offset;
 
499
                  mimetype_offset = GET_UINT32 (cache->buffer, child_offset + 12 * i + 4);
 
500
                  weight = GET_UINT32 (cache->buffer, child_offset + 12 * i + 8);
 
501
 
 
502
                  mime_types[n].mime = cache->buffer + mimetype_offset;
 
503
                  mime_types[n].weight = weight;
 
504
                  n++;
480
505
                  i++;
481
506
                }
482
 
 
483
 
              return n;
484
 
            }
485
 
          else
486
 
            {
487
 
              n_children = GET_UINT32 (cache->buffer, offset + 16 * mid + 8);
488
 
              child_offset = GET_UINT32 (cache->buffer, offset + 16 * mid + 12);
489
 
      
490
 
              return cache_glob_node_lookup_suffix (cache, 
491
 
                                                    n_children, child_offset,
492
 
                                                    suffix, ignore_case,
493
 
                                                    mime_types,
494
 
                                                    n_mime_types);
495
 
            }
 
507
            }
 
508
          return n;
496
509
        }
497
510
    }
498
 
 
499
511
  return 0;
500
512
}
501
513
 
502
514
static int
503
 
cache_glob_lookup_suffix (const char *suffix, 
 
515
cache_glob_lookup_suffix (const char *file_name,
 
516
                          int         len,
504
517
                          int         ignore_case,
505
 
                          const char *mime_types[],
 
518
                          MimeWeight  mime_types[],
506
519
                          int         n_mime_types)
507
520
{
508
521
  int i, n;
517
530
 
518
531
      n = cache_glob_node_lookup_suffix (cache, 
519
532
                                         n_entries, offset, 
520
 
                                         suffix, ignore_case,
 
533
                                         file_name, len,
 
534
                                         ignore_case,
521
535
                                         mime_types,
522
536
                                         n_mime_types);
523
537
      if (n > 0)
527
541
  return 0;
528
542
}
529
543
 
530
 
static void
531
 
find_stopchars (char *stopchars)
 
544
static int compare_mime_weight (const void *a, const void *b)
532
545
{
533
 
  int i, j, k, l;
534
 
 
535
 
  k = 0;
536
 
  for (i = 0; _caches[i]; i++)
537
 
    {
538
 
      XdgMimeCache *cache = _caches[i];
539
 
 
540
 
      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 16);
541
 
      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
542
 
      xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4);
543
 
 
544
 
      for (j = 0; j < n_entries; j++)
545
 
        {
546
 
          xdg_uint32_t match_char = GET_UINT32 (cache->buffer, offset);
547
 
          
548
 
          if (match_char < 128)
549
 
            {
550
 
              for (l = 0; l < k; l++)
551
 
                if (stopchars[l] == match_char)
552
 
                  break;
553
 
              if (l == k)
554
 
                {
555
 
                  stopchars[k] = (char) match_char;
556
 
                  k++;
557
 
                }
558
 
            }
559
 
 
560
 
          offset += 16;
561
 
        }
562
 
    }
563
 
 
564
 
  stopchars[k] = '\0';
 
546
  const MimeWeight *aa = (const MimeWeight *)a;
 
547
  const MimeWeight *bb = (const MimeWeight *)b;
 
548
 
 
549
  return aa->weight - bb->weight;
565
550
}
566
551
 
567
552
static int
569
554
                             const char *mime_types[],
570
555
                             int         n_mime_types)
571
556
{
572
 
  const char *ptr;
573
 
  char stopchars[128];
574
557
  int n;
 
558
  MimeWeight mimes[10];
 
559
  int n_mimes = 10;
 
560
  int i;
 
561
  int len;
575
562
  
576
 
  assert (file_name != NULL);
 
563
  assert (file_name != NULL && n_mime_types > 0);
577
564
 
578
565
  /* First, check the literals */
579
566
  n = cache_glob_lookup_literal (file_name, mime_types, n_mime_types);
580
567
  if (n > 0)
581
568
    return n;
582
569
 
583
 
  find_stopchars (stopchars);
584
 
 
585
 
  /* Next, check suffixes */
586
 
  ptr = strpbrk (file_name, stopchars);
587
 
  while (ptr)
588
 
    {
589
 
      n = cache_glob_lookup_suffix (ptr, FALSE, mime_types, n_mime_types);
590
 
      if (n > 0)
591
 
        return n;
592
 
      
593
 
      n = cache_glob_lookup_suffix (ptr, TRUE, mime_types, n_mime_types);
594
 
      if (n > 0)
595
 
        return n;
596
 
 
597
 
      ptr = strpbrk (ptr + 1, stopchars);
598
 
    }
 
570
  len = strlen (file_name);
 
571
  n = cache_glob_lookup_suffix (file_name, len, FALSE, mimes, n_mimes);
 
572
 
 
573
  if (n == 0)
 
574
    n = cache_glob_lookup_suffix (file_name, len, TRUE, mimes, n_mimes);
599
575
  
600
576
  /* Last, try fnmatch */
601
 
  return cache_glob_lookup_fnmatch (file_name, mime_types, n_mime_types);
 
577
  if (n == 0)
 
578
    n = cache_glob_lookup_fnmatch (file_name, mimes, n_mimes);
 
579
 
 
580
  qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight);
 
581
 
 
582
  if (n_mime_types < n)
 
583
    n = n_mime_types;
 
584
 
 
585
  for (i = 0; i < n; i++)
 
586
    mime_types[i] = mimes[i].mime;
 
587
 
 
588
  return n;
602
589
}
603
590
 
604
591
int
677
664
                                        struct stat *statbuf)
678
665
{
679
666
  const char *mime_type;
680
 
  const char *mime_types[2];
 
667
  const char *mime_types[10];
681
668
  FILE *file;
682
669
  unsigned char *data;
683
670
  int max_extent;
693
680
    return NULL;
694
681
 
695
682
  base_name = _xdg_get_base_name (file_name);
696
 
  n = cache_glob_lookup_file_name (base_name, mime_types, 2);
 
683
  n = cache_glob_lookup_file_name (base_name, mime_types, 10);
697
684
 
698
685
  if (n == 1)
699
686
    return mime_types[0];
918
905
  return result;
919
906
}
920
907
 
 
908
static const char *
 
909
cache_lookup_icon (const char *mime, int header)
 
910
{
 
911
  const char *ptr;
 
912
  int i, min, max, mid, cmp;
 
913
 
 
914
  for (i = 0; _caches[i]; i++)
 
915
    {
 
916
      XdgMimeCache *cache = _caches[i];
 
917
      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, header);
 
918
      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
 
919
      xdg_uint32_t offset;
 
920
 
 
921
      min = 0; 
 
922
      max = n_entries - 1;
 
923
      while (max >= min) 
 
924
        {
 
925
          mid = (min + max) / 2;
 
926
 
 
927
          offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
 
928
          ptr = cache->buffer + offset;
 
929
          cmp = strcmp (ptr, mime);
 
930
         
 
931
          if (cmp < 0)
 
932
            min = mid + 1;
 
933
          else if (cmp > 0)
 
934
            max = mid - 1;
 
935
          else
 
936
            {
 
937
              offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
 
938
              return cache->buffer + offset;
 
939
            }
 
940
        }
 
941
    }
 
942
 
 
943
  return NULL;
 
944
}
 
945
 
 
946
const char *
 
947
_xdg_mime_cache_get_generic_icon (const char *mime)
 
948
{
 
949
  return cache_lookup_icon (mime, 36);
 
950
}
 
951
 
 
952
const char *
 
953
_xdg_mime_cache_get_icon (const char *mime)
 
954
{
 
955
  return cache_lookup_icon (mime, 32);
 
956
}
 
957
 
 
958
static void
 
959
dump_glob_node (XdgMimeCache *cache,
 
960
                xdg_uint32_t  offset,
 
961
                int           depth)
 
962
{
 
963
  xdg_unichar_t character;
 
964
  xdg_uint32_t mime_offset;
 
965
  xdg_uint32_t n_children;
 
966
  xdg_uint32_t child_offset;
 
967
  int i;
 
968
 
 
969
  character = GET_UINT32 (cache->buffer, offset);
 
970
  mime_offset = GET_UINT32 (cache->buffer, offset + 4);
 
971
  n_children = GET_UINT32 (cache->buffer, offset + 8);
 
972
  child_offset = GET_UINT32 (cache->buffer, offset + 12);
 
973
  for (i = 0; i < depth; i++)
 
974
    printf (" ");
 
975
  printf ("%c", character);
 
976
  if (mime_offset)
 
977
    printf (" - %s", cache->buffer + mime_offset);
 
978
  printf ("\n");
 
979
  if (child_offset)
 
980
  {
 
981
    for (i = 0; i < n_children; i++)
 
982
      dump_glob_node (cache, child_offset + 20 * i, depth + 1);
 
983
  }
 
984
}
 
985
 
 
986
void
 
987
_xdg_mime_cache_glob_dump (void)
 
988
{
 
989
  int i, j;
 
990
  for (i = 0; _caches[i]; i++)
 
991
  {
 
992
    XdgMimeCache *cache = _caches[i];
 
993
    xdg_uint32_t list_offset;
 
994
    xdg_uint32_t n_entries;
 
995
    xdg_uint32_t offset;
 
996
    list_offset = GET_UINT32 (cache->buffer, 16);
 
997
    n_entries = GET_UINT32 (cache->buffer, list_offset);
 
998
    offset = GET_UINT32 (cache->buffer, list_offset + 4);
 
999
    for (j = 0; j < n_entries; j++)
 
1000
            dump_glob_node (cache, offset + 20 * j, 0);
 
1001
  }
 
1002
}
 
1003
 
 
1004