]> git.proxmox.com Git - libxdgmime-perl.git/commitdiff
Merge commit '73d5a30a1d93eb79761f2472c685afb8e42a8646' from upstream
authorStoiko Ivanov <s.ivanov@proxmox.com>
Wed, 24 May 2023 11:06:12 +0000 (13:06 +0200)
committerStoiko Ivanov <s.ivanov@proxmox.com>
Wed, 24 May 2023 11:06:12 +0000 (13:06 +0200)
git-subtree-dir: xdgmime-source
git-subtree-origin: https://gitlab.freedesktop.org/xdg/xdgmime.git

23 files changed:
1  2 
xdgmime-source/.gitlab-ci.yml
xdgmime-source/meson.build
xdgmime-source/src/Makefile
xdgmime-source/src/meson.build
xdgmime-source/src/print-mime-data.c
xdgmime-source/src/test-mime-data.c
xdgmime-source/src/test-mime.c
xdgmime-source/src/xdgmime.c
xdgmime-source/src/xdgmime.h
xdgmime-source/src/xdgmimealias.c
xdgmime-source/src/xdgmimealias.h
xdgmime-source/src/xdgmimecache.c
xdgmime-source/src/xdgmimecache.h
xdgmime-source/src/xdgmimeglob.c
xdgmime-source/src/xdgmimeglob.h
xdgmime-source/src/xdgmimeicon.c
xdgmime-source/src/xdgmimeicon.h
xdgmime-source/src/xdgmimeint.c
xdgmime-source/src/xdgmimeint.h
xdgmime-source/src/xdgmimemagic.c
xdgmime-source/src/xdgmimemagic.h
xdgmime-source/src/xdgmimeparent.c
xdgmime-source/src/xdgmimeparent.h

index a1ea511499483b8b0387d40960ea2bf3478548e0,0000000000000000000000000000000000000000..9be9c50bd931e7b147cce940cda283396908f53e
mode 100644,000000..100644
--- /dev/null
@@@ -1,29 -1,0 +1,43 @@@
- build:meson:
 +image: fedora:rawhide
 +
 +variables:
 +  DEPENDENCIES: gcc
 +                gcc-c++
 +                glibc-devel
 +                make
 +                libxml2-devel
 +                glib2-devel
 +                gettext
 +                git
 +                itstool
 +                xmlto
 +                findutils
 +                gettext-devel
 +                meson
 +
++build:autotools:
 +  before_script:
 +    - dnf update -y --nogpgcheck
 +    - dnf install -y --nogpgcheck $DEPENDENCIES
 +  script:
 +    - make
 +
 +    # Compile shared-mime-info
 +    - git clone https://gitlab.freedesktop.org/xdg/shared-mime-info.git
 +    - cd shared-mime-info
++    - meson _build -Dxdgmime-path=$PWD/../
++    - ninja -C _build test
++
++build:meson:
++  before_script:
++    - dnf update -y --nogpgcheck
++    - dnf install -y --nogpgcheck $DEPENDENCIES
++  script:
 +    - meson _build
++    - ninja -C _build
++
++    # Compile shared-mime-info
++    - git clone https://gitlab.freedesktop.org/xdg/shared-mime-info.git
++    - cd shared-mime-info
++    - meson _build -Dxdgmime-path=$PWD/../_build/
 +    - ninja -C _build test
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2b16fdac09826c3d7eda25860112ffb580c8e9b6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++project('xdgmime', 'c',
++    version: '0.0',
++    default_options: ['c_std=c99', 'warning_level=1', 'debug=true'],
++    meson_version: '>=0.48.0',
++)
++
++add_project_arguments(
++    '-D_POSIX_C_SOURCE=200809L',
++    '-DXDG_PREFIX=xdg_test',
++    '-DHAVE_MMAP',
++    '-Wmissing-prototypes',
++    '-Wno-sign-compare',
++    language: 'c',
++    native: true,
++)
++
++subdir('src')
index 6c97f94df057a5090244a8dd26cda84b737b6a3a,0000000000000000000000000000000000000000..44c44f7865edc12a1cc590a1e780be5f5adb2739
mode 100644,000000..100644
--- /dev/null
@@@ -1,14 -1,0 +1,22 @@@
- CFLAGS=-Wall -Wmissing-prototypes  -Wno-sign-compare -g -DXDG_PREFIX=xdg_test -DHAVE_MMAP
++.POSIX:
++.PHONY: all clean
 +
- test-mime: xdgmime.o xdgmimeglob.o xdgmimeint.o xdgmimemagic.o xdgmimealias.o xdgmimeparent.o xdgmimecache.o xdgmimeicon.o
++C_STD = -std=c99 -D_POSIX_C_SOURCE=200809L
++ALL_CFLAGS = $(C_STD) -c -g -DXDG_PREFIX=xdg_test -DHAVE_MMAP -Wall -Wmissing-prototypes -Wno-sign-compare $(CFLAGS)
++
++.c.o:
++      $(CC) $(ALL_CFLAGS) -o $@ $<
 +
 +all: test-mime test-mime-data print-mime-data
 +
- test-mime-data: xdgmime.o xdgmimeglob.o xdgmimeint.o xdgmimemagic.o xdgmimealias.o xdgmimeparent.o xdgmimecache.o xdgmimeicon.o
++test-mime: test-mime.o xdgmime.o xdgmimeglob.o xdgmimeint.o xdgmimemagic.o xdgmimealias.o xdgmimeparent.o xdgmimecache.o xdgmimeicon.o
++      $(CC) $(LDFLAGS) -o $@ $?
 +
- print-mime-data: xdgmime.o xdgmimeglob.o xdgmimeint.o xdgmimemagic.o xdgmimealias.o xdgmimeparent.o xdgmimecache.o xdgmimeicon.o
++test-mime-data: test-mime-data.o xdgmime.o xdgmimeglob.o xdgmimeint.o xdgmimemagic.o xdgmimealias.o xdgmimeparent.o xdgmimecache.o xdgmimeicon.o
++      $(CC) $(LDFLAGS) -o $@ $?
 +
++print-mime-data: print-mime-data.o xdgmime.o xdgmimeglob.o xdgmimeint.o xdgmimemagic.o xdgmimealias.o xdgmimeparent.o xdgmimecache.o xdgmimeicon.o
++      $(CC) $(LDFLAGS) -o $@ $?
 +
 +clean:
 +      rm -f *~ *.o test-mime test-mime-data print-mime-data
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ceb407c7ce36a36ccdb3b5b23e160399dce96793
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,35 @@@
++libcommon = static_library('common',
++    'xdgmime.c',
++    'xdgmimeglob.c',
++    'xdgmimeint.c',
++    'xdgmimemagic.c',
++    'xdgmimealias.c',
++    'xdgmimeparent.c',
++    'xdgmimecache.c',
++    'xdgmimeicon.c',
++    native: true,
++)
++
++test_mime = executable('test-mime',
++    'test-mime.c',
++    link_with: libcommon,
++    native: true,
++    install: false,
++)
++meson.override_find_program('test-mime', test_mime)
++
++test_mime_data = executable('test-mime-data',
++    'test-mime-data.c',
++    link_with: libcommon,
++    native: true,
++    install: false,
++)
++meson.override_find_program('test-mime-data', test_mime_data)
++
++print_mime_data = executable('print-mime-data',
++    'print-mime-data.c',
++    link_with: libcommon,
++    native: true,
++    install: false,
++)
++meson.override_find_program('print-mime-data', print_mime_data)
index 2549e73e1f464988ae395770c679a5f9ceb7b921,0000000000000000000000000000000000000000..f51528e49a2353bb5635c7a55767514d9c9f045e
mode 100644,000000..100644
--- /dev/null
@@@ -1,187 -1,0 +1,171 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  * 
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* print-mime-data.c: debug tests for the mime implementation
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + * 
 + * Copyright (C) 2005  Red Hat, Inc.
 + * Copyright (C) 2005  Matthias Clasen <mclasen@redhat.com>
 + * Copyright (C) 2012  Bastien Nocera <hadess@hadess.net>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <libgen.h>
 +#include <sys/types.h>
 +#include <dirent.h>
 +
 +#include "xdgmime.h"
 +
 +static void
 +usage (void)
 +{
 +  printf ("usage: print-mime-data <DIR>\n\n");
 +  printf ("Prints the mime-type of every file in <DIR>, detected in various ways.\n");
 +
 +  exit (1);
 +}
 +
 +static void
 +test_by_name (const char *filename)
 +{
 +  const char *mt;
 +
 +  mt = xdg_mime_get_mime_type_from_file_name (filename);
 +
 +  printf ("\tname: %s\n", mt);
 +}
 +
 +static void
 +test_by_data (const char *filename)
 +{
 +  FILE  *file;
 +  const char *mt;
 +  int max_extent;
 +  char *data;
 +  int bytes_read;
 +  int result_prio;
 +
 +  file = fopen (filename, "r");
 +
 +  if (file == NULL)
 +    {
 +      printf ("Could not open %s\n", filename);
 +      return;
 +    }
 +
 +  max_extent = xdg_mime_get_max_buffer_extents ();
 +  data = malloc (max_extent);
 +
 +  if (data == NULL)
 +    {
 +      printf ("Failed to allocate memory for file %s\n", filename);
 +      fclose (file);
 +      return;
 +    }
 +
 +  bytes_read = fread (data, 1, max_extent, file);
 +  
 +  if (ferror (file))
 +    {
 +      printf ("Error reading file %s\n", filename);
 +
 +      free (data);
 +      fclose (file);
 +      
 +     return;
 +    }
 +
 +  mt = xdg_mime_get_mime_type_for_data (data, bytes_read, &result_prio);
 +  
 +  free (data);
 +  fclose (file);
 +
 +  printf ("\tdata: %s\n", mt);
 +}
 +
 +static void
 +test_by_file (const char *filename)
 +{
 +  const char *mt;
 +
 +  mt = xdg_mime_get_mime_type_for_file (filename, NULL);
 +
 +  printf ("\tfile: %s\n", mt);
 +}
 +
 +static int
 +is_regular (const char *filename)
 +{
 +  struct stat s;
 +
 +  if (stat (filename, &s) == 0)
 +    if (S_ISREG (s.st_mode))
 +      return 1;
 +
 +  return 0;
 +}
 +
 +static void
 +process_file (const char *dir, const char *filename)
 +{
 +  char path[1024];
 +
 +  snprintf (path, 1024, "%s/%s", dir, filename);
 +
 +  if (!is_regular (path))
 +    return;
 +
 +  printf ("%s:\n", filename);
 +
 +  test_by_name (filename);
 +  test_by_data (path);
 +  test_by_file (path);
 +
 +  printf ("\n");
 +}
 +
 +static void
 +read_from_dir (const char *path)
 +{
 +  DIR *dir;
 +  struct dirent *entry;
 +
 +  dir = opendir (path);
 +  if (!dir) {
 +    printf ("Could not open dir '%s'\n", path);
 +    return;
 +  }
 +
 +  entry = readdir (dir);
 +  while (entry != NULL) {
 +    if (entry->d_name == NULL)
 +      goto next;
 +    if (strcmp (entry->d_name, ".") == 0 ||
 +        strcmp (entry->d_name, "..") == 0)
 +      goto next;
 +    process_file (path, entry->d_name);
 +
 +next:
 +    entry = readdir (dir);
 +  }
 +
 +  closedir (dir);
 +}
 +
 +int
 +main (int argc, char *argv[])
 +{
 +  int i;
 +
 +  if (argc < 2)
 +    usage ();
 +  
 +  for (i = 1; i < argc; i++)
 +    {
 +      read_from_dir (argv[i]);
 +    }
 +
 +  return 0;
 +}
index 1dbc6368facad80529543098b9bd4d940eb4b64a,0000000000000000000000000000000000000000..14fb94e549d05ed35fece933d442a86b332a0ff1
mode 100644,000000..100644
--- /dev/null
@@@ -1,333 -1,0 +1,311 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  * 
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* test-mime-data.c: tests for the mime implementation
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + * 
 + * Copyright (C) 2005  Red Hat, Inc.
 + * Copyright (C) 2005  Matthias Clasen <mclasen@redhat.com>
 + *
-           printf ("%s, '%s' test: expected %s, got %s\n", 
-                   filename, test, mt_expected, mt);
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
++#include <strings.h>
 +#include <libgen.h>
 +
 +#include "xdgmime.h"
 +
 +static int error = 0;
 +static int total = 0;
 +static int failed = 0;
 +static int xfailed = 0;
 +static int xmatch = 0;
 +
 +static int verbose = 0;
 +
 +static void
 +check_mime_type (const char *mt,
 +               const char *mt_expected,
 +                 int         xfail,
 +               const char *test,
 +               const char *filename)
 +{
 +  total++;
 +
 +  if (strcasecmp (mt, mt_expected) != 0)
 +    {
 +      failed++;
 +      
 +      if (xfail)
 +      {
 +        xfailed++;
 +        
 +        if (verbose > 1)
 +        printf ("%s, '%s' test: expected %s, got %s (expected failure)\n", 
 +                filename, test, mt_expected, mt);
 +      }
 +      else
 +      {
 +        if (verbose > 0)
-       printf ("Could not open %s\n", path);
++          fprintf (stderr, "%s, '%s' test: expected %s, got %s\n",
++                   filename, test, mt_expected, mt);
 +      }
 +
 +    }
 +  else
 +    {
 +      if (xfail)
 +      {
 +        xmatch++;
 +
 +        if (verbose > 0)
 +        printf ("%s, '%s' test: got %s (unexpected match)\n", 
 +                filename, test, mt);
 +      }
 +    }
 +
 +}
 +
 +static void 
 +test_by_name (const char *filename,
 +            const char *mt_expected,
 +              int         xfail)
 +{
 +  const char *mt;
 +
 +  mt = xdg_mime_get_mime_type_from_file_name (filename);
 +
 +  check_mime_type (mt, mt_expected, xfail, "name", filename);
 +}
 +
 +static void 
 +test_by_data (const char *dir,
 +            const char *filename,
 +            const char *mt_expected,
 +              int         xfail)
 +{
 +  FILE  *file;
 +  const char *mt;
 +  int max_extent;
 +  char *data;
 +  int bytes_read;
 +  int result_prio;
 +  char path[1024];
 +
 +  snprintf (path, 1024, "%s/%s", dir, filename);
 +
 +  file = fopen (path, "r");
 +
 +  if (file == NULL)
 +    {
-       printf ("Failed to allocate memory for file %s\n", filename);
++      fprintf (stderr, "Could not open %s\n", path);
 +      error++;
 +
 +      return;
 +    }
 +
 +  max_extent = xdg_mime_get_max_buffer_extents ();
 +  data = malloc (max_extent);
 +
 +  if (data == NULL)
 +    {
-       printf ("Error reading file %s\n", path);
++      fprintf (stderr, "Failed to allocate memory for file %s\n", filename);
 +      error++;
 +
 +      fclose (file);
 +      return;
 +    }
 +
 +  bytes_read = fread (data, 1, max_extent, file);
 +  
 +  if (ferror (file))
 +    {
-       printf ("Could not open %s\n", filename);
++      fprintf (stderr, "Error reading file %s\n", path);
 +      error++;
 +
 +      free (data);
 +      fclose (file);
 +      
 +     return;
 +    }
 +
 +  mt = xdg_mime_get_mime_type_for_data (data, bytes_read, &result_prio);
 +  
 +  free (data);
 +  fclose (file);
 +  
 +  check_mime_type (mt, mt_expected, xfail, "data", filename);
 +}
 +
 +static void 
 +test_by_file (const char *dir,
 +            const char *filename,
 +            const char *mt_expected,
 +              int         xfail)
 +{
 +  const char *mt;
 +  char path[1024];
 +
 +  snprintf (path, 1024, "%s/%s", dir, filename);
 +
 +  mt = xdg_mime_get_mime_type_for_file (path, NULL);
 +  
 +  check_mime_type (mt, mt_expected, xfail, "file", filename);
 +}
 +
 +static void
 +test_single_file (const char *dir,
 +                const char *filename,
 +                  const char *mimetype,
 +                  int         xfail_name,
 +                  int         xfail_data,
 +                  int         xfail_file)
 +{
 +  test_by_name (filename, mimetype, xfail_name);
 +  test_by_data (dir, filename, mimetype, xfail_data);
 +  test_by_file (dir, filename, mimetype, xfail_file);
 +}
 +
 +static void
 +read_from_file (const char *filename)
 +{
 +  FILE *file;
 +  char line[255];
 +  int lineno = 0;
 +  char *testfile, *mimetype, *flags;
 +  char *rest, *space, end;
 +  char *dir, *tmp;
 +  int xfail_name, xfail_data, xfail_file;
 +  
 +  file = fopen (filename, "r");
 +  tmp = strdup (filename);
 +  dir = strdup (dirname (tmp));
 +  free (tmp);
 +
 +  if (file == NULL)
 +    {
-         printf ("Malformed line in %s:%d\n\t%s\n", filename, lineno, line);
++      fprintf (stderr, "Could not open %s\n", filename);
 +      exit (1);
 +    }
 +
 +  while (fgets (line, 255, file) != NULL)
 +    {
 +      lineno++;
 +
 +      rest = line;
 +      while (*rest == ' ') rest++;
 +      
 +      if (*rest == '#' || *rest == '\n')
 +      continue;
 +
 +      space = strchr (rest, ' ');
 +      if (!space)
 +      {
-   if (error > 0 || failed > 0)
-     {
-       printf ("%d errors, %d comparisons, %d failed",
-             error, total, failed);
-       if (xfailed > 0)
-       printf (" (%d expected)", xfailed);
-       if (xmatch > 0)
-       printf (", %d unexpected successes", xmatch);
-       printf ("\n");
-       if (xmatch > 0)
-         return 1;
-       if (xfailed == failed)
-         return 0;
-       return 1;
-     }
++        fprintf (stderr, "Malformed line in %s:%d\n\t%s\n", filename, lineno, line);
 +        continue;
 +      }
 +
 +      *space = '\0';
 +      testfile = rest;
 +
 +      rest = space + 1;
 +      while (*rest == ' ') rest++;
 +      space = rest;
 +      while (*space != ' ' && *space != '\n') space++;
 +      end = *space;
 +
 +      *space = '\0';
 +      mimetype = rest;
 +      
 +      xfail_name = 0;
 +      xfail_data = 0;
 +      xfail_file = 0;
 +
 +      if (end != '\n')
 +      {
 +        rest = space + 1;
 +        while (*rest == ' ') rest++;
 +        space = rest;
 +        while (*space != ' ' && *space != '\n') space++;
 +        end = *space;
 +        
 +        *space = '\0';
 +          flags = rest;
 +
 +          switch (strlen (flags))
 +           {
 +             default:
 +               printf ("%s.%d: Extra flags are ignored\n", filename, lineno);
 +               /* Fall thu  */
 +             case 3:
 +               if (flags[2] == 'x')
 +                 xfail_file = 1;
 +               /* Fall thu  */
 +             case 2:
 +               if (flags[1] == 'x')
 +                 xfail_data = 1;
 +               /* Fall thu  */
 +             case 1: 
 +               if (flags[0] == 'x')
 +                 xfail_name = 1;
 +               break;
 +             case 0: ;
 +               /* Should not happen */
 +          }
 +        }
 +
 +      test_single_file (dir, testfile, mimetype, 
 +                        xfail_name, xfail_data, xfail_file);
 +    }
 +
 +  fclose (file);
 +
 +  free (dir);
 +}
 +
 +static void
 +usage (void)
 +{
 +  printf ("usage: test-mime-data <FILE>\n\n");
 +  printf ("Tests the mime system.\n");
 +  printf ("Testcases are specified in the following format:\n\n");
 +  printf ("# comment\n");
 +  printf ("<filename1> <mimetype> [<flags>]\n");
 +  printf ("<filename2> <mimetype> [<flags>]\n");
 +  printf ("...\n\n");
 +  printf ("Where an 'x' in the 1st, 2nd or 3rd position in <flags>\n");
 +  printf ("indicates an expected failure when determining the\n");
 +  printf ("mimetype by name, data or file.\n");
 +
 +  exit (1);
 +}
 +
 +int 
 +main (int argc, char *argv[])
 +{
 +  int i;
 +
 +  if (argc < 2)
 +    usage ();
 +  
 +  for (i = 1; i < argc; i++)
 +    {
 +      if (strcmp (argv[i], "-v") == 0)
 +      verbose++;
 +      else
 +      read_from_file (argv[i]);
 +    }
 +  
++  printf ("%d errors, %d comparisons, %d failed",
++          error, total, failed);
++  if (xfailed > 0)
++    printf (" (%d expected)", xfailed);
++  if (xmatch > 0)
++    printf (", %d unexpected successes", xmatch);
++  printf ("\n");
++
++  if (error > 0 || xmatch > 0 || failed != xfailed)
++    return 1;
 +  return 0;
 +}
index e68222a31dd4153f4605d2051be4684038be3fd2,0000000000000000000000000000000000000000..a194871be1a7997cdf527d95337109d591699771
mode 100644,000000..100644
--- /dev/null
@@@ -1,201 -1,0 +1,186 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* 
 + * Copyright (C) 2003,2004  Red Hat, Inc.
 + * Copyright (C) 2003,2004  Jonathan Blandford <jrb@alum.mit.edu>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +#include "xdgmime.h"
 +#include "xdgmimeglob.h"
 +#include <string.h>
