~adam-stokes/ubuntu/quantal/gnome-vfs/lp977940-multiarch

« back to all changes in this revision

Viewing changes to libgnomevfs/xdgmimecache.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2008-08-05 10:31:15 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080805103115-5vkex0yk6qq619x5
Tags: 1:2.23.0-0ubuntu1
* New upstream version:
  - Sync xdgmime with GIO
* debian/patches/90_from_svn_no_range_for_youtube.patch:
  - the change is in the new version

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>
41
41
 
42
42
#ifdef HAVE_MMAP
43
43
#include <sys/mman.h>
 
44
#else
 
45
#warning Building xdgmime without MMAP support. Binary "mime.info" cache files will not be used.
44
46
#endif
45
47
 
46
48
#include <sys/stat.h>
70
72
#endif
71
73
 
72
74
#define MAJOR_VERSION 1
73
 
#define MINOR_VERSION 0
 
75
#define MINOR_VERSION 1
74
76
 
75
77
struct _XdgMimeCache
76
78
{
297
299
          for (n = 0; n < n_mime_types; n++)
298
300
            {
299
301
              if (mime_types[n] && 
300
 
                  xdg_mime_mime_type_equal (mime_types[n], non_match))
 
302
                  _xdg_mime_mime_type_equal (mime_types[n], non_match))
301
303
                mime_types[n] = NULL;
302
304
            }
303
305
        }
344
346
  return NULL;
345
347
}
346
348
 
 
349
typedef struct {
 
350
  const char *mime;
 
351
  int weight;
 
352
} MimeWeight;
 
353
 
347
354
static int
348
355
cache_glob_lookup_literal (const char *file_name,
349
356
                           const char *mime_types[],
365
372
        {
366
373
          mid = (min + max) / 2;
367
374
 
368
 
          offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
 
375
          offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid);
369
376
          ptr = cache->buffer + offset;
370
377
          cmp = strcmp (ptr, file_name);
371
378
          
375
382
            max = mid - 1;
376
383
          else
377
384
            {
378
 
              offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
 
385
              offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 4);
379
386
              mime_types[0] = (const char *)(cache->buffer + offset);
380
387
              
381
388
              return 1;
388
395
 
389
396
static int
390
397
cache_glob_lookup_fnmatch (const char *file_name,
391
 
                           const char *mime_types[],
 
398
                           MimeWeight  mime_types[],
392
399
                           int         n_mime_types)
393
400
{
394
401
  const char *mime_type;
406
413
 
407
414
      for (j = 0; j < n_entries && n < n_mime_types; j++)
408
415
        {
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);
 
416
          xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j);
 
417
          xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 4);
 
418
          int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 8);
411
419
          ptr = cache->buffer + offset;
412
420
          mime_type = cache->buffer + mimetype_offset;
413
421
 
414
422
          /* FIXME: Not UTF-8 safe */
415
423
          if (fnmatch (ptr, file_name, 0) == 0)
416
 
            mime_types[n++] = mime_type;
 
424
            {
 
425
              mime_types[n].mime = mime_type;
 
426
              mime_types[n].weight = weight;
 
427
              n++;
 
428
            }
417
429
        }
418
430
 
419
431
      if (n > 0)
424
436
}
425
437
 
426
438
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)
 
439
cache_glob_node_lookup_suffix (XdgMimeCache  *cache,
 
440
                               xdg_uint32_t   n_entries,
 
441
                               xdg_uint32_t   offset,
 
442
                               xdg_unichar_t *file_name,
 
443
                               int            len,
 
444
                               int            ignore_case,
 
445
                               MimeWeight     mime_types[],
 
446
                               int            n_mime_types)
