efl/legacy/efreet/src/lib/efreet_mime.c

1598 lines
41 KiB
C
Raw Normal View History

/* vim: set sw=4 ts=4 sts=4 et: */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
2009-08-28 22:29:05 -07:00
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#elif defined __GNUC__
# define alloca __builtin_alloca
#elif defined _AIX
# define alloca __alloca
#elif defined _MSC_VER
# include <malloc.h>
# define alloca _alloca
#else
# include <stddef.h>
# ifdef __cplusplus
extern "C"
# endif
void *alloca (size_t);
#endif
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <unistd.h>
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
#include <time.h>
#include <fcntl.h>
#include <fnmatch.h>
#ifdef _WIN32
# include <winsock2.h>
#endif
2009-04-20 23:16:19 -07:00
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#include <Ecore.h>
#include <Ecore_File.h>
#include <Efreet.h>
#include <Efreet_Mime.h>
#include "efreet_private.h"
static Eina_List *globs = NULL; /* contains Efreet_Mime_Glob structs */
static Eina_List *magics = NULL; /* contains Efreet_Mime_Magic structs */
static Eina_Hash *wild = NULL; /* contains *.ext and mime.types globs*/
static Eina_Hash *monitors = NULL; /* contains file monitors */
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
static Eina_Hash *mime_icons = NULL; /* contains cache with mime->icons */
static Eina_Inlist *mime_icons_lru = NULL;
static unsigned int _efreet_mime_init_count = 0;
/**
2007-07-01 09:32:34 -07:00
* @internal
* @brief Holds whether we are big/little endian
* @note This is set during efreet_mime_init based on
* a runtime check.
*/
static enum
{
EFREET_ENDIAN_BIG = 0,
EFREET_ENDIAN_LITTLE = 1
} efreet_mime_endianess = EFREET_ENDIAN_BIG;
/*
* Buffer sized used for magic checks. The default is good enough for the
2007-07-01 09:32:34 -07:00
* current set of magic rules. This setting is only here for the future.
*/
#define EFREET_MIME_MAGIC_BUFFER_SIZE 512
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
/*
* Minimum timeout in seconds between mime-icons cache flush.
*/
#define EFREET_MIME_ICONS_FLUSH_TIMEOUT 60
/*
* Timeout in seconds, when older mime-icons items are expired.
*/
#define EFREET_MIME_ICONS_EXPIRE_TIMEOUT 600
/*
* mime-icons maximum population.
*/
#define EFREET_MIME_ICONS_MAX_POPULATION 512
/*
* If defined, dump mime-icons statistics after flush.
*/
//#define EFREET_MIME_ICONS_DEBUG
/**
* Efreet_Mime_Glob
* @brief A parsed representation of a globs file
*/
2007-07-01 09:32:34 -07:00
typedef struct Efreet_Mime_Glob Efreet_Mime_Glob;
struct Efreet_Mime_Glob
{
const char *glob;
const char *mime;
2007-07-01 09:32:34 -07:00
};
/**
* Efreet_Mime_Magic
* @brief A parsed representation of a magic file section
*/
2007-07-01 09:32:34 -07:00
typedef struct Efreet_Mime_Magic Efreet_Mime_Magic;
struct Efreet_Mime_Magic
{
unsigned int priority;
const char *mime;
Eina_List *entries;
2007-07-01 09:32:34 -07:00
};
/**
* Efreet_Mime_Magic_Entry
* @brief A parsed representation of a magic file entry
*/
2007-07-01 09:32:34 -07:00
typedef struct Efreet_Mime_Magic_Entry Efreet_Mime_Magic_Entry;
struct Efreet_Mime_Magic_Entry
{
unsigned int indent;
unsigned int offset;
unsigned int word_size;
unsigned int range_len;
unsigned short value_len;
char *mask;
char *value;
2007-07-01 09:32:34 -07:00
};
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
typedef struct Efreet_Mime_Icon_Entry_Head Efreet_Mime_Icon_Entry_Head;
struct Efreet_Mime_Icon_Entry_Head
{
EINA_INLIST; /* node of mime_icons_lru */
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
Eina_Inlist *list;
const char *mime;
time_t timestamp;
};
typedef struct Efreet_Mime_Icon_Entry Efreet_Mime_Icon_Entry;
struct Efreet_Mime_Icon_Entry
{
EINA_INLIST;
const char *icon;
const char *theme;
unsigned int size;
};
/* define macros and variable for using the eina logging system */
#ifdef EFREET_MODULE_LOG_DOM
#undef EFREET_MODULE_LOG_DOM
#endif
#define EFREET_MODULE_LOG_DOM _efreet_mime_log_dom
static int _efreet_mime_log_dom = -1;
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
static int efreet_mime_glob_remove(const char *glob);
static void efreet_mime_mime_types_load(const char *file);
static void efreet_mime_shared_mimeinfo_globs_load(const char *file);
static void efreet_mime_shared_mimeinfo_magic_load(const char *file);
static void efreet_mime_shared_mimeinfo_magic_parse(char *data, int size);
static const char *efreet_mime_magic_check_priority(const char *file,
unsigned int start,
unsigned int end);
static int efreet_mime_init_files(void);
2007-07-03 11:01:56 -07:00
static const char *efreet_mime_special_check(const char *file);
static const char *efreet_mime_fallback_check(const char *file);
static void efreet_mime_glob_free(void *data);
static void efreet_mime_magic_free(void *data);
static void efreet_mime_magic_entry_free(void *data);
static int efreet_mime_glob_match(const char *str, const char *glob);
static int efreet_mime_glob_case_match(char *str, const char *glob);
static int efreet_mime_endian_check(void);
static void efreet_mime_monitor_add(const char *file);
static void efreet_mime_cb_update_file(void *data,
Ecore_File_Monitor *monitor,
Ecore_File_Event event,
const char *path);
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
static void efreet_mime_icons_flush(time_t now);
static void efreet_mime_icon_entry_head_free(Efreet_Mime_Icon_Entry_Head *entry);
static void efreet_mime_icon_entry_add(const char *mime,
const char *icon,
const char *theme,
unsigned int size);
static const char *efreet_mime_icon_entry_find(const char *mime,
const char *theme,
unsigned int size);
static void efreet_mime_icons_debug(void);
/**
* @return Returns 1 on success or 0 on failure
* @brief Initializes the efreet mime settings
*/
2007-11-04 01:32:35 -08:00
EAPI int
efreet_mime_init(void)
{
if (++_efreet_mime_init_count != 1)
return _efreet_mime_init_count;
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
if (!ecore_init())
return --_efreet_mime_init_count;
if (!ecore_file_init())
goto shutdown_ecore;
if (!efreet_init())
goto shutdown_ecore_file;
_efreet_mime_log_dom = eina_log_domain_register("Efreet_mime", EFREET_DEFAULT_LOG_COLOR);
if (_efreet_mime_log_dom < 0)
{
ERROR("Efreet: Could not create a log domain for Efreet_mime.");
goto shutdown_efreet;
}
efreet_mime_endianess = efreet_mime_endian_check();
monitors = eina_hash_string_superfast_new(EINA_FREE_CB(ecore_file_monitor_del));
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
efreet_mime_type_cache_clear();
if (!efreet_mime_init_files())
goto unregister_log_domain;
return _efreet_mime_init_count;
unregister_log_domain:
eina_log_domain_unregister(_efreet_mime_log_dom);
shutdown_efreet:
efreet_shutdown();
shutdown_ecore_file:
ecore_file_shutdown();
shutdown_ecore:
ecore_shutdown();
return --_efreet_mime_init_count;
}
/**
* @return Returns no value
* @brief Cleans up the efreet mime settings system
*/
EAPI int
efreet_mime_shutdown(void)
{
if (--_efreet_mime_init_count != 0)
return _efreet_mime_init_count;
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
efreet_mime_icons_debug();
2009-03-23 05:19:31 -07:00
IF_FREE_LIST(globs, efreet_mime_glob_free);
IF_FREE_LIST(magics, efreet_mime_magic_free);
IF_FREE_HASH(monitors);
IF_FREE_HASH(wild);
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
IF_FREE_HASH(mime_icons);
eina_log_domain_unregister(_efreet_mime_log_dom);
efreet_shutdown();
ecore_file_shutdown();
ecore_shutdown();
return _efreet_mime_init_count;
}
/**
* @param file: The file to find the mime type
* @return Returns mime type as a string
* @brief Retreive the mime type of a file
*/
2007-11-04 01:32:35 -08:00
EAPI const char *
efreet_mime_type_get(const char *file)
{
2007-07-01 09:32:34 -07:00
const char *type = NULL;
if ((type = efreet_mime_special_check(file)))
return type;
2008-08-02 15:09:04 -07:00
/* Check magics with priority > 80 */
if ((type = efreet_mime_magic_check_priority(file, 0, 80)))
return type;
2008-08-02 15:09:04 -07:00
/* Check globs */
if ((type = efreet_mime_globs_type_get(file)))
return type;
2008-08-02 15:09:04 -07:00
/* Check rest of magics */
if ((type = efreet_mime_magic_check_priority(file, 80, 0)))
return type;
return efreet_mime_fallback_check(file);
}
/**
* @param mime: The name of the mime type
* @param theme: The name of the theme to search icons in
* @param size: The wanted size of the icon
* @return Returns mime type icon path as a string
* @brief Retreive the mime type icon for a file
*/
2007-11-04 01:32:35 -08:00
EAPI char *
efreet_mime_type_icon_get(const char *mime, const char *theme, unsigned int size)
{
char *icon = NULL;
char *data;
Eina_List *icons = NULL;
const char *env = NULL;
char *p = NULL, *pp = NULL, *ppp = NULL;
char buf[PATH_MAX];
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
const char *cache;
if (!mime || !theme || !size)
return NULL;
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
mime = eina_stringshare_add(mime);
theme = eina_stringshare_add(theme);
cache = efreet_mime_icon_entry_find(mime, theme, size);
if (cache)
{
eina_stringshare_del(mime);
eina_stringshare_del(theme);
return strdup(cache);
}
/* Standard icon name */
p = strdup(mime);
pp = p;
while (*pp)
{
2008-08-02 15:09:04 -07:00
if (*pp == '/') *pp = '-';
pp++;
}
icons = eina_list_append(icons, p);
/* Environment Based icon names */
if ((env = efreet_desktop_environment_get()))
{
snprintf(buf, sizeof(buf), "%s-mime-%s", env, p);
icons = eina_list_append(icons, strdup(buf));
snprintf(buf, sizeof(buf), "%s-%s", env, p);
icons = eina_list_append(icons, strdup(buf));
}
/* Mime prefixed icon names */
snprintf(buf, sizeof(buf), "mime-%s", p);
icons = eina_list_append(icons, strdup(buf));
/* Generic icons */
pp = strdup(p);
while ((ppp = strrchr(pp, '-')))
{
*ppp = '\0';
snprintf(buf, sizeof(buf), "%s-x-generic", pp);
icons = eina_list_append(icons, strdup(buf));
snprintf(buf, sizeof(buf), "%s-generic", pp);
icons = eina_list_append(icons, strdup(buf));
snprintf(buf, sizeof(buf), "%s", pp);
icons = eina_list_append(icons, strdup(buf));
}
FREE(pp);
/* Search for icons using list */
icon = efreet_icon_list_find(theme, icons, size);
while (icons)
{
data = eina_list_data_get(icons);
free(data);
icons = eina_list_remove_list(icons, icons);
}
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
efreet_mime_icon_entry_add(mime, eina_stringshare_add(icon), theme, size);
return icon;
}
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
EAPI void
efreet_mime_type_cache_clear(void)
{
if (mime_icons)
{
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
eina_hash_free(mime_icons);
mime_icons_lru = NULL;
}
mime_icons = eina_hash_stringshared_new(EINA_FREE_CB(efreet_mime_icon_entry_head_free));
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
}
EAPI void
efreet_mime_type_cache_flush(void)
{
efreet_mime_icons_flush((time_t)ecore_loop_time_get());
}
/**
* @param file: The file to check the mime type
* @return Returns mime type as a string
* @brief Retreive the mime type of a file using magic
*/
2007-11-04 01:32:35 -08:00
EAPI const char *
2007-08-12 22:33:26 -07:00
efreet_mime_magic_type_get(const char *file)
{
return efreet_mime_magic_check_priority(file, 0, 0);
}
/**
* @param file: The file to check the mime type
* @return Returns mime type as a string
* @brief Retreive the mime type of a file using globs
*/
2007-11-04 01:32:35 -08:00
EAPI const char *
2007-08-12 22:33:26 -07:00
efreet_mime_globs_type_get(const char *file)
{
Eina_List *l;
2007-08-12 12:28:02 -07:00
Efreet_Mime_Glob *g;
char *sl, *p;
const char *s;
char *ext, *mime;
2007-08-12 12:28:02 -07:00
2008-08-02 15:09:04 -07:00
/* Check in the extension hash for the type */
2007-08-12 12:28:02 -07:00
ext = strchr(file, '.');
if (ext)
{
sl = alloca(strlen(ext) + 1);
for (s = ext, p = sl; *s; s++, p++) *p = tolower(*s);
*p = 0;
p = sl;
while (p)
{
p++;
if (p && (mime = eina_hash_find(wild, p))) return mime;
2007-08-12 12:28:02 -07:00
p = strchr(p, '.');
}
}
2008-08-02 15:09:04 -07:00
/* Fallback to the other globs if not found */
EINA_LIST_FOREACH(globs, l, g)
2007-08-12 12:28:02 -07:00
{
if (efreet_mime_glob_match(file, g->glob))
2007-08-12 12:28:02 -07:00
return g->mime;
}
ext = alloca(strlen(file) + 1);
for (s = file, p = ext; *s; s++, p++) *p = tolower(*s);
*p = 0;
EINA_LIST_FOREACH(globs, l, g)
2007-08-12 12:28:02 -07:00
{
if (efreet_mime_glob_case_match(ext, g->glob))
2007-08-12 12:28:02 -07:00
return g->mime;
}
return NULL;
}
/**
* @param file: The file to check the mime type
* @return Returns mime type as a string
* @brief Retreive the special mime type of a file
*/
2007-11-04 01:32:35 -08:00
EAPI const char *
2007-08-12 22:33:26 -07:00
efreet_mime_special_type_get(const char *file)
{
return efreet_mime_special_check(file);
}
/**
* @param file: The file to check the mime type
* @return Returns mime type as a string
* @brief Retreive the fallback mime type of a file
*/
2007-11-04 01:32:35 -08:00
EAPI const char *
2007-08-12 22:33:26 -07:00
efreet_mime_fallback_type_get(const char *file)
{
return efreet_mime_fallback_check(file);
}
/**
* @internal
* @return Returns the endianess
* @brief Retreive the endianess of the machine
*/
2007-07-01 09:32:34 -07:00
static int
efreet_mime_endian_check(void)
{
int test = 1;
return (*((char*)(&test)));
}
/**
* @internal
* @param file: File to monitor
* @return Returns no value.
* @brief Creates a new file monitor if we aren't already monitoring the
* given file
*/
static void
efreet_mime_monitor_add(const char *file)
{
Ecore_File_Monitor *fm = NULL;
/* if this is already in our hash then we're already monitoring so no
* reason to re-monitor */
if (eina_hash_find(monitors, file))
return;
if ((fm = ecore_file_monitor_add(file, efreet_mime_cb_update_file, NULL)))
2009-08-28 22:29:05 -07:00
{
eina_hash_del(monitors, file, NULL);
eina_hash_add(monitors, file, fm);
}
}
/**
* @internal
* @param datadirs: List of XDG data dirs
* @param datahome: Path to XDG data home directory
* @return Returns no value
* @brief Read all glob files in XDG data/home dirs.
* Also reads the /etc/mime.types file.
*/
static void
efreet_mime_load_globs(Eina_List *datadirs, const char *datahome)
{
Eina_List *l;
char buf[4096];
const char *datadir = NULL;
IF_FREE_HASH(wild);
wild = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
while (globs)
{
efreet_mime_glob_free(eina_list_data_get(globs));
globs = eina_list_remove_list(globs, globs);
}
/*
* This is here for legacy reasons. It is mentioned briefly
* in the spec and seems to still be quite valid. It is
* loaded first so the globs files will override anything
* in here.
*/
efreet_mime_mime_types_load("/etc/mime.types");
datadir = datahome;
2009-08-28 22:29:05 -07:00
snprintf(buf, sizeof(buf), "%s/mime/globs", datadir);
efreet_mime_shared_mimeinfo_globs_load(buf);
EINA_LIST_FOREACH(datadirs, l, datadir)
{
snprintf(buf, sizeof(buf), "%s/mime/globs", datadir);
efreet_mime_shared_mimeinfo_globs_load(buf);
}
}
/**
* @internal
* @param datadirs: List of XDG data dirs
* @param datahome: Path to XDG data home directory
* @return Returns no value
* @brief Read all magic files in XDG data/home dirs.
*/
static void
efreet_mime_load_magics(Eina_List *datadirs, const char *datahome)
{
Eina_List *l;
char buf[4096];
const char *datadir = NULL;
while (magics)
{
efreet_mime_magic_free(eina_list_data_get(magics));
magics = eina_list_remove_list(magics, magics);
}
datadir = datahome;
2009-08-28 22:29:05 -07:00
snprintf(buf, sizeof(buf), "%s/mime/magic", datadir);
efreet_mime_shared_mimeinfo_magic_load(buf);
EINA_LIST_FOREACH(datadirs, l, datadir)
{
snprintf(buf, sizeof(buf), "%s/mime/magic", datadir);
efreet_mime_shared_mimeinfo_magic_load(buf);
}
}
/**
* @internal
* @param data: Data pointer passed to monitor_add
* @param monitor: Ecore_File_Monitor associated with this event
* @param event: The type of event
* @param path: Path to the file that was updated
* @return Returns no value
* @brief Callback for all file monitors. Just reloads the appropriate
* list depending on which file changed. If it was a magic file
* only the magic list is updated. If it was a glob file or /etc/mime.types,
* the globs are updated.
*/
static void
efreet_mime_cb_update_file(void *data __UNUSED__,
Ecore_File_Monitor *monitor __UNUSED__,
Ecore_File_Event event __UNUSED__,
const char *path)
{
Eina_List *datadirs = NULL;
const char *datahome = NULL;
if (!(datahome = efreet_data_home_get()))
return;
if (!(datadirs = efreet_data_dirs_get()))
return;
2007-07-01 09:32:34 -07:00
if (strstr(path, "magic"))
efreet_mime_load_magics(datadirs, datahome);
else
efreet_mime_load_globs(datadirs, datahome);
}
/**
* @internal
* @param datadirs: List of XDG data dirs
* @param datahome: Path to XDG data home directory
* @return Returns 1 on success, 0 on failure
* @brief Initializes globs, magics, and monitors lists.
*/
static int
2007-07-01 09:32:34 -07:00
efreet_mime_init_files(void)
{
Eina_List *l;
Eina_List *datadirs = NULL;
char buf[PATH_MAX];
const char *datahome, *datadir = NULL;
if (!(datahome = efreet_data_home_get()))
return 0;
if (!(datadirs = efreet_data_dirs_get()))
return 0;
/*
* Add our file monitors
* We watch the directories so we can watch for new files
*/
datadir = datahome;
2009-08-28 22:29:05 -07:00
snprintf(buf, PATH_MAX, "%s/mime", datadir);
efreet_mime_monitor_add(buf);
EINA_LIST_FOREACH(datadirs, l, datadir)
{
snprintf(buf, PATH_MAX, "%s/mime", datadir);
efreet_mime_monitor_add(buf);
}
efreet_mime_monitor_add("/etc/mime.types");
/* Load our mime information */
efreet_mime_load_globs(datadirs, datahome);
efreet_mime_load_magics(datadirs, datahome);
return 1;
}
/**
* @internal
* @param file: File to examine
* @return Returns mime type if special file, else NULL
* @brief Returns a mime type based on the stat of a file.
* This is used first to catch directories and other special
* files. A NULL return doesn't necessarily mean failure, but
* can also mean the file is regular.
* @note Mapping of file types to mime types:
* Stat Macro File Type Mime Type
2007-07-01 09:32:34 -07:00
* S_IFREG regular NULL
* S_IFIFO named pipe (fifo) inode/fifo
* S_IFCHR character special inode/chardevice
* S_IFDIR directory inode/directory
* S_IFBLK block special inode/blockdevice
* S_IFLNK symbolic link inode/symlink
* S_IFSOCK socket inode/socket
*
* This function can also return inode/mount-point.
* This is calculated by comparing the st_dev of the directory
* against that of it's parent directory. If they differ it
* is considered a mount point.
*/
2007-07-01 09:32:34 -07:00
static const char *
efreet_mime_special_check(const char *file)
{
struct stat s;
int path_len = 0;
if (!lstat(file, &s))
{
if (S_ISREG(s.st_mode))
return NULL;
#ifndef _WIN32
if (S_ISLNK(s.st_mode))
return "inode/symlink";
#endif
if (S_ISFIFO(s.st_mode))
return "inode/fifo";
if (S_ISCHR(s.st_mode))
return "inode/chardevice";
if (S_ISBLK(s.st_mode))
return "inode/blockdevice";
#ifndef _WIN32
if (S_ISSOCK(s.st_mode))
return "inode/socket";
#endif
if (S_ISDIR(s.st_mode))
{
struct stat s2;
char parent[PATH_MAX];
char path[PATH_MAX];
strncpy(path, file, PATH_MAX);
path_len = strlen(file);
strncpy(parent, path, PATH_MAX);
2007-07-01 09:32:34 -07:00
/* Kill any trailing slash */
parent[--path_len] = '\0';
2007-07-01 09:32:34 -07:00
/* Truncate to last slash */
while (parent[--path_len] != '/') parent[path_len] = '\0';
if (!lstat(parent, &s2))
{
if (s.st_dev != s2.st_dev)
return "inode/mount-point";
}
return "inode/directory";
}
return NULL;
}
return NULL;
}
/**
* @internal
* @param file: File to examine
2007-07-03 11:01:56 -07:00
* @return Returns mime type or NULL if the file doesn't exist
* @brief Returns text/plain if the file appears to contain text and
2007-07-03 11:01:56 -07:00
* returns application/octet-stream if it appears to be binary.
*/
static const char *
efreet_mime_fallback_check(const char *file)
{
FILE *f = NULL;
char buf[32];
2007-07-03 11:01:56 -07:00
int i;
if (ecore_file_can_exec(file))
return "application/x-executable";
2008-08-02 15:09:04 -07:00
if (!(f = fopen(file, "r"))) return NULL;
2007-07-03 11:01:56 -07:00
i = fread(buf, 1, sizeof(buf), f);
fclose(f);
2008-08-02 15:09:04 -07:00
if (i == 0) return "application/octet-stream";
/*
* Check for ASCII control characters in the first 32 bytes.
* Line Feeds, carriage returns, and tabs are ignored as they are
* quite common in text files in the first 32 chars.
*/
2007-07-03 11:01:56 -07:00
for (i -= 1; i >= 0; --i)
{
if ((buf[i] < 0x20) &&
(buf[i] != '\n') && /* Line Feed */
(buf[i] != '\r') && /* Carriage Return */
(buf[i] != '\t')) /* Tab */
return "application/octet-stream";
}
return "text/plain";
}
/**
* @internal
* @param glob: Glob to search for
* @return Returns 1 on success, 0 on failure
* @brief Removes a glob from the list
*/
static int
efreet_mime_glob_remove(const char *glob)
{
Efreet_Mime_Glob *mime = NULL;
if ((mime = eina_list_search_unsorted(globs, EINA_COMPARE_CB(strcmp), glob)))
2009-08-28 22:29:05 -07:00
{
globs = eina_list_remove(globs, mime);
2009-08-28 22:29:05 -07:00
IF_RELEASE(mime->glob);
IF_RELEASE(mime->mime);
FREE(mime);
return 1;
}
return 0;
}
/**
* @internal
* @param file: mime.types file to load
* @return Returns no value
* @brief Loads values from a mime.types style file
* into the globs list.
* @note Format:
* application/msaccess mdb
* application/msword doc dot
*/
static void
2007-07-01 09:32:34 -07:00
efreet_mime_mime_types_load(const char *file)
{
FILE *f = NULL;
char buf[4096], mimetype[4096];
2007-07-01 09:32:34 -07:00
char ext[4096], *p = NULL, *pp = NULL;
f = fopen(file, "rb");
if (!f) return;
while (fgets(buf, sizeof(buf), f))
{
p = buf;
while (isspace(*p) && (*p != 0) && (*p != '\n')) p++;
2007-07-01 09:32:34 -07:00
if (*p == '#') continue;
if ((*p == '\n') || (*p == 0)) continue;
2007-07-01 09:32:34 -07:00
pp = p;
while (!isspace(*p) && (*p != 0) && (*p != '\n')) p++;
2007-07-01 09:32:34 -07:00
if ((*p == '\n') || (*p == 0)) continue;
strncpy(mimetype, pp, (p - pp));
mimetype[p - pp] = 0;
do
{
while (isspace(*p) && (*p != 0) && (*p != '\n')) p++;
2007-07-01 09:32:34 -07:00
if ((*p == '\n') || (*p == 0)) break;
2007-07-01 09:32:34 -07:00
pp = p;
while (!isspace(*p) && (*p != 0) && (*p != '\n')) p++;
2007-07-01 09:32:34 -07:00
strncpy(ext, pp, (p - pp));
ext[p - pp] = 0;
eina_hash_del(wild, ext, NULL);
eina_hash_add(wild, ext, (void*)eina_stringshare_add(mimetype));
}
while ((*p != '\n') && (*p != 0));
}
2007-08-12 12:28:02 -07:00
fclose(f);
}
/**
* @internal
* @param file: globs file to load
* @return Returns no value
* @brief Loads values from a mime.types style file
* into the globs list.
* @note Format:
* text/vnd.wap.wml:*.wml
* application/x-7z-compressed:*.7z
* application/vnd.corel-draw:*.cdr
* text/spreadsheet:*.sylk
*/
static void
2007-07-01 09:32:34 -07:00
efreet_mime_shared_mimeinfo_globs_load(const char *file)
{
FILE *f = NULL;
char buf[4096], mimetype[4096], ext[4096], *p, *pp;
Efreet_Mime_Glob *mime = NULL;
f = fopen(file, "rb");
if (!f) return;
while (fgets(buf, sizeof(buf), f))
{
p = buf;
while (isspace(*p) && (*p != 0) && (*p != '\n')) p++;
2007-07-01 09:32:34 -07:00
if (*p == '#') continue;
if ((*p == '\n') || (*p == 0)) continue;
2007-07-01 09:32:34 -07:00
pp = p;
while ((*p != ':') && (*p != 0) && (*p != '\n')) p++;
2007-07-01 09:32:34 -07:00
if ((*p == '\n') || (*p == 0)) continue;
strncpy(mimetype, pp, (p - pp));
mimetype[p - pp] = 0;
p++;
pp = ext;
while ((*p != 0) && (*p != '\n'))
{
*pp = *p;
pp++;
p++;
}
*pp = 0;
2007-08-12 12:18:16 -07:00
if (ext[0] == '*' && ext[1] == '.')
{
eina_hash_del(wild, &(ext[2]), NULL);
eina_hash_add(wild, &(ext[2]),
(void*)eina_stringshare_add(mimetype));
}
else
{
mime = NEW(Efreet_Mime_Glob, 1);
if (mime)
{
mime->mime = eina_stringshare_add(mimetype);
mime->glob = eina_stringshare_add(ext);
if ((!mime->mime) || (!mime->glob))
{
IF_RELEASE(mime->mime);
IF_RELEASE(mime->glob);
FREE(mime);
}
else
{
efreet_mime_glob_remove(ext);
globs = eina_list_append(globs, mime);
}
}
}
}
fclose(f);
}
/**
* @internal
* @param in: Number to count the digits
* @return Returns number of digits
* @brief Calculates and returns the number of digits
* in a number.
*/
static int
efreet_mime_count_digits(int in)
{
int i = 1, j = in;
if (j < 10) return 1;
while ((j /= 10) > 0) ++i;
return i;
}
/**
* @internal
* @param file: File to parse
* @return Returns no value
* @brief Loads a magic file and adds information to magics list
*/
static void
efreet_mime_shared_mimeinfo_magic_load(const char *file)
{
int fd = -1, size;
char *data = (void *)-1;
if (!file) return;
size = ecore_file_size(file);
if (size <= 0) return;
fd = open(file, O_RDONLY);
if (fd == -1) return;
data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
{
close(fd);
return;
}
efreet_mime_shared_mimeinfo_magic_parse(data, size);
munmap(data, size);
close(fd);
}
/**
* @param data: The data from the file
* @return Returns no value
* @brief Parses a magic file
* @note Format:
*
* ----------------------------------------------------------------------
2007-07-01 09:32:34 -07:00
* | HEX | ASCII |
* ----------------------------------------------------------------------
* |4D 49 4D 45 2D 4D 61 67 69 63 00 0A 5B 39 30 3A | MIME-Magic..[90: |
* |61 70 70 6C 69 63 61 74 69 6F 6E 2F 64 6F 63 62 | application/docb |
* |6F 6F 6B 2B 78 6D 6C 5D 0A 3E 30 3D 00 05 3C 3F | ook+xml].>0=..<? |
* |78 6D 6C 0A 31 3E 30 3D 00 19 2D 2F 2F 4F 41 53 | xml.1>0=..-//OAS |
* |49 53 2F 2F 44 54 44 20 44 6F 63 42 6F 6F 6B 20 | IS//DTD DocBook |
* |58 4D 4C 2B 31 30 31 0A 31 3E 30 3D 00 17 2D 2F | XML+101.1>0=..-/ |
* ----------------------------------------------------------------------
*
* indent
* The nesting depth of the rule, corresponding to the number of '>'
* characters in the traditional file format.
* ">" start-offset
* The offset into the file to look for a match.
* "=" value
* Two bytes giving the (big-endian) length of the value, followed by the
* value itself.
* "&" mask
* The mask, which (if present) is exactly the same length as the value.
* "~" word-size
* On little-endian machines, the size of each group to byte-swap.
* "+" range-length
* The length of the region in the file to check.
*
* The indent, range-length, word-size and mask components are optional.
* If missing, indent defaults to 0, range-length to 1, the word-size to 1,
* and the mask to all 'one' bits. In our case, mask is null as it is
* quicker, uses less memory and will acheive the same exact effect.
*/
static void
efreet_mime_shared_mimeinfo_magic_parse(char *data, int size)
{
Efreet_Mime_Magic *mime = NULL;
Efreet_Mime_Magic_Entry *entry = NULL;
char *ptr;
ptr = data;
/* make sure we're a magic file */
if (!ptr || (size < 12) || strncmp(ptr, "MIME-Magic\0\n", 12))
return;
ptr += 12;
for (; (ptr - data) < size; )
{
if (*ptr == '[')
{
char *val, buf[512];
mime = NEW(Efreet_Mime_Magic, 1);
magics = eina_list_append(magics, mime);
val = ++ptr;
while ((*val != ':')) val++;
memcpy(&buf, ptr, val - ptr);
buf[val - ptr] = '\0';
mime->priority = atoi(buf);
ptr = ++val;
while ((*val != ']')) val++;
memcpy(&buf, ptr, val - ptr);
buf[val - ptr] = '\0';
mime->mime = eina_stringshare_add(buf);
ptr = ++val;
while (*ptr != '\n') ptr++;
ptr++;
}
else
{
2008-04-06 22:52:45 -07:00
short tshort;
if (!mime) continue;
if (!entry)
{
if (!(entry = NEW(Efreet_Mime_Magic_Entry, 1)))
{
2009-03-23 05:19:31 -07:00
IF_FREE_LIST(magics, efreet_mime_magic_free);
return;
}
entry->indent = 0;
entry->offset = 0;
entry->value_len = 0;
entry->word_size = 1;
entry->range_len = 1;
entry->mask = NULL;
entry->value = NULL;
mime->entries = eina_list_append(mime->entries, entry);
}
switch(*ptr)
{
case '>':
ptr ++;
entry->offset = atoi(ptr);
ptr += efreet_mime_count_digits(entry->offset);
break;
2007-07-01 09:32:34 -07:00
case '=':
ptr++;
2009-03-23 05:19:31 -07:00
2008-04-06 22:52:45 -07:00
memcpy(&tshort, ptr, sizeof(short));
entry->value_len = ntohs(tshort);
ptr += 2;
2007-07-01 09:32:34 -07:00
entry->value = NEW(1, entry->value_len);
memcpy(entry->value, ptr, entry->value_len);
ptr += entry->value_len;
break;
case '&':
ptr++;
entry->mask = NEW(1, entry->value_len);
memcpy(entry->mask, ptr, entry->value_len);
ptr += entry->value_len;
break;
case '~':
ptr++;
entry->word_size = atoi(ptr);
if ((entry->word_size != 0) && ((entry->word_size != 1)
&& (entry->word_size != 2)
&& (entry->word_size != 4)
|| (entry->value_len % entry->word_size)))
{
/* Invalid, Destroy */
FREE(entry->value);
FREE(entry->mask);
FREE(entry);
while (*ptr != '\n') ptr++;
break;
}
if (efreet_mime_endianess == EFREET_ENDIAN_LITTLE)
{
int j;
for (j = 0; j < entry->value_len; j += entry->word_size)
{
if (entry->word_size == 2)
{
((short*)entry->value)[j] =
ntohs(((short*)entry->value)[j]);
if (entry->mask)
((short*)entry->mask)[j] =
ntohs(((short*)entry->mask)[j]);
}
else if (entry->word_size == 4)
{
((int*)entry->value)[j] =
ntohl(((int*)entry->value)[j]);
if (entry->mask)
((int*)entry->mask)[j] =
ntohl(((int*)entry->mask)[j]);
}
}
}
ptr += efreet_mime_count_digits(entry->word_size);
break;
case '+':
ptr++;
entry->range_len = atoi(ptr);
ptr += efreet_mime_count_digits(entry->range_len);
break;
case '\n':
ptr++;
entry = NULL;
break;
default:
if (isdigit(*ptr))
{
entry->indent = atoi(ptr);
ptr += efreet_mime_count_digits(entry->indent);
}
break;
}
}
}
/*
2007-07-03 06:59:40 -07:00
if (entry)
2007-07-03 06:41:44 -07:00
{
IF_FREE(entry->value);
IF_FREE(entry->mask);
2007-07-03 06:59:40 -07:00
FREE(entry);
2007-07-03 06:41:44 -07:00
}
*/
}
/**
* @internal
* @param file: File to check
* @param start: Start priority, if 0 start at beginning
* @param end: End priority, should be less then start
* unless start
* @return Returns mime type for file if found, NULL if not
* @brief Applies magic rules to a file given a start and end priority
*/
2007-07-01 09:32:34 -07:00
static const char *
efreet_mime_magic_check_priority(const char *file,
unsigned int start,
unsigned int end)
{
Efreet_Mime_Magic *m = NULL;
Efreet_Mime_Magic_Entry *e = NULL;
Eina_List *l, *ll;
2007-07-01 09:32:34 -07:00
FILE *f = NULL;
unsigned int i = 0, offset = 0,level = 0, match = 0, bytes_read = 0;
const char *last_mime = NULL;
2007-07-01 09:32:34 -07:00
char c, v, buf[EFREET_MIME_MAGIC_BUFFER_SIZE];
f = fopen(file, "rb");
if (!f) return NULL;
if (!magics)
{
fclose(f);
return NULL;
}
if ((bytes_read = fread(buf, 1, sizeof(buf), f)) == 0)
{
fclose(f);
return NULL;
}
EINA_LIST_FOREACH(magics, l, m)
{
if ((start != 0) && (m->priority > start))
continue;
if (m->priority < end)
break;
EINA_LIST_FOREACH(m->entries, ll, e)
{
if ((level < e->indent) && !match)
continue;
if ((level >= e->indent) && !match)
level = e->indent;
else if ((level > e->indent) && match)
{
fclose(f);
if (last_mime) return last_mime;
}
for (offset = e->offset; offset < e->offset + e->range_len; offset++)
{
if (((offset + e->value_len) > bytes_read) &&
(fseek(f, offset, SEEK_SET) == -1))
break;
2007-07-01 09:32:34 -07:00
match = 1;
for (i = 0; i < e->value_len; ++i)
{
if (offset + e->value_len > bytes_read)
c = fgetc(f);
else
2007-07-01 09:32:34 -07:00
c = buf[offset + i];
v = e->value[i];
if (e->mask) v &= e->mask[i];
if (!(c == v))
{
match = 0;
break;
}
}
if (match)
{
level += 1;
last_mime = m->mime;
break;
}
}
}
if (match)
{
fclose(f);
return last_mime;
}
}
fclose(f);
2007-07-01 09:32:34 -07:00
return NULL;
}
/**
* @internal
* @param data: Data pointer that is being destroyed
* @return Returns no value
* @brief Callback for globs destroy
*/
static void
2007-07-01 09:32:34 -07:00
efreet_mime_glob_free(void *data)
{
Efreet_Mime_Glob *m = data;
IF_RELEASE(m->mime);
IF_RELEASE(m->glob);
IF_FREE(m);
}
/**
* @internal
* @param data: Data pointer that is being destroyed
* @return Returns no value
* @brief Callback for magics destroy
*/
static void
2007-07-01 09:32:34 -07:00
efreet_mime_magic_free(void *data)
{
Efreet_Mime_Magic *m = data;
Efreet_Mime_Magic_Entry *entry = NULL;
IF_RELEASE(m->mime);
while (m->entries)
{
entry = eina_list_data_get(m->entries);
efreet_mime_magic_entry_free(entry);
m->entries = eina_list_remove_list(m->entries, m->entries);
}
IF_FREE(m);
}
/**
* @internal
* @param data: Data pointer that is being destroyed
* @return Returns no value
* @brief Callback for magic entry destroy
*/
static void
efreet_mime_magic_entry_free(void *data)
{
Efreet_Mime_Magic_Entry *e = data;
IF_FREE(e->mask);
IF_FREE(e->value);
IF_FREE(e);
}
/**
* @internal
* @param str: String (filename) to match
* @param glob: Glob to match str to
* @return Returns 1 on success, 0 on failure
* @brief Compares str to glob, case sensitive
*/
static int
efreet_mime_glob_match(const char *str, const char *glob)
{
2007-08-12 12:28:02 -07:00
if (!str || !glob) return 0;
if (glob[0] == 0)
{
if (str[0] == 0) return 1;
return 0;
2007-08-12 12:28:02 -07:00
}
if (!fnmatch(glob, str, 0)) return 1;
return 0;
}
/**
* @internal
* @param str: String (filename) to match
* @param glob: Glob to match str to
* @return Returns 1 on success, 0 on failure
* @brief Compares str to glob, case insensitive (expects str already in lower case)
*/
static int
efreet_mime_glob_case_match(char *str, const char *glob)
{
2007-08-12 12:28:02 -07:00
const char *p;
char *tglob, *tp;
if (!str || !glob) return 0;
if (glob[0] == 0)
{
if (str[0] == 0) return 1;
return 0;
2007-08-12 12:28:02 -07:00
}
tglob = alloca(strlen(glob) + 1);
for (tp = tglob, p = glob; *p; p++, tp++) *tp = tolower(*p);
*tp = 0;
if (!fnmatch(str, tglob, 0)) return 1;
return 0;
}
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
static void
efreet_mime_icons_flush(time_t now)
{
Eina_Inlist *l;
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
static time_t old = 0;
int todo;
if (now - old < EFREET_MIME_ICONS_FLUSH_TIMEOUT)
return;
old = now;
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
todo = eina_hash_population(mime_icons) - EFREET_MIME_ICONS_MAX_POPULATION;
if (todo <= 0)
return;
l = mime_icons_lru->last; /* mime_icons_lru is not NULL, since todo > 0 */
for (; todo > 0; todo--)
{
Efreet_Mime_Icon_Entry_Head *entry = (Efreet_Mime_Icon_Entry_Head *)l;
Eina_Inlist *prev = l->prev;
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
mime_icons_lru = eina_inlist_remove(mime_icons_lru, l);
eina_hash_del_by_key(mime_icons, entry->mime);
l = prev;
}
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
efreet_mime_icons_debug();
}
static void
efreet_mime_icon_entry_free(Efreet_Mime_Icon_Entry *node)
{
eina_stringshare_del(node->icon);
eina_stringshare_del(node->theme);
free(node);
}
static void
efreet_mime_icon_entry_head_free(Efreet_Mime_Icon_Entry_Head *entry)
{
while (entry->list)
{
Efreet_Mime_Icon_Entry *n = (Efreet_Mime_Icon_Entry *)entry->list;
entry->list = eina_inlist_remove(entry->list, entry->list);
efreet_mime_icon_entry_free(n);
}
eina_stringshare_del(entry->mime);
free(entry);
}
static Efreet_Mime_Icon_Entry *
efreet_mime_icon_entry_new(const char *icon,
const char *theme,
unsigned int size)
{
Efreet_Mime_Icon_Entry *entry;
entry = malloc(sizeof(*entry));
if (!entry)
return NULL;
entry->icon = icon;
entry->theme = theme;
entry->size = size;
return entry;
}
static void
efreet_mime_icon_entry_add(const char *mime,
const char *icon,
const char *theme,
unsigned int size)
{
Efreet_Mime_Icon_Entry_Head *entry;
Efreet_Mime_Icon_Entry *n;
n = efreet_mime_icon_entry_new(icon, theme, size);
if (!n)
return;
entry = eina_hash_find(mime_icons, mime);
if (entry)
{
Eina_Inlist *l;
l = EINA_INLIST_GET(n);
entry->list = eina_inlist_prepend(entry->list, l);
l = EINA_INLIST_GET(entry);
mime_icons_lru = eina_inlist_promote(mime_icons_lru, l);
}
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
else
{
Eina_Inlist *l;
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
entry = malloc(sizeof(*entry));
if (!entry)
{
efreet_mime_icon_entry_free(n);
return;
}
l = EINA_INLIST_GET(n);
entry->list = eina_inlist_prepend(NULL, l);
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
entry->mime = mime;
eina_hash_direct_add(mime_icons, mime, entry);
l = EINA_INLIST_GET(entry);
mime_icons_lru = eina_inlist_prepend(mime_icons_lru, l);
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
}
entry->timestamp = (time_t)ecore_loop_time_get();
efreet_mime_icons_flush(entry->timestamp);
}
static const char *
efreet_mime_icon_entry_find(const char *mime,
const char *theme,
unsigned int size)
{
Efreet_Mime_Icon_Entry_Head *entry;
Efreet_Mime_Icon_Entry *n;
entry = eina_hash_find(mime_icons, mime);
if (!entry)
return NULL;
EINA_INLIST_FOREACH(entry->list, n)
{
if ((n->theme == theme) && (n->size == size))
{
Eina_Inlist *l;
l = EINA_INLIST_GET(n);
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
if (entry->list != l)
entry->list = eina_inlist_promote(entry->list, l);
l = EINA_INLIST_GET(entry);
if (mime_icons_lru != l)
mime_icons_lru = eina_inlist_promote(mime_icons_lru, l);
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
entry->timestamp = (time_t)ecore_loop_time_get();
return n->icon;
}
}
return NULL;
}
#ifdef EFREET_MIME_ICONS_DEBUG
static void
efreet_mime_icons_debug(void)
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
{
time_t now = (time_t)ecore_loop_time_get();
Efreet_Mime_Icon_Entry_Head *entry;
EINA_INLIST_FOREACH(mime_icons_lru, entry)
{
Efreet_Mime_Icon_Entry *n;
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
if ((now > 0) &&
(now - entry->timestamp >= EFREET_MIME_ICONS_EXPIRE_TIMEOUT))
{
puts("*** FOLLOWING ENTRIES ARE AGED AND CAN BE EXPIRED ***");
now = 0;
}
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
DBG("mime-icon entry: '%s' last used: %s",
entry->mime, ctime(&entry->timestamp));
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
EINA_INLIST_FOREACH(entry->list, n)
DBG("\tsize: %3u theme: '%s' icon: '%s'",
n->theme, n->size, n->icon);
}
efreet mime types icon cache. This cache is very simple and should work fine when system does not change, it keeps a direct association of mime-types and found icons, remembering theme and icon size. Search is very fast since it uses stringshared strings and thus direct pointer comparison in hash search. We could optimize it even more if we assumed stringshared strings to come in, so no need to eina_stringshare_add() (which is a hash per se), using just eina_stringshare_ref(). Cache population is limited to compile-time value and just values older than a given threshold are deleted. I do not keep a LRU explicit list, so you might have some old but unused items always alive. I don't find this too bad, sure it will consume more memory, but will not hurt performance. We can change this to purge all expired items by not checking for number of items to remove, removing all that match. Next I plan to find out a good way to cache and speed up file->mime discovery. I plan to do auto-generated state-machine to match extensions, so you don't need to check the same extension character more than once. Example: Input: bla.edc Extensions: edc edj eps png bmp It would first try to match against 'e', 'p' and 'b'. It will match 'e' and then check for 'd' (edc or edj) or 'p' (eps). It will match 'd' and then check for 'c' or 'j'. This will reduce number of comparisons considerably. As I'm running out of time (4am, not much time left on this month), I could use some help here. SVN revision: 39343
2009-03-02 23:20:21 -08:00
}
#else
static void
efreet_mime_icons_debug(void)
{
}
#endif