From: raster Date: Sun, 17 Aug 2008 07:44:18 +0000 (+0000) Subject: move around - flatter. X-Git-Tag: 2.0_release~1 X-Git-Url: http://review.tizen.org/git/?p=framework%2Fuifw%2Feet.git;a=commitdiff_plain;h=81ac62fada354cb9d03fe5fdd0535157bc09b663 move around - flatter. git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eet@35497 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- 81ac62fada354cb9d03fe5fdd0535157bc09b663 diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..13e3ed0 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,40 @@ +.config +autom4te.cache +build-stamp +Makefile +Makefile.in +aclocal.m4 +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +configure-stamp +eet.pc +eet_docs.tar.gz +libtool +ltmain.sh +stamp-h +stamp-h1 +stamp-h.in +install-sh +missing +mkinstalldirs +stamp-h1 +autom4te.cache +depcomp +doc +*.tar.gz +*.oe +*.bb +*.spec +README +eet.c +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +compile diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..c491082 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +The Rasterman (Carsten Haitzler) +David Goodlad +Cedric Bail diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..474fcc5 --- /dev/null +++ b/COPYING @@ -0,0 +1,28 @@ +Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies of the Software and its Copyright notices. In addition publicly +documented acknowledgment must be given that this software has been used if no +source code of this software is made available publicly. This includes +acknowledgments in either Copyright notices, Manuals, Publicity and Marketing +documents or any documentation provided with any product containing this +software. This License does not apply to any software that links to the +libraries provided by this software (statically or dynamically), but only to +the software provided. + +Please see the COPYING.PLAIN for a plain-english explanation of this notice +and it's intent. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/COPYING-PLAIN b/COPYING-PLAIN new file mode 100644 index 0000000..376875e --- /dev/null +++ b/COPYING-PLAIN @@ -0,0 +1,33 @@ +Plain English Copyright Notice + +This file is not intended to be the actual License. The reason this file +exists is that we here are programmers and engineers. We aren't lawyers. We +provide licenses that we THINK say the right things, but we have our own +intentions at heart. This is a plain-english explanation of what those +intentions are, and if you follow them you will be within the "spirit" of +the license. + +The intent is for us to enjoy writing software that is useful to us (the +AUTHORS) and allow others to use it freely and also benefit from the work we +put into making it. We don't want to restrict others using it. They should +not *HAVE* to make the source code of the applications they write that +simply link to these libraries (be that statically or dynamically), or for +them to be limited as to what license they choose to use (be it open, closed +or anything else). But we would like to know you are using these libraries. +We simply would like to know that it has been useful to someone. This is why +we ask for acknowledgement of some sort. + +You can do what you want with the source of this software - it doesn't +matter. We still have it here for ourselves and it is open and free to use +and download and play with. It can't be taken away. We don't really mind what +you do with the source to your software. We would simply like to know that +you are using it - especially if it makes it to a commerical product. If you +simply e-mail all the AUTHORS (see COPYING and AUTHORS files) telling us, and +then make sure you include a paragraph or page in the manual for the product +with the copyright notice and state that you used this software, we will be +very happy. If you want to contribute back modifications and fixes you may have +made we will welcome those too with open arms (generally). If you want help +with changes needed, ports needed or features to be added, arrangements can +be easily made with some dialogue. + +Carsten Haitzler diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..0569349 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,86 @@ +2008-04-20 Carsten Haitzler (The Rasterman) + + 1.0.0 release + +2008-04-28 Carsten Haitzler (The Rasterman) + + * Fixed allocation of a list (EET_G_LIST) of simple types + (IS_SIMPLE_TYPE) to alloc the correct amount (using the correct type + offset). Also fixed a hash (EET_G_HASH) of simple types too. + +2008-05-14 Cedric BAIL + + * Fix convertion from a text to a hash (EET_G_HASH). + + * Fix inlined string (EET_T_INLINED_STRING) dump/undump by introducing + the new word for the parser 'inlined'. + +2008-05-15 Cedric BAIL + + * Fix a typo preventing the parsing of unsigned int (EET_T_UINT). + + * Fix group of simple type by implicitly creating a structure with + the simple type in it. + + * Remove dead code handling group of simple type and put assert + instead. + +2008-05-16 Cedric BAIL + + * Fix eet_data_descriptor3_new as it purpose was to introduce + str_direct_alloc/str_direct_free usage. Application should now receive + direct pointer to read only (mmaped) string. + + * Fix EET_FILE_MODE_READ_WRITE when file doesn't exist. + + * Fix some miss use of efn->offset. + + * Introduce unit test in EFL. The current set provide an overall + coverage rate of 2111 of 2607 lines (81.0%) for eet. It helped + finding and fixing the bugs of the last three days. + The test suite is based on library check. At this time we need + cvs version, look at http://check.sourceforge.net/ to find it. + The covering is done by gcov + The html report is done by lcov version 1.6 or above. + You can found it at http://ltp.sourceforge.net/coverage/lcov.php. + +2008-05-19 Cedric BAIL + + * Old Eet file format is now marked as deprecated and accessing old + file will display a warning. You can already remove completely all + code related to it, but it's still enabled by default. We will later + disable it by default and at some point drop the support completely. + + * Remove use of strcpy and sprintf definitively. + +2008-06-02 Cedric BAIL + + * Introduce tile support and the possibility to decompress eet + image inside an existing surface. + +2008-06-26 Cedric BAIL + + * Massiv code cleanup. + * Add EET_G_ARRAY and EET_G_VAR_ARRAY support. + * Plan for version 2.0 API break of eet_data_descriptor_element_add. + +2008-07-17 Cedric BAIL + + Implement various speed improvement : + + * Use the precomputed hash value for Eet_Data_Chunk. + * Use a hash table instead of a list for pointer that need to be freed. + * Use directly the pointer from the dictionary to do a pointer + comparison instead of a strcmp. + +2008-07-24 Cedric BAIL + + * Fix wrongly stored image when compressed size is bigger than + uncompressed. Fix bug #523. + +2008-07-24 Vincent Torri + + * Add Visual Studio solution and vc projects to compile Eet + with Microsoft tools. + + Written by Dmitriy Mazovka. diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..45f743b --- /dev/null +++ b/Doxyfile @@ -0,0 +1,139 @@ +PROJECT_NAME = Eet +PROJECT_NUMBER = +OUTPUT_DIRECTORY = doc +INPUT = eet.c src/lib/Eet.h +IMAGE_PATH = doc/img +OUTPUT_LANGUAGE = English +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = doc/head.html +HTML_FOOTER = doc/foot.html +HTML_STYLESHEET = doc/e.css +HTML_ALIGN_MEMBERS = YES +ENUM_VALUES_PER_LINE = 1 +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = YES +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +INTERNAL_DOCS = NO +STRIP_CODE_COMMENTS = YES +CASE_SENSE_NAMES = YES +SHORT_NAMES = NO +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = NO +SHOW_INCLUDE_FILES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 2 +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ALIASES = +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SHOW_USED_FILES = NO +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +FILE_PATTERNS = +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 2 +IGNORE_PREFIX = +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +GENERATE_MAN = YES +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = YES +GENERATE_XML = NO +XML_SCHEMA = +XML_DTD = +GENERATE_AUTOGEN_DEF = NO +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = NO +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = NO +COLLABORATION_GRAPH = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +GRAPHICAL_HIERARCHY = NO +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 512 +MAX_DOT_GRAPH_HEIGHT = 512 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +SEARCHENGINE = NO diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..df426ed --- /dev/null +++ b/INSTALL @@ -0,0 +1,47 @@ +COMPILING and INSTALLING: + +If you got a official release tar archive do: + ./configure + +( otherwise if you got this from enlightenment cvs do: ./autogen.sh ) + +Then to compile: + make + +To install (run this as root, or the user who handles installs): + make install + +To run the unit tests (See Note 5 below): + make check + +To get the coverage report (See Notes 6 and 7 below): + make coverage + +The report is created in the coverage/ subdir + + + + +NOTE 1: You MUST make install Eet for it to run properly. + +NOTE 2: For compilation with MinGW, fnmatch.h is probably missing. + That file can be found here: +http://www.koders.com/c/fid2B518462CB1EED3D4E31E271DB83CD1582F6EEBE.aspx + It should be installed in the mingw include directory. + +NOTE 3: For compilation with mingw32ce, run configure with the option + +--host=arm-wince-mingw32ce + +NOTE 4: For compilation with cegcc, follow the wiki: + +http://wiki.enlightenment.org/index.php/Category:EFL_Windows_CE + +NOTE 5: If you want to be able to run make check, you need library check + from http://check.sourceforge.net/. + +NOTE 6: If you want to be able to run coverage test over eet, you will need + gcov (usually any distro provides it) and lcov from + http://ltp.sourceforge.net/coverage/lcov.php. + +NOTE 7: For coverage support you also need check support. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..76993fd --- /dev/null +++ b/Makefile.am @@ -0,0 +1,86 @@ +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = src + +MAINTAINERCLEANFILES = \ +Makefile.in \ +aclocal.m4 \ +compile \ +config.guess \ +config.h.in \ +config.sub \ +configure \ +depcomp \ +install-sh \ +ltmain.sh \ +missing \ +eet_docs.tar.gz \ +m4/libtool.m4 \ +m4/lt~obsolete.m4 \ +m4/ltoptions.m4 \ +m4/ltsugar.m4 \ +m4/ltversion.m4 + +EXTRA_DIST = \ +AUTHORS \ +COPYING \ +COPYING-PLAIN \ +autogen.sh \ +eet.c.in \ +eet.pc.in \ +eet.spec.in \ +eet.spec \ +README.in \ +README \ +Doxyfile \ +doc \ +gendoc + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = eet.pc + + +if EET_ENABLE_TESTS + +check-local: + @./src/tests/eet_suite + +else + +check-local: + @echo "reconfigure with --enable-tests" + +endif + +if EET_ENABLE_COVERAGE +lcov-reset: + @rm -rf coverage + @find . -name "*.gcda" -exec rm {} \; + @lcov --directory . --zerocounters + +lcov-report: + @mkdir coverage + @lcov --compat-libtool --directory . --capture --output-file coverage/coverage.info + @lcov -l coverage/coverage.info | grep -v "`cd $(top_srcdir) && pwd`" | cut -d: -f1 > coverage/remove + @lcov -r coverage/coverage.info `cat coverage/remove` > coverage/coverage.cleaned.info + @rm coverage/remove + @mv coverage/coverage.cleaned.info coverage/coverage.info + @genhtml -t "$(PACKAGE_STRING)" -o coverage coverage/coverage.info + +coverage: + @make lcov-reset + @make check + @make lcov-report + +clean-local: + @rm -rf coverage +else +lcov-reset: + @echo "reconfigure with --enable-gcov" + +lcov-report: + @echo "reconfigure with --enable-gcov" + +coverage: + @echo "reconfigure with --enable-tests --enable-gcov" +endif diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..eecaa10 --- /dev/null +++ b/NEWS @@ -0,0 +1,2 @@ +2008-04-20 + 1.0.0 Eet Release diff --git a/README.in b/README.in new file mode 100644 index 0000000..de400ff --- /dev/null +++ b/README.in @@ -0,0 +1,45 @@ +Eet @VERSION@ + +Requirements: +------------- +Must: + libc libm zlib libjpeg + Windows: evil + +****************************************************************************** +*** +*** FOR ANY ISSUES WITH EET PLEASE EMAIL: +*** enlightenment-devel@lists.sourceforge.net +*** +****************************************************************************** + +Eet is a tiny library designed to write an arbitary set of chunks of +data to a file and optionally compress each chunk (very much like a +zip file) and allow fast random-access reading of the file later +on. It does not do zip as a zip itself has more complexity than is +needed, and it was much simpler to implement this once here. + +It also can encode and decode data structures in memory, as well as +image data for saving to eet files or sending across the network to +other machines, or just writing to arbitary files on the system. All +data is encoded in a platform independant way and can be written and +read by any architecture. + +------------------------------------------------------------------------------ +COMPILING AND INSTALLING: + + ./configure + make +(do this as root unless you are installing in your users directories): + make install + +------------------------------------------------------------------------------ +BUILDING PACKAGES: + +RPM: To build rpm packages: + + sudo rpm -ta @PACKAGE@-@VERSION@.tar.gz + +You will find rpm packages in your system /usr/src/redhat/* dirs (note you may +not need to use sudo or root if you have your own ~/.rpmrc. see rpm documents +for more details) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..995ff2f --- /dev/null +++ b/autogen.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +rm -rf autom4te.cache +rm -f aclocal.m4 ltmain.sh + +touch README + +echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS -I m4 || exit 1 +echo "Running autoheader..." ; autoheader || exit 1 +echo "Running autoconf..." ; autoconf || exit 1 +echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1 +echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1 + +if [ -z "$NOCONFIGURE" ]; then + ./configure "$@" +fi diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..ebf301e --- /dev/null +++ b/configure.in @@ -0,0 +1,254 @@ +# get rid of that stupid cache mechanism +rm -f config.cache + +AC_INIT(eet, 1.0.1, enlightenment-devel@lists.sourceforge.net) +AC_PREREQ(2.52) +AC_CONFIG_SRCDIR(configure.in) +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +AC_ISC_POSIX + +AM_INIT_AUTOMAKE(1.6 dist-bzip2) +AM_CONFIG_HEADER(config.h) + +AC_PROG_CC +AM_PROG_CC_STDC +AC_HEADER_STDC +AC_C_CONST +AM_PROG_CC_C_O + +AC_LIBTOOL_WIN32_DLL +define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl +define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl +AC_PROG_LIBTOOL + +VMAJ=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $1);}'` +VMIN=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $2);}'` +VMIC=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $3);}'` +SNAP=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $4);}'` +version_info=`expr $VMAJ + $VMIN`":$VMIC:$VMIN" +AC_SUBST(version_info) + +PKG_PROG_PKG_CONFIG + +WIN32_CFLAGS="" +WIN32_LIBS="" +lt_no_undefined="" +lt_enable_auto_import="" +case "$host_os" in + mingw*|cegcc) + PKG_CHECK_MODULES([EVIL], [evil]) + AC_DEFINE(HAVE_EVIL, 1, [Set to 1 if evil package is installed]) + dnl needed for correct definition of EAPI + AC_DEFINE(EFL_EET_BUILD, 1, [Define to mention that eet is built]) + if test "$host_os" = "cegcc" ; then + WIN32_CFLAGS="-mwin32" + WIN32_LIBS="-lws2" + lt_enable_auto_import="-Wl,--enable-auto-import" + else + WIN32_LIBS="-lws2_32" + fi + lt_no_undefined="-no-undefined" + ;; +esac +AC_SUBST(WIN32_CFLAGS) +AC_SUBST(WIN32_LIBS) +AC_SUBST(lt_no_undefined) +AC_SUBST(lt_enable_auto_import) + +dnl Checking for __attribute__ support +AC_MSG_CHECKING([for __attribute__]) +AC_CACHE_VAL(_cv_have___attribute__, + [ + AC_TRY_COMPILE([#include ], + [int func(int x); int foo(int x __attribute__ ((unused))) { exit(1); }], + [_cv_have___attribute__="yes"], + [_cv_have___attribute__="no"]) + ] +) + +if test "x${_cv_have___attribute__}" = "xyes" ; then + AC_DEFINE(HAVE___ATTRIBUTE__, 1, [Define to 1 if your compiler has __attribute__]) +fi +AC_MSG_RESULT(${_cv_have___attribute__}) + +AC_FUNC_ALLOCA + +AC_CHECK_HEADER(zlib.h,, AC_MSG_ERROR("Cannot find zlib.h. Make sure your CFLAGS environment variable contains include lines for the location of this file")) +AC_CHECK_HEADER(jpeglib.h,, AC_MSG_ERROR("Cannot find jpeglib.h. Make sure your CFLAGS environment variable contains include lines for the location of this file")) + +AC_CHECK_HEADERS(netinet/in.h) + +AC_CHECK_HEADER(fnmatch.h,, AC_MSG_ERROR([Cannot find fnmatch.h. Make sure your CFLAGS environment variable contains include lines for the location of this file. MinGW users: see the INSTALL file])) + +fnmatch_libs="" +AC_CHECK_FUNCS(fnmatch, res=yes, res=no) +if test "x$res" = "xno"; then + AC_CHECK_LIB(fnmatch, fnmatch, res=yes fnmatch_libs="-lfnmatch", res=no) +dnl Test for compilation with MinGW. +dnl fnmatch function is in the libiberty library + if test "x$res" = "xno"; then + AC_CHECK_LIB(iberty, fnmatch, res=yes fnmatch_libs="-liberty", res=no) + fi + if test "x$res" = "xno"; then + AC_MSG_ERROR([Cannot find fnmatch() in neither libc nor libfnmatch, nor libiberty]) + fi +fi + +AC_SUBST(fnmatch_libs) + +dnl These are needed for fmemopen/open_memstream +AC_DEFINE(_GNU_SOURCE, , [Enable GNU extensions]) + +AC_CHECK_FUNCS(fmemopen open_memstream realpath) + +dnl Check whether the null pointer is zero on this arch +AC_MSG_CHECKING([value of the null pointer]) +AC_TRY_RUN([ +#include +int main (int argc, char **argv) { + void *foo = NULL; + int bar = (int)foo; + return (int)foo; +} +], AC_MSG_RESULT([yes]), [ + AC_MSG_RESULT([no]) + AC_MSG_WARN([Your system is a bit too funny, eet might not work properly]) +], AC_MSG_WARN([Cannot check when cross-compiling -- assuming null is okay]) +) + +dnl Unit Tests + +AC_ARG_ENABLE(tests, + [AC_HELP_STRING([--enable-tests], [Enable tests @<:@default=no@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + enable_tests="yes" + else + enable_tests="no" + fi + ], + [enable_tests="no"] +) +AC_MSG_CHECKING([if tests are built]) +AC_MSG_RESULT([${enable_tests}]) + +if test "x${enable_tests}" = "xyes" ; then + PKG_CHECK_MODULES([CHECK], + [check >= 0.9.5], + [dummy="yes"], + [enable_tests="no"] + ) +fi + +AM_CONDITIONAL(EET_ENABLE_TESTS, test "x${enable_tests}" = "xyes") + +dnl Coverage + +AC_ARG_ENABLE(coverage, + [AC_HELP_STRING([--enable-coverage], + [compile with coverage profiling instrumentation @<:@default=no@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + enable_coverage="yes" + else + enable_coverage="no" + fi], + [enable_coverage="no"] +) +AC_MSG_CHECKING([whether to use profiling instrumentation]) +AC_MSG_RESULT($enable_coverage) + +if test "x$enable_tests" = "xno" -a "x$enable_coverage" = "xyes"; then + enable_coverage="no" +fi + +if test "x$enable_coverage" = "xyes"; then + AC_CHECK_PROG(have_lcov, + [lcov], + [yes], + [no] + ) + if test "x$have_lcov" = "xyes" ; then + COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage" + COVERAGE_LIBS="-lgcov" +dnl remove any optimisation flag and force debug symbols + CFLAGS="-g -O0" + else + AC_MSG_WARN([lcov is not found, disable profiling instrumentation]) + enable_coverage="no" + fi +fi +AC_SUBST(COVERAGE_CFLAGS) +AC_SUBST(COVERAGE_LIBS) + +AM_CONDITIONAL(EET_ENABLE_COVERAGE, test "x$enable_coverage" = "xyes") + +dnl Disable support for old eet file format. +old_eet_file_format="yes" +AC_ARG_ENABLE(old-eet-file-format, + AC_HELP_STRING( + [--disable-old-eet-file-format], + [disable old eet file format support. [[default=enabled]]] + ), + [ old_eet_file_format=$enableval ] +) +AM_CONDITIONAL(EET_OLD_EET_FILE_FORMAT, test "x$old_eet_file_format" = "xyes") +if test "x$old_eet_file_format" = "xyes"; then + AC_DEFINE(EET_OLD_EET_FILE_FORMAT, 1, [support old eet file format]) +else + AC_DEFINE(EET_OLD_EET_FILE_FORMAT, 0, [support old eet file format]) +fi + +dnl Assert or fail. +prefer_assert="no" +AC_ARG_ENABLE(assert, + AC_HELP_STRING( + [--enable-assert], + [enable assert, [[default=disabled]]] + ), + [ prefer_assert=$enableval ] +) +AM_CONDITIONAL(EET_ASSERT, test "x$prefer_assert" = "xyes") +if test "x$prefer_assert" = "xno"; then + cflags="$cflags -DNDEBUG" +fi + +#AM_CHECK_DOXYGEN() + +AC_OUTPUT([ +Makefile +eet.pc +eet.c +src/Makefile +src/lib/Makefile +src/bin/Makefile +src/tests/Makefile +README +eet.spec +]) + + +##################################################################### +## Info + +echo +echo +echo +echo "------------------------------------------------------------------------" +echo "$PACKAGE_NAME $PACKAGE_VERSION" +echo "------------------------------------------------------------------------" +echo +echo "Configuration Options Summary:" +echo +echo " Tests................: ${enable_tests}" +echo " Coverage.............: ${enable_coverage}" +echo +echo " Old eet file format..: ${old_eet_file_format}" +echo +echo " Compilation..........: make" +echo +echo " Installation.........: make install" +echo +echo " prefix.............: $prefix" +echo diff --git a/debian/.cvsignore b/debian/.cvsignore new file mode 100644 index 0000000..85c5efb --- /dev/null +++ b/debian/.cvsignore @@ -0,0 +1,8 @@ +files +libeet0 +libeet0-dev +libeet0.postinst.debhelper +libeet0.postrm.debhelper +libeet0.substvars +tmp +changelog diff --git a/debian/changelog.in b/debian/changelog.in new file mode 100644 index 0000000..37c09ac --- /dev/null +++ b/debian/changelog.in @@ -0,0 +1,5 @@ +eet (@VERSION@-1) unstable; urgency=low + + * a CVS snapshot release. + + -- Falko Schmidt Fri, 4 Apr 2008 15:13:56 +0000 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..1e8b314 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +6 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..8e7f9d8 --- /dev/null +++ b/debian/control @@ -0,0 +1,77 @@ +Source: eet +Section: libs +Priority: optional +Maintainer: Falko Schmidt +Build-Depends: debhelper (>= 6), cdbs, automake1.7 | automaken, libtool, pkg-config, zlib1g-dev, libjpeg62-dev, doxygen +Standards-Version: 3.7.3 +Homepage: http://www.enlightenment.org + +Package: libeet-dev +Section: libdevel +Architecture: any +Depends: libeet1 (= ${Source-Version}), zlib1g-dev, libjpeg-dev +Description: Enlightenment DR17 file chunk reading/writing library development files + Eet is a tiny library designed to write an arbitary set of chunks of data to a + file and optionally compress each chunk (very much like a zip file) and allow + fast random-access reading of the file later on. It does not do zip as zip + itself has more complexity than we need, and it was much simpler to implement + this once here. + . + This package contains headers and static libraries for development with libeet. + libeet. + +Package: libeet-doc +Section: doc +Architecture: all +Enhances: libeet-dev +Description: libeet1 API documentation + Eet is a tiny library designed to write an arbitary set of chunks of data to a + file and optionally compress each chunk (very much like a zip file) and allow + fast random-access reading of the file later on. It does not do zip as zip + itself has more complexity than we need, and it was much simpler to implement + this once here. + . + This package contains documentation (html and manpages) for development with + libeet. + +Package: libeet1 +Architecture: any +Depends: ${shlibs:Depends} +Description: Enlightenment DR17 file chunk reading/writing library + Eet is a tiny library designed to write an arbitary set of chunks of data to a + file and optionally compress each chunk (very much like a zip file) and allow + fast random-access reading of the file later on. It does not do zip as zip + itself has more complexity than we need, and it was much simpler to implement + this once here. + . + It's small, fast, and does a job. It's heavily commented and fully documented. + +Package: libeet-bin +Architecture: any +Depends: ${shlibs:Depends} +Description: Enlightenment DR17 file chunk reading/writing utility + Eet is a tiny library designed to write an arbitary set of chunks of data to a + file and optionally compress each chunk (very much like a zip file) and allow + fast random-access reading of the file later on. It does not do zip as zip + itself has more complexity than we need, and it was much simpler to implement + this once here. + . + This package contains eet, an utility that allows you to extract, insert, + encode and decode config blobs created with libeet. + +Package: libeet-dbg +Architecture: any +Section: libdevel +Priority: extra +Depends: libeet1 (= ${binary:Version}) +Description: Enlightenment DR17 file chunk reading/writing library - debug symbols + Eet is a tiny library designed to write an arbitary set of chunks of data to a + file and optionally compress each chunk (very much like a zip file) and allow + fast random-access reading of the file later on. It does not do zip as zip + itself has more complexity than we need, and it was much simpler to implement + this once here + . + This package contains unstripped shared libraries. It is provided primarily + to provide a backtrace with names in a debugger, this makes it somewhat easier + to interpret core dumps. The libraries are installed in /usr/lib/debug and + are automatically used by gdb. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..7dc25b6 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,41 @@ +This package was debianized by Falko Schmidt on +Fri, 4 Apr 2008 12:23:41 +0000. + +The source is downloaded from the e17/libs/eet module of the enlightenment CVS +tree. For more information, see: + + http://www.enlightenment.org + +Upstream Authors: Enlightenment team + +Copyright: + + Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) + +License: + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies of the Software, its documentation and marketing & publicity + materials, and acknowledgment shall be given in the documentation, materials + and software packages that this Software was used. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +On Debian systems, the complete text of the BSD License can be found +in `/usr/share/common-licenses/BSD'. + +The Debian packaging is: + (C) 2006 2007,Debian Pkg-e Team + and is licensed under the GPL, see `/usr/share/common-licenses/GPL'. diff --git a/debian/eet.1 b/debian/eet.1 new file mode 100644 index 0000000..2abe11c --- /dev/null +++ b/debian/eet.1 @@ -0,0 +1,50 @@ +.TH EET 1 "November 4, 2007" eet +.SH NAME +eet \- Small tool to handle eet files. +.SH SYNOPSIS +.B eet +.RI -l " FILE.EET" +.br +.B eet +.RI -r " FILE.EET KEY" +.br +.B eet +.RI "-x|-d" " FILE.EET KEY OUT-FILE" +.br +.B eet +.RI "-i|-e" " FILE.EET KEY IN-FILE COMPRESS" +.br +.SH DESCRIPTION +This manual page documents briefly the +.B eet +command +.PP +\fBeet\fP is a program that can extract, import, delete, list, decode and encode data from eet files. +.SH OPTIONS +.TP +.B \-l +List all keys in FILE.EET. +.TP +.B \-r +Remove KEY in FILE.EET. +.TP +.B \-x +Extract data stored in KEY in FILE.EET and write to OUT-FILE +.TP +.B \-d +Extract and decode data stored in KEY in FILE.EET and write to OUT-FILE +.TP +.B \-i +Insert data to KEY in FILE.EET from IN-FILE and if COMPRESS is 1, compress it +.TP +.B \-e +Insert and encode to KEY in FILE.EET from IN-FILE and if COMPRESS is 1, compress it +.SH BUGS +To report a bug, please visit \fIhttp://bugs.enlightenment.org/\fR +.SH AUTHOR +.TP +eet was written by the Enlightenment Development Team +.I http://web.enlightenment.org +.PP +This manual page was written by Albin Tonnerre , +for the Debian project (but may be used by others). diff --git a/debian/libeet-bin.install b/debian/libeet-bin.install new file mode 100644 index 0000000..3399d7b --- /dev/null +++ b/debian/libeet-bin.install @@ -0,0 +1 @@ +debian/tmp/usr/bin/eet diff --git a/debian/libeet-dev.install b/debian/libeet-dev.install new file mode 100644 index 0000000..4a70bfa --- /dev/null +++ b/debian/libeet-dev.install @@ -0,0 +1,4 @@ +debian/tmp/usr/lib/pkgconfig/* +debian/tmp/usr/include/* +debian/tmp/usr/lib/lib*.a +debian/tmp/usr/lib/lib*.so diff --git a/debian/libeet-doc.dirs b/debian/libeet-doc.dirs new file mode 100644 index 0000000..a110659 --- /dev/null +++ b/debian/libeet-doc.dirs @@ -0,0 +1 @@ +usr/share/doc/libeet-doc diff --git a/debian/libeet-doc.doc-base b/debian/libeet-doc.doc-base new file mode 100644 index 0000000..2d1ef1f --- /dev/null +++ b/debian/libeet-doc.doc-base @@ -0,0 +1,10 @@ +Document: eet +Title: Eet Guide +Author: Carsten Haitzler +Abstract: This document describes Eet API + and provides sample C code. +Section: Programming/C + +Format: HTML +Index: /usr/share/doc/libeet-doc/html/index.html +Files: /usr/share/doc/libeet-doc/html/*.html diff --git a/debian/libeet1.install b/debian/libeet1.install new file mode 100644 index 0000000..c45ebcf --- /dev/null +++ b/debian/libeet1.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/lib*.so.* diff --git a/debian/rules b/debian/rules new file mode 100644 index 0000000..3833157 --- /dev/null +++ b/debian/rules @@ -0,0 +1,22 @@ +#!/usr/bin/make -f + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/autotools.mk + +DEB_INSTALL_MANPAGES_libeet-doc := $(DEB_SRCDIR)/doc/man/man3/*.3 +DEB_INSTALL_MANPAGES_libeet-bin := $(DEB_SRCDIR)/debian/eet.1 +DEB_DH_STRIP_ARGS := --dbg-package=libeet-dbg +DEB_CONFIGURE_EXTRA_FLAGS := --disable-rpath +DEB_MAKE_CLEAN_TARGET := clean + +build/libeet-doc:: + cd $(DEB_SRCDIR) && ./gendoc + +install/libeet-doc:: + cp -R $(DEB_SRCDIR)/doc/html debian/libeet-doc/usr/share/doc/libeet-doc/ + rm $(DEB_SRCDIR)/doc/man/man3/todo.3 + +clean:: + rm -rf $(DEB_SRCDIR)/doc/html $(DEB_SRCDIR)/doc/latex $(DEB_SRCDIR)/doc/man + rm -rf $(DEB_SRCDIR)/eet_docs.tar.gz* + ./autogen.sh --prefix=/usr $(DEB_CONFIGURE_EXTRA_FLAGS) diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 0000000..8723dbe --- /dev/null +++ b/doc/.cvsignore @@ -0,0 +1,5 @@ +Makefile +Makefile.in +html +latex +man diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 0000000..b553e4c --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,139 @@ +PROJECT_NAME = Eet +PROJECT_NUMBER = +OUTPUT_DIRECTORY = . +INPUT = ../eet.c ../src/lib +IMAGE_PATH = img +OUTPUT_LANGUAGE = English +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = head.html +HTML_FOOTER = foot.html +HTML_STYLESHEET = eet.css +HTML_ALIGN_MEMBERS = YES +ENUM_VALUES_PER_LINE = 1 +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +INTERNAL_DOCS = NO +STRIP_CODE_COMMENTS = YES +CASE_SENSE_NAMES = YES +SHORT_NAMES = NO +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = NO +SHOW_INCLUDE_FILES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 2 +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ALIASES = +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SHOW_USED_FILES = NO +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +FILE_PATTERNS = +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 2 +IGNORE_PREFIX = +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +GENERATE_MAN = YES +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = YES +GENERATE_XML = YES +XML_SCHEMA = +XML_DTD = +GENERATE_AUTOGEN_DEF = NO +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = NO +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = NO +COLLABORATION_GRAPH = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +GRAPHICAL_HIERARCHY = NO +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 512 +MAX_DOT_GRAPH_HEIGHT = 512 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +SEARCHENGINE = NO diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..5744849 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,46 @@ + +if BUILD_DOCS + +# install documentation +docdir = $(datadir)/$(PACKAGE)/doc + +all-local: doc-build.stamp + +# rule to remove all old created files +doc-prepare.stamp: + @if test -d html ; then \ + rm -rf html/ latex/ man/ xml/; \ + fi + +# rule to build documentation and copy necessary files +doc-build.stamp: doc-prepare.stamp + @doxygen + @cp img/*.png html/ + +# rules to clean +clean-local: + @rm -rf html/ latex/ man/ xml/ + +# rule to install the documentation in $(docdir) +install-data-local: + @if ! test -d "$(DESTDIR)$(datadir)/$(PACKAGE)"; then \ + $(mkinstalldirs) "$(DESTDIR)$(datadir)/$(PACKAGE)"; \ + fi + @if ! test -d "$(DESTDIR)$(docdir)"; then \ + $(mkinstalldirs) "$(DESTDIR)$(docdir)"; \ + fi + @cp -pr html/ man/ latex/ xml/ "$(DESTDIR)$(docdir)" + +# rule to uninstall the documentation +uninstall-local: + rm -rf $(DESTDIR)$(docdir) + + +MAINTAINERCLEANFILES = Makefile.in eet.c + +DISTCLEANFILES = Makefile.in eet.c + +endif + +EXTRA_DIST = Doxyfile eet.css foot.html head.html img/ + diff --git a/doc/e.css b/doc/e.css new file mode 100644 index 0000000..604ee7f --- /dev/null +++ b/doc/e.css @@ -0,0 +1,161 @@ +body { + background: url("b.png"); + background-repeat: repeat-x; + background-position: top left; + background-color: #f4f4f4; + text-align: center; + font-family: sans-serif; + padding: 0; + margin: 0; +} + +div.main { + margin: 1em auto; + vertical-align: top; + font-family: "Bitstream Vera", "Vera", "Trebuchet MS", Trebuchet, Tahoma, sans-serif; + color: #444444; + font-size: 0.8em; + text-align: justify; + width: 80%; +} + +td.t { background-image:url("t.gif"); } +td.t[class] { background-image:url("t.png"); } +td.tl { background-image:url("tl.gif"); } +td.tl[class] { background-image:url("tl.png"); } + +td.nav, td.lnav, td.rnav { + align: middle; + text-align: center; + vertical-align: middle; + width: 100px; + height: 25px; + font-family: "Bitstream Vera", "Vera", "Trebuchet MS", Trebuchet, Tahoma, sans-serif; + color: #000000; + font-size: 9px; + font-weight: bold; + white-space: no-wrap; +} + +td.lnav[class] { background-image:url("n.png"); } +td.lnav[class] { background-image:url("n.png"); } +td.rnav { background-image:url("n.gif"); } +td.rnav[class] { background-image:url("n.png"); } + +hr { + width: 200px; + height: 1px; + background: #dddddd; + border: 0; +} + +p { color: #444444 ;} +p.tiny, small { + color: #888888; + font-size: 0.5em; +} + +h1 { + text-align: center; + font-size: 1.3em; +} + +h2 { font-size: 1.1em; } +h3 { font-size: 0.9em; } + +span.keyword { color: #008000; } +span.keywordtype { color: #604020; } +span.keywordflow { color: #e08000; } +span.comment { color: #800000; } +span.preprocessor { color: #806020; } +span.stringliteral { color: #002080; } +span.charliteral { color: #008080; } + +a:link { + color: #445566; + text-decoration: underline; +} + +a:visited { + color: #667788; + text-decoration: underline; +} + +a:active { + color: #88cccc; + text-decoration: none; +} + +a:hover { + color: #112266; + text-decoration: underline; +} + +a.nav { + text-decoration: none; + display: block; +} + +a.nav:link, a.nav:visited { color: #888888; } +a.nav:active { color: #000000; } +a.nav:hover { color: #444444; } +a.code:link, a.code:visited { text-decoration: none; } + +div.fragment { + font-size: 1em; + border: 1px dotted #cccccc; + background-color: #ffffff; + text-align: left; + vertical-align: middle; + padding: 2px; + margin-left: 25px; + margin-right: 25px; + overflow: auto; +} + +td.indexkey { + font-weight: bold; + padding-left: 10px; + padding-right: 0; + padding-top: 2px; + padding-bottom: 0px; + margin: 0; + margin-top: 2px; + margin-bottom: 2px; + border: 1px dotted #cccccc; + border-right: 0px dotted #cccccc; +} + +td.indexvalue { + font-style: italic; + padding-right: 10px; + padding-left: 0; + padding-top: 2px; + padding-bottom: 2px; + margin: 0; + margin-top: 2px; + margin-bottom: 2px; + border: 1px dotted #cccccc; + border-left: 0px dotted #cccccc; +} + +.mdescRight { font-style: italic; } +.memitem { + padding-left: 2px; + padding-right: 2px; + border: 1px dotted #cccccc; + background-color: #ffffff; +} +.memname { + white-space: nowrap; + font-weight: bold; +} +.paramname { font-weight: normal; } + +div.ah { + border: thin solid #888888; + font-weight: bold; + margin-bottom: 3px; + margin-top: 3px; +} + diff --git a/doc/eet.css b/doc/eet.css new file mode 100644 index 0000000..6117b39 --- /dev/null +++ b/doc/eet.css @@ -0,0 +1,178 @@ +td.md { + background-color: #ffffff; + font-family: monospace; + text-align: left; + vertical-align: center; + font-size: 10; + padding-right : 1px; + padding-top : 1px; + padding-left : 1px; + padding-bottom : 1px; + margin-left : 1px; + margin-right : 1px; + margin-top : 1px; + margin-bottom : 1px +} +td.mdname { + font-family: monospace; + text-align: left; + vertical-align: center; + font-size: 10; + padding-right : 1px; + padding-top : 1px; + padding-left : 1px; + padding-bottom : 1px; + margin-left : 1px; + margin-right : 1px; + margin-top : 1px; + margin-bottom : 1px +} +h1 +{ + text-align: center; + color: #333333 +} +h2 +{ + text-align: left; + color: #333333 +} +h3 +{ + text-align: left; + color: #333333 +} +a:link +{ + text-decoration: none; + color: #444444; + font-weight: bold; +} +a:visited +{ + text-decoration: none; + color: #666666; + font-weight: bold; +} +a:hover +{ + text-decoration: none; + color: #000000; + font-weight: bold; +} +a.nav:link +{ + text-decoration: none; + color: #444444; + font-weight: normal; +} +a.nav:visited +{ + text-decoration: none; + color: #666666; + font-weight: normal; +} +a.nav:hover +{ + text-decoration: none; + color: #000000; + font-weight: normal; +} +a.qindex:link +{ + text-decoration: none; + color: #444444; + font-weight: normal; +} +a.qindex:visited +{ + text-decoration: none; + color: #666666; + font-weight: normal; +} +a.qindex:hover +{ + text-decoration: none; + color: #000000; + font-weight: normal; +} +p +{ + color: #000000; + font-family: sans-serif; + font-size: 10; +} +body { + background-image: url("hilite.png"); + background-repeat: no-repeat; + background-position: left top; + background-color: #dddddd; + color: #000000; + font-family: sans-serif; + padding: 8px; + margin: 0; +} +div.fragment +{ + background-image: url("hilite.png"); + background-repeat: no-repeat; + background-position: left top; + border: thin solid #888888; + background-color: #eeeeee; + padding: 4px; + text-align: left; + vertical-align: center; + font-size: 12; +} +hr +{ + border: 0; + background-color: #000000; + width: 80%; + height: 1; +} +dl +{ + background-image: url("hilite.png"); + background-repeat: no-repeat; + background-position: left top; + border: thin solid #aaaaaa; + background-color: #eeeeee; + padding: 4px; + text-align: left; + vertical-align: center; + font-size: 12; +} +em +{ + color: #334466; + font-family: courier; + font-size: 10; + font-style: normal; +} + +div.nav +{ + border: thin solid #000000; + background-color: #ffffff; + padding: 1px; + text-align: center; + vertical-align: center; + font-size: 12; +} +div.body +{ + border: thin solid #000000; + background-color: #ffffff; + padding: 4px; + text-align: left; + font-size: 10; +} +div.diag +{ + border: thin solid #888888; + background-color: #eeeeee; + padding: 4px; + text-align: center; + font-size: 8; +} diff --git a/doc/foot.html b/doc/foot.html new file mode 100644 index 0000000..0d3303d --- /dev/null +++ b/doc/foot.html @@ -0,0 +1,6 @@ + +
+

Copyright © Enlightenment.org

+

$projectname Documentation Generated: $datetime

+ + diff --git a/doc/head.html b/doc/head.html new file mode 100644 index 0000000..c2ec935 --- /dev/null +++ b/doc/head.html @@ -0,0 +1,44 @@ + + + + + $title + + + + + + + + + + +
+ + + + + +
Download
+
+ + + + + + + + +
+
+
+ + + + + +
Support
+
+ +
diff --git a/doc/img/_.gif b/doc/img/_.gif new file mode 100644 index 0000000..60fa7a1 Binary files /dev/null and b/doc/img/_.gif differ diff --git a/doc/img/b.png b/doc/img/b.png new file mode 100644 index 0000000..04e5ac8 Binary files /dev/null and b/doc/img/b.png differ diff --git a/doc/img/eet.png b/doc/img/eet.png new file mode 100644 index 0000000..47597a8 Binary files /dev/null and b/doc/img/eet.png differ diff --git a/doc/img/eet_big.png b/doc/img/eet_big.png new file mode 100644 index 0000000..cd818f7 Binary files /dev/null and b/doc/img/eet_big.png differ diff --git a/doc/img/eet_mini.png b/doc/img/eet_mini.png new file mode 100644 index 0000000..f4f99f0 Binary files /dev/null and b/doc/img/eet_mini.png differ diff --git a/doc/img/eet_small.png b/doc/img/eet_small.png new file mode 100644 index 0000000..8bea367 Binary files /dev/null and b/doc/img/eet_small.png differ diff --git a/doc/img/hilite.png b/doc/img/hilite.png new file mode 100644 index 0000000..88a4381 Binary files /dev/null and b/doc/img/hilite.png differ diff --git a/doc/img/n.gif b/doc/img/n.gif new file mode 100644 index 0000000..28608c4 Binary files /dev/null and b/doc/img/n.gif differ diff --git a/doc/img/n.png b/doc/img/n.png new file mode 100644 index 0000000..2bb256f Binary files /dev/null and b/doc/img/n.png differ diff --git a/doc/img/t.gif b/doc/img/t.gif new file mode 100644 index 0000000..cff3068 Binary files /dev/null and b/doc/img/t.gif differ diff --git a/doc/img/t.png b/doc/img/t.png new file mode 100644 index 0000000..06b6079 Binary files /dev/null and b/doc/img/t.png differ diff --git a/doc/img/tl.gif b/doc/img/tl.gif new file mode 100644 index 0000000..4455dbc Binary files /dev/null and b/doc/img/tl.gif differ diff --git a/doc/img/tl.png b/doc/img/tl.png new file mode 100644 index 0000000..95ae5b6 Binary files /dev/null and b/doc/img/tl.png differ diff --git a/eet.c.in b/eet.c.in new file mode 100644 index 0000000..3d6c026 --- /dev/null +++ b/eet.c.in @@ -0,0 +1,188 @@ +/** +@file eet.c +@brief Eet Data Handling Library Public API Calls + +These routines are used for Eet Library interaction +*/ + +/** + +@mainpage Eet Library Documentation +@image html eet.png +@version @PACKAGE_VERSION@ +@author Carsten Haitzler +@date 2000-2008 + + + + + +@section intro What is Eet? + +It is a tiny library designed to write an arbitary set of chunks of data +to a file and optionally compress each chunk (very much like a zip file) +and allow fast random-access reading of the file later on. It does not +do zip as a zip itself has more complexity than is needed, and it was much +simpler to impliment this once here. + +Eet is extremely fast, small and simple. Eet files can be very small and +highly compressed, making them very optimal for just sending across the +internet without having to archive, compress or decompress and install them. +They allow for lightning-fast random-acess reads once created, making them +perfect for storing data that is written once (or rarely) and read many +times, but the program does not want to have to read it all in at once. + +It also can encode and decode data structures in memory, as well as image +data for saving to Eet files or sending across the network to other +machines, or just writing to arbitary files on the system. All data is +encoded in a platform independant way and can be written and read by any +architecture. + + + + + +@section example A simple example on using Eet + +Here is a simple example on how to use Eet to save a series of strings to a +file and load them again. The advantage of using Eet over just fprintf() and +fscanf() is that not only can these entries be strings, they need no special +parsing to handle delimiter characters or escaping, they can be binary data, +image data, data structures containing integers, strings, other data +structures, linked lists and much more, without the programmer having to +worry about parsing, and best of all, Eet is very fast. + +@code +#include + +int +main(int argc, char **argv) +{ + Eet_File *ef; + int i; + char buf[32]; + char *ret; + int size; + char **entries = + { + "Entry 1", + "Big text string here compared to others", + "Eet is cool" + }; + + eet_init(); + + // blindly open an file for output and write strings with their NUL char + ef = eet_open("test.eet", EET_FILE_MODE_WRITE); + eet_write(ef, "Entry 1", entries[0], strlen(entries[0]) + 1, 0); + eet_write(ef, "Entry 2", entries[1], strlen(entries[1]) + 1, 1); + eet_write(ef, "Entry 3", entries[2], strlen(entries[2]) + 1, 0); + eet_close(ef); + + // open the file again and blindly get the entries we wrote + ef = eet_open("test.eet", EET_FILE_MODE_READ); + ret = eet_read(ef, "Entry 1", &size); + printf("%s\n", ret); + ret = eet_read(ef, "Entry 2", &size); + printf("%s\n", ret); + ret = eet_read(ef, "Entry 3", &size); + printf("%s\n", ret); + eet_close(ef); + + eet_shutdown(); +} +@endcode + + + + + +@section format What does an Eet file look like? + +The file format is very simple. There is a directory block at the start of +the file listing entries and offsets into the file where they are stored, +their sizes, compression flags etc. followed by all the entry data strung one +element after the other. + +All Eet files start with t a 4 byte magic number. It is written using network +byte-order (big endian, or from most significant byte first to least +significant byte last) and is 0x1ee7ff00 (or byte by byte 0:1e 1:e7 2:ff +3:00). The next 4 bytes are an integer (in big endian notation) indicating +how many entries are stored in the Eet file. 0 indicates it is empty. This is +a signed integer and thus values less than 0 are invalid, limiting the number +of entries in an Eet file to 0x7fffffff entries at most. The next 4 bytes is +the size of the directory table, in bytes, encoded in big-endian format. This +is a signed integer and cannot be less than 0. + +The directory table for the file follows immediately, with a continuous list +of all entries in the Eet file, their offset in the file etc. The order of +these entries is not important, but convention would have them be from first +to last entry in the file. Each directory entry consiste of 5 integers, one +after the other, each stored as a signed, big endian integer. The first is +the offset in the file that the data for this entry is stored at (based from +the very start of the file, not relative to the end of the directory block). +The second integer holds flags for the entry. currently only the least +significant bit (bit 0) holds any useful information, and it is set to 1 if +the entry is compressed using zlib compression calls, or 0 if it is not +compressed. The next integer is the size of the entry in bytes stored in the +file. The next integer is the size of the data when decompressed (if it was +compressed) in bytes. This may be the same as the previous integer if the +entry was not compressed. The final integer is the number of bytes used by +the string identifier for the entry, without the NUL byte terminator, which +is not stored. The next series of bytes is the string name of the entry, with +the number of bytes being the same as specified in the last integer above. +This list of entries continues until there are no more entries left to list. +To read an entry from an Eet file, simply find the appropriate entry in the +directory table, find it's offset and size, and read it into memory. If it is +compressed, decompress it using zlib and then use that data. + +Here is a data map of an Eet file. All integers are encoded using big-endian +notation (most significant byte first) and are signed. There is no alignment +of data, so all data types follow immediately on, one after the other. All +compressed data is compressed using the zlib compress2() function, and +decompressed using the zlib uncompress() function. Please see zlib +documentation for more information as to the encoding of compressed data. + +@verbatim +HEADER: +[INT] Magic number (0x1ee7ff00) +[INT] Number of entries in the directory table +[INT] The size of the directory table, in bytes + +DIRECTORY TABLE ENTRIES (as many as specified in the header): +[INT] Offest from file start at which entry is stored (in bytes) +[INT] Entry flags (1 = compressed, 0 = not compressed) +[INT] Size of data chunk in file (in bytes) +[INT] Size of the data chunk once decompressed (or the same as above, if not) +[INT] The length of the string itendifier, in bytes, without NUL terminator +[STR] Series of bytes for the string identifier, no NUL terminator +... more directory entries + +DATA STORED, ONE AFTER ANOTHER: +[DAT] DATA ENTRY 1... +[DAT] DATA ENTRY 2... +[DAT] DATA ENTRY 3... +... more data chunks +@endverbatim + +The contents of each entry in an Eet file has no defined format as such. It +is an opaque chunk of data, that is up to the application to deocde, unless +it is an image, ecoded by Eet, or a data structure encoded by Eet. The data +itself for these entries can be encoded and decoded by Eet with extra helper +functions in Eet. eet_data_image_read() and eet_data_image_write() are used +to handle reading and writing image data from a known Eet file entry name. +eet_data_read() and eet_data_write() are used to decode and encode program +data structures from an Eet file, making the loading and saving of program +information stored in data structures a simple 1 function call process. + +Please see src/lib/eet_data.c for information on the format of these +specially encoded data entries in an Eet file (for now). + + + + + +@todo Add hash table, fixed and variable array encode/decode support. +@todo Document data format for images and data structures. + +*/ diff --git a/eet.pc.in b/eet.pc.in new file mode 100644 index 0000000..669d03c --- /dev/null +++ b/eet.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: eet +Description: Library for speedy data storage, retrieval, and compression +Version: @VERSION@ +Libs: -L${libdir} -leet +Libs.private: -lz -ljpeg @fnmatch_libs@ @WIN32_LIBS@ -lm +Cflags: -I${includedir} diff --git a/eet.spec.in b/eet.spec.in new file mode 100644 index 0000000..45bb9f1 --- /dev/null +++ b/eet.spec.in @@ -0,0 +1,74 @@ +%define _missing_doc_files_terminate_build 0 + +Summary: Library for speedy data storage, retrieval, and compression. +Name: @PACKAGE@ +Version: @VERSION@ +Release: 0.%(date '+%Y%m%d') +License: BSD +Group: System Environment/Libraries +Source: %{name}-%{version}.tar.gz +Packager: %{?_packager:%{_packager}}%{!?_packager:Michael Jennings } +Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)} +Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}} +URL: http://www.enlightenment.org/ +BuildRequires: libjpeg-devel zlib-devel +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description +Eet is a tiny library designed to write an arbitary set of chunks of +data to a file and optionally compress each chunk (very much like a +zip file) and allow fast random-access reading of the file later +on. It does not do zip as a zip itself has more complexity than is +needed, and it was much simpler to implement this once here. + +It also can encode and decode data structures in memory, as well as +image data for saving to eet files or sending across the network to +other machines, or just writing to arbitary files on the system. All +data is encoded in a platform independant way and can be written and +read by any architecture. + +%package devel +Summary: Eet headers, static libraries, documentation and test programs +Group: System Environment/Libraries +Requires: %{name} = %{version} +Requires: libjpeg-devel, zlib-devel + +%description devel +Headers, static libraries, test programs and documentation for Eet + +%prep +%setup -q + +%build +%{configure} --prefix=%{_prefix} +### use this if you have build problems +#./configure --prefix=%{_prefix} +%{__make} %{?_smp_mflags} %{?mflags} + +%install +%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install + +%clean +test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%defattr(-, root, root) +%doc AUTHORS COPYING COPYING-PLAIN README +%{_libdir}/*.so.* + +%files devel +%defattr(-, root, root) +%{_bindir}/eet* +%{_libdir}/pkgconfig/* +%{_includedir}/* +%{_libdir}/*.a +%{_libdir}/*.so +%{_libdir}/*.la + +%changelog diff --git a/gendoc b/gendoc new file mode 100755 index 0000000..a308a05 --- /dev/null +++ b/gendoc @@ -0,0 +1,8 @@ +#!/bin/sh +rm -rf ./doc/html ./doc/latex ./doc/man +doxygen +cp doc/img/* doc/html/ +rm -f eet_docs.tar eet_docs.tar.gz +tar -cvf eet_docs.tar doc/html doc/man doc/latex +gzip -9 eet_docs.tar +exit 0 diff --git a/m4/doxygen.m4 b/m4/doxygen.m4 new file mode 100644 index 0000000..32c1349 --- /dev/null +++ b/m4/doxygen.m4 @@ -0,0 +1,73 @@ +dnl Configure script for doxygen +dnl Vincent Torri 2005-22-09 +dnl +dnl AM_CHECK_DOXYGEN([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for the doxygen program, and define BUILD_DOCS and DOXYGEN. +dnl +AC_DEFUN([AM_CHECK_DOXYGEN], + [ + DOXYGEN="doxygen" + dnl + dnl Disable the build of the documentation + dnl + AC_ARG_ENABLE( + [build_docs], + AC_HELP_STRING( + [--disable-build-docs], + [Disable the build of the documentation]), + [if test "${disable_build_docs}" = "yes" ; then + enable_build_docs="no" + else + enable_build_docs="yes" + fi], + [enable_build_docs="yes"]) + dnl + dnl Get the prefix where doxygen is installed. + dnl + AC_ARG_WITH( + [doxygen], + AC_HELP_STRING( + [--with-doxygen=FILE], + [doxygen program to use (eg /usr/bin/doxygen)]), + dnl + dnl Check the given doxygen program. + dnl + [DOXYGEN=${withval} + AC_CHECK_PROG( + [BUILD_DOCS], + [${DOXYGEN}], + [yes], + [no]) + if test $BUILD_DOCS = no; then + echo "WARNING:" + echo "The doxygen program you specified:" + echo "$DOXYGEN" + echo "was not found. Please check the path and make sure " + echo "the program exists and is executable." + AC_MSG_WARN( + [Warning: no doxygen detected. Documentation will not be built]) + fi], + [AC_CHECK_PROG( + [BUILD_DOCS], + [${DOXYGEN}], + [yes], + [no]) + if test ${BUILD_DOCS} = no; then + echo "WARNING:" + echo "The doxygen program was not found in your execute" + echo "You may have doxygen installed somewhere not covered by your path." + echo "" + echo "If this is the case make sure you have the packages installed, AND" + echo "that the doxygen program is in your execute path (see your" + echo "shell's manual page on setting the \$PATH environment variable), OR" + echo "alternatively, specify the program to use with --with-doxygen." + AC_MSG_WARN( + [Warning: no doxygen detected. Documentation will not be built]) + fi]) + dnl + dnl Substitution + dnl + AC_SUBST([DOXYGEN]) + AM_CONDITIONAL(BUILD_DOCS, test "x$BUILD_DOCS" = "xyes") + ]) +dnl End of doxygen.m4 diff --git a/src/.cvsignore b/src/.cvsignore new file mode 100644 index 0000000..4137794 --- /dev/null +++ b/src/.cvsignore @@ -0,0 +1,5 @@ +eet +eet-config +libeet.so.0.0.0 +Makefile +Makefile.in diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..a6fc38f --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,3 @@ +MAINTAINERCLEANFILES = Makefile.in + +SUBDIRS = lib bin tests diff --git a/src/bin/.cvsignore b/src/bin/.cvsignore new file mode 100644 index 0000000..2657148 --- /dev/null +++ b/src/bin/.cvsignore @@ -0,0 +1,5 @@ +.deps +.libs +Makefile +Makefile.in +eet diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am new file mode 100644 index 0000000..024932f --- /dev/null +++ b/src/bin/Makefile.am @@ -0,0 +1,18 @@ + +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir) \ +-I$(top_srcdir)/bin \ +-I$(top_srcdir)/src/lib \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" + +bin_PROGRAMS = eet + +eet_SOURCES = eet_main.c +eet_CFLAGS = @WIN32_CFLAGS@ +eet_LDADD = $(top_builddir)/src/lib/libeet.la +eet_LDFLAGS = @lt_enable_auto_import@ +eet_DEPENDENCIES = $(top_builddir)/src/lib/libeet.la diff --git a/src/bin/eet_main.c b/src/bin/eet_main.c new file mode 100644 index 0000000..d352a0f --- /dev/null +++ b/src/bin/eet_main.c @@ -0,0 +1,251 @@ +#include +#include +#include +#include +#include + +static void +do_eet_list(const char *file) +{ + int i, num; + char **list; + Eet_File *ef; + + ef = eet_open(file, EET_FILE_MODE_READ); + if (!ef) + { + printf("cannot open for reading: %s\n", file); + exit(-1); + } + list = eet_list(ef, "*", &num); + if (list) + { + for (i = 0; i < num; i++) + printf("%s\n",list[i]); + free(list); + } + eet_close(ef); +} + +static void +do_eet_extract(const char *file, const char *key, const char *out) +{ + Eet_File *ef; + void *data; + int size = 0; + FILE *f; + + ef = eet_open(file, EET_FILE_MODE_READ); + if (!ef) + { + printf("cannot open for reading: %s\n", file); + exit(-1); + } + data = eet_read(ef, key, &size); + if (!data) + { + printf("cannot read key %s\n", key); + exit(-1); + } + f = fopen(out, "w"); + if (!f) + { + printf("cannot open %s\n", out); + exit(-1); + } + if (fwrite(data, size, 1, f) != 1) + { + printf("cannot write to %s\n", out); + exit(-1); + } + fclose(f); + free(data); + eet_close(ef); +} + +static void +do_eet_decode_dump(void *data, const char *str) +{ + fputs(str, (FILE *)data); +} + +static void +do_eet_decode(const char *file, const char *key, const char *out) +{ + Eet_File *ef; + FILE *f; + + ef = eet_open(file, EET_FILE_MODE_READ); + if (!ef) + { + printf("cannot open for reading: %s\n", file); + exit(-1); + } + f = fopen(out, "w"); + if (!f) + { + printf("cannot open %s\n", out); + exit(-1); + } + if (!eet_data_dump(ef, key, do_eet_decode_dump, f)) + { + printf("cannot write to %s\n", out); + exit(-1); + } + fclose(f); + eet_close(ef); +} + +static void +do_eet_insert(const char *file, const char *key, const char *out, int compress) +{ + Eet_File *ef; + void *data; + int size = 0; + FILE *f; + + ef = eet_open(file, EET_FILE_MODE_READ_WRITE); + if (!ef) + ef = eet_open(file, EET_FILE_MODE_WRITE); + if (!ef) + { + printf("cannot open for read+write: %s\n", file); + exit(-1); + } + f = fopen(out, "r"); + if (!f) + { + printf("cannot open %s\n", out); + exit(-1); + } + fseek(f, 0, SEEK_END); + size = ftell(f); + rewind(f); + data = malloc(size); + if (!data) + { + printf("cannot allocate %i bytes\n", size); + exit(-1); + } + if (fread(data, size, 1, f) != 1) + { + printf("cannot read file %s\n", out); + exit(-1); + } + fclose(f); + eet_write(ef, key, data, size, compress); + free(data); + eet_close(ef); +} + +static void +do_eet_encode(const char *file, const char *key, const char *out, int compress) +{ + Eet_File *ef; + char *text; + int textlen = 0; + int size = 0; + FILE *f; + + ef = eet_open(file, EET_FILE_MODE_READ_WRITE); + if (!ef) + ef = eet_open(file, EET_FILE_MODE_WRITE); + if (!ef) + { + printf("cannot open for read+write: %s\n", file); + exit(-1); + } + f = fopen(out, "r"); + if (!f) + { + printf("cannot open %s\n", out); + exit(-1); + } + fseek(f, 0, SEEK_END); + textlen = ftell(f); + rewind(f); + text = malloc(textlen); + if (!text) + { + printf("cannot allocate %i bytes\n", size); + exit(-1); + } + if (fread(text, textlen, 1, f) != 1) + { + printf("cannot read file %s\n", out); + exit(-1); + } + fclose(f); + if (!eet_data_undump(ef, key, text, textlen, compress)) + { + printf("cannot parse %s\n", out); + exit(-1); + } + free(text); + eet_close(ef); +} + +static void +do_eet_remove(const char *file, const char *key) +{ + Eet_File *ef; + + ef = eet_open(file, EET_FILE_MODE_READ_WRITE); + if (!ef) + { + printf("cannot open for read+write: %s\n", file); + exit(-1); + } + eet_delete(ef, key); + eet_close(ef); +} + +int +main(int argc, char **argv) +{ + eet_init(); + if (argc < 2) + { + help: + printf("Usage:\n" + " eet -l FILE.EET list all keys in FILE.EET\n" + " eet -x FILE.EET KEY OUT-FILE extract data stored in KEY in FILE.EET and write to OUT-FILE\n" + " eet -d FILE.EET KEY OUT-FILE extract and decode data stored in KEY in FILE.EET and write to OUT-FILE\n" + " eet -i FILE.EET KEY IN-FILE COMPRESS insert data to KEY in FILE.EET from IN-FILE and if COMPRESS is 1, compress it\n" + " eet -e FILE.EET KEY IN-FILE COMPRESS insert and encode to KEY in FILE.EET from IN-FILE and if COMPRESS is 1, compress it\n" + " eet -r FILE.EET KEY remove KEY in FILE.EET\n" + ); + eet_shutdown(); + return 0; + } + if ((!strncmp(argv[1], "-h", 2))) + { + goto help; + } + else if ((!strcmp(argv[1], "-l")) && (argc > 2)) + { + do_eet_list(argv[2]); + } + else if ((!strcmp(argv[1], "-x")) && (argc > 4)) + { + do_eet_extract(argv[2], argv[3], argv[4]); + } + else if ((!strcmp(argv[1], "-d")) && (argc > 4)) + { + do_eet_decode(argv[2], argv[3], argv[4]); + } + else if ((!strcmp(argv[1], "-i")) && (argc > 5)) + { + do_eet_insert(argv[2], argv[3], argv[4], atoi(argv[5])); + } + else if ((!strcmp(argv[1], "-e")) && (argc > 5)) + { + do_eet_encode(argv[2], argv[3], argv[4], atoi(argv[5])); + } + else if ((!strcmp(argv[1], "-r")) && (argc > 3)) + { + do_eet_remove(argv[2], argv[3]); + } + eet_shutdown(); + return 0; +} diff --git a/src/lib/.cvsignore b/src/lib/.cvsignore new file mode 100644 index 0000000..f776647 --- /dev/null +++ b/src/lib/.cvsignore @@ -0,0 +1,10 @@ +eet +eet-config +libeet.so.0.0.0 +.deps +.libs +Makefile +Makefile.in +*.lo +libeet.la +*.gcno diff --git a/src/lib/Eet.h b/src/lib/Eet.h new file mode 100644 index 0000000..dc7a383 --- /dev/null +++ b/src/lib/Eet.h @@ -0,0 +1,1246 @@ +#ifndef _EET_H +#define _EET_H + +#include + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_EET_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_EET_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 + +/** + * @file Eet.h + * @brief The file that provides the eet functions. + * + * This header provides the Eet management functions. + * + */ + +/***************************************************************************/ + +#define EET_T_UNKNOW 0 /**< Unknown data encoding type */ +#define EET_T_CHAR 1 /**< Data type: char */ +#define EET_T_SHORT 2 /**< Data type: short */ +#define EET_T_INT 3 /**< Data type: int */ +#define EET_T_LONG_LONG 4 /**< Data type: long long */ +#define EET_T_FLOAT 5 /**< Data type: float */ +#define EET_T_DOUBLE 6 /**< Data type: double */ +#define EET_T_UCHAR 7 /**< Data type: unsigned char */ +#define EET_T_USHORT 8 /**< Data type: unsigned short */ +#define EET_T_UINT 9 /**< Data type: unsigned int */ +#define EET_T_ULONG_LONG 10 /**< Data type: unsigned long long */ +#define EET_T_STRING 11 /**< Data type: char * */ +#define EET_T_INLINED_STRING 12 /**< Data type: char * (but compressed inside the resulting eet) */ +#define EET_T_LAST 13 /**< Last data type */ + +#define EET_G_UNKNOWN 100 /**< Unknown group data encoding type */ +#define EET_G_ARRAY 101 /**< Fixed size array group type */ +#define EET_G_VAR_ARRAY 102 /**< Variable size array group type */ +#define EET_G_LIST 103 /**< Linked list group type */ +#define EET_G_HASH 104 /**< Hash table group type */ +#define EET_G_LAST 105 /**< Last group type */ + +/***************************************************************************/ + + typedef enum _Eet_File_Mode + { + EET_FILE_MODE_INVALID = -1, + EET_FILE_MODE_READ, + EET_FILE_MODE_WRITE, + EET_FILE_MODE_READ_WRITE + } Eet_File_Mode; + + typedef enum _Eet_Error + { + EET_ERROR_NONE, + EET_ERROR_BAD_OBJECT, + EET_ERROR_EMPTY, + EET_ERROR_NOT_WRITABLE, + EET_ERROR_OUT_OF_MEMORY, + EET_ERROR_WRITE_ERROR, + EET_ERROR_WRITE_ERROR_FILE_TOO_BIG, + EET_ERROR_WRITE_ERROR_IO_ERROR, + EET_ERROR_WRITE_ERROR_OUT_OF_SPACE, + EET_ERROR_WRITE_ERROR_FILE_CLOSED + } Eet_Error; + + typedef struct _Eet_File Eet_File; + typedef struct _Eet_Dictionary Eet_Dictionary; + typedef struct _Eet_Data_Descriptor Eet_Data_Descriptor; + + typedef struct _Eet_Data_Descriptor_Class Eet_Data_Descriptor_Class; + +#define EET_DATA_DESCRIPTOR_CLASS_VERSION 2 + struct _Eet_Data_Descriptor_Class + { + int version; + const char *name; + int size; + struct { + void *(*mem_alloc) (size_t size); + void (*mem_free) (void *mem); + char *(*str_alloc) (const char *str); + void (*str_free) (const char *str); + void *(*list_next) (void *l); + void *(*list_append) (void *l, void *d); + void *(*list_data) (void *l); + void *(*list_free) (void *l); + void (*hash_foreach) (void *h, int (*func) (void *h, const char *k, void *dt, void *fdt), void *fdt); + void *(*hash_add) (void *h, const char *k, void *d); + void (*hash_free) (void *h); + char *(*str_direct_alloc) (const char *str); + void (*str_direct_free) (const char *str); + } func; + }; + +/***************************************************************************/ + + /** + * Initialize the EET library. + * + * @return The new init count. + * + * @since 1.0.0 + */ + EAPI int eet_init(void); + + /** + * Shut down the EET library. + * + * @return The new init count. + * + * @since 1.0.0 + */ + EAPI int eet_shutdown(void); + + /** + * Clear eet cache + * + * Eet didn't free items by default. If you are under memory presure, just + * call this function to recall all memory that are not yet referenced anymore. + * The cache take care of modification on disk. + * + * @since 1.0.0 + */ + EAPI void eet_clearcache(void); + + /** + * Open an eet file on disk, and returns a handle to it. + * @param file The file path to the eet file. eg: "/tmp/file.eet". + * @param mode The mode for opening. Either EET_FILE_MODE_READ, EET_FILE_MODE_WRITE or EET_FILE_MODE_READ_WRITE. + * @return An opened eet file handle. + * + * This function will open an exiting eet file for reading, and build + * the directory table in memory and return a handle to the file, if it + * exists and can be read, and no memory errors occur on the way, otherwise + * NULL will be returned. + * + * It will also open an eet file for writing. This will, if successful, + * delete the original file and replace it with a new empty file, till + * the eet file handle is closed or flushed. If it cannot be opened for + * writing or a memory error occurs, NULL is returned. + * + * You can also open the file for read/write. If you then write a key that + * does not exist it will be created, if the key exists it will be replaced + * by the new data. + * + * Example: + * @code + * #include + * #include + * + * int + * main(int argc, char **argv) + * { + * Eet_File *ef; + * char buf[1024], *ret, **list; + * int size, num, i; + * + * strcpy(buf, "Here is a string of data to save!"); + * + * ef = eet_open("/tmp/my_file.eet", EET_FILE_MODE_WRITE); + * if (!ef) return -1; + * if (!eet_write(ef, "/key/to_store/at", buf, 1024, 1)) + * fprintf(stderr, "Error writing data!\n"); + * eet_close(ef); + * + * ef = eet_open("/tmp/my_file.eet", EET_FILE_MODE_READ); + * if (!ef) return -1; + * list = eet_list(ef, "*", &num); + * if (list) + * { + * for (i = 0; i < num; i++) + * printf("Key stored: %s\n", list[i]); + * free(list); + * } + * ret = eet_read(ef, "/key/to_store/at", &size); + * if (ret) + * { + * printf("Data read (%i bytes):\n%s\n", size, ret); + * free(ret); + * } + * eet_close(ef); + * + * return 0; + * } + * @endcode + * + * @since 1.0.0 + */ + EAPI Eet_File *eet_open(const char *file, Eet_File_Mode mode); + + /** + * Get the mode an Eet_File was opened with. + * @param ef A valid eet file handle. + * @return The mode ef was opened with. + * + * @since 1.0.0 + */ + EAPI Eet_File_Mode eet_mode_get(Eet_File *ef); + + /** + * Close an eet file handle and flush and writes pending. + * @param ef A valid eet file handle. + * + * This function will flush any pending writes to disk if the eet file + * was opened for write, and free all data associated with the file handle + * and file, and close the file. + * + * If the eet file handle is not valid nothing will be done. + * + * @since 1.0.0 + */ + EAPI Eet_Error eet_close(Eet_File *ef); + + + /** + * Return a handle to the shared string dictionary of the Eet file + * @param ef A valid eet file handle. + * @return A handle to the dictionary of the file + * + * This function returns a handle to the dictionary of an Eet file whose + * handle is @p ef, if a dictionary exists. NULL is returned otherwise or + * if the file handle is known to be invalid. + * + * @since 1.0.0 + */ + EAPI Eet_Dictionary *eet_dictionary_get(Eet_File *ef); + + /** + * Check if a given string comes from a given dictionary + * @param ed A valid dictionary handle + * @param string A valid 0 byte terminated C string + * @return 1 if it is in the dictionary, 0 otherwise + * + * This checks the given dictionary to see if the given string is actually + * inside that dictionary (i.e. comes from it) and returns 1 if it does. + * If the dictionary handle is invlide, the string is NULL or the string is + * not in the dictionary, 0 is returned. + * + * @since 1.0.0 + */ + EAPI int eet_dictionary_string_check(Eet_Dictionary *ed, const char *string); + + /** + * Read a specified entry from an eet file and return data + * @param ef A valid eet file handle opened for reading. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param size_ret Number of bytes read from entry and returned. + * @return The data stored in that entry in the eet file. + * + * This function finds an entry in the eet file that is stored under the + * name specified, and returns that data, decompressed, if successful. + * NULL is returned if the lookup fails or if memory errors are + * encountered. It is the job of the calling program to call free() on + * the returned data. The number of bytes in the returned data chunk are + * placed in size_ret. + * + * If the eet file handle is not valid NULL is returned and size_ret is + * filled with 0. + * + * @since 1.0.0 + */ + EAPI void *eet_read(Eet_File *ef, const char *name, int *size_ret); + + /** + * Read a specified entry from an eet file and return data + * @param ef A valid eet file handle opened for reading. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param size_ret Number of bytes read from entry and returned. + * @return The data stored in that entry in the eet file. + * + * This function finds an entry in the eet file that is stored under the + * name specified, and returns that data if not compressed and successful. + * NULL is returned if the lookup fails or if memory errors are + * encountered or if the data is comrpessed. The calling program must never + * call free() on the returned data. The number of bytes in the returned + * data chunk are placed in size_ret. + * + * If the eet file handle is not valid NULL is returned and size_ret is + * filled with 0. + * + * @since 1.0.0 + */ + EAPI const void *eet_read_direct(Eet_File *ef, const char *name, int *size_ret); + + /** + * Write a specified entry to an eet file handle + * @param ef A valid eet file handle opened for writing. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param data Pointer to the data to be stored. + * @param size Length in bytes in the data to be stored. + * @param compress Compression flags (1 == compress, 0 = don't compress). + * @return Success or failure of the write. + * + * This function will write the specified chunk of data to the eet file + * and return greater than 0 on success. 0 will be returned on failure. + * + * The eet file handle must be a valid file handle for an eet file opened + * for writing. If it is not, 0 will be returned and no action will be + * performed. + * + * Name, and data must not be NULL, and size must be > 0. If these + * conditions are not met, 0 will be returned. + * + * The data will be copied (and optionally compressed) in ram, pending + * a flush to disk (it will stay in ram till the eet file handle is + * closed though). + * + * @since 1.0.0 + */ + EAPI int eet_write(Eet_File *ef, const char *name, const void *data, int size, int compress); + + /** + * Delete a specified entry from an Eet file being written or re-written + * @param ef A valid eet file handle opened for writing. + * @param name Name of the entry. eg: "/base/file_i_want". + * @return Success or failure of the delete. + * + * This function will delete the specified chunk of data from the eet file + * and return greater than 0 on success. 0 will be returned on failure. + * + * The eet file handle must be a valid file handle for an eet file opened + * for writing. If it is not, 0 will be returned and no action will be + * performed. + * + * Name, must not be NULL, otherwise 0 will be returned. + * + * @since 1.0.0 + */ + EAPI int eet_delete(Eet_File *ef, const char *name); + + /** + * List all entries in eet file matching shell glob. + * @param ef A valid eet file handle. + * @param glob A shell glob to match against. + * @param count_ret Number of entries found to match. + * @return Pointer to an array of strings. + * + * This function will list all entries in the eet file matching the + * supplied shell glob and return an allocated list of their names, if + * there are any, and if no memory errors occur. + * + * The eet file handle must be valid and glob must not be NULL, or NULL + * will be returned and count_ret will be filled with 0. + * + * The calling program must call free() on the array returned, but NOT + * on the string pointers in the array. They are taken as read-only + * internals from the eet file handle. They are only valid as long as + * the file handle is not closed. When it is closed those pointers in the + * array are now not valid and should not be used. + * + * On success the array returned will have a list of string pointers + * that are the names of the entries that matched, and count_ret will have + * the number of entries in this array placed in it. + * + * Hint: an easy way to list all entries in an eet file is to use a glob + * value of "*". + * + * @since 1.0.0 + */ + EAPI char **eet_list(Eet_File *ef, const char *glob, int *count_ret); + + /** + * Return the number of entries in the specified eet file. + * @param ef A valid eet file handle. + * @return Number of entries in ef or -1 if the number of entries + * cannot be read due to open mode restrictions. + * + * @since 1.0.0 + */ + EAPI int eet_num_entries(Eet_File *ef); + +/***************************************************************************/ + + /** + * Read just the header data for an image and dont decode the pixels. + * @param ef A valid eet file handle opened for reading. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param w A pointer to the unsigned int to hold the width in pixels. + * @param h A pointer to the unsigned int to hold the height in pixels. + * @param alpha A pointer to the int to hold the alpha flag. + * @param compress A pointer to the int to hold the compression amount. + * @param quality A pointer to the int to hold the quality amount. + * @param lossy A pointer to the int to hold the lossiness flag. + * @return 1 on successfull decode, 0 otherwise + * + * This function reads an image from an eet file stored under the named + * key in the eet file and return a pointer to the decompressed pixel data. + * + * The other parameters of the image (width, height etc.) are placed into + * the values pointed to (they must be supplied). The pixel data is a linear + * array of pixels starting from the top-left of the image scanning row by + * row from left to right. Each pile is a 32bit value, with the high byte + * being the alpha channel, the next being red, then green, and the low byte + * being blue. The width and height are measured in pixels and will be + * greater than 0 when returned. The alpha flag is either 0 or 1. 0 denotes + * that the alpha channel is not used. 1 denotes that it is significant. + * Compress is filled with the compression value/amount the image was + * stored with. The quality value is filled with the quality encoding of + * the image file (0 - 100). The lossy flags is either 0 or 1 as to if + * the image was encoded lossily or not. + * + * On success the function returns 1 indicating the header was read and + * decoded properly, or 0 on failure. + * + * @since 1.0.0 + */ + EAPI int eet_data_image_header_read(Eet_File *ef, const char *name, unsigned int *w, unsigned int *h, int *alpha, int *compress, int *quality, int *lossy); + + /** + * Read image data from the named key in the eet file. + * @param ef A valid eet file handle opened for reading. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param w A pointer to the unsigned int to hold the width in pixels. + * @param h A pointer to the unsigned int to hold the height in pixels. + * @param alpha A pointer to the int to hold the alpha flag. + * @param compress A pointer to the int to hold the compression amount. + * @param quality A pointer to the int to hold the quality amount. + * @param lossy A pointer to the int to hold the lossiness flag. + * @return The image pixel data decoded + * + * This function reads an image from an eet file stored under the named + * key in the eet file and return a pointer to the decompressed pixel data. + * + * The other parameters of the image (width, height etc.) are placed into + * the values pointed to (they must be supplied). The pixel data is a linear + * array of pixels starting from the top-left of the image scanning row by + * row from left to right. Each pile is a 32bit value, with the high byte + * being the alpha channel, the next being red, then green, and the low byte + * being blue. The width and height are measured in pixels and will be + * greater than 0 when returned. The alpha flag is either 0 or 1. 0 denotes + * that the alpha channel is not used. 1 denotes that it is significant. + * Compress is filled with the compression value/amount the image was + * stored with. The quality value is filled with the quality encoding of + * the image file (0 - 100). The lossy flags is either 0 or 1 as to if + * the image was encoded lossily or not. + * + * On success the function returns a pointer to the image data decoded. The + * calling application is responsible for calling free() on the image data + * when it is done with it. On failure NULL is returned and the parameter + * values may not contain any sensible data. + * + * @since 1.0.0 + */ + EAPI void *eet_data_image_read(Eet_File *ef, const char *name, unsigned int *w, unsigned int *h, int *alpha, int *compress, int *quality, int *lossy); + + /** + * Read image data from the named key in the eet file. + * @param ef A valid eet file handle opened for reading. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param src_x The starting x coordinate from where to dump the stream. + * @param src_y The starting y coordinate from where to dump the stream. + * @param d A pointer to the pixel surface. + * @param w The expected width in pixels of the pixel surface to decode. + * @param h The expected height in pixels of the pixel surface to decode. + * @param row_stride The length of a pixels line in the destination surface. + * @param alpha A pointer to the int to hold the alpha flag. + * @param compress A pointer to the int to hold the compression amount. + * @param quality A pointer to the int to hold the quality amount. + * @param lossy A pointer to the int to hold the lossiness flag. + * @return 1 on success, 0 otherwise. + * + * This function reads an image from an eet file stored under the named + * key in the eet file and return a pointer to the decompressed pixel data. + * + * The other parameters of the image (width, height etc.) are placed into + * the values pointed to (they must be supplied). The pixel data is a linear + * array of pixels starting from the top-left of the image scanning row by + * row from left to right. Each pile is a 32bit value, with the high byte + * being the alpha channel, the next being red, then green, and the low byte + * being blue. The width and height are measured in pixels and will be + * greater than 0 when returned. The alpha flag is either 0 or 1. 0 denotes + * that the alpha channel is not used. 1 denotes that it is significant. + * Compress is filled with the compression value/amount the image was + * stored with. The quality value is filled with the quality encoding of + * the image file (0 - 100). The lossy flags is either 0 or 1 as to if + * the image was encoded lossily or not. + * + * On success the function returns 1, and 0 on failure. On failure the + * parameter values may not contain any sensible data. + * + * @since 1.0.2 + */ + EAPI int eet_data_image_read_to_surface(Eet_File *ef, const char *name, unsigned int src_x, unsigned int src_y, unsigned int *d, unsigned int w, unsigned int h, unsigned int row_stride, int *alpha, int *compress, int *quality, int *lossy); + + /** + * Write image data to the named key in an eet file. + * @param ef A valid eet file handle opened for writing. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param data A pointer to the image pixel data. + * @param w The width of the image in pixels. + * @param h The height of the image in pixels. + * @param alpha The alpha channel flag. + * @param compress The compression amount. + * @param quality The quality encoding amount. + * @param lossy The lossiness flag. + * @return Success if the data was encoded and written or not. + * + * This function takes image pixel data and encodes it in an eet file + * stored under the supplied name key, and returns how many bytes were + * actually written to encode the image data. + * + * The data expected is the same format as returned by eet_data_image_read. + * If this is not the case weird things may happen. Width and height must + * be between 1 and 8000 pixels. The alpha flags can be 0 or 1 (0 meaning + * the alpha values are not useful and 1 meaning they are). Compress can + * be from 0 to 9 (0 meaning no compression, 9 meaning full compression). + * This is only used if the image is not lossily encoded. Quality is used on + * lossy compression and should be a value from 0 to 100. The lossy flag + * can be 0 or 1. 0 means encode losslessly and 1 means to encode with + * image quality loss (but then have a much smaller encoding). + * + * On success this function returns the number of bytes that were required + * to encode the image data, or on failure it returns 0. + * + * @since 1.0.0 + */ + EAPI int eet_data_image_write(Eet_File *ef, const char *name, const void *data, unsigned int w, unsigned int h, int alpha, int compress, int quality, int lossy); + + /** + * Decode Image data header only to get information. + * @param data The encoded pixel data. + * @param size The size, in bytes, of the encoded pixel data. + * @param w A pointer to the unsigned int to hold the width in pixels. + * @param h A pointer to the unsigned int to hold the height in pixels. + * @param alpha A pointer to the int to hold the alpha flag. + * @param compress A pointer to the int to hold the compression amount. + * @param quality A pointer to the int to hold the quality amount. + * @param lossy A pointer to the int to hold the lossiness flag. + * @return 1 on success, 0 on failure. + * + * This function takes encoded pixel data and decodes it into raw RGBA + * pixels on success. + * + * The other parameters of the image (width, height etc.) are placed into + * the values pointed to (they must be supplied). The pixel data is a linear + * array of pixels starting from the top-left of the image scanning row by + * row from left to right. Each pixel is a 32bit value, with the high byte + * being the alpha channel, the next being red, then green, and the low byte + * being blue. The width and height are measured in pixels and will be + * greater than 0 when returned. The alpha flag is either 0 or 1. 0 denotes + * that the alpha channel is not used. 1 denotes that it is significant. + * Compress is filled with the compression value/amount the image was + * stored with. The quality value is filled with the quality encoding of + * the image file (0 - 100). The lossy flags is either 0 or 1 as to if + * the image was encoded lossily or not. + * + * On success the function returns 1 indicating the header was read and + * decoded properly, or 0 on failure. + * + * @since 1.0.0 + */ + EAPI int eet_data_image_header_decode(const void *data, int size, unsigned int *w, unsigned int *h, int *alpha, int *compress, int *quality, int *lossy); + + /** + * Decode Image data into pixel data. + * @param data The encoded pixel data. + * @param size The size, in bytes, of the encoded pixel data. + * @param w A pointer to the unsigned int to hold the width in pixels. + * @param h A pointer to the unsigned int to hold the height in pixels. + * @param alpha A pointer to the int to hold the alpha flag. + * @param compress A pointer to the int to hold the compression amount. + * @param quality A pointer to the int to hold the quality amount. + * @param lossy A pointer to the int to hold the lossiness flag. + * @return The image pixel data decoded + * + * This function takes encoded pixel data and decodes it into raw RGBA + * pixels on success. + * + * The other parameters of the image (width, height etc.) are placed into + * the values pointed to (they must be supplied). The pixel data is a linear + * array of pixels starting from the top-left of the image scanning row by + * row from left to right. Each pixel is a 32bit value, with the high byte + * being the alpha channel, the next being red, then green, and the low byte + * being blue. The width and height are measured in pixels and will be + * greater than 0 when returned. The alpha flag is either 0 or 1. 0 denotes + * that the alpha channel is not used. 1 denotes that it is significant. + * Compress is filled with the compression value/amount the image was + * stored with. The quality value is filled with the quality encoding of + * the image file (0 - 100). The lossy flags is either 0 or 1 as to if + * the image was encoded lossily or not. + * + * On success the function returns a pointer to the image data decoded. The + * calling application is responsible for calling free() on the image data + * when it is done with it. On failure NULL is returned and the parameter + * values may not contain any sensible data. + * + * @since 1.0.0 + */ + EAPI void *eet_data_image_decode(const void *data, int size, unsigned int *w, unsigned int *h, int *alpha, int *compress, int *quality, int *lossy); + + /** + * Decode Image data into pixel data. + * @param data The encoded pixel data. + * @param size The size, in bytes, of the encoded pixel data. + * @param src_x The starting x coordinate from where to dump the stream. + * @param src_y The starting y coordinate from where to dump the stream. + * @param d A pointer to the pixel surface. + * @param w The expected width in pixels of the pixel surface to decode. + * @param h The expected height in pixels of the pixel surface to decode. + * @param row_stride The length of a pixels line in the destination surface. + * @param alpha A pointer to the int to hold the alpha flag. + * @param compress A pointer to the int to hold the compression amount. + * @param quality A pointer to the int to hold the quality amount. + * @param lossy A pointer to the int to hold the lossiness flag. + * @return 1 on success, 0 otherwise. + * + * This function takes encoded pixel data and decodes it into raw RGBA + * pixels on success. + * + * The other parameters of the image (alpha, compress etc.) are placed into + * the values pointed to (they must be supplied). The pixel data is a linear + * array of pixels starting from the top-left of the image scanning row by + * row from left to right. Each pixel is a 32bit value, with the high byte + * being the alpha channel, the next being red, then green, and the low byte + * being blue. The width and height are measured in pixels and will be + * greater than 0 when returned. The alpha flag is either 0 or 1. 0 denotes + * that the alpha channel is not used. 1 denotes that it is significant. + * Compress is filled with the compression value/amount the image was + * stored with. The quality value is filled with the quality encoding of + * the image file (0 - 100). The lossy flags is either 0 or 1 as to if + * the image was encoded lossily or not. + * + * On success the function returns 1, and 0 on failure. On failure the + * parameter values may not contain any sensible data. + * + * @since 1.0.2 + */ + EAPI int eet_data_image_decode_to_surface(const void *data, int size, unsigned int src_x, unsigned int src_y, unsigned int *d, unsigned int w, unsigned int h, unsigned int row_stride, int *alpha, int *compress, int *quality, int *lossy); + + /** + * Encode image data for storage or transmission. + * @param data A pointer to the image pixel data. + * @param size_ret A pointer to an int to hold the size of the returned data. + * @param w The width of the image in pixels. + * @param h The height of the image in pixels. + * @param alpha The alpha channel flag. + * @param compress The compression amount. + * @param quality The quality encoding amount. + * @param lossy The lossiness flag. + * @return The encoded image data. + * + * This function stakes image pixel data and encodes it with compression and + * possible loss of quality (as a trade off for size) for storage or + * transmission to another system. + * + * The data expected is the same format as returned by eet_data_image_read. + * If this is not the case weird things may happen. Width and height must + * be between 1 and 8000 pixels. The alpha flags can be 0 or 1 (0 meaning + * the alpha values are not useful and 1 meaning they are). Compress can + * be from 0 to 9 (0 meaning no compression, 9 meaning full compression). + * This is only used if the image is not lossily encoded. Quality is used on + * lossy compression and should be a value from 0 to 100. The lossy flag + * can be 0 or 1. 0 means encode losslessly and 1 means to encode with + * image quality loss (but then have a much smaller encoding). + * + * On success this function returns a pointer to the encoded data that you + * can free with free() when no longer needed. + * + * @since 1.0.0 + */ + EAPI void *eet_data_image_encode(const void *data, int *size_ret, unsigned int w, unsigned int h, int alpha, int compress, int quality, int lossy); + +/***************************************************************************/ + + /** + * Create a new empty data structure descriptor. + * @param name The string name of this data structure (most be a global constant and never change). + * @param size The size of the struct (in bytes). + * @param func_list_next The function to get the next list node. + * @param func_list_append The function to append a member to a list. + * @param func_list_data The function to get the data from a list node. + * @param func_list_free The function to free an entire linked list. + * @param func_hash_foreach The function to iterate through all hash table entries. + * @param func_hash_add The function to add a member to a hash table. + * @param func_hash_free The function to free an entire hash table. + * @return A new empty data descriptor. + * + * This function creates a new data descriptore and returns a handle to the + * new data descriptor. On creation it will be empty, containing no contents + * describing anything other than the shell of the data structure. + * + * You add structure members to the data descriptor using the macros + * EET_DATA_DESCRIPTOR_ADD_BASIC(), EET_DATA_DESCRIPTOR_ADD_SUB() and + * EET_DATA_DESCRIPTOR_ADD_LIST(), depending on what type of member you are + * adding to the description. + * + * Once you have described all the members of a struct you want loaded, or + * saved eet can load and save those members for you, encode them into + * endian-independant serialised data chunks for transmission across a + * a network or more. + * + * The function pointers to the list and hash table functions are only + * needed if you use those data types, else you can pass NULL instead. + * + * Example: + * + * @code + * #include + * #include + * + * typedef struct _blah2 + * { + * char *string; + * } + * Blah2; + * + * typedef struct _blah3 + * { + * char *string; + * } + * Blah3; + * + * typedef struct _blah + * { + * char character; + * short sixteen; + * int integer; + * long long lots; + * float floating; + * double floating_lots; + * char *string; + * Blah2 *blah2; + * Evas_List *blah3; + * } + * Blah; + * + * int + * main(int argc, char **argv) + * { + * Blah blah; + * Blah2 blah2; + * Blah3 blah3; + * Eet_Data_Descriptor *edd, *edd2, *edd3; + * void *data; + * int size; + * FILE *f; + * Blah *blah_in; + * + * edd3 = eet_data_descriptor_new("blah3", sizeof(Blah3), + * evas_list_next, + * evas_list_append, + * evas_list_data, + * evas_list_free, + * evas_hash_foreach, + * evas_hash_add, + * evas_hash_free); + * EET_DATA_DESCRIPTOR_ADD_BASIC(edd3, Blah3, "string3", string, EET_T_STRING); + * + * edd2 = eet_data_descriptor_new("blah2", sizeof(Blah2), + * evas_list_next, + * evas_list_append, + * evas_list_data, + * evas_list_free, + * evas_hash_foreach, + * evas_hash_add, + * evas_hash_free); + * EET_DATA_DESCRIPTOR_ADD_BASIC(edd2, Blah2, "string2", string, EET_T_STRING); + * + * edd = eet_data_descriptor_new("blah", sizeof(Blah), + * evas_list_next, + * evas_list_append, + * evas_list_data, + * evas_list_free, + * evas_hash_foreach, + * evas_hash_add, + * evas_hash_free); + * EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Blah, "character", character, EET_T_CHAR); + * EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Blah, "sixteen", sixteen, EET_T_SHORT); + * EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Blah, "integer", integer, EET_T_INT); + * EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Blah, "lots", lots, EET_T_LONG_LONG); + * EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Blah, "floating", floating, EET_T_FLOAT); + * EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Blah, "floating_lots", floating_lots, EET_T_DOUBLE); + * EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Blah, "string", string, EET_T_STRING); + * EET_DATA_DESCRIPTOR_ADD_SUB(edd, Blah, "blah2", blah2, edd2); + * EET_DATA_DESCRIPTOR_ADD_LIST(edd, Blah, "blah3", blah3, edd3); + * + * blah3.string="PANTS"; + * + * blah2.string="subtype string here!"; + * + * blah.character='7'; + * blah.sixteen=0x7777; + * blah.integer=0xc0def00d; + * blah.lots=0xdeadbeef31337777; + * blah.floating=3.141592654; + * blah.floating_lots=0.777777777777777; + * blah.string="bite me like a turnip"; + * blah.blah2 = &blah2; + * blah.blah3 = evas_list_append(NULL, &blah3); + * blah.blah3 = evas_list_append(blah.blah3, &blah3); + * blah.blah3 = evas_list_append(blah.blah3, &blah3); + * blah.blah3 = evas_list_append(blah.blah3, &blah3); + * blah.blah3 = evas_list_append(blah.blah3, &blah3); + * blah.blah3 = evas_list_append(blah.blah3, &blah3); + * blah.blah3 = evas_list_append(blah.blah3, &blah3); + * + * data = eet_data_descriptor_encode(edd, &blah, &size); + * printf("-----DECODING\n"); + * blah_in = eet_data_descriptor_decode(edd, data, size); + * + * printf("-----DECODED!\n"); + * printf("%c\n", blah_in->character); + * printf("%x\n", (int)blah_in->sixteen); + * printf("%x\n", blah_in->integer); + * printf("%lx\n", blah_in->lots); + * printf("%f\n", (double)blah_in->floating); + * printf("%f\n", (double)blah_in->floating_lots); + * printf("%s\n", blah_in->string); + * printf("%p\n", blah_in->blah2); + * printf(" %s\n", blah_in->blah2->string); + * { + * Evas_List *l; + * + * for (l = blah_in->blah3; l; l = l->next) + * { + * Blah3 *blah3_in; + * + * blah3_in = l->data; + * printf("%p\n", blah3_in); + * printf(" %s\n", blah3_in->string); + * } + * } + * eet_data_descriptor_free(edd); + * eet_data_descriptor_free(edd2); + * eet_data_descriptor_free(edd3); + * + * return 0; + * } + * + * @endcode + * + * @since 1.0.0 + */ + EAPI Eet_Data_Descriptor *eet_data_descriptor_new(const char *name, int size, void *(*func_list_next) (void *l), void *(*func_list_append) (void *l, void *d), void *(*func_list_data) (void *l), void *(*func_list_free) (void *l), void (*func_hash_foreach) (void *h, int (*func) (void *h, const char *k, void *dt, void *fdt), void *fdt), void *(*func_hash_add) (void *h, const char *k, void *d), void (*func_hash_free) (void *h)); + /* + * FIXME: + * + * moving to this api from the old above. this will break things when the + * move happens - but be warned + */ + EAPI Eet_Data_Descriptor *eet_data_descriptor2_new(Eet_Data_Descriptor_Class *eddc); + EAPI Eet_Data_Descriptor *eet_data_descriptor3_new(Eet_Data_Descriptor_Class *eddc); + + /** + * This function frees a data descriptor when it is not needed anymore. + * @param edd The data descriptor to free. + * + * This function takes a data descriptor handle as a parameter and frees all + * data allocated for the data descriptor and the handle itself. After this + * call the descriptor is no longer valid. + * + * @since 1.0.0 + */ + EAPI void eet_data_descriptor_free(Eet_Data_Descriptor *edd); + + /** + * This function is an internal used by macros. + * + * This function is used by macros EET_DATA_DESCRIPTOR_ADD_BASIC(), + * EET_DATA_DESCRIPTOR_ADD_SUB() and EET_DATA_DESCRIPTOR_ADD_LIST(). It is + * complex to use by hand and should be left to be used by the macros, and + * thus is not documented. + * + * @since 1.0.0 + */ + EAPI void eet_data_descriptor_element_add(Eet_Data_Descriptor *edd, const char *name, int type, int group_type, int offset, /* int count_offset, */int count, const char *counter_name, Eet_Data_Descriptor *subtype); + + /** + * Read a data structure from an eet file and decodes it. + * @param ef The eet file handle to read from. + * @param edd The data descriptor handle to use when decoding. + * @param name The key the data is stored under in the eet file. + * @return A pointer to the decoded data structure. + * + * This function decodes a data structure stored in an eet file, returning + * a pointer to it if it decoded successfully, or NULL on failure. This + * can save a programmer dozens of hours of work in writing configuration + * file parsing and writing code, as eet does all that work for the program + * and presents a program-friendly data structure, just as the programmer + * likes. Eet can handle members being added or deleted from the data in + * storage and safely zero-fills unfilled members if they were not found + * in the data. It checks sizes and headers whenever it reads data, allowing + * the programmer to not worry about corrupt data. + * + * Once a data structure has been described by the programmer with the + * fields they wish to save or load, storing or retrieving a data structure + * from an eet file, or from a chunk of memory is as simple as a single + * function call. + * + * @since 1.0.0 + */ + EAPI void *eet_data_read(Eet_File *ef, Eet_Data_Descriptor *edd, const char *name); + + /** + * Write a data structure from memory and store in an eet file. + * @param ef The eet file handle to write to. + * @param edd The data descriptor to use when encoding. + * @param name The key to store the data under in the eet file. + * @param data A pointer to the data structure to ssave and encode. + * @param compress Compression flags for storage. + * @return 1 on successful write, 0 on failure. + * + * This function is the reverse of eet_data_read(), saving a data structure + * to an eet file. + * + * @since 1.0.0 + */ + EAPI int eet_data_write(Eet_File *ef, Eet_Data_Descriptor *edd, const char *name, const void *data, int compress); + + /** + * Dump an eet encoded data structure into ascii text + * @param data_in The pointer to the data to decode into a struct. + * @param size_in The size of the data pointed to in bytes. + * @param dumpfunc The function to call passed a string when new data is converted to text + * @param dumpdata The data to pass to the @p dumpfunc callback. + * @return 1 on success, 0 on failure + * + * This function will take a chunk of data encoded by + * eet_data_descriptor_encode() and convert it into human readable ascii text. + * It does this by calling the @p dumpfunc callback for all new text that is + * generated. This callback should append to any existing text buffer and + * will be passed the pointer @p dumpdata as a parameter as well as a string + * with new text to be appended. + * + * Example: + * + * @code + * + * void output(void *data, const char *string) + * { + * printf("%s", string); + * } + * + * void dump(const char *file) + * { + * FILE *f; + * int len; + * void *data; + * + * f = fopen(file, "r"); + * fseek(f, 0, SEEK_END); + * len = ftell(f); + * rewind(f); + * data = malloc(len); + * fread(data, len, 1, f); + * fclose(f); + * eet_data_text_dump(data, len, output, NULL); + * } + * @endcode + * + * @since 1.0.0 + */ + EAPI int eet_data_text_dump(const void *data_in, int size_in, void (*dumpfunc) (void *data, const char *str), void *dumpdata); + + /** + * Take an ascii encoding from eet_data_text_dump() and re-encode in binary. + * @param text The pointer to the string data to parse and encode. + * @param textlen The size of the string in bytes (not including 0 byte terminator). + * @param size_ret This gets filled in with the encoded data blob size in bytes. + * @return The encoded data on success, NULL on failure. + * + * This function will parse the string pointed to by @p text and return + * an encoded data lump the same way eet_data_descriptor_encode() takes an + * in-memory data struct and encodes into a binary blob. @p text is a normal + * C string. + * + * @since 1.0.0 + */ + EAPI void *eet_data_text_undump(const char *text, int textlen, int *size_ret); + + /** + * Dump an eet encoded data structure from an eet file into ascii text + * @param ef A valid eet file handle. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param dumpfunc The function to call passed a string when new data is converted to text + * @param dumpdata The data to pass to the @p dumpfunc callback. + * @return 1 on success, 0 on failure + * + * This function will take an open and valid eet file from eet_open() request + * the data encoded by eet_data_descriptor_encode() corresponding to the key @p name + * and convert it into human readable ascii text. It does this by calling the + * @p dumpfunc callback for all new text that is generated. This callback should + * append to any existing text buffer and will be passed the pointer @p dumpdata + * as a parameter as well as a string with new text to be appended. + * + * @since 1.0.0 + */ + EAPI int eet_data_dump(Eet_File *ef, const char *name, void (*dumpfunc) (void *data, const char *str), void *dumpdata); + + /** + * Take an ascii encoding from eet_data_dump() and re-encode in binary. + * @param ef A valid eet file handle. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param text The pointer to the string data to parse and encode. + * @param textlen The size of the string in bytes (not including 0 byte terminator). + * @param compress Compression flags (1 == compress, 0 = don't compress). + * @return 1 on success, 0 on failure + * + * This function will parse the string pointed to by @p text, encode it the same + * way eet_data_descriptor_encode() takes an in-memory data struct and encodes into a + * binary blob. + * + * The data (optionally compressed) will be in ram, pending a flush to + * disk (it will stay in ram till the eet file handle is closed though). + * + * @since 1.0.0 + */ + EAPI int eet_data_undump(Eet_File *ef, const char *name, const char *text, int textlen, int compress); + + /** + * Decode a data structure from an arbitary location in memory. + * @param edd The data descriptor to use when decoding. + * @param data_in The pointer to the data to decode into a struct. + * @param size_in The size of the data pointed to in bytes. + * @return NULL on failure, or a valid decoded struct pointer on success. + * + * This function will decode a data structure that has been encoded using + * eet_data_descriptor_encode(), and return a data structure with all its + * elements filled out, if successful, or NULL on failure. + * + * The data to be decoded is stored at the memory pointed to by @p data_in, + * and is described by the descriptor pointed to by @p edd. The data size is + * passed in as the value to @p size_in, ande must be greater than 0 to + * succeed. + * + * This function is useful for decoding data structures delivered to the + * application by means other than an eet file, such as an IPC or socket + * connection, raw files, shared memory etc. + * + * Please see eet_data_read() for more information. + * + * @since 1.0.0 + */ + EAPI void *eet_data_descriptor_decode(Eet_Data_Descriptor *edd, const void *data_in, int size_in); + + /** + * Encode a dsata struct to memory and return that encoded data. + * @param edd The data descriptor to use when encoding. + * @param data_in The pointer to the struct to encode into data. + * @param size_ret A pointer to the an int to be filled with the decoded size. + * @return NULL on failure, or a valid encoded data chunk on success. + * + * This function takes a data structutre in memory and encodes it into a + * serialised chunk of data that can be decoded again by + * eet_data_descriptor_decode(). This is useful for being able to transmit + * data structures across sockets, pipes, IPC or shared file mechanisms, + * without having to worry about memory space, machine type, endianess etc. + * + * The parameter @p edd must point to a valid data descriptor, and + * @p data_in must point to the right data structure to encode. If not, the + * encoding may fail. + * + * On success a non NULL valid pointer is returned and what @p size_ret + * points to is set to the size of this decoded data, in bytes. When the + * encoded data is no longer needed, call free() on it. On failure NULL is + * returned and what @p size_ret points to is set to 0. + * + * Please see eet_data_write() for more information. + * + * @since 1.0.0 + */ + EAPI void *eet_data_descriptor_encode(Eet_Data_Descriptor *edd, const void *data_in, int *size_ret); + + /** + * Add a basic data element to a data descriptor. + * @param edd The data descriptor to add the type to. + * @param struct_type The type of the struct. + * @param name The string name to use to encode/decode this member (must be a constant global and never change). + * @param member The struct member itself to be encoded. + * @param type The type of the member to encode. + * + * This macro is a convenience macro provided to add a member to the data + * descriptor @p edd. The type of the structure is provided as the + * @p struct_type parameter (for example: struct my_struct). The @p name + * parameter defines a string that will be used to uniquely name that + * member of the struct (it is suggested to use the struct member itself). + * The @p member parameter is the actual struct member itself (for +eet_dictionary_string_check * example: values), and @p type is the basic data type of the member which + * must be one of: EET_T_CHAR, EET_T_SHORT, EET_T_INT, EET_T_LONG_LONG, + * EET_T_FLOAT, EET_T_DOUBLE, EET_T_UCHAR, EET_T_USHORT, EET_T_UINT, + * EET_T_ULONG_LONG or EET_T_STRING. + * + * @since 1.0.0 + */ +#define EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct_type, name, member, type) \ + { \ + struct_type ___ett; \ + \ + eet_data_descriptor_element_add(edd, name, type, EET_G_UNKNOWN, \ + (char *)(&(___ett.member)) - (char *)(&(___ett)), \ + 0, /* 0, */NULL, NULL); \ + } + + /** + * Add a sub-element type to a data descriptor + * @param edd The data descriptor to add the type to. + * @param struct_type The type of the struct. + * @param name The string name to use to encode/decode this member (must be a constant global and never change). + * @param member The struct member itself to be encoded. + * @param subtype The type of sub-type struct to add. + * + * This macro lets you easily add a sub-type (a struct that's pointed to + * by this one). All the parameters are the same as for + * EET_DATA_DESCRIPTOR_ADD_BASIC(), with the @p subtype being the exception. + * This must be the data descriptor of the struct that is pointed to by + * this element. + * + * @since 1.0.0 + */ +#define EET_DATA_DESCRIPTOR_ADD_SUB(edd, struct_type, name, member, subtype) \ + { \ + struct_type ___ett; \ + \ + eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_UNKNOWN, \ + (char *)(&(___ett.member)) - (char *)(&(___ett)), \ + 0, /* 0, */NULL, subtype); \ + } + + /** + * Add a linked list type to a data descriptor + * @param edd The data descriptor to add the type to. + * @param struct_type The type of the struct. + * @param name The string name to use to encode/decode this member (must be a constant global and never change). + * @param member The struct member itself to be encoded. + * @param subtype The type of linked list member to add. + * + * This macro lets you easily add a linked list of other data types. All the + * parameters are the same as for EET_DATA_DESCRIPTOR_ADD_BASIC(), with the + * @p subtype being the exception. This must be the data descriptor of the + * element that is in each member of the linked list to be stored. + * + * @since 1.0.0 + */ +#define EET_DATA_DESCRIPTOR_ADD_LIST(edd, struct_type, name, member, subtype) \ + { \ + struct_type ___ett; \ + \ + eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_LIST, \ + (char *)(&(___ett.member)) - (char *)(&(___ett)), \ + 0, /* 0, */NULL, subtype); \ + } + + /** + * Add a hash type to a data descriptor + * @param edd The data descriptor to add the type to. + * @param struct_type The type of the struct. + * @param name The string name to use to encode/decode this member (must be a constant global and never change). + * @param member The struct member itself to be encoded. + * @param subtype The type of hash member to add. + * + * This macro lets you easily add a hash of other data types. All the + * parameters are the same as for EET_DATA_DESCRIPTOR_ADD_BASIC(), with the + * @p subtype being the exception. This must be the data descriptor of the + * element that is in each member of the hash to be stored. + * + * @since 1.0.0 + */ +#define EET_DATA_DESCRIPTOR_ADD_HASH(edd, struct_type, name, member, subtype) \ + { \ + struct_type ___ett; \ + \ + eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_HASH, \ + (char *)(&(___ett.member)) - (char *)(&(___ett)), \ + 0, /* 0, */NULL, subtype); \ + } + + /** + * Add a fixed size array type to a data descriptor + * @param edd The data descriptor to add the type to. + * @param struct_type The type of the struct. + * @param name The string name to use to encode/decode this member (must be a constant global and never change). + * @param member The struct member itself to be encoded. + * @param subtype The type of hash member to add. + * + * This macro lets you easily add a fixed size array of other data types. All the + * parameters are the same as for EET_DATA_DESCRIPTOR_ADD_BASIC(), with the + * @p subtype being the exception. This must be the data descriptor of the + * element that is in each member of the hash to be stored. + * + * @since 1.0.2 + */ +#define EET_DATA_DESCRIPTOR_ADD_ARRAY(edd, struct_type, name, member, subtype) \ + { \ + struct_type ___ett; \ + \ + eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_ARRAY, \ + (char *)(&(___ett.member)) - (char *)(&(___ett)), \ + /* 0, */sizeof(___ett.member)/sizeof(___ett.member[0]), NULL, subtype); \ + } + + /** + * Add a variable size array type to a data descriptor + * @param edd The data descriptor to add the type to. + * @param struct_type The type of the struct. + * @param name The string name to use to encode/decode this member (must be a constant global and never change). + * @param member The struct member itself to be encoded. + * @param subtype The type of hash member to add. + * + * This macro lets you easily add a fixed size array of other data types. All the + * parameters are the same as for EET_DATA_DESCRIPTOR_ADD_BASIC(), with the + * @p subtype being the exception. This must be the data descriptor of the + * element that is in each member of the hash to be stored. + * + * @since 1.0.2 + */ +#define EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(edd, struct_type, name, member, subtype) \ + { \ + struct_type ___ett; \ + \ + eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_VAR_ARRAY, \ + (char *)(&(___ett.member)) - (char *)(&(___ett)), \ + (char *)(&(___ett.member ## _count)) - (char *)(&(___ett)), /* 0, */NULL, subtype); \ + } + +/***************************************************************************/ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/Eet_private.h b/src/lib/Eet_private.h new file mode 100644 index 0000000..4af3e2b --- /dev/null +++ b/src/lib/Eet_private.h @@ -0,0 +1,84 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifndef _EET_PRIVATE_H +#define _EET_PRIVATE_H + +#ifdef __GNUC__ +# if __GNUC__ >= 4 +// BROKEN in gcc 4 on amd64 +//# pragma GCC visibility push(hidden) +# endif +#endif + +typedef struct _Eet_String Eet_String; + +struct _Eet_String +{ + const char *mmap; + char *str; + + int hash; + int len; + + int next; + int prev; + + union + { + float f; + double d; + } convert; + + struct + { + unsigned int converted : 1; + unsigned int is_float : 1; + } flags; +}; +struct _Eet_Dictionary +{ + Eet_String *all; + + int size; + int offset; + + int hash[256]; + + int count; + int total; + + const char *start; + const char *end; +}; + +Eet_Dictionary *eet_dictionary_add(void); +void eet_dictionary_free(Eet_Dictionary *ed); +int eet_dictionary_string_add(Eet_Dictionary *ed, const char *string); +int eet_dictionary_string_get_size(const Eet_Dictionary *ed, int index); +const char *eet_dictionary_string_get_char(const Eet_Dictionary *ed, int index); +int eet_dictionary_string_get_float(const Eet_Dictionary *ed, int index, float *result); +int eet_dictionary_string_get_double(const Eet_Dictionary *ed, int index, double *result); +int eet_dictionary_string_get_hash(const Eet_Dictionary *ed, int index); + +FILE *_eet_memfile_read_open(const void *data, size_t size); +void _eet_memfile_read_close(FILE *f); +FILE *_eet_memfile_write_open(void **data, size_t *size); +void _eet_memfile_write_close(FILE *f); +void _eet_memfile_shutdown(void); +int _eet_hash_gen(const char *key, int hash_size); +int _eet_string_to_double_convert(const char *src, long long *m, long *e); +void _eet_double_to_string_convert(char des[128], double d); + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#ifdef DNDEBUG +#define EET_ASSERT(Test, Do) if (Test == 0) Do; +#else +#define EET_ASSERT(Test, Do) if (Test == 0) abort(); +#endif + +#endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am new file mode 100644 index 0000000..4141f7a --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,33 @@ + +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +@EVIL_CFLAGS@ \ +@COVERAGE_CFLAGS@ + +include_HEADERS = Eet.h + +lib_LTLIBRARIES = libeet.la + +libeet_la_SOURCES = \ +eet_lib.c \ +eet_data.c \ +eet_image.c \ +eet_memfile.c \ +eet_dictionary.c \ +eet_utils.c + +libeet_la_CFLAGS = @WIN32_CFLAGS@ +libeet_la_LIBADD = @COVERAGE_LIBS@ @EVIL_LIBS@ @WIN32_LIBS@ -lz -ljpeg @fnmatch_libs@ -lm +libeet_la_LDFLAGS = @lt_no_undefined@ @lt_enable_auto_import@ -version-info @version_info@ +libeet_la_DEPENDENCIES = $(top_builddir)/config.h + +EXTRA_DIST = Eet_private.h + +clean-local: + @rm -rf *.gcno diff --git a/src/lib/eet_data.c b/src/lib/eet_data.c new file mode 100644 index 0000000..f15f923 --- /dev/null +++ b/src/lib/eet_data.c @@ -0,0 +1,2997 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if HAVE___ATTRIBUTE__ +#define __UNUSED__ __attribute__((unused)) +#else +#define __UNUSED__ +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#if defined(_WIN32) && ! defined(__CEGCC__) +# include +#endif + +#include "Eet.h" +#include "Eet_private.h" + +/* + * routines for doing data -> struct and struct -> data conversion + * + * types: + * + * basic types: + * a sequence of... + * + * char + * short + * int + * long long + * float + * double + * unsigned char + * unsigned short + * unsigned int + * unsgined long long + * string + * + * groupings: + * multiple entries ordered as... + * + * fixed size array [ of basic types ] + * variable size array [ of basic types ] + * linked list [ of basic types ] + * hash table [ of basic types ] + * + * need to provide builder/accessor funcs for: + * + * list_next + * list_append + * + * hash_foreach + * hash_add + * + */ + +/*---*/ + +typedef struct _Eet_Data_Element Eet_Data_Element; +typedef struct _Eet_Data_Basic_Type_Codec Eet_Data_Basic_Type_Codec; +typedef struct _Eet_Data_Group_Type_Codec Eet_Data_Group_Type_Codec; +typedef struct _Eet_Data_Chunk Eet_Data_Chunk; +typedef struct _Eet_Data_Stream Eet_Data_Stream; +typedef struct _Eet_Data_Descriptor_Hash Eet_Data_Descriptor_Hash; +typedef struct _Eet_Data_Encode_Hash_Info Eet_Data_Encode_Hash_Info; + +/*---*/ + +/* TODO: + * Eet_Data_Basic_Type_Codec (Coder, Decoder) + * Eet_Data_Group_Type_Codec (Coder, Decoder) + */ +struct _Eet_Data_Basic_Type_Codec +{ + int size; + const char *name; + int (*get) (const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); + void *(*put) (Eet_Dictionary *ed, const void *src, int *size_ret); +}; + +struct _Eet_Data_Group_Type_Codec +{ + int (*get) (const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data_in, int level, void (*dumpfunc) (void *data, const char *str), void *dumpdata, char **p, int *size); + void (*put) (Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in); +}; + +struct _Eet_Data_Chunk +{ + char *name; + int len; + int size; + int hash; + void *data; + unsigned char type; + unsigned char group_type; +}; + +struct _Eet_Data_Stream +{ + void *data; + int size; + int pos; +}; + +struct _Eet_Data_Descriptor_Hash +{ + Eet_Data_Element *element; + Eet_Data_Descriptor_Hash *next; +}; + +struct _Eet_Data_Descriptor +{ + const char *name; + const Eet_Dictionary *ed; + int size; + struct { + void *(*mem_alloc) (size_t size); + void (*mem_free) (void *mem); + char *(*str_alloc) (const char *str); + char *(*str_direct_alloc) (const char *str); + void (*str_free) (const char *str); + void (*str_direct_free) (const char *str); + void *(*list_next) (void *l); + void *(*list_append) (void *l, void *d); + void *(*list_data) (void *l); + void *(*list_free) (void *l); + void (*hash_foreach) (void *h, int (*func) (void *h, const char *k, void *dt, void *fdt), void *fdt); + void *(*hash_add) (void *h, const char *k, void *d); + void (*hash_free) (void *h); + } func; + struct { + int num; + Eet_Data_Element *set; + struct { + int size; + Eet_Data_Descriptor_Hash *buckets; + } hash; + } elements; +// char *strings; +// int strings_len; +}; + +struct _Eet_Data_Element +{ + const char *name; + const char *counter_name; + const char *directory_name_ptr; + Eet_Data_Descriptor *subtype; + int offset; /* offset in bytes from the base element */ + int count; /* number of elements for a fixed array */ + int counter_offset; /* for a variable array we need the offset of the count variable */ + unsigned char type; /* EET_T_XXX */ + unsigned char group_type; /* EET_G_XXX */ +}; + +struct _Eet_Data_Encode_Hash_Info +{ + Eet_Data_Stream *ds; + Eet_Data_Element *ede; + Eet_Dictionary *ed; +}; + +/*---*/ + +static int eet_data_get_char(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); +static void *eet_data_put_char(Eet_Dictionary *ed, const void *src, int *size_ret); +static int eet_data_get_short(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); +static void *eet_data_put_short(Eet_Dictionary *ed, const void *src, int *size_ret); +static int eet_data_get_int(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); +static void *eet_data_put_int(Eet_Dictionary *ed, const void *src, int *size_ret); +static int eet_data_get_long_long(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); +static void *eet_data_put_long_long(Eet_Dictionary *ed, const void *src, int *size_ret); +static int eet_data_get_float(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); +static void *eet_data_put_float(Eet_Dictionary *ed, const void *src, int *size_ret); +static int eet_data_get_double(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); +static void *eet_data_put_double(Eet_Dictionary *ed, const void *src, int *size_ret); +static int eet_data_get_string(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); +static void *eet_data_put_string(Eet_Dictionary *ed, const void *src, int *size_ret); +static int eet_data_get_istring(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); +static void *eet_data_put_istring(Eet_Dictionary *ed, const void *src, int *size_ret); + +static int eet_data_get_type(const Eet_Dictionary *ed, int type, const void *src, const void *src_end, void *dest); +static void *eet_data_put_type(Eet_Dictionary *ed, int type, const void *src, int *size_ret); + +static int eet_data_get_unknown(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data_in, int level, void (*dumpfunc) (void *data, const char *str), void *dumpdata, char **p, int *size); +static void eet_data_put_unknown(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in); +static void eet_data_put_array(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in); +static int eet_data_get_array(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data, int level, void (*dumpfunc) (void *data, const char *str), void *dumpdata, char **p, int *size); +static int eet_data_get_list(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data_in, int level, void (*dumpfunc) (void *data, const char *str), void *dumpdata, char **p, int *size); +static void eet_data_put_list(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in); +static void eet_data_put_hash(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in); +static int eet_data_get_hash(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data, int level, void (*dumpfunc) (void *data, const char *str), void *dumpdata, char **p, int *size); + +static void eet_data_chunk_get(const Eet_Dictionary *ed, Eet_Data_Chunk *chnk, const void *src, int size); +static Eet_Data_Chunk *eet_data_chunk_new(void *data, int size, const char *name, int type, int group_type); +static void eet_data_chunk_free(Eet_Data_Chunk *chnk); + +static Eet_Data_Stream *eet_data_stream_new(void); +static void eet_data_stream_write(Eet_Data_Stream *ds, const void *data, int size); +static void eet_data_stream_free(Eet_Data_Stream *ds); + +static void eet_data_chunk_put(Eet_Dictionary *ed, Eet_Data_Chunk *chnk, Eet_Data_Stream *ds); + +static int eet_data_descriptor_encode_hash_cb(void *hash, const char *key, void *hdata, void *fdata); +static void *_eet_data_descriptor_encode(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, const void *data_in, int *size_ret); +static void *_eet_data_descriptor_decode(const Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + const void *data_in, + int size_in, + int level, + void (*dumpfunc) (void *data, const char *str), + void *dumpdata); + +/*---*/ + +static const Eet_Data_Basic_Type_Codec eet_basic_codec[] = +{ + {sizeof(char), "char", eet_data_get_char, eet_data_put_char }, + {sizeof(short), "short", eet_data_get_short, eet_data_put_short }, + {sizeof(int), "int", eet_data_get_int, eet_data_put_int }, + {sizeof(long long), "long_long", eet_data_get_long_long, eet_data_put_long_long}, + {sizeof(float), "float", eet_data_get_float, eet_data_put_float }, + {sizeof(double), "double", eet_data_get_double, eet_data_put_double }, + {sizeof(char), "uchar", eet_data_get_char, eet_data_put_char }, + {sizeof(short), "ushort", eet_data_get_short, eet_data_put_short }, + {sizeof(int), "uint", eet_data_get_int, eet_data_put_int }, + {sizeof(long long), "ulong_long", eet_data_get_long_long, eet_data_put_long_long}, + {sizeof(char *), "string", eet_data_get_string, eet_data_put_string }, + {sizeof(char *), "inlined", eet_data_get_istring, eet_data_put_istring } +}; + +static const Eet_Data_Group_Type_Codec eet_group_codec[] = +{ + { eet_data_get_unknown, eet_data_put_unknown }, + { eet_data_get_array, eet_data_put_array }, + { eet_data_get_array, eet_data_put_array }, + { eet_data_get_list, eet_data_put_list }, + { eet_data_get_hash, eet_data_put_hash } +}; + +static int words_bigendian = -1; + +/*---*/ + +#define SWAP64(x) (x) = \ + ((((unsigned long long)(x) & 0x00000000000000ffULL ) << 56) |\ + (((unsigned long long)(x) & 0x000000000000ff00ULL ) << 40) |\ + (((unsigned long long)(x) & 0x0000000000ff0000ULL ) << 24) |\ + (((unsigned long long)(x) & 0x00000000ff000000ULL ) << 8) |\ + (((unsigned long long)(x) & 0x000000ff00000000ULL ) >> 8) |\ + (((unsigned long long)(x) & 0x0000ff0000000000ULL ) >> 24) |\ + (((unsigned long long)(x) & 0x00ff000000000000ULL ) >> 40) |\ + (((unsigned long long)(x) & 0xff00000000000000ULL ) >> 56)) +#define SWAP32(x) (x) = \ + ((((int)(x) & 0x000000ff ) << 24) |\ + (((int)(x) & 0x0000ff00 ) << 8) |\ + (((int)(x) & 0x00ff0000 ) >> 8) |\ + (((int)(x) & 0xff000000 ) >> 24)) +#define SWAP16(x) (x) = \ + ((((short)(x) & 0x00ff ) << 8) |\ + (((short)(x) & 0xff00 ) >> 8)) + +#define CONV8(x) +#define CONV16(x) {if (words_bigendian) SWAP16(x);} +#define CONV32(x) {if (words_bigendian) SWAP32(x);} +#define CONV64(x) {if (words_bigendian) SWAP64(x);} + +#define IS_SIMPLE_TYPE(Type) (Type > EET_T_UNKNOW && Type < EET_T_LAST) + +/*---*/ + +/* CHAR TYPE */ +static int +eet_data_get_char(const Eet_Dictionary *ed __UNUSED__, const void *src, const void *src_end, void *dst) +{ + char *s, *d; + + if (((char *)src + sizeof(char)) > (char *)src_end) return -1; + s = (char *)src; + d = (char *)dst; + *d = *s; + CONV8(*d); + return sizeof(char); +} + +static void * +eet_data_put_char(Eet_Dictionary *ed __UNUSED__, const void *src, int *size_ret) +{ + char *s, *d; + + d = (char *)malloc(sizeof(char)); + if (!d) return NULL; + s = (char *)src; + *d = *s; + CONV8(*d); + *size_ret = sizeof(char); + return d; +} + +/* SHORT TYPE */ +static int +eet_data_get_short(const Eet_Dictionary *ed __UNUSED__, const void *src, const void *src_end, void *dst) +{ + short *d; + + if (((char *)src + sizeof(short)) > (char *)src_end) return -1; + memcpy(dst, src, sizeof(short)); + d = (short *)dst; + CONV16(*d); + return sizeof(short); +} + +static void * +eet_data_put_short(Eet_Dictionary *ed __UNUSED__, const void *src, int *size_ret) +{ + short *s, *d; + + d = (short *)malloc(sizeof(short)); + if (!d) return NULL; + s = (short *)src; + *d = *s; + CONV16(*d); + *size_ret = sizeof(short); + return d; +} + +/* INT TYPE */ +static int +eet_data_get_int(const Eet_Dictionary *ed __UNUSED__, const void *src, const void *src_end, void *dst) +{ + int *d; + + if (((char *)src + sizeof(int)) > (char *)src_end) return -1; + memcpy(dst, src, sizeof(int)); + d = (int *)dst; + CONV32(*d); + return sizeof(int); +} + +static void * +eet_data_put_int(Eet_Dictionary *ed __UNUSED__, const void *src, int *size_ret) +{ + int *s, *d; + + d = (int *)malloc(sizeof(int)); + if (!d) return NULL; + s = (int *)src; + *d = *s; + CONV32(*d); + *size_ret = sizeof(int); + return d; +} + +/* LONG LONG TYPE */ +static int +eet_data_get_long_long(const Eet_Dictionary *ed __UNUSED__, const void *src, const void *src_end, void *dst) +{ + unsigned long long *d; + + if (((char *)src + sizeof(unsigned long long)) > (char *)src_end) return -1; + memcpy(dst, src, sizeof(unsigned long long)); + d = (unsigned long long *)dst; + CONV64(*d); + return sizeof(unsigned long long); +} + +static void * +eet_data_put_long_long(Eet_Dictionary *ed __UNUSED__, const void *src, int *size_ret) +{ + unsigned long long *s, *d; + + d = (unsigned long long *)malloc(sizeof(unsigned long long)); + if (!d) return NULL; + s = (unsigned long long *)src; + *d = *s; + CONV64(*d); + *size_ret = sizeof(unsigned long long); + return d; +} + +/* STRING TYPE */ +static int +eet_data_get_string_hash(const Eet_Dictionary *ed, const void *src, const void *src_end) +{ + if (ed) + { + int index; + + if (eet_data_get_int(ed, src, src_end, &index) < 0) return -1; + + return eet_dictionary_string_get_hash(ed, index); + } + + return -1; +} + +static int +eet_data_get_string(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dst) +{ + char *s, **d; + + d = (char **)dst; + + if (ed) + { + const char *str; + int index; + + if (eet_data_get_int(ed, src, src_end, &index) < 0) return -1; + + str = eet_dictionary_string_get_char(ed, index); + if (str == NULL) + return -1; + + *d = (char *) str; + return eet_dictionary_string_get_size(ed, index); + } + + s = (char *)src; + if (s == NULL) + { + *d = NULL; + return 0; + } + + *d = s; + return strlen(s) + 1; +} + +static void * +eet_data_put_string(Eet_Dictionary *ed, const void *src, int *size_ret) +{ + char *s, *d; + int len; + + if (ed) + { + const char *str; + int index; + + str = *((const char **) src); + if (!str) return NULL; + + index = eet_dictionary_string_add(ed, str); + if (index == -1) return NULL; + + return eet_data_put_int(ed, &index, size_ret); + } + + s = (char *)(*((char **)src)); + if (!s) return NULL; + len = strlen(s); + d = malloc(len + 1); + if (!d) return NULL; + memcpy(d, s, len + 1); + *size_ret = len + 1; + return d; +} + +/* ALWAYS INLINED STRING TYPE */ +static int +eet_data_get_istring(const Eet_Dictionary *ed __UNUSED__, const void *src, const void *src_end, void *dst) +{ + return eet_data_get_string(NULL, src, src_end, dst); +} + +static void * +eet_data_put_istring(Eet_Dictionary *ed __UNUSED__, const void *src, int *size_ret) +{ + return eet_data_put_string(NULL, src, size_ret); +} + +/** + * Fast lookups of simple doubles/floats. + * + * These aren't properly a cache because they don't store pre-calculated + * values, but have a so simple math that is almost as fast. + */ +static inline int +_eet_data_float_cache_get(const char *s, int len, float *d) +{ + /* fast handle of simple case 0xMp+E*/ + if ((len == 6) && (s[0] == '0') && (s[1] == 'x') && (s[3] == 'p')) + { + int mantisse = (s[2] >= 'a') ? (s[2] - 'a' + 10) : (s[2] - '0'); + int exponent = (s[5] - '0'); + + if (s[4] == '+') *d = (float)(mantisse << exponent); + else *d = (float)mantisse / (float)(1 << exponent); + + return 1; + } + return 0; +} + +static inline int +_eet_data_double_cache_get(const char *s, int len, double *d) +{ + /* fast handle of simple case 0xMp+E*/ + if ((len == 6) && (s[0] == '0') && (s[1] == 'x') && (s[3] == 'p')) + { + int mantisse = (s[2] >= 'a') ? (s[2] - 'a' + 10) : (s[2] - '0'); + int exponent = (s[5] - '0'); + + if (s[4] == '+') *d = (double)(mantisse << exponent); + else *d = (double)mantisse / (double)(1 << exponent); + + return 1; + } + return 0; +} + +/* FLOAT TYPE */ +static int +eet_data_get_float(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dst) +{ + float *d; + int index; + + d = (float *) dst; + if (!ed) + { + const char *s, *p; + long long mantisse; + long exponent; + int len; + + s = (const char *)src; + p = s; + len = 0; + while ((p < (const char *)src_end) && (*p != 0)) {len++; p++;} + + if (_eet_data_float_cache_get(s, len, d) != 0) return len + 1; + + _eet_string_to_double_convert(s, &mantisse, &exponent); + *d = (float)ldexp((double)mantisse, exponent); + + return len + 1; + } + + if (eet_data_get_int(ed, src, src_end, &index) < 0) return -1; + + if (!eet_dictionary_string_get_float(ed, index, d)) + return -1; + return 1; +} + +static void * +eet_data_put_float(Eet_Dictionary *ed, const void *src, int *size_ret) +{ + char buf[128]; + int index; + + _eet_double_to_string_convert(buf, (double)(*(float *)src)); + + if (!ed) + { + char *d; + int len; + + len = strlen(buf); + d = malloc(len + 1); + if (!d) return NULL; + memcpy(d, buf, len + 1); + *size_ret = len + 1; + return d; + } + + index = eet_dictionary_string_add(ed, buf); + if (index == -1) return NULL; + + return eet_data_put_int(ed, &index, size_ret); +} + +/* DOUBLE TYPE */ +static int +eet_data_get_double(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dst) +{ + double *d; + int index; + + d = (double *) dst; + + if (!ed) + { + const char *s, *p; + long long mantisse = 0; + long exponent = 0; + int len; + + s = (const char *) src; + p = s; + len = 0; + while ((p < (const char *)src_end) && (*p != 0)) {len++; p++;} + + if (_eet_data_double_cache_get(s, len, d) != 0) return len + 1; + + _eet_string_to_double_convert(s, &mantisse, &exponent); + *d = ldexp((double) mantisse, exponent); + + return len + 1; + } + + if (eet_data_get_int(ed, src, src_end, &index) < 0) return -1; + + if (!eet_dictionary_string_get_double(ed, index, d)) + return -1; + return 1; +} + +static void * +eet_data_put_double(Eet_Dictionary *ed, const void *src, int *size_ret) +{ + char buf[128]; + int index; + + _eet_double_to_string_convert(buf, (double)(*(double *)src)); + + if (!ed) + { + char *d; + int len; + + len = strlen(buf); + d = malloc(len + 1); + if (!d) return NULL; + memcpy(d, buf, len + 1); + *size_ret = len + 1; + + return d; + } + + index = eet_dictionary_string_add(ed, buf); + if (index == -1) return NULL; + + return eet_data_put_int(ed, &index, size_ret); +} + +static int +eet_data_get_type(const Eet_Dictionary *ed, int type, const void *src, const void *src_end, void *dest) +{ + int ret; + + ret = eet_basic_codec[type - 1].get(ed, src, src_end, dest); + return ret; +} + +static void * +eet_data_put_type(Eet_Dictionary *ed, int type, const void *src, int *size_ret) +{ + void *ret; + + ret = eet_basic_codec[type - 1].put(ed, src, size_ret); + return ret; +} + +/* chunk format... + * + * char[4] = "CHnK"; // untyped data ... or + * char[4] = "CHKx"; // typed data - x == type + * + * int = chunk size (including magic string); + * char[] = chunk magic/name string (0 byte terminated); + * ... sub-chunks (a chunk can contain chuncks recusrively) ... + * or + * ... payload data ... + * + */ + +static void +eet_data_chunk_get(const Eet_Dictionary *ed, Eet_Data_Chunk *chnk, + const void *src, int size) +{ + const char *s; + int ret1, ret2; + + if (!src) return; + if (size <= 8) return; + + if (!chnk) return; + + s = src; + if (s[2] == 'K') + { + if ((s[0] != 'C') || (s[1] != 'H') || (s[2] != 'K')) + { + return; + } + chnk->type = (unsigned char)(s[3]); + if (chnk->type > EET_T_LAST) + { + chnk->group_type = chnk->type; + chnk->type = EET_T_UNKNOW; + } + else + chnk->group_type = EET_G_UNKNOWN; + if ((chnk->type >= EET_T_LAST) || + (chnk->group_type >= EET_G_LAST)) + { + chnk->type = 0; + chnk->group_type = 0; + } + } + else + { + if ((s[0] != 'C') || (s[1] != 'H') || (s[2] != 'n') || (s[3] != 'K')) + { + return; + } + } + ret1 = eet_data_get_type(ed, EET_T_INT, (s + 4), (s + size), &(chnk->size)); + if (ret1 <= 0) + { + return; + } + if ((chnk->size < 0) || ((chnk->size + 8) > size)) + { + return; + } + ret2 = eet_data_get_type(ed, EET_T_STRING, (s + 8), (s + size), &(chnk->name)); + if (ret2 <= 0) + { + return; + } + + chnk->len = ret2; + + /* Precalc hash */ + chnk->hash = eet_data_get_string_hash(ed, (s + 8), (s + size)); + + if (ed) + { + chnk->data = (char *)src + 4 + ret1 + sizeof(int); + chnk->size -= sizeof(int); + } + else + { + chnk->data = (char *)src + 4 + ret1 + chnk->len; + chnk->size -= chnk->len; + } + + return; +} + +static Eet_Data_Chunk * +eet_data_chunk_new(void *data, int size, const char *name, int type, int group_type) +{ + Eet_Data_Chunk *chnk; + + if (!name) return NULL; + chnk = calloc(1, sizeof(Eet_Data_Chunk)); + if (!chnk) return NULL; + + chnk->name = strdup(name); + chnk->len = strlen(name) + 1; + chnk->size = size; + chnk->data = data; + chnk->type = type; + chnk->group_type = group_type; + return chnk; +} + +static void +eet_data_chunk_free(Eet_Data_Chunk *chnk) +{ + if (chnk->name) free(chnk->name); + free(chnk); +} + +static Eet_Data_Stream * +eet_data_stream_new(void) +{ + Eet_Data_Stream *ds; + + ds = calloc(1, sizeof(Eet_Data_Stream)); + if (!ds) return NULL; + return ds; +} + +static void +eet_data_stream_free(Eet_Data_Stream *ds) +{ + if (ds->data) free(ds->data); + free(ds); +} + +static void +eet_data_stream_write(Eet_Data_Stream *ds, const void *data, int size) +{ + char *p; + + if ((ds->pos + size) > ds->size) + { + ds->data = realloc(ds->data, ds->size + size + 512); + if (!ds->data) + { + ds->pos = 0; + ds->size = 0; + return; + } + ds->size = ds->size + size + 512; + } + p = ds->data; + memcpy(p + ds->pos, data, size); + ds->pos += size; +} + +static void +eet_data_chunk_put(Eet_Dictionary *ed, Eet_Data_Chunk *chnk, Eet_Data_Stream *ds) +{ + int *size; + void *string; + int s; + int size_ret = 0; + int string_ret = 0; + unsigned char buf[4] = "CHK"; + + if (!chnk->data) return; + /* chunk head */ + +/* eet_data_stream_write(ds, "CHnK", 4);*/ + if (chnk->type != EET_T_UNKNOW) buf[3] = chnk->type; + else buf[3] = chnk->group_type; + + string = eet_data_put_string(ed, &chnk->name, &string_ret); + if (!string) + return ; + + /* size of chunk payload data + name */ + s = chnk->size + string_ret; + size = eet_data_put_int(ed, &s, &size_ret); + + /* FIXME: If something goes wrong the resulting file will be corrupted. */ + if (!size) + goto on_error; + + eet_data_stream_write(ds, buf, 4); + + /* write chunk length */ + eet_data_stream_write(ds, size, size_ret); + + /* write chunk name */ + eet_data_stream_write(ds, string, string_ret); + + /* write payload */ + eet_data_stream_write(ds, chnk->data, chnk->size); + + free(string); + on_error: + free(size); +} + +/*---*/ + +static void +_eet_descriptor_hash_new(Eet_Data_Descriptor *edd) +{ + int i; + + edd->elements.hash.size = 1 << 6; + edd->elements.hash.buckets = calloc(1, sizeof(Eet_Data_Descriptor_Hash) * edd->elements.hash.size); + for (i = 0; i < edd->elements.num; i++) + { + Eet_Data_Element *ede; + int hash; + + ede = &(edd->elements.set[i]); + hash = _eet_hash_gen((char *) ede->name, 6); + if (!edd->elements.hash.buckets[hash].element) + edd->elements.hash.buckets[hash].element = ede; + else + { + Eet_Data_Descriptor_Hash *bucket; + + bucket = calloc(1, sizeof(Eet_Data_Descriptor_Hash)); + bucket->element = ede; + bucket->next = edd->elements.hash.buckets[hash].next; + edd->elements.hash.buckets[hash].next = bucket; + } + } +} + +static void +_eet_descriptor_hash_free(Eet_Data_Descriptor *edd) +{ + int i; + + for (i = 0; i < edd->elements.hash.size; i++) + { + Eet_Data_Descriptor_Hash *bucket, *pbucket; + + bucket = edd->elements.hash.buckets[i].next; + while (bucket) + { + pbucket = bucket; + bucket = bucket->next; + free(pbucket); + } + } + if (edd->elements.hash.buckets) free(edd->elements.hash.buckets); +} + +static Eet_Data_Element * +_eet_descriptor_hash_find(Eet_Data_Descriptor *edd, char *name, int hash) +{ + Eet_Data_Descriptor_Hash *bucket; + + if (hash < 0) hash = _eet_hash_gen(name, 6); + else hash &= 0x3f; + if (!edd->elements.hash.buckets[hash].element) return NULL; + /* + When we use the dictionnary as a source for chunk name, we will always + have the same pointer in name. It's a good idea to just compare pointer + instead of running strcmp on both string. + */ + if (edd->elements.hash.buckets[hash].element->directory_name_ptr == name) + return edd->elements.hash.buckets[hash].element; + if (!strcmp(edd->elements.hash.buckets[hash].element->name, name)) + { + edd->elements.hash.buckets[hash].element->directory_name_ptr = name; + return edd->elements.hash.buckets[hash].element; + } + bucket = edd->elements.hash.buckets[hash].next; + while (bucket) + { + if (bucket->element->directory_name_ptr == name) return bucket->element; + if (!strcmp(bucket->element->name, name)) + { + bucket->element->directory_name_ptr = name; + return bucket->element; + } + bucket = bucket->next; + } + return NULL; +} + +static void * +_eet_mem_alloc(size_t size) +{ + return calloc(1, size); +} + +static void +_eet_mem_free(void *mem) +{ + free(mem); +} + +static char * +_eet_str_alloc(const char *str) +{ + return strdup(str); +} + +static void +_eet_str_free(const char *str) +{ + free((char *)str); +} + +/*---*/ + +EAPI Eet_Data_Descriptor * +eet_data_descriptor_new(const char *name, + int size, + void *(*func_list_next) (void *l), + void *(*func_list_append) (void *l, void *d), + void *(*func_list_data) (void *l), + void *(*func_list_free) (void *l), + void (*func_hash_foreach) (void *h, int (*func) (void *h, const char *k, void *dt, void *fdt), void *fdt), + void *(*func_hash_add) (void *h, const char *k, void *d), + void (*func_hash_free) (void *h)) +{ + Eet_Data_Descriptor *edd; + + if (!name) return NULL; + edd = calloc(1, sizeof(Eet_Data_Descriptor)); + if (!edd) return NULL; + + edd->name = name; + edd->ed = NULL; + edd->size = size; + edd->func.mem_alloc = _eet_mem_alloc; + edd->func.mem_free = _eet_mem_free; + edd->func.str_alloc = _eet_str_alloc; + edd->func.str_direct_alloc = NULL; + edd->func.str_direct_free = NULL; + edd->func.str_free = _eet_str_free; + edd->func.list_next = func_list_next; + edd->func.list_append = func_list_append; + edd->func.list_data = func_list_data; + edd->func.list_free = func_list_free; + edd->func.hash_foreach = func_hash_foreach; + edd->func.hash_add = func_hash_add; + edd->func.hash_free = func_hash_free; + return edd; +} + +/* new replcement */ +EAPI Eet_Data_Descriptor * +eet_data_descriptor2_new(Eet_Data_Descriptor_Class *eddc) +{ + Eet_Data_Descriptor *edd; + + if (!eddc) return NULL; + if (eddc->version < 1) return NULL; + edd = calloc(1, sizeof(Eet_Data_Descriptor)); + if (!edd) return NULL; + + edd->name = eddc->name; + edd->ed = NULL; + edd->size = eddc->size; + edd->func.mem_alloc = _eet_mem_alloc; + edd->func.mem_free = _eet_mem_free; + edd->func.str_alloc = _eet_str_alloc; + edd->func.str_free = _eet_str_free; + if (eddc->func.mem_alloc) + edd->func.mem_alloc = eddc->func.mem_alloc; + if (eddc->func.mem_free) + edd->func.mem_free = eddc->func.mem_free; + if (eddc->func.str_alloc) + edd->func.str_alloc = eddc->func.str_alloc; + if (eddc->func.str_free) + edd->func.str_free = eddc->func.str_free; + edd->func.list_next = eddc->func.list_next; + edd->func.list_append = eddc->func.list_append; + edd->func.list_data = eddc->func.list_data; + edd->func.list_free = eddc->func.list_free; + edd->func.hash_foreach = eddc->func.hash_foreach; + edd->func.hash_add = eddc->func.hash_add; + edd->func.hash_free = eddc->func.hash_free; + + return edd; +} + +EAPI Eet_Data_Descriptor * +eet_data_descriptor3_new(Eet_Data_Descriptor_Class *eddc) +{ + Eet_Data_Descriptor *edd; + + if (!eddc) return NULL; + if (eddc->version < 2) return NULL; + edd = calloc(1, sizeof(Eet_Data_Descriptor)); + if (!edd) return NULL; + + edd->name = eddc->name; + edd->ed = NULL; + edd->size = eddc->size; + edd->func.mem_alloc = _eet_mem_alloc; + edd->func.mem_free = _eet_mem_free; + edd->func.str_alloc = _eet_str_alloc; + edd->func.str_free = _eet_str_free; + if (eddc->func.mem_alloc) + edd->func.mem_alloc = eddc->func.mem_alloc; + if (eddc->func.mem_free) + edd->func.mem_free = eddc->func.mem_free; + if (eddc->func.str_alloc) + edd->func.str_alloc = eddc->func.str_alloc; + if (eddc->func.str_free) + edd->func.str_free = eddc->func.str_free; + edd->func.list_next = eddc->func.list_next; + edd->func.list_append = eddc->func.list_append; + edd->func.list_data = eddc->func.list_data; + edd->func.list_free = eddc->func.list_free; + edd->func.hash_foreach = eddc->func.hash_foreach; + edd->func.hash_add = eddc->func.hash_add; + edd->func.hash_free = eddc->func.hash_free; + edd->func.str_direct_alloc = eddc->func.str_direct_alloc; + edd->func.str_direct_free = eddc->func.str_direct_free; + + return edd; +} + +EAPI void +eet_data_descriptor_free(Eet_Data_Descriptor *edd) +{ + _eet_descriptor_hash_free(edd); + if (edd->elements.set) free(edd->elements.set); + free(edd); +} + +EAPI void +eet_data_descriptor_element_add(Eet_Data_Descriptor *edd, + const char *name, + int type, + int group_type, + int offset, + int count, +/* int counter_offset, */ + const char *counter_name /* Useless should go on a major release */, + Eet_Data_Descriptor *subtype) +{ + Eet_Data_Element *ede; + /* int l1, l2, p1, p2, i; + char *ps;*/ + + /* FIXME: Fail safely when realloc fail. */ + edd->elements.num++; + edd->elements.set = realloc(edd->elements.set, edd->elements.num * sizeof(Eet_Data_Element)); + if (!edd->elements.set) return; + ede = &(edd->elements.set[edd->elements.num - 1]); + ede->name = name; + ede->directory_name_ptr = NULL; + + /* + * We do a special case when we do list,hash or whatever group of simple type. + * Instead of handling it in encode/decode/dump/undump, we create an + * implicit structure with only the simple type. + */ + if (group_type > EET_G_UNKNOWN + && group_type < EET_G_LAST + && type != EET_T_UNKNOW + && subtype == NULL) + { + subtype = calloc(1, sizeof (Eet_Data_Descriptor)); + if (!subtype) return ; + subtype->name = "implicit"; + subtype->size = eet_basic_codec[type - 1].size; + memcpy(&subtype->func, &edd->func, sizeof(subtype->func)); + + eet_data_descriptor_element_add(subtype, eet_basic_codec[type - 1].name, type, + EET_G_UNKNOWN, 0, 0, /* 0, */NULL, NULL); + type = EET_T_UNKNOW; + } + + ede->type = type; + ede->group_type = group_type; + ede->offset = offset; + ede->count = count; + /* FIXME: For the time being, EET_G_VAR_ARRAY will put the counter_offset in count. */ + ede->counter_offset = count; +/* ede->counter_offset = counter_offset; */ + ede->counter_name = counter_name; + + ede->subtype = subtype; +} + +EAPI void * +eet_data_read(Eet_File *ef, Eet_Data_Descriptor *edd, const char *name) +{ + const Eet_Dictionary *ed = NULL; + const void *data; + void *data_dec; + int size; + int required_free = 0; + + ed = eet_dictionary_get(ef); + + data = eet_read_direct(ef, name, &size); + if (!data) + { + required_free = 1; + data = eet_read(ef, name, &size); + if (!data) return NULL; + } + + data_dec = _eet_data_descriptor_decode(ed, edd, data, size, 0, NULL, NULL); + if (required_free) + free((void*)data); + + return data_dec; +} + +EAPI int +eet_data_write(Eet_File *ef, Eet_Data_Descriptor *edd, const char *name, const void *data, int compress) +{ + Eet_Dictionary *ed; + void *data_enc; + int size; + int val; + + ed = eet_dictionary_get(ef); + + data_enc = _eet_data_descriptor_encode(ed, edd, data, &size); + if (!data_enc) return 0; + val = eet_write(ef, name, data_enc, size, compress); + free(data_enc); + return val; +} + +typedef struct _Eet_Free Eet_Free; +struct _Eet_Free +{ + int ref; + int len[256]; + int num[256]; + void **list[256]; +}; + +static int +_eet_free_hash(void *data) +{ + unsigned long ptr = (unsigned long)(data); + int hash; + + hash = ptr; + hash ^= ptr >> 8; + hash ^= ptr >> 16; + hash ^= ptr >> 24; + +#if LONG_BIT != 32 + hash ^= ptr >> 32; + hash ^= ptr >> 40; + hash ^= ptr >> 48; + hash ^= ptr >> 56; +#endif + + return hash & 0xFF; +} + +static void +_eet_free_add(Eet_Free *ef, void *data) +{ + int hash; + int i; + + hash = _eet_free_hash(data); + + for (i = 0; i < ef->num[hash]; ++i) + if (ef->list[hash][i] == data) return; + + ef->num[hash]++; + if (ef->num[hash] > ef->len[hash]) + { + void **tmp; + + tmp = realloc(ef->list[hash], (ef->len[hash] + 16) * sizeof(void*)); + if (!tmp) return ; + + ef->len[hash] += 16; + ef->list[hash] = tmp; + } + ef->list[hash][ef->num[hash] - 1] = data; +} +static void +_eet_free_reset(Eet_Free *ef) +{ + int i; + + if (ef->ref > 0) return ; + for (i = 0; i < 256; ++i) + { + ef->len[i] = 0; + ef->num[i] = 0; + if (ef->list[i]) free(ef->list[i]); + ef->list[i] = NULL; + } +} +static void +_eet_free_ref(Eet_Free *ef) +{ + ef->ref++; +} +static void +_eet_free_unref(Eet_Free *ef) +{ + ef->ref--; +} + +static Eet_Free freelist = { 0, { 0 }, { 0 }, { NULL } }; + +#define _eet_freelist_add(Data) _eet_free_add(&freelist, Data); +#define _eet_freelist_reset() _eet_free_reset(&freelist); +#define _eet_freelist_ref() _eet_free_ref(&freelist); +#define _eet_freelist_unref() _eet_free_unref(&freelist); + +static void +_eet_freelist_free(Eet_Data_Descriptor *edd) +{ + int j; + int i; + + if (freelist.ref > 0) return; + for (j = 0; j < 256; ++j) + for (i = 0; i < freelist.num[j]; ++i) + { + if (edd) + edd->func.mem_free(freelist.list[j][i]); + else + free(freelist.list[j][i]); + } + _eet_free_reset(&freelist); +} + +static Eet_Free freelist_list = { 0, { 0 }, { 0 }, { NULL } }; + +#define _eet_freelist_list_add(Data) _eet_free_add(&freelist_list, Data); +#define _eet_freelist_list_reset() _eet_free_reset(&freelist_list); +#define _eet_freelist_list_ref() _eet_free_ref(&freelist_list); +#define _eet_freelist_list_unref() _eet_free_unref(&freelist_list); + +static void +_eet_freelist_list_free(Eet_Data_Descriptor *edd) +{ + int j; + int i; + + if (freelist_list.ref > 0) return; + for (j = 0; j < 256; ++j) + for (i = 0; i < freelist_list.num[j]; ++i) + { + if (edd) + edd->func.list_free(*((void**)(freelist_list.list[j][i]))); + } + _eet_free_reset(&freelist_list); +} + +static Eet_Free freelist_str = { 0, { 0 }, { 0 }, { NULL } }; + +#define _eet_freelist_str_add(Data) _eet_free_add(&freelist_str, Data); +#define _eet_freelist_str_reset() _eet_free_reset(&freelist_str); +#define _eet_freelist_str_ref() _eet_free_ref(&freelist_str); +#define _eet_freelist_str_unref() _eet_free_unref(&freelist_str); + +static void +_eet_freelist_str_free(Eet_Data_Descriptor *edd) +{ + int j; + int i; + + if (freelist_str.ref > 0) return; + for (j = 0; j < 256; ++j) + for (i = 0; i < freelist_str.num[j]; ++i) + { + if (edd) + edd->func.str_free(freelist_str.list[j][i]); + else + free(freelist_str.list[j][i]); + } + _eet_free_reset(&freelist_str); +} + +static Eet_Free freelist_direct_str = { 0, { 0 }, { 0 }, { NULL } }; + +#define _eet_freelist_direct_str_add(Data) _eet_free_add(&freelist_direct_str, Data); +#define _eet_freelist_direct_str_reset() _eet_free_reset(&freelist_direct_str); +#define _eet_freelist_direct_str_ref() _eet_free_ref(&freelist_direct_str); +#define _eet_freelist_direct_str_unref() _eet_free_unref(&freelist_direct_str); + +static void +_eet_freelist_direct_str_free(Eet_Data_Descriptor *edd) +{ + int j; + int i; + + if (freelist_str.ref > 0) return; + for (j = 0; j < 256; ++j) + for (i = 0; i < freelist_str.num[j]; ++i) + { + if (edd) + edd->func.str_direct_free(freelist_str.list[j][i]); + else + free(freelist_str.list[j][i]); + } + _eet_free_reset(&freelist_str); +} + +static int +eet_data_descriptor_encode_hash_cb(void *hash __UNUSED__, const char *key, void *hdata, void *fdata) +{ + Eet_Dictionary *ed; + Eet_Data_Encode_Hash_Info *edehi; + Eet_Data_Stream *ds; + Eet_Data_Element *ede; + Eet_Data_Chunk *echnk; + void *data = NULL; + int size; + + edehi = fdata; + ede = edehi->ede; + ds = edehi->ds; + ed = edehi->ed; + + /* Store key */ + data = eet_data_put_type(ed, + EET_T_STRING, + &key, + &size); + if (data) + { + echnk = eet_data_chunk_new(data, size, ede->name, ede->type, ede->group_type); + eet_data_chunk_put(ed, echnk, ds); + eet_data_chunk_free(echnk); + free(data); + data = NULL; + } + + EET_ASSERT(!IS_SIMPLE_TYPE(ede->type), return 1); + + /* Store data */ + if (ede->subtype) + data = _eet_data_descriptor_encode(ed, + ede->subtype, + hdata, + &size); + if (data) + { + echnk = eet_data_chunk_new(data, size, ede->name, ede->type, ede->group_type); + eet_data_chunk_put(ed, echnk, ds); + eet_data_chunk_free(echnk); + free(data); + data = NULL; + } + return 1; +} + +static char * +_eet_data_string_escape(const char *str) +{ + char *s, *sp; + const char *strp; + int sz = 0; + + for (strp = str; *strp; strp++) + { + if (*strp == '\"') sz += 2; + else if (*strp == '\\') sz += 2; + else sz += 1; + } + s = malloc(sz + 1); + if (!s) return NULL; + for (strp = str, sp = s; *strp; strp++, sp++) + { + if (*strp == '\"') + { + *sp = '\\'; + sp++; + } + else if (*strp == '\\') + { + *sp = '\\'; + sp++; + } + *sp = *strp; + } + *sp = 0; + return s; +} + +static void +_eet_data_dump_string_escape(void *dumpdata, void dumpfunc(void *data, const char *str), const char *str) +{ + char *s; + + s = _eet_data_string_escape(str); + if (s) + { + dumpfunc(dumpdata, s); + free(s); + } +} + +static char * +_eet_data_dump_token_get(const char *src, int *len) +{ + const char *p; + char *tok = NULL; + int in_token = 0; + int in_quote = 0; + int tlen = 0, tsize = 0; + +#define TOK_ADD(x) \ + { \ + tlen++; \ + if (tlen >= tsize) \ + { \ + tsize += 32; \ + tok = realloc(tok, tsize); \ + } \ + tok[tlen - 1] = x; \ + } + + for (p = src; *len > 0; p++, (*len)--) + { + if (in_token) + { + if (in_quote) + { + if ((p[0] == '\"') && (p > src) && (p[-1] != '\\')) + { + in_quote = 0; + } + else if ((p[0] == '\\') && (*len > 1) && (p[1] == '\"')) + { + /* skip */ + } + else if ((p[0] == '\\') && (p > src) && (p[-1] == '\\')) + { + /* skip */ + } + else + TOK_ADD(p[0]); + } + else + { + if (p[0] == '\"') in_quote = 1; + else + { + if ((isspace(p[0])) || (p[0] == ';')) /* token ends here */ + { + TOK_ADD(0); + (*len)--; + return tok; + } + else + TOK_ADD(p[0]); + } + } + } + else + { + if (!((isspace(p[0])) || (p[0] == ';'))) + { + in_token = 1; + (*len)++; + p--; + } + } + } + if (in_token) + { + TOK_ADD(0); + return tok; + } + if (tok) free(tok); + return NULL; +} + +typedef struct _Node Node; + +struct _Node +{ + int type; + int count; + char *name; + char *key; + Node *values; + Node *prev; + Node *next; + Node *parent; + union { + char c; + short s; + int i; + long long l; + float f; + double d; + unsigned char uc; + unsigned short us; + unsigned int ui; + unsigned long long ul; + char *str; + } data; +}; + +static void +_eet_data_dump_free(Node *node) +{ + Node *n, *n2; + + switch (node->type) + { + case EET_G_UNKNOWN: + case EET_G_ARRAY: + case EET_G_VAR_ARRAY: + case EET_G_LIST: + case EET_G_HASH: + if (node->key) free(node->key); + for (n = node->values; n;) + { + n2 = n; + n = n->next; + _eet_data_dump_free(n2); + } + break; + case EET_T_CHAR: + case EET_T_SHORT: + case EET_T_INT: + case EET_T_LONG_LONG: + case EET_T_FLOAT: + case EET_T_DOUBLE: + case EET_T_UCHAR: + case EET_T_USHORT: + case EET_T_UINT: + case EET_T_ULONG_LONG: + break; + case EET_T_INLINED_STRING: + case EET_T_STRING: + if (node->data.str) free(node->data.str); + break; + default: + break; + } + free(node); +} + +static void * +_eet_data_dump_encode(Eet_Dictionary *ed, + Node *node, + int *size_ret) +{ + Eet_Data_Chunk *chnk = NULL, *echnk = NULL; + Eet_Data_Stream *ds; + void *cdata, *data; + int csize, size; + Node *n; + + if (words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) words_bigendian = 1; + else words_bigendian = 0; + } + + ds = eet_data_stream_new(); + if (!ds) return NULL; + + switch (node->type) + { + case EET_G_UNKNOWN: + for (n = node->values; n; n = n->next) + { + data = _eet_data_dump_encode(ed, n, &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + } + break; + case EET_G_ARRAY: + case EET_G_VAR_ARRAY: + data = eet_data_put_type(ed, + EET_T_INT, + &node->count, + &size); + if (data) + { + echnk = eet_data_chunk_new(data, size, node->name, node->type, node->type); + eet_data_chunk_put(ed, echnk, ds); + eet_data_chunk_free(echnk); + free(data); + } + for (n = node->values; n; n = n->next) + { + data = _eet_data_dump_encode(ed, n, &size); + if (data) + { + echnk = eet_data_chunk_new(data, size, node->name, node->type, node->type); + eet_data_chunk_put(ed, echnk, ds); + eet_data_chunk_free(echnk); + free(data); + } + } + + /* Array is somekind of special case, so we should embed it inside another chunk. */ + *size_ret = ds->pos; + cdata = ds->data; + + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + + return cdata; + case EET_G_LIST: + for (n = node->values; n; n = n->next) + { + data = _eet_data_dump_encode(ed, n, &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + } + break; + case EET_G_HASH: + if (node->key) + { + data = eet_data_put_type(ed, + EET_T_STRING, + &node->key, + &size); + if (data) + { + echnk = eet_data_chunk_new(data, size, node->name, node->type, node->type); + eet_data_chunk_put(ed, echnk, ds); + eet_data_chunk_free(echnk); + free(data); + } + } + for (n = node->values; n; n = n->next) + { + data = _eet_data_dump_encode(ed, n, &size); + if (data) + { + echnk = eet_data_chunk_new(data, size, node->name, node->type, node->type); + eet_data_chunk_put(ed, echnk, ds); + eet_data_chunk_free(echnk); + free(data); + } + } + + /* Hash is somekind of special case, so we should embed it inside another chunk. */ + *size_ret = ds->pos; + cdata = ds->data; + + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + + return cdata; + case EET_T_CHAR: + data = eet_data_put_type(ed, node->type, &(node->data.c), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_SHORT: + data = eet_data_put_type(ed, node->type, &(node->data.s), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_INT: + data = eet_data_put_type(ed, node->type, &(node->data.i), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_LONG_LONG: + data = eet_data_put_type(ed, node->type, &(node->data.l), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_FLOAT: + data = eet_data_put_type(ed, node->type, &(node->data.f), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_DOUBLE: + data = eet_data_put_type(ed, node->type, &(node->data.d), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_UCHAR: + data = eet_data_put_type(ed, node->type, &(node->data.uc), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_USHORT: + data = eet_data_put_type(ed, node->type, &(node->data.us), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_UINT: + data = eet_data_put_type(ed, node->type, &(node->data.ui), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_ULONG_LONG: + data = eet_data_put_type(ed, node->type, &(node->data.ul), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_INLINED_STRING: + data = eet_data_put_type(ed, node->type, &(node->data.str), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + case EET_T_STRING: + data = eet_data_put_type(ed, node->type, &(node->data.str), &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + break; + default: + break; + } + + if ((node->type >= EET_G_UNKNOWN) && (node->type < EET_G_LAST)) + chnk = eet_data_chunk_new(ds->data, ds->pos, node->name, EET_T_UNKNOW, node->type); + else + chnk = eet_data_chunk_new(ds->data, ds->pos, node->name, node->type, EET_G_UNKNOWN); + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + + ds = eet_data_stream_new(); + eet_data_chunk_put(ed, chnk, ds); + cdata = ds->data; + csize = ds->pos; + + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + *size_ret = csize; + + free(chnk->data); + eet_data_chunk_free(chnk); + + return cdata; +} + +static void * +_eet_data_dump_parse(Eet_Dictionary *ed, + int *size_ret, + const char *src, + int size) +{ + void *cdata = NULL; + const char *p; +#define M_NONE 0 +#define M_STRUCT 1 +#define M_ 2 + int left, jump; + Node *node_base = NULL; + Node *node = NULL; + Node *n, *nn; + + /* FIXME; handle parse errors */ +#define TOK_GET(t) \ + jump = left; t = _eet_data_dump_token_get(p, &left); p += jump - left; + left = size; + for (p = src; p < (src + size);) + { + char *tok1, *tok2, *tok3, *tok4; + + TOK_GET(tok1); + if (tok1) + { + if (!strcmp(tok1, "group")) + { + TOK_GET(tok2); + if (tok2) + { + TOK_GET(tok3); + if (tok3) + { + TOK_GET(tok4); + if (tok4) + { + if (!strcmp(tok4, "{")) + { + /* we have 'group NAM TYP {' */ + n = calloc(1, sizeof(Node)); + if (n) + { + n->parent = node; + if (!node_base) + { + node_base = n; + } + if (!node) + { + node = n; + } + else + { + /* append node */ + if (!node->values) + node->values = n; + else + { + for (nn = node->values; nn; nn = nn->next) + { + if (!nn->next) + { + nn->next = n; + n->prev = nn; + break; + } + } + } + } + n->name = strdup(tok2); + if (!strcmp(tok3, "struct")) n->type = EET_G_UNKNOWN; + else if (!strcmp(tok3, "array")) n->type = EET_G_ARRAY; + else if (!strcmp(tok3, "var_array")) n->type = EET_G_VAR_ARRAY; + else if (!strcmp(tok3, "list")) n->type = EET_G_LIST; + else if (!strcmp(tok3, "hash")) n->type = EET_G_HASH; + else + { + printf("ERROR: group type '%s' invalid.\n", tok3); + } + node = n; + } + } + free(tok4); + } + free(tok3); + } + free(tok2); + } + } + else if (!strcmp(tok1, "value")) + { + TOK_GET(tok2); + if (tok2) + { + TOK_GET(tok3); + if (tok3) + { + TOK_GET(tok4); + if (tok4) + { + /* we have 'value NAME TYP XXX' */ + if (node_base) + { + n = calloc(1, sizeof(Node)); + if (n) + { + n->parent = node; + /* append node */ + if (!node->values) + node->values = n; + else + { + for (nn = node->values; nn; nn = nn->next) + { + if (!nn->next) + { + nn->next = n; + n->prev = nn; + break; + } + } + } + n->name = strdup(tok2); + if (!strcmp(tok3, "char:")) + { + n->type = EET_T_CHAR; + sscanf(tok4, "%hhi", &(n->data.c)); + } + else if (!strcmp(tok3, "short:")) + { + n->type = EET_T_SHORT; + sscanf(tok4, "%hi", &(n->data.s)); + } + else if (!strcmp(tok3, "int:")) + { + n->type = EET_T_INT; + sscanf(tok4, "%i", &(n->data.i)); + } + else if (!strcmp(tok3, "long_long:")) + { + n->type = EET_T_LONG_LONG; + sscanf(tok4, "%lli", &(n->data.l)); + } + else if (!strcmp(tok3, "float:")) + { + n->type = EET_T_FLOAT; + sscanf(tok4, "%f", &(n->data.f)); + } + else if (!strcmp(tok3, "double:")) + { + n->type = EET_T_DOUBLE; + sscanf(tok4, "%lf", &(n->data.d)); + } + else if (!strcmp(tok3, "uchar:")) + { + n->type = EET_T_UCHAR; + sscanf(tok4, "%hhu", &(n->data.uc)); + } + else if (!strcmp(tok3, "ushort:")) + { + n->type = EET_T_USHORT; + sscanf(tok4, "%hu", &(n->data.us)); + } + else if (!strcmp(tok3, "uint:")) + { + n->type = EET_T_UINT; + sscanf(tok4, "%u", &(n->data.ui)); + } + else if (!strcmp(tok3, "ulong_long:")) + { + n->type = EET_T_ULONG_LONG; + sscanf(tok4, "%llu", &(n->data.ul)); + } + else if (!strcmp(tok3, "string:")) + { + n->type = EET_T_STRING; + n->data.str = strdup(tok4); + } + else if (!strcmp(tok3, "inlined:")) + { + n->type = EET_T_INLINED_STRING; + n->data.str = strdup(tok4); + } + else + { + printf("ERROR: value type '%s' invalid.\n", tok4); + } + } + } + free(tok4); + } + free(tok3); + } + free(tok2); + } + } + else if (!strcmp(tok1, "key")) + { + TOK_GET(tok2); + if (tok2) + { + /* we have 'key NAME' */ + if (node) + { + node->key = strdup(tok2); + } + free(tok2); + } + } + else if (!strcmp(tok1, "count")) + { + TOK_GET(tok2); + if (tok2) + { + /* we have a 'count COUNT' */ + if (node) + { + sscanf(tok2, "%i", &(node->count)); + } + free(tok2); + } + } + else if (!strcmp(tok1, "}")) + { + /* we have an end of the group */ + if (node) node = node->parent; + } + free(tok1); + } + } + + if (node_base) + { + cdata = _eet_data_dump_encode(ed, node_base, size_ret); + _eet_data_dump_free(node_base); + } + return cdata; +} + +#define NEXT_CHUNK(P, Size, Echnk, Ed) \ + { \ + int tmp; \ + tmp = Ed ? (int) (sizeof(int) * 2) : Echnk.len + 4;\ + P += (4 + Echnk.size + tmp); \ + Size -= (4 + Echnk.size + tmp); \ + } + +static void * +_eet_data_descriptor_decode(const Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + const void *data_in, + int size_in, + int level, + void (*dumpfunc) (void *data, const char *str), + void *dumpdata) +{ + void *data = NULL; + char *p, *buf, tbuf[256]; + int size, i, dump; + Eet_Data_Chunk chnk; + + if (words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) words_bigendian = 1; + else words_bigendian = 0; + } + + if (edd) + { + data = edd->func.mem_alloc(edd->size); + if (!data) return NULL; + if (edd->ed != ed) + { + for (i = 0; i < edd->elements.num; i++) + edd->elements.set[i].directory_name_ptr = NULL; + edd->ed = ed; + } + } + _eet_freelist_ref(); + _eet_freelist_str_ref(); + _eet_freelist_list_ref(); + if (data) _eet_freelist_add(data); + dump = 0; + memset(&chnk, 0, sizeof(Eet_Data_Chunk)); + eet_data_chunk_get(ed, &chnk, data_in, size_in); + if (!chnk.name) goto error; + if (edd) + { + if (strcmp(chnk.name, edd->name)) goto error; + } + p = chnk.data; + if (ed) + size = size_in - (4 + sizeof(int) * 2); + else + size = size_in - (4 + 4 + chnk.len); + if (edd) + { + if (!edd->elements.hash.buckets) _eet_descriptor_hash_new(edd); + } + if (dumpfunc) + { + dump = 1; + if (chnk.type == EET_T_UNKNOW) + { + buf = tbuf; + + for (i = 0; i < level; i++) dumpfunc(dumpdata, " "); + dumpfunc(dumpdata, "group \""); + _eet_data_dump_string_escape(dumpdata, dumpfunc, chnk.name); + dumpfunc(dumpdata, "\" "); + switch (chnk.group_type) + { + case EET_G_UNKNOWN: + dumpfunc(dumpdata, "struct"); + break; + case EET_G_ARRAY: + dumpfunc(dumpdata, "array"); + break; + case EET_G_VAR_ARRAY: + dumpfunc(dumpdata, "var_array"); + break; + case EET_G_LIST: + dumpfunc(dumpdata, "list"); + break; + case EET_G_HASH: + dumpfunc(dumpdata, "hash"); + break; + default: + dumpfunc(dumpdata, "???"); + break; + } + dumpfunc(dumpdata, " {\n"); + } + } + while (size > 0) + { + Eet_Data_Chunk echnk; + Eet_Data_Element *ede; + + /* get next data chunk */ + memset(&echnk, 0, sizeof(Eet_Data_Chunk)); + eet_data_chunk_get(ed, &echnk, p, size); + if (!echnk.name) goto error; + /* FIXME: don't REPLY on edd - work without */ + if ((edd) && (!dumpfunc)) + { + ede = _eet_descriptor_hash_find(edd, echnk.name, echnk.hash); + if (ede) + { + int group_type = EET_G_UNKNOWN, type = EET_T_UNKNOW; + int ret = 0; + + group_type = ede->group_type; + type = ede->type; + if ((echnk.type == 0) && (echnk.group_type == 0)) + { + type = ede->type; + group_type = ede->group_type; + } + else + { + if (IS_SIMPLE_TYPE(echnk.type) && + (echnk.type == ede->type)) + type = echnk.type; + else if ((echnk.group_type > EET_G_UNKNOWN) && + (echnk.group_type < EET_G_LAST) && + (echnk.group_type == ede->group_type)) + group_type = echnk.group_type; + } + /* hashes doesnt fit well with the table */ + ret = eet_group_codec[group_type - 100].get(ed, edd, ede, &echnk, type, group_type, ((char *)data) + ede->offset, level, dumpfunc, dumpdata, &p, &size); + if (ret <= 0) goto error; + } + } + /*...... dump func */ + else if (dumpfunc) + { + unsigned char dd[128]; + int group_type = EET_G_UNKNOWN, type = EET_T_UNKNOW; + + if ((echnk.type > EET_T_UNKNOW) && + (echnk.type < EET_T_LAST)) + type = echnk.type; + else if ((echnk.group_type > EET_G_UNKNOWN) && + (echnk.group_type < EET_G_LAST)) + group_type = echnk.group_type; + if (group_type == EET_G_UNKNOWN) + { + int ret; + void *data_ret; + + if (IS_SIMPLE_TYPE(type)) + { + ret = eet_data_get_type(ed, + type, + echnk.data, + ((char *)echnk.data) + echnk.size, + dd); + for (i = 0; i < level; i++) dumpfunc(dumpdata, " "); + dumpfunc(dumpdata, " value \""); + _eet_data_dump_string_escape(dumpdata, dumpfunc, echnk.name); + dumpfunc(dumpdata, "\" "); + switch (type) + { + case EET_T_CHAR: + dumpfunc(dumpdata, "char: "); + snprintf(tbuf, sizeof(tbuf), "%hhi", *((char *)dd)); + dumpfunc(dumpdata, tbuf); break; + case EET_T_SHORT: + dumpfunc(dumpdata, "short: "); + snprintf(tbuf, sizeof(tbuf), "%hi", *((short *)dd)); + dumpfunc(dumpdata, tbuf); break; + case EET_T_INT: + dumpfunc(dumpdata, "int: "); + snprintf(tbuf, sizeof(tbuf), "%i", *((int *)dd)); + dumpfunc(dumpdata, tbuf); break; + case EET_T_LONG_LONG: + dumpfunc(dumpdata, "long_long: "); + snprintf(tbuf, sizeof(tbuf), "%lli", *((long long *)dd)); + dumpfunc(dumpdata, tbuf); break; + case EET_T_FLOAT: + dumpfunc(dumpdata, "float: "); + snprintf(tbuf, sizeof(tbuf), "%1.25f", *((float *)dd)); + dumpfunc(dumpdata, tbuf); break; + case EET_T_DOUBLE: + dumpfunc(dumpdata, "double: "); + snprintf(tbuf, sizeof(tbuf), "%1.25f", *((double *)dd)); + dumpfunc(dumpdata, tbuf); break; + case EET_T_UCHAR: + dumpfunc(dumpdata, "uchar: "); + snprintf(tbuf, sizeof(tbuf), "%hhu", *((unsigned char *)dd)); + dumpfunc(dumpdata, tbuf); break; + case EET_T_USHORT: + dumpfunc(dumpdata, "ushort: "); + snprintf(tbuf, sizeof(tbuf), "%i", *((unsigned short *)dd)); + dumpfunc(dumpdata, tbuf); break; + case EET_T_UINT: + dumpfunc(dumpdata, "uint: "); + snprintf(tbuf, sizeof(tbuf), "%u", *((unsigned int *)dd)); + dumpfunc(dumpdata, tbuf); break; + case EET_T_ULONG_LONG: + dumpfunc(dumpdata, "ulong_long: "); + snprintf(tbuf, sizeof(tbuf), "%llu", *((unsigned long long *)dd)); + dumpfunc(dumpdata, tbuf); break; + case EET_T_INLINED_STRING: + { + char *s; + + s = *((char **)dd); + if (s) + { + dumpfunc(dumpdata, "inlined: \""); + _eet_data_dump_string_escape(dumpdata, dumpfunc, s); + dumpfunc(dumpdata, "\""); + } + } + break; + case EET_T_STRING: + { + char *s; + + s = *((char **)dd); + if (s) + { + dumpfunc(dumpdata, "string: \""); + _eet_data_dump_string_escape(dumpdata, dumpfunc, s); + dumpfunc(dumpdata, "\""); + } + } + break; + default: + dumpfunc(dumpdata, "???: ???"); break; + break; + } + dumpfunc(dumpdata, ";\n"); + } + else + { + data_ret = _eet_data_descriptor_decode(ed, + NULL, + echnk.data, + echnk.size, + level + 1, + dumpfunc, + dumpdata); + if (!data_ret) goto error; + } + } + else + { + for (i = 0; i < level; i++) dumpfunc(dumpdata, " "); + dumpfunc(dumpdata, " group \""); + _eet_data_dump_string_escape(dumpdata, dumpfunc, echnk.name); + dumpfunc(dumpdata, "\" "); + switch (echnk.group_type) + { + case EET_G_UNKNOWN: + dumpfunc(dumpdata, "struct");break; + case EET_G_ARRAY: + dumpfunc(dumpdata, "array");break; + case EET_G_VAR_ARRAY: + dumpfunc(dumpdata, "var_array");break; + case EET_G_LIST: + dumpfunc(dumpdata, "list");break; + case EET_G_HASH: + dumpfunc(dumpdata, "hash");break; + default: + dumpfunc(dumpdata, "???");break; + break; + } + dumpfunc(dumpdata, " {\n"); + switch (group_type) + { + case EET_G_ARRAY: + case EET_G_VAR_ARRAY: + { + int count; + int ret; + int i; + + EET_ASSERT(!IS_SIMPLE_TYPE(type), goto error); + + ret = eet_data_get_type(ed, + EET_T_INT, + echnk.data, + ((char *)echnk.data) + echnk.size, + &count); + if (ret <= 0) goto error; + + for (i = 0; i < level; i++) dumpfunc(dumpdata, " "); + dumpfunc(dumpdata, " count "); + snprintf(tbuf, sizeof(tbuf), "%i", count); + dumpfunc(dumpdata, tbuf); + dumpfunc(dumpdata, ";\n"); + + /* get all array elements */ + for (i = 0; i < count; i++) + { + void *data_ret = NULL; + + /* Advance to next chunk */ + NEXT_CHUNK(p, size, echnk, ed); + memset(&echnk, 0, sizeof(Eet_Data_Chunk)); + + eet_data_chunk_get(ed, &echnk, p, size); + if (!echnk.name) goto error; + /* get the data */ + data_ret = _eet_data_descriptor_decode(ed, + NULL, + echnk.data, + echnk.size, + level + 2, + dumpfunc, + dumpdata); + if (!data_ret) goto error; + } + } + break; + case EET_G_LIST: + { + void *data_ret = NULL; + + EET_ASSERT(!IS_SIMPLE_TYPE(type), goto error); + + data_ret = _eet_data_descriptor_decode(ed, + NULL, + echnk.data, + echnk.size, + level + 2, + dumpfunc, + dumpdata); + if (!data_ret) goto error; + } + break; + case EET_G_HASH: + { + int ret; + char *key = NULL; + void *data_ret = NULL; + + /* Read key */ + ret = eet_data_get_type(ed, + EET_T_STRING, + echnk.data, + ((char *)echnk.data) + echnk.size, + &key); + if (ret <= 0) goto error; + + /* Advance to next chunk */ + NEXT_CHUNK(p, size, echnk, ed); + memset(&echnk, 0, sizeof(Eet_Data_Chunk)); + + /* Read value */ + eet_data_chunk_get(ed, &echnk, p, size); + if (!echnk.name) goto error; + + EET_ASSERT(!IS_SIMPLE_TYPE(type), goto error); + + { + char *s; + + s = key; + if (s) + { + for (i = 0; i < level; i++) dumpfunc(dumpdata, " "); + dumpfunc(dumpdata, " key \""); + _eet_data_dump_string_escape(dumpdata, dumpfunc, s); + dumpfunc(dumpdata, "\";\n"); + } + data_ret = _eet_data_descriptor_decode(ed, + NULL, + echnk.data, + echnk.size, + level + 2, + dumpfunc, + dumpdata); + } + if (!data_ret) + { + goto error; + } + } + break; + default: + break; + } + if (dumpfunc) + { + for (i = 0; i < level; i++) dumpfunc(dumpdata, " "); + dumpfunc(dumpdata, " }\n"); + } + } + } + /* advance to next chunk */ + NEXT_CHUNK(p, size, echnk, ed); + } + + _eet_freelist_unref(); + _eet_freelist_str_unref(); + _eet_freelist_list_unref(); + if (dumpfunc) + { + _eet_freelist_str_free(edd); + _eet_freelist_direct_str_free(edd); + _eet_freelist_list_free(edd); + _eet_freelist_free(edd); + } + else + { + _eet_freelist_reset(); + _eet_freelist_str_reset(); + _eet_freelist_list_reset(); + } + if (dumpfunc) + { + if (dump) + { + if (chnk.type == EET_T_UNKNOW) + { + for (i = 0; i < level; i++) dumpfunc(dumpdata, " "); + dumpfunc(dumpdata, "}\n"); + } + } + return (void *)1; + } + return data; + +error: + _eet_freelist_unref(); + _eet_freelist_str_unref(); + _eet_freelist_list_unref(); + _eet_freelist_str_free(edd); + _eet_freelist_direct_str_free(edd); + _eet_freelist_list_free(edd); + _eet_freelist_free(edd); + if (dumpfunc) + { + if (dump) + { + if (chnk.type == EET_T_UNKNOW) + { + for (i = 0; i < level; i++) dumpfunc(dumpdata, " "); + dumpfunc(dumpdata, "}\n"); + } + } + } + return NULL; +} + +static int +eet_data_get_list(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, + int type __UNUSED__, int group_type __UNUSED__, void *data, + int level, void (*dumpfunc) (void *data, const char *str), void *dumpdata, + char **p __UNUSED__, int *size __UNUSED__) +{ + void *list = NULL; + void **ptr; + void *data_ret; + + EET_ASSERT(!IS_SIMPLE_TYPE(type), return 0); + + ptr = (void **)data; + list = *ptr; + data_ret = NULL; + + data_ret = _eet_data_descriptor_decode(ed, ede->subtype, echnk->data, echnk->size, level + 2, dumpfunc, dumpdata); + if (!data_ret) return 0; + + list = edd->func.list_append(list, data_ret); + *ptr = list; + _eet_freelist_list_add(ptr); + + return 1; +} + +static int +eet_data_get_hash(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, + int type, int group_type __UNUSED__, void *data, + int level, void (*dumpfunc) (void *data, const char *str), void *dumpdata, + char **p, int *size) +{ + void **ptr; + void *hash = NULL; + char *key = NULL; + void *data_ret = NULL; + int ret = 0; + + EET_ASSERT(!IS_SIMPLE_TYPE(type), return 0); + + ptr = (void **)data; + hash = *ptr; + + /* Read key */ + ret = eet_data_get_type(ed, + EET_T_STRING, + echnk->data, + ((char *)echnk->data) + echnk->size, + &key); + if (ret <= 0) goto on_error; + + /* Advance to next chunk */ + NEXT_CHUNK((*p), (*size), (*echnk), ed); + memset(echnk, 0, sizeof(Eet_Data_Chunk)); + + /* Read value */ + eet_data_chunk_get(ed, echnk, *p, *size); + if (!echnk->name) goto on_error; + + data_ret = _eet_data_descriptor_decode(ed, + ede->subtype, + echnk->data, + echnk->size, + level + 2, + dumpfunc, + dumpdata); + if (!data_ret) goto on_error; + + hash = edd->func.hash_add(hash, key, data_ret); + *ptr = hash; + _eet_freelist_list_add(ptr); + return 1; + + on_error: + return ret; +} + +/* var arrays and fixed arrays have to + * get all chunks at once. for fixed arrays + * we can get each chunk and increment a + * counter stored on the element itself but + * it wont be thread safe. for var arrays + * we still need a way to get the number of + * elements from the data, so storing the + * number of elements and the element data on + * each chunk is pointless. + */ +static int +eet_data_get_array(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd __UNUSED__, + Eet_Data_Element *ede, Eet_Data_Chunk *echnk, + int type, int group_type, void *data, + int level, void (*dumpfunc) (void *data, const char *str), void *dumpdata, + char **p, int *size) +{ + void *ptr; + int count; + int ret; + int i; + + EET_ASSERT(!IS_SIMPLE_TYPE(type), return 0); + + ptr = data; + /* read the number of elements */ + ret = eet_data_get_type(ed, + EET_T_INT, + echnk->data, + ((char *)echnk->data) + echnk->size, + &count); + if (ret <= 0) return ret; + if (group_type == EET_G_VAR_ARRAY) + { + /* store the number of elements + * on the counter offset */ + *(int *)(((char *)data) + ede->count - ede->offset) = count; + /* allocate space for the array of elements */ + *(void **)ptr = calloc(count, ede->subtype->size); + + if (!*(void **)ptr) return 0; + + _eet_freelist_add(*(void **)ptr); + } + + /* get all array elements */ + for (i = 0; i < count; i++) + { + void *dst; + void *data_ret = NULL; + + /* Advance to next chunk */ + NEXT_CHUNK((*p), (*size), (*echnk), ed); + memset(echnk, 0, sizeof(Eet_Data_Chunk)); + + eet_data_chunk_get(ed, echnk, *p, *size); + if (!echnk->name) return 0; + /* get the data */ + + /* get the destination pointer */ + if (group_type == EET_G_ARRAY) + dst = (char *)ptr + (ede->subtype->size * i); + else + dst = *(char **)ptr + (ede->subtype->size * i); + data_ret = _eet_data_descriptor_decode(ed, + ede->subtype, + echnk->data, + echnk->size, + level + 2, + dumpfunc, + dumpdata); + if (!data_ret) return 0; + memcpy(dst, data_ret, ede->subtype->size); + free(data_ret); + } + return 1; +} + +static int +eet_data_get_unknown(const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, + int type, int group_type __UNUSED__, void *data, + int level, void (*dumpfunc) (void *data, const char *str), void *dumpdata, + char **p __UNUSED__, int *size __UNUSED__) +{ + int ret; + void *data_ret; + + if (IS_SIMPLE_TYPE(type)) + { + ret = eet_data_get_type(ed, type, echnk->data, ((char *)echnk->data) + echnk->size, ((char *)data)); + if (ret <= 0) return ret; + + if (type == EET_T_STRING) + { + char **str; + + str = (char **)(((char *)data)); + if (*str) + { + if ((ed == NULL) || (edd->func.str_direct_alloc == NULL)) + { + *str = edd->func.str_alloc(*str); + _eet_freelist_str_add(*str); + } + else + { + *str = edd->func.str_direct_alloc(*str); + _eet_freelist_direct_str_add(*str); + } + } + } + else if (type == EET_T_INLINED_STRING) + { + char **str; + + str = (char **)(((char *)data)); + if (*str) + { + *str = edd->func.str_alloc(*str); + _eet_freelist_str_add(*str); + } + } + } + else if (ede->subtype) + { + void **ptr; + + data_ret = _eet_data_descriptor_decode(ed, ede->subtype, echnk->data, echnk->size, level + 1, dumpfunc, dumpdata); + if (!data_ret) return 0; + + ptr = (void **)(((char *)data)); + *ptr = (void *)data_ret; + } + + return 1; +} + +static void +eet_data_encode(Eet_Dictionary *ed, Eet_Data_Stream *ds, void *data, const char *name, int size, int type, int group_type) +{ + Eet_Data_Chunk *echnk; + + echnk = eet_data_chunk_new(data, size, name, type, group_type); + eet_data_chunk_put(ed, echnk, ds); + eet_data_chunk_free(echnk); + free(data); +} + +static void +eet_data_put_array(Eet_Dictionary *ed, Eet_Data_Descriptor *edd __UNUSED__, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in) +{ + void *data; + int size; + int j; + int offset = 0; + int count; + + EET_ASSERT(!IS_SIMPLE_TYPE(ede->type), return ); + + if (ede->group_type == EET_G_ARRAY) + count = ede->counter_offset; + else + count = *(int *)(((char *)data_in) + ede->count - ede->offset); + + if (count <= 0) return; + /* Store number of elements */ + data = eet_data_put_type(ed, EET_T_INT, &count, &size); + if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + + for (j = 0; j < count; j++) + { + void *d; + + if (ede->group_type == EET_G_ARRAY) + d = (void *)(((char *)data_in) + offset); + else + d = *(((char **)data_in)) + offset; + + data = _eet_data_descriptor_encode(ed, ede->subtype, d, &size); + offset += ede->subtype->size; + if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + } +} + +static void +eet_data_put_unknown(Eet_Dictionary *ed, Eet_Data_Descriptor *edd __UNUSED__, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in) +{ + void *data = NULL; + int size; + + if (IS_SIMPLE_TYPE(ede->type)) + data = eet_data_put_type(ed, ede->type, data_in, &size); + else if (ede->subtype) + { + if (*((char **)data_in)) + data = _eet_data_descriptor_encode(ed, + ede->subtype, + *((char **)((char *)(data_in))), + &size); + } + if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); +} + +static void +eet_data_put_list(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in) +{ + void *data; + void *l; + int size; + + EET_ASSERT(!IS_SIMPLE_TYPE(ede->type), return ); + + l = *((void **)(((char *)data_in))); + for (; l; l = edd->func.list_next(l)) + { + data = _eet_data_descriptor_encode(ed, + ede->subtype, + edd->func.list_data(l), + &size); + if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + } +} + +static void +eet_data_put_hash(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in) +{ + Eet_Data_Encode_Hash_Info fdata; + void *l; + + l = *((void **)(((char *)data_in))); + fdata.ds = ds; + fdata.ede = ede; + fdata.ed = ed; + edd->func.hash_foreach(l, eet_data_descriptor_encode_hash_cb, &fdata); +} + +EAPI int +eet_data_dump(Eet_File *ef, + const char *name, + void (*dumpfunc) (void *data, const char *str), + void *dumpdata) +{ + const Eet_Dictionary *ed = NULL; + const void *data; + int ret = 0; + int required_free = 0; + int size; + + ed = eet_dictionary_get(ef); + + data = eet_read_direct(ef, name, &size); + if (!data) + { + required_free = 1; + data = eet_read(ef, name, &size); + if (!data) return 0; + } + + if (_eet_data_descriptor_decode(ed, NULL, data, size, 0, + dumpfunc, dumpdata)) + ret = 1; + + if (required_free) + free((void*)data); + + return ret; +} + + +EAPI int +eet_data_text_dump(const void *data_in, + int size_in, + void (*dumpfunc) (void *data, const char *str), + void *dumpdata) +{ + if (_eet_data_descriptor_decode(NULL, NULL, data_in, size_in, 0, + dumpfunc, dumpdata)) + return 1; + return 0; +} + +EAPI void * +eet_data_text_undump(const char *text, + int textlen, + int *size_ret) +{ + return _eet_data_dump_parse(NULL, size_ret, text, textlen); +} + +EAPI int +eet_data_undump(Eet_File *ef, + const char *name, + const char *text, + int textlen, + int compress) +{ + Eet_Dictionary *ed; + void *data_enc; + int size; + int val; + + ed = eet_dictionary_get(ef); + + data_enc = _eet_data_dump_parse(ed, &size, text, textlen); + if (!data_enc) return 0; + val = eet_write(ef, name, data_enc, size, compress); + free(data_enc); + return val; +} + +EAPI void * +eet_data_descriptor_decode(Eet_Data_Descriptor *edd, + const void *data_in, + int size_in) +{ + return _eet_data_descriptor_decode(NULL, edd, data_in, size_in, 0, + NULL, NULL); +} + +static void * +_eet_data_descriptor_encode(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + const void *data_in, + int *size_ret) +{ + Eet_Data_Stream *ds; + Eet_Data_Chunk *chnk; + void *cdata; + int csize; + int i; + + if (words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) words_bigendian = 1; + else words_bigendian = 0; + } + + ds = eet_data_stream_new(); + for (i = 0; i < edd->elements.num; i++) + { + Eet_Data_Element *ede; + + ede = &(edd->elements.set[i]); + eet_group_codec[ede->group_type - 100].put(ed, edd, ede, ds, ((char *)data_in) + ede->offset); + } + chnk = eet_data_chunk_new(ds->data, ds->pos, edd->name, EET_T_UNKNOW, EET_G_UNKNOWN); + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + + ds = eet_data_stream_new(); + eet_data_chunk_put(ed, chnk, ds); + cdata = ds->data; + csize = ds->pos; + + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + *size_ret = csize; + + free(chnk->data); + eet_data_chunk_free(chnk); + + return cdata; +} + +EAPI void * +eet_data_descriptor_encode(Eet_Data_Descriptor *edd, + const void *data_in, + int *size_ret) +{ + return _eet_data_descriptor_encode(NULL, edd, data_in, size_ret); +} diff --git a/src/lib/eet_dictionary.c b/src/lib/eet_dictionary.c new file mode 100644 index 0000000..666282b --- /dev/null +++ b/src/lib/eet_dictionary.c @@ -0,0 +1,335 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "Eet.h" +#include "Eet_private.h" + +Eet_Dictionary * +eet_dictionary_add(void) +{ + Eet_Dictionary *new; + + new = calloc(1, sizeof (Eet_Dictionary)); + if (!new) + return NULL; + + memset(new->hash, -1, sizeof (int) * 256); + + return new; +} + +void +eet_dictionary_free(Eet_Dictionary *ed) +{ + if (ed) + { + int i; + + for (i = 0; i < ed->count; ++i) + if (ed->all[i].str) + free(ed->all[i].str); + if (ed->all) free(ed->all); + free(ed); + } +} + +static int +_eet_dictionary_lookup(Eet_Dictionary *ed, const char *string, int hash) +{ + int prev = -1; + int current; + + current = ed->hash[hash]; + + while (current != -1) + { + if (ed->all[current].str) + { + if (strcmp(ed->all[current].str, string) >= 0) + break ; + } + if (ed->all[current].mmap) + { + if (strcmp(ed->all[current].mmap, string) >= 0) + break ; + } + + prev = current; + current = ed->all[current].next; + } + + if (current == -1) + return prev; + + return current; +} + +int +eet_dictionary_string_add(Eet_Dictionary *ed, const char *string) +{ + Eet_String *current; + char *str; + int hash; + int index; + int len; + + if (!ed) + return -1; + + hash = _eet_hash_gen(string, 8); + + index = _eet_dictionary_lookup(ed, string, hash); + + if (index != -1) + { + if (ed->all[index].str) + { + if (strcmp(ed->all[index].str, string) == 0) + return index; + } + if (ed->all[index].mmap) + { + if (strcmp(ed->all[index].mmap, string) == 0) + return index; + } + } + + if (ed->total == ed->count) + { + Eet_String *new; + int total; + + total = ed->total + 8; + + new = realloc(ed->all, sizeof (Eet_String) * total); + if (new == NULL) + return -1; + + ed->all = new; + ed->total = total; + } + + len = strlen(string) + 1; + str = strdup(string); + if (str == NULL) + return -1; + + current = ed->all + ed->count; + + current->flags.converted = 0; + current->flags.is_float = 0; + + current->hash = hash; + + current->str = str; + current->len = len; + current->mmap = NULL; + + if (index == -1) + { + current->next = ed->hash[hash]; + current->prev = -1; + ed->hash[hash] = ed->count; + } + else + { + current->next = index; + current->prev = ed->all[index].prev; + + if (current->next != -1) + ed->all[current->next].prev = ed->count; + if (current->prev != -1) + ed->all[current->prev].next = ed->count; + else + ed->hash[hash] = ed->count; + } + + return ed->count++; +} + +int +eet_dictionary_string_get_size(const Eet_Dictionary *ed, int index) +{ + if (!ed) return 0; + if (index < 0) return 0; + if (index < ed->count) + return ed->all[index].len; + return 0; +} + +int +eet_dictionary_string_get_hash(const Eet_Dictionary *ed, int index) +{ + if (!ed) return -1; + if (index < 0) return -1; + if (index < ed->count) + return ed->all[index].hash; + return -1; +} + +const char * +eet_dictionary_string_get_char(const Eet_Dictionary *ed, int index) +{ + if (!ed) return NULL; + if (index < 0) return NULL; + if (index < ed->count) + { +#ifdef _WIN32 + /* Windows file system could change the mmaped file when replacing a file. So we need to copy all string in memory to avoid bugs. */ + if (ed->all[index].str == NULL) + { + ed->all[index].str = strdup(ed->all[index].mmap); + ed->all[index].mmap = NULL; + } +#else + if (ed->all[index].mmap) + return ed->all[index].mmap; +#endif + return ed->all[index].str; + } + return NULL; +} + +static inline int +_eet_dictionary_string_get_me_cache(const char *s, int len, int *mantisse, int *exponent) +{ + if ((len == 6) && (s[0] == '0') && (s[1] == 'x') && (s[3] == 'p')) + { + *mantisse = (s[2] >= 'a') ? (s[2] - 'a' + 10) : (s[2] - '0'); + *exponent = (s[5] - '0'); + + return -1; + } + return 0; +} + +static inline int +_eet_dictionary_string_get_float_cache(const char *s, int len, float *result) +{ + int mantisse; + int exponent; + + if (_eet_dictionary_string_get_me_cache(s, len, &mantisse, &exponent)) + { + if (s[4] == '+') *result = (float) (mantisse << exponent); + else *result = (float) mantisse / (float) (1 << exponent); + + return -1; + } + return 0; +} + +static inline int +_eet_dictionary_string_get_double_cache(const char *s, int len, double *result) +{ + int mantisse; + int exponent; + + if (_eet_dictionary_string_get_me_cache(s, len, &mantisse, &exponent)) + { + if (s[4] == '+') *result = (double) (mantisse << exponent); + else *result = (double) mantisse / (float) (1 << exponent); + + return -1; + } + return 0; +} + +int +eet_dictionary_string_get_float(const Eet_Dictionary *ed, int index, float *result) +{ + if (!result) return 0; + if (!ed) return 0; + if (index < 0) return 0; + if (index < ed->count) + { + if (!(ed->all[index].flags.converted + && ed->all[index].flags.is_float)) + { + const char *str; + + str = ed->all[index].str ? ed->all[index].str : ed->all[index].mmap; + + if (!_eet_dictionary_string_get_float_cache(str, ed->all[index].len, &ed->all[index].convert.f)) + { + long long mantisse = 0; + long exponent = 0; + + if (!_eet_string_to_double_convert(str, &mantisse, &exponent)) + return 0; + + ed->all[index].convert.f = ldexpf((float) mantisse, exponent); + } + + ed->all[index].flags.is_float = 1; + } + + *result = ed->all[index].convert.f; + return -1; + } + return 0; +} + +int +eet_dictionary_string_get_double(const Eet_Dictionary *ed, int index, double *result) +{ + if (!result) return 0; + if (!ed) return 0; + if (index < 0) return 0; + if (index < ed->count) + { + if (!(ed->all[index].flags.converted + && !ed->all[index].flags.is_float)) + { + const char *str; + + str = ed->all[index].str ? ed->all[index].str : ed->all[index].mmap; + + if (!_eet_dictionary_string_get_double_cache(str, ed->all[index].len, &ed->all[index].convert.d)) + { + long long mantisse = 0; + long exponent = 0; + + if (!_eet_string_to_double_convert(str, &mantisse, &exponent)) + return 0; + + ed->all[index].convert.d = ldexp((double) mantisse, exponent); + } + + ed->all[index].flags.is_float = 0; + } + + *result = ed->all[index].convert.d; + return -1; + } + return 0; +} + +EAPI int +eet_dictionary_string_check(Eet_Dictionary *ed, const char *string) +{ + int i; + + if (ed == NULL + || string == NULL) + return 0; + + if (ed->start <= string + && string < ed->end) + return 1; + + for (i = 0; i < ed->count; ++i) + if (ed->all[i].str == string) + return 1; + + return 0; +} diff --git a/src/lib/eet_image.c b/src/lib/eet_image.c new file mode 100644 index 0000000..baeff52 --- /dev/null +++ b/src/lib/eet_image.c @@ -0,0 +1,1155 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_ALLOCA_H +# include +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include +# define alloca _alloca +#else +# include +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "Eet.h" +#include "Eet_private.h" + +/*---*/ + +typedef struct _JPEG_error_mgr *emptr; + +/*---*/ + +struct _JPEG_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; + +/*---*/ + +static void _JPEGFatalErrorHandler(j_common_ptr cinfo); +static void _JPEGErrorHandler(j_common_ptr cinfo); +static void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level); + +static int eet_data_image_jpeg_header_decode(const void *data, int size, unsigned int *w, unsigned int *h); +static int eet_data_image_jpeg_rgb_decode(const void *data, int size, unsigned int src_x, unsigned int src_y, unsigned int *d, unsigned int w, unsigned int h, unsigned int row_stride); +static void *eet_data_image_jpeg_alpha_decode(const void *data, int size, unsigned int src_x, unsigned int src_y, unsigned int *d, unsigned int w, unsigned int h, unsigned int row_stride); +static void *eet_data_image_lossless_convert(int *size, const void *data, unsigned int w, unsigned int h, int alpha); +static void *eet_data_image_lossless_compressed_convert(int *size, const void *data, unsigned int w, unsigned int h, int alpha, int compression); +static void *eet_data_image_jpeg_convert(int *size, const void *data, unsigned int w, unsigned int h, int alpha, int quality); +static void *eet_data_image_jpeg_alpha_convert(int *size, const void *data, unsigned int w, unsigned int h, int alpha, int quality); + +/*---*/ + +static int words_bigendian = -1; + +/*---*/ + +#define SWAP64(x) (x) = \ + ((((unsigned long long)(x) & 0x00000000000000ffULL ) << 56) |\ + (((unsigned long long)(x) & 0x000000000000ff00ULL ) << 40) |\ + (((unsigned long long)(x) & 0x0000000000ff0000ULL ) << 24) |\ + (((unsigned long long)(x) & 0x00000000ff000000ULL ) << 8) |\ + (((unsigned long long)(x) & 0x000000ff00000000ULL ) >> 8) |\ + (((unsigned long long)(x) & 0x0000ff0000000000ULL ) >> 24) |\ + (((unsigned long long)(x) & 0x00ff000000000000ULL ) >> 40) |\ + (((unsigned long long)(x) & 0xff00000000000000ULL ) >> 56)) +#define SWAP32(x) (x) = \ + ((((int)(x) & 0x000000ff ) << 24) |\ + (((int)(x) & 0x0000ff00 ) << 8) |\ + (((int)(x) & 0x00ff0000 ) >> 8) |\ + (((int)(x) & 0xff000000 ) >> 24)) +#define SWAP16(x) (x) = \ + ((((short)(x) & 0x00ff ) << 8) |\ + (((short)(x) & 0xff00 ) >> 8)) + +#define CONV8(x) +#define CONV16(x) {if (words_bigendian) SWAP16(x);} +#define CONV32(x) {if (words_bigendian) SWAP32(x);} +#define CONV64(x) {if (words_bigendian) SWAP64(x);} + +/*---*/ + +static void +_JPEGFatalErrorHandler(j_common_ptr cinfo) +{ + emptr errmgr; + + errmgr = (emptr) cinfo->err; + /* cinfo->err->output_message(cinfo);*/ + longjmp(errmgr->setjmp_buffer, 1); + return; +} + +static void +_JPEGErrorHandler(j_common_ptr cinfo) +{ + emptr errmgr; + + errmgr = (emptr) cinfo->err; + /* cinfo->err->output_message(cinfo);*/ + /* longjmp(errmgr->setjmp_buffer, 1);*/ + return; +} + +static void +_JPEGErrorHandler2(j_common_ptr cinfo, int msg_level) +{ + emptr errmgr; + + errmgr = (emptr) cinfo->err; + /* cinfo->err->output_message(cinfo);*/ + /* longjmp(errmgr->setjmp_buffer, 1);*/ + return; + msg_level = 0; +} + +static int +eet_data_image_jpeg_header_decode(const void *data, int size, unsigned int *w, unsigned int *h) +{ + struct jpeg_decompress_struct cinfo; + struct _JPEG_error_mgr jerr; + FILE *f; + + f = _eet_memfile_read_open(data, (size_t)size); + if (!f) return 0; + cinfo.err = jpeg_std_error(&(jerr.pub)); + jerr.pub.error_exit = _JPEGFatalErrorHandler; + jerr.pub.emit_message = _JPEGErrorHandler2; + jerr.pub.output_message = _JPEGErrorHandler; + if (setjmp(jerr.setjmp_buffer)) + { + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return 0; + } + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, f); + jpeg_read_header(&cinfo, TRUE); + cinfo.do_fancy_upsampling = FALSE; + cinfo.do_block_smoothing = FALSE; + jpeg_start_decompress(&cinfo); + + /* head decoding */ + *w = cinfo.output_width; + *h = cinfo.output_height; + if ((*w < 1) || (*h < 1) || (*w > 8192) || (*h > 8192)) + { + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return 0; + } + /* end head decoding */ + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return 1; +} + +static int +eet_data_image_jpeg_rgb_decode(const void *data, int size, unsigned int src_x, unsigned int src_y, + unsigned int *d, unsigned int w, unsigned int h, unsigned int row_stride) +{ + struct jpeg_decompress_struct cinfo; + struct _JPEG_error_mgr jerr; + unsigned char *ptr, *line[16], *tdata = NULL; + unsigned int *ptr2, *tmp; + unsigned int iw, ih; + int x, y, l, scans; + int i, count, prevy; + FILE *f; + + /* FIXME: handle src_x, src_y and row_stride correctly */ + if (!d) return 0; + + f = _eet_memfile_read_open(data, (size_t)size); + if (!f) return 0; + cinfo.err = jpeg_std_error(&(jerr.pub)); + jerr.pub.error_exit = _JPEGFatalErrorHandler; + jerr.pub.emit_message = _JPEGErrorHandler2; + jerr.pub.output_message = _JPEGErrorHandler; + if (setjmp(jerr.setjmp_buffer)) + { + if (tdata) free(tdata); + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return 0; + } + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, f); + jpeg_read_header(&cinfo, TRUE); + cinfo.dct_method = JDCT_FASTEST; + cinfo.do_fancy_upsampling = FALSE; + cinfo.do_block_smoothing = FALSE; + jpeg_start_decompress(&cinfo); + + /* head decoding */ + iw = cinfo.output_width; + ih = cinfo.output_height; + if ((iw != w) || (ih != h)) + { + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return 0; + } + /* end head decoding */ + /* data decoding */ + if (cinfo.rec_outbuf_height > 16) + { + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return 0; + } + tdata = alloca((iw) * 16 * 3); + ptr2 = d; + count = 0; + prevy = 0; + + if (cinfo.output_components == 3) + { + for (i = 0; i < cinfo.rec_outbuf_height; i++) + line[i] = tdata + (i * (iw) * 3); + for (l = 0; l < ih; l += cinfo.rec_outbuf_height) + { + jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); + scans = cinfo.rec_outbuf_height; + if ((ih - l) < scans) scans = ih - l; + ptr = tdata; + + if (l + scans >= src_y && l < src_y + h) + { + y = src_y - l; + if (y < 0) y = 0; + for (ptr += 3 * iw * y; y < scans && (y + l) < (src_y + h); y++) + { + tmp = ptr2; + ptr += 3 * src_x; + for (x = 0; x < w; x++) + { + *ptr2 = + (0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << 8) | (ptr[2]); + ptr += 3; + ptr2++; + } + ptr += 3 * (iw - w); + ptr2 = tmp + row_stride / 4; + } + } + else + { + ptr += 3 * iw * scans; + } + } + } + else if (cinfo.output_components == 1) + { + for (i = 0; i < cinfo.rec_outbuf_height; i++) + line[i] = tdata + (i * (iw)); + for (l = 0; l < (ih); l += cinfo.rec_outbuf_height) + { + jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); + scans = cinfo.rec_outbuf_height; + if (((ih) - l) < scans) scans = (ih) - l; + ptr = tdata; + + if (l >= src_y && l < src_y + h) + { + y = src_y - l; + if (y < 0) y = 0; + for (ptr += iw * y; y < scans && (y + l) < (src_y + h); y++) + { + tmp = ptr2; + ptr += src_x; + for (x = 0; x < w; x++) + { + *ptr2 = + (0xff000000) | ((ptr[0]) << 16) | ((ptr[0]) << 8) | (ptr[0]); + ptr++; + ptr2++; + } + ptr += iw - w; + ptr2 = tmp + row_stride / 4; + } + } + else + { + ptr += iw * scans; + } + } + } + /* end data decoding */ + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return 1; +} + +static void * +eet_data_image_jpeg_alpha_decode(const void *data, int size, unsigned int src_x, unsigned int src_y, + unsigned int *d, unsigned int w, unsigned int h, unsigned int row_stride) +{ + struct jpeg_decompress_struct cinfo; + struct _JPEG_error_mgr jerr; + unsigned char *ptr, *line[16], *tdata = NULL; + unsigned int *ptr2, *tmp; + int x, y, l, scans; + int i, count, prevy, iw; + FILE *f; + + f = _eet_memfile_read_open(data, (size_t)size); + if (!f) return NULL; + + if (0) + { + char buf[1]; + + while (fread(buf, 1, 1, f)); + _eet_memfile_read_close(f); + return d; + } + cinfo.err = jpeg_std_error(&(jerr.pub)); + jerr.pub.error_exit = _JPEGFatalErrorHandler; + jerr.pub.emit_message = _JPEGErrorHandler2; + jerr.pub.output_message = _JPEGErrorHandler; + if (setjmp(jerr.setjmp_buffer)) + { + if (tdata) free(tdata); + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return NULL; + } + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, f); + jpeg_read_header(&cinfo, TRUE); + cinfo.dct_method = JDCT_FASTEST; + cinfo.do_fancy_upsampling = FALSE; + cinfo.do_block_smoothing = FALSE; + jpeg_start_decompress(&cinfo); + + /* head decoding */ + iw = cinfo.output_width; + if (w != cinfo.output_width + || h != cinfo.output_height) + { + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return NULL; + } + /* end head decoding */ + /* data decoding */ + if (cinfo.rec_outbuf_height > 16) + { + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return NULL; + } + tdata = alloca(w * 16 * 3); + ptr2 = d; + count = 0; + prevy = 0; + if (cinfo.output_components == 1) + { + for (i = 0; i < cinfo.rec_outbuf_height; i++) + line[i] = tdata + (i * w); + for (l = 0; l < h; l += cinfo.rec_outbuf_height) + { + jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); + scans = cinfo.rec_outbuf_height; + if ((h - l) < scans) scans = h - l; + ptr = tdata; + + if (l >= src_y && l < src_y + h) + { + y = src_y - l; + if (y < 0) y = 0; + for (ptr += iw * y; y < scans && (y + l) < (src_y + h); y++) + { + tmp = ptr2; + ptr += src_x; + for (x = 0; x < w; x++) + { + *ptr2 = + ((*ptr2) & 0x00ffffff) | + ((ptr[0]) << 24); + ptr++; + ptr2++; + } + ptr += iw - w; + ptr2 = tmp + row_stride / 4; + } + } + else + { + ptr += iw * scans; + } + } + } + /* end data decoding */ + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + _eet_memfile_read_close(f); + return d; +} + +static void * +eet_data_image_lossless_convert(int *size, const void *data, unsigned int w, unsigned int h, int alpha) +{ + if (words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) words_bigendian = 1; + else words_bigendian = 0; + } + { + unsigned char *d; + int *header; + + d = malloc((w * h * 4) + (8 * 4)); + if (!d) return NULL; + + header = (int *)d; + memset(d, 0, 32); + + header[0] = 0xac1dfeed; + header[1] = w; + header[2] = h; + header[3] = alpha; + + memcpy(d + 32, data, w * h * 4); + + if (words_bigendian) + { + unsigned int i; + + for (i = 0; i < ((w * h) + 8); i++) SWAP32(header[i]); + } + *size = ((w * h * 4) + (8 * 4)); + return d; + } +} + +static void * +eet_data_image_lossless_compressed_convert(int *size, const void *data, unsigned int w, unsigned int h, int alpha, int compression) +{ + if (words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) words_bigendian = 1; + else words_bigendian = 0; + } + + { + unsigned char *d; + unsigned char *comp; + int *header; + int ret; + uLongf buflen; + + d = malloc((w * h * 4) + (8 * 4)); + if (!d) return NULL; + buflen = (((w * h * 101) / 100) + 3) * 4; + comp = malloc(buflen); + if (!comp) + { + free(d); + return NULL; + } + header = (int *)d; + memset(d, 0, 32); + + header[0] = 0xac1dfeed; + header[1] = w; + header[2] = h; + header[3] = alpha; + header[4] = compression; + memcpy(d + 32, data, w * h * 4); + + if (words_bigendian) + { + unsigned int i; + + for (i = 0; i < ((w * h) + 8); i++) SWAP32(header[i]); + } + ret = compress2((Bytef *)comp, &buflen, + (Bytef *)(d + 32), + (uLong)(w * h * 4), + compression); + if (buflen > (w * h * 4)) + { + free(comp); + free(d); + *size = -1; + return NULL; + } + memcpy(d + 32, comp, buflen); + *size = (8 * 4) + buflen; + free(comp); + return d; + } +} + +static void * +eet_data_image_jpeg_convert(int *size, const void *data, unsigned int w, unsigned int h, int alpha, int quality) +{ + const int *ptr; + void *d = NULL; + size_t sz = 0; + struct _JPEG_error_mgr jerr; + JSAMPROW *jbuf; + struct jpeg_compress_struct cinfo; + FILE *f; + unsigned char *buf; + + (void) alpha; /* unused */ + + f =_eet_memfile_write_open(&d, &sz); + if (!f) return NULL; + + buf = alloca(3 * w); + + cinfo.err = jpeg_std_error(&(jerr.pub)); + jerr.pub.error_exit = _JPEGFatalErrorHandler; + jerr.pub.emit_message = _JPEGErrorHandler2; + jerr.pub.output_message = _JPEGErrorHandler; + if (setjmp(jerr.setjmp_buffer)) + { + jpeg_destroy_compress(&cinfo); + _eet_memfile_write_close(f); + if (d) free(d); + return NULL; + } + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, f); + cinfo.image_width = w; + cinfo.image_height = h; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + if (quality >= 90) + { + cinfo.comp_info[0].h_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + } + jpeg_start_compress(&cinfo, TRUE); + + ptr = data; + while (cinfo.next_scanline < cinfo.image_height) + { + unsigned int i, j; + + /* convert scaline from ARGB to RGB packed */ + for (j = 0, i = 0; i < w; i++) + { + buf[j++] = ((*ptr) >> 16) & 0xff; + buf[j++] = ((*ptr) >> 8) & 0xff; + buf[j++] = ((*ptr)) & 0xff; + ptr++; + } + jbuf = (JSAMPROW *) (&buf); + jpeg_write_scanlines(&cinfo, jbuf, 1); + } + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + _eet_memfile_write_close(f); + *size = sz; + return d; +} + +static void * +eet_data_image_jpeg_alpha_convert(int *size, const void *data, unsigned int w, unsigned int h, int alpha, int quality) +{ + unsigned char *d1, *d2; + unsigned char *d; + int *header; + int sz1, sz2; + + (void) alpha; /* unused */ + + if (words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) words_bigendian = 1; + else words_bigendian = 0; + } + + { + const int *ptr; + void *d = NULL; + size_t sz = 0; + struct _JPEG_error_mgr jerr; + JSAMPROW *jbuf; + struct jpeg_compress_struct cinfo; + FILE *f; + unsigned char *buf; + + f = _eet_memfile_write_open(&d, &sz); + if (!f) return NULL; + + buf = alloca(3 * w); + + cinfo.err = jpeg_std_error(&(jerr.pub)); + jerr.pub.error_exit = _JPEGFatalErrorHandler; + jerr.pub.emit_message = _JPEGErrorHandler2; + jerr.pub.output_message = _JPEGErrorHandler; + if (setjmp(jerr.setjmp_buffer)) + { + jpeg_destroy_compress(&cinfo); + _eet_memfile_write_close(f); + if (d) free(d); + return NULL; + } + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, f); + cinfo.image_width = w; + cinfo.image_height = h; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + if (quality >= 90) + { + cinfo.comp_info[0].h_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + } + jpeg_start_compress(&cinfo, TRUE); + + ptr = data; + while (cinfo.next_scanline < cinfo.image_height) + { + unsigned int i, j; + + /* convert scaline from ARGB to RGB packed */ + for (j = 0, i = 0; i < w; i++) + { + buf[j++] = ((*ptr) >> 16) & 0xff; + buf[j++] = ((*ptr) >> 8) & 0xff; + buf[j++] = ((*ptr)) & 0xff; + ptr++; + } + jbuf = (JSAMPROW *) (&buf); + jpeg_write_scanlines(&cinfo, jbuf, 1); + } + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + _eet_memfile_write_close(f); + d1 = d; + sz1 = sz; + } + { + const int *ptr; + void *d = NULL; + size_t sz = 0; + struct _JPEG_error_mgr jerr; + JSAMPROW *jbuf; + struct jpeg_compress_struct cinfo; + FILE *f; + unsigned char *buf; + + f = _eet_memfile_write_open(&d, &sz); + if (!f) + { + free(d1); + return NULL; + } + + buf = alloca(3 * w); + + cinfo.err = jpeg_std_error(&(jerr.pub)); + jerr.pub.error_exit = _JPEGFatalErrorHandler; + jerr.pub.emit_message = _JPEGErrorHandler2; + jerr.pub.output_message = _JPEGErrorHandler; + if (setjmp(jerr.setjmp_buffer)) + { + jpeg_destroy_compress(&cinfo); + _eet_memfile_write_close(f); + if (d) free(d); + free(d1); + return NULL; + } + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, f); + cinfo.image_width = w; + cinfo.image_height = h; + cinfo.input_components = 1; + cinfo.in_color_space = JCS_GRAYSCALE; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + if (quality >= 90) + { + cinfo.comp_info[0].h_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + } + jpeg_start_compress(&cinfo, TRUE); + + ptr = data; + while (cinfo.next_scanline < cinfo.image_height) + { + unsigned int i, j; + + /* convert scaline from ARGB to RGB packed */ + for (j = 0, i = 0; i < w; i++) + { + buf[j++] = ((*ptr) >> 24) & 0xff; + ptr++; + } + jbuf = (JSAMPROW *) (&buf); + jpeg_write_scanlines(&cinfo, jbuf, 1); + } + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + _eet_memfile_write_close(f); + d2 = d; + sz2 = sz; + } + d = malloc(12 + sz1 + sz2); + if (!d) + { + free(d1); + free(d2); + return NULL; + } + header = (int *)d; + header[0] = 0xbeeff00d; + header[1] = sz1; + header[2] = sz2; + if (words_bigendian) + { + int i; + + for (i = 0; i < 3; i++) SWAP32(header[i]); + } + memcpy(d + 12, d1, sz1); + memcpy(d + 12 + sz1, d2, sz2); + + free(d1); + free(d2); + *size = 12 + sz1 + sz2; + return d; +} + +EAPI int +eet_data_image_write(Eet_File *ef, const char *name, + const void *data, unsigned int w, unsigned int h, int alpha, + int compress, int quality, int lossy) +{ + void *d = NULL; + int size = 0; + + d = eet_data_image_encode(data, &size, w, h, alpha, compress, quality, lossy); + if (d) + { + int v; + + v = eet_write(ef, name, d, size, 0); + free(d); + return v; + } + return 0; +} + +EAPI void * +eet_data_image_read(Eet_File *ef, const char *name, + unsigned int *w, unsigned int *h, int *alpha, + int *compress, int *quality, int *lossy) +{ + unsigned int *d = NULL; + void *data; + int size; + int free_data = 0; + + + data = (void *)eet_read_direct(ef, name, &size); + if (!data) + { + data = eet_read(ef, name, &size); + free_data = 1; + } + + if (!data) return NULL; + d = eet_data_image_decode(data, size, w, h, alpha, compress, quality, lossy); + + if (free_data) + free(data); + + return d; +} + +EAPI int +eet_data_image_read_to_surface(Eet_File *ef, const char *name, unsigned int src_x, unsigned int src_y, + unsigned int *d, unsigned int w, unsigned int h, unsigned int row_stride, + int *alpha, int *compress, int *quality, int *lossy) +{ + void *data; + int size; + int free_data = 0; + int res = 1; + + + data = (void *)eet_read_direct(ef, name, &size); + if (!data) + { + data = eet_read(ef, name, &size); + free_data = 1; + } + + if (!data) return 0; + res = eet_data_image_decode_to_surface(data, size, src_x, src_y, d, w, h, row_stride, alpha, compress, quality, lossy); + + if (free_data) + free(data); + + return res; +} + +EAPI int +eet_data_image_header_read(Eet_File *ef, const char *name, + unsigned int *w, unsigned int *h, int *alpha, + int *compress, int *quality, int *lossy) +{ + void *data = NULL; + int size = 0; + int d; + int free_data = 0; + + data = (void *)eet_read_direct(ef, name, &size); + if (!data) + { + data = eet_read(ef, name, &size); + free_data = 1; + } + + if (!data) return 0; + d = eet_data_image_header_decode(data, size, w, h, alpha, compress, quality, lossy); + if (free_data) + free(data); + + return d; +} + +EAPI void * +eet_data_image_encode(const void *data, int *size_ret, unsigned int w, unsigned int h, int alpha, int compress, int quality, int lossy) +{ + void *d = NULL; + int size = 0; + + if (lossy == 0) + { + if (compress > 0) + d = eet_data_image_lossless_compressed_convert(&size, data, w, h, alpha, compress); + + /* eet_data_image_lossless_compressed_convert will refuse to compress something + if the result is bigger than the entry. */ + if (compress <= 0 || d == NULL) + d = eet_data_image_lossless_convert(&size, data, w, h, alpha); + } + else + { + if (!alpha) + d = eet_data_image_jpeg_convert(&size, data, w, h, alpha, quality); + else + d = eet_data_image_jpeg_alpha_convert(&size, data, w, h, alpha, quality); + } + if (size_ret) *size_ret = size; + return d; +} + +EAPI int +eet_data_image_header_decode(const void *data, int size, unsigned int *w, unsigned int *h, int *alpha, int *compress, int *quality, int *lossy) +{ + int header[8]; + + if (words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) words_bigendian = 1; + else words_bigendian = 0; + } + + if (size < 32) return 0; + + memcpy(header, data, 32); + if (words_bigendian) + { + int i; + + for (i = 0; i < 8; i++) SWAP32(header[i]); + } + if ((unsigned)header[0] == 0xac1dfeed) + { + int iw, ih, al, cp; + + iw = header[1]; + ih = header[2]; + al = header[3]; + cp = header[4]; + if ((iw < 1) || (ih < 1) || (iw > 8192) || (ih > 8192)) return 0; + if ((cp == 0) && (size < ((iw * ih * 4) + 32))) return 0; + if (w) *w = iw; + if (h) *h = ih; + if (alpha) *alpha = al ? 1 : 0; + if (compress) *compress = cp; + if (lossy) *lossy = 0; + if (quality) *quality = 100; + return 1; + } + else if ((unsigned)header[0] == 0xbeeff00d) + { + unsigned int iw = 0, ih = 0; + unsigned const char *dt; + int sz1, sz2; + int ok; + + sz1 = header[1]; + sz2 = header[2]; + dt = data; + dt += 12; + ok = eet_data_image_jpeg_header_decode(dt, sz1, &iw, &ih); + if (ok) + { + if (w) *w = iw; + if (h) *h = ih; + if (alpha) *alpha = 1; + if (compress) *compress = 0; + if (lossy) *lossy = 1; + if (quality) *quality = 75; + return 1; + } + } + else + { + unsigned int iw = 0, ih = 0; + int ok; + + ok = eet_data_image_jpeg_header_decode(data, size, &iw, &ih); + if (ok) + { + if (w) *w = iw; + if (h) *h = ih; + if (alpha) *alpha = 0; + if (compress) *compress = 0; + if (lossy) *lossy = 1; + if (quality) *quality = 75; + return 1; + } + } + return 0; +} + +static void +_eet_data_image_copy_buffer(const unsigned int *src, unsigned int src_x, unsigned int src_y, unsigned int src_w, + unsigned int *dst, unsigned int w, unsigned int h, unsigned int row_stride) +{ + src += src_x + src_y * src_w; + + if (row_stride == src_w * 4 && w == src_w) + { + memcpy(dst, src, row_stride * h); + } + else + { + unsigned int *over = dst; + unsigned int y; + + for (y = 0; y < h; ++y, src += src_w, over += row_stride) + memcpy(over, src, w * 4); + } +} + + +static int +_eet_data_image_decode_inside(const void *data, int size, unsigned int src_x, unsigned int src_y, + unsigned int src_w, unsigned int src_h, + unsigned int *d, unsigned int w, unsigned int h, unsigned int row_stride, + int alpha, int compress, int quality, int lossy) +{ + if (lossy == 0 && quality == 100) + { + unsigned int *body; + + body = ((unsigned int *)data) + 8; + if (!compress) + { + _eet_data_image_copy_buffer(body, src_x, src_y, src_w, d, w, h, row_stride); + } + else + { + if (src_h == h && src_w == w && row_stride == src_w * 4) + { + uLongf dlen; + + dlen = w * h * 4; + uncompress((Bytef *)d, &dlen, (Bytef *)body, + (uLongf)(size - 32)); + } + else + { + Bytef *dtmp; + uLongf dlen = src_w * src_h * 4; + + /* FIXME: This could create a huge alloc. So compressed data and tile could not always work. */ + dtmp = malloc(dlen); + if (!dtmp) return 0; + + uncompress(dtmp, &dlen, (Bytef *)body, (uLongf)(size - 32)); + + _eet_data_image_copy_buffer((unsigned int *) dtmp, src_x, src_y, src_w, d, w, h, row_stride); + + free(dtmp); + } + } + + /* Fix swapiness. */ + if (words_bigendian) + { + unsigned int x; + + for (x = 0; x < (w * h); x++) SWAP32(d[x]); + } + } + else if (compress == 0 && lossy == 1) + { + if (alpha) + { + unsigned const char *dt; + int header[8]; + int sz1, sz2; + + memcpy(header, data, 32); + if (words_bigendian) + { + int i; + + for (i = 0; i < 8; i++) SWAP32(header[i]); + } + + sz1 = header[1]; + sz2 = header[2]; + dt = data; + dt += 12; + + if (eet_data_image_jpeg_rgb_decode(dt, sz1, src_x, src_y, d, w, h, row_stride)) + { + dt += sz1; + if (!eet_data_image_jpeg_alpha_decode(dt, sz2, src_x, src_y, d, w, h, row_stride)) + return 0; + } + } + else + { + if (!eet_data_image_jpeg_rgb_decode(data, size, src_x, src_y, d, w, h, row_stride)) + return 0; + } + } + else + { + abort(); + } + + return 1; +} + +EAPI void * +eet_data_image_decode(const void *data, int size, unsigned int *w, unsigned int *h, int *alpha, int *compress, int *quality, int *lossy) +{ + unsigned int *d = NULL; + unsigned int iw, ih; + int ialpha, icompress, iquality, ilossy; + + /* All check are done during header decode, this simplify the code a lot. */ + if (!eet_data_image_header_decode(data, size, &iw, &ih, &ialpha, &icompress, &iquality, &ilossy)) + return NULL; + + d = malloc(iw * ih * 4); + if (!d) return NULL; + + if (!_eet_data_image_decode_inside(data, size, 0, 0, iw, ih, d, iw, ih, iw * 4, ialpha, icompress, iquality, ilossy)) + { + if (d) free(d); + return NULL; + } + + if (w) *w = iw; + if (h) *h = ih; + if (alpha) *alpha = ialpha; + if (compress) *compress = icompress; + if (quality) *quality = iquality; + if (lossy) *lossy = ilossy; + + return d; +} + +EAPI int +eet_data_image_decode_to_surface(const void *data, int size, unsigned int src_x, unsigned int src_y, + unsigned int *d, unsigned int w, unsigned int h, unsigned int row_stride, + int *alpha, int *compress, int *quality, int *lossy) +{ + unsigned int iw, ih; + int ialpha, icompress, iquality, ilossy; + + /* All check are done during header decode, this simplify the code a lot. */ + if (!eet_data_image_header_decode(data, size, &iw, &ih, &ialpha, &icompress, &iquality, &ilossy)) + return 0; + + if (!d) return 0; + if (w * 4 > row_stride) return 0; + if (w > iw || h > ih) return 0; + + if (!_eet_data_image_decode_inside(data, size, src_x, src_y, iw, ih, d, w, h, row_stride, ialpha, icompress, iquality, ilossy)) + return 0; + + if (alpha) *alpha = ialpha; + if (compress) *compress = icompress; + if (quality) *quality = iquality; + if (lossy) *lossy = ilossy; + + return 1; +} diff --git a/src/lib/eet_lib.c b/src/lib/eet_lib.c new file mode 100644 index 0000000..a2775d4 --- /dev/null +++ b/src/lib/eet_lib.c @@ -0,0 +1,1836 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_ALLOCA_H +# include +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include +# define alloca _alloca +#else +# include +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#if defined(_WIN32) && ! defined(__CEGCC__) +# include +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include "Eet.h" +#include "Eet_private.h" + +#ifdef HAVE_REALPATH +#undef HAVE_REALPATH +#endif + +#define EET_MAGIC_FILE 0x1ee7ff00 +#define EET_MAGIC_FILE_HEADER 0x1ee7ff01 + +#define EET_MAGIC_FILE2 0x1ee70f42 + +typedef struct _Eet_File_Header Eet_File_Header; +typedef struct _Eet_File_Node Eet_File_Node; +typedef struct _Eet_File_Directory Eet_File_Directory; + +struct _Eet_File +{ + char *path; + FILE *fp; + FILE *readfp; + Eet_File_Header *header; + const unsigned char *data; + Eet_Dictionary *ed; + + int magic; + int references; + + Eet_File_Mode mode; + int data_size; + time_t mtime; + + unsigned char writes_pending : 1; + unsigned char delete_me_now : 1; +}; + +struct _Eet_File_Header +{ + int magic; + Eet_File_Directory *directory; +}; + +struct _Eet_File_Directory +{ + int size; + Eet_File_Node **nodes; +}; + +struct _Eet_File_Node +{ + char *name; + void *data; + Eet_File_Node *next; /* FIXME: make buckets linked lists */ + + int offset; + int dictionary_offset; + int name_offset; + + int name_size; + int size; + int data_size; + + unsigned char free_name : 1; + unsigned char compression : 1; +}; + +#if 0 +/* Version 2 */ +/* NB: all int's are stored in network byte order on disk */ +/* file format: */ +int magic; /* magic number ie 0x1ee7ff00 */ +int num_directory_entries; /* number of directory entries to follow */ +int bytes_directory_entries; /* bytes of directory entries to follow */ +struct +{ + int offset; /* bytes offset into file for data chunk */ + int flags; /* flags - for now 0 = uncompressed, 1 = compressed */ + int size; /* size of the data chunk */ + int data_size; /* size of the (uncompressed) data chunk */ + int name_size; /* length in bytes of the name field */ + char name[name_size]; /* name string (variable length) and \0 terminated */ +} directory[num_directory_entries]; +/* and now startes the data stream... */ +#endif + +#if 0 +/* Version 3 */ +/* NB: all int's are stored in network byte order on disk */ +/* file format: */ +int magic; /* magic number ie 0x1ee70f42 */ +int num_directory_entries; /* number of directory entries to follow */ +int num_dictionary_entries; /* number of dictionary entries to follow */ +struct +{ + int data_offset; /* bytes offset into file for data chunk */ + int size; /* size of the data chunk */ + int data_size; /* size of the (uncompressed) data chunk */ + int name_offset; /* bytes offset into file for name string */ + int name_size; /* length in bytes of the name field */ + int flags; /* flags - for now 0 = uncompressed, 1 = compressed */ +} directory[num_directory_entries]; +struct +{ + int hash; + int offset; + int size; + int prev; + int next; +} dictionary[num_dictionary_entries]; +/* now start the string stream. */ +/* and right after them the data stream. */ +#endif + +#define EET_FILE2_HEADER_COUNT 3 +#define EET_FILE2_DIRECTORY_ENTRY_COUNT 6 +#define EET_FILE2_DICTIONARY_ENTRY_COUNT 5 + +#define EET_FILE2_HEADER_SIZE (sizeof(int) * EET_FILE2_HEADER_COUNT) +#define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) * EET_FILE2_DIRECTORY_ENTRY_COUNT) +#define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) * EET_FILE2_DICTIONARY_ENTRY_COUNT) + +/* prototypes of internal calls */ +static Eet_File *eet_cache_find(const char *path, Eet_File **cache, int cache_num); +static void eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc); +static void eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc); +static int eet_string_match(const char *s1, const char *s2); +#if 0 /* Unused */ +static Eet_Error eet_flush(Eet_File *ef); +#endif +static Eet_Error eet_flush2(Eet_File *ef); +static Eet_File_Node *find_node_by_name(Eet_File *ef, const char *name); +static int read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len); + +/* cache. i don't expect this to ever be large, so arrays will do */ +static int eet_writers_num = 0; +static int eet_writers_alloc = 0; +static Eet_File **eet_writers = NULL; +static int eet_readers_num = 0; +static int eet_readers_alloc = 0; +static Eet_File **eet_readers = NULL; +static int eet_initcount = 0; + +/* Check to see its' an eet file pointer */ +static inline int +eet_check_pointer(const Eet_File *ef) +{ + if ((!ef) || (ef->magic != EET_MAGIC_FILE)) + return 1; + return 0; +} + +static inline int +eet_check_header(const Eet_File *ef) +{ + if (!ef->header) + return 1; + if (!ef->header->directory) + return 1; + return 0; +} + +static inline int +eet_test_close(int test, Eet_File *ef) +{ + if (test) + { + ef->delete_me_now = 1; + eet_close(ef); + } + return test; +} + +/* find an eet file in the currently in use cache */ +static Eet_File * +eet_cache_find(const char *path, Eet_File **cache, int cache_num) +{ + int i; + + /* walk list */ + for (i = 0; i < cache_num; i++) + { + /* if matches real path - return it */ + if (eet_string_match(cache[i]->path, path)) + { + if (!cache[i]->delete_me_now) + return cache[i]; + } + } + + /* not found */ + return NULL; +} + +/* add to end of cache */ +static void +eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc) +{ + Eet_File **new_cache; + int new_cache_num; + int new_cache_alloc; + + new_cache_num = *cache_num; + if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */ + { + Eet_File *del_ef = NULL; + int i; + + new_cache = *cache; + for (i = 0; i < new_cache_num; i++) + { + if (new_cache[i]->references == 0) + { + del_ef = new_cache[i]; + break; + } + } + + if (del_ef) + { + del_ef->delete_me_now = 1; + eet_close(del_ef); + } + } + + new_cache = *cache; + new_cache_num = *cache_num; + new_cache_alloc = *cache_alloc; + new_cache_num++; + if (new_cache_num > new_cache_alloc) + { + new_cache_alloc += 16; + new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *)); + if (!new_cache) + { + fprintf(stderr, "BAD ERROR! Eet realloc of cache list failed. Abort\n"); + abort(); + } + } + new_cache[new_cache_num - 1] = ef; + *cache = new_cache; + *cache_num = new_cache_num; + *cache_alloc = new_cache_alloc; +} + +/* delete from cache */ +static void +eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc) +{ + Eet_File **new_cache; + int new_cache_num, new_cache_alloc; + int i, j; + + new_cache = *cache; + new_cache_num = *cache_num; + new_cache_alloc = *cache_alloc; + if (new_cache_num <= 0) + return; + + for (i = 0; i < new_cache_num; i++) + { + if (new_cache[i] == ef) + break; + } + + if (i >= new_cache_num) + return; + + new_cache_num--; + for (j = i; j < new_cache_num; j++) + new_cache[j] = new_cache[j + 1]; + + if (new_cache_num < (new_cache_alloc - 16)) + { + new_cache_alloc -= 16; + if (new_cache_num > 0) + { + new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *)); + if (!new_cache) + { + fprintf(stderr, "BAD ERROR! Eet realloc of cache list failed. Abort\n"); + abort(); + } + } + else + { + free(new_cache); + new_cache = NULL; + } + } + *cache = new_cache; + *cache_num = new_cache_num; + *cache_alloc = new_cache_alloc; +} + +/* internal string match. null friendly, catches same ptr */ +static int +eet_string_match(const char *s1, const char *s2) +{ + /* both null- no match */ + if ((!s1) || (!s2)) return 0; + if (s1 == s2) return 1; + return (!strcmp(s1, s2)); +} + +/* flush out writes to a v2 eet file */ +static Eet_Error +eet_flush2(Eet_File *ef) +{ + Eet_File_Node *efn; + Eet_Error error = EET_ERROR_NONE; + int head[EET_FILE2_HEADER_COUNT]; + int num_directory_entries = 0; + int num_dictionary_entries = 0; + int bytes_directory_entries = 0; + int bytes_dictionary_entries = 0; + int bytes_strings = 0; + int data_offset = 0; + int strings_offset = 0; + int num; + int i; + int j; + + if (eet_check_pointer(ef)) + return EET_ERROR_BAD_OBJECT; + if (eet_check_header(ef)) + return EET_ERROR_EMPTY; + if ((ef->mode != EET_FILE_MODE_WRITE) && (ef->mode != EET_FILE_MODE_READ_WRITE)) + return EET_ERROR_NOT_WRITABLE; + if (!ef->writes_pending) + return EET_ERROR_NONE; + if (ef->mode == EET_FILE_MODE_READ_WRITE && ef->fp == NULL) + { + unlink(ef->path); + ef->fp = fopen(ef->path, "wb"); + if (!ef->fp) return EET_ERROR_NOT_WRITABLE; + fcntl(fileno(ef->fp), F_SETFD, FD_CLOEXEC); + } + + /* calculate string base offset and data base offset */ + num = (1 << ef->header->directory->size); + for (i = 0; i < num; ++i) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + { + num_directory_entries++; + bytes_strings += strlen(efn->name) + 1; + } + } + if (ef->ed) + { + num_dictionary_entries = ef->ed->count; + + for (i = 0; i < num_dictionary_entries; ++i) + bytes_strings += ef->ed->all[i].len; + } + + /* calculate section bytes size */ + bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE; + bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries; + + /* calculate per entry offset */ + strings_offset = bytes_directory_entries + bytes_dictionary_entries; + data_offset = bytes_directory_entries + bytes_dictionary_entries + bytes_strings; + + for (i = 0; i < num; ++i) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + { + efn->offset = data_offset; + data_offset += efn->size; + + efn->name_offset = strings_offset; + strings_offset += efn->name_size; + } + } + + /* calculate dictionary strings offset */ + if (ef->ed) + ef->ed->offset = strings_offset; + + /* go thru and write the header */ + head[0] = (int) htonl ((unsigned int) EET_MAGIC_FILE2); + head[1] = (int) htonl ((unsigned int) num_directory_entries); + head[2] = (int) htonl ((unsigned int) num_dictionary_entries); + + fseek(ef->fp, 0, SEEK_SET); + if (fwrite(head, sizeof (head), 1, ef->fp) != 1) + goto write_error; + + /* write directories entry */ + j = 0; + for (i = 0; i < num; i++) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + { + int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT]; + + ibuf[0] = (int) htonl ((unsigned int) efn->offset); + ibuf[1] = (int) htonl ((unsigned int) efn->size); + ibuf[2] = (int) htonl ((unsigned int) efn->data_size); + ibuf[3] = (int) htonl ((unsigned int) efn->name_offset); + ibuf[4] = (int) htonl ((unsigned int) efn->name_size); + ibuf[5] = (int) htonl ((unsigned int) efn->compression); + + if (fwrite(ibuf, sizeof(ibuf), 1, ef->fp) != 1) + goto write_error; + } + } + + /* write dictionnary */ + if (ef->ed) + { + int offset = strings_offset; + + for (j = 0; j < ef->ed->count; ++j) + { + int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT]; + + sbuf[0] = (int) htonl ((unsigned int) ef->ed->all[j].hash); + sbuf[1] = (int) htonl ((unsigned int) offset); + sbuf[2] = (int) htonl ((unsigned int) ef->ed->all[j].len); + sbuf[3] = (int) htonl ((unsigned int) ef->ed->all[j].prev); + sbuf[4] = (int) htonl ((unsigned int) ef->ed->all[j].next); + + offset += ef->ed->all[j].len; + + if (fwrite(sbuf, sizeof (sbuf), 1, ef->fp) != 1) + goto write_error; + } + } + + /* write directories name */ + for (i = 0; i < num; i++) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + { + if (fwrite(efn->name, efn->name_size, 1, ef->fp) != 1) + goto write_error; + } + } + + /* write strings */ + if (ef->ed) + { + for (j = 0; j < ef->ed->count; ++j) + { + if (ef->ed->all[j].str) + { + if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, ef->fp) != 1) + goto write_error; + } + else + { + if (fwrite(ef->ed->all[j].mmap, ef->ed->all[j].len, 1, ef->fp) != 1) + goto write_error; + } + } + } + + /* write data */ + for (i = 0; i < num; i++) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + { + if (fwrite(efn->data, efn->size, 1, ef->fp) != 1) + goto write_error; + } + } + + /* no more writes pending */ + ef->writes_pending = 0; + + return EET_ERROR_NONE; + + write_error: + switch (ferror(ef->fp)) + { + case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break; + case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break; + case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break; + case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break; + default: error = EET_ERROR_WRITE_ERROR; break; + } + if (ef->fp) fclose(ef->fp); + ef->fp = NULL; + return error; +} + +#if 0 /* Unused */ +/* flush out writes to an eet file */ +static Eet_Error +eet_flush(Eet_File *ef) +{ + Eet_File_Node *efn; + int head[3]; + int count = 0; + int size = 0; + int offset = 0; + int i; + int num; + + /* check to see its' an eet file pointer */ + if (eet_check_pointer(ef)) + return EET_ERROR_BAD_OBJECT; + if (eet_check_header(ef)) + return EET_ERROR_EMPTY; + if ((ef->mode != EET_FILE_MODE_WRITE) && (ef->mode != EET_FILE_MODE_READ_WRITE)) + return EET_ERROR_NOT_WRITABLE; + if (!ef->writes_pending) + return EET_ERROR_NONE; + + /* calculate total size in bytes of directory block */ + num = (1 << ef->header->directory->size); + for (i = 0; i < num; i++) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + { + size += 20 + strlen(efn->name) + 1; + count++; + } + } + + /* calculate offsets per entry */ + offset = 0; + for (i = 0; i < num; i++) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + { + efn->offset = 12 + size + offset; + offset += efn->size; + } + } + + /* go thru and write the header */ + head[0] = (int) htonl ((unsigned int) EET_MAGIC_FILE); + head[1] = (int) htonl ((unsigned int) count); + head[2] = (int) htonl ((unsigned int) size); + + fseek(ef->fp, 0, SEEK_SET); + if (fwrite(head, 12, 1, ef->fp) != 1) + goto write_error; + + for (i = 0; i < num; i++) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + { + unsigned int ibuf[5]; + int name_size; + + name_size = strlen(efn->name) + 1; + + ibuf[0] = (int) htonl ((unsigned int) efn->offset); + ibuf[1] = (int) htonl ((unsigned int) efn->compression); + ibuf[2] = (int) htonl ((unsigned int) efn->size); + ibuf[3] = (int) htonl ((unsigned int) efn->data_size); + ibuf[4] = (int) htonl ((unsigned int) name_size); + + + if (fwrite(ibuf, sizeof(ibuf), 1, ef->fp) != 1) + goto write_error; + if (fwrite(efn->name, name_size, 1, ef->fp) != 1) + goto write_error; + } + } + + /* write data */ + for (i = 0; i < num; i++) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + { + if (fwrite(efn->data, efn->size, 1, ef->fp) != 1) + goto write_error; + } + } + + /* no more writes pending */ + ef->writes_pending = 0; + + return EET_ERROR_NONE; + + write_error: + switch (ferror(ef->fp)) + { + case EFBIG: + fclose(ef->fp); + ef->fp = NULL; + return EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; + case EIO: + fclose(ef->fp); + ef->fp = NULL; + return EET_ERROR_WRITE_ERROR_IO_ERROR; + case ENOSPC: + fclose(ef->fp); + ef->fp = NULL; + return EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; + case EPIPE: + fclose(ef->fp); + ef->fp = NULL; + return EET_ERROR_WRITE_ERROR_FILE_CLOSED; + default: + fclose(ef->fp); + ef->fp = NULL; + return EET_ERROR_WRITE_ERROR; + } + fclose(ef->fp); + ef->fp = NULL; + return EET_ERROR_WRITE_ERROR; +} +#endif + +EAPI int +eet_init(void) +{ + return ++eet_initcount; +} + +EAPI int +eet_shutdown(void) +{ + if (--eet_initcount == 0) + { + eet_clearcache(); + _eet_memfile_shutdown(); + } + + return eet_initcount; +} + +EAPI void +eet_clearcache(void) +{ + int num = 0; + int i; + + /* + * We need to compute the list of eet file to close separately from the cache, + * due to eet_close removing them from the cache after each call. + */ + for (i = 0; i < eet_writers_num; i++) + { + if (eet_writers[i]->references <= 0) num++; + } + + for (i = 0; i < eet_readers_num; i++) + { + if (eet_readers[i]->references <= 0) num++; + } + + if (num > 0) + { + Eet_File **closelist = NULL; + + closelist = alloca(num * sizeof(Eet_File *)); + num = 0; + for (i = 0; i < eet_writers_num; i++) + { + if (eet_writers[i]->references <= 0) + { + closelist[num] = eet_writers[i]; + eet_writers[i]->delete_me_now = 1; + num++; + } + } + + for (i = 0; i < eet_readers_num; i++) + { + if (eet_readers[i]->references <= 0) + { + closelist[num] = eet_readers[i]; + eet_readers[i]->delete_me_now = 1; + num++; + } + } + + for (i = 0; i < num; i++) + { + eet_close(closelist[i]); + } + } +} + +/* FIXME: MMAP race condition in READ_WRITE_MODE */ +static Eet_File * +eet_internal_read2(Eet_File *ef) +{ + const int *data = (const int*) ef->data; + const char *start = (const char*) ef->data; + int index = 0; + int num_directory_entries; + int bytes_directory_entries; + int num_dictionary_entries; + int bytes_dictionary_entries; + int i; + + index += sizeof(int); + if (eet_test_close((int) ntohl(*data) != EET_MAGIC_FILE2, ef)) + return NULL; + data++; + +#define GET_INT(Value, Pointer, Index) \ + { \ + Value = ntohl(*Pointer); \ + Pointer++; \ + Index += sizeof(int); \ + } + + /* get entries count and byte count */ + GET_INT(num_directory_entries, data, index); + /* get dictionary count and byte count */ + GET_INT(num_dictionary_entries, data, index); + + bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE; + bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries; + + /* we cant have <= 0 values here - invalid */ + if (eet_test_close((num_directory_entries <= 0), ef)) + return NULL; + + /* we cant have more bytes directory and bytes in dictionaries than the size of the file */ + if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) > ef->data_size, ef)) + return NULL; + + /* allocate header */ + ef->header = calloc(1, sizeof(Eet_File_Header)); + if (eet_test_close(!ef->header, ef)) + return NULL; + + ef->header->magic = EET_MAGIC_FILE_HEADER; + + /* allocate directory block in ram */ + ef->header->directory = calloc(1, sizeof(Eet_File_Directory)); + if (eet_test_close(!ef->header->directory, ef)) + return NULL; + + /* 8 bit hash table (256 buckets) */ + ef->header->directory->size = 8; + /* allocate base hash table */ + ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size)); + if (eet_test_close(!ef->header->directory->nodes, ef)) + return NULL; + + /* actually read the directory block - all of it, into ram */ + for (i = 0; i < num_directory_entries; ++i) + { + const char *name; + Eet_File_Node *efn; + int name_offset; + int name_size; + int hash; + + /* out directory block is inconsistent - we have oveerun our */ + /* dynamic block buffer before we finished scanning dir entries */ + efn = malloc (sizeof(Eet_File_Node)); + if (eet_test_close(!efn, ef)) + return NULL; + + /* get entrie header */ + GET_INT(efn->offset, data, index); + GET_INT(efn->size, data, index); + GET_INT(efn->data_size, data, index); + GET_INT(name_offset, data, index); + GET_INT(name_size, data, index); + GET_INT(efn->compression, data, index); + +#define EFN_TEST(Test, Ef, Efn) \ + if (eet_test_close(Test, Ef)) \ + { \ + free(Efn); \ + return NULL; \ + } + + /* check data pointer position */ + EFN_TEST(!((efn->size > 0) + && (efn->offset + efn->size <= ef->data_size) + && (efn->offset > bytes_dictionary_entries + bytes_directory_entries)), ef, efn); + + /* check name position */ + EFN_TEST(!((name_size > 0) + && (name_offset + name_size < ef->data_size) + && (name_offset >= bytes_dictionary_entries + bytes_directory_entries)), ef, efn); + + name = start + name_offset; + + /* check '\0' at the end of name string */ + EFN_TEST(name[name_size - 1] != '\0', ef, efn); + + efn->free_name = 0; + efn->name = (char*) name; + efn->name_size = name_size; + + hash = _eet_hash_gen(efn->name, ef->header->directory->size); + efn->next = ef->header->directory->nodes[hash]; + ef->header->directory->nodes[hash] = efn; + + /* read-only mode, so currently we have no data loaded */ + if (ef->mode == EET_FILE_MODE_READ) + efn->data = NULL; + /* read-write mode - read everything into ram */ + else + { + efn->data = malloc(efn->size); + if (efn->data) + memcpy(efn->data, ef->data + efn->offset, efn->size); + } + } + + ef->ed = NULL; + + if (num_dictionary_entries) + { + const int *dico = (const int*) ef->data + EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries + EET_FILE2_HEADER_COUNT; + int j; + + if (eet_test_close((num_directory_entries * EET_FILE2_DICTIONARY_ENTRY_SIZE + index) > (bytes_dictionary_entries + bytes_directory_entries), ef)) + return NULL; + + ef->ed = calloc(1, sizeof (Eet_Dictionary)); + if (eet_test_close(!ef->ed, ef)) return NULL; + + ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String)); + if (eet_test_close(!ef->ed->all, ef)) return NULL; + + ef->ed->count = num_dictionary_entries; + ef->ed->total = num_dictionary_entries; + ef->ed->start = start + bytes_dictionary_entries + bytes_directory_entries; + ef->ed->end = ef->ed->start; + + for (j = 0; j < ef->ed->count; ++j) + { + int hash; + int offset; + + GET_INT(hash, dico, index); + GET_INT(offset, dico, index); + GET_INT(ef->ed->all[j].len, dico, index); + GET_INT(ef->ed->all[j].prev, dico, index); + GET_INT(ef->ed->all[j].next, dico, index); + + /* Hash value could be stored on 8bits data, but this will break alignment of all the others data. + So stick to int and check the value. */ + if (eet_test_close(hash & 0xFFFFFF00, ef)) return NULL; + + /* Check string position */ + if (eet_test_close(!((ef->ed->all[j].len > 0) + && (offset > (bytes_dictionary_entries + bytes_directory_entries)) + && (offset + ef->ed->all[j].len < ef->data_size)), ef)) + return NULL; + + ef->ed->all[j].mmap = start + offset; + ef->ed->all[j].str = NULL; + + if (ef->ed->all[j].mmap + ef->ed->all[j].len > ef->ed->end) + ef->ed->end = ef->ed->all[j].mmap + ef->ed->all[j].len; + + /* Check '\0' at the end of the string */ + if (eet_test_close(ef->ed->all[j].mmap[ef->ed->all[j].len - 1] != '\0', ef)) return NULL; + + ef->ed->all[j].hash = hash; + if (ef->ed->all[j].prev == -1) + ef->ed->hash[hash] = j; + } + } + + return ef; +} + +#if EET_OLD_EET_FILE_FORMAT +static Eet_File * +eet_internal_read1(Eet_File *ef) +{ + const unsigned char *dyn_buf = NULL; + const unsigned char *p = NULL; + int index = 0; + int num_entries; + int byte_entries; + int i; + + fprintf(stderr, "EET file format of '%s' is deprecated. You should just open it one time with mode == EET_FILE_MODE_READ_WRITE to solve this issue.\n", ef->path); + + /* build header table if read mode */ + /* geat header */ + index += sizeof(int); + if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef)) + return NULL; + +#define EXTRACT_INT(Value, Pointer, Index) \ + { \ + int tmp; \ + memcpy(&tmp, Pointer + Index, sizeof(int)); \ + Value = ntohl(tmp); \ + Index += sizeof(int); \ + } + + /* get entries count and byte count */ + EXTRACT_INT(num_entries, ef->data, index); + EXTRACT_INT(byte_entries, ef->data, index); + + /* we cant have <= 0 values here - invalid */ + if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef)) + return NULL; + + /* we can't have more entires than minimum bytes for those! invalid! */ + if (eet_test_close((num_entries * 20) > byte_entries, ef)) + return NULL; + + /* check we will not outrun the file limit */ + if (eet_test_close(((byte_entries + sizeof(int) * 3) > ef->data_size), ef)) + return NULL; + + /* allocate header */ + ef->header = calloc(1, sizeof(Eet_File_Header)); + if (eet_test_close(!ef->header, ef)) + return NULL; + + ef->header->magic = EET_MAGIC_FILE_HEADER; + + /* allocate directory block in ram */ + ef->header->directory = calloc(1, sizeof(Eet_File_Directory)); + if (eet_test_close(!ef->header->directory, ef)) + return NULL; + + /* 8 bit hash table (256 buckets) */ + ef->header->directory->size = 8; + /* allocate base hash table */ + ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size)); + if (eet_test_close(!ef->header->directory->nodes, ef)) + return NULL; + + /* actually read the directory block - all of it, into ram */ + dyn_buf = ef->data + index; + + /* parse directory block */ + p = dyn_buf; + + for (i = 0; i < num_entries; i++) + { + Eet_File_Node *efn; + void *data = NULL; + int indexn = 0; + int name_size; + int hash; + int k; + +#define HEADER_SIZE (sizeof(int) * 5) + + /* out directory block is inconsistent - we have oveerun our */ + /* dynamic block buffer before we finished scanning dir entries */ + if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef)) + return NULL; + + /* allocate all the ram needed for this stored node accounting */ + efn = malloc (sizeof(Eet_File_Node)); + if (eet_test_close(!efn, ef)) + return NULL; + + /* get entrie header */ + EXTRACT_INT(efn->offset, p, indexn); + EXTRACT_INT(efn->compression, p, indexn); + EXTRACT_INT(efn->size, p, indexn); + EXTRACT_INT(efn->data_size, p, indexn); + EXTRACT_INT(name_size, p, indexn); + + efn->name_size = name_size; + + /* invalid size */ + if (eet_test_close(efn->size <= 0, ef)) + { + free (efn); + return NULL; + } + + /* invalid name_size */ + if (eet_test_close(name_size <= 0, ef)) + { + free (efn); + return NULL; + } + + /* reading name would mean falling off end of dyn_buf - invalid */ + if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef)) + { + free (efn); + return NULL; + } + + /* This code is useless if we dont want backward compatibility */ + for (k = name_size; k > 0 && ((unsigned char) * (p + HEADER_SIZE + k)) != 0; --k) + ; + + efn->free_name = ((unsigned char) * (p + HEADER_SIZE + k)) != 0; + + if (efn->free_name) + { + efn->name = malloc(sizeof(char) * name_size + 1); + if (eet_test_close(efn->name == NULL, ef)) + { + free (efn); + return NULL; + } + + strncpy(efn->name, (char *)p + HEADER_SIZE, name_size); + efn->name[name_size] = 0; + + printf("File: %s is not up to date for key \"%s\" - needs rebuilding sometime\n", ef->path, efn->name); + } + else + /* The only really usefull peace of code for efn->name (no backward compatibility) */ + efn->name = (char*)((unsigned char*)(p + HEADER_SIZE)); + + /* get hash bucket it should go in */ + hash = _eet_hash_gen(efn->name, ef->header->directory->size); + efn->next = ef->header->directory->nodes[hash]; + ef->header->directory->nodes[hash] = efn; + + /* read-only mode, so currently we have no data loaded */ + if (ef->mode == EET_FILE_MODE_READ) + efn->data = NULL; + /* read-write mode - read everything into ram */ + else + { + data = malloc(efn->size); + if (data) + memcpy(data, ef->data + efn->offset, efn->size); + efn->data = data; + } + /* advance */ + p += HEADER_SIZE + name_size; + } + return ef; +} +#endif + +static Eet_File * +eet_internal_read(Eet_File *ef) +{ + const int *data = (const int*) ef->data; + + if (eet_test_close((ef->data == (void *)-1) || (ef->data == NULL), ef)) + return NULL; + + if (eet_test_close(ef->data_size < sizeof(int) * 3, ef)) + return NULL; + + switch (ntohl(*data)) + { +#if EET_OLD_EET_FILE_FORMAT + case EET_MAGIC_FILE: + return eet_internal_read1(ef); +#endif + case EET_MAGIC_FILE2: + return eet_internal_read2(ef); + default: + ef->delete_me_now = 1; + eet_close(ef); + break; + } + + return NULL; +} + +#if 0 /* No prototype */ +EAPI Eet_File * +eet_memopen_read(const void *data, size_t size) +{ + Eet_File *ef; + + if (data == NULL || size == 0) + return NULL; + + ef = malloc (sizeof (Eet_File)); + if (!ef) + return NULL; + + ef->ed = NULL; + ef->path = NULL; + ef->magic = EET_MAGIC_FILE; + ef->references = 1; + ef->mode = EET_FILE_MODE_READ; + ef->header = NULL; + ef->mtime = 0; + ef->delete_me_now = 1; + ef->fp = NULL; + ef->data = data; + ef->data_size = size; + + return eet_internal_read(ef); +} +#endif + +EAPI Eet_File * +eet_open(const char *file, Eet_File_Mode mode) +{ + FILE *fp; + Eet_File *ef; + int file_len; + struct stat file_stat; + + if (!file) + return NULL; + + /* find the current file handle in cache*/ + ef = NULL; + if (mode == EET_FILE_MODE_READ) + { + ef = eet_cache_find((char *)file, eet_writers, eet_writers_num); + if (ef) + { + eet_flush2(ef); + ef->references++; + ef->delete_me_now = 1; + eet_close(ef); + } + ef = eet_cache_find((char *)file, eet_readers, eet_readers_num); + } + else if ((mode == EET_FILE_MODE_WRITE) || + (mode == EET_FILE_MODE_READ_WRITE)) + { + ef = eet_cache_find((char *)file, eet_readers, eet_readers_num); + if (ef) + { + ef->delete_me_now = 1; + ef->references++; + eet_close(ef); + } + ef = eet_cache_find((char *)file, eet_writers, eet_writers_num); + } + + /* try open the file based on mode */ + if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE)) + { + fp = fopen(file, "rb"); + if (!fp) goto on_error; + if (fstat(fileno(fp), &file_stat)) + { + fclose(fp); + fp = NULL; + goto on_error; + } + if ((mode == EET_FILE_MODE_READ) && + (file_stat.st_size < (sizeof(int) * 3))) + { + fclose(fp); + fp = NULL; + goto on_error; + } + + on_error: + if (fp == NULL && mode == EET_FILE_MODE_READ) return NULL; + } + else + { + if (mode != EET_FILE_MODE_WRITE) return NULL; + memset(&file_stat, 0, sizeof(file_stat)); + /* opening for write - delete old copy of file right away */ + unlink(file); + fp = fopen(file, "wb"); + } + + /* We found one */ + if (ef && (file_stat.st_mtime != ef->mtime)) + { + ef->delete_me_now = 1; + ef->references++; + eet_close(ef); + ef = NULL; + } + + if (ef) + { + /* reference it up and return it */ + if (fp != NULL) fclose(fp); + ef->references++; + return ef; + } + + file_len = strlen(file) + 1; + + /* Allocate struct for eet file and have it zero'd out */ + ef = malloc(sizeof(Eet_File) + file_len); + if (!ef) + return NULL; + + /* fill some of the members */ + ef->fp = fp; + ef->readfp = NULL; + ef->path = ((char *)ef) + sizeof(Eet_File); + memcpy(ef->path, file, file_len); + ef->magic = EET_MAGIC_FILE; + ef->references = 1; + ef->mode = mode; + ef->header = NULL; + ef->mtime = file_stat.st_mtime; + ef->writes_pending = 0; + ef->delete_me_now = 0; + ef->data = NULL; + ef->data_size = 0; + + ef->ed = (mode == EET_FILE_MODE_WRITE) + || (ef->fp == NULL && mode == EET_FILE_MODE_READ_WRITE) ? + eet_dictionary_add() : NULL; + + if (ef->fp == NULL && mode == EET_FILE_MODE_READ_WRITE) goto empty_file; + + /* if we can't open - bail out */ + if (eet_test_close(!ef->fp, ef)) + return NULL; + + fcntl(fileno(ef->fp), F_SETFD, FD_CLOEXEC); + /* if we opened for read or read-write */ + if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE)) + { + ef->data_size = file_stat.st_size; + ef->data = mmap(NULL, ef->data_size, PROT_READ, + MAP_SHARED, fileno(ef->fp), 0); + if (eet_test_close((ef->data == MAP_FAILED), ef)) + return NULL; + ef = eet_internal_read(ef); + if (!ef) + return NULL; + } + + empty_file: + /* we need to delete the original file in read-write mode and re-open for writing */ + if (ef->mode == EET_FILE_MODE_READ_WRITE) + { + ef->readfp = ef->fp; + ef->fp = NULL; + } + + /* add to cache */ + if (ef->references == 1) + { + if (ef->mode == EET_FILE_MODE_READ) + eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc); + else + if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE)) + eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc); + } + + return ef; +} + +EAPI Eet_File_Mode +eet_mode_get(Eet_File *ef) +{ + /* check to see its' an eet file pointer */ + if ((!ef) || (ef->magic != EET_MAGIC_FILE)) + return EET_FILE_MODE_INVALID; + else + return ef->mode; +} + +EAPI Eet_Error +eet_close(Eet_File *ef) +{ + Eet_Error err; + + /* check to see its' an eet file pointer */ + if (eet_check_pointer(ef)) + return EET_ERROR_BAD_OBJECT; + /* deref */ + ef->references--; + /* if its still referenced - dont go any further */ + if (ef->references > 0) return EET_ERROR_NONE; + /* flush any writes */ + err = eet_flush2(ef); + + /* if not urgent to delete it - dont free it - leave it in cache */ + if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ)) + return EET_ERROR_NONE; + + /* remove from cache */ + if (ef->mode == EET_FILE_MODE_READ) + eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc); + else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE)) + eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc); + + /* free up data */ + if (ef->header) + { + if (ef->header->directory) + { + if (ef->header->directory->nodes) + { + int i, num; + + num = (1 << ef->header->directory->size); + for (i = 0; i < num; i++) + { + Eet_File_Node *efn; + + while ((efn = ef->header->directory->nodes[i])) + { + if (efn->data) + free(efn->data); + + ef->header->directory->nodes[i] = efn->next; + + if (efn->free_name) + free(efn->name); + + free(efn); + } + } + free(ef->header->directory->nodes); + } + free(ef->header->directory); + } + free(ef->header); + } + + eet_dictionary_free(ef->ed); + + if (ef->data) munmap((void*)ef->data, ef->data_size); + if (ef->fp) fclose(ef->fp); + if (ef->readfp) fclose(ef->readfp); + + /* zero out ram for struct - caution tactic against stale memory use */ + memset(ef, 0, sizeof(Eet_File)); + + /* free it */ + free(ef); + return err; +} + +EAPI void * +eet_read(Eet_File *ef, const char *name, int *size_ret) +{ + void *data = NULL; + int size = 0; + Eet_File_Node *efn; + + if (size_ret) + *size_ret = 0; + + /* check to see its' an eet file pointer */ + if (eet_check_pointer(ef)) + return NULL; + if (!name) + return NULL; + if ((ef->mode != EET_FILE_MODE_READ) && + (ef->mode != EET_FILE_MODE_READ_WRITE)) + return NULL; + + /* no header, return NULL */ + if (eet_check_header(ef)) + return NULL; + + /* hunt hash bucket */ + efn = find_node_by_name(ef, name); + if (!efn) + return NULL; + + /* get size (uncompressed, if compressed at all) */ + size = efn->data_size; + + /* allocate data */ + data = malloc(size); + if (!data) + return NULL; + + /* uncompressed data */ + if (efn->compression == 0) + { + /* if we alreayd have the data in ram... copy that */ + if (efn->data) + memcpy(data, efn->data, efn->size); + else + if (!read_data_from_disk(ef, efn, data, size)) + { + free(data); + return NULL; + } + } + /* compressed data */ + else + { + void *tmp_data; + int free_tmp = 0; + int compr_size = efn->size; + uLongf dlen; + + /* if we already have the data in ram... copy that */ + if (efn->data) + tmp_data = efn->data; + else + { + tmp_data = malloc(compr_size); + if (!tmp_data) + { + free(data); + return NULL; + } + + free_tmp = 1; + + if (!read_data_from_disk(ef, efn, tmp_data, compr_size)) + { + free(tmp_data); + free(data); + return NULL; + } + } + + /* decompress it */ + dlen = size; + if (uncompress((Bytef *)data, &dlen, + tmp_data, (uLongf)compr_size)) + { + free(data); + return NULL; + } + + if (free_tmp) + free(tmp_data); + } + + /* fill in return values */ + if (size_ret) + *size_ret = size; + + return data; +} + +EAPI const void * +eet_read_direct(Eet_File *ef, const char *name, int *size_ret) +{ + const void *data = NULL; + int size = 0; + Eet_File_Node *efn; + + if (size_ret) + *size_ret = 0; + + /* check to see its' an eet file pointer */ + if (eet_check_pointer(ef)) + return NULL; + if (!name) + return NULL; + if ((ef->mode != EET_FILE_MODE_READ) && + (ef->mode != EET_FILE_MODE_READ_WRITE)) + return NULL; + + /* no header, return NULL */ + if (eet_check_header(ef)) + return NULL; + + /* hunt hash bucket */ + efn = find_node_by_name(ef, name); + if (!efn) + return NULL; + + if (efn->offset < 0 && efn->data == NULL) + return NULL; + + /* get size (uncompressed, if compressed at all) */ + size = efn->data_size; + + /* uncompressed data */ + if (efn->compression == 0) + data = efn->data ? efn->data : ef->data + efn->offset; + /* compressed data */ + else + data = NULL; + + /* fill in return values */ + if (size_ret) + *size_ret = size; + + return data; +} + +EAPI int +eet_write(Eet_File *ef, const char *name, const void *data, int size, int compress) +{ + Eet_File_Node *efn; + void *data2; + int exists_already = 0; + int data_size; + int hash; + + /* check to see its' an eet file pointer */ + if (eet_check_pointer(ef)) + return 0; + if ((!name) || (!data) || (size <= 0)) + return 0; + if ((ef->mode != EET_FILE_MODE_WRITE) && + (ef->mode != EET_FILE_MODE_READ_WRITE)) + return 0; + + if (!ef->header) + { + /* allocate header */ + ef->header = calloc(1, sizeof(Eet_File_Header)); + if (!ef->header) + return 0; + + ef->header->magic = EET_MAGIC_FILE_HEADER; + /* allocate directory block in ram */ + ef->header->directory = calloc(1, sizeof(Eet_File_Directory)); + if (!ef->header->directory) + return 0; + + /* 8 bit hash table (256 buckets) */ + ef->header->directory->size = 8; + /* allocate base hash table */ + ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size)); + if (!ef->header->directory->nodes) + return 0; + } + + /* figure hash bucket */ + hash = _eet_hash_gen(name, ef->header->directory->size); + + data_size = compress ? 12 + ((size * 101) / 100) : size; + + data2 = malloc(data_size); + if (!data2) + return 0; + + /* if we want to compress */ + if (compress) + { + uLongf buflen; + + /* compress the data with max compression */ + buflen = (uLongf)data_size; + if (compress2((Bytef *)data2, &buflen, (Bytef *)data, + (uLong)size, Z_BEST_COMPRESSION) != Z_OK) + { + free(data2); + return 0; + } + /* record compressed chunk size */ + data_size = (int)buflen; + if (data_size < 0 || data_size >= size) + { + compress = 0; + data_size = size; + } + else + { + void *data3; + + data3 = realloc(data2, data_size); + if (data3) + data2 = data3; + } + } + if (!compress) + memcpy(data2, data, size); + + /* Does this node already exist? */ + for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next) + { + /* if it matches */ + if ((efn->name) && (eet_string_match(efn->name, name))) + { + free(efn->data); + efn->compression = !!compress; + efn->size = data_size; + efn->data_size = size; + efn->data = data2; + efn->offset = -1; + exists_already = 1; + break; + } + } + if (!exists_already) + { + efn = malloc(sizeof(Eet_File_Node)); + if (!efn) + { + free(data2); + return 0; + } + efn->name = strdup(name); + efn->name_size = strlen(efn->name) + 1; + efn->free_name = 1; + + efn->next = ef->header->directory->nodes[hash]; + ef->header->directory->nodes[hash] = efn; + efn->offset = -1; + efn->compression = !!compress; + efn->size = data_size; + efn->data_size = size; + efn->data = data2; + } + + /* flags that writes are pending */ + ef->writes_pending = 1; + return data_size; +} + +EAPI int +eet_delete(Eet_File *ef, const char *name) +{ + Eet_File_Node *efn; + Eet_File_Node *pefn; + int hash; + int exists_already = 0; + + /* check to see its' an eet file pointer */ + if (eet_check_pointer(ef)) + return 0; + if (!name) + return 0; + + /* deleting keys is only possible in RW or WRITE mode */ + if (ef->mode == EET_FILE_MODE_READ) + return 0; + + if (eet_check_header(ef)) + return 0; + + /* figure hash bucket */ + hash = _eet_hash_gen(name, ef->header->directory->size); + + /* Does this node already exist? */ + for (pefn = NULL, efn = ef->header->directory->nodes[hash]; + efn; + pefn = efn, efn = efn->next) + { + /* if it matches */ + if (eet_string_match(efn->name, name)) + { + if (efn->data) + free(efn->data); + + if (efn == ef->header->directory->nodes[hash]) + ef->header->directory->nodes[hash] = efn->next; + else + pefn->next = efn->next; + + if (efn->free_name) free(efn->name); + free(efn); + exists_already = 1; + break; + } + } + /* flags that writes are pending */ + if (exists_already) + ef->writes_pending = 1; + + /* update access time */ + return exists_already; +} + +EAPI Eet_Dictionary * +eet_dictionary_get(Eet_File *ef) +{ + if (eet_check_pointer(ef)) return NULL; + + return ef->ed; +} + + +EAPI char ** +eet_list(Eet_File *ef, const char *glob, int *count_ret) +{ + Eet_File_Node *efn; + char **list_ret = NULL; + int list_count = 0; + int list_count_alloc = 0; + int i, num; + + /* check to see its' an eet file pointer */ + if (eet_check_pointer(ef) || eet_check_header(ef) || + (!glob) || + ((ef->mode != EET_FILE_MODE_READ) && + (ef->mode != EET_FILE_MODE_READ_WRITE))) + { + if (count_ret) + *count_ret = 0; + + return NULL; + } + + /* loop through all entries */ + num = (1 << ef->header->directory->size); + for (i = 0; i < num; i++) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + { + /* if the entry matches the input glob + * check for * explicitly, because on some systems, * isn't well + * supported + */ + if ((!strcmp (glob, "*")) || !fnmatch(glob, efn->name, 0)) + { + /* add it to our list */ + list_count++; + + /* only realloc in 32 entry chunks */ + if (list_count > list_count_alloc) + { + char **new_list = NULL; + + list_count_alloc += 64; + new_list = realloc(list_ret, list_count_alloc * (sizeof(char *))); + if (!new_list) + { + free(list_ret); + + if (count_ret) + *count_ret = 0; + + return NULL; + } + list_ret = new_list; + } + + /* put pointer of name string in */ + list_ret[list_count - 1] = efn->name; + } + } + } + + /* return count and list */ + if (count_ret) + *count_ret = list_count; + + return list_ret; +} + +EAPI int +eet_num_entries(Eet_File *ef) +{ + int i, num, ret = 0; + Eet_File_Node *efn; + + /* check to see its' an eet file pointer */ + if (eet_check_pointer(ef) || eet_check_header(ef) || + ((ef->mode != EET_FILE_MODE_READ) && + (ef->mode != EET_FILE_MODE_READ_WRITE))) + return -1; + + /* loop through all entries */ + num = (1 << ef->header->directory->size); + for (i = 0; i < num; i++) + { + for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) + ret++; + } + + return ret; +} + +static Eet_File_Node * +find_node_by_name(Eet_File *ef, const char *name) +{ + Eet_File_Node *efn; + int hash; + + /* get hash bucket this should be in */ + hash = _eet_hash_gen(name, ef->header->directory->size); + + for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next) + { + if (eet_string_match(efn->name, name)) + return efn; + } + + return NULL; +} + +static int +read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len) +{ + if (efn->offset < 0) return 0; + + if (ef->data) + { + if ((efn->offset + len) > ef->data_size) return 0; + memcpy(buf, ef->data + efn->offset, len); + } + else + { + /* seek to data location */ + if (fseek(ef->fp, efn->offset, SEEK_SET) < 0) + return 0; + + /* read it */ + len = fread(buf, len, 1, ef->fp); + } + return len; +} diff --git a/src/lib/eet_memfile.c b/src/lib/eet_memfile.c new file mode 100644 index 0000000..6edbfa6 --- /dev/null +++ b/src/lib/eet_memfile.c @@ -0,0 +1,149 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Eet.h" +#include "Eet_private.h" + +FILE * +_eet_memfile_read_open(const void *data, size_t size) +{ +#ifdef HAVE_FMEMOPEN + return fmemopen((void*)data, size, "rb"); +#else + FILE *f; + + f = tmpfile(); + if (!f) + { + printf("EET: Error opening tmp file (no fmemopen support fallback):\n"); + perror("tmpfile()"); + return NULL; + } + fwrite(data, size, 1, f); + rewind(f); + return f; +#endif +} + +void +_eet_memfile_read_close(FILE *f) +{ +#ifdef HAVE_FMEMOPEN + fclose(f); +#else + fclose(f); +#endif +} + + +typedef struct _Eet_Memfile_Write_Info Eet_Memfile_Write_Info; +struct _Eet_Memfile_Write_Info +{ + FILE *f; + void **data; + size_t *size; +}; + +#ifndef HAVE_OPEN_MEMSTREAM +static int _eet_memfile_info_alloc_num = 0; +static int _eet_memfile_info_num = 0; +static Eet_Memfile_Write_Info *_eet_memfile_info = NULL; +#endif + +void _eet_memfile_shutdown() +{ +#ifdef HAVE_OPEN_MEMSTREAM + return; +#else + int i; + + for (i = 0; i < _eet_memfile_info_num; i++) + free(_eet_memfile_info[i].data); + + free(_eet_memfile_info); + _eet_memfile_info = NULL; +#endif +} + +FILE * +_eet_memfile_write_open(void **data, size_t *size) +{ +#ifdef HAVE_OPEN_MEMSTREAM + return open_memstream((char **)data, size); +#else + FILE *f; + + _eet_memfile_info_num++; + if (_eet_memfile_info_num > _eet_memfile_info_alloc_num) + { + Eet_Memfile_Write_Info *tmp; + + _eet_memfile_info_alloc_num += 16; + tmp = realloc(_eet_memfile_info, + _eet_memfile_info_alloc_num * + sizeof(Eet_Memfile_Write_Info)); + if (!tmp) + { + _eet_memfile_info_alloc_num -= 16; + _eet_memfile_info_num--; + return NULL; + } + _eet_memfile_info = tmp; + } + f = tmpfile(); + if (!f) + { + _eet_memfile_info_num--; + return NULL; + } + _eet_memfile_info[_eet_memfile_info_num - 1].f = f; + _eet_memfile_info[_eet_memfile_info_num - 1].data = data; + _eet_memfile_info[_eet_memfile_info_num - 1].size = size; + return f; +#endif +} + +void +_eet_memfile_write_close(FILE *f) +{ +#ifdef HAVE_OPEN_MEMSTREAM + fclose(f); +#else + int i; + + for (i = 0; i < _eet_memfile_info_num; i++) + { + if (_eet_memfile_info[i].f == f) + { + int j; + + fseek(f, 0, SEEK_END); + (*(_eet_memfile_info[i].size)) = ftell(f); + rewind(f); + (*(_eet_memfile_info[i].data)) = malloc(*(_eet_memfile_info[i].size)); + if (!(*(_eet_memfile_info[i].data))) + { + fclose(f); + (*(_eet_memfile_info[i].size)) = 0; + return; + } + fread((*(_eet_memfile_info[i].data)), (*(_eet_memfile_info[i].size)), 1, f); + for (j = i + 1; j < _eet_memfile_info_num; j++) + _eet_memfile_info[j - 1] = _eet_memfile_info[j]; + _eet_memfile_info_num--; + fclose(f); + return; + } + } + fclose(f); +#endif +} diff --git a/src/lib/eet_utils.c b/src/lib/eet_utils.c new file mode 100644 index 0000000..1785076 --- /dev/null +++ b/src/lib/eet_utils.c @@ -0,0 +1,203 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +#include +#include + +#include "Eet.h" +#include "Eet_private.h" + +int +_eet_hash_gen(const char *key, int hash_size) +{ + int hash_num = 0; + int value, i; + unsigned char *ptr; + + const int masks[9] = + { + 0x00, + 0x01, + 0x03, + 0x07, + 0x0f, + 0x1f, + 0x3f, + 0x7f, + 0xff + }; + + /* no string - index 0 */ + if (!key) return 0; + + /* calc hash num */ + for (i = 0, ptr = (unsigned char *)key, value = (int)(*ptr); + value; + ptr++, i++, value = (int)(*ptr)) + hash_num ^= (value | (value << 8)) >> (i & 0x7); + + /* mask it */ + hash_num &= masks[hash_size]; + /* return it */ + return hash_num; +} + +/* On Windows (using MinGW or VC++), printf-like functions */ +/* rely on MSVCRT, which does not fully support the C99 */ +/* specifications. In particular, they do not support the */ +/* modifier character %a. */ + + +/* That function converts a string created by a valid %a */ +/* modifier to a double. */ +/* */ +/* The string must have the following format: */ +/* */ +/* [-]0xh.hhhhhp[+-]e */ +/* */ +/* where e is a decimal number. */ +/* If n is the number of cyphers after the point, the */ +/* returned mantisse and exponents are */ +/* */ +/* mantisse: [-]hhhhhh */ +/* exponent: 2^([+-]e - 4 * n) */ +int +_eet_string_to_double_convert(const char *src, long long *m, long *e) +{ + const char *str; + long long mantisse; + long exponent; + int nbr_decimals; + int sign; + + str = src; + sign = +1; + + if (*str == '-') + { + sign = -1; + str++; + } + if (*str == '0') + { + str++; + if (*str == 'x') + str++; + else + { + fprintf(stderr, "[Eet] Error 1 during conversion of '%s'\n", src); + return 0; + } + } + else + { + fprintf(stderr, "[Eet] Error 2 during conversion of '%s'\n", src); + return 0; + } + + nbr_decimals = 0; + mantisse = (*str >= 'a') ? *str - 'a' + 10 : *str - '0'; + str++; + if (*str == '.') + { + str++; + while (*str != 'p') + { + mantisse <<= 4; + mantisse += (*str >= 'a') ? *str - 'a' + 10 : *str - '0'; + str++; + nbr_decimals++; + } + } + if (sign < 0) + mantisse = -mantisse; + if (*str != 'p') + { + fprintf(stderr, "[Eet] Error 3 during conversion '%s'\n", src); + return 0; + } + sign = +1; + str++; + if (*str == '-') + { + sign = -1; + str++; + } + else if (*str == '+') str++; + + exponent = 0; + while (*str != '\0') + { + exponent *= 10; + exponent += *str - '0'; + str++; + } + + if (sign < 0) + exponent = -exponent; + + *m = mantisse; + *e = exponent - (nbr_decimals << 2); + + return 1; +} + +/* That function converts a double to a string that as the */ +/* following format: */ +/* */ +/* [-]0xh.hhhhhp[+-]e */ +/* */ +/* where h is a hexadecimal number and e a decimal number. */ +void +_eet_double_to_string_convert(char des[128], double d) +{ + static const char look_up_table[] = {'0', '1', '2', '3', '4', + '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + int p; + int i; + + if (d < 0.0) + { + *(des++) = '-'; + d = -d; + } + + d = frexp(d, &p); + + if (p) + { + d *= 2; + p -= 1; + } + + *(des++) = '0'; + *(des++) = 'x'; + *(des++) = look_up_table[(size_t)d]; + *(des++) = '.'; + + for (i = 0; i < 16; i++) + { + d -= floor(d); + d *= 16; + *(des++) = look_up_table[(size_t)d]; + } + + while (*(des - 1) == '0') + des--; + + if (*(des - 1) == '.') + des--; + + *(des++) = 'p'; + if (p < 0) + { + *(des++) = '-'; + p = -p; + } + else + *(des++) = '+'; + + snprintf(des, 128, "%d", p); +} diff --git a/src/tests/.cvsignore b/src/tests/.cvsignore new file mode 100644 index 0000000..98ae5f2 --- /dev/null +++ b/src/tests/.cvsignore @@ -0,0 +1,5 @@ +.deps +.libs +Makefile +Makefile.in +eet_suite diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am new file mode 100644 index 0000000..11dbc61 --- /dev/null +++ b/src/tests/Makefile.am @@ -0,0 +1,17 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/lib \ +@CHECK_CFLAGS@ + + +if EET_ENABLE_TESTS + +check_PROGRAMS = eet_suite + +eet_suite_SOURCES = eet_suite.c eet_data_suite.c +eet_suite_LDADD = @CHECK_LIBS@ $(top_builddir)/src/lib/libeet.la + +EXTRA_DIST = eet_suite.h + +endif diff --git a/src/tests/TODO b/src/tests/TODO new file mode 100644 index 0000000..da5fa1b --- /dev/null +++ b/src/tests/TODO @@ -0,0 +1,3 @@ +The purpose of the current test is to check the validity of the result in a +normal environment. But we should at some point also test the robustness of +this library when for example malloc fail. diff --git a/src/tests/eet_data_suite.c b/src/tests/eet_data_suite.c new file mode 100644 index 0000000..697bff3 --- /dev/null +++ b/src/tests/eet_data_suite.c @@ -0,0 +1,163 @@ +#include +#include + +#include "eet_suite.h" + +static char* +_eet_str_direct_alloc(const char *str) +{ + return (char*) str; +} + +static void +_eet_str_direct_free(const char *str) +{ +} + +/* Internal list stuff. */ +struct _Eet_List +{ + Eet_List *next; + const void *data; +}; +Eet_List* +eet_list_prepend(Eet_List *list, const void *data) +{ + Eet_List *new; + + new = malloc(sizeof (Eet_List)); + if (!new) return list; + + new->next = list; + new->data = data; + + return new; +} +Eet_List* +eet_list_next(Eet_List *list) +{ + if (!list) return NULL; + + return list->next; +} +void* +eet_list_data(Eet_List *list) +{ + if (!list) return NULL; + + return (void*) list->data; +} +void +eet_list_free(Eet_List *list) +{ + while (list) + { + Eet_List *current = list; + + list = list->next; + free(current); + } +} + +/* Internal hash stuff */ +struct _Eet_Hash +{ + Eet_List *bucket[256]; +}; +typedef struct _Eet_Hash_Item Eet_Hash_Item; +struct _Eet_Hash_Item +{ + const void *data; + char *key; +}; +static inline int +_eet_hash_gen(const char *key) +{ + unsigned int hash_num = 5381; + const unsigned char *ptr; + + if (!key) return 0; + for (ptr = (unsigned char *)key; *ptr; ptr++) + hash_num = (hash_num * 33) ^ *ptr; + + hash_num &= 0xff; + return (int)hash_num; +} +void +eet_hash_foreach(const Eet_Hash *hash, int (*func) (const Eet_Hash *hash, const char *key, void *data, void *fdata), const void *fdata) +{ + int i; + + if (!hash) return ; + + for (i = 0; i < 256; ++i) + { + Eet_List *over; + + for (over = hash->bucket[i]; over; over = eet_list_next(over)) + { + Eet_Hash_Item *item = eet_list_data(over); + + if (!func(hash, item->key, (void*) item->data, (void*) fdata)) return ; + } + } +} +Eet_Hash* +eet_hash_add(Eet_Hash *hash, const char *key, const void *data) +{ + Eet_Hash_Item *item; + Eet_List *find; + int index; + + if (!hash) hash = calloc(1, sizeof (Eet_Hash)); + if (!hash) return NULL; + + item = malloc(sizeof (Eet_Hash_Item) + strlen(key) + 1); + if (!item) return hash; + + item->data = data; + item->key = (char*)(item + 1); + strcpy(item->key, key); + + hash->bucket[_eet_hash_gen(key)] = eet_list_prepend(hash->bucket[_eet_hash_gen(key)], item); + + return hash; +} +void +eet_hash_free(Eet_Hash *hash) +{ + int i; + + if (!hash) return ; + + for (i = 0; i < 256; ++i) + { + Eet_List *over; + + for (over = hash->bucket[i]; over; over = eet_list_next(over)) + free(eet_list_data(over)); + eet_list_free(hash->bucket[i]); + } + + free(hash); +} + +void +eet_test_setup_eddc(Eet_Data_Descriptor_Class *eddc) +{ + eddc->version = EET_DATA_DESCRIPTOR_CLASS_VERSION; + eddc->func.mem_alloc = NULL; + eddc->func.mem_free = NULL; + eddc->func.str_alloc = NULL; + eddc->func.str_free = NULL; + eddc->func.list_next = eet_list_next; + eddc->func.list_append = eet_list_prepend; + eddc->func.list_data = eet_list_data; + eddc->func.list_free = eet_list_free; + eddc->func.hash_foreach = eet_hash_foreach; + eddc->func.hash_add = eet_hash_add; + eddc->func.hash_free = eet_hash_free; + eddc->func.str_direct_alloc = _eet_str_direct_alloc; + eddc->func.str_direct_free = _eet_str_direct_free; +} + diff --git a/src/tests/eet_suite.c b/src/tests/eet_suite.c new file mode 100644 index 0000000..003dfa5 --- /dev/null +++ b/src/tests/eet_suite.c @@ -0,0 +1,1195 @@ +#include +#include +#include +#include + +#include + +#include "eet_suite.h" + +START_TEST(eet_test_init) +{ + int ret; + + ret = eet_init(); + fail_if(ret != 1); + + ret = eet_shutdown(); + fail_if(ret != 0); +} +END_TEST + +typedef struct _Eet_Test_Basic_Type Eet_Test_Basic_Type; +struct _Eet_Test_Basic_Type +{ + char c; + short s; + int i; + long long l; + char *str; + char *istr; + float f1; + float f2; + double d; + unsigned char uc; + unsigned short us; + unsigned int ui; + unsigned long long ul; + Eet_Test_Basic_Type *empty; + Eet_Test_Basic_Type *with; +}; + +#define EET_TEST_CHAR 0x42 +#define EET_TEST_SHORT 0x4224 +#define EET_TEST_INT 0x42211224 +#define EET_TEST_LONG_LONG 0x84CB42211224BC48 +#define EET_TEST_STRING "my little test with escape \\\"" +#define EET_TEST_KEY1 "key1" +#define EET_TEST_KEY2 "key2" +#define EET_TEST_FLOAT 123.45689 +#define EET_TEST_FLOAT2 1.0 +#define EET_TEST_FLOAT3 0.25 +#define EET_TEST_FLOAT4 0.0001234 +#define EET_TEST_DOUBLE 123456789.9876543210 +#define EET_TEST_DOUBLE2 1.0 +#define EET_TEST_DOUBLE3 0.25 +#define EET_TEST_FILE_KEY1 "keys/data/1" +#define EET_TEST_FILE_KEY2 "keys/data/2" +#define EET_TEST_FILE_IMAGE "keys/images/" + +typedef struct _Eet_Test_Image Eet_Test_Image; +struct _Eet_Test_Image +{ + unsigned int w; + unsigned int h; + unsigned int alpha; + unsigned int color[]; +}; + +static const Eet_Test_Image test_noalpha = { + 8, 8, 0, + { + 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, + 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, + 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, + 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, + 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, + 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, + 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, + 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA + } +}; + +static const Eet_Test_Image test_alpha = { + 8, 8, 1, + { + 0x0FAA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x0F110000, + 0x0000AA00, 0x0F0000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x0F110000, 0x00AA0000, + 0x000000AA, 0x00110000, 0x0FAA0000, 0x0000AA00, 0x000000AA, 0x0F110000, 0x00AA0000, 0x0000AA00, + 0x00110000, 0x00AA0000, 0x0000AA00, 0x0F0000AA, 0x0F110000, 0x00AA0000, 0x0000AA00, 0x000000AA, + 0x00AA0000, 0x0000AA00, 0x000000AA, 0x0F110000, 0x0FAA0000, 0x0000AA00, 0x000000AA, 0x00110000, + 0x0000AA00, 0x000000AA, 0x0F110000, 0x00AA0000, 0x0000AA00, 0x0F0000AA, 0x00110000, 0x00AA0000, + 0x000000AA, 0x0F110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x0FAA0000, 0x0000AA00, + 0x0F110000, 0x00AA0000, 0x0000AA00, 0x000000AA, 0x00110000, 0x00AA0000, 0x0000AA00, 0x0F0000AA + } +}; + +static void +_eet_test_basic_set(Eet_Test_Basic_Type *res, int i) +{ + res->c = EET_TEST_CHAR; + res->s = EET_TEST_SHORT; + res->i = EET_TEST_INT + i; + res->l = EET_TEST_LONG_LONG; + res->str = EET_TEST_STRING; + res->istr = EET_TEST_STRING; + res->f1 = - EET_TEST_FLOAT; + res->d = - EET_TEST_DOUBLE; + res->f2 = EET_TEST_FLOAT4; + res->uc = EET_TEST_CHAR; + res->us = EET_TEST_SHORT; + res->ui = EET_TEST_INT; + res->ul = EET_TEST_LONG_LONG; + res->empty = NULL; + res->with = NULL; + + if (i == 0) + { + Eet_Test_Basic_Type *tmp; + + tmp = malloc(sizeof (Eet_Test_Basic_Type)); + fail_if(!tmp); + + res->with = tmp; + tmp->c = EET_TEST_CHAR; + tmp->s = EET_TEST_SHORT; + tmp->i = EET_TEST_INT + i + 1; + tmp->l = EET_TEST_LONG_LONG; + tmp->str = EET_TEST_STRING; + tmp->istr = EET_TEST_STRING; + tmp->f1 = - EET_TEST_FLOAT; + tmp->d = - EET_TEST_DOUBLE; + tmp->f2 = EET_TEST_FLOAT4; + tmp->uc = EET_TEST_CHAR; + tmp->us = EET_TEST_SHORT; + tmp->ui = EET_TEST_INT; + tmp->ul = EET_TEST_LONG_LONG; + tmp->empty = NULL; + tmp->with = NULL; + } +} + +static void +_eet_test_basic_check(Eet_Test_Basic_Type *result, int i) +{ + float tmp; + + fail_if(result->c != EET_TEST_CHAR); + fail_if(result->s != EET_TEST_SHORT); + fail_if(result->i != EET_TEST_INT + i); + fail_if(result->l != EET_TEST_LONG_LONG); + fail_if(strcmp(result->str, EET_TEST_STRING) != 0); + fail_if(strcmp(result->istr, EET_TEST_STRING) != 0); + fail_if(result->uc != EET_TEST_CHAR); + fail_if(result->us != EET_TEST_SHORT); + fail_if(result->ui != EET_TEST_INT); + fail_if(result->ul != EET_TEST_LONG_LONG); + + tmp = (result->f1 + EET_TEST_FLOAT); + if (tmp < 0) tmp = -tmp; + fail_if(tmp > 0.005); + + tmp = (result->f2 - EET_TEST_FLOAT4); + if (tmp < 0) tmp = -tmp; + fail_if(tmp > 0.005); + + tmp = (result->d + EET_TEST_DOUBLE); + if (tmp < 0) tmp = -tmp; + fail_if(tmp > 0.00005); + + fail_if(result->empty != NULL); + if (i == 0) + { + Eet_Test_Basic_Type *tmp; + + tmp = result->with; + fail_if(tmp == NULL); + + fail_if(tmp->c != EET_TEST_CHAR); + fail_if(tmp->s != EET_TEST_SHORT); + fail_if(tmp->i != EET_TEST_INT + i + 1); + fail_if(tmp->l != EET_TEST_LONG_LONG); + fail_if(strcmp(tmp->str, EET_TEST_STRING) != 0); + fail_if(strcmp(tmp->istr, EET_TEST_STRING) != 0); + fail_if(tmp->uc != EET_TEST_CHAR); + fail_if(tmp->us != EET_TEST_SHORT); + fail_if(tmp->ui != EET_TEST_INT); + fail_if(tmp->ul != EET_TEST_LONG_LONG); + } + else + fail_if(result->with != NULL); +} + +static void +_eet_build_basic_descriptor(Eet_Data_Descriptor *edd) +{ + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "c", c, EET_T_CHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "s", s, EET_T_SHORT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "i", i, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "l", l, EET_T_LONG_LONG); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "str", str, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "istr", istr, EET_T_INLINED_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "f1", f1, EET_T_FLOAT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "f2", f2, EET_T_FLOAT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "d", d, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "uc", uc, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "us", us, EET_T_USHORT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "ui", ui, EET_T_UINT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Basic_Type, "ul", ul, EET_T_ULONG_LONG); + + EET_DATA_DESCRIPTOR_ADD_SUB(edd, Eet_Test_Basic_Type, "empty", empty, edd); + EET_DATA_DESCRIPTOR_ADD_SUB(edd, Eet_Test_Basic_Type, "with", with, edd); +} + +START_TEST(eet_test_basic_data_type_encoding_decoding) +{ + Eet_Data_Descriptor *edd; + Eet_Test_Basic_Type *result; + Eet_Data_Descriptor_Class eddc; + Eet_Test_Basic_Type etbt; + void *transfert; + int size; + + eet_init(); + + _eet_test_basic_set(&etbt, 0); + + eet_test_setup_eddc(&eddc); + eddc.name = "Eet_Test_Basic_Type"; + eddc.size = sizeof(Eet_Test_Basic_Type); + + edd = eet_data_descriptor2_new(&eddc); + fail_if(!edd); + + _eet_build_basic_descriptor(edd); + + transfert = eet_data_descriptor_encode(edd, &etbt, &size); + fail_if(!transfert || size <= 0); + + result = eet_data_descriptor_decode(edd, transfert, size); + fail_if(!result); + + _eet_test_basic_check(result, 0); + + free(result->str); + free(result); + + eet_data_descriptor_free(edd); + + eet_shutdown(); +} +END_TEST + +typedef struct _Eet_Test_Ex_Type Eet_Test_Ex_Type; +struct _Eet_Test_Ex_Type +{ + char c; + short s; + int i; + unsigned long long l; + char *str; + char *istr; + float f1; + float f2; + float f3; + float f4; + double d1; + double d2; + double d3; + double d4; + Eet_List *list; + Eet_Hash *hash; + Eet_List *ilist; + Eet_Hash *ihash; + Eet_Test_Basic_Type sarray1[10]; + unsigned int sarray2[5]; + unsigned int varray1_count; + unsigned int *varray1; + unsigned int varray2_count; + Eet_Test_Basic_Type *varray2; + unsigned char uc; + unsigned short us; + unsigned int ui; + unsigned long long ul; +}; + +static int i42 = 42; +static int i7 = 7; + + +static void +_eet_build_ex_descriptor(Eet_Data_Descriptor *edd) +{ + Eet_Data_Descriptor_Class eddc; + Eet_Test_Ex_Type etbt; + Eet_Data_Descriptor *eddb; + + eet_test_setup_eddc(&eddc); + eddc.name = "Eet_Test_Basic_Type"; + eddc.size = sizeof(Eet_Test_Basic_Type); + eddb = eet_data_descriptor3_new(&eddc); + fail_if(!eddb); + + _eet_build_basic_descriptor(eddb); + + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "c", c, EET_T_CHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "s", s, EET_T_SHORT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "i", i, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "l", l, EET_T_LONG_LONG); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "str", str, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "istr", istr, EET_T_INLINED_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "f1", f1, EET_T_FLOAT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "f2", f2, EET_T_FLOAT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "f3", f3, EET_T_FLOAT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "f4", f4, EET_T_FLOAT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "d1", d1, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "d2", d2, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "d3", d3, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "d4", d4, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "uc", uc, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "us", us, EET_T_USHORT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "ui", ui, EET_T_UINT); + EET_DATA_DESCRIPTOR_ADD_BASIC(edd, Eet_Test_Ex_Type, "ul", ul, EET_T_ULONG_LONG); + EET_DATA_DESCRIPTOR_ADD_ARRAY(edd, Eet_Test_Ex_Type, "sarray1", sarray1, eddb); + EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(edd, Eet_Test_Ex_Type, "varray2", varray2, eddb); + eet_data_descriptor_element_add(edd, "varray1", EET_T_INT, EET_G_VAR_ARRAY, + (char *)(&(etbt.varray1)) - (char *)(&(etbt)), + (char *)(&(etbt.varray1_count)) - (char *)(&(etbt)), /* 0, */NULL, NULL); + eet_data_descriptor_element_add(edd, "sarray2", EET_T_INT, EET_G_ARRAY, + (char *)(&(etbt.sarray2)) - (char *)(&(etbt)), + /* 0, */sizeof(etbt.sarray2)/sizeof(etbt.sarray2[0]), NULL, NULL); + EET_DATA_DESCRIPTOR_ADD_LIST(edd, Eet_Test_Ex_Type, "list", list, edd); + EET_DATA_DESCRIPTOR_ADD_HASH(edd, Eet_Test_Ex_Type, "hash", hash, edd); + eet_data_descriptor_element_add(edd, "ilist", EET_T_INT, EET_G_LIST, + (char *)(&(etbt.ilist)) - (char *)(&(etbt)), + 0, /* 0, */NULL, NULL); + eet_data_descriptor_element_add(edd, "ihash", EET_T_INT, EET_G_HASH, + (char *)(&(etbt.ihash)) - (char *)(&(etbt)), + 0, /* 0, */NULL, NULL); +} + +static Eet_Test_Ex_Type* +_eet_test_ex_set(Eet_Test_Ex_Type *res, int offset) +{ + int i; + + if (!res) res = malloc( sizeof(Eet_Test_Ex_Type)); + if (!res) return NULL; + + res->c = EET_TEST_CHAR + offset; + res->s = EET_TEST_SHORT + offset; + res->i = EET_TEST_INT + offset; + res->l = EET_TEST_LONG_LONG + offset; + res->str = EET_TEST_STRING; + res->istr = EET_TEST_STRING; + res->f1 = EET_TEST_FLOAT + offset; + res->f2 = -(EET_TEST_FLOAT2 + offset); + res->f3 = EET_TEST_FLOAT3 + offset; + res->f4 = EET_TEST_FLOAT2 + offset; + res->d1 = EET_TEST_DOUBLE + offset; + res->d2 = -(EET_TEST_DOUBLE2 + offset); + res->d3 = EET_TEST_DOUBLE3 + offset; + res->d4 = EET_TEST_DOUBLE2 + offset; + res->list = NULL; + res->hash = NULL; + res->ilist = NULL; + res->ihash = NULL; + + res->varray2 = malloc(sizeof (Eet_Test_Basic_Type) * 10); + res->varray1 = malloc(sizeof (int) * 5); + fail_if(!res->varray1 || !res->varray2); + for (i = 0; i < 10; ++i) + { + _eet_test_basic_set(res->sarray1 + i, i); + _eet_test_basic_set(res->varray2 + i, i); + } + res->varray2_count = 10; + for (i = 0; i < 5; ++i) + { + res->sarray2[i] = i * 42 + 1; + res->varray1[i] = i * 42 + 1; + } + res->varray1_count = 5; + + res->uc = EET_TEST_CHAR + offset; + res->us = EET_TEST_SHORT + offset; + res->ui = EET_TEST_INT + offset; + res->ul = EET_TEST_LONG_LONG + offset; + + return res; +} + +static int +_eet_test_ex_check(Eet_Test_Ex_Type *stuff, int offset) +{ + double tmp; + int i; + + if (!stuff) return 1; + + if (stuff->c != EET_TEST_CHAR + offset) return 1; + if (stuff->s != EET_TEST_SHORT + offset) return 1; + if (stuff->i != EET_TEST_INT + offset) return 1; + if (stuff->l != EET_TEST_LONG_LONG + offset) return 1; + if (strcmp(stuff->str, EET_TEST_STRING) != 0) return 1; + if (strcmp(stuff->istr, EET_TEST_STRING) != 0) return 1; + + tmp = stuff->f1 - (EET_TEST_FLOAT + offset); + if (tmp < 0) tmp = -tmp; + if (tmp > 0.005) return 1; + + tmp = stuff->d1 - (EET_TEST_DOUBLE + offset); + if (tmp < 0) tmp = -tmp; + if (tmp > 0.00005) return 1; + + if (stuff->f2 != - (EET_TEST_FLOAT2 + offset)) return 1; + if (stuff->d2 != - (EET_TEST_DOUBLE2 + offset)) return 1; + + if (stuff->f3 != EET_TEST_FLOAT3 + offset) return 1; + if (stuff->d3 != EET_TEST_DOUBLE3 + offset) return 1; + + if (stuff->f4 != EET_TEST_FLOAT2 + offset) return 1; + if (stuff->d4 != EET_TEST_DOUBLE2 + offset) return 1; + + if (stuff->uc != EET_TEST_CHAR + offset) return 1; + if (stuff->us != EET_TEST_SHORT + offset) return 1; + if (stuff->ui != EET_TEST_INT + offset) return 1; + if (stuff->ul != EET_TEST_LONG_LONG + offset) return 1; + + for (i = 0; i < 5; ++i) + if (stuff->sarray2[i] != i * 42 + 1) + return 1; + + for (i = 0; i < 10; ++i) + _eet_test_basic_check(stuff->sarray1 + i, i); + + return 0; +} + +static int +func(const Eet_Hash *hash, const char *key, void *data, void *fdata) +{ + int *res = fdata; + + if (strcmp(key, EET_TEST_KEY1) != 0 + && strcmp(key, EET_TEST_KEY2) != 0) *res = 1; + if (_eet_test_ex_check(data, 2)) *res = 1; + + return 1; +} + +static int +func7(const Eet_Hash *hash, const char *key, void *data, void *fdata) +{ + int *res = fdata; + int *val; + + val = data; + if (!val) *res = 1; + if (*val != 7) *res = 1; + + return 1; +} + +START_TEST(eet_test_data_type_encoding_decoding) +{ + Eet_Data_Descriptor *edd; + Eet_Test_Ex_Type *result; + Eet_Test_Ex_Type *tmp; + void *transfert; + Eet_Data_Descriptor_Class eddc; + Eet_Test_Ex_Type etbt; + int size; + int test; + + eet_init(); + + _eet_test_ex_set(&etbt, 0); + etbt.list = eet_list_prepend(etbt.list, _eet_test_ex_set(NULL, 1)); + etbt.hash = eet_hash_add(etbt.hash, EET_TEST_KEY1, _eet_test_ex_set(NULL, 2)); + etbt.ilist = eet_list_prepend(etbt.ilist, &i42); + etbt.ihash = eet_hash_add(etbt.ihash, EET_TEST_KEY1, &i7); + + eet_test_setup_eddc(&eddc); + eddc.name = "Eet_Test_Ex_Type"; + eddc.size = sizeof(Eet_Test_Ex_Type); + + edd = eet_data_descriptor3_new(&eddc); + fail_if(!edd); + + _eet_build_ex_descriptor(edd); + + transfert = eet_data_descriptor_encode(edd, &etbt, &size); + fail_if(!transfert || size <= 0); + + result = eet_data_descriptor_decode(edd, transfert, size); + fail_if(!result); + + fail_if(_eet_test_ex_check(result, 0) != 0); + fail_if(_eet_test_ex_check(eet_list_data(result->list), 1) != 0); + fail_if(eet_list_data(result->ilist) == NULL); + fail_if(*((int*)eet_list_data(result->ilist)) != 42); + + test = 0; + eet_hash_foreach(result->hash, func, &test); + fail_if(test != 0); + eet_hash_foreach(result->ihash, func7, &test); + fail_if(test != 0); + + eet_shutdown(); +} +END_TEST + +static void +append_string(void *data, const char *str) +{ + char **string = data; + int length; + + if (!data) return ; + + length = *string ? strlen(*string) : 0; + *string = realloc(*string, strlen(str) + length + 1); + + memcpy((*string) + length, str, strlen(str) + 1); +} + +START_TEST(eet_test_data_type_dump_undump) +{ + Eet_Data_Descriptor *edd; + Eet_Test_Ex_Type *result; + Eet_Test_Ex_Type *tmp; + Eet_Data_Descriptor_Class eddc; + Eet_Test_Ex_Type etbt; + char *transfert1; + char *transfert2; + char *string1; + char *string2; + int size1; + int size2; + int test; + + int i; + + eet_init(); + + _eet_test_ex_set(&etbt, 0); + etbt.list = eet_list_prepend(etbt.list, _eet_test_ex_set(NULL, 1)); + etbt.list = eet_list_prepend(etbt.list, _eet_test_ex_set(NULL, 1)); + etbt.hash = eet_hash_add(etbt.hash, EET_TEST_KEY1, _eet_test_ex_set(NULL, 2)); + etbt.hash = eet_hash_add(etbt.hash, EET_TEST_KEY2, _eet_test_ex_set(NULL, 2)); + etbt.ilist = eet_list_prepend(etbt.ilist, &i42); + etbt.ilist = eet_list_prepend(etbt.ilist, &i42); + etbt.ihash = eet_hash_add(etbt.ihash, EET_TEST_KEY1, &i7); + etbt.ihash = eet_hash_add(etbt.ihash, EET_TEST_KEY2, &i7); + + eet_test_setup_eddc(&eddc); + eddc.name = "Eet_Test_Ex_Type"; + eddc.size = sizeof(Eet_Test_Ex_Type); + + edd = eet_data_descriptor3_new(&eddc); + fail_if(!edd); + + _eet_build_ex_descriptor(edd); + + transfert1 = eet_data_descriptor_encode(edd, &etbt, &size1); + fail_if(!transfert1 || size1 <= 0); + + string1 = NULL; + eet_data_text_dump(transfert1, size1, append_string, &string1); + fail_if(!string1); + + transfert2 = eet_data_text_undump(string1, strlen(string1), &size2); + fail_if(!transfert2 && size2 <= 0); + fail_if(size1 != size2); + + string2 = NULL; + eet_data_text_dump(transfert2, size2, append_string, &string2); + fail_if(!string2); + + fail_if(memcmp(transfert1, transfert2, size1) != 0); + + result = eet_data_descriptor_decode(edd, transfert2, size2); + fail_if(!result); + + fail_if(_eet_test_ex_check(result, 0) != 0); + fail_if(_eet_test_ex_check(eet_list_data(result->list), 1) != 0); + fail_if(eet_list_data(result->ilist) == NULL); + fail_if(*((int*)eet_list_data(result->ilist)) != 42); + + test = 0; + eet_hash_foreach(result->hash, func, &test); + fail_if(test != 0); + eet_hash_foreach(result->ihash, func7, &test); + fail_if(test != 0); + + eet_shutdown(); +} +END_TEST + +START_TEST(eet_file_simple_write) +{ + const char *buffer = "Here is a string of data to save !"; + Eet_File *ef; + char *test; + char *file = strdup("/tmp/eet_suite_testXXXXXX"); + int size; + + eet_init(); + + mktemp(file); + + fail_if(eet_mode_get(NULL) != EET_FILE_MODE_INVALID); + + ef = eet_open(file, EET_FILE_MODE_WRITE); + fail_if(!ef); + + fail_if(!eet_write(ef, "keys/tests", buffer, strlen(buffer) + 1, 1)); + + fail_if(eet_mode_get(ef) != EET_FILE_MODE_WRITE); + + fail_if(eet_list(ef, "*", &size) != NULL); + fail_if(eet_num_entries(ef) != -1); + + eet_close(ef); + + /* Test read of simple file */ + ef = eet_open(file, EET_FILE_MODE_READ); + fail_if(!ef); + + test = eet_read(ef, "keys/tests", &size); + fail_if(!test); + fail_if(size != strlen(buffer) + 1); + + fail_if(memcmp(test, buffer, strlen(buffer) + 1) != 0); + + fail_if(eet_mode_get(ef) != EET_FILE_MODE_READ); + fail_if(eet_num_entries(ef) != 1); + + eet_close(ef); + + /* Test eet cache system */ + ef = eet_open(file, EET_FILE_MODE_READ); + fail_if(!ef); + + test = eet_read(ef, "keys/tests", &size); + fail_if(!test); + fail_if(size != strlen(buffer) + 1); + + fail_if(memcmp(test, buffer, strlen(buffer) + 1) != 0); + + eet_close(ef); + + fail_if(unlink(file) != 0); + + eet_shutdown(); +} +END_TEST + +START_TEST(eet_file_data_test) +{ + const char *buffer = "Here is a string of data to save !"; + Eet_Data_Descriptor *edd; + Eet_Test_Ex_Type *result; + Eet_Test_Ex_Type *tmp; + Eet_Dictionary *ed; + Eet_File *ef; + char **list; + char *transfert1; + char *transfert2; + char *string1; + char *string2; + char *file = strdup("/tmp/eet_suite_testXXXXXX"); + Eet_Data_Descriptor_Class eddc; + Eet_Test_Ex_Type etbt; + int size; + int size1; + int size2; + int test; + + int i; + + eet_init(); + + _eet_test_ex_set(&etbt, 0); + etbt.list = eet_list_prepend(etbt.list, _eet_test_ex_set(NULL, 1)); + etbt.list = eet_list_prepend(etbt.list, _eet_test_ex_set(NULL, 1)); + etbt.hash = eet_hash_add(etbt.hash, EET_TEST_KEY1, _eet_test_ex_set(NULL, 2)); + etbt.hash = eet_hash_add(etbt.hash, EET_TEST_KEY2, _eet_test_ex_set(NULL, 2)); + etbt.ilist = eet_list_prepend(etbt.ilist, &i42); + etbt.ilist = eet_list_prepend(etbt.ilist, &i42); + etbt.ihash = eet_hash_add(etbt.ihash, EET_TEST_KEY1, &i7); + etbt.ihash = eet_hash_add(etbt.ihash, EET_TEST_KEY2, &i7); + + eet_test_setup_eddc(&eddc); + eddc.name = "Eet_Test_Ex_Type"; + eddc.size = sizeof(Eet_Test_Ex_Type); + + edd = eet_data_descriptor3_new(&eddc); + fail_if(!edd); + + _eet_build_ex_descriptor(edd); + + mktemp(file); + + /* Insert an error in etbt. */ + etbt.i = 0; + + /* Save the encoded data in a file. */ + ef = eet_open(file, EET_FILE_MODE_READ_WRITE); + fail_if(!ef); + + fail_if(!eet_data_write(ef, edd, EET_TEST_FILE_KEY1, &etbt, 0)); + + result = eet_data_read(ef, edd, EET_TEST_FILE_KEY1); + fail_if(!result); + + fail_if(eet_mode_get(ef) != EET_FILE_MODE_READ_WRITE); + + /* Test string space. */ + ed = eet_dictionary_get(ef); + + fail_if(!eet_dictionary_string_check(ed, result->str)); + fail_if(eet_dictionary_string_check(ed, result->istr)); + + eet_close(ef); + + /* Attempt to replace etbt by the correct one. */ + etbt.i = EET_TEST_INT; + + ef = eet_open(file, EET_FILE_MODE_READ_WRITE); + fail_if(!ef); + + fail_if(!eet_data_write(ef, edd, EET_TEST_FILE_KEY1, &etbt, 0)); + + eet_close(ef); + + /* Read back the data. */ + ef = eet_open(file, EET_FILE_MODE_READ_WRITE); + fail_if(!ef); + + fail_if(!eet_data_write(ef, edd, EET_TEST_FILE_KEY2, &etbt, 1)); + + result = eet_data_read(ef, edd, EET_TEST_FILE_KEY1); + fail_if(!result); + + /* Test string space. */ + ed = eet_dictionary_get(ef); + fail_if(!ed); + + fail_if(!eet_dictionary_string_check(ed, result->str)); + fail_if(eet_dictionary_string_check(ed, result->istr)); + + /* Test the resulting data. */ + fail_if(_eet_test_ex_check(result, 0) != 0); + fail_if(_eet_test_ex_check(eet_list_data(result->list), 1) != 0); + fail_if(eet_list_data(result->ilist) == NULL); + fail_if(*((int*)eet_list_data(result->ilist)) != 42); + + test = 0; + eet_hash_foreach(result->hash, func, &test); + fail_if(test != 0); + eet_hash_foreach(result->ihash, func7, &test); + fail_if(test != 0); + + list = eet_list(ef, "keys/*", &size); + fail_if(eet_num_entries(ef) != 2); + fail_if(size != 2); + fail_if(!(strcmp(list[0], EET_TEST_FILE_KEY1) == 0 && strcmp(list[1], EET_TEST_FILE_KEY2) == 0) + && !(strcmp(list[0], EET_TEST_FILE_KEY2) == 0 && strcmp(list[1], EET_TEST_FILE_KEY1) == 0)); + free(list); + + fail_if(eet_delete(ef, NULL) != 0); + fail_if(eet_delete(NULL, EET_TEST_FILE_KEY1) != 0); + fail_if(eet_delete(ef, EET_TEST_FILE_KEY1) == 0); + + list = eet_list(ef, "keys/*", &size); + fail_if(size != 1); + fail_if(eet_num_entries(ef) != 1); + + /* Test some more wrong case */ + fail_if(eet_data_read(ef, edd, "plop") != NULL); + fail_if(eet_data_read(ef, edd, EET_TEST_FILE_KEY1) != NULL); + + /* Reinsert and reread data */ + fail_if(!eet_data_write(ef, edd, EET_TEST_FILE_KEY1, &etbt, 0)); + fail_if(eet_data_read(ef, edd, EET_TEST_FILE_KEY1) == NULL); + fail_if(eet_read_direct(ef, EET_TEST_FILE_KEY1, &size) == NULL); + + eet_close(ef); + + fail_if(unlink(file) != 0); + + eet_shutdown(); +} +END_TEST + +START_TEST(eet_file_data_dump_test) +{ + const char *buffer = "Here is a string of data to save !"; + Eet_Data_Descriptor *edd; + Eet_Test_Ex_Type *result; + Eet_Test_Ex_Type *tmp; + Eet_Data_Descriptor_Class eddc; + Eet_Test_Ex_Type etbt; + Eet_File *ef; + char *transfert1; + char *transfert2; + char *string1; + char *string2; + char *file = strdup("/tmp/eet_suite_testXXXXXX"); + int size; + int size1; + int size2; + int test; + + int i; + + eet_init(); + + _eet_test_ex_set(&etbt, 0); + etbt.list = eet_list_prepend(etbt.list, _eet_test_ex_set(NULL, 1)); + etbt.list = eet_list_prepend(etbt.list, _eet_test_ex_set(NULL, 1)); + etbt.hash = eet_hash_add(etbt.hash, EET_TEST_KEY1, _eet_test_ex_set(NULL, 2)); + etbt.hash = eet_hash_add(etbt.hash, EET_TEST_KEY2, _eet_test_ex_set(NULL, 2)); + etbt.ilist = eet_list_prepend(etbt.ilist, &i42); + etbt.ilist = eet_list_prepend(etbt.ilist, &i42); + etbt.ihash = eet_hash_add(etbt.ihash, EET_TEST_KEY1, &i7); + etbt.ihash = eet_hash_add(etbt.ihash, EET_TEST_KEY2, &i7); + + eet_test_setup_eddc(&eddc); + eddc.name = "Eet_Test_Ex_Type"; + eddc.size = sizeof(Eet_Test_Ex_Type); + + edd = eet_data_descriptor3_new(&eddc); + fail_if(!edd); + + _eet_build_ex_descriptor(edd); + + mktemp(file); + + /* Save the encoded data in a file. */ + ef = eet_open(file, EET_FILE_MODE_WRITE); + fail_if(!ef); + + fail_if(!eet_data_write(ef, edd, EET_TEST_FILE_KEY1, &etbt, 1)); + + eet_close(ef); + + /* Use dump/undump in the middle */ + ef = eet_open(file, EET_FILE_MODE_READ_WRITE); + fail_if(!ef); + + string1 = NULL; + fail_if(eet_data_dump(ef, EET_TEST_FILE_KEY1, append_string, &string1) != 1); + fail_if(eet_delete(ef, EET_TEST_FILE_KEY1) == 0); + fail_if(!eet_data_undump(ef, EET_TEST_FILE_KEY1, string1, strlen(string1), 1)); + + eet_close(ef); + + /* Test the correctness of the reinsertion. */ + ef = eet_open(file, EET_FILE_MODE_READ); + fail_if(!ef); + + result = eet_data_read(ef, edd, EET_TEST_FILE_KEY1); + fail_if(!transfert1); + + eet_close(ef); + + /* Test the resulting data. */ + fail_if(_eet_test_ex_check(result, 0) != 0); + fail_if(_eet_test_ex_check(eet_list_data(result->list), 1) != 0); + fail_if(eet_list_data(result->ilist) == NULL); + fail_if(*((int*)eet_list_data(result->ilist)) != 42); + + test = 0; + eet_hash_foreach(result->hash, func, &test); + fail_if(test != 0); + eet_hash_foreach(result->ihash, func7, &test); + fail_if(test != 0); + + fail_if(unlink(file) != 0); + + eet_shutdown(); +} +END_TEST + +START_TEST(eet_image) +{ + Eet_File *ef; + char *file = strdup("/tmp/eet_suite_testXXXXXX"); + int *data; + int compress; + int quality; + int result; + int lossy; + int alpha; + int w; + int h; + + mktemp(file); + + /* Save the encoded data in a file. */ + ef = eet_open(file, EET_FILE_MODE_READ_WRITE); + fail_if(!ef); + + result = eet_data_image_write(ef, EET_TEST_FILE_IMAGE "0", test_noalpha.color, + test_noalpha.w, test_noalpha.h, test_noalpha.alpha, + 0, 100, 0); + fail_if(result == 0); + + result = eet_data_image_write(ef, EET_TEST_FILE_IMAGE "1", test_noalpha.color, + test_noalpha.w, test_noalpha.h, test_noalpha.alpha, + 5, 100, 0); + fail_if(result == 0); + + result = eet_data_image_write(ef, EET_TEST_FILE_IMAGE "2", test_noalpha.color, + test_noalpha.w, test_noalpha.h, test_noalpha.alpha, + 9, 100, 0); + fail_if(result == 0); + + result = eet_data_image_write(ef, EET_TEST_FILE_IMAGE "3", test_noalpha.color, + test_noalpha.w, test_noalpha.h, test_noalpha.alpha, + 0, 100, 1); + fail_if(result == 0); + + result = eet_data_image_write(ef, EET_TEST_FILE_IMAGE "4", test_noalpha.color, + test_noalpha.w, test_noalpha.h, test_noalpha.alpha, + 0, 60, 1); + fail_if(result == 0); + + result = eet_data_image_write(ef, EET_TEST_FILE_IMAGE "5", test_noalpha.color, + test_noalpha.w, test_noalpha.h, test_noalpha.alpha, + 0, 10, 1); + fail_if(result == 0); + + result = eet_data_image_write(ef, EET_TEST_FILE_IMAGE "6", test_noalpha.color, + test_noalpha.w, test_noalpha.h, test_noalpha.alpha, + 0, 0, 1); + fail_if(result == 0); + + result = eet_data_image_write(ef, EET_TEST_FILE_IMAGE "7", test_alpha.color, + test_alpha.w, test_alpha.h, test_alpha.alpha, + 9, 100, 0); + fail_if(result == 0); + + result = eet_data_image_write(ef, EET_TEST_FILE_IMAGE "8", test_alpha.color, + test_alpha.w, test_alpha.h, test_alpha.alpha, + 0, 80, 1); + fail_if(result == 0); + + result = eet_data_image_write(ef, EET_TEST_FILE_IMAGE "9", test_alpha.color, + test_alpha.w, test_alpha.h, test_alpha.alpha, + 0, 100, 1); + fail_if(result == 0); + + data = eet_data_image_read(ef, EET_TEST_FILE_IMAGE "2", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(data == NULL); + fail_if(w != test_noalpha.w); + fail_if(h != test_noalpha.h); + fail_if(alpha != test_noalpha.alpha); + fail_if(compress != 9); + fail_if(lossy != 0); + fail_if(data[0] != test_noalpha.color[0]); + free(data); + + result = eet_data_image_header_read(ef, EET_TEST_FILE_IMAGE "2", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(result == 0); + fail_if(w != test_noalpha.w); + fail_if(h != test_noalpha.h); + fail_if(alpha != test_noalpha.alpha); + fail_if(compress != 9); + fail_if(lossy != 0); + + eet_close(ef); + + /* Test read of image */ + ef = eet_open(file, EET_FILE_MODE_READ); + fail_if(!ef); + + result = eet_data_image_header_read(ef, EET_TEST_FILE_IMAGE "0", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(result == 0); + fail_if(w != test_noalpha.w); + fail_if(h != test_noalpha.h); + fail_if(alpha != test_noalpha.alpha); + fail_if(compress != 0); + fail_if(lossy != 0); + + data = malloc(w * h * 4); + fail_if(data == NULL); + result = eet_data_image_read_to_surface(ef, EET_TEST_FILE_IMAGE "0", 4, 4, data, 2, 2, w * 4, &alpha, &compress, &quality, &lossy); + fail_if(result != 1); + fail_if(alpha != test_noalpha.alpha); + fail_if(compress != 0); + fail_if(quality != 100); + fail_if(lossy != 0); + fail_if(data[0] != test_noalpha.color[4 + 4 * w]); + free(data); + + data = malloc(w * h * 4); + fail_if(data == NULL); + result = eet_data_image_read_to_surface(ef, EET_TEST_FILE_IMAGE "0", 0, 0, data, w, h, w * 4, &alpha, &compress, &quality, &lossy); + fail_if(result != 1); + fail_if(alpha != test_noalpha.alpha); + fail_if(compress != 0); + fail_if(quality != 100); + fail_if(lossy != 0); + fail_if(data[0] != test_noalpha.color[0]); + free(data); + + data = eet_data_image_read(ef, EET_TEST_FILE_IMAGE "1", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(data == NULL); + fail_if(w != test_noalpha.w); + fail_if(h != test_noalpha.h); + fail_if(alpha != test_noalpha.alpha); + fail_if(compress != 5); + fail_if(quality != 100); + fail_if(lossy != 0); + fail_if(data[0] != test_noalpha.color[0]); + free(data); + + data = eet_data_image_read(ef, EET_TEST_FILE_IMAGE "2", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(data == NULL); + fail_if(w != test_noalpha.w); + fail_if(h != test_noalpha.h); + fail_if(alpha != test_noalpha.alpha); + fail_if(compress != 9); + fail_if(lossy != 0); + fail_if(data[0] != test_noalpha.color[0]); + free(data); + + data = eet_data_image_read(ef, EET_TEST_FILE_IMAGE "3", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(data == NULL); + fail_if(w != test_noalpha.w); + fail_if(h != test_noalpha.h); + fail_if(alpha != test_noalpha.alpha); + fail_if(lossy != 1); + free(data); + + data = eet_data_image_read(ef, EET_TEST_FILE_IMAGE "5", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(data == NULL); + fail_if(w != test_noalpha.w); + fail_if(h != test_noalpha.h); + fail_if(alpha != test_noalpha.alpha); + fail_if(lossy != 1); + free(data); + + data = eet_data_image_read(ef, EET_TEST_FILE_IMAGE "6", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(data == NULL); + fail_if(w != test_noalpha.w); + fail_if(h != test_noalpha.h); + fail_if(alpha != test_noalpha.alpha); + fail_if(lossy != 1); + free(data); + + result = eet_data_image_header_read(ef, EET_TEST_FILE_IMAGE "7", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(result == 0); + fail_if(w != test_alpha.w); + fail_if(h != test_alpha.h); + fail_if(alpha != test_alpha.alpha); + fail_if(compress != 9); + fail_if(lossy != 0); + + data = eet_data_image_read(ef, EET_TEST_FILE_IMAGE "7", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(data == NULL); + fail_if(w != test_alpha.w); + fail_if(h != test_alpha.h); + fail_if(alpha != test_alpha.alpha); + fail_if(compress != 9); + fail_if(lossy != 0); + fail_if(data[0] != test_alpha.color[0]); + free(data); + + result = eet_data_image_header_read(ef, EET_TEST_FILE_IMAGE "9", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(result == 0); + fail_if(w != test_alpha.w); + fail_if(h != test_alpha.h); + fail_if(alpha != test_alpha.alpha); + fail_if(lossy != 1); + + data = eet_data_image_read(ef, EET_TEST_FILE_IMAGE "9", &w, &h, &alpha, &compress, &quality, &lossy); + fail_if(data == NULL); + fail_if(w != test_alpha.w); + fail_if(h != test_alpha.h); + fail_if(alpha != test_alpha.alpha); + fail_if(lossy != 1); + free(data); + + eet_close(ef); + + eet_shutdown(); +} +END_TEST + +#define IM0 0x00112233 +#define IM1 0x44556677 +#define IM2 0x8899aabb +#define IM3 0xccddeeff + +START_TEST(eet_small_image) +{ + char *file = strdup("/tmp/eet_suite_testXXXXXX"); + unsigned int image[4]; + unsigned int *data; + Eet_File *ef; + int w; + int h; + int alpha; + int compression; + int quality; + int lossy; + int result; + + image[0] = IM0; + image[1] = IM1; + image[2] = IM2; + image[3] = IM3; + + eet_init(); + + mktemp(file); + + ef = eet_open(file, EET_FILE_MODE_WRITE); + fail_if(!ef); + + result = eet_data_image_write(ef, "/images/test", image, 2, 2, 1, 9, 100, 0); + fail_if(result == 0); + + eet_close(ef); + + ef = eet_open(file, EET_FILE_MODE_READ); + fail_if(!ef); + + data = (unsigned int*) eet_data_image_read(ef, "/images/test", &w, &h, &alpha, &compression, &quality, &lossy); + fail_if(data == NULL); + + eet_close(ef); + + fail_if(data[0] != IM0); + fail_if(data[1] != IM1); + fail_if(data[2] != IM2); + fail_if(data[3] != IM3); + + free(data); + + eet_shutdown(); +} +END_TEST + +Suite * +eet_suite(void) +{ + Suite *s; + TCase *tc; + + s = suite_create("Eet"); + + tc = tcase_create("Eet_Init"); + tcase_add_test(tc, eet_test_init); + suite_add_tcase(s, tc); + + tc = tcase_create("Eet Data Encoding/Decoding"); + tcase_add_test(tc, eet_test_basic_data_type_encoding_decoding); + tcase_add_test(tc, eet_test_data_type_encoding_decoding); + tcase_add_test(tc, eet_test_data_type_dump_undump); + suite_add_tcase(s, tc); + + tc = tcase_create("Eet File"); + tcase_add_test(tc, eet_file_simple_write); + tcase_add_test(tc, eet_file_data_test); + tcase_add_test(tc, eet_file_data_dump_test); + suite_add_tcase(s, tc); + + tc = tcase_create("Eet Image"); + tcase_add_test(tc, eet_image); + tcase_add_test(tc, eet_small_image); + suite_add_tcase(s, tc); + + return s; +} + +int +main(void) +{ + Suite *s; + SRunner *sr; + int failed_count; + + s = eet_suite(); + sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + failed_count = srunner_ntests_failed(sr); + srunner_free(sr); + + return (failed_count == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/tests/eet_suite.h b/src/tests/eet_suite.h new file mode 100644 index 0000000..4b979a2 --- /dev/null +++ b/src/tests/eet_suite.h @@ -0,0 +1,21 @@ +#ifndef _EET_SUITE_H +# define _EET_SUITE_H + +#include "Eet.h" + +typedef struct _Eet_List Eet_List; +typedef struct _Eet_Hash Eet_Hash; + +Eet_List* eet_list_prepend(Eet_List *list, const void *data); +Eet_List* eet_list_next(Eet_List *list); +void* eet_list_data(Eet_List *list); +void eet_list_free(Eet_List *list); + +void eet_hash_foreach(const Eet_Hash *hash, int (*func) (const Eet_Hash *hash, const char *key, void *data, void *fdata), const void *fdata); +Eet_Hash* eet_hash_add(Eet_Hash *hash, const char *key, const void *data); +void eet_hash_free(Eet_Hash *hash); + +void eet_test_setup_eddc(Eet_Data_Descriptor_Class *eddc); + + +#endif /* _EET_SUITE_H */ diff --git a/win32/MANIFEST.txt b/win32/MANIFEST.txt new file mode 100644 index 0000000..e1272fe --- /dev/null +++ b/win32/MANIFEST.txt @@ -0,0 +1,11 @@ + + This folder content: + + vs8 - Visual Studio 8 project files + start.bat - batch script to start work with the solution + eet.sln - Eet MSVC solution + libeet.vcproj - libeet project + + set_env.bat - common environment startup + MANIFEST.txt - this file + README.txt - about this folder \ No newline at end of file diff --git a/win32/README.txt b/win32/README.txt new file mode 100644 index 0000000..baf3060 --- /dev/null +++ b/win32/README.txt @@ -0,0 +1,8 @@ + + This folder contains Microsoft Visual Studion projects for building Eet. + +Important: + + Do not launch manually any solutions or projects in the folder, to start + a solution run proper start.bat script, it will setup environment for + projects and will check system requirements. diff --git a/win32/set_env.bat b/win32/set_env.bat new file mode 100644 index 0000000..ab862d8 --- /dev/null +++ b/win32/set_env.bat @@ -0,0 +1,25 @@ +@echo off + +rem Set external libraries directory. +set EXT_DIR=%cd%\..\..\..\..\extern + +if not exist %EXT_DIR% ( + set EXT_DIR= + echo ERROR: External libs dir is not set. + pause + goto END +) + +rem Add installation directory pathes. +set INCLUDE=%EXT_DIR%\include;%INCLUDE% +set LIB=%EXT_DIR%\lib;%LIB% + +rem Add Evil lib path +set EvilInclude=%cd%\..\..\..\proto\evil\src\lib +set EvilCommon=%cd%\..\..\..\proto\evil\win32\common +set EvilOut=%cd%\..\..\..\proto\evil\win32\%PROJECT_TYPE%\out + +set INCLUDE=%EvilCommon%;%EvilInclude%;%EvilInclude%\dlfcn;%EvilInclude%\mman;%INCLUDE% +set LIB=%EvilOut%;%LIB% + +:END diff --git a/win32/vs8/eet.sln b/win32/vs8/eet.sln new file mode 100644 index 0000000..24b01bb --- /dev/null +++ b/win32/vs8/eet.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libeet", "libeet.vcproj", "{689B4F2B-666D-439F-9BF3-1203D813DE3F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {689B4F2B-666D-439F-9BF3-1203D813DE3F}.Debug|Win32.ActiveCfg = Debug|Win32 + {689B4F2B-666D-439F-9BF3-1203D813DE3F}.Debug|Win32.Build.0 = Debug|Win32 + {689B4F2B-666D-439F-9BF3-1203D813DE3F}.Release|Win32.ActiveCfg = Release|Win32 + {689B4F2B-666D-439F-9BF3-1203D813DE3F}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/win32/vs8/libeet.vcproj b/win32/vs8/libeet.vcproj new file mode 100644 index 0000000..3d0c6a9 --- /dev/null +++ b/win32/vs8/libeet.vcproj @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/vs8/start.bat b/win32/vs8/start.bat new file mode 100644 index 0000000..7d63109 --- /dev/null +++ b/win32/vs8/start.bat @@ -0,0 +1,33 @@ +@echo off +rem Warning: environment is set for Win32 platform. + +set PROJECT_TYPE=vs8 + +pushd .. +call set_env.bat +popd + +if "%EXT_DIR%" == "" goto END + +rem Setup common Win32 environment variables + +set SolutionDirectory=%cd% +set DebugOutputDirectory=%SolutionDirectory%\out +set ReleaseOutputDirectory=%SolutionDirectory%\out +set DebugLibraryDirectory=%SolutionDirectory%\out +set ReleaseLibraryDirectory=%SolutionDirectory%\out +set TemporaryDirectory=%SolutionDirectory%\temp + +rem Check for basic requirements +if "%VS80COMNTOOLS%" == "" ( + echo ERROR: Microsoft Visual Studio 2005 is not installed. + pause + goto END +) + +rem Setting environment for using Microsoft Visual Studio 2005 x86 tools. +call "%VS80COMNTOOLS%vsvars32.bat" + +eet.sln + +:END \ No newline at end of file