++#include <strings.h>
 +#include <stdio.h>
 +
 +
 +static void
 +test_individual_glob (const char  *glob,
 +                    XdgGlobType  expected_type)
 +{
 +  XdgGlobType test_type;
 +
 +  test_type = _xdg_glob_determine_type (glob);
 +  if (test_type != expected_type)
 +    {
 +      printf ("Test Failed: %s is of type %s, but %s is expected\n",
 +            glob,
 +            ((test_type == XDG_GLOB_LITERAL)?"XDG_GLOB_LITERAL":
 +             ((test_type == XDG_GLOB_SIMPLE)?"XDG_GLOB_SIMPLE":"XDG_GLOB_FULL")),
 +            ((expected_type == XDG_GLOB_LITERAL)?"XDG_GLOB_LITERAL":
 +             ((expected_type == XDG_GLOB_SIMPLE)?"XDG_GLOB_SIMPLE":"XDG_GLOB_COMPLEX")));
 +      exit (1);
 +    }
 +}
 +
 +static void
 +test_glob_type (void)
 +{
 +  test_individual_glob ("*.gif", XDG_GLOB_SIMPLE);
 +  test_individual_glob ("Foo*.gif", XDG_GLOB_FULL);
 +  test_individual_glob ("*[4].gif", XDG_GLOB_FULL);
 +  test_individual_glob ("Makefile", XDG_GLOB_LITERAL);
 +  test_individual_glob ("sldkfjvlsdf\\\\slkdjf", XDG_GLOB_FULL);
 +  test_individual_glob ("tree.[ch]", XDG_GLOB_FULL);
 +}
 +
 +static void
 +test_alias (const char *mime_a,
 +          const char *mime_b,
 +          int         expected)
 +{
 +  int actual;
 +
 +  actual = xdg_mime_mime_type_equal (mime_a, mime_b);
 +
 +  if (actual != expected)
 +    {
 +      printf ("Test Failed: %s is %s to %s\n", 
 +            mime_a, actual ? "equal" : "not equal", mime_b);
 +      exit (1);
 +    }
 +}
 +
 +static void
 +test_aliasing (void)
 +{
 +  test_alias ("application/wordperfect", "application/vnd.wordperfect", 1);
 +  test_alias ("application/x-gnome-app-info", "application/x-desktop", 1);
 +  test_alias ("application/x-wordperfect", "application/vnd.wordperfect", 1);
 +  test_alias ("application/x-wordperfect", "audio/x-midi", 0);
 +  test_alias ("/", "vnd/vnd", 0);
 +  test_alias ("application/octet-stream", "text/plain", 0);
 +  test_alias ("text/plain", "text/*", 0);
 +}
 +
 +static void
 +test_subclass (const char *mime_a,
 +             const char *mime_b,
 +             int         expected)
 +{
 +  int actual;
 +
 +  actual = xdg_mime_mime_type_subclass (mime_a, mime_b);
 +
 +  if (actual != expected)
 +    {
 +      printf ("Test Failed: %s is %s of %s\n", 
 +            mime_a, actual ? "subclass" : "not subclass", mime_b);
 +      exit (1);
 +    }
 +}
 +
 +static void
 +test_subclassing (void)
 +{
 +  test_subclass ("application/rtf", "text/plain", 1);
 +  test_subclass ("message/news", "text/plain", 1);
 +  test_subclass ("message/news", "message/*", 1);
 +  test_subclass ("message/news", "text/*", 1);
 +  test_subclass ("message/news", "application/octet-stream", 1);
 +  test_subclass ("application/rtf", "application/octet-stream", 1);
 +  test_subclass ("application/x-gnome-app-info", "text/plain", 1);
 +  test_subclass ("image/x-djvu", "image/vnd.djvu", 1);
 +  test_subclass ("image/vnd.djvu", "image/x-djvu", 1);
 +  test_subclass ("image/vnd.djvu", "text/plain", 0);
 +  test_subclass ("image/vnd.djvu", "text/*", 0);
 +  test_subclass ("text/*", "text/plain", 1);
 +}
 +
 +static void
 +test_one_match (const char *filename, const char *expected)
 +{
 +  const char *actual;
 +
 +  actual = xdg_mime_get_mime_type_from_file_name (filename);
 +
 +  if (strcasecmp (actual, expected) != 0)
 +    {
 +      printf ("Test Failed: mime type of %s is %s, expected %s\n", 
 +            filename, actual, expected);
 +      exit (1);
 +    }
 +}
 +
 +static void
 +test_matches (void)
 +{
 +  test_one_match ("foo.bar.epub", "application/epub+zip");
 +  test_one_match ("core", "application/x-core");
 +  test_one_match ("README.in", "text/x-readme");
 +  test_one_match ("README.gz", "application/gzip");
 +  test_one_match ("blabla.cs", "text/x-csharp");
 +  test_one_match ("blabla.f90", "text/x-fortran");
 +  test_one_match ("blabla.F95", "text/x-fortran");
 +  test_one_match ("tarball.tar.gz", "application/x-compressed-tar");
 +  test_one_match ("file.gz", "application/gzip");
 +  test_one_match ("file.tar.lzo", "application/x-tzo");
 +  test_one_match ("file.lzo", "application/x-lzop");
 +}
 +
 +static void
 +test_one_icon (const char *mimetype, const char *expected)
 +{
 +  const char *actual;
 +
 +  actual = xdg_mime_get_generic_icon (mimetype);
 +
 +  if (actual != expected && (actual == NULL || strcmp (actual, expected) != 0)) 
 +    {
 +      printf ("Test Failed: icon of %s is %s, expected %s\n", 
 +             mimetype, actual, expected);
 +      exit (1);
 +    }
 +}
 +
 +static void
 +test_icons (void)
 +{
 +  test_one_icon ("application/x-font-ttx", "font-x-generic");
 +  test_one_icon ("application/mathematica", "x-office-document");
 +  test_one_icon ("text/plain", NULL);
 +}
 +
 +int
 +main (int argc, char *argv[])
 +{
 +  const char *result;
 +  const char *file_name;
 +  int i;
 +
 +  test_glob_type ();
 +  test_aliasing ();
 +  test_subclassing ();
 +  test_matches ();
 +  test_icons ();
 +
 +  for (i = 1; i < argc; i++)
 +    {
 +      file_name = argv[i];
 +      result = xdg_mime_get_mime_type_for_file (file_name, NULL);
 +      printf ("File \"%s\" has a mime-type of %s\n", file_name, result);
 +    }
 +
 +#if 0
 +  xdg_mime_dump ();
 +#endif
 +  return 0;
 +}
 +     
index 90a0ed0d56707bb1ae694568a17df3aac3aec008,0000000000000000000000000000000000000000..b6406518863eb90063c7aba25b5eb8244402455f
mode 100644,000000..100644
--- /dev/null
@@@ -1,945 -1,0 +1,998 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  * 
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmime.c: XDG Mime Spec mime resolver.  Based on version 0.11 of the spec.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + * 
 + * Copyright (C) 2003,2004  Red Hat, Inc.
 + * Copyright (C) 2003,2004  Jonathan Blandford <jrb@alum.mit.edu>
 + *
-   file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
-   strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "xdgmime.h"
 +#include "xdgmimeint.h"
 +#include "xdgmimeglob.h"
 +#include "xdgmimemagic.h"
 +#include "xdgmimealias.h"
 +#include "xdgmimeicon.h"
 +#include "xdgmimeparent.h"
 +#include "xdgmimecache.h"
 +#include <stdio.h>
 +#include <string.h>
 +#include <sys/stat.h>
 +#include <sys/types.h>
 +#include <sys/time.h>
 +#include <unistd.h>
 +#include <assert.h>
 +
++#ifndef S_ISREG
++#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
++#endif
++
 +typedef struct XdgDirTimeList XdgDirTimeList;
 +typedef struct XdgCallbackList XdgCallbackList;
 +
 +static int need_reread = TRUE;
 +static time_t last_stat_time = 0;
 +
 +static XdgGlobHash *global_hash = NULL;
 +static XdgMimeMagic *global_magic = NULL;
 +static XdgAliasList *alias_list = NULL;
 +static XdgParentList *parent_list = NULL;
 +static XdgDirTimeList *dir_time_list = NULL;
 +static XdgCallbackList *callback_list = NULL;
 +static XdgIconList *icon_list = NULL;
 +static XdgIconList *generic_icon_list = NULL;
 +
++static char **xdg_dirs = NULL;  /* NULL terminated */
++
 +XdgMimeCache **_caches = NULL;
 +static int n_caches = 0;
 +
 +const char xdg_mime_type_unknown[] = "application/octet-stream";
 +const char xdg_mime_type_empty[] = "application/x-zerosize";
 +const char xdg_mime_type_textplain[] = "text/plain";
 +
 +
 +enum
 +{
 +  XDG_CHECKED_UNCHECKED,
 +  XDG_CHECKED_VALID,
 +  XDG_CHECKED_INVALID
 +};
 +
 +struct XdgDirTimeList
 +{
 +  time_t mtime;
 +  char *directory_name;
 +  int checked;
 +  XdgDirTimeList *next;
 +};
 +
 +struct XdgCallbackList
 +{
 +  XdgCallbackList *next;
 +  XdgCallbackList *prev;
 +  int              callback_id;
 +  XdgMimeCallback  callback;
 +  void            *data;
 +  XdgMimeDestroy   destroy;
 +};
 +
 +/* Function called by xdg_run_command_on_dirs.  If it returns TRUE, further
 + * directories aren't looked at */
 +typedef int (*XdgDirectoryFunc) (const char *directory,
 +                               void       *user_data);
 +
 +static void
 +xdg_dir_time_list_add (char   *file_name, 
 +                     time_t  mtime)
 +{
 +  XdgDirTimeList *list;
 +
 +  for (list = dir_time_list; list; list = list->next) 
 +    {
 +      if (strcmp (list->directory_name, file_name) == 0)
 +        {
 +          free (file_name);
 +          return;
 +        }
 +    }
 +  
 +  list = calloc (1, sizeof (XdgDirTimeList));
 +  list->checked = XDG_CHECKED_UNCHECKED;
 +  list->directory_name = file_name;
 +  list->mtime = mtime;
 +  list->next = dir_time_list;
 +  dir_time_list = list;
 +}
 + 
 +static void
 +xdg_dir_time_list_free (XdgDirTimeList *list)
 +{
 +  XdgDirTimeList *next;
 +
 +  while (list)
 +    {
 +      next = list->next;
 +      free (list->directory_name);
 +      free (list);
 +      list = next;
 +    }
 +}
 +
 +static int
 +xdg_mime_init_from_directory (const char *directory,
 +                              void       *user_data)
 +{
 +  char *file_name;
 +  struct stat st;
 +
 +  assert (directory != NULL);
 +
-   file_name = malloc (strlen (directory) + strlen ("/mime/globs2") + 1);
-   strcpy (file_name, directory); strcat (file_name, "/mime/globs2");
++  file_name = malloc (strlen (directory) + strlen ("/mime.cache") + 1);
++  strcpy (file_name, directory); strcat (file_name, "/mime.cache");
 +  if (stat (file_name, &st) == 0)
 +    {
 +      XdgMimeCache *cache = _xdg_mime_cache_new_from_file (file_name);
 +
 +      if (cache != NULL)
 +      {
 +        xdg_dir_time_list_add (file_name, st.st_mtime);
 +
 +        _caches = realloc (_caches, sizeof (XdgMimeCache *) * (n_caches + 2));
 +        _caches[n_caches] = cache;
 +          _caches[n_caches + 1] = NULL;
 +        n_caches++;
 +
 +        return FALSE;
 +      }
 +    }
 +  free (file_name);
 +
-       file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
-       strcpy (file_name, directory); strcat (file_name, "/mime/globs");
++  file_name = malloc (strlen (directory) + strlen ("/globs2") + 1);
++  strcpy (file_name, directory); strcat (file_name, "/globs2");
 +  if (stat (file_name, &st) == 0)
 +    {
 +      _xdg_mime_glob_read_from_file (global_hash, file_name, TRUE);
 +      xdg_dir_time_list_add (file_name, st.st_mtime);
 +    }
 +  else
 +    {
 +      free (file_name);
-   file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
-   strcpy (file_name, directory); strcat (file_name, "/mime/magic");
++      file_name = malloc (strlen (directory) + strlen ("/globs") + 1);
++      strcpy (file_name, directory); strcat (file_name, "/globs");
 +      if (stat (file_name, &st) == 0)
 +        {
 +          _xdg_mime_glob_read_from_file (global_hash, file_name, FALSE);
 +          xdg_dir_time_list_add (file_name, st.st_mtime);
 +        }
 +      else
 +        {
 +          free (file_name);
 +        }
 +    }
 +
-   file_name = malloc (strlen (directory) + strlen ("/mime/aliases") + 1);
-   strcpy (file_name, directory); strcat (file_name, "/mime/aliases");
++  file_name = malloc (strlen (directory) + strlen ("/magic") + 1);
++  strcpy (file_name, directory); strcat (file_name, "/magic");
 +  if (stat (file_name, &st) == 0)
 +    {
 +      _xdg_mime_magic_read_from_file (global_magic, file_name);
 +      xdg_dir_time_list_add (file_name, st.st_mtime);
 +    }
 +  else
 +    {
 +      free (file_name);
 +    }
 +
-   file_name = malloc (strlen (directory) + strlen ("/mime/subclasses") + 1);
-   strcpy (file_name, directory); strcat (file_name, "/mime/subclasses");
++  file_name = malloc (strlen (directory) + strlen ("/aliases") + 1);
++  strcpy (file_name, directory); strcat (file_name, "/aliases");
 +  _xdg_mime_alias_read_from_file (alias_list, file_name);
 +  free (file_name);
 +
-   file_name = malloc (strlen (directory) + strlen ("/mime/icons") + 1);
-   strcpy (file_name, directory); strcat (file_name, "/mime/icons");
++  file_name = malloc (strlen (directory) + strlen ("/subclasses") + 1);
++  strcpy (file_name, directory); strcat (file_name, "/subclasses");
 +  _xdg_mime_parent_read_from_file (parent_list, file_name);
 +  free (file_name);
 +
-   file_name = malloc (strlen (directory) + strlen ("/mime/generic-icons") + 1);
-   strcpy (file_name, directory); strcat (file_name, "/mime/generic-icons");
++  file_name = malloc (strlen (directory) + strlen ("/icons") + 1);
++  strcpy (file_name, directory); strcat (file_name, "/icons");
 +  _xdg_mime_icon_read_from_file (icon_list, file_name);
 +  free (file_name);
 +
- /* Runs a command on all the directories in the search path */
++  file_name = malloc (strlen (directory) + strlen ("/generic-icons") + 1);
++  strcpy (file_name, directory); strcat (file_name, "/generic-icons");
 +  _xdg_mime_icon_read_from_file (generic_icon_list, file_name);
 +  free (file_name);
 +
 +  return FALSE; /* Keep processing */
 +}
 +
- xdg_run_command_on_dirs (XdgDirectoryFunc  func,
-                        void             *user_data)
++/* Set @xdg_dirs from the environment. It must not have been set already. */
 +static void