434
447
{
435
448
  xdg_unichar_t character;
436
449
  xdg_unichar_t match_char;
437
450
  xdg_uint32_t mimetype_offset;
438
451
  xdg_uint32_t n_children;
439
452
  xdg_uint32_t child_offset; 
 
453
  int weight;
440
454
 
441
455
  int min, max, mid, n, i;
442
456
 
443
 
  character = _xdg_utf8_to_ucs4 (suffix);
 
457
  character = file_name[len - 1];
444
458
  if (ignore_case)
445
459
    character = _xdg_ucs4_to_lower (character);
446
460
 
 
461
  assert (character != 0);
 
462
 
447
463
  min = 0;
448
464
  max = n_entries - 1;
449
465
  while (max >= min)
450
466
    {
451
467
      mid = (min + max) /  2;
452
 
 
453
 
      match_char = GET_UINT32 (cache->buffer, offset + 16 * mid);
454
 
 
 
468
      match_char = GET_UINT32 (cache->buffer, offset + 12 * mid);
455
469
      if (match_char < character)
456
470
        min = mid + 1;
457
471
      else if (match_char > character)
458
472
        max = mid - 1;
459
473
      else 
460
474
        {
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
 
              mime_types[n++] = cache->buffer + mimetype_offset;
467
 
              
468
 
              n_children = GET_UINT32 (cache->buffer, offset + 16 * mid + 8);
469
 
              child_offset = GET_UINT32 (cache->buffer, offset + 16 * mid + 12);
 
475
          len--;
 
476
          n = 0;
 
477
          n_children = GET_UINT32 (cache->buffer, offset + 12 * mid + 4);
 
478
          child_offset = GET_UINT32 (cache->buffer, offset + 12 * mid + 8);
 
479
      
 
480
          if (len > 0)
 
481
            {
 
482
              n = cache_glob_node_lookup_suffix (cache, 
 
483
                                                 n_children, child_offset,
 
484
                                                 file_name, len, 
 
485
                                                 ignore_case,
 
486
                                                 mime_types,
 
487
                                                 n_mime_types);
 
488
            }
 
489
          if (n == 0)
 
490
            {
470
491
              i = 0;
471
492
              while (n < n_mime_types && i < n_children)
472
493
                {
473
 
                  match_char = GET_UINT32 (cache->buffer, child_offset + 16 * i);
474
 
                  mimetype_offset = GET_UINT32 (cache->buffer, offset + 16 * i + 4);
 
494
                  match_char = GET_UINT32 (cache->buffer, child_offset + 12 * i);
475
495
                  if (match_char != 0)
476
496
                    break;
477
497
 
478
 
                  mime_types[n++] = cache->buffer + mimetype_offset;
 
498
                  mimetype_offset = GET_UINT32 (cache->buffer, child_offset + 12 * i + 4);
 
499
                  weight = GET_UINT32 (cache->buffer, child_offset + 12 * i + 8);
 
500
 
 
501
                  mime_types[n].mime = cache->buffer + mimetype_offset;
 
502
                  mime_types[n].weight = weight;
 
503
                  n++;
479
504
                  i++;
480
505
                }
481
 
 
482
 
              return n;
483
 
            }
484
 
          else
485
 
            {
486
 
              n_children = GET_UINT32 (cache->buffer, offset + 16 * mid + 8);
487
 
              child_offset = GET_UINT32 (cache->buffer, offset + 16 * mid + 12);
488
 
      
489
 
              return cache_glob_node_lookup_suffix (cache, 
490
 
                                                    n_children, child_offset,
491
 
                                                    suffix, ignore_case,
492
 
                                                    mime_types,
493
 
                                                    n_mime_types);
494
 
            }
 
506
            }
 
507
          return n;
495
508
        }
496
509
    }
497
 
 
498
510
  return 0;
499
511
}
500
512
 
501
513
static int
502
 
cache_glob_lookup_suffix (const char *suffix, 
503
 
                          int         ignore_case,
504
 
                          const char *mime_types[],
505
 
                          int         n_mime_types)
 
514
cache_glob_lookup_suffix (xdg_unichar_t *file_name,
 
515
                          int            len,
 
516
                          int            ignore_case,
 
517
                          MimeWeight     mime_types[],
 
518
                          int            n_mime_types)
506
519
{
507
520
  int i, n;
508
521
 
516
529
 
517
530
      n = cache_glob_node_lookup_suffix (cache, 
518
531
                                         n_entries, offset, 
519
 
                                         suffix, ignore_case,
 
532
                                         file_name, len,
 
533
                                         ignore_case,
520
534
                                         mime_types,
521
535
                                         n_mime_types);
522
536
      if (n > 0)
526
540
  return 0;
527
541
}
528
542
 
