From b3530965ed6f2f003f8854751ec53b1da3f81e04 Mon Sep 17 00:00:00 2001 From: raster Date: Mon, 2 Dec 2002 23:39:26 +0000 Subject: [PATCH 1/1] move eet to HEAD git-svn-id: http://svn.enlightenment.org/svn/e/trunk/e17/libs/eet@6469 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- .cvsignore | 2 + ChangeLog | 0 INSTALL | 14 + Makefile.am | 10 + NEWS | 0 acconfig.h | 3 + autogen.sh | 137 ++++ configure.ac | 75 ++ configure.in | 75 ++ debian/.cvsignore | 7 + debian/changelog | 6 + debian/control | 29 + debian/copyright | 32 + debian/eet-config.1 | 27 + debian/eet.1 | 61 ++ debian/libeet0-dev.files | 4 + debian/libeet0.files | 2 + debian/rules | 74 ++ eet-config.in | 59 ++ eet.spec | 63 ++ src/.cvsignore | 3 + src/Makefile.am | 3 + src/bin/.cvsignore | 3 + src/bin/Makefile.am | 12 + src/bin/eet_main.c | 420 +++++++++++ src/lib/.cvsignore | 3 + src/lib/Eet.h | 268 +++++++ src/lib/Makefile.am | 20 + src/lib/eet_data.c | 1765 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib/eet_lib.c | 889 +++++++++++++++++++++++ 30 files changed, 4066 insertions(+) create mode 100644 .cvsignore create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 acconfig.h create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 configure.in create mode 100644 debian/.cvsignore create mode 100644 debian/changelog create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/eet-config.1 create mode 100644 debian/eet.1 create mode 100644 debian/libeet0-dev.files create mode 100644 debian/libeet0.files create mode 100644 debian/rules create mode 100644 eet-config.in create mode 100644 eet.spec create mode 100644 src/.cvsignore create mode 100644 src/Makefile.am create mode 100644 src/bin/.cvsignore create mode 100644 src/bin/Makefile.am create mode 100644 src/bin/eet_main.c create mode 100644 src/lib/.cvsignore create mode 100644 src/lib/Eet.h create mode 100644 src/lib/Makefile.am create mode 100644 src/lib/eet_data.c create mode 100644 src/lib/eet_lib.c diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..2b9156e --- /dev/null +++ b/.cvsignore @@ -0,0 +1,2 @@ +.config +build-stamp diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..3a3ad7e --- /dev/null +++ b/INSTALL @@ -0,0 +1,14 @@ +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 + +NOTE: You MUST make install Eet for it to run properly. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..7e766de --- /dev/null +++ b/Makefile.am @@ -0,0 +1,10 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = src + +MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \ + config.h.in config.sub configure install-sh \ + ltconfig ltmain.sh missing mkinstalldirs \ + stamp-h.in + +EXTRA_DIST = README AUTHORS COPYING eet.spec diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000..bd2bb91 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,3 @@ +#undef PACKAGE_SOURCE_DIR +#undef PACKAGE_BIN_DIR +#undef PACKAGE_LIB_DIR diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..9226176 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,137 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +srcdir=`dirname $0` +PKG_NAME="the package." + +DIE=0 + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`autoconf' installed to." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && { + (libtool --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`libtool' installed." + echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2d.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 + } +} + +grep "^AM_GNU_GETTEXT" $srcdir/configure.in >/dev/null && { + grep "sed.*POTFILES" $srcdir/configure.in >/dev/null || \ + (gettext --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`gettext' installed." + echo "Get ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 + } +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`automake' installed." + echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 + NO_AUTOMAKE=yes +} + + +# if no automake, don't bother testing for aclocal +test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: Missing \`aclocal'. The version of \`automake'" + echo "installed doesn't appear recent enough." + echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +if test -z "$*"; then + echo "**Warning**: I am going to run \`configure' with no arguments." + echo "If you wish to pass any to it, please specify them on the" + echo \`$0\'" command line." + echo +fi + +case $CC in +xlc ) + am_opt=--include-deps;; +esac + +for coin in `find $srcdir -name configure.in -print` +do + dr=`dirname $coin` + if test -f $dr/NO-AUTO-GEN; then + echo skipping $dr -- flagged as no auto-gen + else + echo processing $dr + macrodirs=`sed -n -e 's,AM_ACLOCAL_INCLUDE(\(.*\)),\1,gp' < $coin` + ( cd $dr + aclocalinclude="$ACLOCAL_FLAGS" + for k in $macrodirs; do + if test -d $k; then + aclocalinclude="$aclocalinclude -I $k" + ##else + ## echo "**Warning**: No such directory \`$k'. Ignored." + fi + done + if grep "^AM_GNU_GETTEXT" configure.in >/dev/null; then + if grep "sed.*POTFILES" configure.in >/dev/null; then + : do nothing -- we still have an old unmodified configure.in + else + echo "Creating $dr/aclocal.m4 ..." + test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 + echo "Running gettextize... Ignore non-fatal messages." + echo "no" | gettextize --force --copy + echo "Making $dr/aclocal.m4 writable ..." + test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 + fi + fi + if grep "^AM_GNOME_GETTEXT" configure.in >/dev/null; then + echo "Creating $dr/aclocal.m4 ..." + test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 + echo "Running gettextize... Ignore non-fatal messages." + echo "no" | gettextize --force --copy + echo "Making $dr/aclocal.m4 writable ..." + test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 + fi + if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then + echo "Running libtoolize..." + libtoolize --force --copy + fi + echo "Running aclocal $aclocalinclude ..." + aclocal $aclocalinclude + if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then + echo "Running autoheader..." + autoheader + fi + echo "Running automake --gnu $am_opt ..." + automake --add-missing --gnu $am_opt + echo "Running autoconf ..." + autoconf + ) + fi +done + +#conf_flags="--enable-maintainer-mode --enable-compile-warnings" #--enable-iso-c + +if test x$NOCONFIGURE = x; then + echo Running $srcdir/configure $conf_flags "$@" ... + $srcdir/configure $conf_flags "$@" \ + && echo Now type \`make\' to compile $PKG_NAME +else + echo Skipping configure process. +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..a391da6 --- /dev/null +++ b/configure.ac @@ -0,0 +1,75 @@ +dnl Process this file with autoconf to produce a configure script. + +# get rid of that stupid cache mechanism +rm -f config.cache + +AC_INIT(configure.in) +AM_INIT_AUTOMAKE(eet, 0.0.1) +AM_CONFIG_HEADER(config.h) + +AC_ISC_POSIX +AC_PROG_CC +AM_PROG_CC_STDC +AC_HEADER_STDC +AC_C_CONST +AM_ENABLE_SHARED +AM_PROG_LIBTOOL + +if test "x${exec_prefix}" = "xNONE"; then + if test "x${prefix}" = "xNONE"; then + bindir="${ac_default_prefix}/bin"; + else + bindir="${prefix}/bin"; + fi +else + if test "x${prefix}" = "xNONE"; then + bindir="${ac_default_prefix}/bin"; + else + bindir="${prefix}/bin"; + fi +fi + +if test "x${exec_prefix}" = "xNONE"; then + if test "x${prefix}" = "xNONE"; then + libdir="${ac_default_prefix}/lib"; + else + libdir="${prefix}/lib"; + fi +else + if test "x${prefix}" = "xNONE"; then + libdir="${ac_default_prefix}/lib"; + else + libdir="${prefix}/lib"; + fi +fi + +dnl Set PACKAGE_BIN_DIR in config.h. +if test "x${bindir}" = 'xNONE'; then + if test "x${prefix}" = "xNONE"; then + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${ac_default_prefix}/bin") + else + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${prefix}/bin") + fi +else + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${bindir}") +fi + +dnl Set PACKAGE_LIB_DIR in config.h. +if test "x${libdir}" = 'xNONE'; then + if test "x${prefix}" = "xNONE"; then + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${ac_default_prefix}/lib") + else + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${prefix}/lib") + fi +else + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${libdir}") +fi + +dnl Set PACKAGE_SOURCE_DIR in config.h. +packagesrcdir=`cd $srcdir && pwd` +AC_DEFINE_UNQUOTED(PACKAGE_SOURCE_DIR, "${packagesrcdir}") + +AC_OUTPUT([ +Makefile src/Makefile src/lib/Makefile src/bin/Makefile +]) + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..a391da6 --- /dev/null +++ b/configure.in @@ -0,0 +1,75 @@ +dnl Process this file with autoconf to produce a configure script. + +# get rid of that stupid cache mechanism +rm -f config.cache + +AC_INIT(configure.in) +AM_INIT_AUTOMAKE(eet, 0.0.1) +AM_CONFIG_HEADER(config.h) + +AC_ISC_POSIX +AC_PROG_CC +AM_PROG_CC_STDC +AC_HEADER_STDC +AC_C_CONST +AM_ENABLE_SHARED +AM_PROG_LIBTOOL + +if test "x${exec_prefix}" = "xNONE"; then + if test "x${prefix}" = "xNONE"; then + bindir="${ac_default_prefix}/bin"; + else + bindir="${prefix}/bin"; + fi +else + if test "x${prefix}" = "xNONE"; then + bindir="${ac_default_prefix}/bin"; + else + bindir="${prefix}/bin"; + fi +fi + +if test "x${exec_prefix}" = "xNONE"; then + if test "x${prefix}" = "xNONE"; then + libdir="${ac_default_prefix}/lib"; + else + libdir="${prefix}/lib"; + fi +else + if test "x${prefix}" = "xNONE"; then + libdir="${ac_default_prefix}/lib"; + else + libdir="${prefix}/lib"; + fi +fi + +dnl Set PACKAGE_BIN_DIR in config.h. +if test "x${bindir}" = 'xNONE'; then + if test "x${prefix}" = "xNONE"; then + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${ac_default_prefix}/bin") + else + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${prefix}/bin") + fi +else + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${bindir}") +fi + +dnl Set PACKAGE_LIB_DIR in config.h. +if test "x${libdir}" = 'xNONE'; then + if test "x${prefix}" = "xNONE"; then + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${ac_default_prefix}/lib") + else + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${prefix}/lib") + fi +else + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${libdir}") +fi + +dnl Set PACKAGE_SOURCE_DIR in config.h. +packagesrcdir=`cd $srcdir && pwd` +AC_DEFINE_UNQUOTED(PACKAGE_SOURCE_DIR, "${packagesrcdir}") + +AC_OUTPUT([ +Makefile src/Makefile src/lib/Makefile src/bin/Makefile +]) + diff --git a/debian/.cvsignore b/debian/.cvsignore new file mode 100644 index 0000000..a0c9d09 --- /dev/null +++ b/debian/.cvsignore @@ -0,0 +1,7 @@ +files +libeet0 +libeet0-dev +libeet0.postinst.debhelper +libeet0.postrm.debhelper +libeet0.substvars +tmp diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..1201b20 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,6 @@ +libeet (0.0.0-0cvs20021005) unstable; urgency=low + + * a CVS release + + -- Sytse Wielinga Sat, 5 Oct 2002 12:12:06 +0200 + diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..f8ea80e --- /dev/null +++ b/debian/control @@ -0,0 +1,29 @@ +Source: libeet +Section: libs +Priority: optional +Maintainer: Sytse Wielinga +Build-Depends: debhelper (>> 3.0.0), libz-dev, libjpeg-dev +Standards-Version: 3.5.7.0 + +Package: libeet0-dev +Section: devel +Architecture: any +Depends: libeet0 (= ${Source-Version}) +Provides: libeet-dev +Conflicts: libeet-dev +Description: Enlightenment file chunk reading/writing library development files + This package contains headers and static libraries for development with + libeet. + +Package: libeet0 +Section: libs +Architecture: any +Depends: ${shlibs:Depends} +Description: Enlightenment 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. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..daf5283 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,32 @@ +This package was debianized by Sytse Wielinga on +Thu, 3 Oct 2002 12:08:24 +0200. + +The source is downloaded from the e17/libs/eet module of the enlightenment CVS +tree. For more information, see: + + http://www.enlightenment.org/cvs.html + +Upstream Author(s): Enlightenment team + +Copyright: + +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, 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. diff --git a/debian/eet-config.1 b/debian/eet-config.1 new file mode 100644 index 0000000..b64bb22 --- /dev/null +++ b/debian/eet-config.1 @@ -0,0 +1,27 @@ +.\" Hey, EMACS: -*- nroff -*- +.TH EET 1 "oktober 3, 2002" +.SH NAME +eet-config \- script to get information about the installed version of Eet +.SH SYNOPSIS +.B eet-config [\-\-version] [\-\-libs] [\-\-cflags] +.SH DESCRIPTION +\fIeet-config\fP is a tool that is used by configure to determine the +availability of eet and the compiler and linker flags that should be used to +compile programs using it. +.SH OPTIONS +\fIeet-config\fP accepts the following options: +.TP +.B \-\-version +Print the currently installed version of \fIeet\fP on the standard output. +.TP +.B \-\-libs +Print the linker flags that are necessary to link a \fIeet\fP\-program. +.TP +.B \-\-cflags +Print the compiler flags that are necessary to link a \fIeet\fP\-program. +.SH SEE ALSO +.BR eet (1). +.SH AUTHOR +This manual page was written by Sytse Wielinga + for the Debian GNU/Linux system (but may be +used by others). diff --git a/debian/eet.1 b/debian/eet.1 new file mode 100644 index 0000000..f0f43f7 --- /dev/null +++ b/debian/eet.1 @@ -0,0 +1,61 @@ +.\" Hey, EMACS: -*- nroff -*- +.TH EET 1 "oktober 3, 2002" +.SH NAME +eet \- program for editing eet files +.SH SYNOPSIS +.B eet +-l in_file +.br +.B eet +-d in_file +.br +.B eet +-c out_file [-nz glob [-nz glob ...]] dir_file1 [dir_file2 ...] +.SH DESCRIPTION +This manual page documents briefly the +.B eet +command. +This manual page was written for the Debian distribution +because the original program does not have a manual page. +.PP +.B eet +is a program for viewing, unpacking and adding files to eet files, which are +containers for optionally compressed data, allowing for fast random-access +reading. These files are mostly used by the enlightenment project. See +.B www.enlightenment.org +for more details about this project. +.SH OPTIONS +.TP +.B \-l in_file +List the contents of an eet file +.TP +.B \-d in_file +Unpack an eet file +.TP +.B \-c out_file +Create an eet file +.TP +.B \-nz match +Store files matching match glob uncompressed +.SH SEE ALSO +.BR eet-config (1). +.PP +For more information, have a look at the sources of libeet. To get them, have +a look at the website +.B www.enlightenment.org +or execute the following commands: +.TP +.B export CVSROOT=:pserver:anonymous@cvs.enlightenment.sourceforge.net:/cvsroot/enlightenment +If this is command is broken among multiple lines because your terminal is not +as wide as the command, please don't include the minus sign into the command. +.TP +.B cvs login +Just hit enter if it asks about a password for anonymous. +.TP +.B cvs co -r SPLIT e17/libs/eet +This command should create the directory e17/libs/eet, containing the latest +sources of eet. +.SH AUTHOR +This manual page was written by Sytse Wielinga + for the Debian GNU/Linux system (but may be +used by others). diff --git a/debian/libeet0-dev.files b/debian/libeet0-dev.files new file mode 100644 index 0000000..606c89f --- /dev/null +++ b/debian/libeet0-dev.files @@ -0,0 +1,4 @@ +usr/bin/eet-config +usr/include/* +usr/lib/lib*.a +usr/lib/lib*.so diff --git a/debian/libeet0.files b/debian/libeet0.files new file mode 100644 index 0000000..31a86ab --- /dev/null +++ b/debian/libeet0.files @@ -0,0 +1,2 @@ +usr/bin/eet +usr/lib/lib*.so.* diff --git a/debian/rules b/debian/rules new file mode 100644 index 0000000..171d5dc --- /dev/null +++ b/debian/rules @@ -0,0 +1,74 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatibility version to use. +export DH_COMPAT=3 + + +ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) + CFLAGS += -g +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +version=`ls src/.libs/lib*.so.* | \ + awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'` +major=`ls src/.libs/lib*.so.* | \ + awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'` + +build: build-stamp +build-stamp: + dh_testdir + + ./configure --prefix=/usr build + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + + -./configure clean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + ./configure --prefix=$(CURDIR)/debian/tmp/usr install + + +binary-indep: build install + +binary-arch: build install + dh_testdir + dh_testroot + dh_movefiles + + dh_installdocs -plibeet0 README AUTHORS + dh_installdocs -plibeet0-dev + dh_installman -plibeet0 debian/eet.1 + dh_installman -plibeet0-dev debian/eet-config.1 + dh_installchangelogs + dh_link + dh_strip + dh_compress + dh_fixperms + dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/eet-config.in b/eet-config.in new file mode 100644 index 0000000..d80b872 --- /dev/null +++ b/eet-config.in @@ -0,0 +1,59 @@ +#!/bin/sh + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +exec_prefix_set=no + +usage="\ +Usage: evas-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--libs] [--cflags]" + +if test $# -eq 0; then + echo "${usage}" 1>&2 + exit 1 +fi + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + if test $exec_prefix_set = no ; then + exec_prefix=$optarg + fi + ;; + --prefix) + echo $prefix + ;; + --exec-prefix=*) + exec_prefix=$optarg + exec_prefix_set=yes + ;; + --exec-prefix) + echo $exec_prefix + ;; + --version) + echo @VERSION@ + ;; + --cflags) + if test @includedir@ != /usr/include ; then + includes=-I@includedir@ + fi + echo $includes + ;; + --libs) + libdirs=-L@libdir@ + echo $libdirs -leet -ljpeg -lz + ;; + *) + echo "${usage}" 1>&2 + exit 1 + ;; + esac + shift +done + +exit 0 diff --git a/eet.spec b/eet.spec new file mode 100644 index 0000000..419d95f --- /dev/null +++ b/eet.spec @@ -0,0 +1,63 @@ +# Note that this is NOT a relocatable package +%define ver 0.0.1 +%define rel 1 +%define prefix /usr/local + +Summary: eet +Name: eet +Version: %ver +Release: %rel +Copyright: BSD +Group: Base/Group +Source: ftp://ftp.enlightenment.org/pub/eet/eet-%{ver}.tar.gz +BuildRoot: /var/tmp/eet-root +Packager: The Rasterman +URL: http://www.enlightenment.org/ +Requires: libjpeg +Requires: zlib + +Docdir: %{prefix}/doc + +%description +Eet + +%prep +%setup + +%build +./configure --prefix=%prefix + +if [ "$SMP" != "" ]; then + (make "MAKE=make -k -j $SMP"; exit 0) + make +else + make +fi +########################################################################### + +%install +rm -rf $RPM_BUILD_ROOT +make prefix=$RPM_BUILD_ROOT%{prefix} install + +%clean +rm -rf $RPM_BUILD_ROOT + +%post + +%postun + +%files +%defattr(-,root,root) +%doc README COPYING ChangeLog +%attr(755,root,root) %{prefix}/bin/* +%attr(755,root,root) %{prefix}/lib/* +%{prefix}/share/* + +%doc AUTHORS +%doc COPYING +%doc README + +%changelog +* Sat Jun 23 2001 The Rasterman +- Created spec file + diff --git a/src/.cvsignore b/src/.cvsignore new file mode 100644 index 0000000..2fa80b7 --- /dev/null +++ b/src/.cvsignore @@ -0,0 +1,3 @@ +eet +eet-config +libeet.so.0.0.0 diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..7b45af6 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = lib bin diff --git a/src/bin/.cvsignore b/src/bin/.cvsignore new file mode 100644 index 0000000..2fa80b7 --- /dev/null +++ b/src/bin/.cvsignore @@ -0,0 +1,3 @@ +eet +eet-config +libeet.so.0.0.0 diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am new file mode 100644 index 0000000..49b8604 --- /dev/null +++ b/src/bin/Makefile.am @@ -0,0 +1,12 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = \ + -I../lib + +bin_PROGRAMS = eet + +eet_SOURCES = \ +eet_main.c + +eet_LDADD = $(top_builddir)/src/lib/libeet.la +eet_DEPENDANCIES = $(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..0bf1a71 --- /dev/null +++ b/src/bin/eet_main.c @@ -0,0 +1,420 @@ +#include "Eet.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* just some sample code on how to use encoder/decoders */ +#if 0 +#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; + +void +encdectest(void) +{ + 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_hash_foreach, + evas_hash_add); + 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_hash_foreach, + evas_hash_add); + 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_hash_foreach, + evas_hash_add); + 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); + f = fopen("out", "w"); + if (f) + { + fwrite(data, size, 1, f); + fclose(f); + } + 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); + + exit(0); +} +#endif + +int eet_mkdir(char *dir); +void eet_mkdirs(char *s); + +void depak_file(Eet_File *ef, char *file); +void depack(char *pak_file); + +void list(char *pak_file); + +void pak_file(Eet_File *ef, char *file, char **noz, int noz_num); +void pak_dir(Eet_File *ef, char *dir, char **noz, int noz_num); +void pack(char *pak_file, char **files, int count, char **noz, int noz_num); + +static mode_t default_mode = +S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + +int +eet_mkdir(char *dir) +{ + if (mkdir(dir, default_mode) < 0) return 0; + return 1; +} + +void +eet_mkdirs(char *s) +{ + char ss[PATH_MAX]; + int i, ii; + + i = 0; + ii = 0; + while (s[i]) + { + ss[ii++] = s[i]; + ss[ii] = 0; + if (s[i] == '/') eet_mkdir(ss); + i++; + } +} + +void +depak_file(Eet_File *ef, char *file) +{ + void *data; + int size; + char *last; + + data = eet_read(ef, file, &size); + if (data) + { + FILE *f; + char buf[PATH_MAX]; + + strcpy(buf, file); + last = strrchr(buf, '/'); + if (last) + { + last[1] = 0; + eet_mkdirs(buf); + } + + f = fopen(file, "w"); + if (f) + { + fwrite(data, 1, size, f); + fclose(f); + printf("exported: %s\n", file); + } + else + printf("error exporting: %s\n", file); + free(data); + } + else + { + printf("error reading: %s\n", file); + } +} + +void +depack(char *pak_file) +{ + int i, num; + char **list; + Eet_File *ef; + + ef = eet_open(pak_file, EET_FILE_MODE_READ); + if (!ef) + { + printf("cannot open for reading: %s\n", pak_file); + return; + } + list = eet_list(ef, "*", &num); + if (list) + { + for (i = 0; i < num; i++) + depak_file(ef, list[i]); + free(list); + } + eet_close(ef); +} + +void +list(char *pak_file) +{ + int i, num; + char **list; + Eet_File *ef; + + ef = eet_open(pak_file, EET_FILE_MODE_READ); + if (!ef) + { + printf("cannot open for reading: %s\n", pak_file); + return; + } + list = eet_list(ef, "*", &num); + if (list) + { + for (i = 0; i < num; i++) + printf("%s\n",list[i]); + free(list); + } + eet_close(ef); +} + +void +pak_file(Eet_File *ef, char *file, char **noz, int noz_num) +{ + struct stat st; + + if (stat(file, &st) >= 0) + { + void *buf; + + buf = malloc(st.st_size); + if (buf) + { + FILE *f; + + f = fopen(file, "r"); + if (f) + { + int compress = 1; + int i; + + for (i = 0; i < noz_num; i++) + { + if (!fnmatch(noz[i], file, 0)) + { + compress = 0; + break; + } + } + fread(buf, 1, st.st_size, f); + if (!eet_write(ef, file, buf, st.st_size, compress)) + printf("error importing: %s\n", file); + else + { + if (compress) + printf("compress: %s\n", file); + else + printf("imported: %s\n", file); + } + fclose(f); + } + free(buf); + } + } +} + +void +pak_dir(Eet_File *ef, char *dir, char **noz, int noz_num) +{ + DIR *dirp; + struct dirent *dp; + + dirp = opendir(dir); + if (!dirp) + pak_file(ef, dir, noz, noz_num); + else + { + while ((dp = readdir(dirp))) + { + char buf[PATH_MAX]; + + if ((!strcmp(".", dp->d_name)) || (!strcmp("..", dp->d_name))) + { + } + else + { + snprintf(buf, sizeof(buf), "%s/%s", dir, dp->d_name); + pak_dir(ef, buf, noz, noz_num); + } + } + } +} + +void +pack(char *pak_file, char **files, int count, char **noz, int noz_num) +{ + Eet_File *ef; + int i; + + ef = eet_open(pak_file, EET_FILE_MODE_WRITE); + if (!ef) + { + printf("cannot open for writing: %s\n", pak_file); + return; + } + for (i = 0; i < count; i++) pak_dir(ef, files[i], noz, noz_num); + printf("done.\n"); + eet_close(ef); +} + +int +main(int argc, char **argv) +{ + if (argc == 3) + { + if (!strcmp(argv[1], "-d")) + { + depack(argv[2]); + return 0; + } + else if (!strcmp(argv[1], "-l")) + { + list(argv[2]); + return 0; + } + } + else if (argc > 3) + { + char **noz = NULL; + int noz_num = 0; + + if (!strcmp(argv[1], "-c")) + { + int i; + + for (i = 3; i < argc; i++) + { + if (!strcmp(argv[i], "-nz")) + { + if (i < (argc - 1)) + { + i++; + noz_num++; + noz = realloc(noz, noz_num * sizeof(char *)); + noz[noz_num - 1] = argv[i]; + } + } + else + break; + } + pack(argv[2], &(argv[i]), argc - i, noz, noz_num); + return 0; + } + } + printf("usage:\n" + " %s -l in_file\n" + " %s -d in_file\n" + " %s -c out_file [-nz glob [-nz glob ...]] dir_file1 [dir_file2 ...]\n" + "\n" + "where:\n" + " -l in_file list contents of eet file\n" + " -d in_file unpack eet file\n" + " -c out_file pack up eet file\n" + " -nz match don't compress files matching match glob\n" + "\n" + "example:\n" + " %s -c out.eet -nz \"*.jpg\" things/\n" + " %s -l out.eet\n" + " %s -d out.eet\n", + argv[0], argv[0], argv[0], + argv[0], argv[0], argv[0]); + return -1; +} diff --git a/src/lib/.cvsignore b/src/lib/.cvsignore new file mode 100644 index 0000000..2fa80b7 --- /dev/null +++ b/src/lib/.cvsignore @@ -0,0 +1,3 @@ +eet +eet-config +libeet.so.0.0.0 diff --git a/src/lib/Eet.h b/src/lib/Eet.h new file mode 100644 index 0000000..57e231f --- /dev/null +++ b/src/lib/Eet.h @@ -0,0 +1,268 @@ +#ifndef _EET_H +#define _EET_H + +/***************************************************************************/ + +/* + * EET - E file chunk reading/writing library + * + * What is it? + * 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 zip itself has more complexity than we need, and it was much + * simpler to impliment this once here. + * + */ + +/***************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +#define EET_T_UNKNOW 0 +#define EET_T_CHAR 1 +#define EET_T_SHORT 2 +#define EET_T_INT 3 +#define EET_T_LONG_LONG 4 +#define EET_T_FLOAT 5 +#define EET_T_DOUBLE 6 +#define EET_T_UCHAR 7 +#define EET_T_USHORT 8 +#define EET_T_UINT 9 +#define EET_T_ULONG_LONG 10 +#define EET_T_STRING 11 +#define EET_T_LAST 12 + +#define EET_G_UNKNOWN 100 +#define EET_G_ARRAY 101 +#define EET_G_VAR_ARRAY 102 +#define EET_G_LIST 103 +#define EET_G_HASH 104 +#define EET_G_LAST 105 + +/***************************************************************************/ + + enum _Eet_File_Mode + { + EET_FILE_MODE_READ, + EET_FILE_MODE_WRITE + }; + + typedef enum _Eet_File_Mode Eet_File_Mode; + + typedef struct _Eet_File Eet_File; + typedef struct _Eet_Data_Descriptor Eet_Data_Descriptor; + + +/***************************************************************************/ + + /* eet_open - Open an eet file on disk, and returns a handle to it. + * @file: The file path to the eet file. eg: "/tmp/file.eet". + * @mode: The mode for opening. Either EET_FILE_MODE_READ or EET_FILE_MODE_WRITE, but not both. + * + * 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. + */ + Eet_File *eet_open (char *file, Eet_File_Mode mode); + /* eet_close - Close an eet file handle and flush and writes pending. + * @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. + */ + void eet_close (Eet_File *ef); + /* eet_read - Read a specified entry from an eet file and return data + * @ef: A valid eet file handle opened for reading. + * @name: Name of the entry. eg: "/base/file_i_want". + * @size_ret: Number of bytes read from entry and returned. + * + * This function finds an entry in the eet file that is stored under the + * name specified, and returns that data, decompressed, if successfule. + * NULL is retuurned 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. + */ + void *eet_read (Eet_File *ef, char *name, int *size_ret); + /* eet_write - Write a specified entry to an eet file handle + * @ef: A valid eet file handle opened for writing. + * @name: Name of the entry. eg: "/base/file_i_want". + * @data: Pointer to the data to be stored. + * @size: Length in bytes in the data to be stored. + * @compress: Compression flags (1 == compress, 0 = don't compress). + * + * This function will write the specified chunk of data to the eet file + * and return 1 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). + */ + int eet_write (Eet_File *ef, char *name, void *data, int size, int compress); + /* eet_list - List all entries in eet file matching shell glob. + * @ef: A valid eet file handle. + * @glob: A shell glob to match against. + * @count_ret: number of entries foudn to match. + * + * 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 "*". + */ + char **eet_list (Eet_File *ef, char *glob, int *count_ret); + +/***************************************************************************/ + + /* eet_data_image_read - Read image data from the named key in the eet file. + * @ef: A valid eet file handle opened for reading. + * @name: Name of the entry. eg: "/base/file_i_want". + * @w: A pointer to the int to hold the width in pixels. + * @h: A pointer to the int to hold the height in pixels. + * @alpha: A pointer to the int to hold the alpha flag. + * @compress: A pointer to the int to hold the compression amount. + * @quality: A pointer to the int to hold the quality amount. + * @lossy: A pointer to the int to hold the lossiness flag. + * + * 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 piel 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 denoties that it is significant. + * Compress is fiulled with the compression value/amount the image was + * stored with. The quality value si fileld 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. + */ + void *eet_data_image_read(Eet_File *ef, char *name, int *w, int *h, int *alpha, int *compress, int *quality, int *lossy); + /* eet_data_image_write - Write image data to the named key in an eet file. + * @ef: A valid eet file handle opened for writing. + * @name: Name of the entry. eg: "/base/file_i_want". + * @data: A pointer to the image pixel data. + * @w: The width of the image in pixels. + * @h: The height of the image in pixels. + * @alpha: The alpha channel flag. + * @compress: The compression amount. + * @quality: The quality encoding amount. + * @lossy: The lossiness flag. + * + * This function dates 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 wierd 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 shoudl 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 rtuens the numebr fo bytes that were required + * to encode the image data, or on failure it returns 0. + */ + int eet_data_image_write(Eet_File *ef, char *name, void *data, int w, int h, int alpha, int compress, int quality, int lossy); + + /* To Be Documented + * + */ + void *eet_data_image_encode(void *data, int *size_ret, int w, int h, int alpha, int compress, int quality, int lossy); + void *eet_data_image_decode(void *data, int size, int *w, int *h, int *alpha, int *compress, int *quality, int *lossy); +/***************************************************************************/ + + /* To Be Documented + * + */ + Eet_Data_Descriptor *eet_data_descriptor_new(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_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 eet_data_descriptor_free(Eet_Data_Descriptor *edd); + + void eet_data_descriptor_element_add(Eet_Data_Descriptor *edd, char *name, int type, int group_type, int offset, int count, char *counter_name, Eet_Data_Descriptor *subtype); + + void *eet_data_read(Eet_File *ef, Eet_Data_Descriptor *edd, char *name); + int eet_data_write(Eet_File *ef, Eet_Data_Descriptor *edd, char *name, void *data, int compress); + + void *eet_data_descriptor_decode(Eet_Data_Descriptor *edd, void *data_in, int size_in); + void *eet_data_descriptor_encode(Eet_Data_Descriptor *edd, void *data_in, int *size_ret); + +#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, NULL, NULL); \ + } +#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, NULL, subtype); \ + } +#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, NULL, subtype); \ + } + +/***************************************************************************/ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am new file mode 100644 index 0000000..9477e00 --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,20 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = 1.4 foreign + +# A list of all the files in the current directory which can be regenerated +MAINTAINERCLEANFILES = Makefile.in + +LDFLAGS = -L/usr/local/lib +INCLUDES = -I/usr/local/include \ + -I$(includedir) + +lib_LTLIBRARIES = libeet.la +include_HEADERS = Eet.h +libeet_la_SOURCES = \ +eet_lib.c \ +eet_data.c + +libeet_la_LIBADD = $(LDFLAGS) -lz -ljpeg +libeet_la_DEPENDENCIES = $(top_builddir)/config.h +libeet_la_LDFLAGS = -version-info 0:1:0 diff --git a/src/lib/eet_data.c b/src/lib/eet_data.c new file mode 100644 index 0000000..d82b72b --- /dev/null +++ b/src/lib/eet_data.c @@ -0,0 +1,1765 @@ +#include "Eet.h" +#define _GNU_SOURCE /* need this for fmemopen & open_memstream */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * rotuines 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_Decoder Eet_Data_Basic_Type_Decoder; +typedef struct _Eet_Data_Chunk Eet_Data_Chunk; +typedef struct _Eet_Data_Stream Eet_Data_Stream; +typedef struct _JPEG_error_mgr *emptr; + +/*---*/ + +struct _Eet_Data_Basic_Type_Decoder +{ + int size; + int (*get) (void *src, void *src_end, void *dest); + void *(*put) (void *src, int *size_ret); +}; + +struct _Eet_Data_Chunk +{ + char *name; + int size; + void *data; +}; + +struct _Eet_Data_Stream +{ + void *data; + int size; + int pos; +}; + +struct _Eet_Data_Descriptor +{ + char *name; + int size; + struct { + void *(*list_next) (void *l); + void *(*list_append) (void *l, void *d); + void *(*list_data) (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); + } func; + struct { + int num; + Eet_Data_Element *set; + } elements; +}; + +struct _Eet_Data_Element +{ + char *name; + int type; + int group_type; + int offset; + int count; + char *counter_name; + Eet_Data_Descriptor *subtype; +}; + +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 void *eet_data_image_jpeg_rgb_decode(void *data, int size, int *w, int *h); +static void *eet_data_image_jpeg_alpha_decode(void *data, int size, unsigned int *d, int *w, int *h); +static void *eet_data_image_lossless_convert(int *size, void *data, int w, int h, int alpha); +static void *eet_data_image_lossless_compressed_convert(int *size, void *data, int w, int h, int alpha, int compression); +static void *eet_data_image_jpeg_convert(int *size, void *data, int w, int h, int alpha, int quality); +static void *eet_data_image_jpeg_alpha_convert(int *size, void *data, int w, int h, int alpha, int quality); + +static int eet_data_get_char(void *src, void *src_end, void *dest); +static void *eet_data_put_char(void *src, int *size_ret); +static int eet_data_get_short(void *src, void *src_end, void *dest); +static void *eet_data_put_short(void *src, int *size_ret); +static int eet_data_get_int(void *src, void *src_end, void *dest); +static void *eet_data_put_int(void *src, int *size_ret); +static int eet_data_get_long_long(void *src, void *src_end, void *dest); +static void *eet_data_put_long_long(void *src, int *size_ret); +static int eet_data_get_float(void *src, void *src_end, void *dest); +static void *eet_data_put_float(void *src, int *size_ret); +static int eet_data_get_double(void *src, void *src_end, void *dest); +static void *eet_data_put_double(void *src, int *size_ret); +static int eet_data_get_string(void *src, void *src_end, void *dest); +static void *eet_data_put_string(void *src, int *size_ret); + +static int eet_data_get_type(int type, void *src, void *src_end, void *dest); +static void *eet_data_put_type(int type, void *src, int *size_ret); + +static Eet_Data_Chunk *eet_data_chunk_get(void *src, int size); +static Eet_Data_Chunk *eet_data_chunk_new(void *data, int size, char *name); +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, void *data, int size); +static void eet_data_stream_free(Eet_Data_Stream *ds); + +static void eet_data_chunk_put(Eet_Data_Chunk *chnk, Eet_Data_Stream *ds); + +/*---*/ + +const Eet_Data_Basic_Type_Decoder eet_coder[] = +{ + {sizeof(char), eet_data_get_char, eet_data_put_char }, + {sizeof(short), eet_data_get_short, eet_data_put_short }, + {sizeof(int), eet_data_get_int, eet_data_put_int }, + {sizeof(long long), eet_data_get_long_long, eet_data_put_long_long}, + {sizeof(float), eet_data_get_float, eet_data_put_float }, + {sizeof(double), eet_data_get_double, eet_data_put_double }, + {sizeof(char), eet_data_get_char, eet_data_put_char }, + {sizeof(short), eet_data_get_short, eet_data_put_short }, + {sizeof(int), eet_data_get_int, eet_data_put_int }, + {sizeof(long long), eet_data_get_long_long, eet_data_put_long_long}, + {sizeof(char *), eet_data_get_string, eet_data_put_string } +}; + +static int words_bigendian = -1; + +/*---*/ + +#define SWAP64(x) (x) = \ + ((((x) & 0x00000000000000ff ) << 56) |\ + (((x) & 0x000000000000ff00 ) << 40) |\ + (((x) & 0x0000000000ff0000 ) << 24) |\ + (((x) & 0x00000000ff000000 ) << 8) |\ + (((x) & 0x000000ff00000000 ) >> 8) |\ + (((x) & 0x0000ff0000000000 ) >> 24) |\ + (((x) & 0x00ff000000000000 ) >> 40) |\ + (((x) & 0xff00000000000000 ) >> 56)) +#define SWAP32(x) (x) = \ + ((((x) & 0x000000ff ) << 24) |\ + (((x) & 0x0000ff00 ) << 8) |\ + (((x) & 0x00ff0000 ) >> 8) |\ + (((x) & 0xff000000 ) >> 24)) +#define SWAP16(x) (x) = \ + ((((x) & 0x00ff ) << 8) |\ + (((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 void * +eet_data_image_jpeg_rgb_decode(void *data, int size, int *w, int *h) +{ + unsigned int *d; + struct jpeg_decompress_struct cinfo; + struct _JPEG_error_mgr jerr; + unsigned char *ptr, *line[16], *tdata; + unsigned int *ptr2; + int x, y, l, i, scans, count, prevy; + FILE *f; + + f = fmemopen(data, (size_t)size, "r"); + if (!f) return NULL; + 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); + fclose(f); + return NULL; + } + 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; + /* end head decoding */ + /* data decoding */ + if (cinfo.rec_outbuf_height > 16) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return NULL; + } + tdata = malloc((*w) * 16 * 3); + if (!tdata) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return NULL; + } + d = malloc((*w) * (*h) * 4); + if (!d) + { + free(tdata); + jpeg_destroy_decompress(&cinfo); + fclose(f); + return NULL; + } + ptr2 = d; + count = 0; + prevy = 0; + if (cinfo.output_components == 3) + { + for (i = 0; i < cinfo.rec_outbuf_height; i++) + line[i] = tdata + (i * (*w) * 3); + 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; + for (y = 0; y < scans; y++) + { + for (x = 0; x < (*w); x++) + { + *ptr2 = + (0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << 8) | (ptr[2]); + ptr += 3; + ptr2++; + } + } + } + } + else 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; + for (y = 0; y < scans; y++) + { + for (x = 0; x < (*w); x++) + { + *ptr2 = + (0xff000000) | ((ptr[0]) << 16) | ((ptr[0]) << 8) | (ptr[0]); + ptr++; + ptr2++; + } + } + } + } + free(tdata); + fclose(f); + /* end data decoding */ + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + return d; +} + +static void * +eet_data_image_jpeg_alpha_decode(void *data, int size, unsigned int *d, int *w, int *h) +{ + struct jpeg_decompress_struct cinfo; + struct _JPEG_error_mgr jerr; + unsigned char *ptr, *line[16], *tdata; + unsigned int *ptr2; + int x, y, l, i, scans, count, prevy; + FILE *f; + + f = fmemopen(data, (size_t)size, "r"); + if (!f) return NULL; + 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); + fclose(f); + return NULL; + } + 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 */ + if ((*w) != cinfo.output_width) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return NULL; + } + if ((*h) != cinfo.output_height) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return NULL; + } + *w = cinfo.output_width; + *h = cinfo.output_height; + /* end head decoding */ + /* data decoding */ + if (cinfo.rec_outbuf_height > 16) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return NULL; + } + tdata = malloc((*w) * 16 * 3); + if (!tdata) + { + jpeg_destroy_decompress(&cinfo); + fclose(f); + return NULL; + } + ptr2 = d; + count = 0; + prevy = 0; + if (cinfo.output_components == 3) + { + for (i = 0; i < cinfo.rec_outbuf_height; i++) + line[i] = tdata + (i * (*w) * 3); + 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; + for (y = 0; y < scans; y++) + { + for (x = 0; x < (*w); x++) + { + *ptr2 = + ((*ptr2) & 0x00ffffff) | + (((ptr[0] + ptr[1] + ptr[2]) / 3) << 24); + ptr += 3; + ptr2++; + } + } + } + } + else 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; + for (y = 0; y < scans; y++) + { + for (x = 0; x < (*w); x++) + { + *ptr2 = + ((*ptr2) & 0x00ffffff) | + ((ptr[0]) << 24); + ptr++; + ptr2++; + } + } + } + } + free(tdata); + fclose(f); + /* end data decoding */ + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + return d; +} + +static void * +eet_data_image_lossless_convert(int *size, void *data, int w, 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; + header[0] = 0xac1dfeed; + header[1] = w; + header[2] = h; + header[3] = alpha; + header[4] = 0; + memcpy(d + 32, data, w * h * 4); + + if (words_bigendian) + { + 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, void *data, int w, 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; + 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) + { + 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); + *size = ((w * h * 4) + (8 * 4)); + return d; + } + memcpy(d + 32, comp, buflen); + *size = (8 * 4) + buflen; + free(comp); + return d; + } +} + +static void * +eet_data_image_jpeg_convert(int *size, void *data, int w, int h, int alpha, int quality) +{ + int *ptr; + char *d = NULL; + size_t sz = 0; + struct _JPEG_error_mgr jerr; + JSAMPROW *jbuf; + struct jpeg_compress_struct cinfo; + FILE *f; + unsigned char *buf; + + f = open_memstream(&d, &sz); + if (!f) return NULL; + + buf = malloc(3 * w); + if (!buf) + { + fclose(f); + if (d) free(d); + return NULL; + } + + 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); + if (buf) free(buf); + fclose(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); + jpeg_start_compress(&cinfo, TRUE); + + ptr = data; + while (cinfo.next_scanline < cinfo.image_height) + { + 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); + + *size = sz; + if (buf) free(buf); + fclose(f); + return d; +} + +static void * +eet_data_image_jpeg_alpha_convert(int *size, void *data, int w, int h, int alpha, int quality) +{ + unsigned char *d1, *d2; + unsigned char *d; + int *header; + int sz1, sz2; + + if (words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) words_bigendian = 1; + else words_bigendian = 0; + } + + { + int *ptr; + char *d = NULL; + size_t sz = 0; + struct _JPEG_error_mgr jerr; + JSAMPROW *jbuf; + struct jpeg_compress_struct cinfo; + FILE *f; + unsigned char *buf; + + f = open_memstream(&d, &sz); + if (!f) return NULL; + + buf = malloc(3 * w); + if (!buf) + { + fclose(f); + if (d) free(d); + return NULL; + } + + 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); + if (buf) free(buf); + fclose(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); + jpeg_start_compress(&cinfo, TRUE); + + ptr = data; + while (cinfo.next_scanline < cinfo.image_height) + { + 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); + + if (buf) free(buf); + fclose(f); + d1 = d; + sz1 = sz; + } + { + int *ptr; + char *d = NULL; + size_t sz = 0; + struct _JPEG_error_mgr jerr; + JSAMPROW *jbuf; + struct jpeg_compress_struct cinfo; + FILE *f; + unsigned char *buf; + + f = open_memstream(&d, &sz); + if (!f) + { + free(d1); + return NULL; + } + + buf = malloc(3 * w); + if (!buf) + { + fclose(f); + if (d) free(d); + free(d1); + return NULL; + } + + 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); + if (buf) free(buf); + fclose(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); + jpeg_start_compress(&cinfo, TRUE); + + ptr = data; + while (cinfo.next_scanline < cinfo.image_height) + { + 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); + + if (buf) free(buf); + fclose(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 < ((w * h) + 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; +} + + +/* CHAR TYPE */ +static int +eet_data_get_char(void *src, void *src_end, void *dst) +{ + char *s, *d; + + if ((src + sizeof(char)) > src_end) return -1; + s = (char *)src; + d = (char *)dst; + *s = *d; + CONV8(*s); + return sizeof(char); +} + +static void * +eet_data_put_char(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(void *src, void *src_end, void *dst) +{ + short *s, *d; + short tmp; + + if ((src + sizeof(short)) > src_end) return -1; + s = (short *)src; + d = (short *)dst; + /* alignment fixup */ + if ((int)s & (sizeof(short) - 1)) + { + memcpy(&tmp, s, sizeof(short)); + s = &tmp; + } + *d = *s; + CONV16(*d); + return sizeof(short); +} + +static void * +eet_data_put_short(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(void *src, void *src_end, void *dst) +{ + int *s, *d; + int tmp; + + if ((src + sizeof(int)) > src_end) return -1; + s = (int *)src; + d = (int *)dst; + /* alignment fixup */ + if ((int)s & (sizeof(int) - 1)) + { + memcpy(&tmp, s, sizeof(int)); + s = &tmp; + } + *d = *s; + CONV32(*d); + return sizeof(int); +} + +static void * +eet_data_put_int(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(void *src, void *src_end, void *dst) +{ + long long *s, *d; + long long tmp; + + if ((src + sizeof(long long)) > src_end) return -1; + s = (long long *)src; + d = (long long *)dst; + /* alignment fixup */ + if ((int)s & (sizeof(long long) - 1)) + { + memcpy(&tmp, s, sizeof(long long)); + s = &tmp; + } + *d = *s; + CONV64(*d); + return sizeof(long long); +} + +static void * +eet_data_put_long_long(void *src, int *size_ret) +{ + long long *s, *d; + + d = (long long *)malloc(sizeof(long long)); + if (!d) return NULL; + s = (long long *)src; + *d = *s; + CONV64(*d); + *size_ret = sizeof(long long); + return d; +} + +/* STRING TYPE */ +static int +eet_data_get_string(void *src, void *src_end, void *dst) +{ + char *s, **d, *p; + int len; + + s = (char *)src; + d = (char **)dst; + p = s; + len = 0; + while ((p < (char *)src_end) && (*p != 0)) {len++; p++;} + *d = malloc(len + 1); + if (!(*d)) return -1; + memcpy(*d, s, len); + (*d)[len] = 0; + return len + 1; +} + +static void * +eet_data_put_string(void *src, int *size_ret) +{ + char *s, *d; + int len; + + if (!src) src = ""; + s = (char *)(*((char **)src)); + len = strlen(s); + d = malloc(len + 1); + if (!d) return NULL; + strcpy(d, s); + *size_ret = len + 1; + return d; +} + +/* FLOAT TYPE */ +static int +eet_data_get_float(void *src, void *src_end, void *dst) +{ + float *d; + char *s, *str, *p, *prev_locale; + int len; + + s = (char *)src; + d = (float *)dst; + p = s; + len = 0; + while ((p < (char *)src_end) && (*p != 0)) {len++; p++;} + str = malloc(len + 1); + if (!str) return -1; + memcpy(str, s, len); + str[len] = 0; + + prev_locale = setlocale(LC_NUMERIC, "C"); + *d = (float)atof(str); + if (prev_locale) setlocale(LC_NUMERIC, prev_locale); + + free(str); + return len + 1; +} + +static void * +eet_data_put_float(void *src, int *size_ret) +{ + float *s; + char *d, buf[64], *prev_locale; + int len; + + s = (float *)src; + prev_locale = setlocale(LC_NUMERIC, "C"); + snprintf(buf, sizeof(buf), "%16.16f", (double)(*s)); + if (prev_locale) setlocale(LC_NUMERIC, prev_locale); + len = strlen(buf); + d = malloc(len + 1); + if (!d) return NULL; + strcpy(d, buf); + *size_ret = len + 1; + return d; +} + +/* DOUBLE TYPE */ +static int +eet_data_get_double(void *src, void *src_end, void *dst) +{ + double *d; + char *s, *str, *p, *prev_locale; + int len; + + s = (char *)src; + d = (double *)dst; + p = s; + len = 0; + while ((p < (char *)src_end) && (*p != 0)) {len++; p++;} + str = malloc(len + 1); + if (!str) return -1; + memcpy(str, s, len); + str[len] = 0; + + prev_locale = setlocale(LC_NUMERIC, "C"); + *d = (double)atof(str); + if (prev_locale) setlocale(LC_NUMERIC, prev_locale); + + free(str); + return len + 1; +} + +static void * +eet_data_put_double(void *src, int *size_ret) +{ + double *s; + char *d, buf[128], *prev_locale; + int len; + + s = (double *)src; + prev_locale = setlocale(LC_NUMERIC, "C"); + snprintf(buf, sizeof(buf), "%32.32f", (double)(*s)); + if (prev_locale) setlocale(LC_NUMERIC, prev_locale); + len = strlen(buf); + d = malloc(len + 1); + if (!d) return NULL; + strcpy(d, buf); + *size_ret = len + 1; + return d; +} + +static int +eet_data_get_type(int type, void *src, void *src_end, void *dest) +{ + int ret; + + ret = eet_coder[type - 1].get(src, src_end, dest); + return ret; +} + +static void * +eet_data_put_type(int type, void *src, int *size_ret) +{ + void *ret; + + ret = eet_coder[type - 1].put(src, size_ret); + return ret; +} + +/* chunk format... + * + * char[4] = "CHnK"; + * int = chunk size (including magic string); + * char[] = chuck magic/name string (0 byte terminated); + * ... sub-chunks (a chunk can contain chuncks recusrively) ... + * or + * ... payload data ... + * + */ + +static Eet_Data_Chunk * +eet_data_chunk_get(void *src, int size) +{ + Eet_Data_Chunk *chnk; + char *s; + int ret1, ret2; + + if (!src) return NULL; + if (size <= 8) return NULL; + + chnk = calloc(1, sizeof(Eet_Data_Chunk)); + if (!chnk) return NULL; + + s = src; + if ((s[0] != 'C') || (s[1] != 'H') || (s[2] != 'n') || (s[3] != 'K')) + { + free(chnk); + return NULL; + } + ret1 = eet_data_get_type(EET_T_INT, (void *)(s + 4), (void *)(s + size), &(chnk->size)); + if (ret1 <= 0) + { + free(chnk); + return NULL; + } + if ((chnk->size < 0) || ((chnk->size + 8) > size)) + { + free(chnk); + return NULL; + } + ret2 = eet_data_get_type(EET_T_STRING, (void *)(s + 8), (void *)(s + size), &(chnk->name)); + if (ret2 <= 0) + { + free(chnk); + return NULL; + } + chnk->data = src + 4 + ret1 + ret2; + chnk->size -= ret2; + return chnk; +} + +static Eet_Data_Chunk * +eet_data_chunk_new(void *data, int size, char *name) +{ + Eet_Data_Chunk *chnk; + + if (!name) return NULL; + chnk = calloc(1, sizeof(Eet_Data_Chunk)); + if (!chnk) return NULL; + + chnk->name = strdup(name); + chnk->size = size; + chnk->data = data; + + 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, void *data, int size) +{ + char *p; + + if ((ds->pos + size) > ds->size) + { + ds->data = realloc(ds->data, ds->size + size + 256); + if (!ds->data) + { + ds->pos = 0; + ds->size = 0; + return; + } + ds->size = ds->size + size + 256; + } + p = ds->data; + memcpy(p + ds->pos, data, size); + ds->pos += size; +} + +static void +eet_data_chunk_put(Eet_Data_Chunk *chnk, Eet_Data_Stream *ds) +{ + int *size; + int s; + int size_ret; + + if (!chnk->data) return; + /* chunk head */ + eet_data_stream_write(ds, "CHnK", 4); + /* size of chunk payload data + name */ + s = strlen(chnk->name) + 1 + chnk->size; + size = eet_data_put_int(&s, &size_ret); + if (size) + { + eet_data_stream_write(ds, size, size_ret); + free(size); + } + /* write chunk name */ + eet_data_stream_write(ds, chnk->name, strlen(chnk->name) + 1); + /* write payload */ + eet_data_stream_write(ds, chnk->data, chnk->size); +} + +/*---*/ + +int +eet_data_image_write(Eet_File *ef, char *name, + void *data, int w, 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; +} + +void * +eet_data_image_read(Eet_File *ef, char *name, + int *w, int *h, int *alpha, + int *compress, int *quality, int *lossy) +{ + void *data; + int size; + unsigned int *d = NULL; + int header[8]; + + data = eet_read(ef, name, &size); + if (!data) return NULL; + d = eet_data_image_decode(data, size, w, h, alpha, compress, quality, lossy); + free(data); + return d; +} + +void * +eet_data_image_encode(void *data, int *size_ret, int w, 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_convert(&size, data, w, h, alpha); + else + d = eet_data_image_lossless_compressed_convert(&size, data, w, h, alpha, compress); + } + 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; +} + +void * +eet_data_image_decode(void *data, int size, int *w, int *h, int *alpha, int *compress, int *quality, int *lossy) +{ + unsigned int *d = NULL; + 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 NULL; + + memcpy(header, data, 32); + if (words_bigendian) + { + int i; + + for (i = 0; i < 8; i++) SWAP32(header[i]); + } + if (header[0] == 0xac1dfeed) + { + int iw, ih, al, cp; + unsigned int *body; + + iw = header[1]; + ih = header[2]; + al = header[3]; + cp = header[4]; + if ((iw > 8192) || (ih > 8192)) return NULL; + if ((cp == 0) && (size < ((iw * ih * 4) + 32))) return NULL; + body = ((unsigned int *)data) + 8; + d = malloc(iw * ih * 4); + if (!d) return NULL; + if (!cp) + { + memcpy(d, body, iw * ih * 4); + if (words_bigendian) + { + int x; + + for (x = 0; x < (iw * ih); x++) SWAP32(d[x]); + } + } + else + { + uLongf dlen; + + dlen = iw * ih * 4; + uncompress((Bytef *)d, &dlen, (Bytef *)body, + (uLongf)(size - 32)); + if (words_bigendian) + { + int x; + + for (x = 0; x < (iw * ih); x++) SWAP32(d[x]); + } + } + if (d) + { + if (w) *w = iw; + if (h) *h = ih; + if (alpha) *alpha = al; + if (compress) *compress = cp; + if (lossy) *lossy = 0; + if (quality) *quality = 100; + } + } + else if (header[0] == 0xbeeff00d) + { + int iw = 0, ih = 0; + int sz1, sz2; + unsigned char *dt; + + sz1 = header[1]; + sz2 = header[2]; + dt = data; + dt += 12; + d = eet_data_image_jpeg_rgb_decode(dt, sz1, &iw, &ih); + if (d) + { + dt += sz1; + eet_data_image_jpeg_alpha_decode(dt, sz2, d, &iw, &ih); + } + if (d) + { + if (w) *w = iw; + if (h) *h = ih; + if (alpha) *alpha = 1; + if (compress) *compress = 0; + if (lossy) *lossy = 1; + if (quality) *quality = 75; + } + } + else + { + int iw = 0, ih = 0; + + d = eet_data_image_jpeg_rgb_decode(data, size, &iw, &ih); + if (d) + { + 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 d; +} + +Eet_Data_Descriptor * +eet_data_descriptor_new(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_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)) +{ + Eet_Data_Descriptor *edd; + + edd = calloc(1, sizeof(Eet_Data_Descriptor)); + edd->name = strdup(name); + edd->size = size; + edd->func.list_next = func_list_next; + edd->func.list_append = func_list_append; + edd->func.list_data = func_list_data; + edd->func.hash_foreach = func_hash_foreach; + edd->func.hash_add = func_hash_add; + return edd; +} + +void +eet_data_descriptor_free(Eet_Data_Descriptor *edd) +{ + int i; + + if (edd->name) free(edd->name); + for (i = 0; i < edd->elements.num; i++) + { + if (edd->elements.set[i].name) free(edd->elements.set[i].name); + if (edd->elements.set[i].counter_name) free(edd->elements.set[i].counter_name); + } + if (edd->elements.set) free(edd->elements.set); + free(edd); +} + +void +eet_data_descriptor_element_add(Eet_Data_Descriptor *edd, char *name, int type, + int group_type, + int offset, + int count, char *counter_name, + Eet_Data_Descriptor *subtype) +{ + Eet_Data_Element *ede; + + 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 = strdup(name); + ede->type = type; + ede->group_type = group_type; + ede->offset = offset; + ede->count = count; + if (counter_name) + ede->counter_name = strdup(counter_name); + else ede->counter_name = NULL; + ede->subtype = subtype; +} + +void * +eet_data_read(Eet_File *ef, Eet_Data_Descriptor *edd, char *name) +{ + void *data_dec; + void *data; + int size; + + data = eet_read(ef, name, &size); + if (!data) return NULL; + data_dec = eet_data_descriptor_decode(edd, data, size); + free(data); + return data_dec; +} + +int +eet_data_write(Eet_File *ef, Eet_Data_Descriptor *edd, char *name, void *data, int compress) +{ + void *data_enc; + int size; + int val; + + data_enc = eet_data_descriptor_encode(edd, data, &size); + if (!data_enc) return 0; + val = eet_write(ef, name, data_enc, size, compress); + free(data_enc); + return val; +} + +void * +eet_data_descriptor_decode(Eet_Data_Descriptor *edd, + void *data_in, + int size_in) +{ + void *data; + char *p; + int size; + 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; + } + + data = calloc(1, edd->size); + if (!data) return NULL; + chnk = eet_data_chunk_get(data_in, size_in); + if (!chnk) + { + free(data); + return NULL; + } + if (strcmp(chnk->name, edd->name)) + { + eet_data_chunk_free(chnk); + free(data); + return NULL; + } + p = chnk->data; + size = size_in - (4 + 4 + strlen(chnk->name) + 1); + while (size > 0) + { + Eet_Data_Chunk *echnk; + int i; + + /* get next data chunk */ + echnk = eet_data_chunk_get(p, size); + if (!echnk) + { + /* FIXME: partially built data struct - leak!!!! */ + free(data); + eet_data_chunk_free(chnk); + return NULL; + } + for (i = 0; i < edd->elements.num; i++) + { + Eet_Data_Element *ede; + + ede = &(edd->elements.set[i]); + if (!strcmp(echnk->name, ede->name)) + { + if (ede->group_type == EET_G_UNKNOWN) + { + int ret; + void *data_ret; + + if ((ede->type >= EET_T_CHAR) && + (ede->type <= EET_T_STRING)) + { + ret = eet_data_get_type(ede->type, + echnk->data, + ((char *)echnk->data) + echnk->size, + ((char *)data) + ede->offset); + } + else if (ede->subtype) + { + void **ptr; + + data_ret = eet_data_descriptor_decode(ede->subtype, + echnk->data, + echnk->size); + ptr = (void **)(((char *)data) + ede->offset); + *ptr = (void *)data_ret; + } + } + else + { + switch (ede->group_type) + { + case EET_G_ARRAY: + case EET_G_VAR_ARRAY: + { + printf("ARRAY TYPE NOT IMPLIMENTED YET!!!\n"); + } + break; + case EET_G_LIST: + { + int ret; + void *list = NULL; + void **ptr; + void *data_ret; + + ptr = (void **)(((char *)data) + ede->offset); + list = *ptr; + data_ret = NULL; + if ((ede->type >= EET_T_CHAR) && + (ede->type <= EET_T_STRING)) + { + data_ret = calloc(1, eet_coder[ede->type].size); + if (data_ret) + { + ret = eet_data_get_type(ede->type, + echnk->data, + ((char *)echnk->data) + echnk->size, + data_ret); + if (ret <= 0) + { + free(data_ret); + data_ret = NULL; + } + } + } + else if (ede->subtype) + { + data_ret = eet_data_descriptor_decode(ede->subtype, + echnk->data, + echnk->size); + } + if (data_ret) + { + list = edd->func.list_append(list, data_ret); + *ptr = list; + } + } + break; + case EET_G_HASH: + printf("HASH TYPE NOT IMPLIMENTED YET!!!\n"); + break; + default: + break; + } + } + break; + } + } + /* advance to next chunk */ + p += (4 + 4 + strlen(echnk->name) + 1 + echnk->size); + size -= (4 + 4 + strlen(echnk->name) + 1 + echnk->size); + eet_data_chunk_free(echnk); + } + eet_data_chunk_free(chnk); + return data; +} + +void * +eet_data_descriptor_encode(Eet_Data_Descriptor *edd, + void *data_in, + int *size_ret) +{ + Eet_Data_Chunk *chnk; + Eet_Data_Stream *ds; + int i; + void *cdata; + int csize; + + 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; + Eet_Data_Chunk *echnk; + void *data; + int size; + + ede = &(edd->elements.set[i]); + data = NULL; + if (ede->group_type == EET_G_UNKNOWN) + { + if ((ede->type >= EET_T_CHAR) && + (ede->type <= EET_T_STRING)) + data = eet_data_put_type(ede->type, + ((char *)data_in) + ede->offset, + &size); + else if (ede->subtype) + data = eet_data_descriptor_encode(ede->subtype, + *((char **)(((char *)data_in) + ede->offset)), + &size); + if (data) + { + echnk = eet_data_chunk_new(data, size, ede->name); + eet_data_chunk_put(echnk, ds); + eet_data_chunk_free(echnk); + free(data); + data = NULL; + } + } + else + { + switch (ede->group_type) + { + case EET_G_ARRAY: + case EET_G_VAR_ARRAY: + { + printf("ARRAY TYPE NOT IMPLIMENTED YET!!!\n"); + } + break; + case EET_G_LIST: + { + void *l; + + l = *((void **)(((char *)data_in) + ede->offset)); + for (; l; l = edd->func.list_next(l)) + { + if ((ede->type >= EET_T_CHAR) && + (ede->type <= EET_T_STRING)) + data = eet_data_put_type(ede->type, + edd->func.list_data(l), + &size); + else if (ede->subtype) + data = eet_data_descriptor_encode(ede->subtype, + edd->func.list_data(l), + &size); + if (data) + { + echnk = eet_data_chunk_new(data, size, ede->name); + eet_data_chunk_put(echnk, ds); + eet_data_chunk_free(echnk); + free(data); + data = NULL; + } + } + } + break; + case EET_G_HASH: + { + printf("HASH TYPE NOT IMPLIMENTED YET!!!\n"); + } + break; + default: + break; + } + } + } + chnk = eet_data_chunk_new(ds->data, ds->pos, edd->name); + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + + ds = eet_data_stream_new(); + eet_data_chunk_put(chnk, ds); + cdata = ds->data; + csize = ds->pos; + + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + *size_ret = csize; + eet_data_chunk_free(chnk); + + return cdata; +} diff --git a/src/lib/eet_lib.c b/src/lib/eet_lib.c new file mode 100644 index 0000000..e1cef9d --- /dev/null +++ b/src/lib/eet_lib.c @@ -0,0 +1,889 @@ +#include "Eet.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EET_MAGIC_FILE 0x1ee7ff00 +#define EET_MAGIC_FILE_HEADER 0x1ee7ff01 +#define EET_MAGIC_FILE_NODE 0x1ee7ff02 +#define EET_MAGIC_FILE_DIRECTORY 0x1ee7ff03 +#define EET_MAGIC_FILE_DIRECTORY_HASH 0x1ee7ff04 + +typedef struct _Eet_File_Header Eet_File_Header; +typedef struct _Eet_File_Node Eet_File_Node; +typedef struct _Eet_File_Directory Eet_File_Directory; +typedef struct _Eet_File_Directory_Hash Eet_File_Directory_Hash; + +struct _Eet_File +{ + int magic; + int references; + + char *path; + char *real_path; + + FILE *fp; + Eet_File_Mode mode; + + int writes_pending : 1; + + Eet_File_Header *header; +}; +struct _Eet_File_Header +{ + int magic; + Eet_File_Directory *directory; +}; +struct _Eet_File_Node +{ + char *name; + int offset; + int compression; + int size; + int data_size; + void *data; +}; +struct _Eet_File_Directory +{ + int size; + Eet_File_Directory_Hash *hash; +}; +struct _Eet_File_Directory_Hash +{ + int size; + Eet_File_Node *node; +}; + +#if 0 +/* 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) */ +} directory[num_directory_entries]; +/* and now startes the data stream... */ +#endif + +/* prototypes of internal calls */ +static Eet_File *eet_cache_find(char *real_path, Eet_File **cache, int cache_num); +static void eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num); +static void eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num); +static int eet_string_match(char *s1, char *s2); +static int eet_hash_gen(char *key, int hash_size); +static void eet_flush(Eet_File *ef); + +/* cache. i don't expect this to ever be large, so arrays will do */ +static int eet_writers_num = 0; +static Eet_File **eet_writers = NULL; +static int eet_readers_num = 0; +static Eet_File **eet_readers = NULL; + +/* find an eet file in the currently in use cache */ +static Eet_File * +eet_cache_find(char *real_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]->real_path, real_path)) 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) +{ + Eet_File **new_cache; + int new_cache_num; + + new_cache_num = *cache_num; + new_cache = *cache; + new_cache_num++; + new_cache = realloc(new_cache, new_cache_num * sizeof(Eet_File *)); + if (!new_cache) return; + new_cache[new_cache_num - 1] = ef; + *cache = new_cache; + *cache_num = new_cache_num; +} + +/* delete from cache */ +static void +eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num) +{ + Eet_File **new_cache; + int new_cache_num; + int i, j; + + new_cache_num = *cache_num; + new_cache = *cache; + 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]; + new_cache = realloc(new_cache, new_cache_num * sizeof(Eet_File *)); + *cache_num = new_cache_num; + if ((new_cache_num > 0) && (!new_cache)) return; + *cache = new_cache; +} + +/* internal string match. bails out at first mismatch - not comparing all */ +/* bytes in strings */ +static int +eet_string_match(char *s1, char *s2) +{ + /* both null- no match */ + if ((!s1) || (!s2)) return 0; + /* go thru - first mismatch - exit with 0 */ + do + { + if (*s1 != *s2) return 0; + s1++; + s2++; + } + while ((*s1) || (*s2)); + /* got this far. match */ + return 1; +} + +/* caluclate hash table entry valu with bitmask size of hash_size */ +static int +eet_hash_gen(char *key, int hash_size) +{ + int hash_num = 0; + 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 (ptr = key; *ptr; ptr++) hash_num ^= (int)(*ptr); + + /* mask it */ + hash_num &= masks[hash_size]; + /* return it */ + return hash_num; +} + +/* flush out writes to an eet file */ +static void +eet_flush(Eet_File *ef) +{ + int i, j, count, size, num, offset; + int head[3]; + unsigned long int i1, i2; + + /* check to see its' an eet file pointer */ + if ((!ef) || (ef->magic != EET_MAGIC_FILE)) + return; + if (ef->mode != EET_FILE_MODE_WRITE) return; + if (!ef->writes_pending) return; + + /* calculate total size in bytes of directory block */ + size = 0; + count = 0; + num = (1 << (ef->header->directory->size - 1)); + for (i = 0; i < num; i++) + { + for (j = 0; j < ef->header->directory->hash[i].size; j++) + { + size += 20 + strlen(ef->header->directory->hash[i].node[j].name); + count++; + } + } + /* caluclate offsets per entry */ + offset = 0; + for (i = 0; i < num; i++) + { + for (j = 0; j < ef->header->directory->hash[i].size; j++) + { + ef->header->directory->hash[i].node[j].offset = 12 + size + offset; + offset += ef->header->directory->hash[i].node[j].size; + } + } + /* go thru and write the header */ + i1 = (unsigned long int)EET_MAGIC_FILE; + i2 = htonl(i1); + head[0] = (int)i2; + i1 = (unsigned long int)count; + i2 = htonl(i1); + head[1] = (int)i2; + i1 = (unsigned long int)size; + i2 = htonl(i1); + head[2] = (int)i2; + fseek(ef->fp, 0, SEEK_SET); + if (fwrite(head, 12, 1, ef->fp) != 1) return; + offset = 12; + for (i = 0; i < num; i++) + { + for (j = 0; j < ef->header->directory->hash[i].size; j++) + { + unsigned char *buf; + int buf_size; + int name_size; + + name_size = strlen(ef->header->directory->hash[i].node[j].name); + buf_size = 20 + name_size; + buf = malloc(buf_size); + if (!buf) return; + i1 = (unsigned long int)ef->header->directory->hash[i].node[j].offset; + i2 = htonl(i1); + *((int *)(buf + 0)) = (int)i2; + i1 = (unsigned long int)ef->header->directory->hash[i].node[j].compression; + i2 = htonl(i1); + *((int *)(buf + 4)) = (int)i2; + i1 = (unsigned long int)ef->header->directory->hash[i].node[j].size; + i2 = htonl(i1); + *((int *)(buf + 8)) = (int)i2; + i1 = (unsigned long int)ef->header->directory->hash[i].node[j].data_size; + i2 = htonl(i1); + *((int *)(buf + 12)) = (int)i2; + i1 = (unsigned long int)name_size; + i2 = htonl(i1); + *((int *)(buf + 16)) = (int)i2; + memcpy(buf + 20, ef->header->directory->hash[i].node[j].name, name_size); + if (fwrite(buf, buf_size, 1, ef->fp) != 1) + { + free(buf); + return; + } + offset += buf_size; + free(buf); + } + } + /* write data */ + for (i = 0; i < num; i++) + { + for (j = 0; j < ef->header->directory->hash[i].size; j++) + { + if (fwrite(ef->header->directory->hash[i].node[j].data, + ef->header->directory->hash[i].node[j].size, + 1, ef->fp) != 1) + return; + } + } + /* no more writes pending */ + ef->writes_pending = 0; +} + +Eet_File * +eet_open(char *file, Eet_File_Mode mode) +{ + Eet_File *ef; + char buf[PATH_MAX]; + + /* in case this is a symlink... find out where it REALLY points */ + if (!realpath(file, buf)) + { + if (mode == EET_FILE_MODE_READ) return NULL; + } + + /* find the current file handle in cache*/ + ef = NULL; + if (mode == EET_FILE_MODE_READ) + ef = eet_cache_find(buf, eet_readers, eet_readers_num); + else if (mode == EET_FILE_MODE_WRITE) + ef = eet_cache_find(buf, eet_writers, eet_writers_num); + /* we found one */ + if (ef) + { + /* reference it up and return it */ + ef->references++; + return ef; + } + + /* allocate struct for eet file and have it zero'd out */ + ef = calloc(sizeof(Eet_File), 1); + if (!ef) return NULL; + + /* fill some of the members */ + ef->path = strdup(file); + ef->real_path = strdup(buf); + ef->magic = EET_MAGIC_FILE; + ef->references = 1; + ef->mode = mode; + + /* try open the file based on mode */ + if (ef->mode == EET_FILE_MODE_READ) + ef->fp = fopen(ef->path, "r"); + else if (ef->mode == EET_FILE_MODE_WRITE) + { + /* opening for write - delete old copy of file right away */ + unlink(ef->real_path); + ef->fp = fopen(ef->path, "w"); + } + else + { + eet_close(ef); + return NULL; + } + + /* if we can't open - bail out */ + if (!ef->fp) + { + eet_close(ef); + return NULL; + } + + /* if we opened for read */ + if (mode == EET_FILE_MODE_READ) + { + unsigned char buf[12]; + unsigned char *dyn_buf, *p; + unsigned long int i1, i2; + int num_entries, byte_entries, i; + size_t count; + + /* build header table if read mode */ + /* geat header */ + count = fread(buf, 12, 1, ef->fp); + if (count != 1) + { + eet_close(ef); + return NULL; + } + /* get magic no */ + i1 = *((int *)(buf + 0)); + i2 = ntohl(i1); + if (i2 != EET_MAGIC_FILE) + { + eet_close(ef); + return NULL; + } + /* get entries count and byte count */ + i1 = *((int *)(buf + 4)); + i2 = ntohl(i1); + num_entries = (int)i2; + i1 = *((int *)(buf + 8)); + i2 = ntohl(i1); + byte_entries = (int)i2; + /* we cant have <= 0 values here - invalid */ + if ((num_entries <= 0) || (byte_entries <= 0)) + { + eet_close(ef); + return NULL; + } + /* we can't have more entires than minimum bytes for those! invalid! */ + if ((num_entries * 20) > byte_entries) + { + eet_close(ef); + return NULL; + } + /* allocate dynamic buffer for entire directory block */ + dyn_buf = malloc(byte_entries); + if (!dyn_buf) + { + eet_close(ef); + return NULL; + } + /* allocate header */ + ef->header = calloc(sizeof(Eet_File_Header), 1); + if (!ef->header) + { + free(dyn_buf); + eet_close(ef); + return NULL; + } + ef->header->magic = EET_MAGIC_FILE_HEADER; + /* allocate directory block in ram */ + ef->header->directory = calloc(sizeof(Eet_File_Directory), 1); + if (!ef->header->directory) + { + free(dyn_buf); + eet_close(ef); + return NULL; + } + /* 8 bit hash table (256 buckets) */ + ef->header->directory->size = 8; + /* allocate base hash table */ + ef->header->directory->hash = calloc(sizeof(Eet_File_Directory_Hash), (1 << (ef->header->directory->size - 1))); + if (!ef->header->directory->hash) + { + free(dyn_buf); + eet_close(ef); + return NULL; + } + /* actually read the directory block - all of it, into ram */ + count = fread(dyn_buf, byte_entries, 1, ef->fp); + if (count != 1) + { + free(dyn_buf); + eet_close(ef); + return NULL; + } + /* parse directory block */ + p = dyn_buf; + for (i = 0; i < num_entries; i++) + { + int offset; + int flags; + int size; + int data_size; + int name_size; + char *name; + int hash; + Eet_File_Node *node; + int node_size; + + /* out directory block is inconsistent - we have oveerun our */ + /* dynamic block buffer before we finished scanning dir entries */ + if (p >= (dyn_buf + byte_entries)) + { + free(dyn_buf); + eet_close(ef); + return NULL; + } + /* get entrie header */ + i1 = *((int *)(p + 0)); + i2 = ntohl(i1); + offset = (int)i2; + i1 = *((int *)(p + 4)); + i2 = ntohl(i1); + flags = (int)i2; + i1 = *((int *)(p + 8)); + i2 = ntohl(i1); + size = (int)i2; + i1 = *((int *)(p + 12)); + i2 = ntohl(i1); + data_size = (int)i2; + i1 = *((int *)(p + 16)); + i2 = ntohl(i1); + name_size = (int)i2; + /* invalid size */ + if (size <= 0) + { + free(dyn_buf); + eet_close(ef); + return NULL; + } + /* invalid name_size */ + if (name_size <= 0) + { + free(dyn_buf); + eet_close(ef); + return NULL; + } + /* reading name would mean falling off end of dyn_buf - invalid */ + if ((p + 16 + name_size) > (dyn_buf + byte_entries)) + { + free(dyn_buf); + eet_close(ef); + return NULL; + } + /* allocate name string */ + name = malloc(name_size + 1); + if (!name) + { + free(dyn_buf); + eet_close(ef); + return NULL; + } + /* copy name in and terminate it */ + strncpy(name, p + 20, name_size); + name[name_size] = 0; + + /* get hask bucket it should go in */ + hash = eet_hash_gen(name, ef->header->directory->size); + /* resize hask bucket */ + node = realloc(ef->header->directory->hash[hash].node, + (ef->header->directory->hash[hash].size + 1) * + sizeof(Eet_File_Node)); + if (!node) + { + free(dyn_buf); + eet_close(ef); + return NULL; + } + /* current node size */ + node_size = ef->header->directory->hash[hash].size; + /* resized node list set up */ + ef->header->directory->hash[hash].node = node; + /* new node at end */ + ef->header->directory->hash[hash].node[node_size].name = name; + ef->header->directory->hash[hash].node[node_size].offset = offset; + ef->header->directory->hash[hash].node[node_size].compression = flags; + ef->header->directory->hash[hash].node[node_size].size = size; + ef->header->directory->hash[hash].node[node_size].data_size = data_size; + /* currently we have no data loaded */ + ef->header->directory->hash[hash].node[node_size].data = NULL; + /* increment number of nodes */ + ef->header->directory->hash[hash].size++; + /* advance */ + p += 20 + name_size; + } + /* done - free dynamic buffer */ + free(dyn_buf); + } + /* add to cache */ + if (ef->mode == EET_FILE_MODE_READ) + eet_cache_add(ef, &eet_readers, &eet_readers_num); + else if (ef->mode == EET_FILE_MODE_WRITE) + eet_cache_add(ef, &eet_writers, &eet_writers_num); + return ef; +} + +void +eet_close(Eet_File *ef) +{ + /* check to see its' an eet file pointer */ + if ((!ef) || (ef->magic != EET_MAGIC_FILE)) + return; + /* deref */ + ef->references--; + /* if its still referenced - dont go any further */ + if (ef->references > 0) return; + /* remove from cache */ + if (ef->mode == EET_FILE_MODE_READ) + eet_cache_del(ef, &eet_readers, &eet_readers_num); + else if (ef->mode == EET_FILE_MODE_WRITE) + eet_cache_del(ef, &eet_writers, &eet_writers_num); + /* flush any writes */ + eet_flush(ef); + + /* free up members */ + if (ef->fp) fclose(ef->fp); + if (ef->path) free(ef->path); + if (ef->real_path) free(ef->real_path); + + /* free up data */ + if (ef->header) + { + if (ef->header->directory) + { + if (ef->header->directory->hash) + { + int i, num; + + num = (1 << (ef->header->directory->size - 1)); + for (i = 0; i < num; i++) + { + if (ef->header->directory->hash[i].node) + { + int j; + int num2; + + num2 = ef->header->directory->hash[i].size; + for (j = 0; j < num2; j++) + { + if (ef->header->directory->hash[i].node[j].name) + free(ef->header->directory->hash[i].node[j].name); + if (ef->header->directory->hash[i].node[j].data) + free(ef->header->directory->hash[i].node[j].data); + } + free(ef->header->directory->hash[i].node); + } + } + free(ef->header->directory->hash); + } + free(ef->header->directory); + } + free(ef->header); + } + + /* zero out ram for struct - caution tactic against stale memory use */ + memset(ef, 0, sizeof(Eet_File)); + /* free it */ + free(ef); +} + +void * +eet_read(Eet_File *ef, char *name, int *size_ret) +{ + void *data = NULL; + int size = 0, tmp_size; + int hash, i, num; + + /* check to see its' an eet file pointer */ + if ((!ef) || (ef->magic != EET_MAGIC_FILE)) + { + if (size_ret) *size_ret = 0; + return NULL; + } + /* get hash bucket this should be in */ + hash = eet_hash_gen(name, ef->header->directory->size); + /* hunt hash bucket */ + num = ef->header->directory->hash[hash].size; + for (i = 0; i < num; i++) + { + /* if it matches */ + if (eet_string_match(ef->header->directory->hash[hash].node[i].name, name)) + { + /* uncompressed data */ + if (ef->header->directory->hash[hash].node[i].compression == 0) + { + /* get size */ + size = ef->header->directory->hash[hash].node[i].size; + /* allocate data */ + data = malloc(size); + if (data) + { + /* if we alreayd have the data in ram... copy that */ + if (ef->header->directory->hash[hash].node[i].data) + memcpy(data, + ef->header->directory->hash[hash].node[i].data, + ef->header->directory->hash[hash].node[i].size); + /* or get data from disk */ + else + { + /* seek to data location */ + if (fseek(ef->fp, ef->header->directory->hash[hash].node[i].offset, SEEK_SET) < 0) + { + free(data); + data = NULL; + break; + } + /* read it */ + if (fread(data, size, 1, ef->fp) != 1) + { + free(data); + data = NULL; + break; + } + } + } + break; + } + /* compressed data */ + else + { + void *tmp_data; + + /* get size of data in file */ + tmp_size = ef->header->directory->hash[hash].node[i].size; + tmp_data = malloc(tmp_size); + if (!tmp_data) break; + /* get size uncompressed */ + size = ef->header->directory->hash[hash].node[i].data_size; + /* allocate data */ + data = malloc(size); + if (data) + { + uLongf dlen; + + /* if we already have the data in ram... copy that */ + if (ef->header->directory->hash[hash].node[i].data) + memcpy(tmp_data, + ef->header->directory->hash[hash].node[i].data, + tmp_size); + /* or get data from disk */ + else + { + /* seek to data location */ + if (fseek(ef->fp, ef->header->directory->hash[hash].node[i].offset, SEEK_SET) < 0) + { + free(tmp_data); + free(data); + data = NULL; + break; + } + /* read it */ + if (fread(tmp_data, tmp_size, 1, ef->fp) != 1) + { + free(tmp_data); + free(data); + data = NULL; + break; + } + } + /* decompress it */ + dlen = size; + if (uncompress((Bytef *)data, &dlen, + tmp_data, (uLongf)tmp_size)) + { + free(tmp_data); + free(data); + data = NULL; + break; + } + } + free(tmp_data); + break; + } + } + } + /* fill in return values */ + *size_ret = size; + /* update access time */ + return data; +} + +int +eet_write(Eet_File *ef, char *name, void *data, int size, int compress) +{ + int data_size; + int hash, node_size; + Eet_File_Node *node; + char *name2; + void *data2; + + /* check to see its' an eet file pointer */ + if ((!ef) || (ef->magic != EET_MAGIC_FILE) + || (!name) || (!data) || (size <= 0) || + (ef->mode != EET_FILE_MODE_WRITE)) + return 0; + + if (!ef->header) + { + /* allocate header */ + ef->header = calloc(sizeof(Eet_File_Header), 1); + if (!ef->header) return 0; + ef->header->magic = EET_MAGIC_FILE_HEADER; + /* allocate directory block in ram */ + ef->header->directory = calloc(sizeof(Eet_File_Directory), 1); + if (!ef->header->directory) return 0; + /* 8 bit hash table (256 buckets) */ + ef->header->directory->size = 8; + /* allocate base hash table */ + ef->header->directory->hash = calloc(sizeof(Eet_File_Directory_Hash), (1 << (ef->header->directory->size - 1))); + if (!ef->header->directory->hash) return 0; + } + /* figure hash bucket */ + hash = eet_hash_gen(name, ef->header->directory->size); + node_size = ef->header->directory->hash[hash].size; + /* dup name */ + name2 = strdup(name); + if (!name2) return 0; + /* dup data */ + data_size = size; + if (compress == 1) + data_size = 12 + ((size * 101) / 100); + data2 = malloc(data_size); + if (!data2) + { + free(name2); + return 0; + } + /* if we want to compress */ + if (compress == 1) + { + uLongf buflen; + + /* compress the data with max compression */ + if (compress2((Bytef *)data2, &buflen, (Bytef *)data, + (uLong)size, 9) != Z_OK) + { + free(name2); + free(data2); + return 0; + } + /* record compressed chunk size */ + data_size = (int)buflen; + if (data_size >= size) + { + compress = 0; + data_size = size; + } + } + if (!compress) + memcpy(data2, data, size); + /* increase hash bucket size */ + node = realloc(ef->header->directory->hash[hash].node, + (node_size + 1) * sizeof(Eet_File_Node)); + if (!node) + { + free(name2); + free(data2); + return 0; + } + /* resized node list set up */ + ef->header->directory->hash[hash].node = node; + /* new node at end */ + ef->header->directory->hash[hash].node[node_size].name = name2; + ef->header->directory->hash[hash].node[node_size].offset = 0; + ef->header->directory->hash[hash].node[node_size].compression = compress; + ef->header->directory->hash[hash].node[node_size].size = data_size; + ef->header->directory->hash[hash].node[node_size].data_size = size; + ef->header->directory->hash[hash].node[node_size].data = data2; + ef->header->directory->hash[hash].size++; + + /* flags that writes are pending */ + ef->writes_pending = 1; + /* update access time */ + return size; +} + +char ** +eet_list(Eet_File *ef, char *glob, int *count_ret) +{ + char **list_ret = NULL; + int list_count = 0; + int list_count_alloc = 0; + int i, j, num; + + /* check to see its' an eet file pointer */ + if ((!ef) || (ef->magic != EET_MAGIC_FILE) || (!glob)) + { + if (count_ret) *count_ret = 0; + return NULL; + } + /* loop through all entries */ + num = (1 << (ef->header->directory->size - 1)); + for (i = 0; i < num; i++) + { + for (j = 0; j < ef->header->directory->hash[i].size; j++) + { + /* if the entry matches the input glob */ + if (!fnmatch(glob, ef->header->directory->hash[i].node[j].name, 0)) + { + char **new_list; + + /* add it to our list */ + list_count++; + /* only realloc in 32 entry chunks */ + if (list_count > list_count_alloc) + { + list_count_alloc += 32; + 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] = ef->header->directory->hash[i].node[j].name; + } + } + } + /* return count and list */ + if (count_ret) *count_ret = list_count; + return list_ret; +} -- 2.7.4