-   const char *xdg_data_home;
-   const char *xdg_data_dirs;
++xdg_init_dirs (void)
 +{
-   if (xdg_data_home)
++  const char *xdg_data_home, *home, *xdg_data_dirs;
 +  const char *ptr;
++  size_t n_dirs = 0;
++  size_t i, current_dir;
++
++  assert (xdg_dirs == NULL);
 +
 +  xdg_data_home = getenv ("XDG_DATA_HOME");
-       if ((func) (xdg_data_home, user_data))
-       return;
++  home = getenv ("HOME");
++  xdg_data_dirs = getenv ("XDG_DATA_DIRS");
++
++  if (xdg_data_dirs == NULL)
++    xdg_data_dirs = "/usr/local/share/:/usr/share/";
++
++  /* Work out how many dirs we’re dealing with. */
++  if (xdg_data_home != NULL || home != NULL)
++    n_dirs++;
++  n_dirs++;  /* initial entry in @xdg_data_dirs */
++  for (i = 0; xdg_data_dirs[i] != '\0'; i++)
++    if (xdg_data_dirs[i] == ':')
++      n_dirs++;
++
++  xdg_dirs = calloc (n_dirs + 1  /* NULL terminator */, sizeof (char *));
++  current_dir = 0;
++
++  /* $XDG_DATA_HOME */
++  if (xdg_data_home != NULL)
 +    {
-   else
++      char *mime_subdir;
++
++      mime_subdir = malloc (strlen (xdg_data_home) + strlen ("/mime/") + 1);
++      strcpy (mime_subdir, xdg_data_home);
++      strcat (mime_subdir, "/mime/");
++
++      xdg_dirs[current_dir++] = mime_subdir;
 +    }
-       const char *home;
++  else if (home != NULL)
 +    {
-       home = getenv ("HOME");
-       if (home != NULL)
-       {
-         char *guessed_xdg_home;
-         int stop_processing;
-         guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/") + 1);
-         strcpy (guessed_xdg_home, home);
-         strcat (guessed_xdg_home, "/.local/share/");
-         stop_processing = (func) (guessed_xdg_home, user_data);
-         free (guessed_xdg_home);
++      char *guessed_xdg_home;
 +
-         if (stop_processing)
-           return;
-       }
++      guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/mime/") + 1);
++      strcpy (guessed_xdg_home, home);
++      strcat (guessed_xdg_home, "/.local/share/mime/");
 +
-   xdg_data_dirs = getenv ("XDG_DATA_DIRS");
-   if (xdg_data_dirs == NULL)
-     xdg_data_dirs = "/usr/local/share/:/usr/share/";
++      xdg_dirs[current_dir++] = guessed_xdg_home;
 +    }
 +
-       int stop_processing;
++  /* $XDG_DATA_DIRS */
 +  ptr = xdg_data_dirs;
 +
 +  while (*ptr != '\000')
 +    {
 +      const char *end_ptr;
 +      char *dir;
 +      int len;
-       end_ptr ++;
 +
 +      end_ptr = ptr;
 +      while (*end_ptr != ':' && *end_ptr != '\000')
-       {
-         ptr++;
-         continue;
-       }
++        end_ptr ++;
 +
 +      if (end_ptr == ptr)
-       len = end_ptr - ptr;
++        {
++          ptr++;
++          continue;
++        }
 +
 +      if (*end_ptr == ':')
-       len = end_ptr - ptr + 1;
-       dir = malloc (len + 1);
++        len = end_ptr - ptr;
 +      else
-       stop_processing = (func) (dir, user_data);
-       free (dir);
++        len = end_ptr - ptr + 1;
++      dir = malloc (len + strlen ("/mime/") + 1);
 +      strncpy (dir, ptr, len);
 +      dir[len] = '\0';
-       if (stop_processing)
-       return;
++      strcat (dir, "/mime/");
 +
-   file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
-   strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
++      xdg_dirs[current_dir++] = dir;
 +
 +      ptr = end_ptr;
 +    }
++
++  /* NULL terminator */
++  xdg_dirs[current_dir] = NULL;
++
++  need_reread = TRUE;
++}
++
++/* Runs a command on all the directories in the search path (@xdg_dirs). */
++static void
++xdg_run_command_on_dirs (XdgDirectoryFunc  func,
++                         void             *user_data)
++{
++  size_t i;
++
++  if (xdg_dirs == NULL)
++    xdg_init_dirs ();
++
++  for (i = 0; xdg_dirs[i] != NULL; i++)
++    {
++      if ((func) (xdg_dirs[i], user_data))
++        return;
++    }
++}
++
++/* Allows the calling code to override the directories used by xdgmime, without
++ * having to change environment variables in a running process (which is not
++ * thread safe). This is intended to be used by tests. The changes will be
++ * picked up by xdg_mime_init() next time public API is called.
++ *
++ * This will set @xdg_dirs. Directories in @dirs must be complete, including
++ * the conventional `/mime` subdirectory. This is to allow tests to override
++ * them without the need to create a subdirectory. */
++void
++xdg_mime_set_dirs (const char * const *dirs)
++{
++  size_t i;
++
++  for (i = 0; xdg_dirs != NULL && xdg_dirs[i] != NULL; i++)
++    free (xdg_dirs[i]);
++  free (xdg_dirs);
++  xdg_dirs = NULL;
++
++  if (dirs != NULL)
++    {
++      for (i = 0; dirs[i] != NULL; i++);
++      xdg_dirs = calloc (i + 1  /* NULL terminator */, sizeof (char*));
++      for (i = 0; dirs[i] != NULL; i++)
++        xdg_dirs[i] = strdup (dirs[i]);
++      xdg_dirs[i] = NULL;
++    }
++
++  need_reread = TRUE;
 +}
 +
 +/* Checks file_path to make sure it has the same mtime as last time it was
 + * checked.  If it has a different mtime, or if the file doesn't exist, it
 + * returns FALSE.
 + *
 + * FIXME: This doesn't protect against permission changes.
 + */
 +static int
 +xdg_check_file (const char *file_path,
 +                int        *exists)
 +{
 +  struct stat st;
 +
 +  /* If the file exists */
 +  if (stat (file_path, &st) == 0)
 +    {
 +      XdgDirTimeList *list;
 +
 +      if (exists)
 +        *exists = TRUE;
 +
 +      for (list = dir_time_list; list; list = list->next)
 +      {
 +        if (! strcmp (list->directory_name, file_path))
 +          {
 +            if (st.st_mtime == list->mtime)
 +              list->checked = XDG_CHECKED_VALID;
 +            else 
 +              list->checked = XDG_CHECKED_INVALID;
 +
 +            return (list->checked != XDG_CHECKED_VALID);
 +          }
 +      }
 +      return TRUE;
 +    }
 +
 +  if (exists)
 +    *exists = FALSE;
 +
 +  return FALSE;
 +}
 +
 +static int
 +xdg_check_dir (const char *directory,
 +             void       *user_data)
 +{
 +  int invalid, exists;
 +  char *file_name;
 +  int* invalid_dir_list = user_data;
 +
 +  assert (directory != NULL);
 +
 +  /* Check the mime.cache file */
-   file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
-   strcpy (file_name, directory); strcat (file_name, "/mime/globs");
++  file_name = malloc (strlen (directory) + strlen ("/mime.cache") + 1);
++  strcpy (file_name, directory); strcat (file_name, "/mime.cache");
 +  invalid = xdg_check_file (file_name, &exists);
 +  free (file_name);
 +  if (invalid)
 +    {
 +      *invalid_dir_list = TRUE;
 +      return TRUE;
 +    }
 +  else if (exists)
 +    {
 +      return FALSE;
 +    }
 +
 +  /* Check the globs file */
-   file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
-   strcpy (file_name, directory); strcat (file_name, "/mime/magic");
++  file_name = malloc (strlen (directory) + strlen ("/globs") + 1);
++  strcpy (file_name, directory); strcat (file_name, "/globs");
 +  invalid = xdg_check_file (file_name, NULL);
 +  free (file_name);
 +  if (invalid)
 +    {
 +      *invalid_dir_list = TRUE;
 +      return TRUE;
 +    }
 +
 +  /* Check the magic file */
++  file_name = malloc (strlen (directory) + strlen ("/magic") + 1);
++  strcpy (file_name, directory); strcat (file_name, "/magic");
 +  invalid = xdg_check_file (file_name, NULL);
 +  free (file_name);
 +  if (invalid)
 +    {
 +      *invalid_dir_list = TRUE;
 +      return TRUE;
 +    }
 +
 +  return FALSE; /* Keep processing */
 +}
 +
 +/* Walks through all the mime files stat()ing them to see if they've changed.
 + * Returns TRUE if they have. */
 +static int
 +xdg_check_dirs (void)
 +{
 +  XdgDirTimeList *list;
 +  int invalid_dir_list = FALSE;
 +
 +  for (list = dir_time_list; list; list = list->next)
 +    list->checked = XDG_CHECKED_UNCHECKED;
 +
 +  xdg_run_command_on_dirs (xdg_check_dir, &invalid_dir_list);
 +
 +  if (invalid_dir_list)
 +    return TRUE;
 +
 +  for (list = dir_time_list; list; list = list->next)
 +    {
 +      if (list->checked != XDG_CHECKED_VALID)
 +      return TRUE;
 +    }
 +
 +  return FALSE;
 +}
 +
 +/* We want to avoid stat()ing on every single mime call, so we only look for
 + * newer files every 5 seconds.  This will return TRUE if we need to reread the
 + * mime data from disk.
 + */
 +static int
 +xdg_check_time_and_dirs (void)
 +{
 +  struct timeval tv;
 +  time_t current_time;
 +  int retval = FALSE;
 +
 +  gettimeofday (&tv, NULL);
 +  current_time = tv.tv_sec;
 +
 +  if (current_time >= last_stat_time + 5)
 +    {
 +      retval = xdg_check_dirs ();
 +      last_stat_time = current_time;
 +    }
 +
 +  return retval;
 +}
 +
 +/* Called in every public function.  It reloads the hash function if need be.
 + */
 +static void
 +xdg_mime_init (void)
 +{
 +  if (xdg_check_time_and_dirs ())
 +    {
 +      xdg_mime_shutdown ();
 +    }
 +
 +  if (need_reread)
 +    {
 +      global_hash = _xdg_glob_hash_new ();
 +      global_magic = _xdg_mime_magic_new ();
 +      alias_list = _xdg_mime_alias_list_new ();
 +      parent_list = _xdg_mime_parent_list_new ();
 +      icon_list = _xdg_mime_icon_list_new ();
 +      generic_icon_list = _xdg_mime_icon_list_new ();
 +
 +      xdg_run_command_on_dirs (xdg_mime_init_from_directory, NULL);
 +
 +      need_reread = FALSE;
 +    }
 +}
 +
 +const char *
 +xdg_mime_get_mime_type_for_data (const void *data,
 +                               size_t      len,
 +                               int        *result_prio)
 +{
 +  const char *mime_type;
 +
 +  if (len == 0)
 +    {
 +      if (result_prio != NULL)
 +        *result_prio = 100;
 +      return XDG_MIME_TYPE_EMPTY;
 +    }
 +
 +  xdg_mime_init ();
 +
 +  if (_caches)
 +    mime_type = _xdg_mime_cache_get_mime_type_for_data (data, len, result_prio);
 +  else
 +    mime_type = _xdg_mime_magic_lookup_data (global_magic, data, len, result_prio, NULL, 0);
 +
 +  if (mime_type)
 +    return mime_type;
 +
 +  return _xdg_binary_or_text_fallback(data, len);
 +}
 +
 +const char *
 +xdg_mime_get_mime_type_for_file (const char  *file_name,
 +                                 struct stat *statbuf)
 +{
 +  const char *mime_type;
 +  /* currently, only a few globs occur twice, and none
 +   * more often, so 5 seems plenty.
 +   */
 +  const char *mime_types[5];
 +  FILE *file;
 +  unsigned char *data;
 +  int max_extent;
 +  int bytes_read;
 +  struct stat buf;
 +  const char *base_name;
 +  int n;
 +
 +  if (file_name == NULL)
 +    return NULL;
 +  if (! _xdg_utf8_validate (file_name))
 +    return NULL;
 +
 +  xdg_mime_init ();
 +
 +  if (_caches)
 +    return _xdg_mime_cache_get_mime_type_for_file (file_name, statbuf);
 +
 +  base_name = _xdg_get_base_name (file_name);
 +  n = _xdg_glob_hash_lookup_file_name (global_hash, base_name, mime_types, 5);
 +
 +  if (n == 1)
 +    return mime_types[0];
 +
 +  if (!statbuf)
 +    {
 +      if (stat (file_name, &buf) != 0)
 +      return XDG_MIME_TYPE_UNKNOWN;
 +
 +      statbuf = &buf;
 +    }
 +
 +  if (!S_ISREG (statbuf->st_mode))
 +    return XDG_MIME_TYPE_UNKNOWN;
 +
 +  /* FIXME: Need to make sure that max_extent isn't totally broken.  This could
 +   * be large and need getting from a stream instead of just reading it all
 +   * in. */
 +  max_extent = _xdg_mime_magic_get_buffer_extents (global_magic);
 +  data = malloc (max_extent);
 +  if (data == NULL)
 +    return XDG_MIME_TYPE_UNKNOWN;
 +        
 +  file = fopen (file_name, "r");
 +  if (file == NULL)
 +    {
 +      free (data);
 +      return XDG_MIME_TYPE_UNKNOWN;
 +    }
 +
 +  bytes_read = fread (data, 1, max_extent, file);
 +  if (ferror (file))
 +    {
 +      free (data);
 +      fclose (file);
 +      return XDG_MIME_TYPE_UNKNOWN;
 +    }
 +
 +  mime_type = _xdg_mime_magic_lookup_data (global_magic, data, bytes_read, NULL,
 +                                         mime_types, n);
 +
 +  if (!mime_type)
 +    mime_type = _xdg_binary_or_text_fallback (data, bytes_read);
 +
 +  free (data);
 +  fclose (file);
 +
 +  return mime_type;
 +}
 +
 +const char *
 +xdg_mime_get_mime_type_from_file_name (const char *file_name)
 +{
 +  const char *mime_type;
 +
 +  xdg_mime_init ();
 +
 +  if (_caches)
 +    return _xdg_mime_cache_get_mime_type_from_file_name (file_name);
 +
 +  if (_xdg_glob_hash_lookup_file_name (global_hash, file_name, &mime_type, 1))
 +    return mime_type;
 +  else
 +    return XDG_MIME_TYPE_UNKNOWN;
 +}
 +
 +int
 +xdg_mime_get_mime_types_from_file_name (const char *file_name,
 +                                      const char  *mime_types[],
 +                                      int          n_mime_types)
 +{
 +  xdg_mime_init ();
 +  
 +  if (_caches)
 +    return _xdg_mime_cache_get_mime_types_from_file_name (file_name, mime_types, n_mime_types);
 +  
 +  return _xdg_glob_hash_lookup_file_name (global_hash, file_name, mime_types, n_mime_types);
 +}
 +
 +int
 +xdg_mime_is_valid_mime_type (const char *mime_type)
 +{
 +  /* FIXME: We should make this a better test
 +   */
 +  return _xdg_utf8_validate (mime_type);
 +}
 +
 +void
 +xdg_mime_shutdown (void)
 +{
 +  XdgCallbackList *list;
 +
 +  /* FIXME: Need to make this (and the whole library) thread safe */
 +  if (dir_time_list)
 +    {
 +      xdg_dir_time_list_free (dir_time_list);
 +      dir_time_list = NULL;
 +    }
 +      
 +  if (global_hash)
 +    {
 +      _xdg_glob_hash_free (global_hash);
 +      global_hash = NULL;
 +    }
 +  if (global_magic)
 +    {
 +      _xdg_mime_magic_free (global_magic);
 +      global_magic = NULL;
 +    }
 +
 +  if (alias_list)
 +    {
 +      _xdg_mime_alias_list_free (alias_list);
 +      alias_list = NULL;
 +    }
 +
 +  if (parent_list)
 +    {
 +      _xdg_mime_parent_list_free (parent_list);
 +      parent_list = NULL;
 +    }
 +
 +  if (icon_list)
 +    {
 +      _xdg_mime_icon_list_free (icon_list);
 +      icon_list = NULL;
 +    }
 +
 +  if (generic_icon_list)
 +    {
 +      _xdg_mime_icon_list_free (generic_icon_list);
 +      generic_icon_list = NULL;
 +    }
 +  
 +  if (_caches)
 +    {
 +      int i;
 +
 +      for (i = 0; i < n_caches; i++)
 +        _xdg_mime_cache_unref (_caches[i]);
 +      free (_caches);
 +      _caches = NULL;
 +      n_caches = 0;
 +    }
 +
 +  for (list = callback_list; list; list = list->next)
 +    (list->callback) (list->data);
 +
 +  need_reread = TRUE;
 +}
 +
 +int
 +xdg_mime_get_max_buffer_extents (void)
 +{
 +  xdg_mime_init ();
 +  
 +  if (_caches)
 +    return _xdg_mime_cache_get_max_buffer_extents ();
 +
 +  return _xdg_mime_magic_get_buffer_extents (global_magic);
 +}
 +
 +const char *
 +_xdg_mime_unalias_mime_type (const char *mime_type)
 +{
 +  const char *lookup;
 +
 +  if (_caches)
 +    return _xdg_mime_cache_unalias_mime_type (mime_type);
 +
 +  if ((lookup = _xdg_mime_alias_list_lookup (alias_list, mime_type)) != NULL)
 +    return lookup;
 +
 +  return mime_type;
 +}
 +
 +const char *
 +xdg_mime_unalias_mime_type (const char *mime_type)
 +{
 +  xdg_mime_init ();
 +
 +  return _xdg_mime_unalias_mime_type (mime_type);
 +}
 +
 +int
 +_xdg_mime_mime_type_equal (const char *mime_a,
 +                         const char *mime_b)
 +{
 +  const char *unalias_a, *unalias_b;
 +
 +  unalias_a = _xdg_mime_unalias_mime_type (mime_a);
 +  unalias_b = _xdg_mime_unalias_mime_type (mime_b);
 +
 +  if (strcmp (unalias_a, unalias_b) == 0)
 +    return 1;
 +
 +  return 0;
 +}
 +
 +int
 +xdg_mime_mime_type_equal (const char *mime_a,
 +                        const char *mime_b)
 +{
 +  xdg_mime_init ();
 +
 +  return _xdg_mime_mime_type_equal (mime_a, mime_b);
 +}
 +
 +int
 +xdg_mime_media_type_equal (const char *mime_a,
 +                         const char *mime_b)
 +{
 +  char *sep;
 +
 +  sep = strchr (mime_a, '/');
 +  
 +  if (sep && strncmp (mime_a, mime_b, sep - mime_a + 1) == 0)
 +    return 1;
 +
 +  return 0;
 +}
 +
 +#if 1
 +static int
 +ends_with (const char *str,
 +           const char *suffix)
 +{
 +  int length;
 +  int suffix_length;
 +
 +  length = strlen (str);
 +  suffix_length = strlen (suffix);
 +  if (length < suffix_length)
 +    return 0;
 +
 +  if (strcmp (str + length - suffix_length, suffix) == 0)
 +    return 1;
 +
 +  return 0;
 +}
 +
 +static int
 +xdg_mime_is_super_type (const char *mime)
 +{
 +  return ends_with (mime, "/*");
 +}
 +#endif
 +
 +int
 +_xdg_mime_mime_type_subclass (const char *mime,
 +                            const char *base)
 +{
 +  const char *umime, *ubase;
 +  const char **parents;
 +
 +  if (_caches)
 +    return _xdg_mime_cache_mime_type_subclass (mime, base);
 +
 +  umime = _xdg_mime_unalias_mime_type (mime);
 +  ubase = _xdg_mime_unalias_mime_type (base);
 +
 +  if (strcmp (umime, ubase) == 0)
 +    return 1;
 +
 +#if 1  
 +  /* Handle supertypes */
 +  if (xdg_mime_is_super_type (ubase) &&
 +      xdg_mime_media_type_equal (umime, ubase))
 +    return 1;
 +#endif
 +
 +  /*  Handle special cases text/plain and application/octet-stream */
 +  if (strcmp (ubase, "text/plain") == 0 && 
 +      strncmp (umime, "text/", 5) == 0)
 +    return 1;
 +
 +  if (strcmp (ubase, "application/octet-stream") == 0 &&
 +      strncmp (umime, "inode/", 6) != 0)
 +    return 1;
 +  
 +  parents = _xdg_mime_parent_list_lookup (parent_list, umime);
 +  for (; parents && *parents; parents++)
 +    {
 +      if (_xdg_mime_mime_type_subclass (*parents, ubase))
 +      return 1;
 +    }
 +
 +  return 0;
 +}
 +
 +int
 +xdg_mime_mime_type_subclass (const char *mime,
 +                           const char *base)
 +{
 +  xdg_mime_init ();
 +
 +  return _xdg_mime_mime_type_subclass (mime, base);
 +}
 +
 +char **
 +xdg_mime_list_mime_parents (const char *mime)
 +{
 +  const char **parents;
 +  char **result;
 +  int i, n;
 +
++  xdg_mime_init ();
++
 +  if (_caches)
 +    return _xdg_mime_cache_list_mime_parents (mime);
 +
 +  parents = xdg_mime_get_mime_parents (mime);
 +
 +  if (!parents)
 +    return NULL;
 +
 +  for (i = 0; parents[i]; i++) ;
 +  
 +  n = (i + 1) * sizeof (char *);
 +  result = (char **) malloc (n);
 +  memcpy (result, parents, n);
 +
 +  return result;
 +}
 +
 +const char **
 +xdg_mime_get_mime_parents (const char *mime)
 +{
 +  const char *umime;
 +
 +  xdg_mime_init ();
 +
 +  umime = _xdg_mime_unalias_mime_type (mime);
 +
 +  return _xdg_mime_parent_list_lookup (parent_list, umime);
 +}
 +
 +void 
 +xdg_mime_dump (void)
 +{
 +  xdg_mime_init();
 +
 +  printf ("*** ALIASES ***\n\n");
 +  _xdg_mime_alias_list_dump (alias_list);
 +  printf ("\n*** PARENTS ***\n\n");
 +  _xdg_mime_parent_list_dump (parent_list);
 +  printf ("\n*** CACHE ***\n\n");
 +  _xdg_glob_hash_dump (global_hash);
 +  printf ("\n*** GLOBS ***\n\n");
 +  _xdg_glob_hash_dump (global_hash);
 +  printf ("\n*** GLOBS REVERSE TREE ***\n\n");
 +  _xdg_mime_cache_glob_dump ();
 +}
 +
 +
 +/* Registers a function to be called every time the mime database reloads its files
 + */
 +int
 +xdg_mime_register_reload_callback (XdgMimeCallback  callback,
 +                                 void            *data,
 +                                 XdgMimeDestroy   destroy)
 +{
 +  XdgCallbackList *list_el;
 +  static int callback_id = 1;
 +
 +  /* Make a new list element */
 +  list_el = calloc (1, sizeof (XdgCallbackList));
 +  list_el->callback_id = callback_id;
 +  list_el->callback = callback;
 +  list_el->data = data;
 +  list_el->destroy = destroy;
 +  list_el->next = callback_list;
 +  if (list_el->next)
 +    list_el->next->prev = list_el;
 +
 +  callback_list = list_el;
 +  callback_id ++;
 +
 +  return callback_id - 1;
 +}
 +
 +void
 +xdg_mime_remove_callback (int callback_id)
 +{
 +  XdgCallbackList *list;
 +
 +  for (list = callback_list; list; list = list->next)
 +    {
 +      if (list->callback_id == callback_id)
 +      {
 +        if (list->next)
 +          list->next = list->prev;
 +
 +        if (list->prev)
 +          list->prev->next = list->next;
 +        else
 +          callback_list = list->next;
 +
 +        /* invoke the destroy handler */
 +        (list->destroy) (list->data);
 +        free (list);
 +        return;
 +      }
 +    }
 +}
 +
 +const char *
 +xdg_mime_get_icon (const char *mime)
 +{
 +  xdg_mime_init ();
 +  
 +  if (_caches)
 +    return _xdg_mime_cache_get_icon (mime);
 +
 +  return _xdg_mime_icon_list_lookup (icon_list, mime);
 +}
 +
 +const char *
 +xdg_mime_get_generic_icon (const char *mime)
 +{
 +  xdg_mime_init ();
 +  
 +  if (_caches)
 +    return _xdg_mime_cache_get_generic_icon (mime);
 +
 +  return _xdg_mime_icon_list_lookup (generic_icon_list, mime);
 +}
index 6a34edfc38a499497e411aed46b7a6c84dbaa284,0000000000000000000000000000000000000000..abba067126a84f4dadb4af2fb5e0d9dc0f3548ec
mode 100644,000000..100644
--- /dev/null
@@@ -1,133 -1,0 +1,119 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  * 
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmime.h: XDG Mime Spec mime resolver.  Based on version 0.11 of the spec.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + * 
 + * Copyright (C) 2003  Red Hat, Inc.
 + * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +
 +#ifndef __XDG_MIME_H__
 +#define __XDG_MIME_H__
 +
 +#include <stdlib.h>
 +#include <sys/stat.h>
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif /* __cplusplus */
 +
 +#ifdef XDG_PREFIX
 +#define XDG_ENTRY(func) _XDG_ENTRY2(XDG_PREFIX,func)
 +#define _XDG_ENTRY2(prefix,func) _XDG_ENTRY3(prefix,func)
 +#define _XDG_ENTRY3(prefix,func) prefix##_##func
 +
 +#define XDG_RESERVED_ENTRY(func) _XDG_RESERVED_ENTRY2(XDG_PREFIX,func)
 +#define _XDG_RESERVED_ENTRY2(prefix,func) _XDG_RESERVED_ENTRY3(prefix,func)
 +#define _XDG_RESERVED_ENTRY3(prefix,func) _##prefix##_##func
 +#endif
 +
 +typedef void (*XdgMimeCallback) (void *user_data);
 +typedef void (*XdgMimeDestroy)  (void *user_data);
 +
 +  
 +#ifdef XDG_PREFIX
 +#define xdg_mime_get_mime_type_for_data       XDG_ENTRY(get_mime_type_for_data)
 +#define xdg_mime_get_mime_type_for_file       XDG_ENTRY(get_mime_type_for_file)
 +#define xdg_mime_get_mime_type_from_file_name XDG_ENTRY(get_mime_type_from_file_name)
 +#define xdg_mime_get_mime_types_from_file_name XDG_ENTRY(get_mime_types_from_file_name)
 +#define xdg_mime_is_valid_mime_type           XDG_ENTRY(is_valid_mime_type)
 +#define xdg_mime_mime_type_equal              XDG_ENTRY(mime_type_equal)
 +#define xdg_mime_media_type_equal             XDG_ENTRY(media_type_equal)
 +#define xdg_mime_mime_type_subclass           XDG_ENTRY(mime_type_subclass)
 +#define xdg_mime_get_mime_parents             XDG_ENTRY(get_mime_parents)
 +#define xdg_mime_list_mime_parents            XDG_ENTRY(list_mime_parents)
 +#define xdg_mime_unalias_mime_type            XDG_ENTRY(unalias_mime_type)
 +#define xdg_mime_get_max_buffer_extents       XDG_ENTRY(get_max_buffer_extents)
 +#define xdg_mime_shutdown                     XDG_ENTRY(shutdown)
 +#define xdg_mime_dump                         XDG_ENTRY(dump)
 +#define xdg_mime_register_reload_callback     XDG_ENTRY(register_reload_callback)
 +#define xdg_mime_remove_callback              XDG_ENTRY(remove_callback)
 +#define xdg_mime_type_unknown                 XDG_ENTRY(type_unknown)
 +#define xdg_mime_type_empty                   XDG_ENTRY(type_empty)
 +#define xdg_mime_type_textplain               XDG_ENTRY(type_textplain)
 +#define xdg_mime_get_icon                     XDG_ENTRY(get_icon)
 +#define xdg_mime_get_generic_icon             XDG_ENTRY(get_generic_icon)
 +
 +#define _xdg_mime_mime_type_equal             XDG_RESERVED_ENTRY(mime_type_equal)
 +#define _xdg_mime_mime_type_subclass          XDG_RESERVED_ENTRY(mime_type_subclass)
 +#define _xdg_mime_unalias_mime_type           XDG_RESERVED_ENTRY(unalias_mime_type)  
 +#endif
 +
 +extern const char xdg_mime_type_unknown[];
 +extern const char xdg_mime_type_empty[];
 +extern const char xdg_mime_type_textplain[];
 +#define XDG_MIME_TYPE_UNKNOWN xdg_mime_type_unknown
 +#define XDG_MIME_TYPE_EMPTY xdg_mime_type_empty
 +#define XDG_MIME_TYPE_TEXTPLAIN xdg_mime_type_textplain
 +
 +const char  *xdg_mime_get_mime_type_for_data       (const void *data,
 +                                                  size_t      len,
 +                                                  int        *result_prio);
 +const char  *xdg_mime_get_mime_type_for_file       (const char *file_name,
 +                                                    struct stat *statbuf);
 +const char  *xdg_mime_get_mime_type_from_file_name (const char *file_name);
 +int          xdg_mime_get_mime_types_from_file_name(const char *file_name,
 +                                                  const char *mime_types[],
 +                                                  int         n_mime_types);
 +int          xdg_mime_is_valid_mime_type           (const char *mime_type);
 +int          xdg_mime_mime_type_equal              (const char *mime_a,
 +                                                  const char *mime_b);
 +int          xdg_mime_media_type_equal             (const char *mime_a,
 +                                                  const char *mime_b);
 +int          xdg_mime_mime_type_subclass           (const char *mime_a,
 +                                                  const char *mime_b);
 +  /* xdg_mime_get_mime_parents() is deprecated since it does
 +   * not work correctly with caches. Use xdg_mime_list_parents() 
 +   * instead, but notice that that function expects you to free
 +   * the array it returns. 
 +   */
 +const char **xdg_mime_get_mime_parents                   (const char *mime);
 +char **      xdg_mime_list_mime_parents                  (const char *mime);
 +const char  *xdg_mime_unalias_mime_type                  (const char *mime);
 +const char  *xdg_mime_get_icon                     (const char *mime);
 +const char  *xdg_mime_get_generic_icon             (const char *mime);
 +int          xdg_mime_get_max_buffer_extents       (void);
 +void         xdg_mime_shutdown                     (void);
 +void         xdg_mime_dump                         (void);
 +int          xdg_mime_register_reload_callback     (XdgMimeCallback  callback,
 +                                                  void            *data,
 +                                                  XdgMimeDestroy   destroy);
 +void         xdg_mime_remove_callback              (int              callback_id);
 +
++void xdg_mime_set_dirs (const char * const *dirs);
++
 +   /* Private versions of functions that don't call xdg_mime_init () */
 +int          _xdg_mime_mime_type_equal             (const char *mime_a,
 +                                                  const char *mime_b);
 +int          _xdg_mime_mime_type_subclass          (const char *mime,
 +                                                  const char *base);
 +const char  *_xdg_mime_unalias_mime_type           (const char *mime);
 +
 +
 +#ifdef __cplusplus
 +}
 +#endif /* __cplusplus */
 +#endif /* __XDG_MIME_H__ */