529
 
static void
530
 
find_stopchars (char *stopchars)
 
543
static int compare_mime_weight (const void *a, const void *b)
531
544
{
532
 
  int i, j, k, l;
533
 
 
534
 
  k = 0;
535
 
  for (i = 0; _caches[i]; i++)
536
 
    {
537
 
      XdgMimeCache *cache = _caches[i];
538
 
 
539
 
      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 16);
540
 
      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
541
 
      xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4);
542
 
 
543
 
      for (j = 0; j < n_entries; j++)
544
 
        {
545
 
          xdg_uint32_t match_char = GET_UINT32 (cache->buffer, offset);
546
 
          
547
 
          if (match_char < 128)
548
 
            {
549
 
              for (l = 0; l < k; l++)
550
 
                if (stopchars[l] == match_char)
551
 
                  break;
552
 
              if (l == k)
553
 
                {
554
 
                  stopchars[k] = (char) match_char;
555
 
                  k++;
556
 
                }
557
 
            }
558
 
 
559
 
          offset += 16;
560
 
        }
561
 
    }
562
 
 
563
 
  stopchars[k] = '\0';
 
545
  const MimeWeight *aa = (const MimeWeight *)a;
 
546
  const MimeWeight *bb = (const MimeWeight *)b;
 
547
 
 
548
  return aa->weight - bb->weight;
564
549
}
565
550
 
566
551
static int
568
553
                             const char *mime_types[],
569
554
                             int         n_mime_types)
570
555
{
571
 
  const char *ptr;
572
 
  char stopchars[128];
573
556
  int n;
 
557
  MimeWeight mimes[10];
 
558
  int n_mimes = 10;
 
559
  int i;
 
560
  xdg_unichar_t *ucs4;
 
561
  int len;
574
562
  
575
 
  assert (file_name != NULL);
 
563
  assert (file_name != NULL && n_mime_types > 0);
576
564
 
577
565
  /* First, check the literals */
578
566
  n = cache_glob_lookup_literal (file_name, mime_types, n_mime_types);
579
567
  if (n > 0)
580
568
    return n;
581
569
 
582
 
  find_stopchars (stopchars);
583
 
 
584
 
  /* Next, check suffixes */
585
 
  ptr = strpbrk (file_name, stopchars);
586
 
  while (ptr)
587
 
    {
588
 
      n = cache_glob_lookup_suffix (ptr, FALSE, mime_types, n_mime_types);
589
 
      if (n > 0)
590
 
        return n;
591
 
      
592
 
      n = cache_glob_lookup_suffix (ptr, TRUE, mime_types, n_mime_types);
593
 
      if (n > 0)
594
 
        return n;
595
 
 
596
 
      ptr = strpbrk (ptr + 1, stopchars);
597
 
    }
 
570
  ucs4 = _xdg_convert_to_ucs4 (file_name, &len);
 
571
  n = cache_glob_lookup_suffix (ucs4, len, FALSE, mimes, n_mimes);
 
572
 
 
573
  if (n == 0)
 
574
    n = cache_glob_lookup_suffix (ucs4, len, TRUE, mimes, n_mimes);
 
575
  free(ucs4);
598
576
  
599
577
  /* Last, try fnmatch */
600
 
  return cache_glob_lookup_fnmatch (file_name, mime_types, n_mime_types);
 
578
  if (n == 0)
 
579
    n = cache_glob_lookup_fnmatch (file_name, mimes, n_mimes);
 
580
 
 
581
  qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight);
 
582
 
 
583
  if (n_mime_types < n)
 
584
    n = n_mime_types;
 
585
 
 
586
  for (i = 0; i < n; i++)
 
587
    mime_types[i] = mimes[i].mime;
 
588
 
 
589
  return n;
601
590
}
602
591
 
603
592
int
622
611
static const char *
623
612
cache_get_mime_type_for_data (const void *data,
624
613
                              size_t      len,
 
614
                              int        *result_prio,
625
615
                              const char *mime_types[],
626
616
                              int         n_mime_types)
627
617
{
646
636
        }
647
637
    }
648
638
 
 
639
  if (result_prio)
 
640
    *result_prio = priority;
 
641
  
649
642
  if (priority > 0)
