efl: vpath subsystem
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>
Fri, 1 Apr 2016 01:45:07 +0000 (10:45 +0900)
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>
Tue, 5 Apr 2016 07:22:59 +0000 (16:22 +0900)
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

12 files changed:
src/Makefile_Efl.am
src/lib/efl/Efl.h
src/lib/efl/interfaces/efl_interfaces_main.c
src/lib/efl/interfaces/efl_vpath.eo [new file with mode: 0644]
src/lib/efl/interfaces/efl_vpath_core.c [new file with mode: 0644]
src/lib/efl/interfaces/efl_vpath_core.eo [new file with mode: 0644]
src/lib/efl/interfaces/efl_vpath_file.c [new file with mode: 0644]
src/lib/efl/interfaces/efl_vpath_file.eo [new file with mode: 0644]
src/lib/efl/interfaces/efl_vpath_file_core.c [new file with mode: 0644]
src/lib/efl/interfaces/efl_vpath_file_core.eo [new file with mode: 0644]
src/lib/efl/interfaces/efl_vpath_manager.c [new file with mode: 0644]
src/lib/efl/interfaces/efl_vpath_manager.eo [new file with mode: 0644]

index d8683e1..17529a5 100644 (file)
@@ -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@
index 2cb0bd7..651a5bd 100644 (file)
@@ -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;
index 2299022..d01e8df 100644 (file)
@@ -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");
 
diff --git a/src/lib/efl/interfaces/efl_vpath.eo b/src/lib/efl/interfaces/efl_vpath.eo
new file mode 100644 (file)
index 0000000..021b317
--- /dev/null
@@ -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 ]]
+      }
+   }
+}
diff --git a/src/lib/efl/interfaces/efl_vpath_core.c b/src/lib/efl/interfaces/efl_vpath_core.c
new file mode 100644 (file)
index 0000000..5e7d525
--- /dev/null
@@ -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"
diff --git a/src/lib/efl/interfaces/efl_vpath_core.eo b/src/lib/efl/interfaces/efl_vpath_core.eo
new file mode 100644 (file)
index 0000000..d9910a4
--- /dev/null
@@ -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;
+   }
+}
diff --git a/src/lib/efl/interfaces/efl_vpath_file.c b/src/lib/efl/interfaces/efl_vpath_file.c
new file mode 100644 (file)
index 0000000..e62ae1e
--- /dev/null
@@ -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"
diff --git a/src/lib/efl/interfaces/efl_vpath_file.eo b/src/lib/efl/interfaces/efl_vpath_file.eo
new file mode 100644 (file)
index 0000000..7cdb7ce
--- /dev/null
@@ -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 ]]
+   }
+}
diff --git a/src/lib/efl/interfaces/efl_vpath_file_core.c b/src/lib/efl/interfaces/efl_vpath_file_core.c
new file mode 100644 (file)
index 0000000..30c6e08
--- /dev/null
@@ -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"
diff --git a/src/lib/efl/interfaces/efl_vpath_file_core.eo b/src/lib/efl/interfaces/efl_vpath_file_core.eo
new file mode 100644 (file)
index 0000000..a77b4c9
--- /dev/null
@@ -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;
+   }
+}
diff --git a/src/lib/efl/interfaces/efl_vpath_manager.c b/src/lib/efl/interfaces/efl_vpath_manager.c
new file mode 100644 (file)
index 0000000..fdf5e9a
--- /dev/null
@@ -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"
diff --git a/src/lib/efl/interfaces/efl_vpath_manager.eo b/src/lib/efl/interfaces/efl_vpath_manager.eo
new file mode 100644 (file)
index 0000000..532f631
--- /dev/null
@@ -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 ]]
+         }
+      }
+   }
+}