index 07d89eb32e930bbed190dddedc42bbae5849ee9b,0000000000000000000000000000000000000000..857d274a3278d5621fd553fad17ebcfd8f13fe8b
mode 100644,000000..100644
--- /dev/null
@@@ -1,184 -1,0 +1,168 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimealias.c: Private file.  Datastructure for storing the aliases.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2004  Red Hat, Inc.
 + * Copyright (C) 2004  Matthias Clasen <mclasen@redhat.com>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "xdgmimealias.h"
 +#include "xdgmimeint.h"
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <assert.h>
 +#include <string.h>
 +#include <fnmatch.h>
 +
 +#ifndef       FALSE
 +#define       FALSE   (0)
 +#endif
 +
 +#ifndef       TRUE
 +#define       TRUE    (!FALSE)
 +#endif
 +
 +typedef struct XdgAlias XdgAlias;
 +
 +struct XdgAlias 
 +{
 +  char *alias;
 +  char *mime_type;
 +};
 +
 +struct XdgAliasList
 +{
 +  struct XdgAlias *aliases;
 +  int n_aliases;
 +};
 +
 +XdgAliasList *
 +_xdg_mime_alias_list_new (void)
 +{
 +  XdgAliasList *list;
 +
 +  list = malloc (sizeof (XdgAliasList));
 +
 +  list->aliases = NULL;
 +  list->n_aliases = 0;
 +
 +  return list;
 +}
 +
 +void         
 +_xdg_mime_alias_list_free (XdgAliasList *list)
 +{
 +  int i;
 +
 +  if (list->aliases)
 +    {
 +      for (i = 0; i < list->n_aliases; i++)
 +      {
 +        free (list->aliases[i].alias);
 +        free (list->aliases[i].mime_type);
 +      }
 +      free (list->aliases);
 +    }
 +  free (list);
 +}
 +
 +static int
 +alias_entry_cmp (const void *v1, const void *v2)
 +{
 +  return strcmp (((XdgAlias *)v1)->alias, ((XdgAlias *)v2)->alias);
 +}
 +
 +const char  *
 +_xdg_mime_alias_list_lookup (XdgAliasList *list,
 +                           const char   *alias)
 +{
 +  XdgAlias *entry;
 +  XdgAlias key;
 +
 +  if (list->n_aliases > 0)
 +    {
 +      key.alias = (char *)alias;
 +      key.mime_type = NULL;
 +
 +      entry = bsearch (&key, list->aliases, list->n_aliases,
 +                     sizeof (XdgAlias), alias_entry_cmp);
 +      if (entry)
 +        return entry->mime_type;
 +    }
 +
 +  return NULL;
 +}
 +
 +void
 +_xdg_mime_alias_read_from_file (XdgAliasList *list,
 +                              const char   *file_name)
 +{
 +  FILE *file;
 +  char line[255];
 +  int alloc;
 +
 +  file = fopen (file_name, "r");
 +
 +  if (file == NULL)
 +    return;
 +
 +  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
 +   * Blah */
 +  alloc = list->n_aliases + 16;
 +  list->aliases = realloc (list->aliases, alloc * sizeof (XdgAlias));
 +  while (fgets (line, 255, file) != NULL)
 +    {
 +      char *sep;
 +      if (line[0] == '#')
 +      continue;
 +
 +      sep = strchr (line, ' ');
 +      if (sep == NULL)
 +      continue;
 +      *(sep++) = '\000';
 +      sep[strlen (sep) -1] = '\000';
 +      if (list->n_aliases == alloc)
 +      {
 +        alloc <<= 1;
 +        list->aliases = realloc (list->aliases, 
 +                                 alloc * sizeof (XdgAlias));
 +      }
 +      list->aliases[list->n_aliases].alias = strdup (line);
 +      list->aliases[list->n_aliases].mime_type = strdup (sep);
 +      list->n_aliases++;
 +    }
 +  list->aliases = realloc (list->aliases, 
 +                         list->n_aliases * sizeof (XdgAlias));
 +
 +  fclose (file);  
 +  
 +  if (list->n_aliases > 1)
 +    qsort (list->aliases, list->n_aliases, 
 +           sizeof (XdgAlias), alias_entry_cmp);
 +}
 +
 +
 +void
 +_xdg_mime_alias_list_dump (XdgAliasList *list)
 +{
 +  int i;
 +
 +  if (list->aliases)
 +    {
 +      for (i = 0; i < list->n_aliases; i++)
 +      {
 +        printf ("%s %s\n", 
 +                list->aliases[i].alias,
 +                list->aliases[i].mime_type);
 +      }
 +    }
 +}
 +
 +
index 3c28012dc34e14318491ba73cbda6921d76aeb34,0000000000000000000000000000000000000000..05df009916cbf61aefead4fba4c0511dbe742b96
mode 100644,000000..100644
--- /dev/null
@@@ -1,51 -1,0 +1,35 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimealias.h: Private file.  Datastructure for storing the aliases.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2004  Red Hat, Inc.
 + * Copyright (C) 200  Matthias Clasen <mclasen@redhat.com>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifndef __XDG_MIME_ALIAS_H__
 +#define __XDG_MIME_ALIAS_H__
 +
 +#include "xdgmime.h"
 +
 +typedef struct XdgAliasList XdgAliasList;
 +
 +#ifdef XDG_PREFIX
 +#define _xdg_mime_alias_read_from_file        XDG_RESERVED_ENTRY(alias_read_from_file)
 +#define _xdg_mime_alias_list_new              XDG_RESERVED_ENTRY(alias_list_new)
 +#define _xdg_mime_alias_list_free             XDG_RESERVED_ENTRY(alias_list_free)
 +#define _xdg_mime_alias_list_lookup           XDG_RESERVED_ENTRY(alias_list_lookup)
 +#define _xdg_mime_alias_list_dump             XDG_RESERVED_ENTRY(alias_list_dump)
 +#endif
 +
 +void          _xdg_mime_alias_read_from_file (XdgAliasList *list,
 +                                            const char   *file_name);
 +XdgAliasList *_xdg_mime_alias_list_new       (void);
 +void          _xdg_mime_alias_list_free      (XdgAliasList *list);
 +const char   *_xdg_mime_alias_list_lookup    (XdgAliasList *list,
 +                                            const char  *alias);
 +void          _xdg_mime_alias_list_dump      (XdgAliasList *list);
 +
 +#endif /* __XDG_MIME_ALIAS_H__ */
index acaed9d470edf3536f6acb46db0761e7fcde29e8,0000000000000000000000000000000000000000..05378fc9a19cf1697b957a0a1c59634dc34ba231
mode 100644,000000..100644
--- /dev/null
@@@ -1,1071 -1,0 +1,1118 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimealias.c: Private file.  mmappable caches for mime data
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2005  Matthias Clasen <mclasen@redhat.com>
 + *
-       xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 4);
-       xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +
 +#include <fcntl.h>
 +#include <unistd.h>
 +#include <errno.h>
 +#include <fnmatch.h>
 +#include <assert.h>
 +
 +#include <netinet/in.h> /* for ntohl/ntohs */
 +
 +#ifdef HAVE_MMAP
 +#include <sys/mman.h>
 +#else
 +#warning Building xdgmime without MMAP support. Binary "mime.cache" files will not be used.
 +#endif
 +
 +#include <sys/stat.h>
 +#include <sys/types.h>
 +
 +#include "xdgmimecache.h"
 +#include "xdgmimeint.h"
 +
 +#ifndef MAX
 +#define MAX(a,b) ((a) > (b) ? (a) : (b))
 +#endif
 +
 +#ifndef       FALSE
 +#define       FALSE   (0)
 +#endif
 +
 +#ifndef       TRUE
 +#define       TRUE    (!FALSE)
 +#endif
 +
 +#ifndef _O_BINARY
 +#define _O_BINARY 0
 +#endif
 +
 +#ifndef MAP_FAILED
 +#define MAP_FAILED ((void *) -1)
 +#endif
 +