650
643
    return mime_type;
651
644
 
652
645
  for (n = 0; n < n_mime_types; n++)
653
646
    {
 
647
      
654
648
      if (mime_types[n])
655
649
        return mime_types[n];
656
650
    }
660
654
 
661
655
const char *
662
656
_xdg_mime_cache_get_mime_type_for_data (const void *data,
663
 
                                        size_t      len)
 
657
                                        size_t      len,
 
658
                                        int        *result_prio)
664
659
{
665
 
  return cache_get_mime_type_for_data (data, len, NULL, 0);
 
660
  return cache_get_mime_type_for_data (data, len, result_prio, NULL, 0);
666
661
}
667
662
 
668
663
const char *
670
665
                                        struct stat *statbuf)
671
666
{
672
667
  const char *mime_type;
673
 
  const char *mime_types[2];
 
668
  const char *mime_types[10];
674
669
  FILE *file;
675
670
  unsigned char *data;
676
671
  int max_extent;
686
681
    return NULL;
687
682
 
688
683
  base_name = _xdg_get_base_name (file_name);
689
 
  n = cache_glob_lookup_file_name (base_name, mime_types, 2);
 
684
  n = cache_glob_lookup_file_name (base_name, mime_types, 10);
690
685
 
691
686
  if (n == 1)
692
687
    return mime_types[0];
725
720
      return XDG_MIME_TYPE_UNKNOWN;
726
721
    }
727
722
 
728
 
  mime_type = cache_get_mime_type_for_data (data, bytes_read,
 
723
  mime_type = cache_get_mime_type_for_data (data, bytes_read, NULL,
729
724
                                            mime_types, n);
730
725
 
731
726
  free (data);
745
740
    return XDG_MIME_TYPE_UNKNOWN;
746
741
}
747
742
 
 
743
int
 
744
_xdg_mime_cache_get_mime_types_from_file_name (const char *file_name,
 
745
                                               const char  *mime_types[],
 
746
                                               int          n_mime_types)
 
747
{
 
748
  return cache_glob_lookup_file_name (file_name, mime_types, n_mime_types);
 
749
}
 
750
 
748
751
#if 1
749
752
static int
750
753
is_super_type (const char *mime)
850
853
char **
851
854
_xdg_mime_cache_list_mime_parents (const char *mime)
852
855
{
853
 
  int i, j, p;
 
856
  int i, j, k, l, p;
854
857
  char *all_parents[128]; /* we'll stop at 128 */ 
855
858
  char **result;
856
859
 
 
860
  mime = xdg_mime_unalias_mime_type (mime);
 
861
 
857
862
  p = 0;
858
863
  for (i = 0; _caches[i]; i++)
859
864
    {
864
869
 
865
870
      for (j = 0; j < n_entries; j++)
866
871
        {
867
 
          xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * i);
868
 
          xdg_uint32_t parents_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * i + 4);
869
 
          
 
872
          xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j);
 
873
          xdg_uint32_t parents_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j + 4);
 
874
 
870
875
          if (strcmp (cache->buffer + mimetype_offset, mime) == 0)
871
876
            {
 
877
              xdg_uint32_t parent_mime_offset;
872
878
              xdg_uint32_t n_parents = GET_UINT32 (cache->buffer, parents_offset);
873
 
              
874
 
              for (j = 0; j < n_parents; j++)
875
 
                all_parents[p++] = cache->buffer + parents_offset + 4 + 4 * j;
 
879
 
 
880
              for (k = 0; k < n_parents && p < 127; k++)
 
881
                {
 
882
                  parent_mime_offset = GET_UINT32 (cache->buffer, parents_offset + 4 + 4 * k);
 
883
 
 
884
                  /* Don't add same parent multiple times.
 
885
                   * This can happen for instance if the same type is listed in multiple directories
 
886
                   */
 
887
                  for (l = 0; l < p; l++)
 
888
                    {
 
889
                      if (strcmp (all_parents[l], cache->buffer + parent_mime_offset) == 0)
 
890
                        break;
 
891
                    }
 
892
 
 
893
                  if (l == p)
 
894
                    all_parents[p++] = cache->buffer + parent_mime_offset;
 
895
                }
876
896
 
877
897
              break;
878
898
            }
