aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilherme Lepsch <lepsch@expertisesolutions.com.br>2015-07-31 11:27:21 -0300
committerGuilherme Lepsch <lepsch@expertisesolutions.com.br>2015-08-03 11:30:59 -0300
commit802cddc8d3a9564f42ff2973a475eb8a9e7014eb (patch)
tree4b6293189dc0ea543502319b08c528770be2d9bd
parentefl_model: Common Efl.Model implementation functions (diff)
downloadefl-802cddc8d3a9564f42ff2973a475eb8a9e7014eb.tar.gz
eflat_xml_model: "Flat" Xml Model implementation
-rw-r--r--Makefile.am16
-rw-r--r--cmakeconfig/EflatXmlModelConfig.cmake.in32
-rw-r--r--cmakeconfig/EflatXmlModelCxxConfig.cmake.in30
-rw-r--r--configure.ac51
-rw-r--r--pc/eflat_xml_model-cxx.pc.in12
-rw-r--r--pc/eflat_xml_model.pc.in12
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile_EflatXmlModel.am84
-rw-r--r--src/Makefile_EflatXmlModel_Cxx.am22
-rw-r--r--src/lib/eflat_xml_model/Eflat_Xml_Model.h62
-rw-r--r--src/lib/eflat_xml_model/eflat_xml_model.c1049
-rw-r--r--src/lib/eflat_xml_model/eflat_xml_model.eo34
-rw-r--r--src/lib/eflat_xml_model/eflat_xml_model_private.h34
-rw-r--r--src/tests/eflat_xml_model/eflat_xml_model_suite.c121
-rw-r--r--src/tests/eflat_xml_model/eflat_xml_model_suite.h16
-rw-r--r--src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.c503
-rw-r--r--src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.h6
17 files changed, 2083 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am
index 8d2425b01c..1fc5897382 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -151,7 +151,8 @@ pc/edje.pc \
pc/emotion.pc \
pc/ethumb.pc \
pc/ethumb_client.pc \
-pc/elocation.pc
+pc/elocation.pc \
+pc/eflat_xml_model.pc
if HAVE_CXX11
pkgconfig_DATA += \
@@ -163,7 +164,8 @@ pc/eolian-cxx.pc \
pc/edje-cxx.pc \
pc/eet-cxx.pc \
pc/eo-cxx.pc \
-pc/eio-cxx.pc
+pc/eio-cxx.pc \
+pc/eflat_xml_model-cxx.pc
endif
if HAVE_ELUA
@@ -382,6 +384,16 @@ emile_cmakeconfig_DATA = \
cmakeconfig/EmileConfig.cmake \
cmakeconfig/EmileConfigVersion.cmake
+eflat_xml_model_cxx_cmakeconfigdir = $(libdir)/cmake/EflatXmlModelCxx/
+eflat_xml_model_cxx_cmakeconfig_DATA = \
+cmakeconfig/EflatXmlModelCxxConfig.cmake \
+cmakeconfig/EflatXmlModelCxxConfigVersion.cmake
+
+eflat_xml_model_cmakeconfigdir = $(libdir)/cmake/EflatXmlModel/
+eflat_xml_model_cmakeconfig_DATA = \
+cmakeconfig/EflatXmlModelConfig.cmake \
+cmakeconfig/EflatXmlModelConfigVersion.cmake
+
# D-Bus services:
servicedir = @dbusservicedir@
diff --git a/cmakeconfig/EflatXmlModelConfig.cmake.in b/cmakeconfig/EflatXmlModelConfig.cmake.in
new file mode 100644
index 0000000000..95a307d57f
--- /dev/null
+++ b/cmakeconfig/EflatXmlModelConfig.cmake.in
@@ -0,0 +1,32 @@
+# - Try to find eflat_xml_model
+# Once done this will define
+# EFLAT_XML_MODEL_FOUND - System has eflat_xml_model
+# EFLAT_XML_MODEL_INCLUDE_DIRS - The eflat_xml_model include directories
+# EFLAT_XML_MODEL_LIBRARIES - The libraries needed to use eflat_xml_model
+# EFLAT_XML_MODEL_DEFINITIONS - Compiler switches required for using eflat_xml_model
+
+set(MY_PKG eflat_xml_model)
+
+find_package(PkgConfig)
+if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER "2.8.1")
+ # "QUIET" was introduced in 2.8.2
+ set(_QUIET QUIET)
+endif ()
+pkg_check_modules(PC_LIBEFLAT_XML_MODEL ${_QUIET} ${MY_PKG})
+
+find_library(EFLAT_XML_MODEL_LIBRARY
+ NAMES ${PC_LIBEFLAT_XML_MODEL_LIBRARIES}
+ HINTS ${PC_LIBEFLAT_XML_MODEL_LIBDIR} ${PC_LIBEFLAT_XML_MODEL_LIBRARY_DIRS} )
+
+set(EFLAT_XML_MODEL_DEFINITIONS ${PC_LIBEFLAT_XML_MODEL_CFLAGS_OTHER})
+set(EFLAT_XML_MODEL_LIBRARIES ${EFLAT_XML_MODEL_LIBRARY})
+set(EFLAT_XML_MODEL_INCLUDE_DIRS ${PC_LIBEFLAT_XML_MODEL_INCLUDE_DIRS})
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set EFLAT_XML_MODEL_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(${MY_PKG} DEFAULT_MSG
+ EFLAT_XML_MODEL_LIBRARIES EFLAT_XML_MODEL_INCLUDE_DIRS)
+
+mark_as_advanced(EFLAT_XML_MODEL_INCLUDE_DIRS EFLAT_XML_MODEL_LIBRARY EFLAT_XML_MODEL_LIBRARIES EFLAT_XML_MODEL_DEFINITIONS)
+
diff --git a/cmakeconfig/EflatXmlModelCxxConfig.cmake.in b/cmakeconfig/EflatXmlModelCxxConfig.cmake.in
new file mode 100644
index 0000000000..c51ebff515
--- /dev/null
+++ b/cmakeconfig/EflatXmlModelCxxConfig.cmake.in
@@ -0,0 +1,30 @@
+# - Try to find eflat_xml_model
+# Once done this will define
+# EFLAT_XML_MODEL_CXX_FOUND - System has eflat_xml_model
+# EFLAT_XML_MODEL_CXX_INCLUDE_DIRS - The eflat_xml_model include directories
+# EFLAT_XML_MODEL_CXX_LIBRARIES - The libraries needed to use eflat_xml_model
+# EFLAT_XML_MODEL_CXX_DEFINITIONS - Compiler switches required for using eflat_xml_model
+
+set(MY_PKG eflat_xml_model_cxx)
+
+find_package(PkgConfig)
+if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER "2.8.1")
+ # "QUIET" was introduced in 2.8.2
+ set(_QUIET QUIET)
+endif ()
+pkg_check_modules(PC_EFLAT_XML_MODEL_CXX ${_QUIET} ${MY_PKG})
+find_library(EFLAT_XML_MODEL_CXX_LIBRARY
+ NAMES ${PC_EFLAT_XML_MODEL_CXX_LIBRARIES}
+ HINTS ${PC_EFLAT_XML_MODEL_CXX_LIBDIR} ${PC_EFLAT_XML_MODEL_CXX_LIBRARY_DIRS} )
+
+set(EFLAT_XML_MODEL_CXX_DEFINITIONS ${PC_EFLAT_XML_MODEL_CXX_CFLAGS_OTHER})
+set(EFLAT_XML_MODEL_CXX_LIBRARIES ${EFLAT_XML_MODEL_CXX_LIBRARY})
+set(EFLAT_XML_MODEL_CXX_INCLUDE_DIRS ${PC_EFLAT_XML_MODEL_CXX_INCLUDE_DIRS})
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set EFLAT_XML_MODEL_CXX_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(${MY_PKG} DEFAULT_MSG
+ EFLAT_XML_MODEL_CXX_LIBRARIES EFLAT_XML_MODEL_CXX_INCLUDE_DIRS)
+
+mark_as_advanced(EFLAT_XML_MODEL_CXX_INCLUDE_DIRS EFLAT_XML_MODEL_CXX_LIBRARY EFLAT_XML_MODEL_CXX_LIBRARIES EFLAT_XML_MODEL_CXX_DEFINITIONS)
diff --git a/configure.ac b/configure.ac
index 7975e55755..3937baaa9e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3917,7 +3917,7 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [emile])
ECORE_EVAS_MODULE([extn], [${want_ecore_evas_extn}])
ECORE_EVAS_MODULE([ews], [yes])
ECORE_EVAS_MODULE([fb], [${want_fb}])
-ECORE_EVAS_MODULE([drm], [${want_drm}],
+ECORE_EVAS_MODULE([drm], [${want_drm}],
[EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_drm}], [ecore-drm])])
ECORE_EVAS_MODULE([gl-drm], [${want_gl_drm}],
[EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_EVAS], [${want_gl_drm}], [ecore-drm])])
@@ -4566,6 +4566,48 @@ EFL_ADD_LIBS([ELOCATION], [-lm])
EFL_LIB_END([Elocation])
#### End of Elocation
+
+
+#### Eflat_Xml_Model
+EFL_LIB_START([Eflat_Xml_Model])
+
+### Additional options to configure
+
+### Default values
+
+### Checks for programs
+
+### Checks for libraries
+EFL_INTERNAL_DEPEND_PKG([EFLAT_XML_MODEL], [eo])
+EFL_INTERNAL_DEPEND_PKG([EFLAT_XML_MODEL], [efl])
+EFL_INTERNAL_DEPEND_PKG([EFLAT_XML_MODEL], [ecore])
+
+EFL_EVAL_PKGS([EFLAT_XML_MODEL])
+
+### Checks for header files
+
+### Checks for types
+
+### Checks for structures
+
+### Checks for compiler characteristics
+
+### Checks for linker characteristics
+
+### Checks for library functions
+
+EFL_LIB_END([Eflat_Xml_Model])
+#### End of Eflat_Xml_Model
+
+#### Eflat_Xml_Model CXX
+EFL_LIB_START([Eflat_Xml_Model_Cxx])
+
+EFL_EVAL_PKGS([EFLAT_XML_MODEL_CXX])
+
+EFL_LIB_END([Eflat_Xml_Model_Cxx])
+#### End of Eflat_Xml_Model CXX
+
+
### Add Wayland server library if test is enabled
if test "x${want_tests}" = "xyes" -a "x${want_wayland}" = "xyes"; then
EFL_DEPEND_PKG([ECORE_WAYLAND_SRV], [WAYLAND], [wayland-server >= 1.8.0])
@@ -4754,6 +4796,8 @@ pc/ethumb.pc
pc/ethumb_client.pc
pc/elocation.pc
pc/elua.pc
+pc/eflat_xml_model.pc
+pc/eflat_xml_model-cxx.pc
dbus-services/org.enlightenment.Ethumb.service
systemd-services/ethumb.service
$po_makefile_in
@@ -4803,6 +4847,10 @@ cmakeconfig/EluaConfig.cmake
cmakeconfig/EluaConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in
cmakeconfig/EmileConfig.cmake
cmakeconfig/EmileConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in
+cmakeconfig/EflatXmlModelConfig.cmake
+cmakeconfig/EflatXmlModelConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in
+cmakeconfig/EflatXmlModelCxxConfig.cmake
+cmakeconfig/EflatXmlModelCxxConfigVersion.cmake:cmakeconfig/EFLConfigVersion.cmake.in
])
AC_OUTPUT
@@ -4916,6 +4964,7 @@ echo "Emotion.........: yes (${features_emotion})"
echo "Ethumb..........: yes"
echo "Ethumb_Client...: yes"
echo "Elua............: $have_elua"
+echo "Eflat_Xml_Model.: yes"
if test "${build_tests}" = "none"; then
echo "Tests...........: no"
elif test "${build_tests}" = "auto"; then
diff --git a/pc/eflat_xml_model-cxx.pc.in b/pc/eflat_xml_model-cxx.pc.in
new file mode 100644
index 0000000000..7e80346e4f
--- /dev/null
+++ b/pc/eflat_xml_model-cxx.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Eflat_xml_model C++
+Description: "Flat" XML model for EFL
+Requires.private: @requirements_pc_eflat_xml_model@ @requirements_pc_eo@
+Version: @VERSION@
+Libs: -L${libdir} -leflat_xml_model @requirements_public_libs_eflat_xml_model@ @requirements_public_libs_eo@
+Libs.private: @requirements_libs_eflat_xml_model@ @requirements_libs_eo@
+Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eo-@VMAJ@ -I${includedir}/eflat_xml_model-@VMAJ@ -I${includedir}/eflat_xml_model-cxx-@VMAJ@
diff --git a/pc/eflat_xml_model.pc.in b/pc/eflat_xml_model.pc.in
new file mode 100644
index 0000000000..a7c8e236c8
--- /dev/null
+++ b/pc/eflat_xml_model.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Eflat_xml_model
+Description: "Flat" XML model for EFL
+Requires.private: @requirements_pc_eflat_xml_model@
+Version: @VERSION@
+Libs: -L${libdir} -leflat_xml_model @requirements_public_libs_eflat_xml_model@
+Libs.private: @requirements_libs_eflat_xml_model@
+Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eflat_xml_model-@VMAJ@
diff --git a/src/Makefile.am b/src/Makefile.am
index dccc538af2..964dc531f0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -60,6 +60,7 @@ include Makefile_Edje.am
include Makefile_Emotion.am
include Makefile_Ethumb.am
include Makefile_Ethumb_Client.am
+include Makefile_EflatXmlModel.am
include Makefile_Eina_Cxx.am
include Makefile_Ecore_Cxx.am
@@ -71,6 +72,7 @@ include Makefile_Efl_Cxx.am
include Makefile_Edje_Cxx.am
include Makefile_Evas_Cxx.am
include Makefile_Eio_Cxx.am
+include Makefile_EflatXmlModel_Cxx.am
include Makefile_Elua.am
include Makefile_Elocation.am
diff --git a/src/Makefile_EflatXmlModel.am b/src/Makefile_EflatXmlModel.am
new file mode 100644
index 0000000000..27c9bacf40
--- /dev/null
+++ b/src/Makefile_EflatXmlModel.am
@@ -0,0 +1,84 @@
+### Library
+
+eflat_xml_model_eolian_files = \
+lib/eflat_xml_model/eflat_xml_model.eo
+
+eflat_xml_model_eolian_c = $(eflat_xml_model_eolian_files:%.eo=%.eo.c)
+eflat_xml_model_eolian_h = $(eflat_xml_model_eolian_files:%.eo=%.eo.h)
+
+BUILT_SOURCES += \
+ $(eflat_xml_model_eolian_c) \
+ $(eflat_xml_model_eolian_h)
+
+CLEANFILES += \
+ $(eflat_xml_model_eolian_c) \
+ $(eflat_xml_model_eolian_h)
+
+eflat_xml_modeleolianfilesdir = $(datadir)/eolian/include/eflat_xml_model-@VMAJ@
+eflat_xml_modeleolianfiles_DATA = \
+ $(eflat_xml_model_eolian_files)
+
+EXTRA_DIST += \
+ ${eflat_xml_modeleolianfiles_DATA}
+
+lib_LTLIBRARIES += lib/eflat_xml_model/libeflat_xml_model.la
+
+installed_eflat_xml_modelmainheadersdir = $(includedir)/eflat_xml_model-@VMAJ@
+dist_installed_eflat_xml_modelmainheaders_DATA = \
+lib/eflat_xml_model/Eflat_Xml_Model.h
+
+nodist_installed_eflat_xml_modelmainheaders_DATA = \
+ $(eflat_xml_model_eolian_h)
+
+lib_eflat_xml_model_libeflat_xml_model_la_SOURCES = \
+lib/eflat_xml_model/eflat_xml_model_private.h \
+lib/eflat_xml_model/eflat_xml_model.c
+
+lib_eflat_xml_model_libeflat_xml_model_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @EFLAT_XML_MODEL_CFLAGS@ @EFL_CFLAGS@
+lib_eflat_xml_model_libeflat_xml_model_la_LIBADD = @EFLAT_XML_MODEL_LIBS@ @EFL_LIBS@
+lib_eflat_xml_model_libeflat_xml_model_la_DEPENDENCIES = @EFLAT_XML_MODEL_INTERNAL_LIBS@ @EFL_INTERNAL_LIBS@
+lib_eflat_xml_model_libeflat_xml_model_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
+
+### Unit tests
+
+if EFL_ENABLE_TESTS
+
+check_PROGRAMS += tests/eflat_xml_model/eflat_xml_model_suite
+TESTS += tests/eflat_xml_model/eflat_xml_model_suite
+
+tests_eflat_xml_model_eflat_xml_model_suite_SOURCES = \
+tests/eflat_xml_model/eflat_xml_model_suite.c \
+tests/eflat_xml_model/eflat_xml_model_suite.h \
+tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.c \
+tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.h
+
+tests_eflat_xml_model_eflat_xml_model_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
+-DTESTS_SRC_DIR=\"$(abs_top_srcdir)/src/tests/eflat_xml_model\" \
+-DTESTS_BUILD_DIR=\"$(abs_top_builddir)/src/tests/eflat_xml_model\" \
+@CHECK_CFLAGS@ \
+@EFLAT_XML_MODEL_CFLAGS@ @EFL_CFLAGS@
+
+tests_eflat_xml_model_eflat_xml_model_suite_LDADD = \
+@CHECK_LIBS@ \
+@USE_EFLAT_XML_MODEL_LIBS@ \
+@USE_EFL_LIBS@
+
+tests_eflat_xml_model_eflat_xml_model_suite_DEPENDENCIES = \
+@USE_EFLAT_XML_MODEL_INTERNAL_LIBS@
+
+endif
+
+EXTRA_DIST += $(EFLAT_XML_MODEL_DATA_FILES)
+
+if HAVE_ELUA
+
+eflat_xml_model_eolian_lua = $(eflat_xml_model_eolian_files:%.eo=%.eo.lua)
+
+generated_eflat_xml_model_lua_all = $(eflat_xml_model_eolian_lua)
+
+CLEANFILES += $(generated_eflat_xml_model_lua_all)
+
+installed_eflat_xml_modelluadir = $(datadir)/elua/modules/eflat_xml_model
+nodist_installed_eflat_xml_modellua_DATA = $(generated_eflat_xml_model_lua_all)
+
+endif
diff --git a/src/Makefile_EflatXmlModel_Cxx.am b/src/Makefile_EflatXmlModel_Cxx.am
new file mode 100644
index 0000000000..ea5b451a01
--- /dev/null
+++ b/src/Makefile_EflatXmlModel_Cxx.am
@@ -0,0 +1,22 @@
+if HAVE_CXX11
+
+### Generated headers
+
+generated_eflat_xml_model_cxx_bindings = $(eflat_xml_model_eolian_files:%.eo=%.eo.hh)
+
+lib/eflat_xml_model/Eflat_xml_model.hh: $(generated_eflat_xml_model_cxx_bindings)
+ @echo @ECHO_E@ "#ifndef EFL_CXX_EFLAT_XML_MODEL_HH\n#define EFL_CXX_EFLAT_XML_MODEL_HH\n" > $(top_builddir)/src/lib/eflat_xml_model/Eflat_xml_model.hh
+ @echo @ECHO_E@ "#ifdef EFL_BETA_API_SUPPORT" >> $(top_builddir)/src/lib/eflat_xml_model/Eflat_xml_model.hh
+ @for i in $(generated_eflat_xml_model_cxx_bindings); do echo "#include <$$(basename $$i)>" >> $(top_builddir)/src/lib/eflat_xml_model/Eflat_xml_model.hh; done
+ @echo @ECHO_E@ "#endif\n\n#endif\n" >> $(top_builddir)/src/lib/eflat_xml_model/Eflat_xml_model.hh
+
+generated_eflat_xml_model_cxx_all = \
+ $(generated_eflat_xml_model_cxx_bindings) \
+ lib/eflat_xml_model/Eflat_xml_model.hh
+
+CLEANFILES += $(generated_eflat_xml_model_cxx_all)
+
+installed_eflat_xml_modelcxxmainheadersdir = $(includedir)/eflat_xml_model-cxx-@VMAJ@/
+nodist_installed_eflat_xml_modelcxxmainheaders_DATA = $(generated_eflat_xml_model_cxx_all)
+
+endif
diff --git a/src/lib/eflat_xml_model/Eflat_Xml_Model.h b/src/lib/eflat_xml_model/Eflat_Xml_Model.h
new file mode 100644
index 0000000000..19b17eb31a
--- /dev/null
+++ b/src/lib/eflat_xml_model/Eflat_Xml_Model.h
@@ -0,0 +1,62 @@
+#ifndef EFLAT_XML_H
+#define EFLAT_XML_H
+
+#include <Ecore.h>
+#include <Efl.h>
+#include <Efl_Config.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_EFLAT_XML_MODEL_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_EFLAT_XML_MODEL_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Initialize eflat_xml_model.
+ *
+ * @return 1 or greater on success, 0 otherwise
+ */
+EAPI int eflat_xml_model_init(void);
+/**
+ * @brief Shutdown eflat_xml_model.
+ *
+ * @return 0 if eflat_xml_model shuts down, greater than 0 otherwise.
+ */
+EAPI int eflat_xml_model_shutdown(void);
+
+#ifdef EFL_EO_API_SUPPORT
+# include <eflat_xml_model.eo.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#undef EAPI
+#define EAPI
+
+#endif
diff --git a/src/lib/eflat_xml_model/eflat_xml_model.c b/src/lib/eflat_xml_model/eflat_xml_model.c
new file mode 100644
index 0000000000..0588f92e49
--- /dev/null
+++ b/src/lib/eflat_xml_model/eflat_xml_model.c
@@ -0,0 +1,1049 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "eflat_xml_model_private.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define MY_CLASS EFLAT_XML_MODEL_CLASS
+#define MY_CLASS_NAME "Eflat_Xml_Model"
+
+typedef enum
+{
+ EFLAT_XML_MODEL_PATH_TYPE_DATA,
+ EFLAT_XML_MODEL_PATH_TYPE_ATTRIBUTE,
+ EFLAT_XML_MODEL_PATH_TYPE_PROCESSING,
+ EFLAT_XML_MODEL_PATH_TYPE_RAW_XML
+} Eflat_Xml_Model_Path_Type;
+
+typedef struct
+{
+ Eina_Simple_XML_Node_Tag *node;
+ Eflat_Xml_Model_Path_Type type;
+ union
+ {
+ Eina_Simple_XML_Attribute *attribute;
+ Eina_Simple_XML_Node_Processing *processing;
+ };
+} Eflat_Xml_Model_Path_Data;
+
+static void _properties_load(Eflat_Xml_Model_Data *);
+static void _children_load(Eflat_Xml_Model_Data *);
+static bool _init(Eflat_Xml_Model_Data *);
+static void _clear(Eflat_Xml_Model_Data *);
+static void _properties_setup(Eflat_Xml_Model_Data *);
+static Eina_Simple_XML_Node_Tag *_tag_find(Eina_Simple_XML_Node_Tag *, const char *);
+static Eina_Simple_XML_Attribute *_attribute_find(Eina_Simple_XML_Node_Tag *, const char *);
+static Eina_Simple_XML_Node_Tag *_node_from_path_new(Eina_Simple_XML_Node_Root *, const char *, Eflat_Xml_Model_Path_Data *);
+static Eina_Simple_XML_Node_Tag *_node_from_path_get(Eina_Simple_XML_Node_Root *, const char *, Eflat_Xml_Model_Path_Data *);
+static void _node_children_del(Eina_Simple_XML_Node_Tag *);
+static char *_path_from_node_get(Eina_Simple_XML_Node_Tag *);
+static char *_concatenate_path(const char *, const char *, char);
+static void _node_children_properties_del(Eflat_Xml_Model_Data *, Eina_Simple_XML_Node_Tag *, const char *);
+static void _node_attributes_properties_del(Eflat_Xml_Model_Data *, Eina_Simple_XML_Node_Tag *, const char *);
+static void _property_del(Eflat_Xml_Model_Data *, const char *);
+static void _property_add(Eflat_Xml_Model_Data *, const char *, const char *);
+static void _node_clear(Eflat_Xml_Model_Data *, Eina_Simple_XML_Node_Tag *);
+static void _generate_properties_from_node(Eflat_Xml_Model_Data *, Eina_Simple_XML_Node_Tag *);
+static Eina_Simple_XML_Node_Data *_data_value_set(Eina_Simple_XML_Node_Tag *, Eina_Simple_XML_Node_Data *, const char *);
+static char *_data_name_get(const Eina_Simple_XML_Node_Data *);
+static void _stream_load(Eflat_Xml_Model_Data *, Eina_Simple_XML_Node_Tag *, const char *);
+
+static int _eflat_xml_model_init_count = 0;
+int _eflat_xml_model_log_dom = -1;
+
+EAPI int
+eflat_xml_model_init(void)
+{
+ if (_eflat_xml_model_init_count++ > 0)
+ return _eflat_xml_model_init_count;
+
+ if (!eina_init())
+ {
+ fputs("Eflat_Xml_Model: Unable to initialize eina\n", stderr);
+ return 0;
+ }
+
+ _eflat_xml_model_log_dom = eina_log_domain_register("eflat_xml_model",
+ EINA_COLOR_CYAN);
+ if (_eflat_xml_model_log_dom < 0)
+ {
+ EINA_LOG_ERR("Unable to create an 'eflat_xml_model' log domain");
+ _eflat_xml_model_log_dom = -1;
+ eina_shutdown();
+ return 0;
+ }
+
+ if (!ecore_init())
+ {
+ ERR("Unable to initialize ecore");
+ eina_log_domain_unregister(_eflat_xml_model_log_dom);
+ _eflat_xml_model_log_dom = -1;
+ eina_shutdown();
+ return 0;
+ }
+
+ // ...
+
+ return _eflat_xml_model_init_count;
+}
+
+EAPI int
+eflat_xml_model_shutdown(void)
+{
+ if (_eflat_xml_model_init_count <= 0)
+ {
+ ERR("Init count not greater than 0 in shutdown.");
+ _eflat_xml_model_init_count = 0;
+ return 0;
+ }
+
+ if (--_eflat_xml_model_init_count)
+ return _eflat_xml_model_init_count;
+
+ // ...
+
+ ecore_shutdown();
+ eina_log_domain_unregister(_eflat_xml_model_log_dom);
+ _eflat_xml_model_log_dom = -1;
+ eina_shutdown();
+ return 0;
+}
+
+static void
+_eflat_xml_model_hash_free(Eina_Value *value)
+{
+ eina_value_free(value);
+}
+
+static Eo_Base *
+_eflat_xml_model_eo_base_constructor(Eo *obj, Eflat_Xml_Model_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ pd->obj = obj;
+ pd->load.status = EFL_MODEL_LOAD_STATUS_UNLOADED;
+ pd->properties_array = NULL;
+ pd->properties_hash = eina_hash_string_superfast_new(EINA_FREE_CB(_eflat_xml_model_hash_free));
+ pd->root = NULL;
+ pd->xml = NULL;
+ eina_value_setup(&pd->xml_value, EINA_VALUE_TYPE_STRING);
+
+ return eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
+}
+
+static void
+_eflat_xml_model_constructor(Eo *obj EINA_UNUSED,
+ Eflat_Xml_Model_Data *pd EINA_UNUSED,
+ const char *xml)
+{
+ DBG("(%p)", obj);
+ pd->xml = strdup(xml ? xml : "");
+}
+
+static void
+_eflat_xml_model_eo_base_destructor(Eo *obj, Eflat_Xml_Model_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ _clear(pd);
+ eina_hash_free(pd->properties_hash);
+ free(pd->xml);
+ eina_value_flush(&pd->xml_value);
+
+ eo_do_super(obj, MY_CLASS, eo_destructor());
+}
+
+static Efl_Model_Load_Status
+_eflat_xml_model_efl_model_base_properties_get(Eo *obj EINA_UNUSED,
+ Eflat_Xml_Model_Data *pd,
+ Eina_Array * const* properties_array)
+{
+ DBG("(%p)", obj);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EFL_MODEL_LOAD_STATUS_ERROR);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pd->obj, EFL_MODEL_LOAD_STATUS_ERROR);
+
+ *(Eina_Array**)properties_array = pd->properties_array;
+ return pd->load.status;
+}
+
+static void
+_eflat_xml_model_efl_model_base_properties_load(Eo *obj, Eflat_Xml_Model_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if (pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES)
+ return;
+
+ if (!_init(pd))
+ return;
+
+ efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADING_PROPERTIES);
+
+ _properties_load(pd);
+
+ efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES);
+}
+
+static void
+_properties_load(Eflat_Xml_Model_Data *pd)
+{
+ DBG("(%p)", pd->obj);
+
+ _properties_setup(pd);
+
+ if (!pd->xml)
+ return;
+
+ _generate_properties_from_node(pd, pd->root);
+}
+
+static Efl_Model_Load_Status
+_eflat_xml_model_efl_model_base_property_set(Eo *obj,
+ Eflat_Xml_Model_Data *pd,
+ const char *property,
+ const Eina_Value *value)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(property, EFL_MODEL_LOAD_STATUS_ERROR);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(value, EFL_MODEL_LOAD_STATUS_ERROR);
+ DBG("(%p): property=%s", obj, property);
+
+ if (!(pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES))
+ return EFL_MODEL_LOAD_STATUS_ERROR;
+
+ Eflat_Xml_Model_Path_Data data;
+ Eina_Simple_XML_Node_Tag *node = _node_from_path_new(pd->root,
+ property,
+ &data);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(node, EFL_MODEL_LOAD_STATUS_ERROR);
+ DBG("(%p)", obj);
+
+ char *value_str = eina_value_to_string(value);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(value_str, EFL_MODEL_LOAD_STATUS_ERROR);
+
+ switch (data.type)
+ {
+ case EFLAT_XML_MODEL_PATH_TYPE_ATTRIBUTE:
+ {
+ eina_stringshare_del(data.attribute->value);
+ data.attribute->value = eina_stringshare_add(value_str);
+ break;
+ }
+ case EFLAT_XML_MODEL_PATH_TYPE_RAW_XML:
+ {
+ _stream_load(pd, node, value_str);
+ break;
+ }
+ case EFLAT_XML_MODEL_PATH_TYPE_DATA:
+ {
+ _node_clear(pd, node);
+
+ // checks if it's a empty tag
+ size_t len = strlen(value_str);
+ if (len)
+ eina_simple_xml_node_data_new(node, value_str, len);
+ break;
+ }
+ case EFLAT_XML_MODEL_PATH_TYPE_PROCESSING:
+ {
+ Eina_Simple_XML_Node_Data *processing = _data_value_set
+ (node, data.processing, value_str);
+ EINA_SAFETY_ON_NULL_GOTO(processing, on_error);
+ break;
+ }
+ }
+
+ if (data.type != EFLAT_XML_MODEL_PATH_TYPE_RAW_XML)
+ {
+ // TODO: Check if the property exists instead of deleting it
+ _property_del(pd, property);
+ _property_add(pd, property, value_str);
+ }
+
+ free(value_str);
+
+ efl_model_property_changed_notify(obj, property);
+
+ return pd->load.status;
+
+on_error:
+ free(value_str);
+ return EFL_MODEL_LOAD_STATUS_ERROR;
+}
+
+static Efl_Model_Load_Status
+_eflat_xml_model_efl_model_base_property_get(Eo *obj EINA_UNUSED,
+ Eflat_Xml_Model_Data *pd,
+ const char *property,
+ const Eina_Value **value)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(property, EFL_MODEL_LOAD_STATUS_ERROR);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(value, EFL_MODEL_LOAD_STATUS_ERROR);
+ DBG("(%p): property=%s", obj, property);
+
+ if (!(pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES))
+ return EFL_MODEL_LOAD_STATUS_ERROR;
+
+ Eflat_Xml_Model_Path_Data data;
+ Eina_Simple_XML_Node_Tag *node = _node_from_path_get(pd->root,
+ property,
+ &data);
+ if (!node)
+ {
+ ERR("Property doesn't exists: %s", property);
+ return EFL_MODEL_LOAD_STATUS_ERROR;
+ };
+
+ if (data.type == EFLAT_XML_MODEL_PATH_TYPE_RAW_XML)
+ {
+ Eina_Strbuf *buf = eina_strbuf_new();
+ EINA_SAFETY_ON_NULL_RETURN_VAL(buf, EFL_MODEL_LOAD_STATUS_ERROR);
+
+ Eina_Simple_XML_Node *child;
+ EINA_INLIST_FOREACH(node->children, child)
+ {
+ char *dump = eina_simple_xml_node_dump(child, " ");
+ Eina_Bool ret = eina_strbuf_append(buf, dump);
+ free(dump);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret, EFL_MODEL_LOAD_STATUS_ERROR);
+ }
+
+ Eina_Bool ret = eina_value_set(&pd->xml_value, eina_strbuf_string_get(buf));
+ eina_strbuf_free(buf);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret, EFL_MODEL_LOAD_STATUS_ERROR);
+
+ *value = &pd->xml_value;
+ return pd->load.status;
+ }
+
+ *value = eina_hash_find(pd->properties_hash, property);
+ if (!(*value))
+ {
+ ERR("Property doesn't exist: %s", property);
+ return EFL_MODEL_LOAD_STATUS_ERROR;
+ }
+
+ return pd->load.status;
+}
+
+static void
+_eflat_xml_model_efl_model_base_load(Eo *obj, Eflat_Xml_Model_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if ((pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED) == EFL_MODEL_LOAD_STATUS_LOADED)
+ return;
+
+ if (!_init(pd))
+ return;
+
+ if (!(pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_PROPERTIES))
+ {
+ efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADING_PROPERTIES);
+ _properties_load(pd);
+ }
+
+ if (!(pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_CHILDREN))
+ {
+ efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADING_CHILDREN);
+ _children_load(pd);
+ }
+
+ efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADED);
+}
+
+static Efl_Model_Load_Status
+_eflat_xml_model_efl_model_base_load_status_get(Eo *obj EINA_UNUSED,
+ Eflat_Xml_Model_Data *pd)
+{
+ DBG("(%p)", obj);
+ return pd->load.status;
+}
+
+static void
+_eflat_xml_model_efl_model_base_unload(Eo *obj, Eflat_Xml_Model_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ _clear(pd);
+
+ efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_UNLOADED);
+}
+
+Eo *
+_eflat_xml_model_efl_model_base_child_add(Eo *obj EINA_UNUSED,
+ Eflat_Xml_Model_Data *pd EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+ return NULL;
+}
+
+static Efl_Model_Load_Status
+_eflat_xml_model_efl_model_base_child_del(Eo *obj EINA_UNUSED,
+ Eflat_Xml_Model_Data *pd EINA_UNUSED,
+ Eo *child EINA_UNUSED)
+{
+ DBG("(%p)", obj);
+ return EFL_MODEL_LOAD_STATUS_ERROR;
+}
+
+static Efl_Model_Load_Status
+_eflat_xml_model_efl_model_base_children_slice_get(Eo *obj EINA_UNUSED,
+ Eflat_Xml_Model_Data *pd,
+ unsigned start EINA_UNUSED,
+ unsigned count EINA_UNUSED,
+ Eina_Accessor **children_accessor)
+{
+ DBG("(%p)", obj);
+ *children_accessor = NULL;
+ return pd->load.status;
+}
+
+static Efl_Model_Load_Status
+_eflat_xml_model_efl_model_base_children_count_get(Eo *obj EINA_UNUSED,
+ Eflat_Xml_Model_Data *pd,
+ unsigned *children_count)
+{
+ DBG("(%p)", obj);
+ *children_count = 0;
+ return pd->load.status;
+}
+
+static void
+_eflat_xml_model_efl_model_base_children_load(Eo *obj, Eflat_Xml_Model_Data *pd)
+{
+ DBG("(%p)", obj);
+
+ if (pd->load.status & EFL_MODEL_LOAD_STATUS_LOADED_CHILDREN)
+ return;
+
+ if (!_init(pd))
+ return;
+
+ efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADING_CHILDREN);
+
+ _children_load(pd);
+
+ efl_model_load_set(obj, &pd->load, EFL_MODEL_LOAD_STATUS_LOADED_CHILDREN);
+}
+
+static void
+_children_load(Eflat_Xml_Model_Data *pd)
+{
+ DBG("(%p)", pd->obj);
+}
+
+static bool
+_init(Eflat_Xml_Model_Data *pd)
+{
+ if (!pd->root)
+ pd->root = eina_simple_xml_node_load(pd->xml, strlen(pd->xml), EINA_TRUE);
+ return true;
+}
+
+static void
+_clear(Eflat_Xml_Model_Data *pd)
+{
+ EINA_SAFETY_ON_NULL_RETURN(pd);
+
+ eina_hash_free_buckets(pd->properties_hash);
+
+ if (pd->properties_array)
+ {
+ size_t i;
+ char *property;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(pd->properties_array, i, property, it)
+ free(property);
+ eina_array_free(pd->properties_array);
+ pd->properties_array = NULL;
+ }
+
+ eina_simple_xml_node_root_free(pd->root);
+ pd->root = NULL;
+
+ free(pd->xml);
+ pd->xml = strdup("");
+ eina_value_set(&pd->xml_value, "");
+}
+
+static void
+_properties_setup(Eflat_Xml_Model_Data *pd)
+{
+ DBG("(%p)", pd->obj);
+
+ pd->properties_array = eina_array_new(1);
+}
+
+static Eina_Simple_XML_Node_Tag *
+_tag_find(Eina_Simple_XML_Node_Tag *node, const char *name)
+{
+ if (!node) return NULL;
+
+ Eina_Simple_XML_Node *child;
+ EINA_INLIST_FOREACH(node->children, child)
+ {
+ if (EINA_SIMPLE_XML_NODE_TAG == child->type)
+ {
+ Eina_Simple_XML_Node_Tag *tag = (Eina_Simple_XML_Node_Tag*)child;
+ if (strcmp(name, tag->name) == 0)
+ return tag;
+ }
+ }
+
+ return NULL;
+}
+
+static bool
+_space_is(char c)
+{
+ return '\x20' == c || '\x9' == c || '\xD' == c || '\xA' == c;
+}
+
+static char *
+_data_name_get(const Eina_Simple_XML_Node_Data *data)
+{
+ if (!data) return NULL;
+
+ size_t name_length = data->length;
+
+ const char *separator = NULL;
+ const char *pos = data->data;
+ const char *end = pos + name_length;
+ while (pos < end)
+ {
+ if (_space_is(*pos))
+ {
+ separator = pos;
+ break;
+ }
+ ++pos;
+ }
+ if (separator)
+ name_length = (size_t)(ptrdiff_t)(separator - data->data);
+
+ char *name = malloc(name_length + 1);
+ strncpy(name, data->data, name_length);
+ name[name_length] = '\0';
+ return name;
+}
+
+static Eina_Simple_XML_Node_Data *
+_eflat_xml_model_data_find(Eina_Simple_XML_Node_Tag *node,
+ const char *name,
+ Eina_Simple_XML_Node_Type type)
+{
+ if (!node) return NULL;
+
+ const size_t name_length = strlen(name);
+
+ Eina_Simple_XML_Node *child;
+ EINA_INLIST_FOREACH(node->children, child)
+ {
+ if (type != child->type)
+ continue;
+
+ Eina_Simple_XML_Node_Data *data = (Eina_Simple_XML_Node_Data*)child;
+ if (name_length > data->length)
+ continue;
+
+ if (strncmp(data->data, name, name_length) != 0)
+ continue;
+
+ if ((data->length > name_length) && !_space_is(data->data[name_length]))
+ continue;
+
+ return data;
+ }
+
+ return NULL;
+}
+
+static Eina_Simple_XML_Attribute *
+_attribute_find(Eina_Simple_XML_Node_Tag *node, const char *key)
+{
+ if (!node) return NULL;
+
+ Eina_Simple_XML_Attribute *attr;
+ EINA_INLIST_FOREACH(node->attributes, attr)
+ {
+ if (strcmp(key, attr->key) == 0)
+ return attr;
+ }
+
+ return NULL;
+}
+
+static Eina_Simple_XML_Node_Tag *
+_node_new(Eina_Simple_XML_Node_Tag *parent, const char *name)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
+ Eina_Simple_XML_Node_Tag *child = _tag_find(parent, name);
+ if (!child)
+ child = eina_simple_xml_node_tag_new(parent, name);
+
+ return child;
+}
+
+static Eina_Simple_XML_Attribute *
+_attr_new(Eina_Simple_XML_Node_Tag *parent, const char *key)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
+ Eina_Simple_XML_Attribute *attr = _attribute_find(parent, key);
+ if (!attr)
+ attr = eina_simple_xml_attribute_new(parent, key, "");
+
+ return attr;
+}
+
+static Eina_Simple_XML_Node_Data *
+_data_new(Eina_Simple_XML_Node_Tag *parent,
+ const char *name,
+ Eina_Simple_XML_Node_Type type)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
+ Eina_Simple_XML_Node_Data *data = _eflat_xml_model_data_find(parent, name, type);
+ if (data)
+ return data;
+
+ switch (type)
+ {
+ case EINA_SIMPLE_XML_NODE_PROCESSING:
+ return eina_simple_xml_node_processing_new(parent, name, strlen(name));
+ default:
+ ERR("Node type not supported: %d", type);
+ return NULL;
+ }
+}
+
+static const char *
+_next_node_name(char **it, char c)
+{
+ char *separator = strchr(*it, c);
+ if (!separator) return NULL;
+
+ *separator = '\0';
+ char *node_name = *it;
+ *it = separator + 1;
+ return node_name;
+}
+
+typedef struct
+{
+ Eina_Simple_XML_Node_Tag *(*node_find)(Eina_Simple_XML_Node_Tag *, const char *);
+ Eina_Simple_XML_Attribute *(*attr_find)(Eina_Simple_XML_Node_Tag *, const char *);
+ Eina_Simple_XML_Node_Data *(*data_find)(Eina_Simple_XML_Node_Tag *, const char *, Eina_Simple_XML_Node_Type);
+} Eflat_Xml_Model_Path_Operators;
+
+static const Eflat_Xml_Model_Path_Operators
+_const_path_operators = {
+ .node_find = _tag_find,
+ .attr_find = _attribute_find,
+ .data_find = _eflat_xml_model_data_find,
+};
+
+static const Eflat_Xml_Model_Path_Operators
+_new_path_operators = {
+ .node_find = _node_new,
+ .attr_find = _attr_new,
+ .data_find = _data_new,
+};
+
+static Eina_Simple_XML_Node_Tag *
+_node_path(Eina_Simple_XML_Node_Root *root,
+ const char *path,
+ Eflat_Xml_Model_Path_Data *data,
+ Eflat_Xml_Model_Path_Operators ops)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(root, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(data, NULL);
+
+ *data = (Eflat_Xml_Model_Path_Data){0};
+ Eina_Simple_XML_Node_Tag *node = (Eina_Simple_XML_Node_Tag*)root;
+
+ char *path_tmp = strdup(path);
+ char *it = path_tmp;
+
+ const char *node_name;
+ while ((node_name = _next_node_name(&it, '/')))
+ {
+ if (strlen(node_name))
+ {
+ node = ops.node_find(node, node_name);
+ if (!node) goto on_error;
+ }
+ }
+
+ if ((node_name = _next_node_name(&it, '@')))
+ {
+ if (!strlen(node_name)) goto on_error; // attribute cannot be assigned to root
+
+ node = ops.node_find(node, node_name);
+ if (!node) goto on_error;
+
+ char *attr_key = it;
+ if (strlen(attr_key) == 0)
+ {
+ ERR("Attributes cannot have null key: %s", path);
+ goto on_error;
+ }
+
+ data->attribute = ops.attr_find(node, attr_key);
+ if (!data->attribute) goto on_error;
+ data->type = EFLAT_XML_MODEL_PATH_TYPE_ATTRIBUTE;
+ }
+ else
+ if ((node_name = _next_node_name(&it, '?')))
+ {
+ if (strlen(node_name))
+ {
+ node = ops.node_find(node, node_name);
+ if (!node) goto on_error;
+ }
+
+ char *processing_key = it;
+ if (strlen(processing_key) == 0)
+ {
+ ERR("Processing tags cannot have null name: %s", path);
+ goto on_error;
+ }
+
+ data->processing = (Eina_Simple_XML_Node_Processing*)
+ ops.data_find(node, processing_key, EINA_SIMPLE_XML_NODE_PROCESSING);
+ if (!data->processing) goto on_error;
+ data->type = EFLAT_XML_MODEL_PATH_TYPE_PROCESSING;
+ }
+ else
+ {
+ node_name = it;
+ if (strlen(node_name) == 0) // terminating with '/'
+ data->type = EFLAT_XML_MODEL_PATH_TYPE_RAW_XML;
+ else
+ {
+ node = ops.node_find(node, node_name);
+ if (!node) goto on_error;
+ data->type = EFLAT_XML_MODEL_PATH_TYPE_DATA;
+ }
+ }
+
+ free(path_tmp);
+ return node;
+
+on_error:
+ free(path_tmp);
+ return NULL;
+}
+
+static Eina_Simple_XML_Node_Tag *
+_node_from_path_new(Eina_Simple_XML_Node_Root *root,
+ const char *path,
+ Eflat_Xml_Model_Path_Data *data)
+{
+ return _node_path(root, path, data, _new_path_operators);
+}
+
+static Eina_Simple_XML_Node_Tag *
+_node_from_path_get(Eina_Simple_XML_Node_Root *root,
+ const char *path,
+ Eflat_Xml_Model_Path_Data *data)
+{
+ return _node_path(root, path, data, _const_path_operators);
+}
+
+static void
+_node_children_del(Eina_Simple_XML_Node_Tag *tag)
+{
+ while (tag->children)
+ {
+ Eina_Simple_XML_Node *node = EINA_INLIST_CONTAINER_GET(tag->children,
+ Eina_Simple_XML_Node);
+ if (EINA_SIMPLE_XML_NODE_TAG == node->type)
+ eina_simple_xml_node_tag_free((Eina_Simple_XML_Node_Tag*)node);
+ else
+ eina_simple_xml_node_data_free((Eina_Simple_XML_Node_Data*)node);
+ }
+}
+
+static char *
+_path_from_node_get(Eina_Simple_XML_Node_Tag *tag)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tag, NULL);
+
+ Eina_Strbuf *buf = eina_strbuf_new();
+ EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL);
+
+ Eina_Bool ret = eina_strbuf_append(buf, tag->name ? tag->name : "");
+ EINA_SAFETY_ON_FALSE_GOTO(ret, on_error);
+
+ Eina_Simple_XML_Node_Tag *parent = tag;
+ while ((parent = parent->base.parent) && parent->name)
+ {
+ ret = eina_strbuf_prepend(buf, "/")
+ && eina_strbuf_prepend(buf, parent->name);
+ EINA_SAFETY_ON_FALSE_GOTO(ret, on_error);
+ }
+
+ char *result = eina_strbuf_string_steal(buf);
+ eina_strbuf_free(buf);
+ return result;
+
+on_error:
+ eina_strbuf_free(buf);
+ return NULL;
+}
+
+static char *
+_concatenate_path(const char *path, const char *child, char separator)
+{
+ int len = strlen(path) + sizeof(separator) + strlen(child) + 1;
+
+ char *child_path = malloc(len);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(child_path, NULL);
+
+ int written = snprintf(child_path, len, "%s%c%s", path, separator, child);
+ EINA_SAFETY_ON_FALSE_GOTO((written > 0) && (written < len), on_error);
+
+ return child_path;
+
+on_error:
+ free(child_path);
+ return NULL;
+}
+
+static void
+_node_children_properties_del(Eflat_Xml_Model_Data *pd,
+ Eina_Simple_XML_Node_Tag *tag,
+ const char *path)
+{
+ DBG("(%p)", pd->obj);
+ Eina_Simple_XML_Node *child;
+ EINA_INLIST_FOREACH(tag->children, child)
+ {
+ switch (child->type)
+ {
+ case EINA_SIMPLE_XML_NODE_TAG:
+ {
+ Eina_Simple_XML_Node_Tag *child_tag = (Eina_Simple_XML_Node_Tag*)child;
+
+ char *child_path = _concatenate_path(path, child_tag->name, '/');
+ EINA_SAFETY_ON_NULL_RETURN(child_path);
+
+ _property_del(pd, child_path);
+ _node_children_properties_del(pd, child_tag, child_path);
+ _node_attributes_properties_del(pd, child_tag, child_path);
+
+ free(child_path);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+static void
+_node_attributes_properties_del(Eflat_Xml_Model_Data *pd,
+ Eina_Simple_XML_Node_Tag *tag,
+ const char *path)
+{
+ Eina_Simple_XML_Attribute *attr;
+ EINA_INLIST_FOREACH(tag->attributes, attr)
+ {
+ char *attr_path = _concatenate_path(path, attr->key, '@');
+ _property_del(pd, attr_path);
+ free(attr_path);
+ }
+}
+
+static Eina_Bool
+_property_array_keep_cb(void *data, void *gdata)
+{
+ char *a = (char *)data;
+ const char *b = (char *)gdata;
+
+ if (strcmp(a, b) != 0) return EINA_TRUE;
+
+ free(a);
+ return EINA_FALSE;
+}
+
+static void
+_property_del(Eflat_Xml_Model_Data *pd, const char *property)
+{
+ DBG("(%p) deleting property %s", pd->obj, property);
+ eina_hash_del(pd->properties_hash, property, NULL);
+
+ eina_array_remove(pd->properties_array,
+ _property_array_keep_cb,
+ (void*)property);
+}
+
+static void
+_property_add(Eflat_Xml_Model_Data *pd, const char *property, const char *value)
+{
+ EINA_SAFETY_ON_NULL_RETURN(property);
+ EINA_SAFETY_ON_NULL_RETURN(value);
+
+ DBG("(%p) adding property %s=%s", pd->obj, property, value);
+
+ char *property_copy = strdup(property);
+ EINA_SAFETY_ON_NULL_RETURN(property_copy);
+
+ Eina_Bool ret = eina_array_push(pd->properties_array, property_copy);
+ EINA_SAFETY_ON_FALSE_RETURN(ret);
+
+ Eina_Value *prop_value = eina_hash_find(pd->properties_hash, property);
+ if (!prop_value)
+ {
+ prop_value = eina_value_new(EINA_VALUE_TYPE_STRING);
+ EINA_SAFETY_ON_NULL_RETURN(prop_value);
+
+ ret = eina_hash_add(pd->properties_hash, property, prop_value);
+ EINA_SAFETY_ON_FALSE_RETURN(ret);
+ }
+
+ ret = eina_value_set(prop_value, value);
+ EINA_SAFETY_ON_FALSE_RETURN(ret);
+}
+
+static void
+_node_clear(Eflat_Xml_Model_Data *pd, Eina_Simple_XML_Node_Tag *node)
+{
+ DBG("(%p)", pd->obj);
+ EINA_SAFETY_ON_NULL_RETURN(node);
+ char *path = _path_from_node_get(node);
+ EINA_SAFETY_ON_NULL_RETURN(path);
+
+ DBG("(%p)", pd->obj);
+ _node_children_properties_del(pd, node, path);
+ free(path);
+
+ _node_children_del(node);
+}
+
+static void
+_generate_properties_from_node(Eflat_Xml_Model_Data *pd,
+ Eina_Simple_XML_Node_Tag *node)
+{
+ char *path = _path_from_node_get(node);
+
+ Eina_Simple_XML_Attribute *attr;
+ EINA_INLIST_FOREACH(node->attributes, attr)
+ {
+ char *attr_path = _concatenate_path(path, attr->key, '@');
+ _property_add(pd, attr_path, attr->value);
+ free(attr_path);
+ }
+
+ size_t lines_count = 0;
+ Eina_Strbuf *buf = eina_strbuf_new();
+
+ Eina_Simple_XML_Node *child;
+ EINA_INLIST_FOREACH(node->children, child)
+ {
+ switch (child->type)
+ {
+ case EINA_SIMPLE_XML_NODE_TAG:
+ _generate_properties_from_node(pd, (Eina_Simple_XML_Node_Tag*)child);
+ break;
+ case EINA_SIMPLE_XML_NODE_DATA:
+ {
+ Eina_Simple_XML_Node_Data *data = (Eina_Simple_XML_Node_Data*)child;
+ if (!data->length) break;
+ eina_strbuf_append_length(buf, data->data, data->length);
+ if (lines_count > 0)
+ eina_strbuf_append(buf, "\n");
+ ++lines_count;
+ break;
+ }
+ case EINA_SIMPLE_XML_NODE_PROCESSING:
+ {
+ const Eina_Simple_XML_Node_Processing *data = (Eina_Simple_XML_Node_Processing*)child;
+
+ char *name = _data_name_get(data);
+ char *processing_path = _concatenate_path(path, name, '?');
+
+ size_t name_length = strlen(name);
+ if (data->length == name_length)
+ _property_add(pd, processing_path, "");
+ else
+ _property_add(pd, processing_path, data->data + name_length + 1);
+
+ free(processing_path);
+ free(name);
+ break;
+ }
+ default:
+ ERR("Node type not supported: %d", child->type);
+ break;
+ }
+ }
+
+ if (lines_count)
+ _property_add(pd, path, eina_strbuf_string_get(buf));
+
+ eina_strbuf_free(buf);
+ free(path);
+}
+
+static Eina_Simple_XML_Node_Data *
+_data_value_set(Eina_Simple_XML_Node_Tag *node,
+ Eina_Simple_XML_Node_Data *data,
+ const char *value)
+{
+ Eina_Strbuf *buf = eina_strbuf_new();
+ EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL);
+
+ char *name = _data_name_get(data);
+ EINA_SAFETY_ON_NULL_GOTO(name, on_error_1);
+
+ Eina_Bool ret = eina_strbuf_append_printf(buf, "%s %s", name, value);
+ EINA_SAFETY_ON_FALSE_GOTO(ret, on_error_2);
+
+ Eina_Simple_XML_Node_Data *processing = eina_simple_xml_node_processing_new
+ (node, eina_strbuf_string_get(buf), eina_strbuf_length_get(buf));
+
+ eina_simple_xml_node_processing_free(data);
+ free(name);
+ eina_strbuf_free(buf);
+ return processing;
+
+on_error_2:
+ free(name);
+on_error_1:
+ eina_strbuf_free(buf);
+ return NULL;
+}
+
+static void
+_stream_load(Eflat_Xml_Model_Data *pd,
+ Eina_Simple_XML_Node_Tag *node,
+ const char *xml)
+{
+ _node_clear(pd, node);
+
+ Eina_Simple_XML_Node_Root *root = eina_simple_xml_node_load(xml,
+ strlen(xml),
+ EINA_TRUE);
+ // steals root items
+ Eina_Simple_XML_Node *child;
+ EINA_INLIST_FOREACH(root->children, child)
+ child->parent = node;
+ node->children = root->children;
+ root->children = NULL;
+
+ Eina_Simple_XML_Attribute *attr;
+ EINA_INLIST_FOREACH(root->attributes, attr)
+ attr->parent = node;
+ node->attributes = root->attributes;
+ root->attributes = NULL;
+
+ eina_simple_xml_node_root_free(root);
+
+ _generate_properties_from_node(pd, node);
+}
+
+#include "eflat_xml_model.eo.c"
diff --git a/src/lib/eflat_xml_model/eflat_xml_model.eo b/src/lib/eflat_xml_model/eflat_xml_model.eo
new file mode 100644
index 0000000000..6cf9eebc7e
--- /dev/null
+++ b/src/lib/eflat_xml_model/eflat_xml_model.eo
@@ -0,0 +1,34 @@
+class Eflat_Xml.Model (Eo.Base, Efl.Model.Base) {
+ legacy_prefix: null;
+ methods {
+ constructor {
+ [[Custom Eflat_Xml_Model constructor.
+ @.constructor
+
+ @since 1.13
+ ]]
+ params {
+ xml: const(char)*; [[The XML document]]
+ }
+ }
+ }
+ implements {
+ Eo.Base.constructor;
+ Eo.Base.destructor;
+ Efl.Model.Base.properties.get;
+ Efl.Model.Base.properties_load;
+ Efl.Model.Base.property.set;
+ Efl.Model.Base.property.get;
+ Efl.Model.Base.load;
+ Efl.Model.Base.load_status.get;
+ Efl.Model.Base.unload;
+ Efl.Model.Base.child_add;
+ Efl.Model.Base.child_del;
+ Efl.Model.Base.children_slice.get;
+ Efl.Model.Base.children_count.get;
+ Efl.Model.Base.children_load;
+ }
+ constructors {
+ .constructor;
+ }
+}
diff --git a/src/lib/eflat_xml_model/eflat_xml_model_private.h b/src/lib/eflat_xml_model/eflat_xml_model_private.h
new file mode 100644
index 0000000000..f27837f5fe
--- /dev/null
+++ b/src/lib/eflat_xml_model/eflat_xml_model_private.h
@@ -0,0 +1,34 @@
+#ifndef _EFLAT_XML_MODEL_PRIVATE_H
+#define _EFLAT_XML_MODEL_PRIVATE_H
+
+#include "Eflat_Xml_Model.h"
+
+#include <stdbool.h>
+
+/* logging support */
+extern int _eflat_xml_model_log_dom;
+
+#define CRI(...) EINA_LOG_DOM_CRIT(_eflat_xml_model_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_eflat_xml_model_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_eflat_xml_model_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_eflat_xml_model_log_dom, __VA_ARGS__)
+#define DBG(...) EINA_LOG_DOM_DBG(_eflat_xml_model_log_dom, __VA_ARGS__)
+
+typedef struct _Eflat_Xml_Model_Data Eflat_Xml_Model_Data;
+
+/**
+ * eflat_xml_model
+ */
+struct _Eflat_Xml_Model_Data
+{
+ Eo *obj;
+ Efl_Model_Load load;
+ Eina_Array *properties_array;
+ Eina_Hash *properties_hash;
+ Eina_Simple_XML_Node_Root *root;
+ char *xml;
+ Eina_Value xml_value;
+};
+
+#endif
+
diff --git a/src/tests/eflat_xml_model/eflat_xml_model_suite.c b/src/tests/eflat_xml_model/eflat_xml_model_suite.c
new file mode 100644
index 0000000000..185a053c22
--- /dev/null
+++ b/src/tests/eflat_xml_model/eflat_xml_model_suite.c
@@ -0,0 +1,121 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "eflat_xml_model_suite.h"
+
+#include <Eina.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int _test_eflat_xml_model_log_dom = -1;
+
+typedef struct _Eflat_Xml_Test_Case Eflat_Xml_Test_Case;
+
+struct _Eflat_Xml_Test_Case
+{
+ const char *test_case;
+ void (*build)(TCase *tc);
+};
+
+static const Eflat_Xml_Test_Case etc[] = {
+ { "Eflat_Xml_Model", eflat_xml_test_eflat_xml_model },
+ { NULL, NULL }
+};
+
+static void
+_list_tests(void)
+{
+ const Eflat_Xml_Test_Case *it = etc;
+ fputs("Available Test Cases:\n", stderr);
+ for (; it->test_case; it++)
+ fprintf(stderr, "\t%s\n", it->test_case);
+}
+
+static bool
+_use_test(int argc, const char **argv, const char *test_case)
+{
+ if (argc < 1)
+ return true;
+
+ for (; argc > 0; argc--, argv++)
+ if (strcmp(test_case, *argv) == 0)
+ return true;
+ return false;
+}
+
+static Suite *
+_eflat_xml_suite_build(int argc, const char **argv)
+{
+ Suite *s = suite_create("Eflat_Xml");
+
+ for (int i = 0; etc[i].test_case; ++i)
+ {
+ if (!_use_test(argc, argv, etc[i].test_case)) continue;
+ TCase *tc = tcase_create(etc[i].test_case);
+
+ etc[i].build(tc);
+
+ suite_add_tcase(s, tc);
+ //tcase_set_timeout(tc, 0);
+ }
+
+ return s;
+}
+
+static void
+_init_logging(void)
+{
+ _test_eflat_xml_model_log_dom = eina_log_domain_register("test_eflat_xml_model", EINA_COLOR_LIGHTBLUE);
+ if (_test_eflat_xml_model_log_dom < 0)
+ ck_abort_msg("Could not register log domain: test_eflat_xml_model");
+
+ //eina_log_domain_level_set("esskyuehl", EINA_LOG_LEVEL_DBG);
+ //eina_log_domain_level_set("eflat_xml_model", EINA_LOG_LEVEL_DBG);
+ eina_log_domain_level_set("test_eflat_xml_model", EINA_LOG_LEVEL_DBG);
+}
+
+static void
+_shutdown_logging(void)
+{
+ eina_log_domain_unregister(_test_eflat_xml_model_log_dom);
+ _test_eflat_xml_model_log_dom = -1;
+}
+
+int
+main(int argc, char **argv)
+{
+ for (int i = 1; i < argc; ++i)
+ {
+ if ((strcmp(argv[i], "-h") == 0) ||
+ (strcmp(argv[i], "--help") == 0))
+ {
+ fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n", argv[0]);
+ _list_tests();
+ return 0;
+ }
+ else if ((strcmp(argv[i], "-l") == 0) ||
+ (strcmp(argv[i], "--list") == 0))
+ {
+ _list_tests();
+ return 0;
+ }
+ }
+
+ _init_logging();
+
+ Suite *s = _eflat_xml_suite_build(argc - 1, (const char **)argv + 1);
+ SRunner *sr = srunner_create(s);
+
+ srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml");
+
+ srunner_run_all(sr, CK_ENV);
+ int failed_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ _shutdown_logging();
+
+ return (failed_count == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/tests/eflat_xml_model/eflat_xml_model_suite.h b/src/tests/eflat_xml_model/eflat_xml_model_suite.h
new file mode 100644
index 0000000000..d90a2c5a6d
--- /dev/null
+++ b/src/tests/eflat_xml_model/eflat_xml_model_suite.h
@@ -0,0 +1,16 @@
+#ifndef _EFLAT_XML_SUITE_H
+#define _EFLAT_XML_SUITE_H
+
+#include <check.h>
+
+extern int _test_eflat_xml_model_log_dom;
+
+#define CRI(...) EINA_LOG_DOM_CRIT(_test_eflat_xml_model_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_test_eflat_xml_model_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_test_eflat_xml_model_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_test_eflat_xml_model_log_dom, __VA_ARGS__)
+#define DBG(...) EINA_LOG_DOM_DBG(_test_eflat_xml_model_log_dom, __VA_ARGS__)
+
+void eflat_xml_test_eflat_xml_model(TCase *tc);
+
+#endif
diff --git a/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.c b/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.c
new file mode 100644
index 0000000000..2e05f1a511
--- /dev/null
+++ b/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.c
@@ -0,0 +1,503 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "eflat_xml_model_test_eflat_xml_model.h"
+#include "eflat_xml_model_suite.h"
+
+#include <Ecore.h>
+#include <Eina.h>
+#include <Eflat_Xml_Model.h>
+
+#include <stdbool.h>
+
+static void
+_setup(void)
+{
+ int ret = eflat_xml_model_init();
+ ck_assert_int_ge(ret, 1);
+}
+
+static void
+_teardown(void)
+{
+ int ret = eflat_xml_model_shutdown();
+ ck_assert_int_eq(ret, 0);
+}
+
+static Eina_Bool
+_eo_event_load_status_cb(void *data,
+ Eo *obj EINA_UNUSED,
+ const Eo_Event_Description *desc EINA_UNUSED,
+ void *event_info EINA_UNUSED)
+{
+ Efl_Model_Load_Status expected_status = *((Efl_Model_Load_Status*)data);
+ Efl_Model_Load load = *((Efl_Model_Load*)event_info);
+ if ((load.status & expected_status) != expected_status)
+ return EINA_TRUE;
+
+ ecore_main_loop_quit();
+ return EINA_FALSE;
+}
+
+static void
+_wait_until_load_status(Efl_Model_Base *emodel,
+ Efl_Model_Load_Status expected_status)
+{
+ Efl_Model_Load_Status actual_status;
+ eo_do(emodel, actual_status = efl_model_load_status_get());
+ if (expected_status == actual_status) return;
+
+ eo_do(emodel, eo_event_callback_add(EFL_MODEL_BASE_EVENT_LOAD_STATUS,
+ _eo_event_load_status_cb,
+ &expected_status));
+ ecore_main_loop_begin();
+ eo_do(emodel, eo_event_callback_del(EFL_MODEL_BASE_EVENT_LOAD_STATUS,
+ _eo_event_load_status_cb,
+ &expected_status));
+}
+
+static void
+_check_efl_model_property_str_eq(Efl_Model_Base *emodel,
+ const char *property,
+ const char *expected_value)
+{
+ const Eina_Value *value;
+ Efl_Model_Load_Status status;
+ eo_do(emodel, status = efl_model_property_get(property, &value));
+ ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_LOADED, status);
+ ck_assert_ptr_ne(NULL, value);
+
+ const Eina_Value_Type *property_type = eina_value_type_get(value);
+ fail_if(EINA_VALUE_TYPE_STRING != property_type &&
+ EINA_VALUE_TYPE_STRINGSHARE != property_type);
+
+ const char *actual_value = NULL;
+ eina_value_get(value, &actual_value);
+ ck_assert_str_eq(expected_value, actual_value);
+}
+
+static void
+_check_efl_model_load(Efl_Model_Base *model)
+{
+ eo_do(model, efl_model_load());
+ _wait_until_load_status(model, EFL_MODEL_LOAD_STATUS_LOADED);
+}
+
+static void
+_check_efl_model_properties(Efl_Model_Base *model,
+ const char *expected_properties[])
+{
+ Eina_Array *properties = NULL;
+ Efl_Model_Load_Status status;
+ eo_do(model, status = efl_model_properties_get(&properties));
+ ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_LOADED, status);
+ ck_assert_ptr_ne(NULL, properties);
+
+ unsigned int actual_properties_count = eina_array_count(properties);
+
+ unsigned int expected_properties_count = 0;
+ const char *expected_property = NULL;
+ while ((expected_property = *expected_properties++))
+ {
+ const char *actual_property = eina_array_data_get(properties,
+ expected_properties_count);
+ ck_assert_str_eq(expected_property, actual_property);
+ ++expected_properties_count;
+ ck_assert_int_le(expected_properties_count, actual_properties_count);
+ }
+
+ ck_assert_int_eq(expected_properties_count, actual_properties_count);
+}
+
+static Eflat_Xml_Model *
+_create_flat_xml_model(void)
+{
+ Efl_Model_Base *xml_model = eo_add(EFLAT_XML_MODEL_CLASS,
+ NULL,
+ eflat_xml_model_constructor(NULL));
+ ck_assert_ptr_ne(NULL, xml_model);
+ return xml_model;
+}
+
+START_TEST(smoke)
+{
+ Efl_Model_Base *xml_model = _create_flat_xml_model();
+ eo_unref(xml_model);
+}
+END_TEST
+
+static void
+_check_string_property_set(Efl_Model_Base *model,
+ const char *property,
+ const char *v)
+{
+ Eina_Value value;
+ eina_value_setup(&value, EINA_VALUE_TYPE_STRING);
+ eina_value_set(&value, v);
+ Efl_Model_Load_Status status;
+ eo_do(model, status = efl_model_property_set(property, &value));
+ eina_value_flush(&value);
+ ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_LOADED, status);
+}
+
+static void
+_check_xml_string(Efl_Model_Base *model, const char *expected_xml_string)
+{
+ _check_efl_model_property_str_eq(model, "/", expected_xml_string);
+}
+
+static const char *SAMPLE_XML =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ "<soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">\n"
+ " <soap:Header>\n"
+ " <m:Trans xmlns:m=\"http://my.namespace/header\" soap:mustUnderstand=\"1\">\n"
+ " 1234\n"
+ " </m:Trans>\n"
+ " </soap:Header>\n"
+ " <soap:Body>\n"
+ " <m:MethodName xmlns:m=\"http://my.namespece/body\">\n"
+ " <m:Item>\n"
+ " Value\n"
+ " </m:Item>\n"
+ " </m:MethodName>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>\n";
+
+static void
+_check_sample_xml_properties_names(Efl_Model_Base *xml_model)
+{
+ _check_efl_model_properties(xml_model, (const char*[]){
+ "?xml",
+ "soap:Envelope@xmlns:soap",
+ "soap:Envelope@soap:encodingStyle",
+ "soap:Envelope/soap:Header/m:Trans@xmlns:m",
+ "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand",
+ "soap:Envelope/soap:Header/m:Trans",
+ "soap:Envelope/soap:Body/m:MethodName@xmlns:m",
+ "soap:Envelope/soap:Body/m:MethodName/m:Item",
+ NULL});
+}
+
+static void
+_check_sample_xml_properties_values(Efl_Model_Base *xml_model)
+{
+ _check_efl_model_property_str_eq(xml_model, "?xml", "version=\"1.0\" encoding=\"UTF-8\"");
+ _check_efl_model_property_str_eq(xml_model, "soap:Envelope@xmlns:soap", "http://www.w3.org/2001/12/soap-envelope");
+ _check_efl_model_property_str_eq(xml_model, "soap:Envelope@soap:encodingStyle", "http://www.w3.org/2001/12/soap-encoding");
+ _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Header/m:Trans@xmlns:m", "http://my.namespace/header");
+ _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand", "1");
+ _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Header/m:Trans", "1234");
+ _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Body/m:MethodName@xmlns:m", "http://my.namespece/body");
+ _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Body/m:MethodName/m:Item", "Value");
+}
+
+static void
+_check_property_set(Efl_Model_Base *xml_model)
+{
+ _check_string_property_set(xml_model, "?xml", "version=\"1.0\" encoding=\"UTF-8\"");
+ _check_string_property_set(xml_model, "soap:Envelope@xmlns:soap", "http://www.w3.org/2001/12/soap-envelope");
+ _check_string_property_set(xml_model, "soap:Envelope@soap:encodingStyle", "http://www.w3.org/2001/12/soap-encoding");
+ _check_string_property_set(xml_model, "soap:Envelope/soap:Header/m:Trans@xmlns:m", "http://my.namespace/header");
+ _check_string_property_set(xml_model, "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand", "1");
+ _check_string_property_set(xml_model, "soap:Envelope/soap:Header/m:Trans", "1234");
+ _check_string_property_set(xml_model, "soap:Envelope/soap:Body/m:MethodName@xmlns:m", "http://my.namespece/body");
+ _check_string_property_set(xml_model, "soap:Envelope/soap:Body/m:MethodName/m:Item", "Value");
+
+ _check_xml_string(xml_model, SAMPLE_XML);
+
+ _check_sample_xml_properties_names(xml_model);
+
+ _check_efl_model_property_str_eq(xml_model, "?xml", "version=\"1.0\" encoding=\"UTF-8\"");
+}
+
+START_TEST(property_set_basic)
+{
+ Efl_Model_Base *xml_model = _create_flat_xml_model();
+
+ _check_efl_model_load(xml_model);
+
+ _check_property_set(xml_model);
+
+ eo_unref(xml_model);
+}
+END_TEST
+
+static void
+_check_property_not_exists(Efl_Model_Base *model, const char *property)
+{
+ const Eina_Value *value;
+ Efl_Model_Load_Status status;
+ eo_do(model, status = efl_model_property_get(property, &value));
+ ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_ERROR, status);
+
+ Eina_Array *properties = NULL;
+ eo_do(model, status = efl_model_properties_get(&properties));
+ ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_LOADED, status);
+ ck_assert_ptr_ne(NULL, properties);
+
+ unsigned int i;
+ char *item;
+ Eina_Array_Iterator it;
+ EINA_ARRAY_ITER_NEXT(properties, i, item, it)
+ ck_assert_str_ne(property, item);
+}
+
+START_TEST(property_set_existing)
+{
+ Efl_Model_Base *xml_model = _create_flat_xml_model();
+
+ _check_efl_model_load(xml_model);
+
+ _check_property_set(xml_model);
+
+ // replaces an attribute
+ _check_string_property_set(xml_model, "soap:Envelope/soap:Header/m:Trans@xmlns:m", "http://other.namespace/header");
+
+ _check_efl_model_properties(xml_model, (const char*[]){
+ "?xml",
+ "soap:Envelope@xmlns:soap",
+ "soap:Envelope@soap:encodingStyle",
+ "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand",
+ "soap:Envelope/soap:Header/m:Trans",
+ "soap:Envelope/soap:Body/m:MethodName@xmlns:m",
+ "soap:Envelope/soap:Body/m:MethodName/m:Item",
+ "soap:Envelope/soap:Header/m:Trans@xmlns:m",
+ NULL});
+
+ // replaces a value
+ _check_string_property_set(xml_model, "soap:Envelope/soap:Header/m:Trans", "4321");
+
+ _check_efl_model_properties(xml_model, (const char*[]){
+ "?xml",
+ "soap:Envelope@xmlns:soap",
+ "soap:Envelope@soap:encodingStyle",
+ "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand",
+ "soap:Envelope/soap:Body/m:MethodName@xmlns:m",
+ "soap:Envelope/soap:Body/m:MethodName/m:Item",
+ "soap:Envelope/soap:Header/m:Trans@xmlns:m",
+ "soap:Envelope/soap:Header/m:Trans",
+ NULL});
+
+ // clears a value
+ _check_string_property_set(xml_model, "soap:Envelope/soap:Body/m:MethodName/m:Item", "");
+
+ _check_xml_string(xml_model,
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ "<soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">\n"
+ " <soap:Header>\n"
+ " <m:Trans xmlns:m=\"http://other.namespace/header\" soap:mustUnderstand=\"1\">\n"
+ " 4321\n"
+ " </m:Trans>\n"
+ " </soap:Header>\n"
+ " <soap:Body>\n"
+ " <m:MethodName xmlns:m=\"http://my.namespece/body\">\n"
+ " <m:Item/>\n"
+ " </m:MethodName>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>\n"
+ );
+
+ _check_efl_model_properties(xml_model, (const char*[]){
+ "?xml",
+ "soap:Envelope@xmlns:soap",
+ "soap:Envelope@soap:encodingStyle",
+ "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand",
+ "soap:Envelope/soap:Body/m:MethodName@xmlns:m",
+ "soap:Envelope/soap:Header/m:Trans@xmlns:m",
+ "soap:Envelope/soap:Header/m:Trans",
+ "soap:Envelope/soap:Body/m:MethodName/m:Item",
+ NULL});
+
+ // clearing a value clears its children too
+ _check_string_property_set(xml_model, "soap:Envelope/soap:Body", "");
+
+ _check_property_not_exists(xml_model, "soap:Envelope/soap:Body/m:MethodName/m:Item");
+ _check_property_not_exists(xml_model, "soap:Envelope/soap:Body/m:MethodName@xmlns:m");
+
+ _check_xml_string(xml_model,
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ "<soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">\n"
+ " <soap:Header>\n"
+ " <m:Trans xmlns:m=\"http://other.namespace/header\" soap:mustUnderstand=\"1\">\n"
+ " 4321\n"
+ " </m:Trans>\n"
+ " </soap:Header>\n"
+ " <soap:Body/>\n"
+ "</soap:Envelope>\n"
+ );
+
+ _check_efl_model_properties(xml_model, (const char*[]){
+ "?xml",
+ "soap:Envelope@xmlns:soap",
+ "soap:Envelope@soap:encodingStyle",
+ "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand",
+ "soap:Envelope/soap:Header/m:Trans@xmlns:m",
+ "soap:Envelope/soap:Header/m:Trans",
+ "soap:Envelope/soap:Body",
+ NULL});
+
+ eo_unref(xml_model);
+}
+END_TEST
+
+START_TEST(property_set_stream)
+{
+ Efl_Model_Base *xml_model = _create_flat_xml_model();
+
+ _check_efl_model_load(xml_model);
+
+ // root level
+ _check_string_property_set(xml_model, "/", SAMPLE_XML);
+ _check_sample_xml_properties_names(xml_model);
+ _check_sample_xml_properties_values(xml_model);
+
+ _check_string_property_set(xml_model, "soap:Envelope/soap:Body/",
+ " <m:OtherMethod xmlns:m=\"http://my.namespece/body\">\n"
+ " <m:OtherItem>\n"
+ " OtherValue\n"
+ " </m:OtherItem>\n"
+ " </m:OtherMethod>\n"
+ );
+
+ _check_efl_model_properties(xml_model, (const char*[]){
+ "?xml",
+ "soap:Envelope@xmlns:soap",
+ "soap:Envelope@soap:encodingStyle",
+ "soap:Envelope/soap:Header/m:Trans@xmlns:m",
+ "soap:Envelope/soap:Header/m:Trans@soap:mustUnderstand",
+ "soap:Envelope/soap:Header/m:Trans",
+ "soap:Envelope/soap:Body/m:OtherMethod@xmlns:m",
+ "soap:Envelope/soap:Body/m:OtherMethod/m:OtherItem",
+ NULL});
+
+
+ _check_xml_string(xml_model,
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ "<soap:Envelope xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">\n"
+ " <soap:Header>\n"
+ " <m:Trans xmlns:m=\"http://my.namespace/header\" soap:mustUnderstand=\"1\">\n"
+ " 1234\n"
+ " </m:Trans>\n"
+ " </soap:Header>\n"
+ " <soap:Body>\n"
+ " <m:OtherMethod xmlns:m=\"http://my.namespece/body\">\n"
+ " <m:OtherItem>\n"
+ " OtherValue\n"
+ " </m:OtherItem>\n"
+ " </m:OtherMethod>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>\n"
+ );
+
+ eo_unref(xml_model);
+}
+END_TEST
+
+START_TEST(property_get_stream)
+{
+ Efl_Model_Base *xml_model = _create_flat_xml_model();
+
+ _check_efl_model_load(xml_model);
+
+ _check_property_set(xml_model);
+
+ // sublevel
+ _check_efl_model_property_str_eq(xml_model, "soap:Envelope/",
+ "<soap:Header>\n"
+ " <m:Trans xmlns:m=\"http://my.namespace/header\" soap:mustUnderstand=\"1\">\n"
+ " 1234\n"
+ " </m:Trans>\n"
+ "</soap:Header>\n"
+ "<soap:Body>\n"
+ " <m:MethodName xmlns:m=\"http://my.namespece/body\">\n"
+ " <m:Item>\n"
+ " Value\n"
+ " </m:Item>\n"
+ " </m:MethodName>\n"
+ "</soap:Body>\n"
+ );
+
+ // sublevel
+ _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Header/",
+ "<m:Trans xmlns:m=\"http://my.namespace/header\" soap:mustUnderstand=\"1\">\n"
+ " 1234\n"
+ "</m:Trans>\n"
+ );
+
+ // sublevel data
+ _check_efl_model_property_str_eq(xml_model, "soap:Envelope/soap:Header/m:Trans/",
+ "1234\n"
+ );
+
+ eo_unref(xml_model);
+}
+END_TEST
+
+START_TEST(load_status_get)
+{
+ Efl_Model_Base *xml_model = _create_flat_xml_model();
+
+ Efl_Model_Load_Status status;
+ eo_do(xml_model, status = efl_model_load_status_get());
+ ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_UNLOADED, status);
+
+ _check_efl_model_load(xml_model);
+
+ eo_do(xml_model, status = efl_model_load_status_get());
+ ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_LOADED, status);
+
+ eo_unref(xml_model);
+}
+END_TEST
+
+START_TEST(unload)
+{
+ Efl_Model_Base *xml_model = _create_flat_xml_model();
+
+ _check_efl_model_load(xml_model);
+ _check_property_set(xml_model);
+
+ eo_do(xml_model, efl_model_unload());
+
+ // status must be unloaded now
+ Efl_Model_Load_Status status;
+ eo_do(xml_model, status = efl_model_load_status_get());
+ ck_assert_int_eq(EFL_MODEL_LOAD_STATUS_UNLOADED, status);
+
+ // reload and manipulate content
+ _check_efl_model_load(xml_model);
+ _check_property_set(xml_model);
+
+ eo_unref(xml_model);
+}
+END_TEST
+
+START_TEST(xml_load)
+{
+ Efl_Model_Base *xml_model = eo_add(EFLAT_XML_MODEL_CLASS,
+ NULL,
+ eflat_xml_model_constructor(SAMPLE_XML));
+ ck_assert_ptr_ne(NULL, xml_model);
+
+ _check_efl_model_load(xml_model);
+ _check_sample_xml_properties_names(xml_model);
+ _check_sample_xml_properties_values(xml_model);
+
+ eo_unref(xml_model);
+}
+END_TEST
+
+void
+eflat_xml_test_eflat_xml_model(TCase *tc)
+{
+ tcase_add_checked_fixture(tc, _setup, _teardown);
+ tcase_add_test(tc, smoke);
+ tcase_add_test(tc, property_set_basic);
+ tcase_add_test(tc, property_set_existing);
+ tcase_add_test(tc, property_set_stream);
+ tcase_add_test(tc, property_get_stream);
+ tcase_add_test(tc, load_status_get);
+ tcase_add_test(tc, unload);
+ tcase_add_test(tc, xml_load);
+}
diff --git a/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.h b/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.h
new file mode 100644
index 0000000000..b9c836363b
--- /dev/null
+++ b/src/tests/eflat_xml_model/eflat_xml_model_test_eflat_xml_model.h
@@ -0,0 +1,6 @@
+#ifndef _EFLAT_XML_MODEL_TEST_EFLAT_XML_MODEL_H
+#define _EFLAT_XML_MODEL_TEST_EFLAT_XML_MODEL_H
+
+#include <Eflat_Xml_Model.h>
+
+#endif