++#ifndef S_ISREG
++#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
++#endif
++
 +#define MAJOR_VERSION 1
 +#define MINOR_VERSION_MIN 1
 +#define MINOR_VERSION_MAX 2
 +
 +struct _XdgMimeCache
 +{
 +  int ref_count;
 +  int minor;
 +
 +  size_t  size;
 +  char   *buffer;
 +};
 +
 +#define GET_UINT16(cache,offset) (ntohs(*(xdg_uint16_t*)((cache) + (offset))))
 +#define GET_UINT32(cache,offset) (ntohl(*(xdg_uint32_t*)((cache) + (offset))))
 +
 +XdgMimeCache *
 +_xdg_mime_cache_ref (XdgMimeCache *cache)
 +{
 +  cache->ref_count++;
 +  return cache;
 +}
 +
 +void
 +_xdg_mime_cache_unref (XdgMimeCache *cache)
 +{
 +  cache->ref_count--;
 +
 +  if (cache->ref_count == 0)
 +    {
 +#ifdef HAVE_MMAP
 +      munmap (cache->buffer, cache->size);
 +#endif
 +      free (cache);
 +    }
 +}
 +
 +XdgMimeCache *
 +_xdg_mime_cache_new_from_file (const char *file_name)
 +{
 +  XdgMimeCache *cache = NULL;
 +
 +#ifdef HAVE_MMAP
 +  int fd = -1;
 +  struct stat st;
 +  char *buffer = NULL;
 +  int minor;
 +
 +  /* Open the file and map it into memory */
 +  do {
 +    fd = open (file_name, O_RDONLY|_O_BINARY, 0);
 +  } while (fd == -1 && errno == EINTR);
 +
 +  if (fd < 0)
 +    return NULL;
 +  
 +  if (fstat (fd, &st) < 0 || st.st_size < 4)
 +    goto done;
 +
 +  buffer = (char *) mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
 +
 +  if (buffer == MAP_FAILED)
 +    goto done;
 +
 +  minor = GET_UINT16 (buffer, 2);
 +  /* Verify version */
 +  if (GET_UINT16 (buffer, 0) != MAJOR_VERSION ||
 +      (minor < MINOR_VERSION_MIN ||
 +       minor > MINOR_VERSION_MAX))
 +    {
 +      munmap (buffer, st.st_size);
 +
 +      goto done;
 +    }
 +  
 +  cache = (XdgMimeCache *) malloc (sizeof (XdgMimeCache));
 +  cache->minor = minor;
 +  cache->ref_count = 1;
 +  cache->buffer = buffer;
 +  cache->size = st.st_size;
 +
 + done:
 +  if (fd != -1)
 +    close (fd);
 +
++#else /* HAVE_MMAP */
++  cache = (XdgMimeCache *) malloc (sizeof (XdgMimeCache));
++  cache->minor = 0;
++  cache->ref_count = 1;
++  cache->buffer = NULL;
++  cache->size = 0;
 +#endif  /* HAVE_MMAP */
 +
 +  return cache;
 +}
 +
 +static int
 +cache_magic_matchlet_compare_to_data (XdgMimeCache *cache, 
 +                                    xdg_uint32_t  offset,
 +                                    const void   *data,
 +                                    size_t        len)
 +{
 +  xdg_uint32_t range_start = GET_UINT32 (cache->buffer, offset);
 +  xdg_uint32_t range_length = GET_UINT32 (cache->buffer, offset + 4);
 +  xdg_uint32_t data_length = GET_UINT32 (cache->buffer, offset + 12);
 +  xdg_uint32_t data_offset = GET_UINT32 (cache->buffer, offset + 16);
 +  xdg_uint32_t mask_offset = GET_UINT32 (cache->buffer, offset + 20);
 +  
 +  xdg_uint32_t i, j;
 +
 +  for (i = range_start; i < range_start + range_length; i++)
 +    {
 +      int valid_matchlet = TRUE;
 +      
 +      if (i + data_length > len)
 +      return FALSE;
 +
 +      if (mask_offset)
 +      {
 +        for (j = 0; j < data_length; j++)
 +          {
 +            if ((((unsigned char *)cache->buffer)[data_offset + j] & ((unsigned char *)cache->buffer)[mask_offset + j]) !=
 +                ((((unsigned char *) data)[j + i]) & ((unsigned char *)cache->buffer)[mask_offset + j]))
 +              {
 +                valid_matchlet = FALSE;
 +                break;
 +              }
 +          }
 +      }
 +      else
 +      {
 +        valid_matchlet = memcmp(cache->buffer + data_offset, (unsigned char *)data + i, data_length) == 0;
 +      }
 +
 +      if (valid_matchlet)
 +      return TRUE;
 +    }
 +  
 +  return FALSE;  
 +}
 +
 +static int
 +cache_magic_matchlet_compare (XdgMimeCache *cache, 
 +                            xdg_uint32_t  offset,
 +                            const void   *data,
 +                            size_t        len)
 +{
 +  xdg_uint32_t n_children = GET_UINT32 (cache->buffer, offset + 24);
 +  xdg_uint32_t child_offset = GET_UINT32 (cache->buffer, offset + 28);
 +
 +  xdg_uint32_t i;
 +  
 +  if (cache_magic_matchlet_compare_to_data (cache, offset, data, len))
 +    {
 +      if (n_children == 0)
 +      return TRUE;
 +      
 +      for (i = 0; i < n_children; i++)
 +      {
 +        if (cache_magic_matchlet_compare (cache, child_offset + 32 * i,
 +                                          data, len))
 +          return TRUE;
 +      }
 +    }
 +  
 +  return FALSE;  
 +}
 +
 +static const char *
 +cache_magic_compare_to_data (XdgMimeCache *cache, 
 +                           xdg_uint32_t  offset,
 +                           const void   *data, 
 +                           size_t        len, 
 +                           int          *prio)
 +{
 +  xdg_uint32_t priority = GET_UINT32 (cache->buffer, offset);
 +  xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, offset + 4);
 +  xdg_uint32_t n_matchlets = GET_UINT32 (cache->buffer, offset + 8);
 +  xdg_uint32_t matchlet_offset = GET_UINT32 (cache->buffer, offset + 12);
 +
 +  xdg_uint32_t i;
 +
 +  for (i = 0; i < n_matchlets; i++)
 +    {
 +      if (cache_magic_matchlet_compare (cache, matchlet_offset + i * 32, 
 +                                      data, len))
 +      {
 +        *prio = priority;
 +        
 +        return cache->buffer + mimetype_offset;
 +      }
 +    }
 +
 +  return NULL;
 +}
 +
 +static const char *
 +cache_magic_lookup_data (XdgMimeCache *cache, 
 +                       const void   *data, 
 +                       size_t        len, 
 +                       int          *prio)
 +{
 +  xdg_uint32_t list_offset;
 +  xdg_uint32_t n_entries;
 +  xdg_uint32_t offset;
 +
 +  xdg_uint32_t j;
 +
 +  *prio = 0;
 +
 +  list_offset = GET_UINT32 (cache->buffer, 24);
 +  n_entries = GET_UINT32 (cache->buffer, list_offset);
 +  offset = GET_UINT32 (cache->buffer, list_offset + 8);
 +  
 +  for (j = 0; j < n_entries; j++)
 +    {
 +      const char *match;
 +
 +      match = cache_magic_compare_to_data (cache, offset + 16 * j, 
 +                                         data, len, prio);
 +      if (match)
 +      return match;
 +    }
 +
 +  return NULL;
 +}
 +
 +static const char *
 +cache_alias_lookup (const char *alias)
 +{
 +  const char *ptr;
 +  int i, min, max, mid, cmp;
 +
 +  for (i = 0; _caches[i]; i++)
 +    {
 +      XdgMimeCache *cache = _caches[i];
-       xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 12);
-       xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
++      xdg_uint32_t list_offset;
++      xdg_uint32_t n_entries;
 +      xdg_uint32_t offset;
 +
++      if (cache->buffer == NULL)
++        continue;
++
++      list_offset = GET_UINT32 (cache->buffer, 4);
++      n_entries = GET_UINT32 (cache->buffer, list_offset);
++
 +      min = 0; 
 +      max = n_entries - 1;
 +      while (max >= min) 
 +      {
 +        mid = (min + max) / 2;
 +
 +        offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
 +        ptr = cache->buffer + offset;
 +        cmp = strcmp (ptr, alias);
 +        
 +        if (cmp < 0)
 +          min = mid + 1;
 +        else if (cmp > 0)
 +          max = mid - 1;
 +        else
 +          {
 +            offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
 +            return cache->buffer + offset;
 +          }
 +      }
 +    }
 +
 +  return NULL;
 +}
 +
 +typedef struct {
 +  const char *mime;
 +  int weight;
 +} MimeWeight;
 +
 +static int
 +cache_glob_lookup_literal (const char *file_name,
 +                         const char *mime_types[],
 +                         int         n_mime_types,
 +                         int         case_sensitive_check)
 +{
 +  const char *ptr;
 +  int i, min, max, mid, cmp;
 +
 +  for (i = 0; _caches[i]; i++)
 +    {
 +      XdgMimeCache *cache = _caches[i];
-       xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 20);
-       xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
++      xdg_uint32_t list_offset;
++      xdg_uint32_t n_entries;
 +      xdg_uint32_t offset;
 +
++      if (cache->buffer == NULL)
++        continue;
++
++      list_offset = GET_UINT32 (cache->buffer, 12);
++      n_entries = GET_UINT32 (cache->buffer, list_offset);
++
 +      min = 0; 
 +      max = n_entries - 1;
 +      while (max >= min) 
 +      {
 +        mid = (min + max) / 2;
 +
 +        offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid);
 +        ptr = cache->buffer + offset;
 +        cmp = strcmp (ptr, file_name);
 +
 +        if (cmp < 0)
 +          min = mid + 1;
 +        else if (cmp > 0)
 +          max = mid - 1;
 +        else
 +          {
 +            int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 8);
 +            int case_sensitive = weight & 0x100;
 +            weight = weight & 0xff;
 +
 +            if (case_sensitive_check || !case_sensitive)
 +              {
 +                offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 4);
 +                mime_types[0] = (const char *)(cache->buffer + offset);
 +
 +                return 1;
 +              }
 +            return 0;
 +          }
 +      }
 +    }
 +
 +  return 0;
 +}
 +
 +static int
 +cache_glob_lookup_fnmatch (const char *file_name,
 +                         MimeWeight  mime_types[],
 +                         int         n_mime_types,
 +                         int         case_sensitive_check)
 +{
 +  const char *mime_type;
 +  const char *ptr;
 +
 +  int i, n;
 +  xdg_uint32_t j;
 +
 +  n = 0;
 +  for (i = 0; _caches[i]; i++)
 +    {
 +      XdgMimeCache *cache = _caches[i];
 +
-       xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 16);
-       xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
-       xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4);
++      xdg_uint32_t list_offset;
++      xdg_uint32_t n_entries;
++
++      if (cache->buffer == NULL)
++        continue;
++
++      list_offset = GET_UINT32 (cache->buffer, 20);
++      n_entries = GET_UINT32 (cache->buffer, list_offset);
 +
 +      for (j = 0; j < n_entries && n < n_mime_types; j++)
 +      {
 +        xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j);
 +        xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 4);
 +        int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 8);
 +        int case_sensitive = weight & 0x100;
 +        weight = weight & 0xff;
 +        ptr = cache->buffer + offset;
 +        mime_type = cache->buffer + mimetype_offset;
 +        if (case_sensitive_check || !case_sensitive)
 +          {
 +            /* FIXME: Not UTF-8 safe */
 +            if (fnmatch (ptr, file_name, 0) == 0)
 +              {
 +                mime_types[n].mime = mime_type;
 +                mime_types[n].weight = weight;
 +                n++;
 +              }
 +          }
 +      }
 +
 +      if (n > 0)
 +      return n;
 +    }
 +  
 +  return 0;
 +}
 +
 +static int
 +cache_glob_node_lookup_suffix (XdgMimeCache  *cache,
 +                             xdg_uint32_t   n_entries,
 +                             xdg_uint32_t   offset,
 +                             const char    *file_name,
 +                             int            len,
 +                             int            case_sensitive_check,
 +                             MimeWeight     mime_types[],
 +                             int            n_mime_types)
 +{
 +  xdg_unichar_t character;
 +  xdg_unichar_t match_char;
 +  xdg_uint32_t mimetype_offset;
 +  xdg_uint32_t n_children;
 +  xdg_uint32_t child_offset; 
 +  int weight;
 +  int case_sensitive;
 +
 +  xdg_uint32_t i;
 +  int min, max, mid, n;
 +
 +  character = file_name[len - 1];
 +
 +  assert (character != 0);
 +
 +  min = 0;
 +  max = n_entries - 1;
 +  while (max >= min)
 +    {
 +      mid = (min + max) /  2;
 +      match_char = GET_UINT32 (cache->buffer, offset + 12 * mid);
 +      if (match_char < character)
 +      min = mid + 1;
 +      else if (match_char > character)
 +      max = mid - 1;
 +      else 
 +      {
 +          len--;
 +          n = 0;
 +          n_children = GET_UINT32 (cache->buffer, offset + 12 * mid + 4);
 +          child_offset = GET_UINT32 (cache->buffer, offset + 12 * mid + 8);
 +      
 +          if (len > 0)
 +            {
 +              n = cache_glob_node_lookup_suffix (cache, 
 +                                                 n_children, child_offset,
 +                                                 file_name, len, 
 +                                                 case_sensitive_check,
 +                                                 mime_types,
 +                                                 n_mime_types);
 +            }
 +          if (n == 0)
 +            {
 +            i = 0;
 +            while (n < n_mime_types && i < n_children)
 +              {
 +                match_char = GET_UINT32 (cache->buffer, child_offset + 12 * i);
 +                if (match_char != 0)
 +                  break;
 +
 +                mimetype_offset = GET_UINT32 (cache->buffer, child_offset + 12 * i + 4);
 +                weight = GET_UINT32 (cache->buffer, child_offset + 12 * i + 8);
 +                case_sensitive = weight & 0x100;
 +                weight = weight & 0xff;
 +
 +                if (case_sensitive_check || !case_sensitive)
 +                  {
 +                    mime_types[n].mime = cache->buffer + mimetype_offset;
 +                    mime_types[n].weight = weight;
 +                    n++;
 +                  }
 +                i++;
 +              }
 +          }
 +        return n;
 +      }
 +    }
 +  return 0;
 +}
 +
 +static int
 +cache_glob_lookup_suffix (const char *file_name,
 +                        int         len,
 +                        int         ignore_case,
 +                        MimeWeight  mime_types[],
 +                        int         n_mime_types)
 +{
 +  int i, n;
 +
 +  for (i = 0; _caches[i]; i++)
 +    {
 +      XdgMimeCache *cache = _caches[i];
 +
-       
-       xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 8);
-       xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
++      xdg_uint32_t list_offset;
++      xdg_uint32_t n_entries;
++      xdg_uint32_t offset;
++
++      if (cache->buffer == NULL)
++        continue;
++
++      list_offset = GET_UINT32 (cache->buffer, 16);
++      n_entries = GET_UINT32 (cache->buffer, list_offset);
++      offset = GET_UINT32 (cache->buffer, list_offset + 4);
 +
 +      n = cache_glob_node_lookup_suffix (cache, 
 +                                       n_entries, offset, 
 +                                       file_name, len,
 +                                       ignore_case,
 +                                       mime_types,
 +                                       n_mime_types);
 +      if (n > 0)
 +      return n;
 +    }
 +
 +  return 0;
 +}
 +
 +static int compare_mime_weight (const void *a, const void *b)
 +{
 +  const MimeWeight *aa = (const MimeWeight *)a;
 +  const MimeWeight *bb = (const MimeWeight *)b;
 +
 +  return bb->weight - aa->weight;
 +}
 +
 +#define ISUPPER(c)            ((c) >= 'A' && (c) <= 'Z')
 +static char *
 +ascii_tolower (const char *str)
 +{
 +  char *p, *lower;
 +
 +  lower = strdup (str);
 +  p = lower;
 +  while (*p != 0)
 +    {
 +      char c = *p;
 +      *p++ = ISUPPER (c) ? c - 'A' + 'a' : c;
 +    }
 +  return lower;
 +}
 +
 +static int
 +cache_glob_lookup_file_name (const char *file_name, 
 +                           const char *mime_types[],
 +                           int         n_mime_types)
 +{
 +  int n;
 +  MimeWeight mimes[10];
 +  int n_mimes = 10;
 +  int i;
 +  int len;
 +  char *lower_case;
 +
 +  assert (file_name != NULL && n_mime_types > 0);
 +
 +  /* First, check the literals */
 +
 +  lower_case = ascii_tolower (file_name);
 +
 +  n = cache_glob_lookup_literal (lower_case, mime_types, n_mime_types, FALSE);
 +  if (n > 0)
 +    {
 +      free (lower_case);
 +      return n;
 +    }
 +
 +  n = cache_glob_lookup_literal (file_name, mime_types, n_mime_types, TRUE);
 +  if (n > 0)
 +    {
 +      free (lower_case);
 +      return n;
 +    }
 +
 +  len = strlen (file_name);
 +  n = cache_glob_lookup_suffix (lower_case, len, FALSE, mimes, n_mimes);
 +  if (n == 0)
 +    n = cache_glob_lookup_suffix (file_name, len, TRUE, mimes, n_mimes);
 +
 +  /* Last, try fnmatch */
 +  if (n == 0)
 +    n = cache_glob_lookup_fnmatch (lower_case, mimes, n_mimes, FALSE);
 +  if (n == 0)
 +    n = cache_glob_lookup_fnmatch (file_name, mimes, n_mimes, TRUE);
 +
 +  free (lower_case);
 +
 +  qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight);
 +
 +  if (n_mime_types < n)
 +    n = n_mime_types;
 +
 +  for (i = 0; i < n; i++)
 +    mime_types[i] = mimes[i].mime;
 +
 +  return n;
 +}
 +
 +int
 +_xdg_mime_cache_get_max_buffer_extents (void)
 +{
 +  xdg_uint32_t offset;
 +  xdg_uint32_t max_extent;
 +  int i;
 +
 +  max_extent = 0;
 +  for (i = 0; _caches[i]; i++)
 +    {
 +      XdgMimeCache *cache = _caches[i];
 +
++      if (cache->buffer == NULL)
++        continue;
++
 +      offset = GET_UINT32 (cache->buffer, 24);
 +      max_extent = MAX (max_extent, GET_UINT32 (cache->buffer, offset + 4));
 +    }
 +
 +  return max_extent;
 +}
 +
 +static const char *
 +cache_get_mime_type_for_data (const void *data,
 +                            size_t      len,
 +                            int        *result_prio,
 +                            const char *mime_types[],
 +                            int         n_mime_types)
 +{
 +  const char *mime_type;
 +  int i, n, priority;
 +
 +  priority = 0;
 +  mime_type = NULL;
 +  for (i = 0; _caches[i]; i++)
 +    {
 +      XdgMimeCache *cache = _caches[i];
 +
 +      int prio;
 +      const char *match;
 +
++      if (cache->buffer == NULL)
++        continue;
++
 +      match = cache_magic_lookup_data (cache, data, len, &prio);
 +      if (prio > priority)
 +      {
 +        priority = prio;
 +        mime_type = match;
 +      }
 +    }
 +
 +  if (result_prio)
 +    *result_prio = priority;
 +
 +  if (priority > 0)
 +    {
 +      /* Pick glob-result R where mime_type inherits from R */
 +      for (n = 0; n < n_mime_types; n++)
 +        {
 +          if (mime_types[n] && _xdg_mime_cache_mime_type_subclass(mime_types[n], mime_type))
 +              return mime_types[n];
 +        }
 +      if (n == 0)
 +        {
 +          /* No globs: return magic match */
 +          return mime_type;
 +        }
 +    }
 +
 +  /* Pick first glob result, as fallback */
 +  for (n = 0; n < n_mime_types; n++)
 +    {
 +      if (mime_types[n])
 +        return mime_types[n];
 +    }
 +
 +  return NULL;
 +}
 +
 +const char *
 +_xdg_mime_cache_get_mime_type_for_data (const void *data,
 +                                      size_t      len,
 +                                      int        *result_prio)
 +{
 +  return cache_get_mime_type_for_data (data, len, result_prio, NULL, 0);
 +}
 +
 +const char *
 +_xdg_mime_cache_get_mime_type_for_file (const char  *file_name,
 +                                      struct stat *statbuf)
 +{
 +  const char *mime_type;
 +  const char *mime_types[10];
 +  FILE *file;
 +  unsigned char *data;
 +  int max_extent;
 +  int bytes_read;
 +  struct stat buf;
 +  const char *base_name;
 +  int n;
 +
 +  if (file_name == NULL)
 +    return NULL;
 +
 +  if (! _xdg_utf8_validate (file_name))
 +    return NULL;
 +
 +  base_name = _xdg_get_base_name (file_name);
 +  n = cache_glob_lookup_file_name (base_name, mime_types, 10);
 +
 +  if (n == 1)
 +    return mime_types[0];
 +
 +  if (!statbuf)
 +    {
 +      if (stat (file_name, &buf) != 0)
 +      return XDG_MIME_TYPE_UNKNOWN;
 +
 +      statbuf = &buf;
 +    }
 +
 +  if (statbuf->st_size == 0)
 +    return XDG_MIME_TYPE_EMPTY;
 +
 +  if (!S_ISREG (statbuf->st_mode))
 +    return XDG_MIME_TYPE_UNKNOWN;
 +
 +  /* FIXME: Need to make sure that max_extent isn't totally broken.  This could
 +   * be large and need getting from a stream instead of just reading it all
 +   * in. */
 +  max_extent = _xdg_mime_cache_get_max_buffer_extents ();
 +  data = malloc (max_extent);
 +  if (data == NULL)
 +    return XDG_MIME_TYPE_UNKNOWN;
 +        
 +  file = fopen (file_name, "r");
 +  if (file == NULL)
 +    {
 +      free (data);
 +      return XDG_MIME_TYPE_UNKNOWN;
 +    }
 +
 +  bytes_read = fread (data, 1, max_extent, file);
 +  if (ferror (file))
 +    {
 +      free (data);
 +      fclose (file);
 +      return XDG_MIME_TYPE_UNKNOWN;
 +    }
 +
 +  mime_type = cache_get_mime_type_for_data (data, bytes_read, NULL,
 +                                          mime_types, n);
 +
 +  if (!mime_type)
 +    mime_type = _xdg_binary_or_text_fallback (data, bytes_read);
 +
 +  free (data);
 +  fclose (file);
 +
 +  return mime_type;
 +}
 +
 +const char *
 +_xdg_mime_cache_get_mime_type_from_file_name (const char *file_name)
 +{
 +  const char *mime_type;
 +
 +  if (cache_glob_lookup_file_name (file_name, &mime_type, 1))
 +    return mime_type;
 +  else
 +    return XDG_MIME_TYPE_UNKNOWN;
 +}
 +
 +int
 +_xdg_mime_cache_get_mime_types_from_file_name (const char *file_name,
 +                                             const char  *mime_types[],
 +                                             int          n_mime_types)
 +{
 +  return cache_glob_lookup_file_name (file_name, mime_types, n_mime_types);
 +}
 +
 +#if 1
 +static int
 +ends_with (const char *str,
 +           const char *suffix)
 +{
 +  int length;
 +  int suffix_length;
 +
 +  length = strlen (str);
 +  suffix_length = strlen (suffix);
 +  if (length < suffix_length)
 +    return 0;
 +
 +  if (strcmp (str + length - suffix_length, suffix) == 0)
 +    return 1;
 +
 +  return 0;
 +}
 +
 +static int
 +is_super_type (const char *mime)
 +{
 +  return ends_with (mime, "/*");
 +}
 +#endif
 +
 +int
 +_xdg_mime_cache_mime_type_subclass (const char *mime,
 +                                  const char *base)
 +{
 +  const char *umime, *ubase;
 +
 +  xdg_uint32_t j;
 +  int i, min, max, med, cmp;
 +  
 +  umime = _xdg_mime_cache_unalias_mime_type (mime);
 +  ubase = _xdg_mime_cache_unalias_mime_type (base);
 +
 +  if (strcmp (umime, ubase) == 0)
 +    return 1;
 +
 +  /* We really want to handle text/ * in GtkFileFilter, so we just
 +   * turn on the supertype matching
 +   */
 +#if 1
 +  /* Handle supertypes */
 +  if (is_super_type (ubase) &&
 +      xdg_mime_media_type_equal (umime, ubase))
 +    return 1;
 +#endif
 +
 +  /*  Handle special cases text/plain and application/octet-stream */
 +  if (strcmp (ubase, "text/plain") == 0 && 
 +      strncmp (umime, "text/", 5) == 0)
 +    return 1;
 +
 +  if (strcmp (ubase, "application/octet-stream") == 0 &&
 +      strncmp (umime, "inode/", 6) != 0)
 +    return 1;
 + 
 +  for (i = 0; _caches[i]; i++)
 +    {
 +      XdgMimeCache *cache = _caches[i];
-                 if (_xdg_mime_cache_mime_type_subclass (cache->buffer + parent_offset, ubase))
++      xdg_uint32_t list_offset;
++      xdg_uint32_t n_entries;
 +      xdg_uint32_t offset, n_parents, parent_offset;
 +
++      if (cache->buffer == NULL)
++        continue;
++
++      list_offset = GET_UINT32 (cache->buffer, 8);
++      n_entries = GET_UINT32 (cache->buffer, list_offset);
++
 +      min = 0; 
 +      max = n_entries - 1;
 +      while (max >= min)
 +      {
 +        med = (min + max)/2;
 +        
 +        offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * med);
 +        cmp = strcmp (cache->buffer + offset, umime);
 +        if (cmp < 0)
 +          min = med + 1;
 +        else if (cmp > 0)
 +          max = med - 1;
 +        else
 +          {
 +            offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * med + 4);
 +            n_parents = GET_UINT32 (cache->buffer, offset);
 +            
 +            for (j = 0; j < n_parents; j++)
 +              {
 +                parent_offset = GET_UINT32 (cache->buffer, offset + 4 + 4 * j);
-   
-       xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 8);
-       xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
++                if (strcmp (cache->buffer + parent_offset, mime) != 0 &&
++                    strcmp (cache->buffer + parent_offset, umime) != 0 &&
++                    _xdg_mime_cache_mime_type_subclass (cache->buffer + parent_offset, ubase))
 +                  return 1;
 +              }
 +
 +            break;
 +          }
 +      }
 +    }
 +
 +  return 0;
 +}
 +
 +const char *
 +_xdg_mime_cache_unalias_mime_type (const char *mime)
 +{
 +  const char *lookup;
 +  
 +  lookup = cache_alias_lookup (mime);
 +  
 +  if (lookup)
 +    return lookup;
 +  
 +  return mime;  
 +}
 +
 +char **
 +_xdg_mime_cache_list_mime_parents (const char *mime)
 +{
 +  int i, l, p;
 +  xdg_uint32_t j, k;
 +  char *all_parents[128]; /* we'll stop at 128 */ 
 +  char **result;
 +
 +  mime = xdg_mime_unalias_mime_type (mime);
 +
 +  p = 0;
 +  for (i = 0; _caches[i]; i++)
 +    {
 +      XdgMimeCache *cache = _caches[i];
-       xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, header);
-       xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
++      xdg_uint32_t list_offset;
++      xdg_uint32_t n_entries;
++
++      if (cache->buffer == NULL)
++        continue;
++
++      list_offset = GET_UINT32 (cache->buffer, 8);
++      n_entries = GET_UINT32 (cache->buffer, list_offset);
 +
 +      for (j = 0; j < n_entries; j++)
 +      {
 +        xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j);
 +        xdg_uint32_t parents_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j + 4);
 +
 +        if (strcmp (cache->buffer + mimetype_offset, mime) == 0)
 +          {
 +            xdg_uint32_t parent_mime_offset;
 +            xdg_uint32_t n_parents = GET_UINT32 (cache->buffer, parents_offset);
 +
 +            for (k = 0; k < n_parents && p < 127; k++)
 +              {
 +                parent_mime_offset = GET_UINT32 (cache->buffer, parents_offset + 4 + 4 * k);
 +
 +                /* Don't add same parent multiple times.
 +                 * This can happen for instance if the same type is listed in multiple directories
 +                 */
 +                for (l = 0; l < p; l++)
 +                  {
 +                    if (strcmp (all_parents[l], cache->buffer + parent_mime_offset) == 0)
 +                      break;
 +                  }
 +
 +                if (l == p)
 +                  all_parents[p++] = cache->buffer + parent_mime_offset;
 +              }
 +
 +            break;
 +          }
 +      }
 +    }
 +  all_parents[p++] = NULL;
 +  
 +  result = (char **) malloc (p * sizeof (char *));
 +  memcpy (result, all_parents, p * sizeof (char *));
 +
 +  return result;
 +}
 +
 +static const char *
 +cache_lookup_icon (const char *mime, int header)
 +{
 +  const char *ptr;
 +  int i, min, max, mid, cmp;
 +
 +  for (i = 0; _caches[i]; i++)
 +    {
 +      XdgMimeCache *cache = _caches[i];
++      xdg_uint32_t list_offset;
++      xdg_uint32_t n_entries;
 +      xdg_uint32_t offset;
 +
++      if (cache->buffer == NULL)
++        continue;
++
++      list_offset = GET_UINT32 (cache->buffer, header);
++      n_entries = GET_UINT32 (cache->buffer, list_offset);
++
 +      min = 0; 
 +      max = n_entries - 1;
 +      while (max >= min) 
 +        {
 +          mid = (min + max) / 2;
 +
 +          offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
 +          ptr = cache->buffer + offset;
 +          cmp = strcmp (ptr, mime);
 +         
 +          if (cmp < 0)
 +            min = mid + 1;
 +          else if (cmp > 0)
 +            max = mid - 1;
 +          else
 +            {
 +              offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
 +              return cache->buffer + offset;
 +            }
 +        }
 +    }
 +
 +  return NULL;
 +}
 +
 +const char *
 +_xdg_mime_cache_get_generic_icon (const char *mime)
 +{
 +  return cache_lookup_icon (mime, 36);
 +}
 +
 +const char *
 +_xdg_mime_cache_get_icon (const char *mime)
 +{
 +  return cache_lookup_icon (mime, 32);
 +}
 +
 +static void
 +dump_glob_node (XdgMimeCache *cache,
 +              xdg_uint32_t  offset,
 +              int           depth)
 +{
 +  xdg_unichar_t character;
 +  xdg_uint32_t mime_offset;
 +  xdg_uint32_t n_children;
 +  xdg_uint32_t child_offset;
 +  xdg_uint32_t k;
 +  int i;
 +
 +  character = GET_UINT32 (cache->buffer, offset);
 +  mime_offset = GET_UINT32 (cache->buffer, offset + 4);
 +  n_children = GET_UINT32 (cache->buffer, offset + 8);
 +  child_offset = GET_UINT32 (cache->buffer, offset + 12);
 +  for (i = 0; i < depth; i++)
 +    printf (" ");
 +  printf ("%c", character);
 +  if (mime_offset)
 +    printf (" - %s", cache->buffer + mime_offset);
 +  printf ("\n");
 +  if (child_offset)
 +  {
 +    for (k = 0; k < n_children; k++)
 +      dump_glob_node (cache, child_offset + 20 * k, depth + 1);
 +  }
 +}
 +
 +void
 +_xdg_mime_cache_glob_dump (void)
 +{
 +  xdg_uint32_t i, j;
 +  for (i = 0; _caches[i]; i++)
 +  {
 +    XdgMimeCache *cache = _caches[i];
 +    xdg_uint32_t list_offset;
 +    xdg_uint32_t n_entries;
 +    xdg_uint32_t offset;
++
++    if (cache->buffer == NULL)
++      continue;
++
 +    list_offset = GET_UINT32 (cache->buffer, 16);
 +    n_entries = GET_UINT32 (cache->buffer, list_offset);
 +    offset = GET_UINT32 (cache->buffer, list_offset + 4);
 +    for (j = 0; j < n_entries; j++)
 +          dump_glob_node (cache, offset + 20 * j, 0);
 +  }
 +}
 +
 +
index 27f42d0ca17573f47e98ce0985d654987ac920eb,0000000000000000000000000000000000000000..48aa752b9d2a6c02303a48b9a4929788133381dc
mode 100644,000000..100644
--- /dev/null
@@@ -1,81 -1,0 +1,65 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimecache.h: Private file.  Datastructure for mmapped caches.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2005  Matthias Clasen <mclasen@redhat.com>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifndef __XDG_MIME_CACHE_H__
 +#define __XDG_MIME_CACHE_H__
 +
 +#include "xdgmime.h"
 +
 +typedef struct _XdgMimeCache XdgMimeCache;
 +
 +#ifdef XDG_PREFIX
 +#define _xdg_mime_cache_new_from_file                 XDG_RESERVED_ENTRY(cache_new_from_file)
 +#define _xdg_mime_cache_ref                           XDG_RESERVED_ENTRY(cache_ref)
 +#define _xdg_mime_cache_unref                         XDG_RESERVED_ENTRY(cache_unref)
 +#define _xdg_mime_cache_get_max_buffer_extents        XDG_RESERVED_ENTRY(cache_get_max_buffer_extents)
 +#define _xdg_mime_cache_get_mime_type_for_data        XDG_RESERVED_ENTRY(cache_get_mime_type_for_data)
 +#define _xdg_mime_cache_get_mime_type_for_file        XDG_RESERVED_ENTRY(cache_get_mime_type_for_file)
 +#define _xdg_mime_cache_get_mime_type_from_file_name  XDG_RESERVED_ENTRY(cache_get_mime_type_from_file_name)
 +#define _xdg_mime_cache_get_mime_types_from_file_name XDG_RESERVED_ENTRY(cache_get_mime_types_from_file_name)
 +#define _xdg_mime_cache_list_mime_parents             XDG_RESERVED_ENTRY(cache_list_mime_parents)
 +#define _xdg_mime_cache_mime_type_subclass            XDG_RESERVED_ENTRY(cache_mime_type_subclass)
 +#define _xdg_mime_cache_unalias_mime_type             XDG_RESERVED_ENTRY(cache_unalias_mime_type)
 +#define _xdg_mime_cache_get_icon                      XDG_RESERVED_ENTRY(cache_get_icon)
 +#define _xdg_mime_cache_get_generic_icon              XDG_RESERVED_ENTRY(cache_get_generic_icon)
 +#define _xdg_mime_cache_glob_dump                     XDG_RESERVED_ENTRY(cache_glob_dump)
 +#endif
 +
 +extern XdgMimeCache **_caches;
 +
 +XdgMimeCache *_xdg_mime_cache_new_from_file (const char   *file_name);
 +XdgMimeCache *_xdg_mime_cache_ref           (XdgMimeCache *cache);
 +void          _xdg_mime_cache_unref         (XdgMimeCache *cache);
 +
 +
 +const char  *_xdg_mime_cache_get_mime_type_for_data       (const void *data,
 +                                                         size_t      len,
 +                                                         int        *result_prio);
 +const char  *_xdg_mime_cache_get_mime_type_for_file       (const char  *file_name,
 +                                                         struct stat *statbuf);
 +int          _xdg_mime_cache_get_mime_types_from_file_name (const char *file_name,
 +                                                          const char  *mime_types[],
 +                                                          int          n_mime_types);
 +const char  *_xdg_mime_cache_get_mime_type_from_file_name (const char *file_name);
 +int          _xdg_mime_cache_is_valid_mime_type           (const char *mime_type);
 +int          _xdg_mime_cache_mime_type_equal              (const char *mime_a,
 +                                                         const char *mime_b);
 +int          _xdg_mime_cache_media_type_equal             (const char *mime_a,
 +                                                         const char *mime_b);
 +int          _xdg_mime_cache_mime_type_subclass           (const char *mime_a,
 +                                                         const char *mime_b);
 +char       **_xdg_mime_cache_list_mime_parents                  (const char *mime);
 +const char  *_xdg_mime_cache_unalias_mime_type            (const char *mime);
 +int          _xdg_mime_cache_get_max_buffer_extents       (void);
 +const char  *_xdg_mime_cache_get_icon                     (const char *mime);
 +const char  *_xdg_mime_cache_get_generic_icon             (const char *mime);
 +void         _xdg_mime_cache_glob_dump                    (void);
 +
 +#endif /* __XDG_MIME_CACHE_H__ */
