forked from enlightenment/efl
efl: vpath subsystem
this adds a core vpath subsystem to efl that allows paths like: ~/file.jpg ~user/file.jpg (:tmp/file.jpg (:config/file.jpg (:videos/file.mp4 (:pictures/file.jpg (:app.config/mycfg.cfg etc. to be translated/looked up. it is desitgned to be async and call event callbacks when ready. the reason for this complexity is fo in future also handle: file:///whatever/file.jpg http://blah.com/file.jpg https://blah.com/file.jpg ssh://blah.com:~/file.jpg etc. @feature
This commit is contained in:
parent
a7400abbf6
commit
6291c61556
|
@ -23,6 +23,11 @@ efl_eolian_files = \
|
|||
lib/efl/interfaces/efl_gfx_filter.eo \
|
||||
lib/efl/interfaces/efl_model_base.eo \
|
||||
lib/efl/interfaces/efl_animator.eo \
|
||||
lib/efl/interfaces/efl_vpath.eo \
|
||||
lib/efl/interfaces/efl_vpath_manager.eo \
|
||||
lib/efl/interfaces/efl_vpath_file.eo \
|
||||
lib/efl/interfaces/efl_vpath_core.eo \
|
||||
lib/efl/interfaces/efl_vpath_file_core.eo \
|
||||
$(efl_eolian_legacy_files) \
|
||||
$(NULL)
|
||||
|
||||
|
@ -55,7 +60,11 @@ lib_LTLIBRARIES += lib/efl/libefl.la
|
|||
lib_efl_libefl_la_SOURCES = \
|
||||
lib/efl/interfaces/efl_interfaces_main.c \
|
||||
lib/efl/interfaces/efl_model_common.c \
|
||||
lib/efl/interfaces/efl_gfx_shape.c
|
||||
lib/efl/interfaces/efl_gfx_shape.c \
|
||||
lib/efl/interfaces/efl_vpath_file.c \
|
||||
lib/efl/interfaces/efl_vpath_manager.c \
|
||||
lib/efl/interfaces/efl_vpath_core.c \
|
||||
lib/efl/interfaces/efl_vpath_file_core.c
|
||||
|
||||
lib_efl_libefl_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl -I$(top_srcdir)/src/lib/efl @EFL_CFLAGS@ -DEFL_GFX_FILTER_BETA
|
||||
lib_efl_libefl_la_LIBADD = @EFL_LIBS@
|
||||
|
|
|
@ -50,6 +50,12 @@ typedef struct tm Efl_Time;
|
|||
|
||||
#include <Efl_Model_Common.h>
|
||||
|
||||
#include "interfaces/efl_vpath_file.eo.h"
|
||||
#include "interfaces/efl_vpath.eo.h"
|
||||
#include "interfaces/efl_vpath_core.eo.h"
|
||||
#include "interfaces/efl_vpath_manager.eo.h"
|
||||
#include "interfaces/efl_vpath_file_core.eo.h"
|
||||
|
||||
/* Data types */
|
||||
#include "interfaces/efl_gfx_types.eot.h"
|
||||
typedef Efl_Gfx_Path_Command_Type Efl_Gfx_Path_Command;
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include "interfaces/efl_gfx_filter.eo.c"
|
||||
|
||||
#include "interfaces/efl_vpath.eo.c"
|
||||
|
||||
EAPI const Eo_Event_Description _EFL_GFX_CHANGED =
|
||||
EO_EVENT_DESCRIPTION("Graphics changed");
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
interface Efl.Vpath
|
||||
{
|
||||
[[ VPath is the EFL "Virtual Path" system that maps paths and downloads
|
||||
You can provide virtual paths common in unix shells like:
|
||||
"~/file.jpg"
|
||||
"~username/file.png"
|
||||
And also other extended paths like:
|
||||
"(:cache/file.png"
|
||||
"(:videos/file.mp4"
|
||||
...
|
||||
And in future:
|
||||
"file:///blah.jpg"
|
||||
"http://blah.com/file.jpg"
|
||||
"https://blahblah.com/file.jpg"
|
||||
"ssh://blahblah.com:~/file.jpg"
|
||||
...
|
||||
]]
|
||||
legacy_prefix: null;
|
||||
eo_prefix: efl_vpath;
|
||||
methods {
|
||||
fetch {
|
||||
[[ Fetch a new Vpath File object from the Vpath system ]]
|
||||
params {
|
||||
path: const(char)*; [[ The input virtual file path to fetch ]]
|
||||
}
|
||||
return: own(Efl.Vpath_File *); [[ An object representing the file ]]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,351 @@
|
|||
#include "config.h"
|
||||
#include "Efl.h"
|
||||
|
||||
#ifdef HAVE_GETPWENT
|
||||
# include <sys/types.h>
|
||||
# include <pwd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MY_CLASS EFL_VPATH_CORE_CLASS
|
||||
|
||||
typedef struct _Efl_Vpath_Core_Data Efl_Vpath_Core_Data;
|
||||
|
||||
struct _Efl_Vpath_Core_Data
|
||||
{
|
||||
Eina_Spinlock lock;
|
||||
Eina_Hash *meta;
|
||||
};
|
||||
|
||||
static Efl_Vpath_Core *vpath_core = NULL;
|
||||
|
||||
EOLIAN static Eo_Base *
|
||||
_efl_vpath_core_eo_base_constructor(Eo *obj, Efl_Vpath_Core_Data *pd)
|
||||
{
|
||||
char buf[PATH_MAX], bufhome[PATH_MAX], *s;
|
||||
const char *home;
|
||||
|
||||
if (vpath_core) return NULL;
|
||||
obj = eo_constructor(eo_super(obj, MY_CLASS));
|
||||
pd->meta = eina_hash_string_superfast_new
|
||||
((Eina_Free_Cb)eina_stringshare_del);
|
||||
eina_spinlock_new(&(pd->lock));
|
||||
|
||||
vpath_core = obj;
|
||||
|
||||
// $HOME / ~/ etc.
|
||||
home = eina_environment_home_get();
|
||||
if (!home)
|
||||
{
|
||||
uid_t uid = getuid();
|
||||
struct stat st;
|
||||
|
||||
snprintf(bufhome, sizeof(bufhome), "/tmp/%i", (int)uid);
|
||||
mkdir(bufhome, S_IRUSR | S_IWUSR | S_IXUSR);
|
||||
if (stat(bufhome, &st) == 0) home = bufhome;
|
||||
else
|
||||
{
|
||||
if (stat("/tmp", &st) == 0) home = "/tmp";
|
||||
else home = "/";
|
||||
}
|
||||
}
|
||||
efl_vpath_core_meta_set(obj, "home", home);
|
||||
// tmp dir - system wide
|
||||
s = getenv("TMPDIR");
|
||||
if (!s) s = getenv("TMP");
|
||||
if (!s) s = getenv("TEMPDIR");
|
||||
if (!s) s = getenv("TEMP");
|
||||
if (!s) s = "/tmp";
|
||||
efl_vpath_core_meta_set(obj, "tmp", s);
|
||||
|
||||
#define ENV_HOME_SET(_env, _dir, _meta) \
|
||||
if (!(s = getenv(_env))) { \
|
||||
snprintf(buf, sizeof(buf), "%s/"_dir, home); s = buf; \
|
||||
} efl_vpath_core_meta_set(obj, _meta, s);
|
||||
// $XDG_DATA_HOME defines the base directory relative to which user
|
||||
// specific data files should be stored. If $XDG_DATA_HOME is either
|
||||
// not set or empty, a default equal to $HOME/.local/share should be
|
||||
// used.
|
||||
ENV_HOME_SET("XDG_DATA_HOME", ".local/share", "data");
|
||||
// $XDG_CONFIG_HOME defines the base directory relative to which user
|
||||
// specific configuration files should be stored. If $XDG_CONFIG_HOME
|
||||
// is either not set or empty, a default equal to $HOME/.config should
|
||||
// be used.
|
||||
ENV_HOME_SET("XDG_CONFIG_HOME", ".config", "config");
|
||||
// $XDG_CACHE_HOME defines the base directory relative to which
|
||||
// user specific non-essential data files should be stored. If
|
||||
// $XDG_CACHE_HOME is either not set or empty, a default equal to
|
||||
// $HOME/.cache should be used.
|
||||
ENV_HOME_SET("XDG_CACHE_HOME", ".cache", "cache");
|
||||
// $XDG_RUNTIME_DIR defines the base directory relative to which
|
||||
// user-specific non-essential runtime files and other file objects
|
||||
// (such as sockets, named pipes, ...) should be stored. The
|
||||
// directory MUST be owned by the user, and he MUST be the only one
|
||||
// having read and write access to it. Its Unix access mode MUST
|
||||
// be 0700.
|
||||
if (!(s = getenv("XDG_RUNTIME_DIR")))
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
// fallback - make ~/.run
|
||||
snprintf(buf, sizeof(buf), "%s/.run", home);
|
||||
mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);
|
||||
// if mkdir worked - use, otherwse use /tmp
|
||||
if (stat(bufhome, &st) == 0) s = buf;
|
||||
else
|
||||
{
|
||||
uid_t uid;
|
||||
|
||||
// use /tmp/.run-UID if ~/ dir cant be made
|
||||
s = (char *)efl_vpath_core_meta_get(obj, "tmp");
|
||||
uid = getuid();
|
||||
snprintf(buf, sizeof(buf), "%s/.run-%i", s, (int)uid);
|
||||
mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);
|
||||
// if ok - use it or fall back to /tmp
|
||||
if (stat(bufhome, &st) == 0) s = buf;
|
||||
else s = (char *)efl_vpath_core_meta_get(obj, "tmp");
|
||||
}
|
||||
}
|
||||
efl_vpath_core_meta_set(obj, "run", s);
|
||||
// https://www.freedesktop.org/wiki/Software/xdg-user-dirs/
|
||||
// https://wiki.archlinux.org/index.php/Xdg_user_directories
|
||||
// ^^^^ we don't handle:
|
||||
// /etc/xdg/user-dirs.conf
|
||||
// /etc/xdg/user-dirs.defaults
|
||||
// (:config/user-dirs.conf
|
||||
// (:config/user-dirs.defaults
|
||||
|
||||
// $XDG_DESKTOP_DIR="$HOME/Desktop"
|
||||
ENV_HOME_SET("XDG_DESKTOP_DIR", "Desktop", "desktop");
|
||||
// $XDG_DOCUMENTS_DIR="$HOME/Documents"
|
||||
ENV_HOME_SET("XDG_DOCUMENTS_DIR", "Documents", "documents");
|
||||
// $XDG_DOWNLOAD_DIR="$HOME/Downloads"
|
||||
ENV_HOME_SET("XDG_DOWNLOAD_DIR", "Downloads", "downloads");
|
||||
// $XDG_MUSIC_DIR="$HOME/Music"
|
||||
ENV_HOME_SET("XDG_MUSIC_DIR", "Music", "music");
|
||||
// $XDG_PICTURES_DIR="$HOME/Pictures"
|
||||
ENV_HOME_SET("XDG_PICTURES_DIR", "Pictures", "pictures");
|
||||
// $XDG_PUBLICSHARE_DIR="$HOME/Public"
|
||||
ENV_HOME_SET("XDG_PUBLIC_DIR", "Public", "public");
|
||||
// $XDG_TEMPLATES_DIR="$HOME/.Templates"
|
||||
ENV_HOME_SET("XDG_TEMPLATES_DIR", ".Templates", "templates");
|
||||
// $XDG_VIDEOS_DIR="$HOME/Videos"
|
||||
ENV_HOME_SET("XDG_VIDEOS_DIR", "Videos", "videos");
|
||||
|
||||
// Add ~/Applications for user-installed apps
|
||||
ENV_HOME_SET("E_APPS_DIR", "Applications", "apps");
|
||||
|
||||
// XXX: do the below ... later
|
||||
//
|
||||
// FHS FOR APP:
|
||||
// app.dir = PREFIX
|
||||
// app.bin = PREFIX/bin
|
||||
// app.lib = PREFIX/lib
|
||||
// app.data = PREFIX/share/APPNAME
|
||||
// app.locale = PREFIX/share/locale
|
||||
//
|
||||
// XXX: figure out how to merge these with XDG/FHS?
|
||||
// Tizen:
|
||||
// App Dir Structure:
|
||||
// bin Executable binary pathOwner: Read
|
||||
// lib Library pathOwner: Read
|
||||
// data Used to store private data of an application.
|
||||
// res Used to read resource files that are delivered with the application package.
|
||||
// shared Parent directory of the data, res, and trusted sub-directories. Files in this directory cannot be delivered with the application package.Owner: Read
|
||||
// shared/data Used to share data with other applications.
|
||||
// shared/res Used to share resources with other applications. The resource files are delivered with the application package.
|
||||
// shared/trusted Used to share data with family of trusted applications. The family applications signed with the same certificate can access data in the shared/trusted directory.
|
||||
//
|
||||
// XXX: figure out how to merge these with XDG?
|
||||
// Media/...vvv
|
||||
// Images Used for Image data.Read and Write
|
||||
// Sounds Used for Sound data.
|
||||
// Videos Used for Video data.
|
||||
// Cameras Used for Camera pictures.
|
||||
// Downloads Used for Downloaded data.
|
||||
// Music Used for Music data.
|
||||
// Documents Used for Documents.
|
||||
// Others Used for other types.
|
||||
// System Ringtones Used for System default ringtones.Read
|
||||
//
|
||||
// $TZ_SYS_HOME=/home
|
||||
// $TZ_SYS_DB=/var/db
|
||||
// $TZ_SYS_CONFIG=/var/kdb
|
||||
// $TZ_SYS_CONFIG_VOLATILE=/run/kdb
|
||||
// $TZ_SYS_APP=/usr/apps
|
||||
// $TZ_SYS_DESKTOP_APP=/usr/share/applications
|
||||
//
|
||||
// $TS_USER_DB=<user_homeid>/.tizen/db
|
||||
// $TZ_USER_CONFIG=<user_home_dir>/.tizen/kdb
|
||||
// $TZ_USER_APP=<user_home_dir>/.tizen/apps
|
||||
// $TZ_USER_DESKTOP_APP=<user_home_dir>/.tizen/desktop
|
||||
// $TZ_USER_DOCUMENTS=<user_home_dir>/Documents
|
||||
// $TZ_USER_PICTURES=<user_home_dir>/Pictures
|
||||
// $TZ_USER_VIDEOS=<user_home_dir>/Videos
|
||||
// $TZ_USER_MUSIC=<user_home_dir>/Music
|
||||
// $TZ_USER_DOWNLOADS=<user_home_dir>/Downloads
|
||||
// $TZ_USER_PUBLIC=<user_home_dir>/Public
|
||||
return obj;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_vpath_core_eo_base_destructor(Eo *obj, Efl_Vpath_Core_Data *pd)
|
||||
{
|
||||
eina_hash_free(pd->meta);
|
||||
pd->meta = NULL;
|
||||
eina_spinlock_free(&(pd->lock));
|
||||
if (vpath_core == obj) vpath_core = NULL;
|
||||
eo_destructor(eo_super(obj, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static Efl_Vpath_Core *
|
||||
_efl_vpath_core_get(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED)
|
||||
{
|
||||
// no locks here as we expect efl to init this early in main "thread"
|
||||
if (!vpath_core) vpath_core = eo_add(EFL_VPATH_CORE_CLASS, NULL);
|
||||
return vpath_core;
|
||||
}
|
||||
|
||||
EOLIAN static const char *
|
||||
_efl_vpath_core_meta_get(Eo *obj EINA_UNUSED, Efl_Vpath_Core_Data *pd, const char *key)
|
||||
{
|
||||
const char *meta;
|
||||
|
||||
if (!key) return NULL;
|
||||
eina_spinlock_take(&(pd->lock));
|
||||
meta = eina_hash_find(pd->meta, key);
|
||||
eina_spinlock_release(&(pd->lock));
|
||||
return meta;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_vpath_core_meta_set(Eo *obj EINA_UNUSED, Efl_Vpath_Core_Data *pd, const char *key, const char *path)
|
||||
{
|
||||
if (!key) return;
|
||||
eina_spinlock_take(&(pd->lock));
|
||||
if (path) eina_hash_add(pd->meta, key, eina_stringshare_add(path));
|
||||
else eina_hash_del(pd->meta, key, NULL);
|
||||
eina_spinlock_release(&(pd->lock));
|
||||
}
|
||||
|
||||
EOLIAN static Efl_Vpath_File *
|
||||
_efl_vpath_core_efl_vpath_fetch(Eo *obj, Efl_Vpath_Core_Data *pd EINA_UNUSED, const char *path)
|
||||
{
|
||||
Efl_Vpath_File_Core *file;
|
||||
|
||||
file = eo_add(EFL_VPATH_FILE_CORE_CLASS, obj);
|
||||
efl_vpath_file_path_set(file, path);
|
||||
// XXX: implement parse of path then look up in hash if not just create
|
||||
// object where path and result are the same and return that with
|
||||
// path set and result set to resolved path - return obj handler calls
|
||||
// "do" on object to get the result inside fetched or failed callback.
|
||||
// if it's a url then we need a new classs that overrides the do and
|
||||
// begins a fetch and on finish calls the event cb or when wait is called
|
||||
if (path)
|
||||
{
|
||||
// /* <- full path
|
||||
if (path[0] == '/')
|
||||
{
|
||||
efl_vpath_file_result_set(file, path);
|
||||
return file;
|
||||
}
|
||||
// .*
|
||||
if (path[0] == '.')
|
||||
{
|
||||
// .[/]* <- current dir relative
|
||||
if ((path[1] == '/') || (path[1] == 0))
|
||||
{
|
||||
efl_vpath_file_result_set(file, path);
|
||||
return file;
|
||||
}
|
||||
// ..[/]* <- parent dir relative
|
||||
if ((path[1] == '.') && ((path[2] == '/') || (path[2] == 0)))
|
||||
{
|
||||
efl_vpath_file_result_set(file, path);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
// ~* ...
|
||||
if (path[0] == '~')
|
||||
{
|
||||
// ~/ <- home directory
|
||||
if (path[1] == '/')
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
const char *home = efl_vpath_core_meta_get(obj, "home");
|
||||
|
||||
if (home)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%s%s", home, path + 1);
|
||||
efl_vpath_file_result_set(file, buf);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_GETPWENT
|
||||
// ~username/ <- homedir of user "username"
|
||||
else
|
||||
{
|
||||
const char *p;
|
||||
struct passwd pwent, *pwent2 = NULL;
|
||||
char *name, buf[PATH_MAX], pwbuf[8129];
|
||||
|
||||
for (p = path + 1; *p; p++)
|
||||
{
|
||||
if (*p =='/') break;
|
||||
}
|
||||
name = alloca(p - path);
|
||||
strncpy(name, path + 1, p - path - 1);
|
||||
name[p - path - 1] = 0;
|
||||
if (!getpwnam_r(name, &pwent, pwbuf, sizeof(pwbuf), &pwent2))
|
||||
{
|
||||
if ((pwent2) && (pwent.pw_dir))
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%s%s", pwent.pw_dir, p);
|
||||
efl_vpath_file_result_set(file, buf);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_GETPWENT */
|
||||
}
|
||||
// (:xxx/* ... <- meta has table
|
||||
if ((path[0] == '(') && (path[1] == ':'))
|
||||
{
|
||||
const char *p, *meta;
|
||||
char *name, buf[PATH_MAX];
|
||||
|
||||
for (p = path + 2; *p; p++)
|
||||
{
|
||||
if (*p =='/') break;
|
||||
}
|
||||
name = alloca(p - path);
|
||||
strncpy(name, path + 2, p - path - 2);
|
||||
name[p - path - 2] = 0;
|
||||
eina_spinlock_take(&(pd->lock));
|
||||
meta = eina_hash_find(pd->meta, name);
|
||||
eina_spinlock_release(&(pd->lock));
|
||||
if (meta)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "%s%s", meta, p);
|
||||
efl_vpath_file_result_set(file, buf);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
// file:/// <- local file path uri
|
||||
// file://localhost/ <- local file path uri
|
||||
// file://hostname/ <- remove file path uri
|
||||
// XXX: %c4,%17,%fe etc. are bytes escaped
|
||||
// http://www.ietf.org/rfc/rfc2396.txt
|
||||
// http://www.ietf.org/rfc/rfc1738.txt
|
||||
// http://equinox-project.org/spec/file-uri-spec.txt
|
||||
// http://en.wikipedia.org/wiki/File_URI_scheme
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
#include "interfaces/efl_vpath_core.eo.c"
|
|
@ -0,0 +1,31 @@
|
|||
class Efl.Vpath.Core (Eo.Base, Efl.Vpath)
|
||||
{
|
||||
[[ Core EFL implementation of a Vpath system ]]
|
||||
legacy_prefix: null;
|
||||
eo_prefix: efl_vpath_core;
|
||||
methods {
|
||||
get @class {
|
||||
[[ This gets the global EFL Core Vpath class - only 1 - singleton ]]
|
||||
return: Efl.Vpath.Core *; [[ Get the singleton core vpath ]]
|
||||
}
|
||||
meta_set {
|
||||
[[ A Meta key is a mapping from a virtual path to a real one ]]
|
||||
params {
|
||||
key: const(char)*; [[ The magic path key being looked up ]]
|
||||
path: const(char)*; [[ The real path the key maps to ]]
|
||||
}
|
||||
}
|
||||
meta_get {
|
||||
[[ This returns the real path set for a Meta key, or NULL if not ]]
|
||||
params {
|
||||
key: const(char)*; [[ The magic path key being looked up ]]
|
||||
}
|
||||
return: const(char)*;
|
||||
}
|
||||
}
|
||||
implements {
|
||||
Eo.Base.constructor;
|
||||
Eo.Base.destructor;
|
||||
Efl.Vpath.fetch;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#include "config.h"
|
||||
#include "Efl.h"
|
||||
|
||||
#define MY_CLASS EFL_VPATH_FILE_CLASS
|
||||
|
||||
typedef struct _Efl_Vpath_File_Data Efl_Vpath_File_Data;
|
||||
|
||||
struct _Efl_Vpath_File_Data
|
||||
{
|
||||
const char *path;
|
||||
const char *result;
|
||||
Eina_Bool called : 1;
|
||||
};
|
||||
|
||||
EOLIAN static void
|
||||
_efl_vpath_file_path_set(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd, const char *path)
|
||||
{
|
||||
eina_stringshare_replace(&(pd->path), path);
|
||||
}
|
||||
|
||||
EOLIAN static const char *
|
||||
_efl_vpath_file_path_get(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd)
|
||||
{
|
||||
return pd->path;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_vpath_file_result_set(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd, const char *path)
|
||||
{
|
||||
eina_stringshare_replace(&(pd->result), path);
|
||||
}
|
||||
|
||||
EOLIAN static const char *
|
||||
_efl_vpath_file_result_get(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd)
|
||||
{
|
||||
return pd->result;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_vpath_file_do(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd)
|
||||
{
|
||||
if (pd->called) return EINA_FALSE;
|
||||
pd->called = EINA_TRUE;
|
||||
eo_event_callback_call(obj, EFL_VPATH_FILE_EVENT_FETCHED, NULL);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_vpath_file_wait(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd EINA_UNUSED)
|
||||
{
|
||||
if (!pd->called)
|
||||
{
|
||||
pd->called = EINA_TRUE;
|
||||
if (pd->result)
|
||||
eo_event_callback_call(obj, EFL_VPATH_FILE_EVENT_FETCHED, NULL);
|
||||
else
|
||||
eo_event_callback_call(obj, EFL_VPATH_FILE_EVENT_FAILED, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#include "interfaces/efl_vpath_file.eo.c"
|
|
@ -0,0 +1,46 @@
|
|||
class Efl.Vpath_File (Eo.Base)
|
||||
{
|
||||
[[ VPath File is an actual representation of a downloaded/mapped vpath file
|
||||
|
||||
Keep this object around for as long as you need to use the file as it
|
||||
may have been downloaded and kept as a local temporary file and
|
||||
deletion may remove it.
|
||||
|
||||
When you have a Vpath File object for the first time, call the do()
|
||||
method on it to actually begin/do the mapping. From here the
|
||||
fetched or failed event callbacks will be called, inside of which or
|
||||
afterwards you can fetch the resulting local file path by getting the
|
||||
result property.
|
||||
]]
|
||||
legacy_prefix: null;
|
||||
eo_prefix: efl_vpath_file;
|
||||
methods {
|
||||
@property path {
|
||||
[[ The original source path provided to lookup/fetch from ]]
|
||||
set {}
|
||||
get {}
|
||||
values {
|
||||
path: const(char)*; [[ The input virtual path to a file ]]
|
||||
}
|
||||
}
|
||||
@property result {
|
||||
[[ The resulting real local file path to open/read ]]
|
||||
set {}
|
||||
get {}
|
||||
values {
|
||||
path: const(char)*; [[ The resulting destination file ]]
|
||||
}
|
||||
}
|
||||
do {
|
||||
[[ Actually begin the resolving here - emit event now or do later ]]
|
||||
return: bool; [[ Result callback already called ]]
|
||||
}
|
||||
wait {
|
||||
[[ If not fteched yet, wait until it is and call result cb ]]
|
||||
}
|
||||
}
|
||||
events {
|
||||
fetched; [[ File successfully mapped/fetched ]]
|
||||
failed; [[ File fetch or mapping failed ]]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
#include "config.h"
|
||||
#include "Efl.h"
|
||||
|
||||
#define MY_CLASS EFL_VPATH_FILE_CORE_CLASS
|
||||
|
||||
typedef struct _Efl_Vpath_File_Core_Data Efl_Vpath_File_Core_Data;
|
||||
|
||||
struct _Efl_Vpath_File_Core_Data
|
||||
{
|
||||
int dummy;
|
||||
};
|
||||
|
||||
EOLIAN static Eo_Base *
|
||||
_efl_vpath_file_core_eo_base_constructor(Eo *obj, Efl_Vpath_File_Core_Data *pd)
|
||||
{
|
||||
obj = eo_constructor(eo_super(obj, MY_CLASS));
|
||||
pd->dummy = 0;
|
||||
return obj;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_vpath_file_core_eo_base_destructor(Eo *obj, Efl_Vpath_File_Core_Data *pd)
|
||||
{
|
||||
pd->dummy = 0;
|
||||
eo_destructor(eo_super(obj, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_efl_vpath_file_core_efl_vpath_file_do(Eo *obj, Efl_Vpath_File_Core_Data *pd)
|
||||
{
|
||||
const char *path;
|
||||
|
||||
if (efl_vpath_file_result_get(obj))
|
||||
return efl_vpath_file_do(eo_super(obj, MY_CLASS));
|
||||
// vpath core didn't find a match, so it'ss likely a protocol like
|
||||
// http:// etc. etc. so deal with that here
|
||||
path = efl_vpath_file_path_get(obj);
|
||||
if (path)
|
||||
{
|
||||
if ((!strncasecmp(path, "http://", 7)) ||
|
||||
(!strncasecmp(path, "https://", 8)))
|
||||
{
|
||||
// XXX: handle urls --- need a loop object
|
||||
}
|
||||
}
|
||||
// ...
|
||||
pd->dummy = 0;
|
||||
|
||||
// not a magic path - just set result to path
|
||||
efl_vpath_file_result_set(obj, efl_vpath_file_path_get(obj));
|
||||
return efl_vpath_file_do(eo_super(obj, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_vpath_file_core_efl_vpath_file_wait(Eo *obj, Efl_Vpath_File_Core_Data *pd)
|
||||
{
|
||||
if (efl_vpath_file_result_get(obj))
|
||||
{
|
||||
efl_vpath_file_do(eo_super(obj, MY_CLASS));
|
||||
return;
|
||||
}
|
||||
pd->dummy = 0;
|
||||
// XXX: not found yet, so do what is necessary
|
||||
}
|
||||
|
||||
#include "interfaces/efl_vpath_file_core.eo.c"
|
|
@ -0,0 +1,12 @@
|
|||
class Efl.Vpath_File.Core (Efl.Vpath_File)
|
||||
{
|
||||
[[ Core EFL implementation of a Vpath File ]]
|
||||
legacy_prefix: null;
|
||||
eo_prefix: efl_vpath_file_core;
|
||||
implements {
|
||||
Eo.Base.constructor;
|
||||
Eo.Base.destructor;
|
||||
Efl.Vpath_File.do;
|
||||
Efl.Vpath_File.wait;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
#include "config.h"
|
||||
#include "Efl.h"
|
||||
|
||||
#define MY_CLASS EFL_VPATH_MANAGER_CLASS
|
||||
|
||||
typedef struct _Efl_Vpath_Manager_Data Efl_Vpath_Manager_Data;
|
||||
typedef struct _Efl_Vpath_Manager_Entry Efl_Vpath_Manager_Entry;
|
||||
|
||||
struct _Efl_Vpath_Manager_Data
|
||||
{
|
||||
Eina_List *list;
|
||||
};
|
||||
|
||||
struct _Efl_Vpath_Manager_Entry
|
||||
{
|
||||
Efl_Vpath *vpath;
|
||||
int priority;
|
||||
};
|
||||
|
||||
static Efl_Vpath_Manager_Data vpath_manager =
|
||||
{
|
||||
NULL
|
||||
};
|
||||
|
||||
EOLIAN static Efl_Vpath_File *
|
||||
_efl_vpath_manager_fetch(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED, const char *path)
|
||||
{
|
||||
Efl_Vpath_Manager_Entry *entry;
|
||||
Eina_List *l;
|
||||
Efl_Vpath_File *file;
|
||||
|
||||
EINA_LIST_FOREACH(vpath_manager.list, l, entry)
|
||||
{
|
||||
file = efl_vpath_fetch(entry->vpath, path);
|
||||
if (file) return file;
|
||||
}
|
||||
file = eo_add(EFL_VPATH_FILE_CLASS, NULL);
|
||||
if (file)
|
||||
{
|
||||
efl_vpath_file_path_set(file, path);
|
||||
efl_vpath_file_result_set(file, path);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
static int
|
||||
_register_sort_cb(Efl_Vpath_Manager_Entry *e1, Efl_Vpath_Manager_Entry *e2)
|
||||
{
|
||||
// sort higher numbers first in list
|
||||
return (e2->priority - e1->priority);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_vpath_del(void *data, const Eo_Event *event)
|
||||
{
|
||||
efl_vpath_manager_unregister(data, event->obj);
|
||||
eo_event_callback_del(event->obj, EO_BASE_EVENT_DEL, _cb_vpath_del, data);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_vpath_manager_register(Eo *obj, void *pd EINA_UNUSED, int priority, Efl_Vpath *vpath)
|
||||
{
|
||||
Efl_Vpath_Manager_Entry *entry = malloc(sizeof(Efl_Vpath_Manager_Entry));
|
||||
entry->vpath = vpath;
|
||||
entry->priority = priority;
|
||||
eo_event_callback_add(vpath, EO_BASE_EVENT_DEL, _cb_vpath_del, obj);
|
||||
vpath_manager.list = eina_list_sorted_insert
|
||||
(vpath_manager.list, EINA_COMPARE_CB(_register_sort_cb), entry);
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_vpath_manager_unregister(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED, Efl_Vpath *vpath)
|
||||
{
|
||||
Efl_Vpath_Manager_Entry *entry;
|
||||
Eina_List *l;
|
||||
|
||||
EINA_LIST_FOREACH(vpath_manager.list, l, entry)
|
||||
{
|
||||
if (entry->vpath == vpath)
|
||||
{
|
||||
vpath_manager.list = eina_list_remove_list(vpath_manager.list, l);
|
||||
free(entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "interfaces/efl_vpath_manager.eo.c"
|
|
@ -0,0 +1,28 @@
|
|||
class Efl.Vpath_Manager (Eo.Base)
|
||||
{
|
||||
[[ Vpath Manager manages multiple VPath objects that remap/download ]]
|
||||
legacy_prefix: null;
|
||||
eo_prefix: efl_vpath_manager;
|
||||
methods {
|
||||
fetch @class {
|
||||
[[ This class function fetches a Vpath File given an input path ]]
|
||||
params {
|
||||
path: const(char)*; [[ The input virtual file path to fetch ]]
|
||||
}
|
||||
return: own(Efl.Vpath_File *); [[ An object representing the file ]]
|
||||
}
|
||||
register @class {
|
||||
[[ ]]
|
||||
params {
|
||||
priority: int; [[ Search order - higher values tired first ]]
|
||||
vpath: Efl.Vpath * @nonull; [[ A Vpath implementation object ]]
|
||||
}
|
||||
}
|
||||
unregister @class {
|
||||
[[ ]]
|
||||
params {
|
||||
vpath: Efl.Vpath * @nonull; [[ A Vpath implementation object ]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue