efl/legacy/ethumb/src/lib/ethumb.c

1843 lines
42 KiB
C
Raw Normal View History

/**
* @file
*
* Copyright (C) 2009 by ProFUSION embedded systems
*
* 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.1 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, see <http://www.gnu.org/licenses/>.
*
* @author Rafael Antognolli <antognolli@profusion.mobi>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#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 <stdlib.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <dlfcn.h>
#include <ctype.h>
#ifdef HAVE_XATTR
# include <sys/xattr.h>
#endif
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif
#include <Eina.h>
#include <eina_safety_checks.h>
#include <Evas.h>
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Ecore_File.h>
#include <Edje.h>
#include "Ethumb.h"
#include "ethumb_private.h"
#include "Ethumb_Plugin.h"
#include "md5.h"
#ifdef HAVE_LIBEXIF
#include <libexif/exif-data.h>
#endif
static Ethumb_Version _version = { VMAJ, VMIN, VMIC, VREV };
EAPI Ethumb_Version *ethumb_version = &_version;
static int _log_dom = -1;
#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
static int initcount = 0;
static const char *_home_thumb_dir = NULL;
static const char *_thumb_category_normal = NULL;
static const char *_thumb_category_large = NULL;
static const int THUMB_SIZE_NORMAL = 128;
static const int THUMB_SIZE_LARGE = 256;
static Eina_Hash *_plugins_ext = NULL;
static Eina_Array *_plugins = NULL;
static Eina_Bool
_ethumb_plugin_list_cb(Eina_Module *m, void *data __UNUSED__)
{
const char *file;
const char **ext;
Ethumb_Plugin *plugin;
Ethumb_Plugin *(*plugin_get)(void);
file = eina_module_file_get(m);
if (!eina_module_load(m))
{
ERR("could not load module \"%s\": %s",
file, eina_error_msg_get(eina_error_get()));
return EINA_FALSE;
}
plugin_get = eina_module_symbol_get(m, "ethumb_plugin_get");
if (!plugin_get)
{
ERR("could not find ethumb_plugin_get() in module \"%s\": %s",
file, eina_error_msg_get(eina_error_get()));
eina_module_unload(m);
return EINA_FALSE;
}
plugin = plugin_get();
if (!plugin)
{
ERR("plugin \"%s\" failed to init.", file);
eina_module_unload(m);
return EINA_FALSE;
}
DBG("loaded plugin \"%s\" (%p) with extensions:", file, plugin);
for (ext = plugin->extensions; *ext; ext++)
{
DBG(" extension \"%s\"", *ext);
eina_hash_add(_plugins_ext, *ext, plugin);
}
return EINA_TRUE;
}
static void
_ethumb_plugins_load(void)
{
_plugins_ext = eina_hash_string_small_new(NULL);
EINA_SAFETY_ON_NULL_RETURN(_plugins_ext);
_plugins = eina_module_list_get(_plugins, PLUGINSDIR, 1,
&_ethumb_plugin_list_cb, NULL);
}
static void
_ethumb_plugins_unload(void)
{
eina_hash_free(_plugins_ext);
_plugins_ext = NULL;
eina_module_list_unload(_plugins);
eina_module_list_free(_plugins);
eina_array_free(_plugins);
_plugins = NULL;
}
EAPI int
ethumb_init(void)
{
const char *home;
char buf[PATH_MAX];
if (initcount)
return ++initcount;
if (!eina_init())
{
fprintf(stderr, "ERROR: Could not initialize eina.\n");
return 0;
}
_log_dom = eina_log_domain_register("ethumb", EINA_COLOR_GREEN);
if (_log_dom < 0)
{
EINA_LOG_ERR("Could not register log domain: ethumb");
eina_shutdown();
return 0;
}
evas_init();
ecore_init();
ecore_evas_init();
edje_init();
home = getenv("HOME");
snprintf(buf, sizeof(buf), "%s/.thumbnails", home);
_home_thumb_dir = eina_stringshare_add(buf);
_thumb_category_normal = eina_stringshare_add("normal");
_thumb_category_large = eina_stringshare_add("large");
_ethumb_plugins_load();
return ++initcount;
}
EAPI int
ethumb_shutdown(void)
{
if (initcount <= 0)
{
EINA_LOG_ERR("Init count not greater than 0 in shutdown.");
return 0;
}
initcount--;
if (initcount == 0)
{
_ethumb_plugins_unload();
eina_stringshare_del(_home_thumb_dir);
eina_stringshare_del(_thumb_category_normal);
eina_stringshare_del(_thumb_category_large);
evas_shutdown();
ecore_shutdown();
ecore_evas_shutdown();
edje_shutdown();
eina_log_domain_unregister(_log_dom);
_log_dom = -1;
eina_shutdown();
}
return initcount;
}
EAPI Ethumb *
ethumb_new(void)
{
Ethumb *ethumb;
Ecore_Evas *ee, *sub_ee;
Evas *e, *sub_e;
Evas_Object *o, *img;
ethumb = calloc(1, sizeof(Ethumb));
EINA_SAFETY_ON_NULL_RETURN_VAL(ethumb, NULL);
/* IF CHANGED, UPDATE DOCS in (Ethumb.c, Ethumb_Client.c, python...)!!! */
ethumb->tw = THUMB_SIZE_NORMAL;
ethumb->th = THUMB_SIZE_NORMAL;
ethumb->orientation = ETHUMB_THUMB_ORIENT_ORIGINAL;
ethumb->crop_x = 0.5;
ethumb->crop_y = 0.5;
ethumb->quality = 80;
ethumb->compress = 9;
ethumb->video.start = 0.1;
ethumb->video.time = 3;
ethumb->video.interval = 0.05;
ethumb->video.ntimes = 3;
ethumb->video.fps = 10;
ee = ecore_evas_buffer_new(1, 1);
e = ecore_evas_get(ee);
if (!e)
{
ERR("could not create ecore evas buffer");
free(ethumb);
return NULL;
}
evas_image_cache_set(e, 0);
evas_font_cache_set(e, 0);
o = ecore_evas_object_image_new(ee);
if (!o)
{
ERR("could not create sub ecore evas buffer");
ecore_evas_free(ee);
free(ethumb);
return NULL;
}
sub_ee = ecore_evas_object_ecore_evas_get(o);
sub_e = ecore_evas_object_evas_get(o);
ecore_evas_alpha_set(sub_ee, EINA_TRUE);
evas_image_cache_set(sub_e, 0);
evas_font_cache_set(sub_e, 0);
img = evas_object_image_add(sub_e);
if (!img)
{
ERR("could not create source objects.");
ecore_evas_free(ee);
free(ethumb);
return NULL;
}
ethumb->ee = ee;
ethumb->e = e;
ethumb->sub_ee = sub_ee;
ethumb->sub_e = sub_e;
ethumb->o = o;
ethumb->img = img;
DBG("ethumb=%p", ethumb);
return ethumb;
}
static void
_ethumb_frame_free(Ethumb_Frame *frame)
{
Evas_Object *o;
if (!frame)
return;
if (frame->swallow && frame->edje)
{
o = edje_object_part_swallow_get(frame->edje, frame->swallow);
if (o)
edje_object_part_unswallow(frame->edje, o);
}
eina_stringshare_del(frame->file);
eina_stringshare_del(frame->group);
eina_stringshare_del(frame->swallow);
if (frame->edje)
evas_object_del(frame->edje);
free(frame);
}
EAPI void
ethumb_free(Ethumb *ethumb)
{
EINA_SAFETY_ON_NULL_RETURN(ethumb);
DBG("ethumb=%p", ethumb);
if (ethumb->frame)
_ethumb_frame_free(ethumb->frame);
ethumb_file_free(ethumb);
evas_object_del(ethumb->o);
ecore_evas_free(ethumb->ee);
eina_stringshare_del(ethumb->thumb_dir);
eina_stringshare_del(ethumb->category);
if (ethumb->finished_idler)
ecore_idler_del(ethumb->finished_idler);
free(ethumb);
}
EAPI void
ethumb_thumb_fdo_set(Ethumb *e, Ethumb_Thumb_FDO_Size s)
{
EINA_SAFETY_ON_NULL_RETURN(e);
EINA_SAFETY_ON_FALSE_RETURN(s == ETHUMB_THUMB_NORMAL ||
s == ETHUMB_THUMB_LARGE);
DBG("ethumb=%p, size=%d", e, s);
if (s == ETHUMB_THUMB_NORMAL)
{
e->tw = THUMB_SIZE_NORMAL;
e->th = THUMB_SIZE_NORMAL;
}
else
{
e->tw = THUMB_SIZE_LARGE;
e->th = THUMB_SIZE_LARGE;
}
e->format = ETHUMB_THUMB_FDO;
e->aspect = ETHUMB_THUMB_KEEP_ASPECT;
e->orientation = ETHUMB_THUMB_ORIENT_ORIGINAL;
_ethumb_frame_free(e->frame);
e->frame = NULL;
eina_stringshare_del(e->thumb_dir);
eina_stringshare_del(e->category);
e->thumb_dir = NULL;
e->category = NULL;
}
EAPI void
ethumb_thumb_size_set(Ethumb *e, int tw, int th)
{
EINA_SAFETY_ON_NULL_RETURN(e);
EINA_SAFETY_ON_FALSE_RETURN(tw > 0);
EINA_SAFETY_ON_FALSE_RETURN(th > 0);
DBG("ethumb=%p, w=%d, h=%d", e, tw, th);
e->tw = tw;
e->th = th;
}
EAPI void
ethumb_thumb_size_get(const Ethumb *e, int *tw, int *th)
{
EINA_SAFETY_ON_NULL_RETURN(e);
if (tw) *tw = e->tw;
if (th) *th = e->th;
}
EAPI void
ethumb_thumb_format_set(Ethumb *e, Ethumb_Thumb_Format f)
{
EINA_SAFETY_ON_NULL_RETURN(e);
EINA_SAFETY_ON_FALSE_RETURN(f == ETHUMB_THUMB_FDO ||
f == ETHUMB_THUMB_JPEG ||
f == ETHUMB_THUMB_EET);
DBG("ethumb=%p, format=%d", e, f);
e->format = f;
}
EAPI Ethumb_Thumb_Format
ethumb_thumb_format_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->format;
}
EAPI void
ethumb_thumb_aspect_set(Ethumb *e, Ethumb_Thumb_Aspect a)
{
EINA_SAFETY_ON_NULL_RETURN(e);
EINA_SAFETY_ON_FALSE_RETURN(a == ETHUMB_THUMB_KEEP_ASPECT ||
a == ETHUMB_THUMB_IGNORE_ASPECT ||
a == ETHUMB_THUMB_CROP);
DBG("ethumb=%p, aspect=%d", e, a);
e->aspect = a;
}
EAPI Ethumb_Thumb_Aspect
ethumb_thumb_aspect_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->aspect;
}
EAPI void
ethumb_thumb_orientation_set(Ethumb *e, Ethumb_Thumb_Orientation o)
{
EINA_SAFETY_ON_NULL_RETURN(e);
EINA_SAFETY_ON_FALSE_RETURN(o == ETHUMB_THUMB_ORIENT_NONE ||
o == ETHUMB_THUMB_ROTATE_90_CW ||
o == ETHUMB_THUMB_ROTATE_180 ||
o == ETHUMB_THUMB_ROTATE_90_CCW ||
o == ETHUMB_THUMB_FLIP_HORIZONTAL ||
o == ETHUMB_THUMB_FLIP_VERTICAL ||
o == ETHUMB_THUMB_FLIP_TRANSPOSE ||
o == ETHUMB_THUMB_FLIP_TRANSVERSE ||
o == ETHUMB_THUMB_ORIENT_ORIGINAL);
DBG("ethumb=%p, orientation=%d", e, o);
e->orientation = o;
}
EAPI Ethumb_Thumb_Orientation
ethumb_thumb_orientation_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->orientation;
}
EAPI void
ethumb_thumb_crop_align_set(Ethumb *e, float x, float y)
{
EINA_SAFETY_ON_NULL_RETURN(e);
DBG("ethumb=%p, x=%f, y=%f", e, x, y);
e->crop_x = x;
e->crop_y = y;
}
EAPI void
ethumb_thumb_crop_align_get(const Ethumb *e, float *x, float *y)
{
EINA_SAFETY_ON_NULL_RETURN(e);
if (x) *x = e->crop_x;
if (y) *y = e->crop_y;
}
EAPI void
ethumb_thumb_quality_set(Ethumb *e, int quality)
{
EINA_SAFETY_ON_NULL_RETURN(e);
DBG("ethumb=%p, quality=%d", e, quality);
e->quality = quality;
}
EAPI int
ethumb_thumb_quality_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->quality;
}
EAPI void
ethumb_thumb_compress_set(Ethumb *e, int compress)
{
EINA_SAFETY_ON_NULL_RETURN(e);
DBG("ethumb=%p, compress=%d", e, compress);
e->compress = compress;
}
EAPI int
ethumb_thumb_compress_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->compress;
}
EAPI Eina_Bool
ethumb_frame_set(Ethumb *e, const char *theme_file, const char *group, const char *swallow)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
Ethumb_Frame *frame;
frame = e->frame;
DBG("ethumb=%p, theme_file=%s, group=%s, swallow=%s",
e, theme_file ? theme_file : "", group ? group : "",
swallow ? swallow : "");
if (frame)
{
edje_object_part_unswallow(frame->edje, e->img);
if (!theme_file)
_ethumb_frame_free(frame);
}
if (!theme_file)
{
e->frame = NULL;
return EINA_FALSE;
}
if (!frame)
{
frame = calloc(1, sizeof(Ethumb_Frame));
if (!frame)
{
ERR("could not allocate Ethumb_Frame structure.");
return EINA_FALSE;
}
frame->edje = edje_object_add(e->sub_e);
if (!frame->edje)
{
ERR("could not create edje frame object.");
_ethumb_frame_free(frame);
e->frame = NULL;
return EINA_FALSE;
}
}
if (!edje_object_file_set(frame->edje, theme_file, group))
{
ERR("could not load frame theme.");
_ethumb_frame_free(frame);
e->frame = NULL;
return EINA_FALSE;
}
edje_object_part_swallow(frame->edje, swallow, e->img);
if (!edje_object_part_swallow_get(frame->edje, swallow))
{
ERR("could not swallow image to edje frame.");
_ethumb_frame_free(frame);
e->frame = NULL;
return EINA_FALSE;
}
eina_stringshare_replace(&frame->file, theme_file);
eina_stringshare_replace(&frame->group, group);
eina_stringshare_replace(&frame->swallow, swallow);
e->frame = frame;
return EINA_TRUE;
}
EAPI void
ethumb_frame_get(const Ethumb *e, const char **theme_file, const char **group, const char **swallow)
{
EINA_SAFETY_ON_NULL_RETURN(e);
if (e->frame)
{
if (theme_file) *theme_file = e->frame->file;
if (group) *group = e->frame->group;
if (swallow) *swallow = e->frame->swallow;
}
else
{
if (theme_file) *theme_file = NULL;
if (group) *group = NULL;
if (swallow) *swallow = NULL;
}
}
static const char *
_ethumb_build_absolute_path(const char *path, char buf[PATH_MAX])
{
char *p;
int len;
if (!path)
return NULL;
p = buf;
if (path[0] == '/')
strcpy(p, path);
else if (path[0] == '~')
{
const char *home = getenv("HOME");
if (!home)
return NULL;
strcpy(p, home);
len = strlen(p);
p += len;
p[0] = '/';
p++;
strcpy(p, path + 2);
}
else
{
if (!getcwd(p, PATH_MAX))
return NULL;
len = strlen(p);
p += len;
p[0] = '/';
p++;
strcpy(p, path);
}
return buf;
}
EAPI void
ethumb_thumb_dir_path_set(Ethumb *e, const char *path)
{
char buf[PATH_MAX];
EINA_SAFETY_ON_NULL_RETURN(e);
DBG("ethumb=%p, path=%s", e, path ? path : "");
path = _ethumb_build_absolute_path(path, buf);
eina_stringshare_replace(&e->thumb_dir, path);
}
EAPI const char *
ethumb_thumb_dir_path_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
return e->thumb_dir;
}
EAPI void
ethumb_thumb_category_set(Ethumb *e, const char *category)
{
EINA_SAFETY_ON_NULL_RETURN(e);
DBG("ethumb=%p, category=%s", e, category ? category : "");
eina_stringshare_replace(&e->category, category);
}
EAPI const char *
ethumb_thumb_category_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
return e->category;
}
EAPI void
ethumb_video_start_set(Ethumb *e, float start)
{
EINA_SAFETY_ON_NULL_RETURN(e);
EINA_SAFETY_ON_FALSE_RETURN(start >= 0.0);
EINA_SAFETY_ON_FALSE_RETURN(start <= 1.0);
DBG("ethumb=%p, video_start=%f", e, start);
e->video.start = start;
}
EAPI float
ethumb_video_start_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->video.start;
}
EAPI void
ethumb_video_time_set(Ethumb *e, float t)
{
EINA_SAFETY_ON_NULL_RETURN(e);
DBG("ethumb=%p, video_start=%f", e, t);
e->video.time = t;
}
EAPI float
ethumb_video_time_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->video.time;
}
EAPI void
ethumb_video_interval_set(Ethumb *e, float interval)
{
EINA_SAFETY_ON_NULL_RETURN(e);
DBG("ethumb=%p, video_interval=%f", e, interval);
e->video.interval = interval;
}
EAPI float
ethumb_video_interval_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->video.interval;
}
EAPI void
ethumb_video_ntimes_set(Ethumb *e, unsigned int ntimes)
{
EINA_SAFETY_ON_NULL_RETURN(e);
EINA_SAFETY_ON_FALSE_RETURN(ntimes > 0);
DBG("ethumb=%p, video_ntimes=%d", e, ntimes);
e->video.ntimes = ntimes;
}
EAPI unsigned int
ethumb_video_ntimes_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->video.ntimes;
}
EAPI void
ethumb_video_fps_set(Ethumb *e, unsigned int fps)
{
EINA_SAFETY_ON_NULL_RETURN(e);
EINA_SAFETY_ON_FALSE_RETURN(fps > 0);
DBG("ethumb=%p, video_fps=%d", e, fps);
e->video.fps = fps;
}
EAPI unsigned int
ethumb_video_fps_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->video.fps;
}
EAPI void
ethumb_document_page_set(Ethumb *e, unsigned int page)
{
EINA_SAFETY_ON_NULL_RETURN(e);
DBG("ethumb=%p, document_page=%d", e, page);
e->document.page = page;
}
EAPI unsigned int
ethumb_document_page_get(const Ethumb *e)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
return e->document.page;
}
EAPI Eina_Bool
ethumb_file_set(Ethumb *e, const char *path, const char *key)
{
char buf[PATH_MAX];
EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
eina_stringshare_replace(&e->thumb_path, NULL);
eina_stringshare_replace(&e->thumb_key, NULL);
DBG("ethumb=%p, path=%s, key=%s", e, path ? path : "", key ? key : "");
if (path && access(path, R_OK))
{
ERR("couldn't access file \"%s\"", path);
return EINA_FALSE;
}
path = _ethumb_build_absolute_path(path, buf);
eina_stringshare_replace(&e->src_hash, NULL);
eina_stringshare_replace(&e->src_path, path);
eina_stringshare_replace(&e->src_key, key);
return EINA_TRUE;
}
EAPI void
ethumb_file_get(const Ethumb *e, const char **path, const char **key)
{
2009-04-24 14:02:40 -07:00
EINA_SAFETY_ON_NULL_RETURN(e);
if (path) *path = e->src_path;
if (key) *key = e->src_key;
}
static const char ACCEPTABLE_URI_CHARS[96] = {
/* ! " # $ % & ' ( ) * + , - . / */
0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
/* @ A B C D E F G H I J K L M N O */
0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
/* P Q R S T U V W X Y Z [ \ ] ^ _ */
0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
/* ` a b c d e f g h i j k l m n o */
0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
/* p q r s t u v w x y z { | } ~ DEL */
0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20
};
static const char *
_ethumb_generate_hash(const char *file)
{
int n;
MD5_CTX ctx;
char md5out[(2 * MD5_HASHBYTES) + 1];
unsigned char hash[MD5_HASHBYTES];
static const char hex[] = "0123456789abcdef";
char *uri;
char *t;
const unsigned char *c;
#ifdef HAVE_XATTR
ssize_t length;
length = getxattr(file, "user.e.md5", NULL, 0);
if (length > 0)
{
char *tmp;
tmp = alloca(length);
length = getxattr(file, "user.e.md5", tmp, length);
/* check if we have at least something that look like a md5 hash */
if (length > 0 && (length == MD5_HASHBYTES * 2 + 1))
{
tmp[length] = '\0';
return eina_stringshare_add(tmp);
}
}
#endif
#define _check_uri_char(c) \
((c) >= 32 && (c) < 128 && (ACCEPTABLE_URI_CHARS[(c) - 32] & 0x08))
EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
uri = alloca(3 * strlen(file) + 9);
memcpy(uri, "file://", sizeof("file://") - 1);
t = uri + sizeof("file://") - 1;
for (c = (const unsigned char *)file; *c != '\0'; c++)
{
if (!_check_uri_char(*c))
{
*t++ = '%';
*t++ = hex[*c >> 4];
*t++ = hex[*c & 15];
}
else