index 5071418cc4a79d17f51b8168d2a21ec630b48dd8,0000000000000000000000000000000000000000..a07305cc2a466a01fbf50e69f9a409acbba99c89
mode 100644,000000..100644
--- /dev/null
@@@ -1,691 -1,0 +1,675 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimeglob.c: Private file.  Datastructure for storing the globs.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2003  Red Hat, Inc.
 + * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "xdgmimeglob.h"
 +#include "xdgmimeint.h"
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <assert.h>
 +#include <string.h>
 +#include <fnmatch.h>
 +
 +#ifndef       FALSE
 +#define       FALSE   (0)
 +#endif
 +
 +#ifndef       TRUE
 +#define       TRUE    (!FALSE)
 +#endif
 +
 +typedef struct XdgGlobHashNode XdgGlobHashNode;
 +typedef struct XdgGlobList XdgGlobList;
 +
 +struct XdgGlobHashNode
 +{
 +  xdg_unichar_t character;
 +  const char *mime_type;
 +  int weight;
 +  int case_sensitive;
 +  XdgGlobHashNode *next;
 +  XdgGlobHashNode *child;
 +};
 +struct XdgGlobList
 +{
 +  const char *data;
 +  const char *mime_type;
 +  int weight;
 +  int case_sensitive;
 +  XdgGlobList *next;
 +};
 +
 +struct XdgGlobHash
 +{
 +  XdgGlobList *literal_list;
 +  XdgGlobHashNode *simple_node;
 +  XdgGlobList *full_list;
 +};
 +
 +
 +/* XdgGlobList
 + */
 +static XdgGlobList *
 +_xdg_glob_list_new (void)
 +{
 +  XdgGlobList *new_element;
 +
 +  new_element = calloc (1, sizeof (XdgGlobList));
 +
 +  return new_element;
 +}
 +
 +/* Frees glob_list and all of its children */
 +static void
 +_xdg_glob_list_free (XdgGlobList *glob_list)
 +{
 +  XdgGlobList *ptr, *next;
 +
 +  ptr = glob_list;
 +
 +  while (ptr != NULL)
 +    {
 +      next = ptr->next;
 +
 +      if (ptr->data)
 +      free ((void *) ptr->data);
 +      if (ptr->mime_type)
 +      free ((void *) ptr->mime_type);
 +      free (ptr);
 +
 +      ptr = next;
 +    }
 +}
 +
 +static XdgGlobList *
 +_xdg_glob_list_append (XdgGlobList *glob_list,
 +                     void        *data,
 +                     const char  *mime_type,
 +                     int          weight,
 +                     int          case_sensitive)
 +{
 +  XdgGlobList *new_element;
 +  XdgGlobList *tmp_element;
 +
 +  tmp_element = glob_list;
 +  while (tmp_element != NULL)
 +    {
 +      if (strcmp (tmp_element->data, data) == 0 &&
 +        strcmp (tmp_element->mime_type, mime_type) == 0)
 +      return glob_list;
 +
 +      tmp_element = tmp_element->next;
 +    }
 +
 +  new_element = _xdg_glob_list_new ();
 +  new_element->data = data;
 +  new_element->mime_type = mime_type;
 +  new_element->weight = weight;
 +  new_element->case_sensitive = case_sensitive;
 +  if (glob_list == NULL)
 +    return new_element;
 +
 +  tmp_element = glob_list;
 +  while (tmp_element->next != NULL)
 +    tmp_element = tmp_element->next;
 +
 +  tmp_element->next = new_element;
 +
 +  return glob_list;
 +}
 +
 +/* XdgGlobHashNode
 + */
 +
 +static XdgGlobHashNode *
 +_xdg_glob_hash_node_new (void)
 +{
 +  XdgGlobHashNode *glob_hash_node;
 +
 +  glob_hash_node = calloc (1, sizeof (XdgGlobHashNode));
 +
 +  return glob_hash_node;
 +}
 +
 +static void
 +_xdg_glob_hash_node_dump (XdgGlobHashNode *glob_hash_node,
 +                        int depth)
 +{
 +  int i;
 +  for (i = 0; i < depth; i++)
 +    printf (" ");
 +
 +  printf ("%c", (char)glob_hash_node->character);
 +  if (glob_hash_node->mime_type)
 +    printf (" - %s %d\n", glob_hash_node->mime_type, glob_hash_node->weight);
 +  else
 +    printf ("\n");
 +  if (glob_hash_node->child)
 +    _xdg_glob_hash_node_dump (glob_hash_node->child, depth + 1);
 +  if (glob_hash_node->next)
 +    _xdg_glob_hash_node_dump (glob_hash_node->next, depth);
 +}
 +
 +static XdgGlobHashNode *
 +_xdg_glob_hash_insert_ucs4 (XdgGlobHashNode *glob_hash_node,
 +                          xdg_unichar_t   *text,
 +                          const char      *mime_type,
 +                          int              weight,
 +                          int              case_sensitive)
 +{
 +  XdgGlobHashNode *node;
 +  xdg_unichar_t character;
 +
 +  character = text[0];
 +
 +  if ((glob_hash_node == NULL) ||
 +      (character < glob_hash_node->character))
 +    {
 +      node = _xdg_glob_hash_node_new ();
 +      node->character = character;
 +      node->next = glob_hash_node;
 +      glob_hash_node = node;
 +    }
 +  else if (character == glob_hash_node->character)
 +    {
 +      node = glob_hash_node;
 +    }
 +  else
 +    {
 +      XdgGlobHashNode *prev_node;
 +      int found_node = FALSE;
 +
 +      /* Look for the first character of text in glob_hash_node, and insert it if we
 +       * have to.*/
 +      prev_node = glob_hash_node;
 +      node = prev_node->next;
 +
 +      while (node != NULL)
 +      {
 +        if (character < node->character)
 +          {
 +            node = _xdg_glob_hash_node_new ();
 +            node->character = character;
 +            node->next = prev_node->next;
 +            prev_node->next = node;
 +
 +            found_node = TRUE;
 +            break;
 +          }
 +        else if (character == node->character)
 +          {
 +            found_node = TRUE;
 +            break;
 +          }
 +        prev_node = node;
 +        node = node->next;
 +      }
 +
 +      if (! found_node)
 +      {
 +        node = _xdg_glob_hash_node_new ();
 +        node->character = character;
 +        node->next = prev_node->next;
 +        prev_node->next = node;
 +      }
 +    }
 +
 +  text++;
 +  if (*text == 0)
 +    {
 +      if (node->mime_type)
 +      {
 +        if (strcmp (node->mime_type, mime_type) != 0)
 +          {
 +            XdgGlobHashNode *child;
 +            int found_node = FALSE;
 +
 +            child = node->child;
 +            while (child && child->character == 0)
 +              {
 +                if (strcmp (child->mime_type, mime_type) == 0)
 +                  {
 +                    found_node = TRUE;
 +                    break;
 +                  }
 +                child = child->next;
 +              }
 +
 +            if (!found_node)
 +              {
 +                child = _xdg_glob_hash_node_new ();
 +                child->character = 0;
 +                child->mime_type = strdup (mime_type);
 +                child->weight = weight;
 +                child->case_sensitive = case_sensitive;
 +                child->child = NULL;
 +                child->next = node->child;
 +                node->child = child;
 +              }
 +          }
 +      }
 +      else
 +      {
 +        node->mime_type = strdup (mime_type);
 +        node->weight = weight;
 +        node->case_sensitive = case_sensitive;
 +      }
 +    }
 +  else
 +    {
 +      node->child = _xdg_glob_hash_insert_ucs4 (node->child, text, mime_type, weight, case_sensitive);
 +    }
 +  return glob_hash_node;
 +}
 +
 +/* glob must be valid UTF-8 */
 +static XdgGlobHashNode *
 +_xdg_glob_hash_insert_text (XdgGlobHashNode *glob_hash_node,
 +                          const char      *text,
 +                          const char      *mime_type,
 +                          int              weight,
 +                          int              case_sensitive)
 +{
 +  XdgGlobHashNode *node;
 +  xdg_unichar_t *unitext;
 +  int len;
 +
 +  unitext = _xdg_convert_to_ucs4 (text, &len);
 +  _xdg_reverse_ucs4 (unitext, len);
 +  node = _xdg_glob_hash_insert_ucs4 (glob_hash_node, unitext, mime_type, weight, case_sensitive);
 +  free (unitext);
 +  return node;
 +}
 +
 +typedef struct {
 +  const char *mime;
 +  int weight;
 +} MimeWeight;
 +
 +static int
 +_xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode *glob_hash_node,
 +                                    const char      *file_name,
 +                                    int              len,
 +                                    int              case_sensitive_check,
 +                                    MimeWeight       mime_types[],
 +                                    int              n_mime_types)
 +{
 +  int n;
 +  XdgGlobHashNode *node;
 +  xdg_unichar_t character;
 +
 +  if (glob_hash_node == NULL)
 +    return 0;
 +
 +  character = file_name[len - 1];
 +
 +  for (node = glob_hash_node; node && character >= node->character; node = node->next)
 +    {
 +      if (character == node->character)
 +        {
 +          len--;
 +          n = 0;
 +          if (len > 0) 
 +          {
 +            n = _xdg_glob_hash_node_lookup_file_name (node->child,
 +                                                      file_name,
 +                                                      len,
 +                                                      case_sensitive_check,
 +                                                      mime_types,
 +                                                      n_mime_types);
 +          }
 +        if (n == 0)
 +          {
 +              if (node->mime_type &&
 +                (case_sensitive_check ||
 +                 !node->case_sensitive))
 +                {
 +                mime_types[n].mime = node->mime_type;
 +                mime_types[n].weight = node->weight;
 +                n++; 
 +                }
 +            node = node->child;
 +            while (n < n_mime_types && node && node->character == 0)
 +              {
 +                  if (node->mime_type &&
 +                    (case_sensitive_check ||
 +                     !node->case_sensitive))
 +                  {
 +                    mime_types[n].mime = node->mime_type;
 +                    mime_types[n].weight = node->weight;
 +                    n++;
 +                  }
 +                node = node->next;
 +              }
 +          }
 +        return n;
 +      }
 +    }
 +
 +  return 0;
 +}
 +
 +static int compare_mime_weight (const void *a, const void *b)
 +{
 +  const MimeWeight *aa = (const MimeWeight *)a;
 +  const MimeWeight *bb = (const MimeWeight *)b;
 +
 +  return bb->weight - aa->weight;
 +}
 +
 +#define ISUPPER(c)            ((c) >= 'A' && (c) <= 'Z')
 +static char *
 +ascii_tolower (const char *str)
 +{
 +  char *p, *lower;
 +
 +  lower = strdup (str);
 +  p = lower;
 +  while (*p != 0)
 +    {
 +      char c = *p;
 +      *p++ = ISUPPER (c) ? c - 'A' + 'a' : c;
 +    }
 +  return lower;
 +}
 +
 +int
 +_xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
 +                               const char  *file_name,
 +                               const char  *mime_types[],
 +                               int          n_mime_types)
 +{
 +  XdgGlobList *list;
 +  int i, n;
 +  MimeWeight mimes[10];
 +  int n_mimes = 10;
 +  int len;
 +  char *lower_case;
 +
 +  /* First, check the literals */
 +
 +  assert (file_name != NULL && n_mime_types > 0);
 +
 +  n = 0;
 +
 +  lower_case = ascii_tolower (file_name);
 +
 +  for (list = glob_hash->literal_list; list; list = list->next)
 +    {
 +      if (strcmp ((const char *)list->data, file_name) == 0)
 +      {
 +        mime_types[0] = list->mime_type;
 +        free (lower_case);
 +        return 1;
 +      }
 +    }
 +
 +  for (list = glob_hash->literal_list; list; list = list->next)
 +    {
 +      if (!list->case_sensitive &&
 +        strcmp ((const char *)list->data, lower_case) == 0)
 +      {
 +        mime_types[0] = list->mime_type;
 +        free (lower_case);
 +        return 1;
 +      }
 +    }
 +
 +
 +  len = strlen (file_name);
 +  n = _xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, lower_case, len, FALSE,
 +                                          mimes, n_mimes);
 +  if (n == 0)
 +    n = _xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, file_name, len, TRUE,
 +                                            mimes, n_mimes);
 +
 +  if (n == 0)
 +    {
 +      for (list = glob_hash->full_list; list && n < n_mime_types; list = list->next)
 +        {
 +          if (fnmatch ((const char *)list->data, file_name, 0) == 0)
 +          {
 +            mimes[n].mime = list->mime_type;
 +            mimes[n].weight = list->weight;
 +            n++;
 +          }
 +        }
 +    }
 +  free (lower_case);
 +
 +  qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight);
 +
 +  if (n_mime_types < n)
 +    n = n_mime_types;
 +
 +  for (i = 0; i < n; i++)
 +    mime_types[i] = mimes[i].mime;
 +
 +  return n;
 +}
 +
 +
 +
 +/* XdgGlobHash
 + */
 +
 +XdgGlobHash *
 +_xdg_glob_hash_new (void)
 +{
 +  XdgGlobHash *glob_hash;
 +
 +  glob_hash = calloc (1, sizeof (XdgGlobHash));
 +
 +  return glob_hash;
 +}
 +
 +
 +static void
 +_xdg_glob_hash_free_nodes (XdgGlobHashNode *node)
 +{
 +  if (node)
 +    {
 +      if (node->child)
 +       _xdg_glob_hash_free_nodes (node->child);
 +      if (node->next)
 +       _xdg_glob_hash_free_nodes (node->next);
 +      if (node->mime_type)
 +      free ((void *) node->mime_type);
 +      free (node);
 +    }
 +}
 +
 +void
 +_xdg_glob_hash_free (XdgGlobHash *glob_hash)
 +{
 +  _xdg_glob_list_free (glob_hash->literal_list);
 +  _xdg_glob_list_free (glob_hash->full_list);
 +  _xdg_glob_hash_free_nodes (glob_hash->simple_node);
 +  free (glob_hash);
 +}
 +
 +XdgGlobType
 +_xdg_glob_determine_type (const char *glob)
 +{
 +  const char *ptr;
 +  int maybe_in_simple_glob = FALSE;
 +  int first_char = TRUE;
 +
 +  ptr = glob;
 +
 +  while (*ptr != '\0')
 +    {
 +      if (*ptr == '*' && first_char)
 +      maybe_in_simple_glob = TRUE;
 +      else if (*ptr == '\\' || *ptr == '[' || *ptr == '?' || *ptr == '*')
 +        return XDG_GLOB_FULL;
 +
 +      first_char = FALSE;
 +      ptr = _xdg_utf8_next_char (ptr);
 +    }
 +  if (maybe_in_simple_glob)
 +    return XDG_GLOB_SIMPLE;
 +  else
 +    return XDG_GLOB_LITERAL;
 +}
 +
 +/* glob must be valid UTF-8 */
 +void
 +_xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
 +                          const char  *glob,
 +                          const char  *mime_type,
 +                          int          weight,
 +                          int          case_sensitive)
 +{
 +  XdgGlobType type;
 +
 +  assert (glob_hash != NULL);
 +  assert (glob != NULL);
 +
 +  type = _xdg_glob_determine_type (glob);
 +
 +  switch (type)
 +    {
 +    case XDG_GLOB_LITERAL:
 +      glob_hash->literal_list = _xdg_glob_list_append (glob_hash->literal_list, strdup (glob), strdup (mime_type), weight, case_sensitive);
 +      break;
 +    case XDG_GLOB_SIMPLE:
 +      glob_hash->simple_node = _xdg_glob_hash_insert_text (glob_hash->simple_node, glob + 1, mime_type, weight, case_sensitive);
 +      break;
 +    case XDG_GLOB_FULL:
 +      glob_hash->full_list = _xdg_glob_list_append (glob_hash->full_list, strdup (glob), strdup (mime_type), weight, case_sensitive);
 +      break;
 +    }
 +}
 +
 +void
 +_xdg_glob_hash_dump (XdgGlobHash *glob_hash)
 +{
 +  XdgGlobList *list;
 +  printf ("LITERAL STRINGS\n");
 +  if (!glob_hash || glob_hash->literal_list == NULL)
 +    {
 +      printf ("    None\n");
 +    }
 +  else
 +    {
 +      for (list = glob_hash->literal_list; list; list = list->next)
 +      printf ("    %s - %s %d\n", (char *)list->data, list->mime_type, list->weight);
 +    }
 +  printf ("\nSIMPLE GLOBS\n");
 +  if (!glob_hash || glob_hash->simple_node == NULL)
 +    {
 +      printf ("    None\n");
 +    }
 +  else
 +    {
 +      _xdg_glob_hash_node_dump (glob_hash->simple_node, 4);
 +    }
 +
 +  printf ("\nFULL GLOBS\n");
 +  if (!glob_hash || glob_hash->full_list == NULL)
 +    {
 +      printf ("    None\n");
 +    }
 +  else
 +    {
 +      for (list = glob_hash->full_list; list; list = list->next)
 +      printf ("    %s - %s %d\n", (char *)list->data, list->mime_type, list->weight);
 +    }
 +}
 +
 +
 +void
 +_xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
 +                             const char  *file_name,
 +                             int          version_two)
 +{
 +  FILE *glob_file;
 +  char line[255];
 +  char *p;
 +
 +  glob_file = fopen (file_name, "r");
 +
 +  if (glob_file == NULL)
 +    return;
 +
 +  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
 +   * Blah */
 +  while (fgets (line, 255, glob_file) != NULL)
 +    {
 +      char *colon;
 +      char *mimetype, *glob, *end;
 +      int weight;
 +      int case_sensitive;
 +
 +      if (line[0] == '#' || line[0] == 0)
 +      continue;
 +
 +      end = line + strlen(line) - 1;
 +      if (*end == '\n')
 +      *end = 0;
 +
 +      p = line;
 +      if (version_two)
 +      {
 +        colon = strchr (p, ':');
 +        if (colon == NULL)
 +          continue;
 +        *colon = 0;
 +          weight = atoi (p);
 +        p = colon + 1;
 +      }
 +      else
 +      weight = 50;
 +
 +      colon = strchr (p, ':');
 +      if (colon == NULL)
 +      continue;
 +      *colon = 0;
 +
 +      mimetype = p;
 +      p = colon + 1;
 +      glob = p;
 +      case_sensitive = FALSE;
 +
 +      colon = strchr (p, ':');
 +      if (version_two && colon != NULL)
 +      {
 +        char *flag;
 +
 +        /* We got flags */
 +        *colon = 0;
 +        p = colon + 1;
 +
 +        /* Flags end at next colon */
 +        colon = strchr (p, ':');
 +        if (colon != NULL)
 +          *colon = 0;
 +
 +        flag = strstr (p, "cs");
 +        if (flag != NULL &&
 +            /* Start or after comma */
 +            (flag == p ||
 +             flag[-1] == ',') &&
 +            /* ends with comma or end of string */
 +            (flag[2] == 0 ||
 +             flag[2] == ','))
 +          case_sensitive = TRUE;
 +      }
 +
 +      _xdg_glob_hash_append_glob (glob_hash, glob, mimetype, weight, case_sensitive);
 +    }
 +
 +  fclose (glob_file);
 +}
index 00182920d44250b837a118d20fdd2471692f92c8,0000000000000000000000000000000000000000..7ecee9a8ffb77446a84f09c94f590c831c74ae79
mode 100644,000000..100644
--- /dev/null
@@@ -1,70 -1,0 +1,54 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimeglob.h: Private file.  Datastructure for storing the globs.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2003  Red Hat, Inc.
 + * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifndef __XDG_MIME_GLOB_H__
 +#define __XDG_MIME_GLOB_H__
 +
 +#include "xdgmime.h"
 +
 +typedef struct XdgGlobHash XdgGlobHash;
 +
 +typedef enum
 +{
 +  XDG_GLOB_LITERAL, /* Makefile */
 +  XDG_GLOB_SIMPLE,  /* *.gif */
 +  XDG_GLOB_FULL     /* x*.[ch] */
 +} XdgGlobType;
 +
 +  
 +#ifdef XDG_PREFIX
 +#define _xdg_mime_glob_read_from_file         XDG_RESERVED_ENTRY(glob_read_from_file)
 +#define _xdg_glob_hash_new                    XDG_RESERVED_ENTRY(hash_new)
 +#define _xdg_glob_hash_free                   XDG_RESERVED_ENTRY(hash_free)
 +#define _xdg_glob_hash_lookup_file_name       XDG_RESERVED_ENTRY(hash_lookup_file_name)
 +#define _xdg_glob_hash_append_glob            XDG_RESERVED_ENTRY(hash_append_glob)
 +#define _xdg_glob_determine_type              XDG_RESERVED_ENTRY(determine_type)
 +#define _xdg_glob_hash_dump                   XDG_RESERVED_ENTRY(hash_dump)
 +#endif
 +
 +void         _xdg_mime_glob_read_from_file   (XdgGlobHash *glob_hash,
 +                                            const char  *file_name,
 +                                            int          version_two);
 +XdgGlobHash *_xdg_glob_hash_new              (void);
 +void         _xdg_glob_hash_free             (XdgGlobHash *glob_hash);
 +int          _xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
 +                                            const char  *text,
 +                                            const char  *mime_types[],
 +                                            int          n_mime_types);
 +void         _xdg_glob_hash_append_glob      (XdgGlobHash *glob_hash,
 +                                            const char  *glob,
 +                                            const char  *mime_type,
 +                                            int          weight,
 +                                            int          case_sensitive);
 +XdgGlobType  _xdg_glob_determine_type        (const char  *glob);
 +void         _xdg_glob_hash_dump             (XdgGlobHash *glob_hash);
 +
 +#endif /* __XDG_MIME_GLOB_H__ */
index 05c9473a680eb43cfb6965273eb21906ff6230d2,0000000000000000000000000000000000000000..4aaa564f1192592d6bd32f9732f6774ef7646f07
mode 100644,000000..100644
--- /dev/null
@@@ -1,183 -1,0 +1,167 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimeicon.c: Private file.  Datastructure for storing the aliases.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2008  Red Hat, Inc.
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "xdgmimeicon.h"
 +#include "xdgmimeint.h"
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <assert.h>
 +#include <string.h>
 +#include <fnmatch.h>
 +
 +#ifndef       FALSE
 +#define       FALSE   (0)
 +#endif
 +
 +#ifndef       TRUE
 +#define       TRUE    (!FALSE)
 +#endif
 +
 +typedef struct XdgIcon XdgIcon;
 +
 +struct XdgIcon 
 +{
 +  char *mime_type;
 +  char *icon_name;
 +};
 +
 +struct XdgIconList
 +{
 +  struct XdgIcon *icons;
 +  int n_icons;
 +};
 +
 +XdgIconList *
 +_xdg_mime_icon_list_new (void)
 +{
 +  XdgIconList *list;
 +
 +  list = malloc (sizeof (XdgIconList));
 +
 +  list->icons = NULL;
 +  list->n_icons = 0;
 +
 +  return list;
 +}
 +
 +void         
 +_xdg_mime_icon_list_free (XdgIconList *list)
 +{
 +  int i;
 +
 +  if (list->icons)
 +    {
 +      for (i = 0; i < list->n_icons; i++)
 +      {
 +        free (list->icons[i].mime_type);
 +        free (list->icons[i].icon_name);
 +      }
 +      free (list->icons);
 +    }
 +  free (list);
 +}
 +
 +static int
 +icon_entry_cmp (const void *v1, const void *v2)
 +{
 +  return strcmp (((XdgIcon *)v1)->mime_type, ((XdgIcon *)v2)->mime_type);
 +}
 +
 +const char  *
 +_xdg_mime_icon_list_lookup (XdgIconList *list,
 +                          const char  *mime_type)
 +{
 +  XdgIcon *entry;
 +  XdgIcon key;
 +
 +  if (list->n_icons > 0)
 +    {
 +      key.mime_type = (char *)mime_type;
 +      key.icon_name = NULL;
 +
 +      entry = bsearch (&key, list->icons, list->n_icons,
 +                     sizeof (XdgIcon), icon_entry_cmp);
 +      if (entry)
 +        return entry->icon_name;
 +    }
 +
 +  return NULL;
 +}
 +
 +void
 +_xdg_mime_icon_read_from_file (XdgIconList *list,
 +                             const char   *file_name)
 +{
 +  FILE *file;
 +  char line[255];
 +  int alloc;
 +
 +  file = fopen (file_name, "r");
 +
 +  if (file == NULL)
 +    return;
 +
 +  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
 +   * Blah */
 +  alloc = list->n_icons + 16;
 +  list->icons = realloc (list->icons, alloc * sizeof (XdgIcon));
 +  while (fgets (line, 255, file) != NULL)
 +    {
 +      char *sep;
 +      if (line[0] == '#')
 +      continue;
 +
 +      sep = strchr (line, ':');
 +      if (sep == NULL)
 +      continue;
 +      *(sep++) = '\000';
 +      sep[strlen (sep) -1] = '\000';
 +      if (list->n_icons == alloc)
 +      {
 +        alloc <<= 1;
 +        list->icons = realloc (list->icons, 
 +                                 alloc * sizeof (XdgIcon));
 +      }
 +      list->icons[list->n_icons].mime_type = strdup (line);
 +      list->icons[list->n_icons].icon_name = strdup (sep);
 +      list->n_icons++;
 +    }
 +  list->icons = realloc (list->icons, 
 +                         list->n_icons * sizeof (XdgIcon));
 +
 +  fclose (file);  
 +  
 +  if (list->n_icons > 1)
 +    qsort (list->icons, list->n_icons, 
 +           sizeof (XdgIcon), icon_entry_cmp);
 +}
 +
 +
 +void
 +_xdg_mime_icon_list_dump (XdgIconList *list)
 +{
 +  int i;
 +
 +  if (list->icons)
 +    {
 +      for (i = 0; i < list->n_icons; i++)
 +      {
 +        printf ("%s %s\n", 
 +                list->icons[i].mime_type,
 +                list->icons[i].icon_name);
 +      }
 +    }
 +}
 +
 +