879
899
        }
880
900
    }
881
 
  all_parents[p++] = 0;
 
901
  all_parents[p++] = NULL;
882
902
  
883
903
  result = (char **) malloc (p * sizeof (char *));
884
904
  memcpy (result, all_parents, p * sizeof (char *));
886
906
  return result;
887
907
}
888
908
 
 
909
static const char *
 
910
cache_lookup_icon (const char *mime, int header)
 
911
{
 
912
  const char *ptr;
 
913
  int i, min, max, mid, cmp;
 
914
 
 
915
  for (i = 0; _caches[i]; i++)
 
916
    {
 
917
      XdgMimeCache *cache = _caches[i];
 
918
      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, header);
 
919
      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
 
920
      xdg_uint32_t offset;
 
921
 
 
922
      min = 0; 
 
923
      max = n_entries - 1;
 
924
      while (max >= min) 
 
925
        {
 
926
          mid = (min + max) / 2;
 
927
 
 
928
          offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
 
929
          ptr = cache->buffer + offset;
 
930
          cmp = strcmp (ptr, mime);
 
931
         
 
932
          if (cmp < 0)
 
933
            min = mid + 1;
 
934
          else if (cmp > 0)
 
935
            max = mid - 1;
 
936
          else
 
937
            {
 
938
              offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
 
939
              return cache->buffer + offset;
 
940
            }
 
941
        }
 
942
    }
 
943
 
 
944
  return NULL;
 
945
}
 
946
 
 
947
const char *
 
948
_xdg_mime_cache_get_generic_icon (const char *mime)
 
949
{
 
950
  return cache_lookup_icon (mime, 36);
 
951
}
 
952
 
 
953
const char *
 
954
_xdg_mime_cache_get_icon (const char *mime)
 
955
{
 
956
  const char *icon;
 
957
 
 
958
  icon = cache_lookup_icon (mime, 32);
 
959
 
 
960
  if (icon == NULL)
 
961
    icon = _xdg_mime_cache_get_generic_icon (mime);
 
962
 
 
963
  return icon;
 
964
}
 
965
 
 
966
static void
 
967
dump_glob_node (XdgMimeCache *cache,
 
968
                xdg_uint32_t  offset,
 
969
                int           depth)
 
970
{
 
971
  xdg_unichar_t character;
 
972
  xdg_uint32_t mime_offset;
 
973
  xdg_uint32_t n_children;
 
974
  xdg_uint32_t child_offset;
 
975
  int i;
 
976
 
 
977
  character = GET_UINT32 (cache->buffer, offset);
 
978
  mime_offset = GET_UINT32 (cache->buffer, offset + 4);
 
979
  n_children = GET_UINT32 (cache->buffer, offset + 8);
 
980
  child_offset = GET_UINT32 (cache->buffer, offset + 12);
 
981
  for (i = 0; i < depth; i++)
 
982
    printf (" ");
 
983
  printf ("%c", character);
 
984
  if (mime_offset)
 
985
    printf (" - %s", cache->buffer + mime_offset);
 
986
  printf ("\n");
 
987
  if (child_offset)
 
988
  {
 
989
    for (i = 0; i < n_children; i++)
 
990
      dump_glob_node (cache, child_offset + 20 * i, depth + 1);
 
991
  }
 
992
}
 
993
 
 
994
void
 
995
_xdg_mime_cache_glob_dump (void)
 
996
{
 
997
  int i, j;
 
998
  for (i = 0; _caches[i]; i++)
 
999
  {
 
1000
    XdgMimeCache *cache = _caches[i];
 
1001
    xdg_uint32_t list_offset;
 
1002
    xdg_uint32_t n_entries;
 
1003
    xdg_uint32_t offset;
 
1004
    list_offset = GET_UINT32 (cache->buffer, 16);
 
1005
    n_entries = GET_UINT32 (cache->buffer, list_offset);
 
1006
    offset = GET_UINT32 (cache->buffer, list_offset + 4);
 
1007
    for (j = 0; j < n_entries; j++)
 
1008
            dump_glob_node (cache, offset + 20 * j, 0);
 
1009
  }
 
1010
}
 
1011
 
 
1012