index b5f25835db0676d36b2d07d4f51fe8928c3970f8,0000000000000000000000000000000000000000..f7244305aaacf0da4994c071b88421905b0b0e18
mode 100644,000000..100644
--- /dev/null
@@@ -1,50 -1,0 +1,34 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimeicon.h: Private file.  Datastructure for storing the aliases.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2008  Red Hat, Inc.
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifndef __XDG_MIME_ICON_H__
 +#define __XDG_MIME_ICON_H__
 +
 +#include "xdgmime.h"
 +
 +typedef struct XdgIconList XdgIconList;
 +
 +#ifdef XDG_PREFIX
 +#define _xdg_mime_icon_read_from_file        XDG_ENTRY(icon_read_from_file)
 +#define _xdg_mime_icon_list_new              XDG_ENTRY(icon_list_new)
 +#define _xdg_mime_icon_list_free             XDG_ENTRY(icon_list_free)
 +#define _xdg_mime_icon_list_lookup           XDG_ENTRY(icon_list_lookup)
 +#define _xdg_mime_icon_list_dump             XDG_ENTRY(icon_list_dump)
 +#endif
 +
 +void          _xdg_mime_icon_read_from_file (XdgIconList *list,
 +                                          const char   *file_name);
 +XdgIconList  *_xdg_mime_icon_list_new       (void);
 +void          _xdg_mime_icon_list_free      (XdgIconList *list);
 +const char   *_xdg_mime_icon_list_lookup    (XdgIconList *list,
 +                                           const char  *mime);
 +void          _xdg_mime_icon_list_dump      (XdgIconList *list);
 +
 +#endif /* __XDG_MIME_ICON_H__ */
index 5eaa7154e2cc88698a3c1c17dbec6bd456cd8d65,0000000000000000000000000000000000000000..0655fa0b1097d62e2a957cb5d4aabb1a012650db
mode 100644,000000..100644
--- /dev/null
@@@ -1,206 -1,0 +1,190 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimeint.c: Internal defines and functions.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2003  Red Hat, Inc.
 + * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "xdgmimeint.h"
 +#include <ctype.h>
 +#include <string.h>
 +
 +#ifndef       FALSE
 +#define       FALSE   (0)
 +#endif
 +
 +#ifndef       TRUE
 +#define       TRUE    (!FALSE)
 +#endif
 +
 +static const char _xdg_utf8_skip_data[256] = {
 +  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 +  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 +  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 +  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 +  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 +  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 +  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
 +  3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
 +};
 +
 +const char * const _xdg_utf8_skip = _xdg_utf8_skip_data;
 +
 +
 +
 +/* Returns the number of unprocessed characters. */
 +xdg_unichar_t
 +_xdg_utf8_to_ucs4(const char *source)
 +{
 +  xdg_unichar_t ucs32;
 +  if( ! ( *source & 0x80 ) )
 +    {
 +      ucs32 = *source;
 +    }
 +  else
 +    {
 +      int bytelength = 0;
 +      xdg_unichar_t result;
 +      if ( ! (*source & 0x40) )
 +      {
 +        ucs32 = *source;
 +      }
 +      else
 +      {
 +        if ( ! (*source & 0x20) )
 +          {
 +            result = *source++ & 0x1F;
 +            bytelength = 2;
 +          }
 +        else if ( ! (*source & 0x10) )
 +          {
 +            result = *source++ & 0x0F;
 +            bytelength = 3;
 +          }
 +        else if ( ! (*source & 0x08) )
 +          {
 +            result = *source++ & 0x07;
 +            bytelength = 4;
 +          }
 +        else if ( ! (*source & 0x04) )
 +          {
 +            result = *source++ & 0x03;
 +            bytelength = 5;
 +          }
 +        else if ( ! (*source & 0x02) )
 +          {
 +            result = *source++ & 0x01;
 +            bytelength = 6;
 +          }
 +        else
 +          {
 +            result = *source++;
 +            bytelength = 1;
 +          }
 +
 +        for ( bytelength --; bytelength > 0; bytelength -- )
 +          {
 +            result <<= 6;
 +            result |= *source++ & 0x3F;
 +          }
 +        ucs32 = result;
 +      }
 +    }
 +  return ucs32;
 +}
 +
 +
 +/* hullo.  this is great code.  don't rewrite it */
 +
 +xdg_unichar_t
 +_xdg_ucs4_to_lower (xdg_unichar_t source)
 +{
 +  /* FIXME: Do a real to_upper sometime */
 +  /* CaseFolding-3.2.0.txt has a table of rules. */
 +  if ((source & 0xFF) == source)
 +    return (xdg_unichar_t) tolower ((unsigned char) source);
 +  return source;
 +}
 +
 +int
 +_xdg_utf8_validate (const char *source)
 +{
 +  /* FIXME: actually write */
 +  return TRUE;
 +}
 +
 +const char *
 +_xdg_get_base_name (const char *file_name)
 +{
 +  const char *base_name;
 +
 +  if (file_name == NULL)
 +    return NULL;
 +
 +  base_name = strrchr (file_name, '/');
 +
 +  if (base_name == NULL)
 +    return file_name;
 +  else
 +    return base_name + 1;
 +}
 +
 +xdg_unichar_t *
 +_xdg_convert_to_ucs4 (const char *source, int *len)
 +{
 +  xdg_unichar_t *out;
 +  int i;
 +  const char *p;
 +
 +  out = malloc (sizeof (xdg_unichar_t) * (strlen (source) + 1));
 +
 +  p = source;
 +  i = 0;
 +  while (*p) 
 +    {
 +      out[i++] = _xdg_utf8_to_ucs4 (p);
 +      p = _xdg_utf8_next_char (p); 
 +    }
 +  out[i] = 0;
 +  *len = i;
 + 
 +  return out;
 +}
 +
 +void
 +_xdg_reverse_ucs4 (xdg_unichar_t *source, int len)
 +{
 +  xdg_unichar_t c;
 +  int i;
 +
 +  for (i = 0; i < len - i - 1; i++) 
 +    {
 +      c = source[i]; 
 +      source[i] = source[len - i - 1];
 +      source[len - i - 1] = c;
 +    }
 +}
 +
 +const char *
 +_xdg_binary_or_text_fallback(const void *data, size_t len)
 +{
 +  unsigned char *chardata;
 +  size_t i;
 +
 +  chardata = (unsigned char *) data;
 +  for (i = 0; i < 128 && i < len; ++i)
 +    {
 +       if (chardata[i] < 32 && chardata[i] != 9 && chardata[i] != 10 && chardata[i] != 13)
 +         return XDG_MIME_TYPE_UNKNOWN; /* binary data */
 +    }
 +
 +  return XDG_MIME_TYPE_TEXTPLAIN;
 +}
index 9e8b2cb85a41555345db545e0e10f8a5bd466664,0000000000000000000000000000000000000000..041c4f489bb8ba9e51de2e810fa339052d81f1b4
mode 100644,000000..100644
--- /dev/null
@@@ -1,78 -1,0 +1,62 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimeint.h: Internal defines and functions.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2003  Red Hat, Inc.
 + * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifndef __XDG_MIME_INT_H__
 +#define __XDG_MIME_INT_H__
 +
 +#include "xdgmime.h"
 +
 +
 +#ifndef       FALSE
 +#define       FALSE (0)
 +#endif
 +
 +#ifndef       TRUE
 +#define       TRUE (!FALSE)
 +#endif
 +
 +/* FIXME: Needs to be configure check */
 +typedef unsigned int   xdg_unichar_t;
 +typedef unsigned char  xdg_uchar8_t;
 +typedef unsigned short xdg_uint16_t;
 +typedef unsigned int   xdg_uint32_t;
 +
 +#ifdef XDG_PREFIX
 +#define _xdg_utf8_skip       XDG_RESERVED_ENTRY(utf8_skip)
 +#define _xdg_utf8_to_ucs4    XDG_RESERVED_ENTRY(utf8_to_ucs4)
 +#define _xdg_ucs4_to_lower   XDG_RESERVED_ENTRY(ucs4_to_lower)
 +#define _xdg_utf8_validate   XDG_RESERVED_ENTRY(utf8_validate)
 +#define _xdg_get_base_name   XDG_RESERVED_ENTRY(get_base_name)
 +#define _xdg_convert_to_ucs4 XDG_RESERVED_ENTRY(convert_to_ucs4)
 +#define _xdg_reverse_ucs4    XDG_RESERVED_ENTRY(reverse_ucs4)
 +#endif
 +
 +#define SWAP_BE16_TO_LE16(val) (xdg_uint16_t)(((xdg_uint16_t)(val) << 8)|((xdg_uint16_t)(val) >> 8))
 +
 +#define SWAP_BE32_TO_LE32(val) (xdg_uint32_t)((((xdg_uint32_t)(val) & 0xFF000000U) >> 24) |   \
 +                                            (((xdg_uint32_t)(val) & 0x00FF0000U) >> 8) |      \
 +                                            (((xdg_uint32_t)(val) & 0x0000FF00U) << 8) |      \
 +                                            (((xdg_uint32_t)(val) & 0x000000FFU) << 24))
 +/* UTF-8 utils
 + */
 +extern const char *const _xdg_utf8_skip;
 +#define _xdg_utf8_next_char(p) (char *)((p) + _xdg_utf8_skip[*(unsigned char *)(p)])
 +#define _xdg_utf8_char_size(p) (int) (_xdg_utf8_skip[*(unsigned char *)(p)])
 +
 +xdg_unichar_t  _xdg_utf8_to_ucs4  (const char    *source);
 +xdg_unichar_t  _xdg_ucs4_to_lower (xdg_unichar_t  source);
 +int            _xdg_utf8_validate (const char    *source);
 +xdg_unichar_t *_xdg_convert_to_ucs4 (const char *source, int *len);
 +void           _xdg_reverse_ucs4 (xdg_unichar_t *source, int len);
 +const char    *_xdg_get_base_name (const char    *file_name);
 +const char    *_xdg_binary_or_text_fallback(const void *data, size_t len);
 +
 +#endif /* __XDG_MIME_INT_H__ */
index fd49fa8e682de9c69571c626e59b3e4d35c5a2b3,0000000000000000000000000000000000000000..98a1274c87f3abc1fb39acd45f0e95654a71df43
mode 100644,000000..100644
--- /dev/null
@@@ -1,816 -1,0 +1,819 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimemagic.: Private file.  Datastructure for storing magic files.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2003  Red Hat, Inc.
 + * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <assert.h>
 +#include "xdgmimemagic.h"
 +#include "xdgmimeint.h"
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <ctype.h>
 +#include <errno.h>
 +#include <limits.h>
 +
 +#ifndef       FALSE
 +#define       FALSE   (0)
 +#endif
 +
 +#ifndef       TRUE
 +#define       TRUE    (!FALSE)
 +#endif
 +
 +#if !defined getc_unlocked && !defined HAVE_GETC_UNLOCKED
 +# define getc_unlocked(fp) getc (fp)
 +#endif
 +
 +typedef struct XdgMimeMagicMatch XdgMimeMagicMatch;
 +typedef struct XdgMimeMagicMatchlet XdgMimeMagicMatchlet;
 +
 +typedef enum
 +{
 +  XDG_MIME_MAGIC_SECTION,
 +  XDG_MIME_MAGIC_MAGIC,
 +  XDG_MIME_MAGIC_ERROR,
 +  XDG_MIME_MAGIC_EOF
 +} XdgMimeMagicState;
 +
 +struct XdgMimeMagicMatch
 +{
 +  const char *mime_type;
 +  int priority;
 +  XdgMimeMagicMatchlet *matchlet;
 +  XdgMimeMagicMatch *next;
 +};
 +
 +
 +struct XdgMimeMagicMatchlet
 +{
 +  int indent;
 +  int offset;
 +  unsigned int value_length;
 +  unsigned char *value;
 +  unsigned char *mask;
 +  unsigned int range_length;
 +  unsigned int word_size;
 +  XdgMimeMagicMatchlet *next;
 +};
 +
 +
 +struct XdgMimeMagic
 +{
 +  XdgMimeMagicMatch *match_list;
 +  int max_extent;
 +};
 +
 +static XdgMimeMagicMatch *
 +_xdg_mime_magic_match_new (void)
 +{
 +  return calloc (1, sizeof (XdgMimeMagicMatch));
 +}
 +
 +
 +static XdgMimeMagicMatchlet *
 +_xdg_mime_magic_matchlet_new (void)
 +{
 +  XdgMimeMagicMatchlet *matchlet;
 +
 +  matchlet = malloc (sizeof (XdgMimeMagicMatchlet));
++  if (matchlet == NULL)
++    return NULL;
 +
 +  matchlet->indent = 0;
 +  matchlet->offset = 0;
 +  matchlet->value_length = 0;
 +  matchlet->value = NULL;
 +  matchlet->mask = NULL;
 +  matchlet->range_length = 1;
 +  matchlet->word_size = 1;
 +  matchlet->next = NULL;
 +
 +  return matchlet;
 +}
 +
 +
 +static void
 +_xdg_mime_magic_matchlet_free (XdgMimeMagicMatchlet *mime_magic_matchlet)
 +{
 +  if (mime_magic_matchlet)
 +    {
 +      if (mime_magic_matchlet->next)
 +      _xdg_mime_magic_matchlet_free (mime_magic_matchlet->next);
 +      if (mime_magic_matchlet->value)
 +      free (mime_magic_matchlet->value);
 +      if (mime_magic_matchlet->mask)
 +      free (mime_magic_matchlet->mask);
 +      free (mime_magic_matchlet);
 +    }
 +}
 +
 +
 +/* Frees mime_magic_match and the remainder of its list
 + */
 +static void
 +_xdg_mime_magic_match_free (XdgMimeMagicMatch *mime_magic_match)
 +{
 +  XdgMimeMagicMatch *ptr, *next;
 +
 +  ptr = mime_magic_match;
 +  while (ptr)
 +    {
 +      next = ptr->next;
 +
 +      if (ptr->mime_type)
 +      free ((void *) ptr->mime_type);
 +      if (ptr->matchlet)
 +      _xdg_mime_magic_matchlet_free (ptr->matchlet);
 +      free (ptr);
 +
 +      ptr = next;
 +    }
 +}
 +
 +/* Reads in a hunk of data until a newline character or a '\000' is hit.  The
 + * returned string is null terminated, and doesn't include the newline.
 + */
 +static unsigned char *
 +_xdg_mime_magic_read_to_newline (FILE *magic_file,
 +                               int  *end_of_file)
 +{
 +  unsigned char *retval;
 +  int c;
 +  int len, pos;
 +
 +  len = 128;
 +  pos = 0;
 +  retval = malloc (len);
 +  *end_of_file = FALSE;
 +
 +  while (TRUE)
 +    {
 +      c = getc_unlocked (magic_file);
 +      if (c == EOF)
 +      {
 +        *end_of_file = TRUE;
 +        break;
 +      }
 +      if (c == '\n' || c == '\000')
 +      break;
 +      retval[pos++] = (unsigned char) c;
 +      if (pos % 128 == 127)
 +      {
 +        len = len + 128;
 +        retval = realloc (retval, len);
 +      }
 +    }
 +
 +  retval[pos] = '\000';
 +  return retval;
 +}
 +
 +/* Returns the number read from the file, or -1 if no number could be read.
 + */
 +static int
 +_xdg_mime_magic_read_a_number (FILE *magic_file,
 +                             int  *end_of_file)
 +{
 +  /* LONG_MAX is about 20 characters on my system */
 +#define MAX_NUMBER_SIZE 30
 +  char number_string[MAX_NUMBER_SIZE + 1];
 +  int pos = 0;
 +  int c;
 +  long retval = -1;
 +
 +  while (TRUE)
 +    {
 +      c = getc_unlocked (magic_file);
 +
 +      if (c == EOF)
 +      {
 +        *end_of_file = TRUE;
 +        break;
 +      }
 +      if (! isdigit (c))
 +      {
 +        ungetc (c, magic_file);
 +        break;
 +      }
 +      number_string[pos] = (char) c;
 +      pos++;
 +      if (pos == MAX_NUMBER_SIZE)
 +      break;
 +    }
 +  if (pos > 0)
 +    {
 +      number_string[pos] = '\000';
 +      errno = 0;
 +      retval = strtol (number_string, NULL, 10);
 +
 +      if ((retval < INT_MIN) || (retval > INT_MAX) || (errno != 0))
 +      return -1;
 +    }
 +
 +  return retval;
 +}
 +
 +/* Headers are of the format:
 + * [<priority>:<mime-type>]
 + */
 +static XdgMimeMagicState
 +_xdg_mime_magic_parse_header (FILE *magic_file, XdgMimeMagicMatch *match)
 +{
 +  int c;
 +  char *buffer;
 +  char *end_ptr;
 +  int end_of_file = 0;
 +
 +  assert (magic_file != NULL);
 +  assert (match != NULL);
 +
 +  c = getc_unlocked (magic_file);
 +  if (c == EOF)
 +    return XDG_MIME_MAGIC_EOF;
 +  if (c != '[')
 +    return XDG_MIME_MAGIC_ERROR;
 +
 +  match->priority = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
 +  if (end_of_file)
 +    return XDG_MIME_MAGIC_EOF;
 +  if (match->priority == -1)
 +    return XDG_MIME_MAGIC_ERROR;
 +
 +  c = getc_unlocked (magic_file);
 +  if (c == EOF)
 +    return XDG_MIME_MAGIC_EOF;
 +  if (c != ':')
 +    return XDG_MIME_MAGIC_ERROR;
 +
 +  buffer = (char *)_xdg_mime_magic_read_to_newline (magic_file, &end_of_file);
 +  if (end_of_file)
 +    {
 +      free (buffer);
 +      return XDG_MIME_MAGIC_EOF;
 +    }
 +
 +  end_ptr = buffer;
 +  while (*end_ptr != ']' && *end_ptr != '\000' && *end_ptr != '\n')
 +    end_ptr++;
 +  if (*end_ptr != ']')
 +    {
 +      free (buffer);
 +      return XDG_MIME_MAGIC_ERROR;
 +    }
 +  *end_ptr = '\000';
 +
 +  match->mime_type = strdup (buffer);
 +  free (buffer);
 +
 +  return XDG_MIME_MAGIC_MAGIC;
 +}
 +
 +static XdgMimeMagicState
 +_xdg_mime_magic_parse_error (FILE *magic_file)
 +{
 +  int c;
 +
 +  while (1)
 +    {
 +      c = getc_unlocked (magic_file);
 +      if (c == EOF)
 +      return XDG_MIME_MAGIC_EOF;
 +      if (c == '\n')
 +      return XDG_MIME_MAGIC_SECTION;
 +    }
 +}
 +
 +/* Headers are of the format:
 + * [ indent ] ">" start-offset "=" value
 + * [ "&" mask ] [ "~" word-size ] [ "+" range-length ] "\n"
 + */
 +static XdgMimeMagicState
 +_xdg_mime_magic_parse_magic_line (FILE              *magic_file,
 +                                XdgMimeMagicMatch *match)
 +{
 +  XdgMimeMagicMatchlet *matchlet;
 +  int c;
 +  int end_of_file;
 +  int indent = 0;
 +  size_t bytes_read;
 +
 +  assert (magic_file != NULL);
 +
 +  /* Sniff the buffer to make sure it's a valid line */
 +  c = getc_unlocked (magic_file);
 +  if (c == EOF)
 +    return XDG_MIME_MAGIC_EOF;
 +  else if (c == '[')
 +    {
 +      ungetc (c, magic_file);
 +      return XDG_MIME_MAGIC_SECTION;
 +    }
 +  else if (c == '\n')
 +    return XDG_MIME_MAGIC_MAGIC;
 +
 +  /* At this point, it must be a digit or a '>' */
 +  end_of_file = FALSE;
 +  if (isdigit (c))
 +    {
 +      ungetc (c, magic_file);
 +      indent = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
 +      if (end_of_file)
 +      return XDG_MIME_MAGIC_EOF;
 +      if (indent == -1)
 +      return XDG_MIME_MAGIC_ERROR;
 +      c = getc_unlocked (magic_file);
 +      if (c == EOF)
 +      return XDG_MIME_MAGIC_EOF;
 +    }
 +
 +  if (c != '>')
 +    return XDG_MIME_MAGIC_ERROR;
 +
 +  matchlet = _xdg_mime_magic_matchlet_new ();
++
++  /* OOM */
++  if (matchlet == NULL)
++    return XDG_MIME_MAGIC_ERROR;
++
 +  matchlet->indent = indent;
 +  matchlet->offset = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
 +  if (end_of_file)
 +    {
 +      _xdg_mime_magic_matchlet_free (matchlet);
 +      return XDG_MIME_MAGIC_EOF;
 +    }
 +  if (matchlet->offset == -1)
 +    {
 +      _xdg_mime_magic_matchlet_free (matchlet);
 +      return XDG_MIME_MAGIC_ERROR;
 +    }
 +  c = getc_unlocked (magic_file);
 +  if (c == EOF)
 +    {
 +      _xdg_mime_magic_matchlet_free (matchlet);
 +      return XDG_MIME_MAGIC_EOF;
 +    }
 +  else if (c != '=')
 +    {
 +      _xdg_mime_magic_matchlet_free (matchlet);
 +      return XDG_MIME_MAGIC_ERROR;
 +    }
 +
 +  /* Next two bytes determine how long the value is */
 +  matchlet->value_length = 0;
 +  c = getc_unlocked (magic_file);
 +  if (c == EOF)
 +    {
 +      _xdg_mime_magic_matchlet_free (matchlet);
 +      return XDG_MIME_MAGIC_EOF;
 +    }
 +  matchlet->value_length = c & 0xFF;
 +  matchlet->value_length = matchlet->value_length << 8;
 +
 +  c = getc_unlocked (magic_file);
 +  if (c == EOF)
 +    {
 +      _xdg_mime_magic_matchlet_free (matchlet);
 +      return XDG_MIME_MAGIC_EOF;
 +    }
 +  matchlet->value_length = matchlet->value_length + (c & 0xFF);
 +
 +  matchlet->value = malloc (matchlet->value_length);
 +
 +  /* OOM */
 +  if (matchlet->value == NULL)
 +    {
 +      _xdg_mime_magic_matchlet_free (matchlet);
 +      return XDG_MIME_MAGIC_ERROR;
 +    }
 +  bytes_read = fread (matchlet->value, 1, matchlet->value_length, magic_file);
 +  if (bytes_read != (size_t) matchlet->value_length)
 +    {
 +      _xdg_mime_magic_matchlet_free (matchlet);
 +      if (feof (magic_file))
 +      return XDG_MIME_MAGIC_EOF;
 +      else
 +      return XDG_MIME_MAGIC_ERROR;
 +    }
 +
 +  c = getc_unlocked (magic_file);
 +  if (c == '&')
 +    {
 +      matchlet->mask = malloc (matchlet->value_length);
 +      /* OOM */
 +      if (matchlet->mask == NULL)
 +      {
 +        _xdg_mime_magic_matchlet_free (matchlet);
 +        return XDG_MIME_MAGIC_ERROR;
 +      }
 +      bytes_read = fread (matchlet->mask, 1, matchlet->value_length, magic_file);
 +      if (bytes_read != (size_t) matchlet->value_length)
 +      {
 +        _xdg_mime_magic_matchlet_free (matchlet);
 +        if (feof (magic_file))
 +          return XDG_MIME_MAGIC_EOF;
 +        else
 +          return XDG_MIME_MAGIC_ERROR;
 +      }
 +      c = getc_unlocked (magic_file);
 +    }
 +
 +  if (c == '~')
 +    {
 +      matchlet->word_size = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
 +      if (end_of_file)
 +      {
 +        _xdg_mime_magic_matchlet_free (matchlet);
 +        return XDG_MIME_MAGIC_EOF;
 +      }
 +      if (matchlet->word_size != 0 &&
 +        matchlet->word_size != 1 &&
 +        matchlet->word_size != 2 &&
 +        matchlet->word_size != 4)
 +      {
 +        _xdg_mime_magic_matchlet_free (matchlet);
 +        return XDG_MIME_MAGIC_ERROR;
 +      }
 +      c = getc_unlocked (magic_file);
 +    }
 +
 +  if (c == '+')
 +    {
 +      matchlet->range_length = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
 +      if (end_of_file)
 +      {
 +        _xdg_mime_magic_matchlet_free (matchlet);
 +        return XDG_MIME_MAGIC_EOF;
 +      }
 +      if (matchlet->range_length == (unsigned int) -1)
 +      {
 +        _xdg_mime_magic_matchlet_free (matchlet);
 +        return XDG_MIME_MAGIC_ERROR;
 +      }
 +      c = getc_unlocked (magic_file);
 +    }
 +
 +
 +  if (c == '\n')
 +    {
 +      /* We clean up the matchlet, byte swapping if needed */
 +      if (matchlet->word_size > 1)
 +      {
++#if LITTLE_ENDIAN
 +        unsigned int i;
++#endif
 +        if (matchlet->value_length % matchlet->word_size != 0)
 +          {
 +            _xdg_mime_magic_matchlet_free (matchlet);
 +            return XDG_MIME_MAGIC_ERROR;
 +          }
 +        /* FIXME: need to get this defined in a <config.h> style file */
 +#if LITTLE_ENDIAN
 +        for (i = 0; i < matchlet->value_length; i = i + matchlet->word_size)
 +          {
 +            if (matchlet->word_size == 2)
 +              *((xdg_uint16_t *) matchlet->value + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->value + i)));
 +            else if (matchlet->word_size == 4)
 +              *((xdg_uint32_t *) matchlet->value + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->value + i)));
 +            if (matchlet->mask)
 +              {
 +                if (matchlet->word_size == 2)
 +                  *((xdg_uint16_t *) matchlet->mask + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->mask + i)));
 +                else if (matchlet->word_size == 4)
 +                  *((xdg_uint32_t *) matchlet->mask + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->mask + i)));
 +
 +              }
 +          }
 +#endif
 +      }
 +
 +      matchlet->next = match->matchlet;
 +      match->matchlet = matchlet;
 +
 +
 +      return XDG_MIME_MAGIC_MAGIC;
 +    }
 +
 +  _xdg_mime_magic_matchlet_free (matchlet);
 +  if (c == EOF)
 +    return XDG_MIME_MAGIC_EOF;
 +
 +  return XDG_MIME_MAGIC_ERROR;
 +}
 +
 +static int
 +_xdg_mime_magic_matchlet_compare_to_data (XdgMimeMagicMatchlet *matchlet,
 +                                        const void           *data,
 +                                        size_t                len)
 +{
 +  unsigned int i, j;
 +  for (i = matchlet->offset; i < matchlet->offset + matchlet->range_length; i++)
 +    {
 +      int valid_matchlet = TRUE;
 +
 +      if (i + matchlet->value_length > len)
 +      return FALSE;
 +
 +      if (matchlet->mask)
 +      {
 +        for (j = 0; j < matchlet->value_length; j++)
 +          {
 +            if ((matchlet->value[j] & matchlet->mask[j]) !=
 +                ((((unsigned char *) data)[j + i]) & matchlet->mask[j]))
 +              {
 +                valid_matchlet = FALSE;
 +                break;
 +              }
 +          }
 +      }
 +      else
 +      {
 +        for (j = 0; j <  matchlet->value_length; j++)
 +          {
 +            if (matchlet->value[j] != ((unsigned char *) data)[j + i])
 +              {
 +                valid_matchlet = FALSE;
 +                break;
 +              }
 +          }
 +      }
 +      if (valid_matchlet)
 +      return TRUE;
 +    }
 +  return FALSE;
 +}
 +
 +static int
 +_xdg_mime_magic_matchlet_compare_level (XdgMimeMagicMatchlet *matchlet,
 +                                      const void           *data,
 +                                      size_t                len,
 +                                      int                   indent)
 +{
 +  while ((matchlet != NULL) && (matchlet->indent == indent))
 +    {
 +      if (_xdg_mime_magic_matchlet_compare_to_data (matchlet, data, len))
 +      {
 +        if ((matchlet->next == NULL) ||
 +            (matchlet->next->indent <= indent))
 +          return TRUE;
 +
 +        if (_xdg_mime_magic_matchlet_compare_level (matchlet->next,
 +                                                    data,
 +                                                    len,
 +                                                    indent + 1))
 +          return TRUE;
 +      }
 +
 +      do
 +      {
 +        matchlet = matchlet->next;
 +      }
 +      while (matchlet && matchlet->indent > indent);
 +    }
 +
 +  return FALSE;
 +}
 +
 +static int
 +_xdg_mime_magic_match_compare_to_data (XdgMimeMagicMatch *match,
 +                                     const void        *data,
 +                                     size_t             len)
 +{
 +  return _xdg_mime_magic_matchlet_compare_level (match->matchlet, data, len, 0);
 +}
 +
 +static void
 +_xdg_mime_magic_insert_match (XdgMimeMagic      *mime_magic,
 +                            XdgMimeMagicMatch *match)
 +{
 +  XdgMimeMagicMatch *list;
 +
 +  if (mime_magic->match_list == NULL)
 +    {
 +      mime_magic->match_list = match;
 +      return;
 +    }
 +
 +  if (match->priority > mime_magic->match_list->priority)
 +    {
 +      match->next = mime_magic->match_list;
 +      mime_magic->match_list = match;
 +      return;
 +    }
 +
 +  list = mime_magic->match_list;
 +  while (list->next != NULL)
 +    {
 +      if (list->next->priority < match->priority)
 +      {
 +        match->next = list->next;
 +        list->next = match;
 +        return;
 +      }
 +      list = list->next;
 +    }
 +  list->next = match;
 +  match->next = NULL;
 +}
 +
 +XdgMimeMagic *
 +_xdg_mime_magic_new (void)
 +{
 +  return calloc (1, sizeof (XdgMimeMagic));
 +}
 +
 +void
 +_xdg_mime_magic_free (XdgMimeMagic *mime_magic)
 +{
 +  if (mime_magic) {
 +    _xdg_mime_magic_match_free (mime_magic->match_list);
 +    free (mime_magic);
 +  }
 +}
 +
 +int
 +_xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic)
 +{
 +  return mime_magic->max_extent;
 +}
 +
 +const char *
 +_xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
 +                           const void   *data,
 +                           size_t        len,
 +                           int           *result_prio,
 +                             const char   *mime_types[],
 +                             int           n_mime_types)
 +{
 +  XdgMimeMagicMatch *match;
 +  const char *mime_type;
 +  int n;
 +  int prio;
 +
 +  prio = 0;
 +  mime_type = NULL;
 +  for (match = mime_magic->match_list; match; match = match->next)
 +    {
 +      if (_xdg_mime_magic_match_compare_to_data (match, data, len))
 +      {
 +        prio = match->priority;
 +        mime_type = match->mime_type;
 +        break;
 +      }
 +      else 
 +      {
 +        for (n = 0; n < n_mime_types; n++)
 +          {
 +            if (mime_types[n] && 
 +                _xdg_mime_mime_type_equal (mime_types[n], match->mime_type))
 +              mime_types[n] = NULL;
 +          }
 +      }
 +    }
 +
 +  if (mime_type == NULL)
 +    {
 +      for (n = 0; n < n_mime_types; n++)
 +      {
 +        if (mime_types[n])
 +          mime_type = mime_types[n];
 +      }
 +    }
 +  
 +  if (result_prio)
 +    *result_prio = prio;
 +
 +  return mime_type;
 +}
 +
 +static void
 +_xdg_mime_update_mime_magic_extents (XdgMimeMagic *mime_magic)
 +{
 +  XdgMimeMagicMatch *match;
 +  int max_extent = 0;
 +
 +  for (match = mime_magic->match_list; match; match = match->next)
 +    {
 +      XdgMimeMagicMatchlet *matchlet;
 +
 +      for (matchlet = match->matchlet; matchlet; matchlet = matchlet->next)
 +      {
 +        int extent;
 +
 +        extent = matchlet->value_length + matchlet->offset + matchlet->range_length;
 +        if (max_extent < extent)
 +          max_extent = extent;
 +      }
 +    }
 +
 +  mime_magic->max_extent = max_extent;
 +}
 +
 +static XdgMimeMagicMatchlet *
 +_xdg_mime_magic_matchlet_mirror (XdgMimeMagicMatchlet *matchlets)
 +{
 +  XdgMimeMagicMatchlet *new_list;
 +  XdgMimeMagicMatchlet *tmp;
 +
 +  if ((matchlets == NULL) || (matchlets->next == NULL))
 +    return matchlets;
 +
 +  new_list = NULL;
 +  tmp = matchlets;
 +  while (tmp != NULL)
 +    {
 +      XdgMimeMagicMatchlet *matchlet;
 +
 +      matchlet = tmp;
 +      tmp = tmp->next;
 +      matchlet->next = new_list;
 +      new_list = matchlet;
 +    }
 +
 +  return new_list;
 +
 +}
 +
 +static void
 +_xdg_mime_magic_read_magic_file (XdgMimeMagic *mime_magic,
 +                               FILE         *magic_file)
 +{
 +  XdgMimeMagicState state;
 +  XdgMimeMagicMatch *match = NULL; /* Quiet compiler */
 +
 +  state = XDG_MIME_MAGIC_SECTION;
 +
 +  while (state != XDG_MIME_MAGIC_EOF)
 +    {
 +      switch (state)
 +      {
 +      case XDG_MIME_MAGIC_SECTION:
 +        match = _xdg_mime_magic_match_new ();
++
++        /* OOM */
++        if (match == NULL)
++          return;
++
 +        state = _xdg_mime_magic_parse_header (magic_file, match);
 +        if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
 +          _xdg_mime_magic_match_free (match);
 +        break;
 +      case XDG_MIME_MAGIC_MAGIC:
 +        state = _xdg_mime_magic_parse_magic_line (magic_file, match);
 +        if (state == XDG_MIME_MAGIC_SECTION ||
 +            (state == XDG_MIME_MAGIC_EOF && match->mime_type))
 +          {
 +            match->matchlet = _xdg_mime_magic_matchlet_mirror (match->matchlet);
 +            _xdg_mime_magic_insert_match (mime_magic, match);
 +          }
 +        else if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
 +          _xdg_mime_magic_match_free (match);
 +        break;
 +      case XDG_MIME_MAGIC_ERROR:
 +        state = _xdg_mime_magic_parse_error (magic_file);
++
++        /* After a parse error we can only be at EOF or reset to starting a
++         * new section. */
++        assert (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_SECTION);
++
 +        break;
 +      case XDG_MIME_MAGIC_EOF:
 +      default:
 +        /* Make the compiler happy */
 +        assert (0);
 +      }
 +    }
 +  _xdg_mime_update_mime_magic_extents (mime_magic);
 +}
 +
 +void
 +_xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
 +                              const char   *file_name)
 +{
 +  FILE *magic_file;
 +  char header[12];
 +
 +  magic_file = fopen (file_name, "r");
 +
 +  if (magic_file == NULL)
 +    return;
 +
 +  if (fread (header, 1, 12, magic_file) == 12)
 +    {
 +      if (memcmp ("MIME-Magic\0\n", header, 12) == 0)
 +        _xdg_mime_magic_read_magic_file (mime_magic, magic_file);
 +    }
 +
 +  fclose (magic_file);
 +}
index 35c8039c8eef4dd8859a7bf690c31ef5d8eb41f5,0000000000000000000000000000000000000000..81125c2a082f3654310dd171fd5fabe4e0a08013
mode 100644,000000..100644
--- /dev/null
@@@ -1,57 -1,0 +1,41 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimemagic.h: Private file.  Datastructure for storing the magic files.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2003  Red Hat, Inc.
 + * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifndef __XDG_MIME_MAGIC_H__
 +#define __XDG_MIME_MAGIC_H__
 +
 +#include <unistd.h>
 +#include "xdgmime.h"
 +typedef struct XdgMimeMagic XdgMimeMagic;
 +
 +#ifdef XDG_PREFIX
 +#define _xdg_mime_glob_read_from_file             XDG_RESERVED_ENTRY(glob_read_from_file)
 +#define _xdg_mime_magic_new                       XDG_RESERVED_ENTRY(magic_new)
 +#define _xdg_mime_magic_read_from_file            XDG_RESERVED_ENTRY(magic_read_from_file)
 +#define _xdg_mime_magic_free                      XDG_RESERVED_ENTRY(magic_free)
 +#define _xdg_mime_magic_get_buffer_extents        XDG_RESERVED_ENTRY(magic_get_buffer_extents)
 +#define _xdg_mime_magic_lookup_data               XDG_RESERVED_ENTRY(magic_lookup_data)
 +#endif
 +
 +
 +XdgMimeMagic *_xdg_mime_magic_new                (void);
 +void          _xdg_mime_magic_read_from_file     (XdgMimeMagic *mime_magic,
 +                                                const char   *file_name);
 +void          _xdg_mime_magic_free               (XdgMimeMagic *mime_magic);
 +int           _xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic);
 +const char   *_xdg_mime_magic_lookup_data        (XdgMimeMagic *mime_magic,
 +                                                const void   *data,
 +                                                size_t        len,
 +                                                int          *result_prio,
 +                                                const char   *mime_types[],
 +                                                int           n_mime_types);
 +
 +#endif /* __XDG_MIME_MAGIC_H__ */
index 511bbacbc19c19b59cbcf359499aa492e3bc6cca,0000000000000000000000000000000000000000..e03a78f6caf197dfc7d4df50aabc8f4067940339
mode 100644,000000..100644
--- /dev/null
@@@ -1,219 -1,0 +1,204 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimealias.c: Private file.  Datastructure for storing the hierarchy.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2004  Red Hat, Inc.
 + * Copyright (C) 2004  Matthias Clasen <mclasen@redhat.com>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "xdgmimeparent.h"
 +#include "xdgmimeint.h"
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <assert.h>
 +#include <string.h>
 +#include <fnmatch.h>
 +
 +#ifndef       FALSE
 +#define       FALSE   (0)
 +#endif
 +
 +#ifndef       TRUE
 +#define       TRUE    (!FALSE)
 +#endif
 +
 +typedef struct XdgMimeParents XdgMimeParents;
 +
 +struct XdgMimeParents
 +{
 +  char *mime;
 +  char **parents;
 +  int n_parents;
 +};
 +
 +struct XdgParentList
 +{
 +  struct XdgMimeParents *parents;
 +  int n_mimes;
 +};
 +
 +XdgParentList *
 +_xdg_mime_parent_list_new (void)
 +{
 +  XdgParentList *list;
 +
 +  list = malloc (sizeof (XdgParentList));
 +
 +  list->parents = NULL;
 +  list->n_mimes = 0;
 +
 +  return list;
 +}
 +
 +void         
 +_xdg_mime_parent_list_free (XdgParentList *list)
 +{
 +  int i;
 +  char **p;
 +
 +  if (list->parents)
 +    {
 +      for (i = 0; i < list->n_mimes; i++)
 +      {
 +        for (p = list->parents[i].parents; *p; p++)
 +          free (*p);
 +
 +        free (list->parents[i].parents);
 +        free (list->parents[i].mime);
 +      }
 +      free (list->parents);
 +    }
 +  free (list);
 +}
 +
 +static int
 +parent_entry_cmp (const void *v1, const void *v2)
 +{
 +  return strcmp (((XdgMimeParents *)v1)->mime, ((XdgMimeParents *)v2)->mime);
 +}
 +
 +const char **
 +_xdg_mime_parent_list_lookup (XdgParentList *list,
 +                            const char    *mime)
 +{
 +  XdgMimeParents *entry;
 +  XdgMimeParents key;
 +
 +  if (list->n_mimes > 0)
 +    {
 +      key.mime = (char *)mime;
 +      key.parents = NULL;
++      key.n_parents = 0;
 +
 +      entry = bsearch (&key, list->parents, list->n_mimes,
 +                     sizeof (XdgMimeParents), &parent_entry_cmp);
 +      if (entry)
 +        return (const char **)entry->parents;
 +    }
 +
 +  return NULL;
 +}
 +
 +void
 +_xdg_mime_parent_read_from_file (XdgParentList *list,
 +                               const char    *file_name)
 +{
 +  FILE *file;
 +  char line[255];
 +  int i, alloc;
 +  XdgMimeParents *entry;
 +
 +  file = fopen (file_name, "r");
 +
 +  if (file == NULL)
 +    return;
 +
 +  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
 +   * Blah */
 +  alloc = list->n_mimes + 16;
 +  list->parents = realloc (list->parents, alloc * sizeof (XdgMimeParents));
 +  while (fgets (line, 255, file) != NULL)
 +    {
 +      char *sep;
 +      if (line[0] == '#')
 +      continue;
 +
 +      sep = strchr (line, ' ');
 +      if (sep == NULL)
 +      continue;
 +      *(sep++) = '\000';
 +      sep[strlen (sep) -1] = '\000';
 +      entry = NULL;
 +      for (i = 0; i < list->n_mimes; i++)
 +      {
 +        if (strcmp (list->parents[i].mime, line) == 0)
 +          {
 +            entry = &(list->parents[i]);
 +            break;
 +          }
 +      }
 +      
 +      if (!entry)
 +      {
 +        if (list->n_mimes == alloc)
 +          {
 +            alloc <<= 1;
 +            list->parents = realloc (list->parents, 
 +                                     alloc * sizeof (XdgMimeParents));
 +          }
 +        list->parents[list->n_mimes].mime = strdup (line);
 +        list->parents[list->n_mimes].parents = NULL;
 +        entry = &(list->parents[list->n_mimes]);
 +        list->n_mimes++;
 +      }
 +
 +      if (!entry->parents)
 +      {
 +        entry->n_parents = 1;
 +        entry->parents = malloc ((entry->n_parents + 1) * sizeof (char *));
 +      }
 +      else
 +      {
 +        entry->n_parents += 1;
 +        entry->parents = realloc (entry->parents, 
 +                                  (entry->n_parents + 2) * sizeof (char *));
 +      }
 +      entry->parents[entry->n_parents - 1] = strdup (sep);
 +      entry->parents[entry->n_parents] = NULL;
 +    }
 +
 +  list->parents = realloc (list->parents, 
 +                         list->n_mimes * sizeof (XdgMimeParents));
 +
 +  fclose (file);  
 +  
 +  if (list->n_mimes > 1)
 +    qsort (list->parents, list->n_mimes, 
 +           sizeof (XdgMimeParents), &parent_entry_cmp);
 +}
 +
 +
 +void         
 +_xdg_mime_parent_list_dump (XdgParentList *list)
 +{
 +  int i;
 +  char **p;
 +
 +  if (list->parents)
 +    {
 +      for (i = 0; i < list->n_mimes; i++)
 +      {
 +        for (p = list->parents[i].parents; *p; p++)
 +          printf ("%s %s\n", list->parents[i].mime, *p);
 +      }
 +    }
 +}
 +
 +
index b564f4127f5270dc6db4c180aea24bc33670c0cf,0000000000000000000000000000000000000000..b656e38cce076a203ef821b87b271ef5779e6f70
mode 100644,000000..100644
--- /dev/null
@@@ -1,51 -1,0 +1,35 @@@
-  * Licensed under the Academic Free License version 2.0
-  * Or under the following terms:
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2 of the License, or (at your option) any later version.
-  *
-  * This library is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the
-  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-  * Boston, MA 02111-1307, USA.
 +/* -*- mode: C; c-file-style: "gnu" -*- */
 +/* xdgmimeparent.h: Private file.  Datastructure for storing the hierarchy.
 + *
 + * More info can be found at http://www.freedesktop.org/standards/
 + *
 + * Copyright (C) 2004  Red Hat, Inc.
 + * Copyright (C) 200  Matthias Clasen <mclasen@redhat.com>
 + *
++ * SPDX-License-Identifier: LGPL-2.1-or-later or AFL-2.0
 + */
 +
 +#ifndef __XDG_MIME_PARENT_H__
 +#define __XDG_MIME_PARENT_H__
 +
 +#include "xdgmime.h"
 +
 +typedef struct XdgParentList XdgParentList;
 +
 +#ifdef XDG_PREFIX
 +#define _xdg_mime_parent_read_from_file        XDG_RESERVED_ENTRY(parent_read_from_file)
 +#define _xdg_mime_parent_list_new              XDG_RESERVED_ENTRY(parent_list_new)
 +#define _xdg_mime_parent_list_free             XDG_RESERVED_ENTRY(parent_list_free)
 +#define _xdg_mime_parent_list_lookup           XDG_RESERVED_ENTRY(parent_list_lookup)
 +#define _xdg_mime_parent_list_dump             XDG_RESERVED_ENTRY(parent_list_dump)
 +#endif
 +
 +void          _xdg_mime_parent_read_from_file (XdgParentList *list,
 +                                             const char    *file_name);
 +XdgParentList *_xdg_mime_parent_list_new       (void);
 +void           _xdg_mime_parent_list_free      (XdgParentList *list);
 +const char   **_xdg_mime_parent_list_lookup    (XdgParentList *list,
 +                                              const char    *mime);
 +void           _xdg_mime_parent_list_dump      (XdgParentList *list);
 +
 +#endif /* __XDG_MIME_PARENT_H__ */