diff --git a/.svnignore b/.svnignore new file mode 100644 index 000000000..e44c6013e --- /dev/null +++ b/.svnignore @@ -0,0 +1,12 @@ +autom4te.cache +*.in +aclocal.m4 +config.* +configure +depcomp +install-sh +*.pc +libtool +ltmain.sh +missing +stamp.h1 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..2af2daa33 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,31 @@ +In order of appearance in cvs: +------------------------------------------------ +"Funboard" +Steffen Hehn +Philipp Leusmann +Thomas Waldmann +Georg Lukas +Peter Feldbaumer +Rainer Scherg +M. Langer +Andreas Monzner +Matthias Kramer +Bastian Blank +Andreas Oberritter +Henning Heinold +Christian Scheele +Frank Bormann +Darius Hulboj +Dirk Szymanski +Michael Lantzen +Fakili Maho +Wolfram Joost +Alexander Wild +Ralf Gandy +Sven Traenkle +Florian Schirmer +Mike Bretz + +Also many thanks to everyone who supported development +without having cvs write access + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..1356a4690 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,3 @@ +AUTOMAKE_OPTIONS = gnu + +SUBDIRS = lib src data diff --git a/NEWS b/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 000000000..19409caae --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,406 @@ +AC_DEFUN([TUXBOX_APPS],[ +AM_CONFIG_HEADER(config.h) +AM_MAINTAINER_MODE + +AC_GNU_SOURCE +AC_SYS_LARGEFILE + +AC_ARG_WITH(target, + [ --with-target=TARGET target for compilation [[native,cdk]]], + [TARGET="$withval"],[TARGET="native"]) + +AC_ARG_WITH(targetprefix, + [ --with-targetprefix=PATH prefix relative to target root (only applicable in cdk mode)], + [targetprefix="$withval"],[targetprefix="NONE"]) + +AC_ARG_WITH(debug, + [ --without-debug disable debugging code], + [DEBUG="$withval"],[DEBUG="yes"]) + +if test "$DEBUG" = "yes"; then + DEBUG_CFLAGS="-g3 -ggdb" + AC_DEFINE(DEBUG,1,[Enable debug messages]) +fi + +AC_MSG_CHECKING(target) + +if test "$TARGET" = "native"; then + AC_MSG_RESULT(native) + + if test "$CFLAGS" = "" -a "$CXXFLAGS" = ""; then + CFLAGS="-Wall -O2 -pipe $DEBUG_CFLAGS" + CXXFLAGS="-Wall -O2 -pipe $DEBUG_CFLAGS" + fi + if test "$prefix" = "NONE"; then + prefix=/usr/local + fi + targetprefix=$prefix +elif test "$TARGET" = "cdk"; then + AC_MSG_RESULT(cdk) + + if test "$CC" = "" -a "$CXX" = ""; then + CC=powerpc-tuxbox-linux-gnu-gcc CXX=powerpc-tuxbox-linux-gnu-g++ + fi + if test "$CFLAGS" = "" -a "$CXXFLAGS" = ""; then + CFLAGS="-Wall -Os -mcpu=823 -pipe $DEBUG_CFLAGS" + CXXFLAGS="-Wall -Os -mcpu=823 -pipe $DEBUG_CFLAGS" + fi + if test "$prefix" = "NONE"; then + AC_MSG_ERROR(invalid prefix, you need to specify one in cdk mode) + fi + if test "$targetprefix" = "NONE"; then + targetprefix="" + fi + if test "$host_alias" = ""; then + cross_compiling=yes + host_alias=powerpc-tuxbox-linux-gnu + fi +else + AC_MSG_RESULT(none) + AC_MSG_ERROR([invalid target $TARGET, choose on from native,cdk]); +fi + +AC_CANONICAL_BUILD +AC_CANONICAL_HOST + +check_path () { + return $(perl -e "if(\"$1\"=~m#^/usr/(local/)?bin#){print \"0\"}else{print \"1\";}") +} + +]) + +AC_DEFUN([TUXBOX_APPS_DIRECTORY_ONE],[ +AC_ARG_WITH($1,[ $6$7 [[PREFIX$4$5]]],[ + _$2=$withval + if test "$TARGET" = "cdk"; then + $2=`eval echo "${targetprefix}$withval"` + else + $2=$withval + fi + TARGET_$2=${$2} +],[ + $2="\${$3}$5" + if test "$TARGET" = "cdk"; then + _$2=`eval echo "${target$3}$5"` + else + _$2=`eval echo "${$3}$5"` + fi + TARGET_$2=$_$2 +]) + +dnl automake <= 1.6 don't support this +dnl AC_SUBST($2) +AC_DEFINE_UNQUOTED($2,"$_$2",$7) +AC_SUBST(TARGET_$2) +]) + +AC_DEFUN([TUXBOX_APPS_DIRECTORY],[ +AC_REQUIRE([TUXBOX_APPS]) + +if test "$TARGET" = "cdk"; then + datadir="\${prefix}/share" + sysconfdir="\${prefix}/etc" + localstatedir="\${prefix}/var" + libdir="\${prefix}/lib" + targetdatadir="\${targetprefix}/share" + targetsysconfdir="\${targetprefix}/etc" + targetlocalstatedir="\${targetprefix}/var" + targetlibdir="\${targetprefix}/lib" +fi + +TUXBOX_APPS_DIRECTORY_ONE(configdir,CONFIGDIR,localstatedir,/var,/tuxbox/config, + [--with-configdir=PATH ],[where to find the config files]) + +TUXBOX_APPS_DIRECTORY_ONE(datadir,DATADIR,datadir,/share,/tuxbox, + [--with-datadir=PATH ],[where to find data]) + +TUXBOX_APPS_DIRECTORY_ONE(fontdir,FONTDIR,datadir,/share,/fonts, + [--with-fontdir=PATH ],[where to find the fonts]) + +TUXBOX_APPS_DIRECTORY_ONE(gamesdir,GAMESDIR,localstatedir,/var,/tuxbox/games, + [--with-gamesdir=PATH ],[where games data is stored]) + +TUXBOX_APPS_DIRECTORY_ONE(libdir,LIBDIR,libdir,/lib,/tuxbox, + [--with-libdir=PATH ],[where to find the internal libs]) + +TUXBOX_APPS_DIRECTORY_ONE(plugindir,PLUGINDIR,libdir,/lib,/tuxbox/plugins, + [--with-plugindir=PATH ],[where to find the plugins]) + +TUXBOX_APPS_DIRECTORY_ONE(ucodedir,UCODEDIR,localstatedir,/var,/tuxbox/ucodes, + [--with-ucodedir=PATH ],[where to find the ucodes]) + +TUXBOX_APPS_DIRECTORY_ONE(themesdir,THEMESDIR,datadir,/share,/tuxbox/neutrino/themes, + [--with-themesdir=PATH ],[where to find the themes (don't change)]) +]) + +dnl automake <= 1.6 needs this specifications +AC_SUBST(CONFIGDIR) +AC_SUBST(DATADIR) +AC_SUBST(FONTDIR) +AC_SUBST(GAMESDIR) +AC_SUBST(LIBDIR) +AC_SUBST(PLUGINDIR) +AC_SUBST(UCODEDIR) +AC_SUBST(THEMESDIR) +dnl end workaround + +AC_DEFUN([TUXBOX_APPS_ENDIAN],[ +AC_CHECK_HEADERS(endian.h) +AC_C_BIGENDIAN +]) + +AC_DEFUN([TUXBOX_APPS_DRIVER],[ +AC_ARG_WITH(driver, + [ --with-driver=PATH path for driver sources [[NONE]]], + [DRIVER="$withval"],[DRIVER=""]) + +if test -d "$DRIVER/include"; then + AC_DEFINE(HAVE_DBOX2_DRIVER,1,[Define to 1 if you have the dbox2 driver sources]) +else + AC_MSG_ERROR([can't find driver sources]) +fi + +AC_SUBST(DRIVER) + +CPPFLAGS="$CPPFLAGS -I$DRIVER/include" +]) + +AC_DEFUN([TUXBOX_APPS_DVB],[ +AC_ARG_WITH(dvbincludes, + [ --with-dvbincludes=PATH path for dvb includes [[NONE]]], + [DVBINCLUDES="$withval"],[DVBINCLUDES=""]) + +if test "$DVBINCLUDES"; then + CPPFLAGS="$CPPFLAGS -I$DVBINCLUDES" +fi + +AC_CHECK_HEADERS(ost/dmx.h,[ + DVB_API_VERSION=1 + AC_MSG_NOTICE([found dvb version 1]) +]) + +if test -z "$DVB_API_VERSION"; then +AC_CHECK_HEADERS(linux/dvb/version.h,[ + AC_LANG_PREPROC_REQUIRE() + AC_REQUIRE([AC_PROG_EGREP]) + AC_LANG_CONFTEST([AC_LANG_SOURCE([[ +#include +version DVB_API_VERSION + ]])]) + DVB_API_VERSION=`(eval "$ac_cpp conftest.$ac_ext") 2>&AS_MESSAGE_LOG_FD | $EGREP "^version" | sed "s,version\ ,,"` + rm -f conftest* + + AC_MSG_NOTICE([found dvb version $DVB_API_VERSION]) +]) +fi + +if test "$DVB_API_VERSION"; then + AC_DEFINE(HAVE_DVB,1,[Define to 1 if you have the dvb includes]) + AC_DEFINE_UNQUOTED(HAVE_DVB_API_VERSION,$DVB_API_VERSION,[Define to the version of the dvb api]) +else + AC_MSG_ERROR([can't find dvb headers]) +fi +]) + +AC_DEFUN([TUXBOX_APPS_CAPTURE],[ +AC_CHECK_HEADER(linux/dvb/avia/avia_gt_capture.h,[ + AC_DEFINE(HAVE_OLD_CAPTURE_API,1,[Define this if you want to use the old dbox2 capture API]) + AC_MSG_NOTICE([using old demux capture API])],[ + AC_MSG_NOTICE([using v4l2 capture API]) + ]) +]) + +AC_DEFUN([_TUXBOX_APPS_LIB_CONFIG],[ +AC_PATH_PROG($1_CONFIG,$2,no) +if test "$$1_CONFIG" != "no"; then + if test "$TARGET" = "cdk" && check_path "$$1_CONFIG"; then + AC_MSG_$3([could not find a suitable version of $2]); + else + if test "$1" = "CURL"; then + $1_CFLAGS=$($$1_CONFIG --cflags) + $1_LIBS=$($$1_CONFIG --libs) + else + if test "$1" = "FREETYPE"; then + $1_CFLAGS=$($$1_CONFIG --cflags) + $1_LIBS=$($$1_CONFIG --libs) + else + $1_CFLAGS=$($$1_CONFIG --prefix=$targetprefix --cflags) + $1_LIBS=$($$1_CONFIG --prefix=$targetprefix --libs) + fi + fi + fi +fi + +AC_SUBST($1_CFLAGS) +AC_SUBST($1_LIBS) +]) + +AC_DEFUN([TUXBOX_APPS_LIB_CONFIG],[ +_TUXBOX_APPS_LIB_CONFIG($1,$2,ERROR) +if test "$$1_CONFIG" = "no"; then + AC_MSG_ERROR([could not find $2]); +fi +]) + +AC_DEFUN([TUXBOX_APPS_LIB_CONFIG_CHECK],[ +_TUXBOX_APPS_LIB_CONFIG($1,$2,WARN) +]) + +AC_DEFUN([TUXBOX_APPS_PKGCONFIG],[ +AC_PATH_PROG(PKG_CONFIG, pkg-config,no) +if test "$PKG_CONFIG" = "no" ; then + AC_MSG_ERROR([could not find pkg-config]); +fi +]) + +AC_DEFUN([_TUXBOX_APPS_LIB_PKGCONFIG],[ +AC_REQUIRE([TUXBOX_APPS_PKGCONFIG]) +AC_MSG_CHECKING(for package $2) +if PKG_CONFIG_PATH="${prefix}/lib/pkgconfig" $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + $1_CFLAGS=$(PKG_CONFIG_PATH="${prefix}/lib/pkgconfig" $PKG_CONFIG --cflags "$2") + $1_LIBS=$(PKG_CONFIG_PATH="${prefix}/lib/pkgconfig" $PKG_CONFIG --libs "$2") +else + AC_MSG_RESULT(no) +fi + +AC_SUBST($1_CFLAGS) +AC_SUBST($1_LIBS) +]) + +AC_DEFUN([TUXBOX_APPS_LIB_PKGCONFIG],[ +_TUXBOX_APPS_LIB_PKGCONFIG($1,$2) +if test -z "$$1_CFLAGS" ; then + AC_MSG_ERROR([could not find package $2]); +fi +]) + +AC_DEFUN([TUXBOX_APPS_LIB_PKGCONFIG_CHECK],[ +_TUXBOX_APPS_LIB_PKGCONFIG($1,$2) +]) + +AC_DEFUN([_TUXBOX_APPS_LIB_SYMBOL],[ +AC_CHECK_LIB($2,$3,HAVE_$1="yes",HAVE_$1="no") +if test "$HAVE_$1" = "yes"; then + $1_LIBS=-l$2 +fi + +AC_SUBST($1_LIBS) +]) + +AC_DEFUN([TUXBOX_APPS_LIB_SYMBOL],[ +_TUXBOX_APPS_LIB_SYMBOL($1,$2,$3,ERROR) +if test "$HAVE_$1" = "no"; then + AC_MSG_ERROR([could not find $2]); +fi +]) + +AC_DEFUN([TUXBOX_APPS_LIB_CONFIG_SYMBOL],[ +_TUXBOX_APPS_LIB_SYMBOL($1,$2,$3,WARN) +]) + +AC_DEFUN([TUXBOX_APPS_GETTEXT],[ +AC_PATH_PROG(MSGFMT, msgfmt, no) +AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) +AC_PATH_PROG(XGETTEXT, xgettext, no) +AC_PATH_PROG(MSGMERGE, msgmerge, no) + +AC_MSG_CHECKING([whether NLS is requested]) +AC_ARG_ENABLE(nls, + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) +AC_MSG_RESULT($USE_NLS) +AC_SUBST(USE_NLS) + +if test "$USE_NLS" = "yes"; then + AC_CACHE_CHECK([for GNU gettext in libc], gt_cv_func_gnugettext_libc,[ + AC_TRY_LINK([ + #include + #ifndef __GNU_GETTEXT_SUPPORTED_REVISION + #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) + #endif + extern int _nl_msg_cat_cntr; + extern int *_nl_domain_bindings; + ],[ + bindtextdomain ("", ""); + return (int) gettext ("") + _nl_msg_cat_cntr + *_nl_domain_bindings; + ], gt_cv_func_gnugettext_libc=yes, gt_cv_func_gnugettext_libc=no + )] + ) + + if test "$gt_cv_func_gnugettext_libc" = "yes"; then + AC_DEFINE(ENABLE_NLS, 1, [Define to 1 if translation of program messages to the user's native language is requested.]) + gt_use_preinstalled_gnugettext=yes + else + USE_NLS=no + fi +fi + +if test -f "$srcdir/po/LINGUAS"; then + ALL_LINGUAS=$(sed -e "/^#/d" "$srcdir/po/LINGUAS") +fi + +POFILES= +GMOFILES= +UPDATEPOFILES= +DUMMYPOFILES= +for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" +done +INST_LINGUAS= +if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test -n "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done +fi +CATALOGS= +if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done +fi +AC_SUBST(POFILES) +AC_SUBST(GMOFILES) +AC_SUBST(UPDATEPOFILES) +AC_SUBST(DUMMYPOFILES) +AC_SUBST(CATALOGS) +]) + +dnl backward compatiblity +AC_DEFUN([AC_GNU_SOURCE], +[AH_VERBATIM([_GNU_SOURCE], +[/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif])dnl +AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl +AC_BEFORE([$0], [AC_RUN_IFELSE])dnl +AC_DEFINE([_GNU_SOURCE]) +]) + +AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +]) + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 000000000..2240566a3 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,72 @@ +#!/bin/sh + +package="tuxbox-neutrino" + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +cd "$srcdir" +DIE=0 + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to compile $package." + echo "Download the appropriate package for your system," + echo "or get the source from one of the GNU ftp sites" + echo "listed in http://www.gnu.org/order/ftp.html" + DIE=1 +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have automake installed to compile $package." + echo "Download the appropriate package for your system," + echo "or get the source from one of the GNU ftp sites" + echo "listed in http://www.gnu.org/order/ftp.html" + DIE=1 +} + +(libtool --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have libtool installed to compile $package." + echo "Download the appropriate package for your system," + echo "or get the source from one of the GNU ftp sites" + echo "listed in http://www.gnu.org/order/ftp.html" + DIE=1 +} + +#(gettext --version) < /dev/null > /dev/null 2>&1 || { +# echo +# echo "You must have gettext installed to compile $package." +# echo "Download the appropriate package for your system," +# echo "or get the source from one of the GNU ftp sites" +# echo "listed in http://www.gnu.org/order/ftp.html" +# DIE=1 +#} + +if test "$DIE" -eq 1; then + exit 1 +fi + +if [ ! -e acinclude.m4 ]; then + for i in .. ../.. ../../..; do + if [ -e `pwd`/$i/acinclude.m4 ]; then + ln -s `pwd`/$i/acinclude.m4 . + fi + done +fi + +echo "Generating configuration files for $package, please wait...." + +echo " aclocal $ACLOCAL_FLAGS" +aclocal $ACLOCAL_FLAGS +echo " libtoolize --automake" +libtoolize --automake +#echo " gettextize" +#gettextize +echo " autoconf" +autoconf +echo " autoheader" +autoheader +echo " automake --add-missing" +automake --add-missing diff --git a/configure.ac b/configure.ac new file mode 100644 index 000000000..77f3b8538 --- /dev/null +++ b/configure.ac @@ -0,0 +1,111 @@ +AC_INIT(tuxbox-neutrino,1.0.1) +AM_INIT_AUTOMAKE(tuxbox-neutrino,1.0.1) + +TUXBOX_APPS +TUXBOX_APPS_DIRECTORY + +AC_PROG_CC +AC_PROG_CXX +AC_DISABLE_STATIC +AM_PROG_LIBTOOL + +TUXBOX_APPS_DVB +#TUXBOX_APPS_DRIVER +TUXBOX_APPS_LIB_CONFIG(CURL,curl-config) +TUXBOX_APPS_LIB_CONFIG(FREETYPE,freetype-config) +TUXBOX_APPS_LIB_PKGCONFIG(OPENSSL,openssl) +TUXBOX_APPS_LIB_PKGCONFIG(ID3TAG,libid3tag) +TUXBOX_APPS_LIB_PKGCONFIG(MAD,libmad) +#TUXBOX_APPS_LIB_PKGCONFIG(VORBISIDEC,tremor) +TUXBOX_APPS_LIB_PKGCONFIG(PNG,libpng) +TUXBOX_APPS_LIB_PKGCONFIG(AVFORMAT,libavformat) +TUXBOX_APPS_LIB_PKGCONFIG(AVCODEC,libavcodec) +TUXBOX_APPS_LIB_PKGCONFIG(AVUTIL,libavutil) +#TUXBOX_APPS_LIB_PKGCONFIG(CONFIGFILE,tuxbox-configfile) +#TUXBOX_APPS_LIB_PKGCONFIG(CONNECTION,tuxbox-connection) +#TUXBOX_APPS_LIB_PKGCONFIG(EVENTSERVER,tuxbox-eventserver) +#TUXBOX_APPS_LIB_PKGCONFIG(LCDDISPLAY,tuxbox-lcddisplay) +#TUXBOX_APPS_LIB_PKGCONFIG(LIRCDCLIENT,tuxbox-lircdclient) +#TUXBOX_APPS_LIB_PKGCONFIG(NET,tuxbox-net) +#TUXBOX_APPS_LIB_PKGCONFIG(PLUGINS,tuxbox-plugins) +#TUXBOX_APPS_LIB_PKGCONFIG(TUXBOX,tuxbox) +#TUXBOX_APPS_LIB_PKGCONFIG(UCODES,tuxbox-ucodes) +#TUXBOX_APPS_LIB_PKGCONFIG(MPEGTOOLS,tuxbox-mpegtools) +#TUXBOX_APPS_LIB_PKGCONFIG(TUXTXT,tuxbox-tuxtxt) + +AC_ARG_ENABLE(keyboard-no-rc, + [ --enable-keyboard-no-rc enable keyboard control, disable rc control], + [AC_DEFINE(KEYBOARD_INSTEAD_OF_REMOTE_CONTROL,1,[enable keyboard control, disable rc control])]) + +AC_ARG_ENABLE(restore-prev-mode, + [ --enable-restore-prev-mode enable return from graphics mode], + [AC_DEFINE(RETURN_FROM_GRAPHICS_MODE,1,[enable return from graphics mode])]) + +# +# Check for libtdservicedb - the new one - for testing only +# +#CSL_VERSION=0.0.1 +#FCSL_VERSION=`$PKG_CONFIG --modversion libcoolstream` +#AC_MSG_CHECKING(for package libcoolstream >= $CSL_VERSION) +#if $PKG_CONFIG --atleast-version $CSL_VERSION libcoolstream ; then + #AC_MSG_RESULT(found (version $FCSL_VERSION)) + #LIBCS_CFLAGS=`$PKG_CONFIG --cflags libcoolstream` + #LIBCS_LIBS=`$PKG_CONFIG --libs libcoolstream` +#else + #AC_MSG_ERROR([ +#*** libcoolstream $CSL_VERSION or newer is required! *** + #]) +#fi +AC_SUBST(LIBCS_CFLAGS) +AC_SUBST(LIBCS_LIBS) +AC_SUBST(FREETYPE_CFLAGS) +AC_SUBST(FREETYPE_LIBS) +AC_SUBST(VORBISIDEC_CFLAGS) +AC_SUBST(VORBISIDEC_LIBS) + +AC_OUTPUT([ +Makefile +lib/Makefile +lib/libconfigfile/Makefile +lib/connection/Makefile +lib/libeventserver/Makefile +lib/libmd5sum/Makefile +lib/libnet/Makefile +lib/xmltree/Makefile +lib/controldclient/Makefile +lib/sectionsdclient/Makefile +lib/timerdclient/Makefile +lib/libtuxtxt/Makefile +lib/libdvbsub/Makefile +lib/libupnpclient/Makefile +src/nhttpd/Makefile +src/nhttpd/web/Makefile +src/nhttpd/web/images/Makefile +src/nhttpd/web/scripts/Makefile +src/nhttpd/tuxboxapi/Makefile +src/nhttpd/yhttpd_core/Makefile +src/nhttpd/yhttpd_mods/Makefile +src/Makefile +src/daemonc/Makefile +src/driver/pictureviewer/Makefile +src/driver/audiodec/Makefile +src/driver/Makefile +src/gui/Makefile +src/gui/bedit/Makefile +src/gui/widget/Makefile +src/system/Makefile +data/Makefile +data/fonts/Makefile +data/icons/Makefile +data/iso-codes/Makefile +data/lcd/Makefile +data/lcd/icons/Makefile +data/lcd/clock/Makefile +data/locale/Makefile +src/sectionsd/Makefile +src/timerd/Makefile +src/zapit/Makefile +src/zapit/lib/Makefile +src/zapit/src/Makefile +]) + diff --git a/cross-configure.cool b/cross-configure.cool new file mode 100755 index 000000000..00d022f0f --- /dev/null +++ b/cross-configure.cool @@ -0,0 +1,32 @@ +#!/bin/sh + +PREFIX=/opt/newcross/arm-cx2450x-linux-gnueabi/arm-cx2450x-linux-gnueabi/sys-root/usr +CCPATH= +HOST=arm-cx2450x-linux-gnueabi + +export PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig +export CC=$CCPATH$HOST-gcc +export AR=$CCPATH$HOST-ar +export NM=$CCPATH$HOST-nm +export RANLIB=$CCPATH$HOST-ranlib +export OBJDUMP=$CCPATH$HOST-objdump +export STRIP=$CCPATH$HOST-strip + +export CFLAGS="-Wall -g0 -O2 \ + -D__KERNEL_STRICT_NAMES -DUSE_NEVIS_GXA \ + -I"$PWD"/include -I"$PWD"/include/linux/dvb -I"$PREFIX"/include/freetype2" + +export CXXFLAGS="-Wall -g0 -O2 \ + -D__KERNEL_STRICT_NAMES -DUSE_NEVIS_GXA \ + -I"$PWD"/include -I"$PWD"/include/linux/dvb -I"$PREFIX"/include/freetype2" + +export LDFLAGS="-L"$PREFIX"/lib -lcurl -lssl -lcrypto -ldl" + +export DVB_API_VERSION=3 +export FREETYPE_CONFIG=$PREFIX/bin/freetype-config +export CURL_CONFIG=$PREFIX/bin/curl-config +export PKG_CONFIG_PATH==$PREFIX/lib/pkgconfig + +./autogen.sh +./configure --prefix=${PREFIX} --build=i386-pc-linux-gnu --host=$HOST --without-driver --with-target=cdk --with-targetprefix="" "$*" + diff --git a/cross-configure.tuxbox b/cross-configure.tuxbox new file mode 100755 index 000000000..ec653ef7e --- /dev/null +++ b/cross-configure.tuxbox @@ -0,0 +1,25 @@ +#!/bin/sh + +PREFIX=$HOME/dbox2/cdkroot +CCPATH= +HOST=powerpc-tuxbox-linux-gnu + +export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig +export CC=$CCPATH$HOST-gcc +export AR=$CCPATH$HOST-ar +export NM=$CCPATH$HOST-nm +export RANLIB=$CCPATH$HOST-ranlib +export OBJDUMP=$CCPATH$HOST-objdump +export STRIP=$CCPATH$HOST-strip + +export CFLAGS="-std=gnu99 -Wall -O2 -g0 -DNDEBUG -I"$PREFIX"/include/freetype2 -I"$PWD"/include -I"$PWD"/include/linux/dvb -DHAVE_DBOX2" +export CXXFLAGS="-std=gnu++98 -Wall -O2 -g0 -DNDEBUG -I"$PREFIX"/include/freetype2 -I"$PWD"/include -I"$PWD"/include/linux/dvbooo -DHAVE_DBOX2" + +export LDFLAGS="-L"$PREFIX"/lib -lcurl -lssl -lcrypto -ldl" + +export DVB_API_VERSION=3 +export FREETYPE_CONFIG=$PREFIX/bin/freetype-config + +./autogen.sh +./configure --prefix=$PREFIX --build=i386-pc-linux-gnu --host=$HOST --without-driver --with-target=cdk --with-targetprefix="/" "$*" + diff --git a/data/Makefile.am b/data/Makefile.am new file mode 100644 index 000000000..4fa783ab4 --- /dev/null +++ b/data/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = fonts icons iso-codes lcd locale diff --git a/data/fonts/12.pcf.gz b/data/fonts/12.pcf.gz new file mode 100644 index 000000000..161c87d77 Binary files /dev/null and b/data/fonts/12.pcf.gz differ diff --git a/data/fonts/14B.pcf.gz b/data/fonts/14B.pcf.gz new file mode 100644 index 000000000..e3bd7cd7b Binary files /dev/null and b/data/fonts/14B.pcf.gz differ diff --git a/data/fonts/15B.pcf.gz b/data/fonts/15B.pcf.gz new file mode 100644 index 000000000..2a1b1e757 Binary files /dev/null and b/data/fonts/15B.pcf.gz differ diff --git a/data/fonts/Makefile.am b/data/fonts/Makefile.am new file mode 100644 index 000000000..c6ce3f4a4 --- /dev/null +++ b/data/fonts/Makefile.am @@ -0,0 +1,7 @@ +installdir = $(FONTDIR) + +install_DATA = \ + micron.ttf micron_bold.ttf micron_italic.ttf \ + 12.pcf.gz 14B.pcf.gz 15B.pcf.gz \ + md_khmurabi_10.ttf + diff --git a/data/fonts/README.pcf b/data/fonts/README.pcf new file mode 100644 index 000000000..1f4f51fd8 --- /dev/null +++ b/data/fonts/README.pcf @@ -0,0 +1,10 @@ +12.pcf,gz, 14B.pcf.gz and 15B.pcf.gz are +Bitmap fonts taken from X11. Original names are + +6x12-ISO8859-1.pcf.gz +7x14-ISO8859-1.pcf.gz +9x15-ISO8859-1.pcf.gz + +Fontnames inside the fonts have been patched to Fix12,Fix14,Fix15 +(original name Fixed), cause tuxbox lcd-fontrenderer does not support +2 files for the same font with diffrent pixel sizes. diff --git a/data/fonts/md_khmurabi_10.ttf b/data/fonts/md_khmurabi_10.ttf new file mode 100644 index 000000000..2e8af5fd8 Binary files /dev/null and b/data/fonts/md_khmurabi_10.ttf differ diff --git a/data/fonts/micron.ttf b/data/fonts/micron.ttf new file mode 100644 index 000000000..7696532c5 Binary files /dev/null and b/data/fonts/micron.ttf differ diff --git a/data/fonts/micron_bold.ttf b/data/fonts/micron_bold.ttf new file mode 100644 index 000000000..78bd9beb3 Binary files /dev/null and b/data/fonts/micron_bold.ttf differ diff --git a/data/fonts/micron_italic.ttf b/data/fonts/micron_italic.ttf new file mode 100644 index 000000000..9967797ce Binary files /dev/null and b/data/fonts/micron_italic.ttf differ diff --git a/data/icons/0.raw b/data/icons/0.raw new file mode 100644 index 000000000..4c7cad03c Binary files /dev/null and b/data/icons/0.raw differ diff --git a/data/icons/1.raw b/data/icons/1.raw new file mode 100644 index 000000000..97d379fdd Binary files /dev/null and b/data/icons/1.raw differ diff --git a/data/icons/16_9.raw b/data/icons/16_9.raw new file mode 100644 index 000000000..1dfd0a709 Binary files /dev/null and b/data/icons/16_9.raw differ diff --git a/data/icons/16_9_gray.raw b/data/icons/16_9_gray.raw new file mode 100644 index 000000000..cef4c4882 Binary files /dev/null and b/data/icons/16_9_gray.raw differ diff --git a/data/icons/2.raw b/data/icons/2.raw new file mode 100644 index 000000000..9e37b1efe Binary files /dev/null and b/data/icons/2.raw differ diff --git a/data/icons/3.raw b/data/icons/3.raw new file mode 100644 index 000000000..41e7b42ec Binary files /dev/null and b/data/icons/3.raw differ diff --git a/data/icons/4.raw b/data/icons/4.raw new file mode 100644 index 000000000..ed31f741e Binary files /dev/null and b/data/icons/4.raw differ diff --git a/data/icons/5.raw b/data/icons/5.raw new file mode 100644 index 000000000..c8208aafc Binary files /dev/null and b/data/icons/5.raw differ diff --git a/data/icons/6.raw b/data/icons/6.raw new file mode 100644 index 000000000..59cc4da33 Binary files /dev/null and b/data/icons/6.raw differ diff --git a/data/icons/7.raw b/data/icons/7.raw new file mode 100644 index 000000000..539ae0ffe Binary files /dev/null and b/data/icons/7.raw differ diff --git a/data/icons/8.raw b/data/icons/8.raw new file mode 100644 index 000000000..544f7cf02 Binary files /dev/null and b/data/icons/8.raw differ diff --git a/data/icons/9.raw b/data/icons/9.raw new file mode 100644 index 000000000..309abc74f Binary files /dev/null and b/data/icons/9.raw differ diff --git a/data/icons/Makefile.am b/data/icons/Makefile.am new file mode 100644 index 000000000..da8d65ed0 --- /dev/null +++ b/data/icons/Makefile.am @@ -0,0 +1,17 @@ +installdir = $(DATADIR)/neutrino/icons + +install_DATA = \ + 16_9.raw 16_9_gray.raw audio.raw blau.raw border_lr.raw border_ul.raw \ + colors.raw dbox.raw dd.raw dd_avail.raw dd_gray.raw error.raw features.raw \ + file.raw folder.raw games.raw gelb.raw gruen.raw help.raw help_small.raw \ + home.raw info.raw keybinding.raw language.raw lcd.raw lock.raw mainmenue.raw \ + mounted.raw mp3.raw mute.raw network.raw not_mounted.raw numericpad.raw ok.raw power.raw radar.pal \ + radar0.raw radar1.raw radar2.raw radar3.raw radar4.raw radar5.raw radar6.raw \ + radar7.raw radar8.raw radar9.raw radiomode.pal radiomode.raw recording.raw \ + rot.raw scan.pal scan.raw settings.raw shell.raw shutdown.pal shutdown.raw softupdate.raw \ + streaming.raw timer.raw video.raw volume.raw volumebody.raw volumeslider2.raw \ + volumeslider2alpha.raw volumeslider2blue.raw volumeslider2green.raw \ + volumeslider2red.raw vtxt.raw vtxt_gray.raw movie.raw movieplayer.raw \ + hidden.raw bookmarkmanager.raw mute_small.raw dbox_small.raw \ + 0.raw 1.raw 2.raw 3.raw 4.raw 5.raw 6.raw 7.raw 8.raw 9.raw \ + up.raw right.raw down.raw left.raw fta.raw ca.raw diff --git a/data/icons/audio.raw b/data/icons/audio.raw new file mode 100644 index 000000000..f90b8c1c6 Binary files /dev/null and b/data/icons/audio.raw differ diff --git a/data/icons/blau.raw b/data/icons/blau.raw new file mode 100644 index 000000000..6514d89c2 Binary files /dev/null and b/data/icons/blau.raw differ diff --git a/data/icons/bookmarkmanager.raw b/data/icons/bookmarkmanager.raw new file mode 100755 index 000000000..788c83e40 Binary files /dev/null and b/data/icons/bookmarkmanager.raw differ diff --git a/data/icons/border_lr.raw b/data/icons/border_lr.raw new file mode 100644 index 000000000..6124b20a8 Binary files /dev/null and b/data/icons/border_lr.raw differ diff --git a/data/icons/border_ul.raw b/data/icons/border_ul.raw new file mode 100644 index 000000000..3393a7115 Binary files /dev/null and b/data/icons/border_ul.raw differ diff --git a/data/icons/ca.raw b/data/icons/ca.raw new file mode 100644 index 000000000..72e6921df Binary files /dev/null and b/data/icons/ca.raw differ diff --git a/data/icons/colors.raw b/data/icons/colors.raw new file mode 100644 index 000000000..04032bf79 Binary files /dev/null and b/data/icons/colors.raw differ diff --git a/data/icons/dbox.raw b/data/icons/dbox.raw new file mode 100644 index 000000000..b73f3e5ee Binary files /dev/null and b/data/icons/dbox.raw differ diff --git a/data/icons/dbox_small.raw b/data/icons/dbox_small.raw new file mode 100644 index 000000000..cffb98e1a Binary files /dev/null and b/data/icons/dbox_small.raw differ diff --git a/data/icons/dd.raw b/data/icons/dd.raw new file mode 100644 index 000000000..d0da4717e Binary files /dev/null and b/data/icons/dd.raw differ diff --git a/data/icons/dd_avail.raw b/data/icons/dd_avail.raw new file mode 100644 index 000000000..e24eae9b2 Binary files /dev/null and b/data/icons/dd_avail.raw differ diff --git a/data/icons/dd_gray.raw b/data/icons/dd_gray.raw new file mode 100644 index 000000000..f90074789 Binary files /dev/null and b/data/icons/dd_gray.raw differ diff --git a/data/icons/down.raw b/data/icons/down.raw new file mode 100644 index 000000000..568ab860c Binary files /dev/null and b/data/icons/down.raw differ diff --git a/data/icons/error.raw b/data/icons/error.raw new file mode 100644 index 000000000..c4d9dfcd3 Binary files /dev/null and b/data/icons/error.raw differ diff --git a/data/icons/features.raw b/data/icons/features.raw new file mode 100644 index 000000000..6827fa5ef Binary files /dev/null and b/data/icons/features.raw differ diff --git a/data/icons/file.raw b/data/icons/file.raw new file mode 100644 index 000000000..4d4e911be Binary files /dev/null and b/data/icons/file.raw differ diff --git a/data/icons/folder.raw b/data/icons/folder.raw new file mode 100644 index 000000000..0c4ab46f8 Binary files /dev/null and b/data/icons/folder.raw differ diff --git a/data/icons/fta.raw b/data/icons/fta.raw new file mode 100644 index 000000000..be8f7ba05 Binary files /dev/null and b/data/icons/fta.raw differ diff --git a/data/icons/games.raw b/data/icons/games.raw new file mode 100644 index 000000000..06202519c Binary files /dev/null and b/data/icons/games.raw differ diff --git a/data/icons/gelb.raw b/data/icons/gelb.raw new file mode 100644 index 000000000..f864848a3 Binary files /dev/null and b/data/icons/gelb.raw differ diff --git a/data/icons/gruen.raw b/data/icons/gruen.raw new file mode 100644 index 000000000..d742246dc Binary files /dev/null and b/data/icons/gruen.raw differ diff --git a/data/icons/help.raw b/data/icons/help.raw new file mode 100644 index 000000000..5c100306f Binary files /dev/null and b/data/icons/help.raw differ diff --git a/data/icons/help_small.raw b/data/icons/help_small.raw new file mode 100644 index 000000000..4549a5d13 Binary files /dev/null and b/data/icons/help_small.raw differ diff --git a/data/icons/hidden.raw b/data/icons/hidden.raw new file mode 100644 index 000000000..7f64e7fd2 Binary files /dev/null and b/data/icons/hidden.raw differ diff --git a/data/icons/home.raw b/data/icons/home.raw new file mode 100644 index 000000000..2e7849273 Binary files /dev/null and b/data/icons/home.raw differ diff --git a/data/icons/info.raw b/data/icons/info.raw new file mode 100644 index 000000000..6827fa5ef Binary files /dev/null and b/data/icons/info.raw differ diff --git a/data/icons/keybinding.raw b/data/icons/keybinding.raw new file mode 100644 index 000000000..8d38cd8dc Binary files /dev/null and b/data/icons/keybinding.raw differ diff --git a/data/icons/language.raw b/data/icons/language.raw new file mode 100644 index 000000000..d322ffd7e Binary files /dev/null and b/data/icons/language.raw differ diff --git a/data/icons/lcd.raw b/data/icons/lcd.raw new file mode 100644 index 000000000..3c476ee25 Binary files /dev/null and b/data/icons/lcd.raw differ diff --git a/data/icons/left.raw b/data/icons/left.raw new file mode 100644 index 000000000..b63814e3d Binary files /dev/null and b/data/icons/left.raw differ diff --git a/data/icons/lock.raw b/data/icons/lock.raw new file mode 100644 index 000000000..04b6e6994 Binary files /dev/null and b/data/icons/lock.raw differ diff --git a/data/icons/mainmenue.raw b/data/icons/mainmenue.raw new file mode 100644 index 000000000..9d913c7c9 Binary files /dev/null and b/data/icons/mainmenue.raw differ diff --git a/data/icons/mounted.raw b/data/icons/mounted.raw new file mode 100644 index 000000000..81acf7670 Binary files /dev/null and b/data/icons/mounted.raw differ diff --git a/data/icons/movie.raw b/data/icons/movie.raw new file mode 100644 index 000000000..ea1085a35 Binary files /dev/null and b/data/icons/movie.raw differ diff --git a/data/icons/movieplayer.raw b/data/icons/movieplayer.raw new file mode 100644 index 000000000..c8788f5bf Binary files /dev/null and b/data/icons/movieplayer.raw differ diff --git a/data/icons/mp3-0.jpg b/data/icons/mp3-0.jpg new file mode 100644 index 000000000..73364958a Binary files /dev/null and b/data/icons/mp3-0.jpg differ diff --git a/data/icons/mp3-1.jpg b/data/icons/mp3-1.jpg new file mode 100644 index 000000000..e4826fde1 Binary files /dev/null and b/data/icons/mp3-1.jpg differ diff --git a/data/icons/mp3-2.jpg b/data/icons/mp3-2.jpg new file mode 100644 index 000000000..079fb16df Binary files /dev/null and b/data/icons/mp3-2.jpg differ diff --git a/data/icons/mp3-3.jpg b/data/icons/mp3-3.jpg new file mode 100644 index 000000000..420aa2324 Binary files /dev/null and b/data/icons/mp3-3.jpg differ diff --git a/data/icons/mp3-4.jpg b/data/icons/mp3-4.jpg new file mode 100644 index 000000000..5de37cf74 Binary files /dev/null and b/data/icons/mp3-4.jpg differ diff --git a/data/icons/mp3-5.jpg b/data/icons/mp3-5.jpg new file mode 100644 index 000000000..1abefd2c2 Binary files /dev/null and b/data/icons/mp3-5.jpg differ diff --git a/data/icons/mp3-6.jpg b/data/icons/mp3-6.jpg new file mode 100644 index 000000000..711ed9539 Binary files /dev/null and b/data/icons/mp3-6.jpg differ diff --git a/data/icons/mp3-7.jpg b/data/icons/mp3-7.jpg new file mode 100644 index 000000000..396af3556 Binary files /dev/null and b/data/icons/mp3-7.jpg differ diff --git a/data/icons/mp3.jpg b/data/icons/mp3.jpg new file mode 100644 index 000000000..b25956a5a Binary files /dev/null and b/data/icons/mp3.jpg differ diff --git a/data/icons/mp3.raw b/data/icons/mp3.raw new file mode 100644 index 000000000..ea1085a35 Binary files /dev/null and b/data/icons/mp3.raw differ diff --git a/data/icons/mute.raw b/data/icons/mute.raw new file mode 100644 index 000000000..c87a418d9 Binary files /dev/null and b/data/icons/mute.raw differ diff --git a/data/icons/mute_small.raw b/data/icons/mute_small.raw new file mode 100644 index 000000000..6ff04f998 Binary files /dev/null and b/data/icons/mute_small.raw differ diff --git a/data/icons/network.raw b/data/icons/network.raw new file mode 100644 index 000000000..f551a5389 Binary files /dev/null and b/data/icons/network.raw differ diff --git a/data/icons/not_mounted.raw b/data/icons/not_mounted.raw new file mode 100644 index 000000000..9c17e7a77 Binary files /dev/null and b/data/icons/not_mounted.raw differ diff --git a/data/icons/numericpad.raw b/data/icons/numericpad.raw new file mode 100644 index 000000000..5806fa487 Binary files /dev/null and b/data/icons/numericpad.raw differ diff --git a/data/icons/ok.raw b/data/icons/ok.raw new file mode 100644 index 000000000..bf98a4d23 Binary files /dev/null and b/data/icons/ok.raw differ diff --git a/data/icons/power.raw b/data/icons/power.raw new file mode 100644 index 000000000..7e9c26209 Binary files /dev/null and b/data/icons/power.raw differ diff --git a/data/icons/radar.pal b/data/icons/radar.pal new file mode 100644 index 000000000..c558075ea Binary files /dev/null and b/data/icons/radar.pal differ diff --git a/data/icons/radar0.raw b/data/icons/radar0.raw new file mode 100644 index 000000000..2b81c6752 Binary files /dev/null and b/data/icons/radar0.raw differ diff --git a/data/icons/radar1.raw b/data/icons/radar1.raw new file mode 100644 index 000000000..5128a57de Binary files /dev/null and b/data/icons/radar1.raw differ diff --git a/data/icons/radar2.raw b/data/icons/radar2.raw new file mode 100644 index 000000000..3e7f25a76 Binary files /dev/null and b/data/icons/radar2.raw differ diff --git a/data/icons/radar3.raw b/data/icons/radar3.raw new file mode 100644 index 000000000..0524946ce Binary files /dev/null and b/data/icons/radar3.raw differ diff --git a/data/icons/radar4.raw b/data/icons/radar4.raw new file mode 100644 index 000000000..afb68e74b Binary files /dev/null and b/data/icons/radar4.raw differ diff --git a/data/icons/radar5.raw b/data/icons/radar5.raw new file mode 100644 index 000000000..38753247c Binary files /dev/null and b/data/icons/radar5.raw differ diff --git a/data/icons/radar6.raw b/data/icons/radar6.raw new file mode 100644 index 000000000..1270210f7 Binary files /dev/null and b/data/icons/radar6.raw differ diff --git a/data/icons/radar7.raw b/data/icons/radar7.raw new file mode 100644 index 000000000..af5fe8e4e Binary files /dev/null and b/data/icons/radar7.raw differ diff --git a/data/icons/radar8.raw b/data/icons/radar8.raw new file mode 100644 index 000000000..5331ad591 Binary files /dev/null and b/data/icons/radar8.raw differ diff --git a/data/icons/radar9.raw b/data/icons/radar9.raw new file mode 100644 index 000000000..6b6315c77 Binary files /dev/null and b/data/icons/radar9.raw differ diff --git a/data/icons/radio.jpg b/data/icons/radio.jpg new file mode 100644 index 000000000..0113c51ea Binary files /dev/null and b/data/icons/radio.jpg differ diff --git a/data/icons/radiomode.jpg b/data/icons/radiomode.jpg new file mode 100644 index 000000000..0113c51ea Binary files /dev/null and b/data/icons/radiomode.jpg differ diff --git a/data/icons/radiomode.pal b/data/icons/radiomode.pal new file mode 100644 index 000000000..22605624a Binary files /dev/null and b/data/icons/radiomode.pal differ diff --git a/data/icons/radiomode.raw b/data/icons/radiomode.raw new file mode 100644 index 000000000..804824dd6 --- /dev/null +++ b/data/icons/radiomode.raw @@ -0,0 +1 @@ +Ð@ÿ/./...................... . . . . . .. . ...............././/////////////=//=/==/==/=/=/=/=/=/=////..  .../...  .//==F=@F=========@@@@=@==@=========F=====F@F=======/////=/===F=@@G@G@GCGCF@=F======F=@@@G@@G@G@GCGCGCGCGCGCGCGCG@@G@GCGG@GGG@GG@GGGGG@GF@F@F@FF@FFGFFFF=F@F@F@F@FF@FF@FFFFFFFFFFFFFFFF@FF@FF@FFFFFFFFFFFFFFFFFFFFFFFF=F=F=====/====/=//////////(/.*.(/(.(.((.((.(.*/(/*(/**.*(((((((((((((((((((((((((((((((((%(((((%((((%(((%((%((%((%((((%(((((*(*****(**(**(*(( (/====@@F@@@@@@G@GCGCOGLGOLOOOOOLOOOOOOMOTOTTTTTTTOTOOOOTOTTTTTTTVTTVTVVTYVVTTTTTTTTVVYYYYYYYYYYYYYYYYYY[YYYYYYYYYYYYYYYYVYYVYVVVTVTVVVVVVVVVVTVTSTVTVTVTVTVTVSVVVVVVVVVVVUVVSVSVSVSVSSSSS/./............./......... .. . . . . ... ...................//2/////=/=/=/====F==@F==@=F=@F@=@F@F=F@===/.. .././....   . ..2=FCGCGCGCGCGC@GCGCGCGCGCGCG@F@F@GCG@G@G@G@CF@G@F======F=F@F@@FGGCGOGOGCG@F@@F@F@F@@GGGGCOGCOCOLOLOOLGLOOOOOOCOGGGCGOGOCOGOGOOOOOOOOOGOGG@GGGGGGGOGGGG@GFG@GGGGGG@GGGGGGGFGFGFGFGFGFGG@GGFGFG@GGGGGGGGGGGGFGGFGGFGF@FGF@F@F@F=F=F=F==F=====/=///=//=///=/8/=/==*=====/=/8/=*/*=*/**/*****8**********8***8*888888*8*8**********************&***(*****8**8*8*8*8*8****((( .===@F@CGCGGOCOOOOOOOOOMOOTOMOTOTOMOTOTOTTTTTTTTTTOOOTOTTTTTTVTYVVVTVTVTTTTTOTTTTTWVYYYYYYYY[YYY[YY[Y[YY[Y[Y[Y[YYYYYYYYYYYYYYYYYVVVTVVVVVVVVVVVVVTVTTVTVVVTVVTVVTVSVVVVVVVSVVSVSVSVSSVSTS//.........../....... . .. . ... . . .. .. .. .........../../////2/=/==2=/=2=F=F@F@@@@F@@@F@@F@@@@@F@F@F==/. ../...  ....../FCGCGLGOCOCOCOCGLGLGLGCGLG@G@GCGCGCGCG@GCGCG@@@F@F=F=F=@F@F@FCGCOGOLGOCG@G@G@G@G@GGCOOLOLOOOMOOOOOOMOOTOTTOOOLOOLOOOOOOOOMOTOOTOOOOOOOCOGGGGGGOGOGGGGGGCGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG@G@@F@F@=F@F@@@@==========/======@=@=========8==8==*=8=*=*8*8/8=*=8=8/88=88=88=88=8=888=8888888888*8*8*8*8*8&8********8*888888888888=8=88=****(((//==@@G@@GCGLOOMOTOMTMTOTTTTTTTTTTTTTTTTTTTTTTTTTOOOTOTTTTTTVTYVYYYYYYYYTTTTTQTTTWVVYYYYYY[YY[Z[YYYZ[Y[Y[Z[Z[[Z[Y[Y[YYYYY[Y[YY[YYYYYYVVVVVVTVVVTVVTVVTVTVTVVSVVVVVVVSVSVSVVSVTUTSVSVSSVSS//..........././..... .. .. . .. . . . ... ... ............./.2//////2/////=/====F@F@F@=F@=F@@F@F@F@=F=F==...   .  ......//FCGCGCOCOCCGCGCCCGC@CGCG@@@@G@GC@@G@GC@@F@@F@F@==/=F==F=F@F@F@@G@G@@F@F@FCFG@F@F@GGCGGCGLGOOOLOOLOOOOOMOOOLOGOGGGOGOOOOOOOOMOOOOOGGGCGG@GGCGGGGGGGGG@G@G@GGGGGGGGGGGGGFGFGFGGGGGGGGGGFG@GFGGGGGGGGGGGGGGGFGFFG@GF@FCF@F@F@=F=F=====F========/=/======@====8===/8/*//8/=*/8/*/8**/8*/**8*/*8*8/*8*8**8*8*888=8*8*****************&*****&****&********8*8*8*8*8****((((( .===F@F@@@G@GCGGLOOOOOTOTOTOTOMOOTMOTTMTTTTTTTTOOOMOTTTOTTTTTTVTYVVYTTTTTTTTTTWTTYYYYYYYYY[ZY[YZ[Y[YZ[Z[Y[Y[Y[Y[Y[Y[Y[Y[YYY[YY[Y[Y[YXYYVVVVVVVVVTVVTVTVTSVTVVVVVVVVVSVVTVSVTVVUSVSTSTSST/./......././/........ .. . .. .. .. .. . .. ...../..../../.2/.//.///////.////2=======/=/==/=/===/=/==////..  .... ./=F@CFC@@FC@F@@F=@@F@@===F=F@F@F=F=F=F=F=F=F==////2//=/=/=/=2=F=F=F=F=F@F@@F=F=F@@G@GCG@GCGCGCGGCGCGGGGCGGGGGGGGGGGGGGOGOGOGOGGG@G@FF@F@F@F@F@FFF@FF=F@FF@F@F@F@F@FFFF@FFFFFFFFFFFFFFFFF@FF@FFFFFFF@FFF@FFFFFFF@F@F@F@=F=2===//=2===/=//////////=*/=//*//*.((.*.(.(/*(/*/(*/*(/(*.((*(.(*((.(((((((((((*(*(*(*((((*(((%((((%((((%((%(((%((((%(((((*(*(*(*((((((( //===@F@F@@@G@G@GCGOOOOMOOTOOOMOOTOTTTTTTTTTTOOOOTOTOTOTOTOTTTTTTTTTTTTTTTTTTTTVYYYYYYY[ZY[YZ[YY[ZY[Y[Y[Z[Y[Z[Y[Y[Y[Y[Y[YYYYYYYY[YY[Y[YXYYYVVVVVVTVVTVVTVTVSVVVVVVVVVVVVSVVSVSVSVSSVSTU/../.././././1/./..... ... . .. .. .. .. .. .............././///1////./..//////======2==/=/=/==2=/2///=///..  ... ../=F@@GF@@F@@@===F=@=F====@F@F===F=F====F====2/////=/=2=/=/F/=2==2=F=F@@F@F@F=F@FG@G@G@G@G@GGCG@GGGCGGGGCGGGGGGGGGGGGGOOGOGGGGCFGF@F@G@F@F@F@F@FFF@F@FF@FF@FF@FFFF@FF@FFFFFFFFFF@FFF@FFFFFFFFFFFF@FFF@FF@F@F@=F=F=F=@F==F=2=F=2==/=/==/=/=/====/=/=/*//(/.*./(.(/*/*//*.**(*.**.(*((.*(((((((*((*((*((*(*(**(*(*((((*(((%((*(*%*((%((%(((%((((%((((%(((((((*( ./=@F@F@@G@G@G@GGCGGOOGOOOOOMOOTOMTOTTTTTTTTTOOOMOTTOTOTOTOTOTTTTTTTTTTTTVTTVTVYYYYY[YYYYYY[YY[ZY[YY[Y[Z[Y[Z[Y[Y[YY[YY[Y[Y[Y[Y[YYYYYXY[Y[YXYYYVVVVVVVTVVSVTVTVSVSVVVVXVVVVVVVVSVSTSSVSS/......../.2//.2....... .. .. .. .. . . .. ........../../.2//2////////././////=2======/=/=//=2==////./////..  ....../F@G@G@@G@F@F=F@=@F=@=F@F@@F=@F=@F===F==2===///////2/=/=F==2==2==F=@@F@@F@==F@F@G@FCF@F@FCGCGGCGGGGCGCGGGGGGGGGGGGGOOGOGGGCG@GF@FG@F@F@F@F@F@F@F@FF@F@F@F@F@F@FGFFFFGFFFFFFF@FFFF@FFFF@FFFFFFGFFFFFFF@FF@FFF=F==F=F=F====2==2==/==2=========/=//*/.(/(/.(//*//*/*//(*/**.*(*.*((((((((*.*(**(*(*(*((*(*((*(((((*%((((%(((((%(((((%(((%((((%((((*(*(((*((*((*(..=F@@@G@G@GCG@GCGLGOOOOOOGOOGLGOOOMOOTTTTTTOOOOMOOOOTOOTOTTOTOTOTTTTTTVTTTTTVWVYYYYYYYYYYYZ[ZY[YY[ZY[Z[Y[Z[YY[ZY[YY[Z[Y[Y[Y[YYYYXYYYYYYY[YYXYXYYXYVVVVVTVVSVTVTVVVSVVVVXYXVVVVSVUVSSVS././././.2/./2......... .... . .. . . .. . .. ... ......././//2//////./////2/F==F=F=F@@F@F@F@@F@==.//./////..     . ..../././@GLOOLOGLCGCGCGCGC@G@CGCGCG@@G@G@G@G@F@@F@==2==2=@==@F@@G@@F@F=@F@G@G@G@@FG@FGCG@GG@G@GCGGOOOOOOOOGOOOOOOOOOOOOOOOOOOOOOGGOGGOGCGGCGGCGG@GG@GGGGGGGGGGGGGGGGGGGGGGGGGGGGFGGFG@GFGG@GGGGGGGGGGGGGGGGG@GGFG@F@@F@@F@F@F@F=F=F@F=FF@@@G@@C@@@======/==/==============8=/=*=*/***/*/**8=8*88=*88*8=*888/***8*88*88**8*8************(*&*(**(&******8*****8*8*8***( //=@FC@GCGCGCGGGOGOOOOMOOMOOOOGOLOOOMOOTMOOOOOOOMOOTOTTTTTTTTTTTTTTTTVTVTTVTVVYYYYYYYYYYYY[YY[YYZY[Y[Y[Y[YY[ZY[Y[Y[Z[Y[Y[Y[Y[[[[YYYXYYYXVYYYYYXYYYVVYVVVVSVVVSVVTVSVTVVVVVXVVXVVUVSVSV././././/./2./.2..1......... .. . . .. . .. ... .....././/2//2=/=2=//////=/===F@@@F@@F@@F@@@G@@F=//....////..    ./////////2//F=GOMOOMOOLOCGCGCCGCGLGLGLGCGGCGCGCG@G@G@F@F===F=F@GCGOGOCGCG@G@GGCGGCGGG@G@GGCGGGGCG@GGCOOMTTOTOOMOOOOMOTOTOTOTTQTTTOOOOOGOOOOOOCOGGOGGOGCGGGGOOOGGGGGCGGCGGGGGOGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGCGG@GG@GF@G@G@@F@F@G@@@@@@GGCGC@G@@@=@==@@@=@@@=@=@=@========8==8=*8=8/8=8=8=88=888=8=8888=8888=888888888888888**88*********8*&8**8*8888888888888888=8* .(..(.  ../=@@GCGOCOGLOOLOMOTMTOTOTOOOMOOOOMOTOTTOTOOOCOGOOOTTTVVVVTVTTTTTTTTVTTTTTTTTTYVYYYYVTVTYYYY[YYY[YYYYY[Y[Z[Y[Y[YYY[Y[Y[Y[Y[Y[YYY[Y[YY[YYYVYVYXYYXYXYYXYYVVVVVTVTVSVTVSVSVSVVVVVUVVUVSVS/./.2./.2/./2././1........ .. .. . . . . ... .. ......././/2///2/=//.///2//====F=====@F@@=F@=G@@F/... . .. .  .//2=F=F=2////==@GOMOOOLOCOCCCF@G@CGCGC@@G@G@@@F@@G@@@F@==F===@F@GCGLGCGCG@G@F@G@GCG@G@F@F@@GF@G@G@G@G@GOOOOOOOOOOOOOOOOOOTOQOQOOOQOOOGGCGCGCGCGCGCGCGCGGCGGGGGGGGGCGGGGGGGGGGGGGGGGGGG@G@F@GFG@GFGGGGGGGHGGGGGGGGG@GFG@GF@F@@F@F@F@F@F@=F@F@G@@@F@@F@=====@@@@@@=@=@==========8===8=8/8/8/8=88=888=8=8*8=*8=88/8*=88*88/888=8888*******%****&***(*((&****************8*8**( .*//=//...(.//=FCGCGCGCOCOOOOOOOOMOOTOMOOOOOOOOOMOOTOOOGGGLGOOTTTVTVVVVVTTTTTVTTVTTTTTOTTTTVTTVTVWVTYY[Y[Y[Z[Y[ZYYZYYY[Y[Y[[Y[Y[Y[Y[Y[Y[[Y[Y[Y[YY[YXYYXYVYXYYYYYYXYXYXYVXVVVVSVTVSVVVSVVSVVSVUSVSS//.//.2/.2/./1.2./............ .. . . ... .. ... ....../2.////2=///././////2=2=/=//=/==/=======2/.   ..//F==F=@=2///F=@G@GCGC@G@F@@F==@F@@F@F==F=F=F==F==F==F//=2==F=@F@@G@G@@F@F=@F@F@F@F@F@F=FF@F@F@F@=F=F@GCGCGCGGGGGGGGOOOOGOOOOOGGGGGF@G@F@F@F@F@F@F@F@F@G@GF@F@F@F@F@F@F@F@F@FFFGF@F@FF=FF=F=FF@FFFFFFFFFF@FF=F@F=FF@F@F=F=F==F==F====F=F=F==F=F====/======/===/=/=*/=//*/*/*//*/*/*/**.**.*(*.*(*(*(*.*(*(*(**((*(**(*((*(*((*((*((%(((((%((%((%((((%((*((*(*(*(**(****( (.//=/===/////==@@G@GCGCGGCGOOOOOOOMOOOOOOOLOOOMOOOTOMOOOOOOMTTTTVTVTVTVTTTTTTTVTTVTVTTTTTTTTTTTTTVTVYYY[Y[Z[Y[Z[YYYYYYYYYYY[Z[Y[Y[Y[Y[[Y[Y[YY[Y[YY[Y[YY[YXYYXYXYYYXYYYXYYXYVVVVSVVTVSVVSVTVSVSVSVS//1//2.//.2.././.1/.1..1.... .. . .. .. ... .. ........///./2=//2/././////=/=/=/2=/=/=/==2=======/  ../2==F=FF@F=F==F@G@GCG@@@@@F===F@@F@==F=F====/====F=F======F==F=@F@@G@G@F@@F@F@F@GF@F@F@F@F@F@F@@F@=F@GGCGOGGGG@GGGGGOGOOQOGOGOGGGGFGG@F@F@G@F@@FG@F@GG@GF@F@GF@GF@F@F@FF@FFF@FF@FF@FF=FFF=F@FFF@FF@FFFFFFFFF@FF@F@FF@F@F=F=F==F==F=F=F==F=F====================/=/=//*///*//*/*/*/*/***.***.**.**((/*(**(**(*(*(**(**(**(***((*((%(((((%((((((((((((%*(*(*((*(*(*****(* (///====@=@==@=@FC@GCG@GCGOCOOOOOMOOOMOOTOMOOTOOTOMOTOOOOMOOTTTTVTVTVVTTTTTTTTTTVTVVTVTTTTTTTTTTTTOTTYYYY[Z[Y[Z[Y[Y[YYYYYYYYYYY[Y[Y[[Y[Y[Y[Y[Y[YY[YXYY[XY[Y[YY[YYX[Y[Y[YXYYXYXYVXVVYUVVSVSVSTSVSVSV////2//1/./1./1.//1/./....... .. . .. .. .. .. .. ...././2////2=/././///=2/=/=/=/=//=/=2===F=F=F=/. ..  .//=F=F@@G@G@@FG@G@GCGCGGG@F@=@F@@F@F@F@F==F=2==2======F=F===F==F@@FG@G@F@F=F@=F@FG@G@F@F@FG@G@GGF@F=@FCGCGGCGGGGGGGGOOOGOGOOGGGGGGGGF@GF@G=F@@F@@F@@GF@GF@GF@F@FGF@FF@F@F@FGF@GFF@FF@F@FF=F=FF@FF@FF@FFF=F=F=F=F@FF@F@F@=F===F==F==F=F=F==F==F@F=F=============/==//=//*///*///**/*/*/**(/**(/(**(/*(*(*(*(**(*(**(**(**(**(*((((*((%(((((%(((((%((((*((*(*(*(((*(******(( (///===@=@@@@@G@GCGCGCOCGCGOGOOOOOMOOOOTOOOMOOTOMOTOTOTOTOTTOTTTTTVTVTVTTTOTOTOTTVTVTVVVVVTYVYVVTTTTTYYYYYYY[Y[Y[Z[Y[Y[Y[YYYYYYYYYYYY[Y[Y[Y[Y[Y[Y[YY[YXYYXYY[X[Y[Y[YX[Y[Y[YXYYXYXYXYXYVVVVSVSVSTSSS/2/2///.2/./../.1/./1/.2..... .. .. .... .. . . ......2/.//2///2/././//2=====F=====F====@F@@G@@@G@/.. ../....   /2=@FCGGOOOGOOOOOOOLOOOLOLGCGGCOCGCG@GCGC@@F@@F@@F@FCF@G@@F@@@G@G@GGCGOGCG@@G@GGGGGGGOGGOGOGGOOOCGC@G@OOOOOOOOOOOOOOOTOTOOTOOOOOOGOGGOGGCGG@G@GGGGCGGGOGCGGGGGGGGGGGGGGGGGGGGGGGGGGGCG@GGFGF@FG@GFGGFGGGFGFGFG@GFGGG@GG@F@F@F@F@F@F@F@@F@FC@GCFC@G@G@@C@@@@@@@@@@@@@@@@@==========8===8==8*=8=*8/88*8=8=88=88=888888888*88*888888*******(*&*(*(*&*(*************8**8**88*8*8*(..*===@=@@@F@@@G@CGCCOOLOOOOOMOMOMOOTOTMOOMOTOTOMOTOTMOTTOTOTTTTTTVTVTVTTTTOTTTTTTTVTYTYYVYYYYYYYYVTYYYYYYYYYYYYZY[Y[Z[Z[Y[[Y[YYYYYYYYYYYXY[Y[Y[Y[Y[XY[Y[YYXY[YY[X[Y[Y[Y[Y[X[[Y[YYXYXYXYXYVVUVSVSSTS/2//2/2/.2..1.../.2./2........ .. .. .... .. .... ....//./2//2=//.//=/====F@F@==F====F@F@@FCGGGC@G@=....//=./....   /=FGCGOOMOOOOOMOOMOTOTTOOOLOOLOOOCGLGCOCGG@@FC@G@@G@GCG@GG@G@GG@GCGCOOLGGCGG@GGOOOMOOOOMOOOOTOOLOOGCGOMOTOMOOMOTOTOTTTTQTTTTTOOOOOOOOOOGGCGGLGGCGOGOOOGGOGGGOGLGOGGOGGGGGGGGGGGGGGGGGGGCGGG@GCGGGGGGGGGGGGGGGG@GGGGGGCGGGG@G@G@G@G@GGGGCGGGGCGLGGC@CG@GCGCCGCCGCC@C@@@@@@@@@=@@@===8===8==8=88=8=8=8=888=888=888@88=8888888888888888*8*****8**8**8**888888888888*888888=8=88/8(./==@@@@@@G@GCGCGCGCOLGOLOOTMOTTTTTTVTTTTTTTTTTTTTTTTTTTOTTTTTOTTTTTVTTTTOTOTTTTVVVYVVYVVYYYYYYYYVTVYY[Y[[Y[YYY[YYY[Z[Y[Y[Z[[Y[[Y[YYVVVYVYYVXY[Y[Y[Y[Y[XY[Y[YXYXYYY[X[Y[Y[X[YY[X[[Y[YXYYXVYVXVVVUVUS//2//2///./../.1/./2.//1/.1.... .. .. ... ... .... ../.2/.//2//././////=2=========F=====F@@F@@@FG@F=/ ..///./..  .2=@GCOOOOOOOOOOOOOOOLOOLOCOLOOCGCGCGCGC@F@@@F@F@F@@@G@@@@@G@@@GCG@GCGG@G@F@GCGGOOOOOOOOOOOOOOOOC@G@GOOOLOOOOOOOMOOOOQOTOQOQOOOOOOOGOGGCGGCGCGGCGCGCG@GCG@GCGGGGGGGGGGGGGGGGGGGGG@GGG@G@G@F@F@FGF@GFG@GFGFG@GFG@GFG@G@G@F@F@F@F@F@G@GCGCGCGCGCG@@G@@G@@@@@@@C@@@@@@@@@@@@=======8==8==8=*=88/8=*888=88=888=8888888888=8*=*8*8/88*8********&(***&*(**********(***(*(*****8***((( (/==@@@@G@@@C@@CGCGCGCGCOOGOOTOTOTTTTTTTTTTTTOTMOTMOTOTTTTTTTTTTVTVTTTTOTOTTTTVVYVYYYYYYVYYYYYYVTVVY[Y[Y[Y[Y[YY[Y[Y[Y[Y[[[Y[[Y[[Y[Y[YVYVVVVVVVYXYXY[Y[Y[Y[YXY[YXYXYYVYXY[YY[X[Y[Y[X[Y[VXYXVVVUYUVXY2/2/2//2.2...1/..2.//1/.......... .... ... .... ..../././/.//./..///.//=====/===2=/////==2===F==2===/  .. .   ./F=G@GCGGGGGGCGG@GGCGC@G@G@GC@@F@F@F=F==F=F==F===F===F=F=F=F==F@F@F=F=F=@F@GCGCGOGOGOGOGOGCGCF@=F@GCGCGCGCGOCOGOGOOGOGOOGGOGGGGGGGG@G@F@F@F@G@F@F@F@F@F@F@F@F@F@F@G@F@F@F@F=F@F@F@FF=F=F@F=F@=FF=FFFFFF@FFF=F=F=F=F@=F=F=F=F=F@F@F@F@F@F@F@==F===F===@=@=====@=====/=//8//*/*/*/*/(***.*(/*(/*.*(*(*(((*(*(*(*(**(*((*((*(((((((((((((((%(((((%(((((%(((%(((((((((((((//=@=@@@@G@G@G@@CCG@GCGGLGOOOOOMOTTTTTTTTTTTVTTTTTTTTOTTTTTTTTTTVTTTTOTOTTTTYVYVYYYYYYYYYYYVVTTVVY[Y[Y[Y[Z[Y[[Z[Y[Z[Y[Y[Z[[[[Y[[Y[YY[YYXYVVVVVVVYXYXY[Y[X[Y[YXYYYXYXYYXYX[Y[Y[X[[Y[X[YXYXVVXVVXVVX/=2=/2//.././../../2.//1./.......... .. ... ......../././/.//../././////=2===2===//=/=/=/==2==2===2=/.      ../F@G@GGGGGGG@G@G@G@@FC@G@G@@F@F@@F=====F======F==2=F===F==F=F=@=F===F=F=G@GGGGOGOGGOCOGGCGG@F=F@GCGG@GGCGGOOGOGOGOGOGGGOGGGGGGGGG@G@GFCFG@G@F@@@F@F@F@F@F@F@F@FGF@GFGF@FF@FF@FF@FF@F=F=F=F=F=F@FF=FF@FFFF=F=F=F=F@F=F@F=F@F@@F@F@F@F@F===F@F@F@F==F==F==@======/==/==//*=/*/*.*/*/*/*(*/(**(/**(*.*(**(*(*(***(**(*((((%(((%((((((((((((((%(((((%((((((((((%((((( .===@@F@G@GCGCGLGCOLGOLOGLOOOOOOOMOTOTTTTVTTTVTVTVTTTTTTTTTTTTVTTTTTTOTTTTVYVYYYYYYYYYYYYYVTTTTTYYYY[Y[Y[Y[Y[Z[[Z[[Y[[Z[[Y[Y[[Y[[Y[[Y[Y[YYXYVVVVVVYYXYXYYYXY[YYXYYXYYXYXYVXYXY[YX[Y[X[Y[XYXYXVXVXY2/=2//2//1./1.2./1/./1/...1....... ... .. ..... ...//./././/..././//./=/=/=/=====/=/=/=/=2==2==2==/=//.     ../2@FCGGGGOGGGGGGGFCGG@GCGCG@G@F@F@@F=F=F=F=F=F========F==F====F=F=@F===F@GCGCGCGCGOGLGGOCGG@F@F@GCGCGCGGCOGOGOGOGGOGOGGGGGGGGGGGGCGG@G@G@G@F@@F@F@@@F=F@F=F@F@F@GFG@FF@F@FF@FF@FF@F@F=F==F=F=F=F=FFF@FFF@FF=F=FF=F=F@F@F@F@F@F@F@@@F===F@F@F@@@=@@F=====@========/===/8/=*/*/*/**/*(*/*(*/(/***/**((*.*(**(***(*((((((%(((((%((((((((((((((%((((((%(((%(((((%((  (./=@=@C@@C@GCCGCGCOLOOOLOOOOMOOMOOOTOTOTOTTTTTTTTTTVTVTVTVTTVTTTVTTOTOTTTVVYYYYYYYYYYYYYYVVTTTTYYYYYYYY[Y[Y[Y[Y[[Y[[[Y[[[Y[YY[YY[[Y[Y[[Y[YYYXYYXYXYXYYYXYXYYXYXYYXYXYVYVXYVYXYXY[XYXY[XYXY[XYXYXYX=2/2/2//2./1./.../.2./.2/....1..... .... . ......./././//./....///.///2/=/==F=F===F=F==F=@F@F@F@F=F=F==.  . ../////=@GGOOOTMOTTOOOOOOOLOOOOOOLOCGLGCGCFC@GCGCG@@@G@F@G@F@@@G@G@G@C@G@@F@FGCGGOOOOOOOOOOOMOOOG@G@@GGOLOOGOOOOMOOOOOOOOOOOOOOOOOOOGOGOGOGOGOGGGGCGG@G@G@G@G@GF@G@GGGGCGGGCGGGGGG@GFG@GGGFG@G@GF@F@F@GF@GFGGG@GFGG@GFG@GFGGGGGGGGGGGGCGF@GCGGCGCGCG@GCGCCG@C@@G@@C@@@@@@@@@@@@======8=====8=8=8=88=8=888=8888=8*8=*88*8**8*******(****(**(((((*(((*%((*((((*(*((((%(((((**(*(((((..(.(//=@CCGCGCGCGCLGCOCOLOOOMOOTOMOOTOMOTOTTMTOTTMTTTTTTTTTTVTVTVTTTTTOTTTTVVVYYYYYYYYYYYYYYVVTTTTVYYYYYYYYYYYYY[Y[Z[[Z[[[[Y[[[[YY[YYYY[YY[[Y[[Y[YXYYYXYVXYYXYYXYYYXYXYVVVUYVXYXYXYXYXYX[VYXYXVVXYXYXY=2=/2/////1/...2.2...2...2......... ... ... ......./././/.././////2//===/==F=F@@F@@F@@@@F@@G@@@F@F@=F==/.  . . .../2=F=FF@GOOTTTTTTTTTTOOOOOOMOTLOOOOLOGCGCGCGCGLGCGGCGCG@G@G@GC@G@GCGGCG@G@GCGGLOOOMOTOMOTTTOTOGCGG@GOMOOOTOMTTTOTTTTTTTTTQTTOTOTOOOOOOOOOOOOOOOCGGCGCGGCGGCGGGCGGGCGGOGOGOGGCGGGGGGGGGCGGCGG@G@GG@GGCGGGGGGGGGGGGGGGGGGGGOOOGCOGGOCGCGGCGCGGLGGLGCGLGCOCGCGCGC@GCG@CG@C@@@@@@@@@@@@=@8=@=8==@8=9=@9@9=9@8=9=888=888=8=888*8******8****8*************8****8********************(((( (.*/=/==@@@GCCOCOLLOLOLOLOOMOTMTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTVTTTTTOTTTVVVYYYYYYYYYY[YYYVTTTTVYYYYYYYYYYYYYYY[Y[Z[[Y[[[[[Y[Y[[YY[YYYXYYYX[Y[Y[Y[YXYYXYYVVYXYVXYXYYXVVVVVVVVVVYXYXYYVVXVVVUVUVVUVXV=2/2//2/1//.2/./././1./1/../......... .. ... ...././././/....././//////2//=/F======@=F==@F@@F@F=======/=.  ...//=F@G@GGGOOOTTTTQTOOOOOOLOOOOOLOLGLGCG@G@G@GCGCG@G@@@G@@@F@@F@G@@G@@G@G@G@GCGOGLOOOOOOOOOOOCG@F@@GGOOOOOOMOOOOMOOOOOOOQOOOOOOQOGOGOGGOOGOOCGCG@GCG@GCF@G@G@@G@G@GGGCGGCGGCGGG@GGGG@G@G@GFCFG@GF@GF@F@FFG@G@GGFGG@GGGGGGGOGGCGGGCG@GG@GCGGCGGCGCGCGCGCGCCGC@@G@@@@@@@@@@@@@@=@=@===8====8=8=8=8=8=8888=888/8*=*8=88/888*8***8**********(*(*(*(*(((*((**(*(*(**(*(((*((*(*(((((((.*/=====@@CCGLGLGLCOLOLOLOLOOOMOTOTMOTOTMOTTTTTTTTTTOTTTTTTTTTTVTVTTTTTTTTTVTYVVVYYYYYYY[YYYYTTTTTVYYYYY[YYYYYYYYYYYYYYY[[Y[Y[Y[[[Y[[Y[YXYYYXYYVYY[V[Y[Y[XYYXYVVVVVVVYXVYXYVVVVVUVUVVVVXVXYXVXVVUVSVSVSV/2=/2///./2/.2.2./1/./1/..2........ .... ... ..../.././.../..///.///./////2=//==2===/=====2==/=///2////..    ../2=F@FG@G@GOOGOOOGOGGG@G@GCGCGG@G@@F@F==F@F@F@F@F@FF==F==F==F==F==F====F=F@F@G@G@GCGCOGCGG@@F=F=F@GCGCGGOGOGLGOGOGOOGOGOGGGGGGGGGG@GG@GCG@G@F@@F@F@F@@F=F=F@F@F@@F@F=@F@F@F@F@F@F@F@F=F=F=F=F=F=F=F@FF@FFFFF@F@FF@GFG@G@F@GF@F@F@F@F@@F@F@F@F@F@F@F@@=F@@F=@==F==@======/==/8/*=*/**/**/*(/(*/***/***(**(***(**((*(*(*(((*((%(((%(((%((((((((%((((%((((%(((%(((%(((%.*//==@@=@@GCCCGLGCGLGCOCOLOOMOTOTOTMTTOTTTTTTTTTTTTTTTTTTTTTVTTVTTVTTTTTTTVVTYVVVVYYYYYYYYVTTTTTVYYY[YYYYYY[YY[Y[Y[Y[Y[YYYYYY[[Y[Y[Y[Y[Y[YYYYVVVVVVXYX[YY[YYXYVVVUVVVVVVVXVXYXVVVVUVUVVVVXYVVXYVVUSVSSS/=2///2.2///2./.2./.2./.2........... ..... ......../././...././///////////=///2=/==/==2====/=2/=2/////...    ..//=F@G@GG@GGGOGGGGGGGG@GG@G@G@@F@F@@==F==F=F=@@F=F=@====F=====F=F=@F=F=@F@F@@@G@G@GGCGGGC@F=@=F=@G@GGGLGGOGOGOGOGOGOGGGGOGGGGGGGGGG@GGGCG@G@G@G@F@G=F@=F@@F@F@@F@@F@F@F@=F@F@F@FF@FF=F=F=F=F=F=F=F=F=F=FF=FFF@FG@GFG@GFGF@F@F@F@F@FG@G@F@G=@@F=F@F@@F@@@F=@===========/==/8//8/*=*//*/***/****.***/**/*(/**(/(*(*(*(*(*((((((((%((((((%(((((%(((((((%(((((%(((((%((( (.*/==@=@@@C@CGLCGLGLGLGLOLOOOMOOTMOTOTOTTMTTTTTTTTTTTTTTTTTVTTVTTVTTVTTTVTVVVVVYVYVVYYYYYYVTTTTTVYYYYYY[YYYYYYYYYYYY[YYY[Y[YYYYYYY[Y[Y[Y[Y[YYXYXYVVVVVVVYXYXYYXYVVVVSVVVVVVVVVVXYXVVYUVUVVVXVXYXVXYXVUVS2/2/2/.///2.//2/./1./.2.//.1/.......... ... . .../../......././/.///////////2=/=/===2==/=2==2=///////....   . ./2=F@GGGGGOOOGOGOGOGGGGGGCGGCGGG@G@F@F@=F@@F@F@F@@@F=F=F===F==F==@F=F=@F=@F@F@FG@GGCGCGCG@F=F=F=F@GCGCGOGLGOGOCOGGGGGOGGGGOGGGGGGGCGG@G@G@F@F@GF@F@F@F@F@F@@F@F@F@F@@F@=F@=F@F@F@F@F=F=F=F=F=F=F=F=F=F=F=FF=F@FG@GFGGFG@GF@FG@FG@FG@F@FG@F@F@F@@@F@F@@@F@@@F@=@===========//8//*=*/*=**/*/**/***.***/(****/*****((((*(((*((((((((((%(((((%((((%((((((%(((((((((%(((((.*/===@@@@C@GCCOCLGLGLGLGLOOMOOTMOTTMTOTMTTOTTTTTVTTTTTTTTVTTVTVTVTVTTVVTVVTVVVVVYVYVYYYYVTTTTTTVYYYY[YYYYY[YY[YY[Y[YY[Y[YYYY[YYYYYYYXYYX[Y[[Y[YYXYVVVVVVVVVYXVVVVVVVVSVVSVSVVSVVVVVUYXVVXVVXVYXYXYXYXVVU/2////2.2//2///2/./2./.2../............. .. ..............././///////////=/==/===F=====@=@=F===F===2=///...  ..///=F@@GOOMOTTTOTOTOTOOOOOOOMOOOOOOOGCGGCGGCGC@GCGCGGCG@@G@F@@F@@G@G@G@G@G@GGCGGGCGOLOGOOGCG@F@F@F@GCGOOOOMOOOOMOOOOOOOOOOOMOOOOOOOOOOOGGCGGCGGCGGCG@G@@G@G@G@G@G@G@G@GCGG@GG@GGGG@GG@G@FG@F@F@FCFCFG@GFG@GFG@GGGGGGGOGGOGGGGGGGGCGGGGGCOGCGCGCGCGCGCGCGGLGCGCCG@@G@@@@C@@@@@@@=@====8===8=@8==8=8=8=8=88=8=88=*8=88=*8/88*888*8**8*********(***(******(***(******(*(*(***(*(((((( (//8=@@C@CGCOCOLOLOLOLOLOOLOMOTMOTTTTTTTTTTTTTTTTTTTTVTTTVTTVTVVTVVTVVVTVTVTVVTYVYVYVYYVYVTTTTTTVVYYYYYYY[YYYYYYYYYYY[YYYYY[YYYYYY[YXYYYYYYXY[Y[X[YXYXVVVVVUVVTVVVVVVVVVSVTVSVVSVTVUVUVVUVYXVYXXYXYXYXVXVX/=2/2////2//2///1/./2.//1/................ ......./../.....//////=/=/=/=====2=F===F@@F@F@@F@F=F==F===///...  ..//2=F@GGOMOTTTTTTTTTTTTTTTTTTOTOMOOMOOOCGOGCGGOGGOGLGCGCGCGCGCFCGGCGCGCGCGCGCGGCOCOOOOMOOOCG@@@@@@@GCOOOMOTTTTTOTOTOTOTOMOTTQTTTTTOTOTOOOOOCOGOOGCGGCGGGGCGGCGGGCGGCGGCGGCGGCGCGGCGGGGG@GG@G@GG@GFCG@GFGCFG@GGOGOGOOGOOOOOOOOOOOOGOOOGCOGGOGOGOGCOGCOOLOOLOCGCGCGCGCGCCGC@CC@@C@@@@@@@@8@@@9@@@@@8=8=8=8=88=98=8@88=888=88=8=8=88=88=888=88*888*8**8*8*88*8888888**8**88*88*****(((((/*=@@CCLGLLOLLLOMOMTMOTMOMOTTMTTTTVTVTTTVTTTTTTVTVTVTTVTTTTVTVTVTVTVVTVVTVVTVTVVYVYYYYYVVTTTOTTTVVYYYY[YYYYY[YYY[YYYYYY[Y[YYY[YY[YYYYXYYXYYYXYXYY[Y[YYXYXVVVVSVSVSVSVSVVVSVVVSVTVSVTVSVSVSVUVUVVXXYXXVVXVU2/2///1/2/2//2///2///1/././/../...................../.. ...././/////////=/=/===/F=======F=========////....  ..//=F@GGGOMOTTTTOTOOOOOOOTOTOOOOOOOOOCGCOGCOCGCGCGCGCGCG@G@G@@G@@@G@G@GCG@GCGCGGCGOLOOOGCG@@F@F=F@F@GCOOOOOOOMOOMOOOOOOOOOOOOOOOOOOOTOOGCGCGCGCGCG@@G@@@G@G@GCG@G@GG@G@GCG@GG@G@GG@G@G@G@F@F@F@F@F@GF@G@FG@GGGGGGGGGGGGGGOGOGOGGGCGGCGGGCGCGCGCOGCGCGCGCGCGCCGCGCG@@@@@C@@@C@@@@@====8==8==8=8=8=88=8*8/8=88*=888=888=888/88888=888=88/8**8******8*(************8************((((( ((/8=@@CCCGCLGLOLOLOLOMOOLOMOOOMOTTMTTTTTTTTSTTTTVTVTTVTTVTVTVTVTVTVVVVVVVVTVVVVVVYVVVVVTTTOTTTVTVVYYYYYYY[YYYYYYYYYYXYYYYYYYYYYYYY[YYYYYYYXYYYYXYXYYX[YXYXYXYVVSVTVTSVTSVVSVTVSVSVSVSVSSVSVSVUVUVVUVXVXVUV/2//2////2/2//2///1///./2.././............ ............ ../././////=///=////=//=///=2=/=//////2///...... ..2/=F=G@GGOOOGOGGOGOGOGOGOGOCGGCGG@G@G@G@@F@F@F@F@@F@F@F=F==F==F=F=@F==F@F@F@@F@G@GCG@G=====2===F=F@GCGGLGCOGOGOGOCGGGGOOGOOGGOOOOGCG@G@G@G@G@F@F@F@F@F@F@F@F@F@F@F@F@F@F@F@F=F=F@F=F=F=F==F=2=F=F=F==F=F@F@F@F@G@FCFCFCF@G@F@G@GF@G@F@F@F@F@@F@G@@@F@@F@@F@@@@=@@==@==========/8/8/8/*=**/**/**/(*.*(*((/**(**(**/*(*/***/*/******(*(*(((((((*((((((((((*(*((((((((((((((((.*/=@@@CCCGCCGCOLOLOLOLOLOOOMOTOTTTTTMTTMTTTTTVTTVTVTVTVTVTVTVTVTVVTVTVWVVVVVVWYVYVYYVTTTOTTTTTVTYYYYY[YYYY[YY[YYYYYYYYYYXYYXYYY[YYXY[YXYYYXYXYYXYYXYXYY[YXYYXVVVVSVTSTVSTVSVTVSVSVSVSVSVSVSVSSVUVUVUVSVUV//2///2/2//2/2/2///2.2/.//./......................... .......//.//////=///////=//=/=/=/=/=///////..... ./2==F@GGCGGGGGGGGGGGGGGGGGGG@GG@G@F@@F@F@F@@F@F@F=@F=@===F==F==F=F=F@F@F@@=F@@G@GG@@G=F==2===2===F@FCGCGGCGCOCGLGOGLGGGOGGOOGOGGCGF@G@G@GF@F@@F@@@F@F@F@F@F@@@F@@F@F@@F@F@=F=F=F@F=F@=F==2=======F=F=F@F@F@F@GFFG@GFG@GGF@GF@FF@G@FF@F@F@F@FG@F@F@F@F@@F@@F@=@F=@====@======/==/=*/*/**(/**(*/(*/*(/*.**(*/*/*/****/***/***8**/**(*(((*(((((*(((*((*(*(*(((((((((((((((((.*=8@@@CCCCCGLCLOLOLOLOOMOOMOOMTOTMTTTTTTTTTTSTVTTVTVVVTVVTVTVVTVVTVVVTVVVVWVYVYVYYVVTTOTOTOTTTTVTYYYYYY[YYY[YYYYYYYYYXYYYYYYYXYYYYYYXYYYXYYXYYXYYXVVVYXVY[X[YXYYVVSVVSTSVTSVSVVSVSVVSVSVSSVSVSVSSVSVSVSVS2///2//2//2///2//2//////.//........................... ..../..///.////////.././//=/=/=2/=//////./.... . .//F=G@GGOOGOGGOGGGGGGOGOGGGGGCGG@G@GG@GG@F@F@@@F@F@@F@F@F==F=F@F=@=@F@=@F@F@FG@G@G@G@F=2===2===F==@G@GGCGGLGGCOGCGCGOGGGOGOGOGG@F@F@FCG@G@G@F@@F@F@F@=@F=@F@F@@F@F@F@F@F@=F@=F=@F=F=F==F==2=2=F=F==F@F@F@F=FF@GF@GFG@GF@GFF@G@F@F@F@F@FG@F@@@F@F@@@@F@@@F@@F@@@@F@=@=============*=*/*/(**/***/***/***/*.****/**/***/***/*/*/*(*(*((*(((((((((((((*((**(*(((((((((((/=8@@C@GCGCLGLOLOLOLOMOOLOOMOOTMTTTTTTTTTTTTTTTVTVTVTVVTVVVVTVVVTVVTVVVVTYVVVVVYVYVTTTTOTOTTTTTTVVYYY[YYY[YYYYY[YYYYXYYYYYVYVYVVSVYYYXYYXYYYXYYVVVVVVVVVVVVYXY[XY[VXYVVVSTSTVSVTVVUVVSVSVSSVSSSVSSVSSSSSS//2//2//2//2/2/2///2//1//1///...................... .. ...../././/.////=///.. ../=F=F=====/=/=//////.....  /F@GGOOTOOTOMOOTOOOTOTOTOTOOOOOOOCOOOOLGOOGOGGGCGCGGCG@G@@G@GC@GCGGCGCGG@GCGOCOGOCGGCF@F=F=@F=F@F@GCGOLOOOOLOOOOOOOOOOOOOMOOOOG@G@G@GGGOCGG@GCGGCG@C@G@@G@@G@G@G@G@G@GCG@G@G@@G@GFCFGF@F@F@F@F@F@GGG@GF@G@GGGGGGOGGGGOGGGOGGGGGGGGOGGGCGGCGGGCOGLGGGCGGGCGCLGCGCC@C@C@C@C@@@@@@@====8=8==8=8=8=8=88=8=8=8=8==98=8=888=88=888*8=**8***********8*8***8***8**((***(*(((((==@@CCLCCLOLOLOLTOMTTOTMOTOTOTOTOTTMTTTTTTSTVTVTVTVTVVTVVVTVVVTVVVVVVVVVVVVVVYVYVVVTTOTTOTTTOTTTTVYYYYYYYYYY[YYYYY[YYY[YYXYYVTTTTTSVYYXYYXYXYYXYXVVVSVSVVSVVYXYYXXY[XYXVVVSVSVSVSVSVUVSVSVSSSVSSVSSVSTSTS/2//2/2//2//2///2//////.//.//./.........../........ .........///////=/===//. ..../=F=F@F==F==/=//////......  ./F@OOMOTOTOTQTTQTTTTTTTTTQTTTOOOOMOOMOOOOOOOLOGCOGGOCGGCGGCGCGGCGCGCOGCGCGOLOOOLGOOCG@F@F@F@F@@G@GCOOOOOOMOOOOMOOMOTOMOTTOTOOGGGCGGGOLOOOCOGGOCGGLGGCGGCGGG@G@GGCGGLGCGG@GCGG@G@GG@G@G@G@F@@FGGGG@GGGCGG@GG@GGGOGOOGOOOOOGOOOGOOGOCOOOGLGOOCOOOLOOLOCOCOLOLGLGCOCGCGCCGCCCCCC@C@C@@@=@=8@=@8=8@8==8=8=88=9@@9@@8@8=8=9=88=8=8888=*8*88*8*=888=88=88=8=8=88*(**/***(((.8@CCLOLOMOLMLTMOTSTTTSTTTTTTTTTTSTTVTVTVVTVVTVTVTVTVTVVTVTVTVVVVVWVVYVVYVVVYYVYVVTTTTTOTTTTTTTTTVYYYYYYYXYYYYYXYYYYXY[YY[YYYVTSTTMTVVVYVYYYVXYVXVVVVVSVTSVSVVVVYXYXYX[YXYXYVVSVSVSVSVSVSVSVSVSVSSVSSSVSSS//2//2/2//2//2/2/2//2.//.//.//./.................. ........././../././//=/.. . ./======/=////....... . .  .=FCOOOOOOOOOOOOOOTQTTOOOOOOOOOOOOOMOOOOOGOOGCGCGCGCGCFC@GCGCG@G@GCGCGCGCGOGCOGCGCG@F@@F@F@F@F@@F@GGLOOLGOGLOOOOOOOOOOOOOOGG@G@G@G@G@OGGCGGCGCGCGCGCG@@@F@@F@@@GG@G@G@G@G@G@@G@G@G@GF@F@F@F@@F@G@G@G@G@GF@G@G@GGGGGGGGGOGCGCGGCGCGGGCGGGCGCGOCGLGCGCOGCGCGCGCCGCCC@C@@@@@@C@@@@@@@=@=8==8=8=8=8=8=8=8=8=8=8=88=888=88*=8=888/8/8****/****8**=8*88/8*8*=88**((((((/8@CCCLLGLLOLOLMOTMTMTTTMTMOTMOTOTTTTTSTTTSTVTVTVTVTVTVVTVTVVTVTVVVVVWVVYVYVVYVYVTTTTOTOTOTTTTTTVYYYYYYYYYYYXYYY[YYYYYYXYYVVTSTTTVTVVVSVTVSVVVVVVVVVVVVVSTSTSSVUVVYYVXYXYXYXYXVVVSVSSVSVSVSVSVSVSVSVSTSTS/2/2//2/2///2/////////.//.//./............./..... .......././..././/.///=.. ..///////... .  ./=FGGGGGGGGGGOGOGOOGOGOGOGOGGGGGGGGGG@GGCG@G@F@F@F@F=@F@F@F@@F@F@F@F@F@@G@G@@F@F@@F=F==2=F==F=F=FCGCGGCGCGGCGCGCGCGCGGCF@F@F@F@FF=@G@GCG@G@G@@G@G@@@F@F=F==F=F=F@F=F=F==F=F==F=F=F=F=F==F=F=F=F=FF=F=F=F=F=F==F@F@G@F@F@GFG@GF@G@F@G@F@G@@G@@G@@G@@@@F@@F@@F@@@@=@=@=@==@===@===8=*/***.**/**(***.**(/(*(*(/**/(**.*(/*(/(*(*(((((((((*((**(*************(((.=9@@CCCLCGLGLOLMOMOTMTOTMOTTOTMTTTMTTTTVTTVTTTVTVVVTVVTVVVTVTVTVTVTVVVVVYVYYVYVTVTTTTOTOTTOTTTTYYYYYYYYYYYYYYXYYYY[YXYYVTTTTTVTVSYYXYVTSTTSTSVVVVVVVVVVVVSVTSTSTSSSYVVXYX[YX[YXYXVSVSSSSSVSVUVUVSVSSSVST//2/2=/2//2///2///2/.//.//././/./......../..... . ......../...././././///=/.  ..//./....   ./=FG@GFGGGGGGGGGGGGGGGGGGG@GFGGGG@G@GGFG@FG@F@F@F@==F@F@@F=F@@F@@F=@F@G@G@F@FG@F@F=F=F==F=F==F=@G@GGCG@GGCGGCGGCGGCG@GF@F@F=F@F=@F@GG@G@GG@G@G@G@@F@@F@==F=F==F=F===F======F==F=F==F==F==F===F=F=F@F==F=F=F=F=F@FF@FGFG@FF@FG@FF@GF@FG@F@F@F@F@@@F@F@@F@@@F@@@F=@==============*/*/*/(/*(*(/(/(/(*(.(((/(/**(/**.**.**(/*(*/*(*(*(*(*(*(*********(**(**(*(*(/8@@CCCOCLCOLLOLOMTMTTMTTTTMTTOTTTTTTTSTVTVTTVTVTVTVVVVVVVVVTVVTVVTVVTVVVVWVVYVVVTTTTTTTTOTTOTTVYYYYYYYYYYYYXYYYYXYYYYVSTVTTVTSTVVYXYYYXVVTTSTMTSTSVSVUVUVSVSVTSTSTTSTSVVVVVXYX[YXYXSVSSVSSTSSVSVUVUVSTSS2//2=2//2///2//2//.////././/././/./..../........ ( .../././..../././/./////. (. . ..    ./2@FGFGGGGGGGGGGOOOOGGGGGGGGGGGGGGGGGGGGGG@G@GFG@F@F@F@@F@F@@F@@F@@F@F@G@G@F@G@F@F@F@=F=F===F==F@GGCG@GGCGG@GCG@G@@F@F@@F=F@F@F=F=G@GCGCG@G@G@G@G@G@F@@F=F===F====F=F===F=2==F==F=F==F=F=F==F=F=F=F=F@F=F===F=F=F@F@F@G@FGFCFG@G@GF@FCF@G@FG@G@@FC@FCF@@G@FC@F@@@F@@=@=@=======/=*//*/*(/*/(***.**.*(/**.*(*/(**.**/(*.*(*(*(**.*((*((**(*/(********(****(*(((.8=@@CCLCOLLLOLOMMOMTMTTTMTTTTMTTTTMTTTTVTTTVTTVTVVTVVVTVVVVVVVVVVVVTVVVVWVVVVTVVVVTTTTTTOTTOTTVVYYYYYYYYYVYYYYXYYYVVTTTTTTTTTTTSVYXYYYXYYVVVMTTMTMTSTMVTSVVSVSVTSTMTMTSMTSSSVVXYXYXVVUVSSTSSSTSSSSVSVUVSS/2/=2/2//2//////2//2.//././/.//.//............ . ........//./../././/.//=//=.. .   .. . . . . .  ../F@GOOOOOOOOOOOTTOTOOTOOTOOOOOOOOOOOOOOOOOOOGOOGGGCGGGGGCGGCGGCGGCGGCGOGGOGCOGCOGCGCGCF@F@F@F@FFCGOCGOGLGOGOGOCGG@G@G@G@G@G@G@G@F@GGOOGLGGLGLGCGGCGCGCG@G@@G@@@F=F@F@@F@F@F@F@F@FC@@GG@@F@@G@FCF@G@G@GFCF@GF@@FG@G@GGGGGGGOGGOCGGOGGOGGOGGOCGCGGOLGOCGLGLGLCGLCGCGCCCC@CC@C@@@@@====8===*=*=8=/88=88=8*=8=*=88=*=8*=8=8*8=*=88=88*88*8=8=888=8=8*=88=8*=*8/8*=**==@CCLLOLLOMOMOMOMTMTTTTSTTTTTTTMTTTTTVTTVTVTTVTTVTVVVVVVVVVVVVVVVVVYVVVVVVVVVVVTVTVTTTTOTTTTTTYYYYYYVVVYVVYYVVYVTVTTTTTTTTTTTMTTYYYYXYYVXVVVVSTSTMTMTMMTMTMTSVSVVSTSTMTMTMTSSTVUVVVUVUVUVVSTSSTSTSSTSSVSV/2=2/=2///2//2.///2///.//./././/././.././...... ......//.//.//./////=/=/2===/.. .. ..    . . ... .....   ../=FGGOOOOOTOTOWTTWTTTTTQTTOTOOTOTOTOOTOTOOOOOOOOOOOGGGOGOGCOGCOGOCGGGOOOOLGOGLOOGCGOGGCGGCFG@FG@GOOOOOLOOOOOOLGGCG@GGCGGCGGCGGCG@GCOOMOOMOOOLOLOOOOGGOGOGOGCGCF@@@G@@G@@G@@@F@@@G@GGCFCFG@GGCGGC@G@G@GGGCGG@GG@G@GFGGGOGLGOGOGOGOOOOOOOOOOLOGOOLOLOOOLOLOLOOLOOLLGLGLGCCGCC@@@@@@=@=======8@==9@=8=8=8=8=88=8=8=88=8=88=8=888=88@8@8@8@898@8@8@8@99=889=9=888=888/*=CCLLLMLMMTMMMTMTTSTTSVTVVVTVSTVTVTVVVVVVVVVVVTVTVTVTVTVVVVVVVVVVYYYVVYYYVYVYVVVVTVTTTTOTTOTTTYYYYYYYYYVYVVVVTTTTTMTTTTTTTTTMTTTVYYXYYYXYVVVVVVVVSTTMTMMMTLMMOMVSTVSTSTMTMTMTMSTSSSVUSVUVSVSVSSTSTSTSSVSSS/2//2//2/2//////2///.//./../././//..//.....(... . (.....//../..//.//.//////=/// . .  . . . . .  ..F=GGOGOOOOQOOOTQTTQTQOTTQOOOQOTQOOOOOOOOOOOOOOOGGOCGOCGGGGCGGCGCGCGCOOLGOCGCGGCGCGCGGG@F@@F@F@GGCOGOGOLOOOGCG@F@G@@G@G@G@G@G@F@F@GOLOOCGOCOCGGCGCGCGCGCGCG@@F@F@F@F@F@F@F@F@FF@F@@F@G@FCG@G@G@G@GF@GF@G@GF@G@F@FG@@GCGGGCGGCGCGGGGOGGGGGGCGCGCGGLGCOCGLGCLGCOCGLCGCGCC@@@@@@========8==8==8=8=8=8=*8*=8*=88=8=8=8/88=*=8=8=88=88=88=888=88=88888=888=8888=*88/8=((*=@CCCLOLOLOMOMMOMMTMTMTMTTTSTTTTTTTTSTTVTVTVTVTVTTVTVVVVTVVVVVVVYVYVYYYYVYYYYYYVVYTTTTOTOMTOTVVYYYYYYYYYVVVTTTMTOTTTMTTTTTTMTTTVVXYYVVVVVVVVXVVVVVVUTTMTMOMOMOMMOSTMVTSTSTMTMTMTMTSMTSSVSVSVSVSSSTSMTSTSTM//2=/2/2///2/////.///.//.//.//.//.//./......(. (. ..(.././/.././/.//////.///2=/.       ..=FF@GGGGGGGOGOOOOGOOOGGGGGGOGGGGGGGGGG@G@GG@G@@G@FG@F@F@F@G@F@F@FCG@G@@FCFCG@F@G@F@F@=F==F==F@GGCGCGCGG@G@F=F@F@F@F@F@@F@=F=F=F@GCGCGCGCG@G@CG@G@F@FCF@F@F@=========2===/=/==/==2=F=F=F@F=F@F=F=F=F=F=F=F=F=F==F=F=F=@F@F@F@GF@G@G@G@G@G@@FG@@@G@G@G@@@G@@G@@G@@@@@=====/=//*//*/*//*/*=*.**.*(/(*.*(*.(((/(**/(*/(**(/*(*/******=*8/*8/8**/*/******/**/**(/*(**(=8@CCLCLLLMOMOMMTMOMTMOTMTTTMTTMTTSTTTVTVTVVVTVTVVTVVVVVVVVVVVVVVYVYVYYYYYYYYYYYYVVTTOOOMOOTVVVYVYVYYYYYYVTTOTOTMTTTTTTMTMTTTTSVYYVXYVVXVVVVVVVVVUVVVUVMMMOMOMOMMOMMMTSMTSMMTMTMTMTMTMTSTSSUSVSSTSSTSMTMTM2/2/2/2=2////2///////.//./.././/././//....(... .(....../././././//////./////=///      ..2=FGFGGFGGGGGOGGGGGGGGGGGGGGGGGGGGG@GFGFCFCFF@FF@F@F@F@F@F@F@F@FCF@G@FG@G@GF@G@GF@F@F=2==2=F@GG@GGGGG@GG=F=F@F@F@G@F@F@@F=F==F@GCGCGCGCG@G@G@F@G@G@G@G@@F@F=F=F=2=2===2===2=/2=/F==F@=@F=F@F@F===F=F=F=F@F=F=F=F==F=F=F@F@F@F@F@FF@FF@F@F@@F@F@@F@@@F@@F@F@@F@F@@=====/=/////*//*/*/*/(/*(.**(/(*(*/(**/*(*.*(*/(**.***/***/*/*/8**/*8/**/*****/*(/*(/****.**/**.*=@CCCCLOLLMOMMOMTMMOTMTTMTTTTTTTTTTTSTTTVTVTVVVTVVVVVVVVVVVVVVYVVYVYYVYYYYYYYYYYYTTTTOTOTTTVVVVVVYYYYYVVTOTMTTTTTTTMTTTTTMTTTVVYVYVVVVVVVVVVVVVVVUVVVUVTSMOMLOMOMMOMMTMMMTMMMMMMTMMMTMMTMMTMSTSSTSSTSTMMM/=2/=2///2/2///2//.///.//..//.//.//././..... (....(..../././/.//////////////=//.  .. ..2=GGGGGGGGOOOGOQOOGGGGGGGOGGGGGGGGGGGGGGG@G@G@G@GF@GF@F@G@F@FCFG@G@FCFCFG@@GFG@GF@=2==2=F=FG@GG@GCGG@F@F@F@FGCG@G@F@@F=F=F==@GCG@GCGGCGG@C@@G@G@G@F@@F@@F@F=======2===2===/=//=/=F=F=F@@=F@=F=F=F==F=F=F==F==F==F==F=F@F@F@@F@FG@G@GF@G@G@FCG@G@@G@@G@@G@@G@@@@@@@======/=////*/*//(/**.**.*(*/*.**/*(*/(**/(**/(*/*/**/***/*8**/8**/8****/**/(*******(*/(**(/**((=@CCCLCLOLMMOMMTOMTMTMTTTTTSTTTTTTSTTVTTVTVVTVTVVVVVVVVVVYVVYVVYVVYVYYYYYYYYYYYYYTTTOTOTTTVVVVVVVYYYYVTTTMTTTTTSTTTTTTMTOTMTTVYVVVVVVVVVVVVVVVSVSVVUVVSVSTSMOMOLMTMMTMMOMMTMMMOMMMMMMTMMMMMMMMTSTSSTSSTST2/=2//2/2//////////.///./.././/./////....(.... .(......../././/.////////2///2==/..     . . ...//......//FGOOOOOOTTQTQOTOTTOOOOTOTOOTQTOOOOOOOOOOGOGGOGOGGGCGGGGGGOGOGOOOGOGOOGOGGOGOCGGCF@FF=F@FGCGGOGOGOCGG@GFGCOGOOGGCG@G@@@@@@FCGCOLOOOOOOLOCGGGCGGCGGCGCG@G@@@F@F@F@F@F@@F@=F=F=F=F@@@G@G@GG@GC@G@G@FG@F@FCG@GF@F@FF@FG@GG@GGGGGGCGGGGGOGGOGOGOGCOGOCGOCOGCOCGLGCGCGCGC@@@=@===========8==/8/8/=8=88=8=8=8=8/8=8=*8=8=88=88=8=88=8=88@8=8@8=888=88/8/8/8/**8/*=*8/*=(*=CLLLLLMMOMTMTMTMTMTTMTTTSTTVTSTTTTTTTVTVTVVTVTVTVVVVVYYVVVVYVYYYYYYYYYYYYVYYYVTTTOTOTTTVYVVVYVVYVVVTOTTTTVTVTVTTTTMTTOTMTTVVVVVVVVVVVVVVVVVVVVSVSVTSVSVSVSTMLOMOMOMMTMTMMOMTMMMOMMMMMMMMMMMMMMTMTMTSTMM/2/2=2=2/2//2//2////.///.//././/.///./....( .......(//.../////////=/=/========F=/.     .....2/2//////.//=FOOOQTTWTTTWTTWTQTTTTWTTWTTTQTTQTOOOOOOOOOOOOOGOCOOGOOOGOOOOOOOOOOOOOOOOOOOOLOG@F@F@FG@GGOOOOOOOGCFGCOOTOTOOMOGCGCGG@G@G@GLOOMOTOMOMOOOOLOOLGOCGLGCGOCOGCG@@G@@G@G@@F@F@F=F@G@G@@G@GCG@GGGGCFG@G@GG@GG@GG@GG@GG@GGGCGGGGGGGGGGCGOGOOLOLOOOOLOLOOLOLOLOLOOLGCGCOCCCG@@@====@==========@8=8=8==8=@8@8@8=8=8=8=8=8=8@@8@=9@9@@8@9@9@9@9@99=888=888888=8=8=8=8=8==8(.8@LLMMTMTSSTSTSTTTTSVTVVTVVVVVTVVVVVVVTVVVTVVVVTVVTVVVVVVYVVVYVYYYYYYYYYYYVYYVTTOTOMTTTVVVYVYVYYVVTOTMTTVVVVVTTTTMTOTMTOTMTVVVVVVVVVVVVVVVVVVVSVVVSVTSVSVSVSTSTMLMMOMMTMMMMMOMMOMMMMOMMMMMMMMMMMMMMMTSTS/2=/2=2////2///////.//.//.//.//./////......( ...(.././...../././///////2/=2//2=/=/..    ..././2=2///../2=FOOOTQTOTQTQTOOOOQOTOTQTQTQTQOOOOTOOOOGOGGGGCGGGCGGCGCOGOGOGGGGGOGOGCOGLGCOG@@F@F@F@F@GGCGGCGCF@FG@OOOMOOOOCG@F@@F@F@F@@GGLOOLOOOLOOLOCGOGCGCGCG@GCGC@G@@G@@F@@@@F@F==F=@@@@F@F@F@@G@G@G@@G@G@FF@FG@FG@F@F@F@@G@G@G@GGCGCGCG@G@GGCGOGOCGOCGOCGLGCOCOCGCCGCGC@@G@@@@==@==========8==8==8=*=8=88=8=8=8=88=*8/8=8=88=88=8=88=88=8=8=888=88=888/8=8=*8=***8/*/**/*/(/CCLOLMOMTMTMMTMTMTTTMTTTTSTTVTTTTTSTVTVTVVTVTVVTVVVVVVVVVVVYVYYYYYYYYYYYYYYTTOTOOTOTTVTYVVYYVVVTOTTTVVYVVVTVTMOTTTMOTMTTVVVVSVVSVVVVVVVVVVSVVVSVSVTSSVSTSTSTTSTMMTMOMMTMOTMMMLMMOMMTMOMMTMMOMMTMMMMMMM/=2/=2/2/2///2///2//.//.//.//.//////./..... .(....///../.././/.///////=////////=2/.     . ..../......../FGOGOOGGOGOGGGGGOOGQGOOOOOOGGGGOGG@G@G@G@G@F@F@F@GF@G@G@G@G@G@G@F@G@G@G@G@=F=2==2===F=F@F@F@F=F=GGCOOGOCGCF@F@F=======F@@GCGCG@GCG@GCG@@@@@F@F@F@F@F@=F==F=F=F===/=/===2=F/==2=====F===F=F=F==F=F=F=F==F=F=2=F==F=F@F@F@F@F@F@F@F@G@@G@@G@@G@@@G@@@F@@F=@=====/==/=/////*////*//*/*/(*/(*.*.*(/*****.(*(.**.**/*/8*=**/**/**/*8*/*8*/**/**(**(**/**/*(*.**.*.(/@CLLLMOMMMTMTMMTMTTTSTTTTVTTTTTTTTTVVTVVTVVVTVVVVTVVVVVVVVVVYYYYYYYYYYYYYVTTOOMTOTTTTVVVVVVTTTTTTTYYVYVVVTTOMOTOMTOTOTSVVVVTVTVVVVVVVVSVVSVSVTVSVSVVSVSTSTMSTTSTMTSOMMOMMMOMOMMMMMMMMOMMMMTMMMOMMTMTM/2/=2/=2///2///2/////.//.///././////../..... .(./././//./..././/.//////2//////=///.   ...1........ ./FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG@GFG@GF@F@F@F@F@F@F@F@GF@FF@FGF@G@GF@G@G=F==2==2==F=F=F=F@F==F=GGGOGLOGOCF@F=F==F==F=F=G@GCG@GC@GCGCG@G@G@F@@@F@@@F=F@@F@=F===2=2==F=F=====2==/F/F===F=F==F=F==F=F=F=F===2=F==2=F=FF@F@F@F@F=F=F@F@F@F@F@F@F@F@=@F=@====//=/=/===/=/=/////8/=/*//*/*/(*(.*(*(/**/(/*(/(*(/(**/**/***/***/**/**/8*/***/****/(**.***/(*/*(*.*(((/CCLOLMOMTMMOTTMTTTTTSTTTTSTTTTTTTSTTVTVVVTVVVVVVVVVVVVVVVVVYVVYVYVYYYVYVTOTOTTOTTTOTTTTTTTTOOTTVYYYYVYVTTMOOMOOMOMOMTTVTVSVVVSVVSVVSVVSTVTVSTSVTVVSVVSVMTMTMMTSTSSTSOMMOMLMMLMOMOMMMMMOMMMMOMMMMMMTM/=/2=2//2////2=///////.//.///./////././.... (./../////./././././/.////=///////2=//     . . ......./FFGGGGGOGGGGGGOGOGOOQOOQGGGGGGGGGG@G@GFCFG@FF@FG@FG@GFCFG@FG@F@FG@G@G@@F=2=/=2==2==F==F=F=F=FGCOGOOGLGGCF@F==>=2>====@F@G@G@@GGCGCG@G@G@@@F@F@F@F@F@F@F@F====/===F====F=2==/=/=2=/F====2====F====F==F=F==2==2=F=F=F@F@F@GF@F@F@FG@G@G@G@F@@F@F@@@F======/==========/===////*/=*//*/*(/(*(/(**.****/(*.(*(/***/**=*8*/***/***=**8*/*8*/*/***/***/*(*/**.*(/(. (=CLLMOMMMMTMMTMTTTSTTVTSTTVTTTTTSTTVTVTVTVVVVVVVVVVYVVYVVVVVYVVYVYVVYVVTOTOTMOTTOTTOTTTOTOOMTTVVVYYYYVVSTOMOOOMOOOMOTTSVTVTSVTVVVTVTVTSVTSTVSTSVSVVSVSVSTMTMMTMSTSTSSTMLOMOLMOMLMOMMMOMMOMMMMLMTMMTM/2==//2//2/2=/////////.////.//////.///........././//.////././././//////=////=/=///.  . . .  .. .2.//.//2/=GGOOOTQOOOOOTOTQTQTTWOTTQTOOOOOOOOOOGOGGGGCGGGCGOOGOGOGCGGGGOGLGGGOGGG@@F=F@@F@F@F=F@F@F@FGLOOOMOOMOOOCGF?IE?E?I>I>I@CGLGCGCOCOGLGOCOCGGCGCGC@G@GCGCGCG@@F@F@F@F@@G@F@F@F@F=F=@F@=F@F@@F@F@F@FF@F@FF@F@F@F@@F@FCG@GGGGGCGGGGGGCGGGOGOGCGGCGCGCG@@G@F@@@=@=@@@@@@@@@=@=@=@=@=====8==8/8/*==8=8/=8/8=*8=*=*==8=8=8===8=8=8=8=8@=8@@8=@8=8=8=8=8/8=*=*=*8//*/(( (/@LMOMTTMTTMTMTTMTTSTTVTVVMTTTSTTTTTSTVTVTVTVVVVVVVVVVVYVVVVVYVYVYVYVVTOTOOMOTTOTOTTOOOMOOTTTVVYVYVYVVVTTOOMOLOLOLOLMOTVTSTVTVTVSVVTSTTSTSTTSVSTVSVVSVTSTSTMTMMTSTSTSSTSMOLLLLLMOMLMOMMMLMOMLMMMMMTM==2=2==2=/2=/2/2/2//////////./////././/...../../////////////////////=/=2/=/F/===2/.  ... ....... . .././2/////=2=GTQTTTOTOTTQTQTWTTWTTTWTTWTTQTOOOOOOOOOOOOGOOOOOOOOOOCGOCGOOOOOOLOLGCF@F@@F@F@G@G@G@G@GGOOMOTOTTOTOOOPwwwuwvuvuIEIBIAOCOLOOLOOOOLOOOLOOLGGCGGCOLGLOOCG@G@@F@G@CGG@G@@@G@F@F@F@F@F@@G@G@GF@F@@F@GGCFG@G@G@G@G@G@GGGCGOGOGGOGGCGGOOOCOGOCGOCGCGCG@G@@G@@@@GCG@G@C@@@@@@@@@@==@=@=@====8==8=8==8=8=8=8=8=8=8==@8=@9@9@@9=9@@9@9@@9@@9@@9@@@9@9@8=8=8=8==8=*/*.(.(.(*=LTSSSVSVSVTVSVVTVVVVVVVVVVVVVTVTVTVVTVTVVVVTVTVVTVVVVVVVVVVVVYVYYVVTTOOOMOOOTOTTOTMOTOTMTTVVVVVVYVVVTMTOMOOLOLOLOLOTTSTTTTSTVTVTSVTVTSTTSTMTSSVSVTVSSVTSTMMTMMTMSSTSTSTMMTLLLLLLOMMLMOMLMLMOMOMTMM2/=2=2=2/2//2////=//////////////.//.//...../..////////////././././//.////////2/=//. . ....... .. . ./././.2/2///FGOTQOOOOQOTQTOTQTOOOQOTOOTOOOOOOOGOGOCGOGCGGOCOGGOGCGCGGCGCGCOGGOCG=F==F=F@F@F@F@FG@GGGOOOOOMOOOOOPBzt|~t~tttvtuv??IAGCGCCGCGLGLGLGCGCGCGCGCGCGGLG@G@@@F@@@F@F@@F@F@@@F@@==@==F@F@F@F@=F@=F=F@F@F@F@F@F@F@F@F@F@G@GGCGGCGCG@GGCGOGCGCOCG@G@@F@@@F@@F@@@@@@@@@@@@@@=@=@==@======8=8=/*=*/8*=8==*=8/8=*=8=8=8=8==8==8==8=8=9=9@@9=9=8=8=9=8=8=8=8=*/8/*/*/( .(.((/9LMTSTSTTSTMTTMTTTSTTTSTTTSTTVTSTTTTSTVTTVTVTVTVTVVVTVTVTVVTVVYVVVWTOMOOOOOMOTOOTOTTOTTTVVVVVVVVVVVTTTTOOLOOLOLOLOMOTTTMTMTTTTSVTTSTSTTMTTSTSTSTVSVSVTSTMTMMTMTMTSTSTMMTMMMTLLLLLLLOMLOMLOMLMLMMTM/2=2/2/=2=2=////2////////////////.//.....././/.//////////////././/.///.////////./.    ... ... ..............//FGGGGGGGGOGGGQGOGGGGOGGOGGGOGGG@G@G@G@G@G@G@G@F@@@@F@F@F@F@G@FC@@F===2==2===F=F@F@FG@GGOGOOOGOGOCI|~{~{{{{{|~y|tvqE?IAF@@F@@@G@G@@G@@G@F@@@F@@G@@@F@F==F=F====/F=====2==2=/2=/=/==2==2==2=2==2==F=F==F===2==2=F==F@F@F@F@F@F@F@F@F@G=F==F==F=====2==/==/=======/=/=/=/=*///*/*//(/**.(/(/(*.*(*(/(*/(*.**/**/**/**=*/8*=*8/88/8=*8/8*8/*8/8*/**/(*((.((  ((.(((.((.(/=COMMTMTMTTTMTTSTTTSTTVTVTTVTTTTTSTVTTSVTVTVVTVTVVTVVTVVVTVVTVVVYVTTOOOOMOOOTOTTTTTTTTSVVVVYVVVVVVVTTTOMOOMOLOLOLOMTTTMTMTMTMTTMTSTTSTTSTSTTSTSVSTSVTSTSTMTMTMMTMTMTMTMTMTMMTMMLLLLLLMLLMLLMOMOMMO/=2///2/=2//2/////2/////////////..//../..//.//////=/=/////////././//./././///././.   ..........2/2=2/2/.....2=FG@FGGGGGGGGGGGGGGGGGGGGGGGFGF@F@FGF@@FF@F@F@F@F@F@F@F@@@F@F@G@F@F===2==F=F@@@G@G@GGCGOGOGOGGGAz}}}}}}}}}{}{~sttuvw?IA@F@@F@@@@G@@G@@@@@F@G@G@F@@=@F=@====2=/===F=2==/==/=/=/==2==2===2===2==F=2==F==2=2==2===2=F=F=F=F=F=F=F=F@F@F==F=/=F/=/=2=/==/=/==/==/=/=//=////=////*/*/.*.*.*(/(*(*.*/(**.*(**.**/**/**/**/*/**=*8/8=*8=8*8/*8*/****/**(/(/(( .(.((.*.*/====8/*.(.*/8CLMTMTMTSTSTSTTTSTTVTTSTVTTSTTTTTTTSVTVTVSVTVTVTVTVTVTVTVTVVTVVTVTTOOOOOOMTTTTTTTTTTVTVVYYVYVVVVVVTTTTMOOLOLOLOLOTTSTTMTOMOMOTMTMTTMTMTTTSTSTVSTVSTSVTSSTSTMTMTMTMMMMMMTMMMMMMMMLLLLLLLOLMLOMLOML2//2=2/2=/2=///2////2//////////./././..././/////=///==/=/////././/./.././/.//./....  . ..../..//2=2=FFF=F/2/2/2@FGGGGGGGGGQGQGGGGGGGGGGGGGGGGGG@G@G@G@G@GF@G@F@@F@F@@@F@F@F@@GF@F=F=F=F@F@G@G@G@GGCGGGOOGGGAPw}f}}}a}{{{ttzEw>I>@F@@F@FAF@FAF@FAF@A@FAF@>F=@=F=F=2===2==2====2=//=/2=/=/=/==2===2==2==2==F==2=F==2==2=F=2=F=F@F=F=F=F@F@F@F=F==F=F===2====/=======/====/=/=//=///=*////*/(/**/(/*/(**.**.**(/(**.*/*/*/***/8*=*=*/8=8=8/=8=*=*/*8/*/***/(*.((( (((.**/*==9@@C@@@@=8==@COMMMTTSTTSTTSTSTVTSTTVTSTVTVTSTTTTTSTVVVVVTVVVTVVTVVVTVTVTVVVTVTTTTMTOTTTTTVTVTVTVTVVVVVVVVYVVVVVVTTTTMTOOLOLGLOMTTTMTOMOMOMOMOMMTMTTMTSTVSVSVSVTSTSTSTSTMTMMMTMTMTMTMOMOMOMMTMMMOMCLLLLOLMLMLOM/2=2//2=2/=/2//////2//////////./././..././////////=/=/=/==/////.//././././/.///.. .   .....//=/=/==F@FGGGOOGGGF@FGGGGOOOOQOQOWOTQOOQOOOOOOTOOOOOOOOOOLGOOOGLGGCGGCGGCGCGGCGGCGLGGLGCG@GCG@GCGGCGOOOGOOOOMOOPPIw~nnononmm}}}a}~||zzwwBIBIBIBIBIBIBIBIBPIBIBIBIBIBIBIBI>I>I>I>I>F>F>F>F=F==F=F=F=F=F@F=@F@FF@F@F@FF@F@F@@F@F@@F@F@G@G@G@G@G@G@G@G@G@FCF@@F@F@@@F@F@F@@@@F@@@=@@@=@=@=@=@=@==========8===8===8/8=8/=8=/8=8===8===8=8==@8@@@@@@@9@@@@@@@=8=8=8==*/**/*.(.  (.(.*//8/=@@@CCCLLLCLCCCCLLMTTMTSTTSTVTSTTSTTVTVTSVTTVSTTSTTSTVTVTSVTVVVTVVTVVVTVTTVTVTVVTVTTTTTTTTVTVTVTVTVTVVVVVVVVVVVVYVVVVVTTTTMOLOCOLTTSTTMOMOMOMOMOMOLMOMMTTSTVTVSVVSVTSTMTSTMTMMTMTMTMMMTMMOMLLMOMMMMMMMMOLLLLOLOMLO=2//2=/=2=2=/=2=2//////////////././....///////=/=//======/==////////.//////////...   . ....././/=F==F=FGGGGOOOOOOGOOGOOOQTQTQTWOTWTTQTTQTTQTTOTTTOOOOOMOOOOOMOOOOOCOGCOCGGLGLGLGOLOGOGGOGCOGOOGLOOOOMOOMOOMOOPxwn¥¢¢£¢¢¥¥onmmf}}}~|~||zzzwwwwwBwBwBwPwNwBwPwBwNwBwBwBwBw?Bw?E?E?I?v?I?I?D?I>D>>F=F=F@F@F@F@@F@FG@G@GG@G@GF@F@F@@G@GFCGGGGGG@GFGG@GGG@GG@G@G@CG@G@@@G@@G@G@@G@@@@@@@@@@@@@@@@@@@@@=@=@=@===8===8=8=8==8=8===9===8=@=9@@@C@CC@CCCCCCC@@@@@9==8=8==8==*/*.( ..(//8===@@@CCLLMLMMTLMMMMTMTSVVSVVVVVVVVSVVVVVVVVVTVVVVVVVVVVSVVVVVVVVVVVVVVVVVVVVVTVTVTVVTVTTTVTVTTVTVVVTVVVTVVVVVVVVVVVVVVYVVVVVTTOLOLGLTTMTMOTLMOOLLMLMOMOMOMLOMTSTSVTSVSTSTSMMMOSMOMMMTMTMTMMOMMLOLLLMOMMOMTMMMOLLLOLOL/=2/2/2/=//2=////2///////////./../../././////=///=/=/=2=/==//=///./.././././....   . ..../////=2=F@F@GOOOGGOGOOGOGGOOOOQOQOQOQOQOQOOOOOOOOOOOOOOOOOOOLOOGOCGCGCGCGGAGAICGCGCGCGCGCGCGCGCGCGCGCOOGLOGOOOPPw~n¢££££œ£££££¥oommfkf}}}~~||vzuzvuwwuwwwBwwwBwwBwwBwww?w?w?ww?v?EEvEEEEwED>>=>F==F@F@F=F@F@F@F@FG@F@@F=@F@F@F@F@F@F@F@F@F@G@G@G@@G@F@@G@F@@F@F@@@F@@F@@@G@@@@=@=@=@=@=@==@====8===8==*=8=*===8==8=8/=8==8==8=@8@@@9C@@@:@@@@9@@@@9==8=8/8=8/*/*.(( .(/(//8===@=@CCCLOLOLMOMOMOMMTMTSTSVTSTSVTTSTTSTSTSTTSTVTSTTSTTTTVSVTVVVVVVTVVVVVTVVVTVVVTVVTVTVTTTVTTVTTVTVTVVVVVVVTVVVVVVVVVVVVVTTMOOLOLTTMTMOTLOOLOLOLOMOMTMOLMLOMOMTMSTSTSTSTTMTLOLMOLMMMOMMTMMMOMLMLOLLLMMMMTMTMMOLLOLL2/2/=2=/2///2/2///2/////.///././......//////=/=//2/=====/=/=/////./././/./../..    . .././/=//2=FF@GF@FGGFGF@FGGGGGGGGOGOGGOGOGGGGGGGGGGGGGG@G@G@GC@G@@G=@F@I>I?v?w>F@@F@@F@@F@F@F@@@G@@G@G@GAGINIww~¥œ£œ¢¢¢¢¢¢¢œ££¢oommmmk}}}}~~tttttvtuvuEuwuwuvuvuwuvuvuvuvuvuEvqvrErErEq6t6EqE66E6;5;D;/D=/==2===2==F==F==F=F/==2=2==2===F==F==F=F=F=F=F=F==F=F=F=F=====/==2==F/====/==/===/==/=/=*/=*//*/*.*/(*.*.*(/*(/*(/*/**/***/8/8*=8=8=8=8=8@8=8*=*=**/*(/*.*.((. (.(//*====@@@@CCCLCLLLLOLMOMOMMMTTMTTSTTSTVTVTTSTTTSTVTSVTVTSVTVTVTVVSVVVVVVVVVVVVVVVVTVVVTVVTTVTTTTTTSTTVTVTVVVTVVVVVTVVVVVVVVVVTTMOLOOTTTMTOMOMOLOLOLOLMOMOMTTMTLOLOLLTLMTTMTSTMTLLOCCCGLOLOMMOMTLMOMLLLMOLOLMTMMTTMMOMOL/2=2//2////2=/=/2///////////.../....././///=/=/2=/=/=/=/=/=/==/////././/././..   ......//2=/=2@FF@FFF@FGFFF@FGFGFGGGGGHGGGGFGGGGGG@GGFGGFGF@F@G@F@F@F=F>>II?vuvu~t~|~uF@G@F@F@F@@F>FAIBI?I?w?wwzwz|~}n¢œ¢™…—ƒ¢‚ƒ¢ƒ¢¢¢£¦ollmmm}}}}~{|tttttvtutvutvttvtutvutvtuvuvuvutvtutErt6tqtqqqEq666E6;6;D;;2=/2====2=F/F/=F====F==2==/2=/=2==F=2==F==2==2==F=F==F==2====2==F/==2=========/====/=/=////*///*//*/*/*//*/*//*/*/*/*/*/*/*8/8=8=8==@8=@=@8@==/*/*/*/*/*(/(((.(  .(./*/====@@@@CCCGLLLLOMLMOMLMOMTMTMTTMTSTTTSTTTSTTSTTMTTSTVTVTSVTVVSVVVVVVVVVTVVVVVVVVVVVTVVTVTVTTTTTTMTTTSTVTVTVVVTVVVVTVVVVVVTTMOOLOMTTMTOMTMOMOLOCLCGLOLOMMTMTMTMTMOLOLOLLLLMOMMOMOLLCC@@CCCCCLGMOLMLOMLMLMMOLOLOMMOTMTM/2//=/2=///2/=2=2///////////./../..././///==/=/=/=2==/2==/=////////////.//./..  ..././//=F=@F@G@GFGGGGGOGGOOGOOGOQOQQOQOQOQOQOOOTOOOOOOOOOOOOOCOGCOGAIBwwzz~||}~}~zGCGCGCAGIAIBIBwBwwwzwz|z|z~|~nœœ™—…ƒƒƒ‚‚‚‚¥ƒ¢ƒ¢£¥olmmm}}~}|z~z|w|wuvzzvzuzwuzvzuzvzzwzzwzzvzzvtvtuttvttvtvrvqvD>D>>F=@F=FF@F@F@F@FFF@F@F@F@F==F=F@FF@F@F@F=F=F=F@G@G@F@F@F@@F@F@F@F@F@FF@F@F@@@@@@@@=@@==@@=@=@=@=@=======@==@=8==@==9=@@=@=@=9@@@@CC@CC@CCCC@C@@=8/8===8==*=/*/*.   (../*====@@C@CLCCLOLOLMMMMTMMTMTMTMTTSTSTTTSTTTTSTTTMTMTMTTTSTVTVVSVTVTVVSVVVVVVVVVVVVYVVVTVTVTVVTTVTTTTTMTOTTTVTTVTVTVVTVVVVVVVVTTMOOLOMTMOTLTOMOMOMOLOCOLGLGLOLMOMTMMMMMMMLCLGLOLOLOLMLOLCC@@@@C@CCCCCLOLLMOMOMMMOLOLOLMOMTM/=2=2==2=2==2=/2==2=//2=/////.//.././//2/=2==/=2===/=/===2==/=////////=/////..  ....////=2=@F@FGGGCGGGGOGOGOOOOOQOOQTOTWOTQOTQTOTTQTOTOTOOOOOOOOOOLOPBwwzz||~~}}}}zGPGPBPIBPwBwwwzzzzz||||€~|~~n¢£™—…ƒƒ‚‚‚‚‚‚‚‚¢ƒ¢£¦olmmm}}~|||z|wzvzvztzzvzvzzvzzvzzwzwzwzwzzwuzztvt~t~t~ttttvtvEEEI>F>F>F>I>I>I>FI@F@GF@G@F@@F@F@F@F@F@F@FF@F@F@F@@G@GG@G@@@G@@G@@F@@FG@G@FC@GCGC@@C@@@@C@@@@@@@C@@@@@@@@@@@@@@@@@9@@@@@@@@@@@@@CCCCCCLCCLCCCCLCCC@==8/8==8=/8/*/*.  .(.*//==@@@CCCLGLOMOMMMTTTTSTVSTSTSVTVVSVTVVVVVSVVTVTSTTTTTSTVTVVSVTVVVVVVVVVVVVVSVTVVVVVVVVTVVTVVTVTVTTTTMTOTTTSTTVTTTVTVVTVTVTVVTTTOLOLMTTOMOOMOMOMOLLOLOCCLGLLOLOMOMMOMTMOMMOLLOCOCOLOCOCCCGC@C@@C@C@CC@LCCLLMOMTMMOMOLOLOLOM/////2//2=///2=//2//////////./.....././/2==2==/==2=/=/=/==/=///////////.//....  ...../=====F@G@FGF@GGGGGGGOOOGOOOOQOQOOQOOQOOOOOOOOOQOOOOOOOOOGGPBwwzz~~~}}nmn|IwBwIwzwzz~z||~|~|~~|~~}~}|¢£™…ƒƒƒ‚‚j‚j‚j‚‚¥ƒ¢™¢oommm}}|~|~|||t|~{|~{|~t|t||t||tz|zz|w|wztztzt~~~{~aaaaaaa~{~sttEtErvttttt~tvttvtvqvE?I?I=>F=@F@F=@F@F@F@F@F==F==F==F=F@@G@F@F@F@F@F@@F@@F@F@F@G@GCG@G@@@@@@@@@@@@@=@=@===========8=====8==@8@=@=9@@@CCCCCCCCCCCCCCC@@@/8/*/*/*/*/*.(  .(///==@@CCGCLLLOLOLMOMMMTMMTMTMTMTSTTSTSTTTTTTSTMTTTMTMTTTMTTSTTSTVTSVVSVVVSVVTVVVVVVVVVVVTVTVTVTVTVTTTOTTMTTTTTSTVTTVTTTVTVVTVTTOLOLTTTTMOMOOLOLOMOLLOLGCCCOCLOLOLMOMMOMTLMMOMOLLGLOCOCCCC@@C@@@@C@C@CC@CCCCOLMOMTMMOMLOCOLO//2////2=/2=//2=/=////=2///////...//./2/=2==2==F===2===2===//////.///.//.....   ..././//F==F==F=F@FF@FG@GFGGFGGGGGGGGGGGGGGGGGOGGGGGGGGGCG@GI?vzt~{}}fmnno¥¥¥n}vzvt|t|t~y~{~{~~}~}~}~}~}~}¥£™™ƒƒ‚‚‚jjjjj‚j‚ƒ˜—¢™ollmmmm}}}~}{{a}eee}aa{{{{{{{{{{}{{{{{~{~{~{{}afnnooo¥o¥oonnnfffeeeaea}aaa{a{{ytsttqvqE6ED;D==2==2=2=2=2/2/2//2/2/=2=F=F=F===2====F=F=F=F=F@F=F@@F==========/=/=/=/=====/8/8/=*=*=*=*=*=*/8/8/8/=8===8@=@=9=@=@8@=@==8/((.((.((.  ..(//===@@@CGCGLCLOLLOLMOMOMOMMMTMTMTTMTTMTTSTTMTMTMTTMTMTTMTTSVTVTSTVTVTVVVVSVTVTVSVVVVTVVTVTVTVTSTTTMTTOTOTTTTTVTSTTTTTTSTTTTOLOLOMTTTTTOOLOLOLOLOLOLCLGCCCGLCOLLOMOMMOMOMOMOMTLLOLGCCC@@@@@@@@@@@C@@C@@C@CCCGLOMOTMTOMOLOC///2=/2///=2/=/2//////////.//./.././/.//2=2===F==2==/===/==2=///////.//....   ( .////===F=2=F=FF=FF@FGFGFGFGFG@GFGFGFFGG@GGGG@GFGFG@GFCFG?v|t{{}fkmno¥¦££££¢{~y|~{~{{|{{}~}{}~}~}~}~}}o¢£—ƒƒƒ‚jjjjjjjj‚‚‚ƒ¢™£™¤oolmmmmff}efffkffffee}e}e}ee}}}}}}}}}ffno¥¢¢œœœœœœœœœœœ¢¢oonkfkfffeea}a{a{ysstsqqE6E;D>2==2=2=2=2/2=//2=2=/2=/=2=/==2===2==2=2===F=F=F=F=F=========/=/=///=/=*/=///*//*///8//8/*//8/*=/8/8===8@=@=9@=@=@@=@@====/*.*(.(.( (.///===@@CGCLCOLOLOLMOMMMMTMMOTMTTMTMTMTTMTTMTMTMTTMMTMOMTMTSTTSTTSTTSTVTSVTVTVTSVTVTVSVTVVTVTSTTTTTTMTOMOTMTTTTTSTVTVTTTTTTMOOLOOLTTTTMOMOOLOLOLOLGCGCGCGCGCCOCOLOLOMOLMOMOMMOMTMLOLCGC@@@@=@@@@@C@C@@@@@C@CC@CCCLOLMOMOLLO/2=//2//=2//2/=/=//////////.//./././2///=/=2========2====2=///////.//.....   ....///=2==2=F=F=F=FFG@GFG@GFG@GFGGFGGGGGGGGGGGGGGGGGGFGAGww|{}}fkmoo¢£££££œn}~{~{{}{}{}~}{}~}~}~}}~}}no£™¢ƒƒ‚‚jjjjhjjj‚‚‚¢ƒ™™¤ololoooommkmmkmllnmmmkkkfkkmmmmmkmkkfkkmfmmmnmo¥œœ££œ¢£¢£œ£œ£¢¥olmmmkffeeaeaa{{ssssqtqE6EE>D>2===2=/=2==F==2==2=2==/=2==F=F==F==F@FF@FF@F@F===@===@======/=/===/===/===/=*/=*=/8/=*=/8=*=*==8/=8===@9=@@@=@=@=@=@@8=/*.(.*.(. .(//=/=@@@@CCGLOLLOLOMOMTMOMTMTMTMTMTTSTTMTMTMTMTTMTMTMOTMTMTMTSTSTTSTVTSTTTSTVTSTTVTVSVTVTSTTVTVTSTTTTOMOMOOOTMTTTVTTTTSTTTOOCOGLOMTTTTMTOMOLOLOLLGCCGCCG@GCGCCCCOCOMOMOLMOMOLMMOMTMOLLC@@@=@=@=@@@@@C@@C@@C@CC@GCCCOLOMOLOL/=/2///2//=2=/2/2////////.///.//.//.//2/2=/=F==F==2===F====/////./////...  ...//==F@@F@@F@G@FG@GGGOGOOGOGOGOOOGOOOOOOGOOOOOOOOOPPPPIPww|}}mmo¥¢£££££™££n~}~}|~}|}~}|}~}~}|}}}}o¥£—ƒƒ‚‚jjjhjjjjj‚‚‚¢—£¦¤¤o¤o¥¦£¢¥ololooo¥o¥¥o¥ooiolollmmmmmmollolo¤o¤¦££££¢¢£¢££££œ£¢onmkfke}a}{{tytsvtvtvuvE?I>F>F=F@F@F@FF@F@FF@F=F=FF=F@F@F@F@G@GCGCGG@G@G@GCG@GCG@G@@C@@=@@@@@@@@@@@@=@@=======@==@@@@@@@=@@@@@@CCCCCC@CC@CCCCC@C@===/*//*/(.(.//==@@C@GLOLOMOMOMMOMTMTMTSTTSTTSTTSTSTTSTTTMTTTTTMTTMTMMOTTMTTTSTTSTTTSTTTTTTSTTTSTTTVTVTSTVTTSTTTTTTMOTOOMOMOTTTTTTVTSTTTOCOCOCOLTTTTTMOMOOLOLLG@CG@CG@CG@C@CGCCOCLOLLMOLLOLMOMOMMOMOLL@@@=====@=@@@@@@@@@@@@CC@CGCGCGLOCLO=2=//2=/=2==2====/=2=///////////2//2///=/=2==F==F===F==F===/////.///////..  ...//===@F@@FG@GGGCGGGOOOOOOOOOOOOOOOOQOOOOOOOTOOOOPPPPxIxzwz}mno¥¢££™£™š›££¢}~}|}~}|}~}~}|}|}}}lo¦‘£…¢‚‚‚jjjhhjhjj‚‚˜—™¦¤o¤¦¦££”¢¥o¤¥¦¢££££—¦¤¤¤o¤lo¤o¤¤o¤¤¤¤¤¤¦£ž££¢£¢££££¢¦¢¦¢¢££¢£œ£¢onfe}a}{{{{{{~ytt~tttztwv?II>F@FG@G@G@GF@G@F@F=F=F@F@G@GGCGGCOGGOCGGGG@GGCGCGCCGCG@G@CG@@@C@@@C@@@C@@@C@@@@@@@@@@@@@@C@@CCCCCCLCLLLCCCCCCCLCCC@@==*//*//*/(. .==@CCGLMOMOMTSTSTTSTSTVTVVVVVVSVTSVVTVVSVSVVSVTVSVTSTTSTSTVSTSVTSVTVSVTVTSTVTTSTTTTSTTTTTTVTTTTTTTMTTMTOMOOOOMOOTTSTTTTTTOCGLGOLOMTTMTMTOOMOLLGC@G@@GCGCG@@G@@@CGCCGLOLOLOLLOLOLMOMOLLOLLC@@@=@===@=@@@@@@@@C@@CC@GCCGCGCGCC/=2////2//2///2/////////.////././//////2=2/===2==2=2====2=//......././... ...//====F=@F@G@GFCGGGOGGOGOOGOGOOOOOOOOOOOOOGOPPPIPwwwzzzz}moo¢£££™™™š››››o}~}~}~}}}~}}~}}mmmmo¤£‘™¢ƒƒ‚jjjhjjjjj‚‚‚ƒ™‰ž™¦¤¦¡£ž£££¡—££›ž“‘››‘›‘‘ž£—¦¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦£‘£¢™¦¢££££¦¥oooooo¥¥££¢¢¢£¢offe}a}{{{{{{{{{{{y~y~t~tttwuvE?I>IIFAFF@FF=F=F=F=F@F=F@@G@GCGCGC@GCG@GCGCGCGCG@@G@@@G@@@G@@@C@@@@@@@@@@@@=@=@@@@@@@@@@@@@@CCCCCCCLCC@@@@@@@@@==/*.(.(.*.(..   /=@@GCGLOLMOTMTTMTTMTTSTSTSTTSTTSTMTMTSTTTSTTMTTTTMTMMTMTMOSTTMTTSTSTMTTSTTMTTTSTTTTTTSTTTTTMTTTMTTTMOTOMOLOOOMOTOTTTTSOOCOCGLGLOTMTTOTMOMOLGC@G@@@G@CGCCG@@G@@@@@CCCLOLOLOLOLLOLOMLOLLOLCCC@@==@====@=@=@@@@@@@C@C@GCC@GCGC/2//2///////2=/2///////.//././/2/2//2=/////=2=====/=/=2=///... .../.... """!,4..////=/2==2=>F=FAFFGF@FGFGFAFIFGIGIFIIAIIBIIwvwwzw|z~~~mo¥££™—™™Ž››“£n}}~}}}}}}}}}mlommmlo¤¦£‘™…„‚‚‚jjjjhjj‚‚‚˜…™‘š¡¡šž›£‡ž‘žžžžž‘››‰š™‰£‘‘™¡¤¤¤  ¤    ¤¤¤™££™¢™¢™£££¢¥oioilllolo¥œ£¢¥¢œ¢offaaa{a{{{{{ay{{{{{{{y{{{stttEtEEEEEEEEEDD;DD>2>2=2=FF=F=F=@F=F@F@@F@F@F=F==@F@======F===F============/=8=/=8/=8/===8====@=@=@@@@@@==/*/*//*/(.   /==@@CGCGLOLOMOMLMTMTTSTTSTSTTMTMOTMTMTMMOMTMOTMTMTMOMTOMMOMMTTMTTSTSTTTTTMTMTTTMTTMTTTTTTTTTMTOTMOTTMOOLOLOLOOMOTTMTOOCGCGLGLGLOTMTTTOMOOLCF@@@@@CGCCGC@G@@@==@@@@GCCLCGLGCOCOLLOLLOLCOCLCC@C@========@==@@@@@@C@@C@GCCGCG/=/2///2//2////////2///.//.//.////2=/////=2==2=F==/=2////5.4 ,  .... "#$$$q64;////>2>DD>EEII?I?IIBI?II?IIIwI?IwIwIw?vwvvzvt~t~~|{}fm¥££™—™™‡‡‰ŽŽŽ›”¦na}{}}}fmf}}foo¥¥o¤oo¤¤¤¡›‘™™…ƒ‚jjjjjjjj‚‚ƒƒ™ž›¡†š›ž£Ž‡››‘žžž’›››Žš£‰‡™—™ž—¡   ¡  ¤ ¤¦¡‘£¢¢™¢™£££¢¤oiolilillhoo¥œ£¢¥¢£¥nffeaaaa{a{{yy`{y`{y{y{{{y~ststtqtEt6vqEqEqE6E6EEEEEE;E>D>D>>F=F=F=@=======F====F=====================/=/=*=/==8=====8======@=@@@=@==/*./(.(. /@@@GCGLOLMOMOTMOTMTMTSTTSTTMTTMTMTTTMTTMTMOTMMOMTMTMOMTOMTMMTMTTSTTMTTMTTMTMTTTMTTMTTTSTMTTTTMTMTOMOMOOLOOCOOOMOTOOLGCGCGCGCOLOMTMTOMOMCG@@@@F@G@CGCGCG@@@=====F@@@CGCCCCLGLLOLLOLCLGLCGCCC@CC@@======@=@=@@@@@G@@GCG@CGC/2/=/2=//////2/////////.///./.2/2=//2=/2//=/==2====2=/;564,-$$$#$,#, ,. "^^^^`pssq6;D;DED>>F=F@F@F@F@=F@@F===F=@=@================================@=@@=@@@@@@@==//(..  =@G@CLGLOOMOMTOMMTMTTSTSTSTTMTMTMTMTSTTMTTMMTOMTMOMTMOMMOMTMOMMTMTMTMTTMTMTTMTMTMMTMOTMTTTMTOTMOTMOMOOLOCOCOLOOMOOLGCGCG@GCGCOLOOMOTMOLGC@@=F@=@@GCG@G@@@========@@@@CG@GCLGLGLLCOCLCCLCCCCCC@C@@=@=========@=@@@@@CG@GC@=/=2///2/=2/////.///////.//.////=/2=///=/2=2=2=/F=F=D;56--q$$$$$$$$$$$$$$,#""""^^^^^^^`{y{{tE??I?Ew?wwwwwwwwwwwwwwzzzwwwwwwwxwwwzwzzz~z|z~||~mo£™™……………‡‡‰Ž›”¢n}mno¥omno¢£‘ž‘‘‘£š¡¡š›“‡™ƒƒ‚‚‚‚‚‚‚‚ƒ……™‘žŽš†šŒž‘š‡›‡›Ž››ŽŽ‡‡™……™…™‡‘‘š¡–¡ ¡ ¡¦‡‘£™¢¢™¢¢™££¥¤o¤o¤¤¥¤ooillol¥œ£¥¥¢œ¢offfeeee}aaaaa{{a{{{~{~ttttvvtEvvvvwvuvvzvzvzvtvzvuwuw?wIBIIAIGAG@GCG@GGC@GC@GC@G@G@GCCG@@C@@C@@@@@@@@C@C@C@CCC@CCCCCCCCCCCCCCCCCCC===//(.   ./@COMOMTMTTTTSTVTTTVSVTVTVTVSTVTSVTVSVTSTSTTMTMMOTMOMOMOMOMOMTMTMOTMTMTMTMTMOTMTOTMTTMOTMOTMTOTMOTMOOLOLGOCOGLOOLGCG@GCCG@C@GCGLOOMOLOCC@@F@=@@@G@G@C@@F====/=====@@@@CCCCOCOCGLCLGLGLCCGCC@C@@@@@@@==========@=@@@@CG@GC=F==2==/=2=/2/2//2=/////////2/=2=2====2=/===2===F==>D>E6qq`$`$`$^$^$^$$$$#$^"#"#^^^^^^^__aa}a}a|vI;EEqtsp``^`^`^^`^^^^^^^^^^""""^^^^]^_]___eeeefe}{t~vtzvzwwwzwwzwzz~~~|~zzzwwwzwwzwzzzz~~|~|~~}mo¦™‡……ƒƒ………‡ž™omno¦£žž¦oo¦£“‡‡‡‡‡‡‰›‘“ŒšŒ‘“‡™…ƒƒƒƒƒƒ………‡“‘šš†šš›ž‡™‰™‡‰Ž‘”žžž”ž‘Ž‡™…ƒƒƒ¢ƒ—…™‘‘›¡–¡ ¡¡›“£‡™™…¢—™£‘™¤¦¡£“‘ž£¦¤¤¤i¤¤¢£¢¢¥¢£¢omkfkfffffea}a}a}a}{{{{~tttEvuEvEEuv?v?vwEwuwEw?IBI?IBIIIAIAIIAGAGGCGCGCGCGCGCCG@GC@GCG@G@C@C@@C@@@@@C@CCCC@CCCCCCCCCCCCCCCCCCCLGCLC@==/.  ../=LOMTTTTTMTSTVTSVTVVSVVVTVSVSVTSTSVTSVTSTTSTTMTMTMTLMOLOLOMLMMOMMTMMOMTMOTMMTMOTMTMTOMOMOTOOMOMOMOMOOLOCGCCGC@@G@@CG@G@G@@G@@GCOLOCLG@@@@@F@@@@F@F======/=/==/===@@CCGCCGCGCCCCCGCCCCCCGCC@C@@@@@@@C@@===/=====@@@@@@C@/=2/////2////..5;5.;45;4;14;4;;2;D;2>/2;/2//=2=2>>DEEEuttss`^`^`^_^_^^^^^^^^^^^^^^^^^^^^^^]^]^]_]__b_cecfkkkffffa~{~ttvzvvztt~~~}~~~~~z~wzwwzww~z~~~~~}}}fmo™‘£………ƒƒƒƒ…‡›¦nfkmo¦£žžžž™¦¢‘ž›‡‡‰‡™‡™‡‰›ž›šš›“‘‡‡™…………………™‡“‘šš– ¡š›‘£‡‡™‡™‡›‘“ŽŒ››’“‡™„¢ƒƒƒƒƒ¢…™‘‘š¡– ¡š‘‘™™…¢ƒ…¢…œ—¡ ™ž££›£›šŸ¤¤¤i¤¢£¢¢¢œ£jnmkmkkkffffeeeaeaaaaa{{{yyttqqEq6EqEEqEEqEuEvEE?EEEIE>>I>I>I>I>>I>FAF@F@F@F@F@F@@@=@F@@=@=@===@@=@=@===@=@=@=@=@@@@@@@@@@=@@@@@@@@C@@@==/.  ../@GLOLOMOMOTMOMTTMTTTTMTTSTTTMTTMTMTTMTTMTMTMTMOMTOMOMOLOLOLOMMOMOMTMTMOTMTOMTMTMOTMOTOMOOMOOLOOOLOOLOCOCGCCF@F@FCF@@G@@G@@G@CGCGLGCCG@@F@==@F=========/==/=/=/=@FCG@CCGCC@GC@CCCCCCLGCCCC@@@@@@@C@@@@@@@==/=====@@@@@G/2//2/2/////.1;.5;45;45;4666666E6ED>ID>D>ID>D>D>D>>F==@====F@=F@F=F@@=@=@===@===@=============@=@=@@@=@@@@@@=@@@@@@@@@@=//   ../=COLOMOOMOMOTMOTTMTTMTTTMTSTMTMTSTTMTTMTTMTMOTMTMTOMOLOLLOLOLOMMOMOLOMMMOMTMOTMOTMOTLOTLOOMOLOLOLOLOLGCGCG@@F=@@F@@@@F@@F@@G@COCCCG@@@@@@=======F==2===//=//=/=@@@GCGCC@G@@@G@@C@CGCCCCCCC@@@@@@@@@@@@@@====/====@@@@@/////////2./.;45.6446466q-q6qqqqvqqEt6qEq666E6EEEEttttt~y{a{___c_c_bcbcbc]b]]]^]]]]]^]]^]^]^]]^]]]_b_bcbbcbkkkklhoŸ¢£œœœœœ¢¥nfa~~{~{}}a}}}non~~~~}{}}}}fkml¥™……ƒƒƒƒ……‡“™ollo—“ž‘›’“‘ž“Ž‡‡…ƒƒƒƒ……™‡›“Œššš›ž‘‘›‰›‘£¦Ÿ¤¤¤ ¤¡™™¢ƒ¢ƒ™™‘‘š¡–†šš‘‘¢„ƒ‚¥‚ƒ˜ƒ—™‘‘š–¡¡›‘™„ƒ˜‚¢‚¢™™¦ —ž£‘ž£—¤¤¤i¤¥£¢¢¢¢¢£¢ohlllkkmkkfkfefeeaeaea}{{yysqtqEqEqqqEqvuEvEuEE?IE>I>>I>DI>I>DI>I>I=AF@F@F@@@G@F@G@@G@G@@@@F@@@@@@@@@@@=@@=@@@@@@@@@@C@@@@@@@@@@@G@C@@@@=//   .../=GCOMOOMOTOMTOTMTTMTTTMTTMTTMTMTMTMTSTTMTMTMTMMOTMOLMOLOLLOLOMOLMOMOMOLOMOMOTLTMOTMOTLOMOLOLOCOLOLGLGLGCCG@@=@=F@@F@F@@F@@F@GCCGC@@@@@F=@==F======/==2==//=/===F@G@C@GC@C@@@@@@@C@CCCCCC@C@@@@@@@@@@@@@@@@==@=====@=@@=2=/2=/2///2.5/46464666q-qqqtqttqtttqtttqttqtqtttttt~{{{}a}aeeccccbcbcbbbbbcb]b]_c]]]]]]]]^]]_]]b]b_bbcbkbkkglgh¤¢œ£™¢¢¢¢œœœ¥na}}}no¢œo~}}~}}}mmo¦‘£‡……ƒƒƒƒ……‡‘‘¦¤oo¡žž››Ž›““”›‡‡…ƒƒ‚‚ƒƒƒ…‡™›“šš¡†š›‘ž‘‘“‘‘£¥¥i¤¤¤¤¤¤¡£™—¢ƒƒ¢„™‰‘™¡–¡–¡š‘‘‰¢ƒƒ‚‚‚‚ƒƒ™‰“£¡–—‘™—˜‚Ÿ‚‚¥‚¢¦ŸŸ¡£‘££¦Ÿ¤ioi¤¢£¢¦¢¢¢£¢ollmmmkmkkkffffef}e}a}a}{{~ttvqvqv6vqvEvuvwEBIw>IAIIIAIAIAIIAIAIAAGGGGCOCOGOLOLGLOLGLGCGCGCCGCGCCCCCCCCCCCCCCCCLLLLLOLLOCLGLOCOLLOLOLCC@@==.  ...//==GLOTTTTTTTTSTVTTVTVSVTVVSVTSVTSTVTSVTSVTSTTTMTTMTMOMOOLLOCLOLLOLOMLMOLMOMLOMOMOMOMOMOMOOLOLGLGLGLOCOCGCGC@F@F=@=@F@F@=F@=F@G@GCG@G@@@F@==F==/=2==/====/=////==@@@@@GC@G@@C@@@@@@@@C@CGCC@@@@@@=@@=@@=@@=@@@=@=======@===F=/2=/=2///;5;;6566666qqqtqttsttttttttttsttsttt{~{{}}a}efeffckbkkkbkgkdgdbdddghjjdc]]]]]_]_]b_bbbbbcbkbkkgkho¤¢£™¢¢—¢¢¥¢¢œœ¢nmmmnno¢£££o}}~mmoo¡‡……ƒƒƒ…ƒ‡‰‘‘¦¤¤¤£ž‘ŽŽŽŽŽ›‘‘Ž‡‡……ƒ‚‚‚‚‚ƒ……‡‘“›¡ ¡¡¡¡™š£¢¢¦¥¥oololo¤¤¤¤¦‡‘™¢ƒ¢ƒƒ¢ƒ™‘‘š¡–¡†¡š‘™„˜‚‚‚‚˜ƒ—™‘‘š¡š‘™„ƒ‚‚‚j‚‚˜™™Ÿ¤¥¦¦¦¦Ÿ¤oioio¥™¢¢¥¢¥¢œ¢olkmkmkkfmfkeffeea}a}~{t~ttqvrvrvuvuv?wIwIBIIAPIAIPIAPINIPGAPGPPPOOOOMOOOOOOOOLOOLOLGCOCLOLOLOLOLOCOCGLCOLOLOLOMLOLLOMLOLOLOMOLMOLGCC@@//  ..///=@FCTTSVVTVSVVVVVVVVVVYVVVVVVVVVVVVVVVVVVVVVUVSVTVTTVTTMTOMOLOMOMOMLOMOMOMLOMLOMOMOTMOMOMOOLOLGLGLGLGLGCCGCG@@F@F=F=@=@@F=@==@=@@G@@@F@@@@=====/==/==2===/=/=/===F@@@@@G@@C@@@@@@=@@@@C@@C@C@@@@@=@=@@@@=@@=@=@=@@=@===@=2=/2///2////1;5;46646q6qqqqqtqstsststttstststs{t{{{}a}a}feffkkkkkgkggggggggggj¥Šœjbb_b]cb]bcbbbbcbbkbkkgkglij™œ™¢ƒƒ˜•ƒ˜Ÿ˜¢¢œonfmmmmmnoo££œœ£onmmmmo¤™‘‡…ƒƒƒƒƒ…‡“£Ÿ¤¤¦›ž’ŒŽŽŽŽŽŽŽ‡‰…ƒƒ‚‚‚‚‚ƒ…™‡‘š¡ ¤¤¤¤¤o¤oooololol¤o¤¤¤¤ ™ž™™¢ƒƒŸƒ—™‘š–† †š‘‰…ƒƒƒ‚‚‚ƒ™…“›š‡“‡¢ƒ‚‚j‚‚‚Ÿ˜£—Ÿ¤Ÿ¤¤i¤iiioŸ™™¢¥¢¥¥¢œ¢hnkkkkkfmffkefffeffefee}a}{{{sttttttttvtvvuEv?I?IIAIAIAIAIAIPAIPIPNGPCOLOLOLOLOLOLOLOCCGCCCGCCCOCOCLGLGCCCGCCCCOLOLOLLOLLOLLGLLOLLOLOCC@@@==/.  ../==@@GLTTTTSTTTTSTVVSVVVVSVVVSVTVSVTSTSTSTVTSTTSTTMTTSTMTOMOLOLLOCOLOLOLLOLOLOLOLOLOLOLOMOOMOLOOCGCOCGLGCGCCGCF@@===@=F@F==@F==F@F@==F=@F==F=====////=/=/=/=/=/===@=@=F@@@@G@G@@@@=@@@@@@C@@@@@@@=@=@==@==@=@=@=@==@@=@@@@=/2/////././..D446466-6q$qqsqsssstsysytytsstyt{y{{{{a}a}feffkffkkkgkglgligiiiiŸ™œœ¥hgdddddddbbbbbbkbdgkgkglij™œ¢ƒƒ¥ƒ‚ƒ‚ƒ˜Ÿƒ™££¤olmmmmooo¦££¢¢££¥nmmmmmmmmlo¤¤š‡……ƒƒƒ……‡‘‘šŸ¤¤¡žŽŽŽ‡Ž‡ŽŽŽ‡‡……‚‚‚‚‚ƒƒ…‡‰›™¤¤¤olololollololl¤i¤¤   ¡š—…¢ƒ˜ƒ¢„™‘‘šš†¡‹–š“…—ƒ‚‚‚ƒƒƒ™‡‘‘šŽ’‘‡…ƒƒ‚‚‚‚‚ƒƒ™‘‘—¡ŸŸ¤Ÿ¤Ÿ¥—œœ¢¥˜¥˜¥¢œ¥okkkfkfkfffffffkfffefefeaaaa{{y`ssssstsstsqtEqEEEEEE?DIE>I>IAI>IAAIAI@G@G@G@G@G@G@G@@G@@@@F@@@F@@@C@C@@C@@@@@@@@@@C@CGC@C@G@@@C@CG@C@@@@===///.  ..//=FCGLOMOMOMMTOTTMTTTTTTTSTTTSTTMTTTTMTTMTMTMTMMOTMOTMOMOMOLOLCOCLGLCLOLOLOLOLOCOLOLOLOLOOLOLOCOCCGCGCCCGCCG@@F@==F====@===@F=@==F======F=====/=/=///=//=///===F=@=@=@F@@@@@@@@@=@@=@@@@@@@@@@======@=@===@=@=@=@=@=@@@@@/=///.//2./2.;5446466q-qqqqsqsrssssystysytyy{~y{{{}a}}feeffkkkmkghggigiiiiiŸ™‘™™™•ji‚¥…˜‚jhhbdbgbgkgkgglij¦œ¢ƒ¥ƒ‚‚‚‚j‚‚ƒ¢…™‘‘™¡¤olooo¤¢£££¢¢££¥oooooolmmmllolo¤¤¡£‘……ƒƒƒƒ……‰‘“— ¤¡¦’’ŽŽ‡Ž‡Ž‡ŽŽ‘‡……ƒƒ‚‚ƒƒ…ˆ‡‰‘¡¤¤olololoi¥¤¥¥¦Ÿ¤¤     ¡ š‘™…ƒƒƒƒƒ™…‰‘“šš‹ ‹š‘‘‰…ƒƒ‚‚ƒƒ¢…™›“ŽŽ‘‘‡‰…ƒ‚‚‚‚‚ƒƒ…™‘“‘‡š™—™™‘™¢ƒ¥˜¥˜¥¢¢hkkkkkfkfkfkekefefffefeeaeaa{`{`ss`sssssstsqtqt6E6EEEE?EEI>I>IIAIIAIAAF@G@@G@@G@@G@@F@F@F@@=@F@@@@@G@G@@@@@@@@@@@@@G@@@C@@@G@@G@@CFC@@@====///.   .../==GCOMOMTOTOMTTMTTTTTSTTTSTTTTTTMTTTTMTTMTMTMOTMTMTOMTMOMOLLOLCOCLOCLLCLLLGLCLGLLOLOLOLOLOLOLGCGCCGCGCGCG@CF@=F=====F==@F=F=@=======F=======/=///////////=/=F==@====F@=@F@G@F@=@@=@@@=@@@@@=@==========@=@=@=@===@=@@@@G/2///./././.;5.6466-6$qqqqqsqsssssyys{sysyt{y{y{{}{}aeeffkkkkkkllgligiigii¤„‘™™‡—™œˆjiggkggglglgiiŸœ™ƒƒƒ‚‚j‚j‚‚‚‚ƒ……‰‘‘— ¤¤¤¤¥¢£££¢¢£££¦ ¤¤¤¦¢¥oolool¤¤¤¤¡‘‡…„ƒƒ……‡‘›¡¤¤ —›“Ž‡‡‡Ž““‘‰‡……ƒƒƒƒ……‡‡£“£¤¤o¤llo¤¥¢¢££“‘›¡¡  ¡ ¡ ¡š›‘‰™—¢ƒƒ¢ƒ™‡“‘š‹‹¡†›‘™„ƒƒ‚ƒƒƒ…‡“›Ž’“‡…ƒƒ‚‚‚‚‚‚ƒ……‰‘“‘“‘“‘‘‘™…¢ƒ¢ƒ¢¢ƒœ£¥olkkkkkfkfkeffeffekefeeeaeaaay{`ysssssstststqt6tEEEEuEv?I?IIAIAIAIAIAI@G@GG@GG@GG@G@@@@G@@G@@@@@GCG@GCG@GC@G@@@G@CG@CCG@GCG@GC@GCGC@G======///.. ...//=@GLOTOMMOTMOTTTTTSTTTTTTTSTTSTTTTSTTTMTMOMOTMOMTMMOTMOMOLOLOLLGLCOCOLGLGCOCOCOCLOLOLOLOLOCGLCGCGCCG@CG@G@G=F===/=============/=/====@@F@===//////////=/====@=F=====@=@@@@=@@=@=@@=@@=@@@@==============@=@===@==@=@@@@=/=2//////.2;5;44646-6-6qqqqsqstssys{syyys{y{{{{{a}aeeffkfkkkmlkhlghiiiiii•™‘£‡™‘‘‘‘‰™™‰œ‘ƒjigglggiiiij—‰¢ƒ‚Ÿ‚j‚jjjj‚‚‚ƒ…™›“›¡¡ ¦¦£££™£š£ž£¡¡¡¦££”¢¤o¤o¤¤¤¤¤ ¡›‘‰‡……ƒƒ………Ž“£¡¤¤¤¦›“Ž‡Ž‡‡‡Ž“‘“‰‡………„……‡‰‰›‘—¦¤¤lo¤¤™žžž‘ž‘£ž‘š¡¡ ¡¡ ¡–¡›‘—…ƒ¢ƒƒ—…™‡›”’š‹‹‹š‘‘……ƒ˜ƒƒƒ…™‡‘ž››“‡…ƒƒ‚‚‚‚‚‚‚ƒƒ……‡‰‰‰‰™…—ƒ…¢ƒ¢…¢™£Ÿolllmkmkkkfkfkffkefefeeaaaa{y{ytsttttttttttEtvqvuvuvw?wIBIPIPPPAPPPPPPGOCOLOOLOOLOLOOOCOLOCOOLOLOLMOLMOLOLOLOLOLOLLOLOLOLOLOLOOLOLOLC@@======///.   ( /.///==GCMTTTTVTTVVSVVVVVVVVVVVVVVVVVVVSVTVSVTTTTSTMTTMOTMOMOMLOLOLGLGLGLCCLCLCLGCCLCGLCOCOCOCOCOCGCCGCG@CG@CG@@@====/=2=======F==/==/==F@F@F@@F=//=///.//////==F==F========F@@@@=@=@=@=@=@=@@=@@=====/=/=======@=@====@==@@@=2=/////////D;5;46665656E6EqEqtqtttstyts~ty~y{{{}{}}efeffkfkkkkllgliiiiiii¤•‘‰‡‰™£‘‘™™‡™™…™‰‘‘—Ÿiiiiiiii¤¦™ƒƒ‚‚j‚jjjjjj‚‚ƒƒ…‰‘“šš¡Œ‘ž£™™š™£›‘›ššš›ž£ž£¦¤¤¤o¤¤¤¤¡¡›‘‡…ƒ…ƒ……‡“™¤¤ ¤¦›“Ž‡‡‡‰‡‘““‘‰‡‡‡ˆ‡…‰‡Ž›“£¦¤¤o¤¤¤¡›ž£›£š››ž£¡¡¡ ‹ š ¡š“‰™—ƒƒ—˜…‡‰››”’š‹‹š›‘‰™„ƒƒ¢„…™‡›“Ž›“‘‡…ƒ‚‚‚‚‚‚‚‚ƒƒƒ„ƒ…—……¢„ƒƒ¢ƒ¢ƒ—˜—™™‘™Ÿ¤iioilllmmkkmfkfkfkefefea}a{{y~tttvt|vttvtvtvuvEw?w?IwPwPPPPPPPPPPPPPOPOMOOMOTOMOOMOLOMOOMOMOOMOMOTMTMTOMTOMOMOMOMOTLMOMOMOTMOMTMOMOC@==///=/=/..    ...///==/=FCOTVVVVVVVVVVYVYYVYVYYVYVVVVVVYVVVVVVVVVVTSTTTTMTTTMTMMMOLLOLLOLOLOLOLOLLOLOCLOLLOLOLOLOCCGCGC@CG@GC@@G=F==//=/=/=2=====/==/=2=F@@@@@F@=/=/////.//.//=/=======/=/=/==@=F@@=F@==@=@==@=@======/==/8=======@==@====@=@@/=/////.////;4.6464-646656Eqqqqqtqssssssstsyyyy{{}a}eefckckkkkkklhlgigiiii•–£‘™™š™‰‰‡™‡™‡™‡‡™‘‘—–¤¤¤¤i¤iŸ‡™ƒ‚‚‚jjjjjhjjj‚‚ƒ…‡›“Žšš’“‡£‡£‡››ž›ŒŒžžž£ž£š¦¤¤¤¤¤¤  ¡›‘‰‡……„ƒ……‰›‘š¤¤¤¤¦›“Ž‡‡‡‡‡‡“‘‘‘›‰‰‡Ž‡Œ›”£¡¤¤o¤¤¤ ¡£ž›š£‡›‘‘š¡ ¡ ¡ ¡¡¡›‘£…™—¢ƒ…™™‡›žžŒ‹‹š›“™…™…„…™…‰Ž›”›Œ‘ž‡……ƒ‚‚‚‚‚‚‚‚‚ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ¢…¢™¦¤¤i¤iliollllmmmkkkfkfefeeeaa}{{t~tttttttvrtEtEEE?EI?IwBIBPwNPPPIPPPPPPPOOOLOOOLOOOLOOLOLOLOOOMOOLOMOLOMOMOLMOOLOLOLOLOOMOLOMOLOMOOLOCG=//(..(.(..     ...////=/==@OMTTTSTVTVVVVVVVVVSVVVVVVVVVSVVVVSVTTSTTMOMOMOMOLOLOOLOLGCCGCCLCLCOCLGCCGCGCGCGCOCCOCLGLCG@GCG@G@G@G@==//=///=2=/=2===/=/===@@F@F@F@==2//////./////=2====/=/////===F=@=@=@=@======@=@==@====/////*=======@=======@F///./...../.4;4464-4-64666q6q6qqtqssssststsysy{y{{}aaefeckkkkkkkdlghliiiii¤•‘‡‰‰‡™š™™‰‡™‰‡™‡‡‰›“—–––   •–£‘™„ƒ‚‚jjjjhjjjjjj‚ƒ……“›šŽž‘Ž‡‡‰‡›‡‘ž›Œžž›››”£¡ ¤¤¤¤¤ ¦¡›‘‡……ƒ……‡‡‘“—¤¤¤¤¦“Ž‡‰‡‡‰‡Ž‘‘£‘“›ŽŽŽŽ‘’”£—¤oo¤¤¤¤ ¡›ž›š‰š‰›ž¡– ¡ ¡  ¡£‘™…™ƒ™—™…™›‘ž›š‹ ‹Ž‘™‡™…™…™‡Ž›“‘›šŒ“‘‡…ƒƒ‚‚‚‚‚‚‚‚‚‚‚‚ƒ‚ƒ‚ƒƒƒ‚ƒƒ¢ƒ™—‰£Ÿ¤i¤l¤ililhlllllkmkkkkfkffeeeaa{{yysstsstsqtq6qEEEEEE?DI?wIIIBIBIBIBIAGAGG@GCGCGCGCGCCG@GCGCCGCCGCGCGCGCGCCGCGCGCGCGCGCCGCGCGCGCGCCGC@@/..        ....//.///==GMOMTMTTTMTTTTTTTTTTMTTTTSTTTTTMTTMTMOTLOMOLMOLOMOLLOLOCCOCLGLGLCLCCCCGCC@C@GCCCOCCOCCGCCG@G@G@@G@=F==/=//////=/==/=2===F@F@=@@@F@==2=////././/.//===/=/=///////====@==@=F@=========@=====/=///*.//======@===@==F@/.//./.././..44646--6-64666q6qqqqsqssssstssyyyy{{{a}eefccckbkdkdlkggggigii•–‡™‡™‡‰‰š™‰‡™‡™‡‰‡‘žŽ–––––––—‘™ƒƒ‚‚jjjjhjhhjjj‚‚ƒ…‡‘“ŽŒ“›Ž™‡™Ž›“›Œžž’›››ž›š¡¤¤¤¤ ¤ ¡›‘‡……………‡‰‘›¦¤¤¤¤¤™žŽŽ‡‡‡‡‰Ž‘‘‡›‘“‘›‘’““™¥¤o¤l¤¤¤  ¡›‘›‡£‡‰™£‘›¡¡¡   ¡ ¡¡‘‘™™—™¢…™™›“›š–¡–¡š‘‡™™…™—™‰‘‘‘šš¡†›“‘‡‡…ƒƒ‚‚‚‚‚‚j‚‚‚‚‚‚‚‚‚‚ƒƒƒ¢ƒ—¢™—¤¤ii¤lioilllllhkmkkkkfkffffeeeaaay{{`ysssssqttEqEEE;?I>I>?DI?w?wIBIBIBPIBGIPCPLOOOMTTTTTSTTTTVTSVTVSVTVSVVVVVVYVYYXYYYVVYVVVVVVVVVVVVVVVVVVVVTVTTMG@F=//..    ./F@GLOOTMTTOTTTTMTTTTTTTTSTVVVVVVYVVVVSVTTVTVTVTVTVTVTTTTTTTTMTTMTMOOOLGCGCGCC@GCCGCC@@@C@@@@@@@@@@@C@@@=============/=/=//////////=///////././/.////.....  . ......... . .. ....././././././////=/=//////.//./////////./////.//=/=///........... .,.4)4.,.4.4)4)44-64-66q6666q66q6q6qqs``___]cbbbbbdbbgbdbgbggggg•‰…¢……™…™‡“‡¡–‡ž‡……™…‡‡“›šŒžž›››››“ž›Œš’“‘›‡‰‡™‡›‘“›‹š‹›“‡……………‡‡‘““““ŽŽ‰‰‡‡‡‡Ž‘ž’›žž›ŽŽŽ‰‡‡………‡‡“£¦ommmmno““›ŽŽŽ›£‘¦nm}}|||z|zzuzw?z??wBzwz~nnnononoooooooonnnkfefeea``p-4*.(.(.(. (...( .( ..(....(...( .(. (...., , ,,,,-,,,,,    . .. ........./././//////2//2/=/==>>F>D?I?I>I>IAF@G@G@GCGGLOLOOOMOMOMOTLTOMOTMOTMOTTMTTTSTTTSTTTMTOTMTTTTTTSTTTTTMTOTMOOGC=//..  /=@GCOLOOOLOMOOLOOMOMOMOMOMOTMTTTSVTTTTTMTMTOTTMTTTMOTTMTOOMOOLOOLOLOCGCG@@@@F@@@@@@@C@@@@==@=@=@@@@=@=@====/=/====/==/=///////.///////////.//.//.//..... .  . ....... ( . .. ../.././././/.//////////////.//././///.//.//.////////=/.......... ...,...,...4...44446464646666666666q6qp``^^__]_bbbbbbbbbgbgbggggh•œ‰¢ƒ…¢……™™‘›—–š‘‘‡‰…‡™‰‡‰“‘Œš’ž’›’žžžž”ž›ŽŽ‡›ž‘‹‹‹‹›“›‡‰™………‰‡Ž’‘ŽŽ‡‡‰‡‰‡ŽŽ“ž›žž’›ŽŽŽ‡‡‡…‡ˆ‡›‘™¥mmfn¥žžŽ›Ž£om}zzzuzuwuw?z?w?w?w?www€~€w~w~z~~}}}aa}a}{aa{a_y_spp-4( (. (....( . (....../.....( ...(. (. . .  ' , , ,   ( ..... ..././././././////=/=/=2=F=F=F@@=F=F@F=@@@@@G@CGCCGCOLOLOLOMOMOMOMOMOOMOTOTOTOTTMTTTTTMTOTOTOTOMTOTTMTTOTOTMOTOLG@F//   .=FCGLOOLOMOOOMOMOOMOMOMOMOTMOTTTTTSTTTTTMTTMTOTTMOTTTOTOTLOOLOLOLOLGCCG@G@@@@@@@@@@@@@@@@=@=@=@=@=@@@=====/==/=/===/==/////.//././/.//././.../(/./..... . . . .... .. . . ......./../././/././/////////.//.///./////.//.//.////=//=.......... ............ ....)4.44)5;46;46;6666646-p`^^_]_]b]bbbbbbbbbbbbgbggj……ƒ¢……¢…‡‘‘‡––‡‘‘‡‡™‡…‡‰Ž›“ŽšŒ”ž›››’’žž’›Ž›Ž›Ž›Ž‘ž›‹‹š‹š“‘‡‡………‡‰ŽŽŽŽŽŽŽ‡‡‰‡Ž‡’žž’”’›ŽŽ‰‡‰‡‡‡‰Ž‘‘£¥m}}n¥”ž›‘¦n}|uzuwuwuw?w?w?w?BBB>ABIAIPIPGAIwIwvvtEqq6qqppqrprpp--...(...( .(....../../..(........( . ( .  . (      . ( .. .(...././././/././////=/====F=@=@F@@@@@@G@F@G@G@GCGCOCOLOMOTMOTTMTTTTTTMTTTTMTTTTTTTTTTTTTTMTOTTTTTTTTTTTTMTTOTMOOOC@=/..   ..=GOLOOMOOTOMOOTOMOTOMOMOTLTTMOTMTTTTTMTTOTMTTMOTTMOTTMTOTOMOOLOLGLCGCC@@F@@@F@@@@@@@@@=@@==@==@=@@=@=====///=//=/=//=/=//.///././././(../.(....../.. (. .  . .( .. ( . . . ..././/././././/.////////.//.//.////.///.//.//./////=//./././............/........//./..;/;.;;.;5;46464--$`^^^]_]b]]b]bbbbbbbbbgbgg˜ˆƒƒ¢……™‘™Ÿ•–—‘™‡‰…‰™‡Žž›šŒžž’›Ž›Ž›Ž››Ž›ŽŽ››’ž›š‹ ‹‹š›ž‡‡™‡‰‡‡ŽŽŽ›ŽŽŽ‰Ž‡Ž‡›Žžžžžž’žž”‘‡‡‰‰‡Ž‡›‘£o}}}}¢”ž’£om}|zzwBxzBBwBwBNwNPNPPLTMMTLLMOMOMLO@A==@=@=@=>=;/;;;;6);./*.//(/./..(/.//////=//=/////././/...(..(......(...(...( ..... (..wD././/.//.//.////=/==F=F@F@@@GCGCGCGOCGOCGLGLGLOLOLOMTTTTVTVVVVVVVVVVVVVVVVYVVYVYYYYYYYVVVVVVVVVVVVVVVVVVVVVVVTVTTOOCF=/..   . ./FCOTTTTTTTTTTSTVTVTTVTTTTTTSTVTVVVTVSVTVTSTTTVTSTVTTTTTTTMTOMOOMOOOLOGCGCG@@@@@@@@@@@@@@@@@@@@@@@@@@=@====////////=///////././././././(.(.....(... .. (  . ... . . . ...././././../././/.//.////.//.////.////././././//////=////////././/.//////.//.///////////////////;/;..44,-$$^^_]]]]b]b]]]b]bbbbbbggjŠ™¢ƒ—˜…œ‘™•¤¤•–‘‡™‡™‡‰‡š“›‹šžž›Ž›Ž›Ž››Ž››››‘ž“›šš¡‹ ¡‹šž‘‰‡‡‰…‡‰ŽŽŽ’’“‘Ž‡‡ŽŽŽ›“ž›’”ž“££‘‡‡‡ŽŽ›ž£n||||~¥£”¦n|€zNxzNxBxNxNxNPPMPMMTMTMMTMTMMMOLC@@@@@@@=@=====/=//=////*//////(//./////=====/=/=//=/////*./././(..(/...(..(...(....(...(Dw..€§x.///////////=/==/==F=@@@G@GCOCOCOLOLOLOLOLOLOMOOMTTTTTSVVYVYVYVYYYXYYXYYYXYYYYYXYY[YXYYYYYYVYVYYYVVVYYYYVYVYVYVTTMOG@=//.      ...///GOTVTVVTVTVVVVVVVVYVVVVVVSVVVVVVVVVVVVVVVVVVTVVVVVVVVVTTVTTTTTTMTMOOLOCGCGCG@G@GCGCGC@C@@C@@@@@@@@@@@@====/////////////(//./*././(/....(...(... ( . . . .  . . .. . . . .../././././.././/.////././/.//.//////.////././/.////////././/.../......./.......././..//..//.///./..... ,,#$^^^^^]]]]]]]]]]]bbbbbbghˆœƒ¢ƒ¢™™Ÿiiii•‰™‡™™‡™‘“šš†šžž’Ž›Ž›ŽŽ›‘’“““““‘šš¡   ¡ ¡š›“‡‰‡‰‡Ž‡ŽŽ“ž“ž‘‡‡ŽŽŽŽ’ž›¡™££¦¥¥£‘£‡Ž‰‡Ž‡›Žž£o}~|€||€}o£¢ozzNzNwBBwNBNNNOLLLMOMMMMMOMLMOLOL@@===========//=/=*////*//(//.*..(..*//////////I€w=//.*..;D.(.(...(.w€€€5.(.( (.. . €§D€§(.//.///////////=/===F@@G@GCGCCGLOCOLGLGLOLOLOLOOMOMTTTTSVVVVVVVXVYYVYVYVYYYYXYYYYYYYYXYYYVVVVVVVVTTTTSVVVVVVTTTOOCCF=/..     ...//=FMTTTTTSTTTTTVTVTVTTSTTTTTTSTTTSVTVTSTVTSTTTTSTTTSTTTTTMOTMTOMOOLOLGCG@@@@@@@@@@@@@@@@@@@@=@@@@@@=@====/////.*/..(/..*..(...(.*..(/.(..(. .(  . ( . . . . . . .. .../././.../...//.//././/./..//././//////.///.//.////=................................./...(..///./.... ##"#^^]]]]]]]]]]]bbbbhƒœ¢‚¢ˆ™jgggiii‰‘™™™™™™‰›‘™¡–¡¡Œ“‘›‰›™š£‘”‘‘£š¦¡¤ ¤ ¤   ¡š“‘š‰Ž‡ŽŽ““’Ž“‘›‡›ŽŽ›‘ž£¦¤¤oool¤¥£‘‡ŽŒ‰ŽŽŽ’o}~||||||~~nm||wBww?w?BIB@@CCCCCCCCLCCCCCCCCCC==///8////*/*./*.*..(.(.(.(.(.. . (. (....(/.(€§€...( E ( E§€~.  .  (€§§§ .§§Iv/./././././////=/=/=====F=@@F@@G@GCG@GCG@GCG@GCGCGLGLOLOMTTTTSTTTTTSTTSTTVSVVVVVVVVVVVTVTSTTTTTTTOOLGCGOLOOOMOCG@F=/...  ..././FOMTTOTTMOTTMTTTMTTOMOLOMOOMOTMOTMTTMOTOMMOTOTMTOMMOMOOMOLOLOCOCCGC@@@@F@=========@===================////./.(./(..(...(..(/..(..*..(..( .  . ( .  . . . . . . .../../../..../././../...././..//.////.////.////.//////........................ ....../......(..../(... """]]]]]]]]bbbjŠ™˜¢Š¢jgggdggi¢™™—¢—™™Ÿ¤ ¤ ¡™ž£—™™™™ž£š¦Ÿ¤¤¤¤¤¤¤¤¤ Ÿ¡›‘Ž™š‰ŽŽ‘ž›š‡‘‘šŽ›’“™¤olmmmmmmo™Ž‡ŽŽŽŽŽž£n}~|||z|zt|~|}}|wBu????IA@@@@CC@CCCLGLCCCCCGCCC==//*///*€w//.*./.(/.(/(..(.(. € ( (wE...v§€x§2(  4 .( 5€0 . (.€5 ( H . 5§§§x.///.///////=/=/==2===F==@F@@F@@G@@@G@G@G@G@GCCCGCGLGLOMOOMOMTMTOTTTMTTTTTTTTTTTTVTTTTVTTTTTTMTTOTLG@G@GCOLGCG@@=//..   ..../2/=FOMTTOTOTOMTTTMTTMOMOMOOLOLOMOMTOTMTTMOTOMTMOMOMOOTOLOLOOLOCOCGCCG@@@F===F====@====@===@======@=====////*..(...(../(..(...(..(...(..(...   ( . . . . . .. . . ........../.../..../....../...../.././///////./////./////................/........... .../.... .(. .( ""]]]]]]bh‚œœœ˜hdbbbbbgh¥Š¢¢¢¢™¢¤¤i¤¤¤¤¡™‘£¢™™™££“™ ¤¤¤¤¤¤¤¤¤¤¤ —žŽ™šž›—¡¡™ž£››‘“¢onmffml¥™ž£ŽŽŽŽŽ“£n~|zzzuwuzwuwwzz?wB??IA8@@@@C@CCCCLCLCCCCGLCCC@=///=/*/w/./*/./€€E..(.(v€ .4 ( 5~v4. (€§H.€  v§§D ( ,v§w. ( .§€ .§.(2H2w§H././///////=/=/======F==@@@F@G@G@GCGCCCGCGCOCGCOCOLOLOOMOTMTTTTTTTSTTTVTSVTVVVVVVVVVVVTVTVTTTTTTTTOOG@@F@@G@@F==/..   ...2///2=@OTTTOMOTOTMTTOTTMOMOOLOOLOOMOMOTOMTOTMOMOOMOMOMOOLOOLOCOCOCOCGCC@G@@=@=============@====@==========///(/(.(..(/.(...(..( ( .( ..(...    . . . . . . . . . ........................./...../././////.////.////.///////...././/.///./...../.....././//...  ]]]]]h˜˜jdbbb]bbbbdjœ˜¥‚¢œœ¥ihliii¤i¤Ÿ™£™¢¦™™™££“£¥¤i¤o¤io¤o¤¤¤¤¡ž££‘‘£Ÿ¤¤¤¦‘£›£‘¢om}}mm¥££‡›ŽŽ’“¢€zzzzwzBwBwNzPwNNPPCCLCCLLLCLLMMTMTMMTMMMTxxP@@=@@===wF/I/==/€>/=///§2€§x...;§€5..(.€€. §w...(..€1(..(wv..(D€v1(......Fx3/////////==/===F=F@FC@CCGCGCCOCOLOLOMOMOMTMMOMTMTMTTTTSTVVVVVVVVVVVYYYYXYYYYYYYYYXYYYYXYYYYYYYYYYYYVVOOGCG@@F@==....            ..///=2==F@GTTTVTTTVTVTVVTSTTTTMOMOMTMTTTTTTVTTTTTTTTTTTTTTMTOMOOLOOLOLOLOLGCGC@@@@=@===@=@@@=@=@@@=@=@========///(.(.(..(..(.. ( .( ... ( .(    . ( . . . . . .. . . . ... .. .. ... . . . .. ..........././/./////./////////.////////////////////////.//././//////....  ]]]ddb]]]]]]]]]chœ˜j¢œ¢¥hklklllilio¤¢££¢¢¦¢¦¢¢££¤olollolllloo¤¤¦¢£££¦ooloo¤£‘££¦o}}}}}}}mmo££›ŽŽ›ž¢€zxzNxBxNxNNPPPLPxxTLLLOLMOMTSTWSTST€xC@@@@@@x€w>===§€===/>§w.///§€3w...(€§§§ ..2/€v/..(...1(........../1/./...(..(/./////=/=/=====@@=C@G@GCGCOLGLGLLOLOMOMTMTTTTTTVTSTTTVTVSVVVVVVVYVYVYXY[Y[Y[[[[[[Y[Y[Y[Y[Y[[Y[Y[Y[Y[YYYYVTOCG@G=F///..         ...//2==F=F@F@OVVVVVVTVVVVVVVVTVTTTTTTTTTTSVTVTVVTVSVTVTSTTVTTTTMOMTOMOMOMOLOMOCGCG@@@@@@@@@@@@@@@@@@@@@@@@@@@@====///*..(..(..(...(..(.. . (.      .. . .. . .. . . . . . . . .. . . . ...../........././//.///////.///////.//....././////......./....../././/.... ]]]]]^]^]d˜¢˜œ˜hdfcckkklkllllh¥œ£¢¢¢¦¢£¢olllllllmlmllllooo¥oonmmmllo¦£¥n}}}~}|~}||}mn¥£££›Ž›ž¥€zNzxzNwzzNNPLLxOCLCx€TOMxSMMx§Zx@@@@@@@=€I§§€F=/*=§€HI>///w§Z€§/.(/w€5.( v€€3w3D ..(.(.........(...( (.(..(.(.*../(..(..(...(//.///=/=====F@@@G@GCGCOCGLGCOLOLOMOMOMTMTMTTTMTTTSVTTVTVSVVVVVVYYYYYXY[YY[YY[YYVVVVTYYYYYYYYYYYYYYYVTOGCF==/// .        ...//2====F=F@OTTTTTTTSTTTSTTTTMTMOOMOMOTOTTTMTTTTTMTOTMTTMOTMOOLOLOOLOLGLOLGCCG@@@F@======@@=@@=@=@==@==@======//*/.(.(.(....(.. (         . ( . . . . . .. . . . . . . . ..../............/.././//./////.////............../..  (.. .....(.././.. ]c˜˜˜jdc___eccckckkckknj¢œ£¢¢¥¢œ¢ommkmkmkmfkmkkkfkkfnfkkkmmloo¦¥ofa}{{{|~}|~|}~}}mo™‘££›o~zzBwBwBB§x9CCA§€PC@@€§KCCOOVZA=======/I§I(//.Iw./(D€15D€2.( . 1E5465EE555vEvvv~w~€~€€~€€~€~€~€~€~vvvvvvEEvDEDD/./.(...(..(/.//////==/======F@@=@@@@@@@@@@C@GCGCOLGLOLOLOLOLOMOMOTLTOMTOMTOTTSVVVVYVYYVYVVVTTOLOCOMTVVVVVVVVVVVTTTOCF=F/...    ..///2=2=/==2@GMTTOTOMOMTOMOMOOLOLOOLOLOLOOOOMOOLOOMOLOOLOOLOLGCGCCCG@GC@CGC@@@@@====================/===/=/=/=//*/..(.(......(          . ( . . . . . . . . . . . . . . ......./.............././///////.///..... ......./...  .. ../..././.... ^dhn_^^^^^^`__e_e_eecfn¥¢œœ¢¢œ¥nfefeee}e}ee}ee}efeeefkkkfffa{{y|y|y||t|~t|y}}fmo¦£ž£o~zwwBz?Bz§9C@P§O@@CO§§ZCCCCLOx§@=====/==F€€/.(///€€E..(....EE55v€v€~€~€~€€€~€~€~€~€€€€€€€€€€€€€€€€€~€~€~€~€~€€€€€€€€€€€€v€E5D;...(/.///=/=======@=@=@@@F@G@@@G@@@G@@CGCGLGCOCOLOLOLOLOMOOMOOMOOMOTOTTTTVTVVVVVVVVTTOC@G@GGOTTTVTTTVTTTTTOGCF=/..     .../2./2/==2==F==FOMOTTOTOOMOMOMOOLOLOLOLOOOLOMOOOMOMOOMOLOLOLOLGLGCGCG@C@CG@C@G@@@@========/=========/===/==/==//8///*..(.( (.( ( .         . . . . . . . . . . . . . . . .. ................ . .././/////./////............../...  ..../........(. ^^^"""#$p^`^``^`_`aeefn¥¢œœ¢oeaay{yy{{{{{aa{aa{a{}aeee}{{{{~ytt|tutu|ut|t|tz|{}mno¦¢£¦zwBzB?BAw§§PCCC§Z€xC@@Cx§TGCLCLO€xF==========8/==v€.*/.E;DDvww€w€€€€€€€€€€~€~w~€~~v~vvsvvsvs5s5v5v55555555555555q5svvvv~v€~€€€€€€€€€€€~€vD//////=/=/=====@=@@F@C@@@G@@@G@CGCGCCLOLOLOLOLOMOOMTOTMTTMOTOTMTTTTVTVVVYVYYVVVVTTGCF@G@GLTVVVVVTVTTTTOOC@F//..   ..//=/2==2==2=2==F@OTMOTOMOLOOMOMOOLOLOLOOLOOOOLOOOOOMOLOOMOLOLOLGCCG@C@G@@@G@@@@@@@@@====/===/=====/==/==/=/=/*=///*/.(.(..(.... (     ( . . . . . .. . . . . . .. .. ..............  ...///////.//.////./.../././///./..  .//.////.//... #$$$p^p`pp`p``aafnn¥of~srrurtrttyytyy|yy|rt|y|{|ru|uutwuw?z?wwzwzwzwzzzz|}}nnonxzPNPNPPT§YLLO\§ZPLLMTZYZ\TMMTMOLOC@@@@@@@@@@@@@GIPI€w€€€€€€€€€€€~wwvvvvv5DD121..1. . . . ......;..4...   . ..1/15DEvw€~€€€€€€€D/./=/=/===@=@G@G@GCGLOLOCOLOLOOLOMMTMTTMTTTSTVTTVTVVVVVVVVVVVVVVVYYYXY[Y[Y[[YYYYVTOOGCGGOMVYYYYYYYYYVVTOOCF=/..      .../=FF@@F@F=F=F@F=@FOTTVTTTTTTTMTTTTMOTOOMOOTMTTOTTMOTMOTMTOTMTOMOOLOLGCGCGCCCGCCGCGC@@@@@=@==@=@=@================///*.(.(.(..( (.       . . . . . . . . ... ... ............  . ././/.////.//./////////////////./.  ./////////./.. '!-$,-,-,)-4-6-qs~a~~q6<<;>>>>>>??I??w???wwu?wzzzz|zBNCCCCLCCCCCCCCCCC@CCCCCCCCGLCCGCOCOCOCPGxx€€€€€€€xxPPPG@F=/*/*./(/.*..(.(.(..( ( .         ( .    ( ( .(..(./.*/////////////=/==/=/=======@=@@@@CCCGCCGCCGLOLOMLMOMOLOLMOOMOMTMTTTSTTTTTVTVTVVVVVVVVTTOMOGCGLG@==2==F@@GCOTTOTOOCGCF=F///.    ..2/F@GCGGCF@F===FF@OOMTTTMOOTOOMOOOOLOOOLOOLOLOOOLOLGLGOLOLOOOLOCCGCG@@@@@@@@@@@@@=@@=@======/=/8/=/=//8///=*=///8//(/(.(.(..(.             . . . . . . . ...1..... ... ......  ......././././///.............. .. ....   ..(.    ( (,(4).;);.;;);;;;;;;;);;);;;;;;;+;;+;/>;==>=>>>=>>>E>?E???w???BBBBBN@CCCCCCCCCCC@C@@C@@@C@CCGCCCCLCLCGPxxx€€€€€xIII@=@=@F====*///(/(.*..(.(.(. ( (. ( (   ( ( (        (..( .(..(//////////////=//=/==/========@@=@@C@GCCCGCCCCOCOLOLOLOLOLOLOLOMOOTMTTTTTMTTTTTSTTTTTTMOOLGG@G@G@G@F=//2//F=F@GGOCOGCFF===//...      ./2=F@GGGGG@@FF=@@GLOTOTMTOTOMOOMOOMOOLGLOGLOOLOLOOLOGLCGLGLGLOCOCCGC@@@@@@@=@@@@@@=@======/=//=/8/=/=//*=////=*///*/(/((.( (..(           . . . . . 1 . 0..1...... .. . . .. . .. ....../././////............... .......    .    ( (.(..(.;(;./;.;.;.;.;(;/.;*;/)//+//*======8==>>>>>>?>???I??IAAPGCCCCCCCCCLCLCCCCCC@C@CCCCGCLCLCOLPxx€x€xxxxPG@@=@==@@@=@====///*/*//*///*/.(.(.( .. (    ..        (. (....(../.*//////=/=/=/==/==============@@@@@G@CGLCOCOLLMLOMOLMOMOLOLOMOMOTTTTTTSTVTVTVTVVVTTTTOOOCGGCGG@G@GG@F/////2=F@G@G@FF==2/2/....  ../=F@FCGGCGG@@F@GGOMOTTOTTMOTOMOOMOOLOOCOLGOLOOLGLOGLGCGCCOCGLCLGCCC@G@@@@@@=@=@@@@=@======/=/8/=//=*=////8/=//=/*/*.(.(.( (.(         . . . .. . . .0. . . . ......1.. . . . . . . ...........//.//.//.././././/......././../..      .(.((.*/**////*/*=*/*=/8>=*====8=8@@9=@@@CCCCC@ACAAGNGAPCPLLOMMMMLMMMLMMMLTLMLLLLLLOLLOLOMMOMTxZ€Z€ZxZTTTTMOLCCC@CCCCC@C@@@=@======@=@==@===////*./(.(.(.(.(.(..*.(..( ( .      ..(.(..(.(.(././/*//=/=//=/=========@=@=@@@@@CGCGLLOLMOMTMTSTTVSTSVTUTSTVTSTVTVSVVVVVYVYYVYVYYYVVVTTTOMOOOOOLOOOOLOG@F=2/=/=F@FG@F@==2//./.....    .../........../2=F@GGGCOOGGGLGOTTTVTTTTTTTTTTTTTMOOOMOOOMOOTOMOOMOOOLOOLOLOLOLOLOLGCCG@C@@@C@@C@@@@@@@===========/=====/=/=/=/=*//*.(.((.....             ... ... . . . . . . 1 1.1.1... . . . . .. ...........//.//////////////////.////.//////..    .((.(((.(*.*//*=8==8=/8==8====8=8=@@9@@@@C@CCCCCCCCLCLCCLLLLLLMMTMMTMMTMMTMTMTSMTMTMOMOMOMMMTMTWx€\€ZxYVTTSTTMTMOLCCCCCCCCCC@C@=@@@@@@@@C@@@@@@====///*/./*..(.(./*./.(.(.( (..(.( ( ( ( (..(///*/.*//.*/.////=*============@=@@@@@@C@@CGCCCOLOLMTMTTSTTVVSVVVYVVVVVVVVVVSVVYVYXYYXYYXYVVVTSTTMOOMOOOMOTOOMOOTOTOOCF==F/F==F=F@=2=2..........     ../1//2=2/2//./2/=F=FCGGGOLOOOOOMTTVVTVVVTVTVTVTVTTTTTTMTOTTTMTTTTOTMOOMOOMOMOMOMOMOLOLCOCCCCCGCCGCG@@@C@@@@@@=@=================/=/*/.(.(.(.(.(...           . ... ... . . . . . . .....0.. . . . . .............././/././/././/.///./....././../////..      ((.((.**/(/*/*/*/*/=8=8==*=8=8=8=9@@9@@@CCCCC@CCCCCLCLLLLMLMLMOMLMOMLMMMMOMMOMLOLLLOLTxx€Z€ZxUTSTMTMMMTMMOLCCCC@CC@@@@@@=@=@@@@C@@@@@@@=@===//*..*.(..(.(.(..(.(.(        ..(.(.(.(..(.(..(..(/*/////8/=/=========@@@@@@@C@CCCCCLOLOMMTMMTSTSVVSVVVSVSVTVSVVVVVVVVVVVVVVTTTOMOOOOMOOOMOTTTTTTTTTTOMOGCF===/2=2//2//.... .      .../1////2=/F///=2=F=F@G@GCG@GCOOMTTTTTTTTTTTTTTTTTTMOOOOLOOMOOMOOMOOLOLOLGCOLGLOLOCLCGCC@@@@@@@@@@@@@@=@============/==/=*=//=*//*/*.((.. (           .. .. .. . . 1 .0. 1.1... . . . .... ..............///./.... ........ .... ....../....     ( ( ((.(((/(*/(/*/*/*/*/***/*/*/*=*=*=*=8==8===9=@@@@@@@@CCCL@CCCCCCCCCCCCCLCCCCCCC@CPx€xxxTPMLLNLCCLCOCLGC@@@==@====@==/=============*==8//*.(..( ( (        ..(..(.(.(.(./(../(/.*/=//=/8/=/=========@=@=@@==@@@@@@CCGCGLGLOMOMMTMMMTMTMTMTTMTTTTTTMTTTMOMOCGGCGCGCGLGOMTTTTMTTOTMTOOOCF=F/2///...    ......1/./2==F=2===F=F=F@F=F@F@GGOMTOTOMOOLOMOMOLOOOLOLGCOCGLGOLGOCGCGCCG@C@C@CCCCC@@@@@@@@=@=@===========/==//*///=*//////*///*/*..(.(( (         . .. ... .. . . .. ...0. . . . .............../././/.//............ ... ... ...../.......    (( ((.((.(.*/(/*/*/*/*/*/*/8/8/*=**=*=8=8=8==8@=@@@=9@@CCCCCCCC@CCCCCCCCCCCCCCCC@P€xxxOLCLLCCCGCCOCLCOCCC@=====@===========@=@====/==/=*=//(.(.(.( (          ...(..(.(.(..(/(..(..(.//(//=/*=/==/=/====@=@=@=@@@@=@@=@@@C@GCCCCLCLOLOMOMOMOMOMOTMTTTTMTTTTMTTOMOOCG@@@G@GCOOOTMOTTOTTMOTOMOOOG=F=2/2...  ..1...2//=F=F@FF@F@FF=F=F=F=F@GGOMTOOOOMOOOOOMOOMOOLOCGGLGLGOCOCOCGCGC@C@G@@G@G@C@C@@@@@=@===========/==//=*==/=///*///*////*/*/(/((.((     . .. ... . . .0 . 1. 1. .0. . . . ... ....... ......./././/1//............ .... .. ../..........     (( ((( ((((.**.*(/*/*/**/8*/**/8*/8*=8/=8=8=@=@8@@@@@CCCCCCCCCCCCCCCCCCLCLCLCCGPxxPPGCCCOLGLOCLCOCCOCLCC@=@==@=@@@@=@=@=@@@@@======/8==/*/(..(.(... (      ((. (.(.(.(..(.(.(..(.*.(/.(//*////=*=/===/====@=@@@@@=@@@@@@@@CGCCGLOLOLMMOTMTTMTMTTSTTSVTVTVSTVTTSTTTMOLGGCG@GGLOTTTTTTTTTTTTTTTTTMOG@F==2..   ...././/2=F=GCGGGG@@F@@F===F=F@GGOMOTOOOOOLOOOOMOOOLGOCGCGCGLGCCOCCGCG@G@@@C@@C@C@@@@@@@=@==@=======/==/==/=/*=//=//*/////*//(//(..(.( (        . . ... ... . .1 .. 0. . . ... ..... .........././././2/.//././././/./..../.../../////////.....    ( (.(.(.(*.*//*/*=*==8=8/8=@8=@8@@@@9@@@C@CCCCCCLCLLLLMLMLMLMLLMLMLMMLMTMOMMTxTOMOLMOMMTMMMMMMMMTMMMOCC@@C@CCCCCOCCCLCCCCCCCC@@@@@@@@==/=*/=//(//(.(.(..(.( ( (   .(.(.*..(./(//(/(/./(/*./(..(//(///*/=/====/====@@@@C@CCCCCCCCLLLOLLMOMTMTMTSVVSVVVVYXVVVVYYXYYXYYYXYYYXYYYVVTMOOOLOMTTTVVVVVYVYVYVVVVVVTTTOOG@2/.    .2.2/2/2==FCGGLOOOOOOOGCF@F@F=F@GOTTTTTTTMTTTMTOTOMOOMOOOLOOLOLOLOLCOCGCGCGCCGCCGCCCCC@C@@@@@@@@@=@===@===========/=//=*/=///*/*/*.*.((.        . .. ....   .0 . . . . . . .. ... ...... ......./..//./././/.//.////////.//////////////////////....   (((.((((.((/*.*/*/8/==8====9=@@8@@@@@@9@@CCCCCCLCLLLLLLLMMMMMTMMMMMMMTMTMTSTMTMTTMTMMTMMTMTSTSTTMTTTMTMTMLCCCCCCCOLOMLMOMOLOLLOCCC@@@@@@@@===*===//////*/..(.(.(.(.(.(..((.*/*//*/*//*///*//*///*.//*///*////=/==========@@@@CCLCLGLLOLMOLTMMTMTTSTTSVTVVVVYXYXYYXYXY[Y[Y[[Y[Y[Y[Y[Y[YXYVVTMOOMOOTTTVYYYYYYYYYYYYYVVVTTTTOG==.     ..//2/2=F@@GOOMTTTTTTTOOOGG@F@F@GCTTTTTTTTTTTTTTMTTOTOTOLOMOOMOMOMOMOLLOLGLGLCOLCCOCCCCCCCCC@@@@C@@@@@@@@@=@@=@==========/=/=///*//*/(.(.((         . ... .   .0 . 0. . . .. ...... ............././/./2/./2/././././../.../..../../////////......   .(.((((.*.*/*/*/*=8=8=8==8=8@=9@@9@@C@CCCCCLCLLLLOLLMLMLMOLLMLOMLMMMMMMMOMOMOMOLMOSTTMMMMMOMMMMOCC@@@@CCCLLOLOLLOLLLCGCC@C@@@@@@==/*/=/*//=/*//(.*.(.(...(. ( ..(.((/.(.(/(/.*./.(.(..*.(.(./.*/*//*/=/8========@@@CCCGLCLCLOLOLOLOMMOSTMTTSTSVVVVVVVVVVVVVVVXYVYYXYYYXYYYXYVTTTOMOOOLOOMTTTVVVVVVVVVVVVTTTTOOOGG==.   ..2//=2=F=GCGOOOMOTOTMOOOCF@F@FF@GLOTTTTMTTOTMOOOLOOLOLOOGLGLOOLOLGLGCCCCCCGC@CC@CC@C@@@@@@@@@=@==@===========8=/=/8////*//*//*/*.*.(.(( (       . .. .    0. . . ....1..1 ................/.2/.///.///......... .. ..... .(.....(....(... .    ( ( (( (.(((/*/*/*(/**/*8/8/*8/8=*=8=8=8@8@@9@@@@C@CCCC@CCCCCCCCCCCCCCLCOCCLCCCCCGLOLLGLGCCLGCGC@======@@C@CCCGCCC@@@@@@====8==/*/(.(.(.*.(.(.(.( (      (.(.(.(.((.(.(.*.*./(/.(.(./.*./(/.*//8/==*===/=====@=@@@@@C@CCCCCCCCGLOCOLMOLMOLLLOLLOCLCOLCLOOMMTMTTTTVTSTTTOMOLG@@@@@@G@GGOOTMTTTTTTTOTOOOGGCG@F=2/.  ./2./2=F=G@GCGOLGOOOOOOG@F=2==2=@GOOLOOOOLOOLOCOCOCGCG@GCG@CGC@G@C@G@@@@@=@@@@@=@@@=@===========/8/=*=/=/8///*//*///*//(/.(/.(/(.(.(.      . . .    . . .....1........ ............./././//.2//2/......... . (..... ..(/.....(.. ( .  .(.(.(((.((.(/(**(/*/8/8/*=*=8=8*=8==8=@8@=@@@@C@9C@CCCCC@CC@@CCCCCLCCCCCCCCGCLCLCLCLCOCCCCCC@======@@CCGC@CCC@@C@C@@@@======*/(.*.((..(.(..(.( (.   (.(..(.((.( ((.(.*.*.(.(.*.(..*./*.*/*//8//*/(/*./*/====@@@@@@C@C@C@CCCCCLLOCLOCCGC@C@@@@@@@@@G@CGCGCGLOLOLOOLOCGC@@F@F@F@FCFCGLOOOTMOTOMOOGGCG@GF==F//..  .//2===@G@GGCGGLGOGOOOOO@F==2==2@GLOOOOOLOOCOGCGGCG@C@G@CG@C@G@@G@@@@@@@@@=@@@@=@=@========8/===*=/=*=/=/=//*/*/.*/.*./(/(.*.(/(.(.(      ..     ..1......1...1..1............./.2.2//.2//....... . (. .( ..( ...(../..( (     . ( (.(((.(*((.*.***/*8/*/8=*=8=8=8==9@=@9@@@C@C@C@CCCCCCCCCCC@CCCCCLCLCOCCCCCOLOLOCOLCOLGLC@====8=@@CCCCCCCCC@CC@@@@@=@=====*.*(.(.((/(.(.(.( ( (    .(.(.(.((.(.( (.(/(/(.(/(..(/.*./.*//(/*/(.(.(..(.((.(/*==@@@@CC@CGCCGCLOCLOLO@GC@@@@@@@@@@@@G@C@GC@GCGCOCOLOLGLCG@G@@F@@@G@GGOOMTTTTTTTTOOCG@F@F@F==2//.  2//F=F@GGCGCGCGOGGOGOOOOCFF=2==2@GOOLOOOLOOCGLGCG@G@G@F@G@G@@@G@@@@@@=@@@@=@=@=@=======8/===*==/8///*/*///=/*.*./(./*...*.(/(.*.(( (      .      . ......1...... . ............/.././/.2///2/////...........(...///////...    ( (( ((.((.*.**(*/8/8=8=8=8@@@9@@@C@CCCCCCCLLLLLLLLLLMLMMLMLLLMLLMLMOMMMMTMMTLMTMMMTMMMMTMLL@C@@CCCLMOMOLOMOLOLOLLOLCCCCCCC@==///*///*/*//*/.*./(..(.(.((..(..*./.*..(.((..(/(/(/.*.*.*./(/(/(/.(.(.(( ((.( ((.(.(/*/==@@CCOLCLOMLOMLOMLOLCCC@C@GCGCGCGCGCCOLOLOLMOMOMOOMOOMOLOCGCGCGGOMOTTTTVVVVVVVTTOOG@FF@=F@F==//..   .F=F@GGCOOOOOOOOOOMOMOTTTOG@F=F=FCOOMOTOTOMOOOLGCGGCGCCGCGCGCGCC@CGC@@@C@@@@C@@@@@@@@===@=====@========8==/=//*/(//(//*//(//*/(/(.(.       . .        . ..1../....1... .. ..............1/1///2/////////./.././//.////////////.     ( (.(.((.((.((/*.**/*=8/88=8=8@@@9@@CC:CCLCCLCLLLLLMLMLMLMMMMMMTMMMMMMMMMTMMTMTMTTMVSTSTMTSTTTMTMLCCCLCMTMTMMMMMOMMMMOMOLOLLOCLCC@===/=*=/*///*//*//*./*/*.(*.(..*///=///*/(.(.(.((.*/.*/*.*//*/*/./*.((.(.((.(.(.(.(.*.*//*===@@@CCCCCCLCGLCCCCGCGCGCCGCCGLOLOLOLOLOLOLOMOMOMOTMTMOMOMGGCOCOLOTTVVVVVYYVVVVVOO@F==F==F==2=2/..  ./F@GCOOOMOTTTOMOTOTOTTTTTTOOG@F@GOMTTTTTTTOTOOMOOLGCGCCGCGCOCGLGCCCGCCCCCCCCCCCCC@@@@@@@@@@@@@@@=========8===//8///*////=*//*//*/.(.(       .        .......1.2... .. ..1.........../..././1///2/=///.......(.....././..////(.    .(.((.(((.*(/**/8*=8=8=8@@8@9@9C@:CCCCCLLLLLLLLLLLMLMLMMMMOLMOLOMOMLMOMMMTMTMTMMTMMMMMOLCCCCLOMLOLOLOLOLOLOLLLLLLLCCCCC@@==/8//*/*/*/*/(/*..*..(.(.(.(.(/.*//(/.(.(( ( (.(.(( ((.(.((    ( ((.((.(.(.(.*//*=/========@=@=@@@@@@@@@@C@CGLCLOLLLOLGLOLOLOLOLOLOOLOLOOLGCGCG@GCOMOTTVTVVVVVTTOO@=2///.//2//....  ./=FCGCGOOOOOOOOOOOOOOOMOTOTOOG@G@GOOOTOMOOOLOLGCGCG@@G@@G@C@CGCCG@C@@@@@@@@@@@@@@@@==========8====8==/=*//*//8/(/.*.(.*.*.*/*/(/((.         . .          . 1.../..... .. ... .. ...........1/1//.2//......... . (...(....(.....    .   ((.(((.((*(/(*/*/*8*8=*=888=8=8@9@9@9C@C@@9CC@CCCCCCCLCCCCCCCCCCCCGLLOLOLLGLGLGCLC@@@@CCCCCCCCC@CCCCCCC@@@@@@@@@@@=/8/*.*.(.((.( (..(( (.(. ( (..(/(/.(.(        ( (..(.(.(.((.((/(//*/.///*=/=====@@@@GCGCLOLMMTOMMOMLOLCGCGCGCG@CGCG@@G@@==@F@F@GCOOOMOTOOTTOO@2//... .. ..  /=F@FCG@GCGOCGGCGCGCGGGGLGOOGG@G@GGLOGGLGCGCGCG@@@F@=F@=@=@=@@=@@@================8=/8/8/=*//*//*//*/(/*/*/*./(.(.(.(.(.(.(.*.(.(        .          . ....1.1.. .. .. ..1... ......./..../.2/./2/./.... . ( .(..(....../.(.     (.(((.(((/(/*((/(**=*/8*8=*=8=9=9=9@@9@C@@:@@C@C@CCCCCCCCCC@CCCCCCCCLGLLOLCCLCLCLGCCCCCCCCC@CC@@C@@C@C@C@C@@@@@@@@@===/*//(/(.(((.( ((.(....(..(./(..(.(  (     .(((/(/*/*///*///=/*///=/8/====@@CCGLOLLOMOMTMTTMTTTMTMTMTMTMOLOCOC@G@@F@=F======F@@G@GOOMOOOOLO@F/...  ./F@@G@GGGCGGCGGGGG@G@G@GGCGOOOGGOGOCOGCOCGCG@G@F@@=F=@F===@=F@@=@==@=======@=======*/=/*/=*//*//*/(/*./(/*/*//(.(.(( (.(.(.(.((         .           . . .. .0..0.. 1................./..2../2././..... ( .. ( ..(...(.......     (.((.(/(*(*/(*(/***/8*=*8888=8@@@9@@9C@C@CC@C@CCCCCCCCCCCCCCCCCCCLCOLOLLLGCOCOCCLCCCCCCCCCCC@C@C@C@CCC@C@C@@@@@@@@==/8//*/.*(.(((.(.(( (( (...(.(.(.(..( ( (    (/*/========@=@=@@@@@CC@@@C@CCLCLLOMLMOMMOMMTMTTMTSTSTSTTTTTSTVTSTTTMOOOLG@@F@F@F@@FGCGOLOOOTOMOOG@/...    ./=F@G@G@GCGGGCGGCGG@GF@F@GGGOGOOOCOGOCGGCGCG@CF@@F=@===@==@==@===@===============8=/8/=/*//*//*/*//(/(/*./(/(/*.((.(( (((.(.(.((                     . . . . 1. 1.....1........./...1/..2./.2//////........(..././/.///.//...   ((.(**(/*/**/*/*=*=8=88@@@9@CCCCLCLLLLLLLLLLLLLLLMLMLMMLMMMMOMOMMTMSVSTMMMMMMMTMMOMMOMMMOLLOLOLOLOLOLOLOLGLCOCLCCCC@@=======*=/*//*/*./(./(.(..(.*./(/.(.(.(..   (/*==@@@@@@@C@@@CCCCCLCLLLMOLLLOMMTMTSTSTVTVSVVVVVVYXVVYVVVVVVVYXYVYXYVVVVVTVVTTTMTTTTTTOTTTTVTVTTVTOO@2/..       .=F@GGCGGLGOOCOOOOOGGGCGG@F@GLOMOTOMOOOOOLOGCGGCG@CF@F@@@@@@@@@@@@@@@===@=@=@@@@@==@====/===*=/8//*///*//*/*//*//*/(.(.(..(.((.( ((                 1 .. . 1......1..../.1...../1/.2.////////./.......////////////.//.(   ( (   (.(**/*/88=8=88=8=8=8=@@9@@:@:CLLLLLLMLMLLMLMLMLMMMMMMMTMTMTMSTMSTMTVVSVSTTTSTTMTMTMTMTSTMMTLMOLOMLMMMOMOMOLLOLOLOLLCC@@@@=8@==8=/8/=*//*=*//*/*///(///(//.(.(..      ((/*==@9@@@CCCCCCCCLCLLLOMOMMTMTMTMTMTSSVSVVSVVVVYXYXYXYYXYXYXYXYXYYXYXYYXYVVVVVVVSVTVTTVTVTTTVTVTVVTVTTOO=/...      . . ./F@GGOLOOGLOOOOOOOOOOGGCG@GGCOOTTTTTTMTOOOLOLGLGCGC@G@G@G@G@G@CC@@@@@@@@@@@@@@@@@@@@=@=========8=/=8/=*/8//*=/8/=/*/.*(/(((.(.(.((.( (                  . 1 .1.../1./....2.../..2../.2/.2.///./....(...(.././//.///...(..  .((.**/*8**/*8/8/8=88=8=9@9C@:CLCLLLLLLLLLLLLLLLLMOMMLMMMMMMMTLTMSSVSTMMMMTMMMOMOMOMMOMTLLOLLLLLOLOLLLLCLCGLCCLCLCCC@@=@==8===*=*///*/*./*.(.(.(./(.*.(.(...    ((/*/*=*=@=@@@@C@CCCCCCCLLLMOLLMMOMMMTMTTSTSVSVVVVXYXYXYXYXYVXYVVVYXYYYYXYVVVVTSVTTTTTTSTTTTTTSTTTTTTTTOMOG@/.    ..//2/==F@GCGCGGCGCGCGLGGCGG@F@@F@@GOCOOOOOLOLGLGGCGC@@G=@@F@@@@@@@@@@@@@=====@=@=@=@======8==/*/8///*//*/*/*/*/*/*/*/*/(*.((( ((.(.(                       . . ...1....../1./...1.....1/./1//...... (.. ( ..(....(./......(   (.(((*/*/***/*/***/*8/8*=88=99=9@9@9@@9@@9C@@@CCCCCCCCCCCLLCLLLOLMOMOLOCOLCGCCCCCCCGLCCCCC@C@C@@C@CC@@C@@@@@@@@@@@@==8/8/*/*.*/(.*/(.*.(.(.(.(.( (. (.( ((    (.*.*.*.*/8/8=8=@=9=@=@@@@@@CCCLCOCLLCOCLLLLOMOMMMTMTTVTVSVVTVTSTSTSTTVSTSTTMTMOMOOMOLOOOOLOOLOLOOOMOOOOLOG@F=/.  ..2==2///=F=F==F@F@F=F@@F@@F@F==2=F=@GCGCG@G@G@@@F@@F@=======F===============/==/8===8=/8//*/*//(/*/*.*.*.*.(/(/(.*.(.(.((.((.                       .0 ..0...1./1.../..1../../1/./1./.2./.... ..(. (.....(./../...( .     (((.**/**/*8*8/8*8/8*8=888=9=9@@9@@@9@C@C9C@@CCCCC@CCCLCCOLCLLLMOLLOLLGLCLCCCC@CCCCCCGC@C@@C@C@C@C@C@@C@@@@C@@C@@===8//8/*//*/*/(/*./((.((..( .(.(.( ((     ..*/(/(*/*/*/8===8=@=@@@@@@@C@C@CCCCLCCCLCCLGLLOMOMOMMTMTSTTSTTMTMTMTMTMTTTMTMOMOOOLOLOOLOLOOLOOCOOOLOOOOOGCG@F=/.  ../=F@@F/2//===F==F=2==F/F==F=F====2==F@G@G@G@G@F@@F@=@F=================/====/==/8/==/8///*//*/*.*./*.*.*.**.*(/(.((*((.((.((                        . 1..1....../..2./../1/./1///1//./...... ...(....(./../......         .(*.***/**/8/8/8*8/888=8@8@9@=9@C@9@@:@@C@CC@CCCCCCCCCOLLLLOMOMMOLLOLLLOCCGCCGCGCCGCCC@CCC@C@@C@CC@C@@C@C@@@C@@@===8=/*/8///*/*/.*/(.(.(.(.( (.( ((.(     .(.*.*.*.*/(/8/=8==@8@@@@@@@C@CCLCLLLOLLLLLCLLLOLLMOMMTMTTVSVTVSTSTTTMTTTTSTTMTTMTOMOLOLOOOOLOOOLOLOOOMOOOLGGCF@F//   ./2@FG@@=/2/2//F/=///2///2/=====2==/=F=F@@G@@F@@@F@=F================/===/=/=/=*=/=*=/=*=/*//*/*./*.*/.*.*.*(.(.*(.(.((*.((.((                       0...1..1..1..1./.2/1/.2//.2/./1/.///./....../././////.///.....     ((/(**/*8=88=8=8=@8@8@@9CC:CCLCLCLLLLLCLLLLLLMLMLLMLMMTMMTMSTSVVSVTSTSTSMOMLOMLOLOMLOLOLOLLOLLOLOLOLOLLOLOLCLLCCCC@@@=@===========*=/=*//*.(.(..(.(.(.(.(      (.(.(/(/(*/*=8==@@@@@CCCCCLLLLMMMMMTMSSTSTMTSTMTSTSTVSVVVXYVXYXYYXYVXVVVVVVVVVVVSVTVTTMOTTTTTTSTTTTTTTTTTTTTOOOCF@F=/   .../F@GLGOGG@F=2=/F/F/==/2=/=/=2=F@F=F==F@FC@GCG@G@CF@@@F@F===@=@@=@==@===============8=====8=/=/=*/=*//8.**/*/*/*.**.*.*.*/(*.(((.                    ..1...1..1.....2./1//1//1//2.//2.//////////./////////=////....          (.( ((*=*=8=88==9=@9@@@9@:CCLCLCLLLLMLLLLLMLLLMLMMMMTMMTMTSSSVSVVVVVVUVVSVVTSMMTMOMTMMTMMOMMOLMLMOMMMOMMLOMLOLLMOLLLCC@@@@@@@@@@=@=========//*//*//(.(.(.(/(.(    ( (.((.(.( ( ((((/(*//*====@@@CCCCLCLMLMMMTMTSTSVSVVVSSVSVSVSVSVVVVXVYXYX[Y[YXYXYXYXYXYXYVVVVVVVSTTTTTSTTVTTVTVTTVTTVTTTOOOCG@=F/.     . ../2@GOOOLOGCG@F=2==2=2==/=2/=/==F@@F@F@F@F@G@GCCGCCGCG@@@F@@@@@@=@@@@@@==@===@======@=@=============8=/8//*/*/*/=*/*/*/*/*//*/(.(((.(                     .1..1...1....1..2./2/.2///1//1///////./.../././//////.//.....    (.(****/*=8=8=8=9@9=9@:C9CCCCCLLLCLLLLCLLLLLOLOLMOMMMMTMTMSTUSSVSVSTSSTMTLOMOMOLOMOLOMOLLOLOLLOLOLLOLLOLLLOLLLLC@@=@=@8=====8===8==8//*=*//(..(.(.(.( ((   ((..(    ((.(*/*/=8==@9@@CCCCCLLLOMLMMTSSTSVSVSVSTSVMSVSVSVVVUYYXYYXYXYXYXYVVVVVVVVVVVSTVTMTOMTTTTTTSTTTTTTTTMTOOOLG@F@==/.   ...//=FCOGGCOGCG@G=2/=2=//2=//////=2=F==F==/=F@=F@@F@@F@@F=========@==============8====8/===8=/8/=8/=*//8.*/*/*/**.*(.*.*.**.*.(((.(                    ...1..1. .1....1.2./2.//2//.2/.2/.....(....(..../../.......        ((.***/***/8*=8=88=8@8@99@@@9@@9@@@9@@@@CC@CC@CCCLCGLLLLLMOMOLOMOMOMOCCLCGCCCCCGCCCCCG@C@C@CCCC@CCC@CC@C@C@C@===*=8==*=*///*/*/*//*/(..(.(.(..(.(  (.(   .(.*/*/*/8/8==8=8@@@@@C@CCCLLLOMMMMTMTMMTMMOMMTMMTMSTSTSVTVVVVVTSTTTMTTMTMTMTOLOOCGGCOLOOLOOOLOOOLOOGLG@F@=2=2...  ..../=@G@@F@F@F@==2//.//.//.//./././/=//=////=/=F==F=====////===/==/=//////*////*////*=/*//*/*//*/*/*.**.(((.((.(.((.((((.((((.(( (                 . 1...1..1..1.1....2.2/1///1///1//./.. (. (...././.../.....( .       ((/(/(**/8*=*=88=8@8@@@9=@@@@9@@@@9@@@@@C@C@@CCCCCCLCLCLLMOLLOMOLMOLLLGCCCCGCGCCCGC@C@C@C@C@C@CC@CCC@CCCCC@@======/8=//=*//*//*/*/.*.*./(..(.(.(.(   ( (( (   ((.(/**/8/=*==8==8@=@@@@C@@CCCCLLLMOMMMMTMMOMMMOMMMTMTMTSTSTSTSTTSTTTMTMOTMTOMOMOCC@@G@GCOCOLOLOOOLGGCGG@@F=F////..  ......2=@GF@@@F@F=F=F==2.///.////.././////////.///=/==/==/=/////=/=/=/=/=/=///*///*////*//*//*/*//*/*/*.*(.(((.(((((.((.(((.(.((.((.                  .. 1...1.......1..1/.//.2/./2.//....( .. .(..././../..... .          (((**.***/8*8=8=8=9=9@@9@@9@@@@9@@@@@C@C@CC@@CCCLCLCLOLLOMLOLLLMOLMOLOLLGCCCGCCGCCGCGCGCG@CC@CCC@C@CCCGC@C@@====8===/8//=*//*/*./*/.*.*..(.(.(.(( (  (    (.((.**/*//8/8=====8@@@9C@CCCCCLLLMMMMTMTSTSTSTMTSTMTTSTSSTSTSVTVSVTSVTTTTSTMTTMOOLGCF@@F@GLOOLOOOLOOOOCG@F@==2///..   . ...../=F@F@F@=F@=F=F===//////////....//////./....///=//=///////////////*////*////*////*//*//*/*/*/(/*/(/((.(((.(.(((.((.((((.(((.               ....1...1.1.1..1...1/1//.2./././/.... ( .///////.//.....            ((.*.**8/8*=8=8=@9@@@CCCCCCCCCLCCCLLCLLLLLLLLLLLMLTMTMMMTSTSTSTSTSTSTSTMTMMTMMMOMLOMLOLOLOLLOLOLLOLOLOLOLMLCC@@@@@@@=@@======8/=/=/=*//////*//*.(.((.       (.((.((.(/*/*==8@@@CCCCCLLLLMLLMMMMTSTSVVUVXYXYXVVVVVVVUVVYVYXYVYXYXYYXYVVVVVVVVSVTTTLG@@F@@GCOTTTTTTTTTTOOCG@F=F==2/..  ..././2///=FCGGCG@CG@G@@G@G@F@F========///.///=////./...//=/////./*///====/=/=*/=/////*/=/=/8///8//=*=/*/*/*/**.*/(*(.(/*/(*.(/(((.(((.(                  . .1..1.......1....../.2./.2.././... ...///////////...  .    ( (   ( ( ((.((.(((.***=*=8=8=@8@9@@CCCLCLLLLLLLLLLLLLLLLLMLMMMOMMTMMTSTSTSVSVVSVSVTVSTSTSVTTSTOTMTMMTMMOMMLTMMTLMOLMLOMMMMOLCCCCCCC@C@@C@@@@@====8======/=/=//8//*//(.   ( (.(.(.*.(*//*/*(.*/(*/*===@@CCCLLLMLMMMMMMTMSTSVUVXXYXYXY[XXYXXXYXYXYXXXYXYXYY[XY[YXYXYVVVVVVVMOO@@F===F@GLTTTTTTVTTTOC@F@==2//...    ...//2//////=FCGCGCGGCGCGCG@G@G@G@F@@F=====/////=////.././..//////.(././=============/============8=/=8==8=*=*//*/*/**/*/**/*/(*/*(/*/*(.((                     . .....1.1.1...1../1../..........  ..//////.....  .          (.((((/**/*8=88=8=8@8@@CCC@CCCCLCCCCLLCLCLLLLOLLLOMMOMOMTMSTSSTSTSTTSTTMTSTMTMTMTLMOLOMOLMOMOLOMLOLLOLLLOLOLL@@@@@@@@@@@@@=@=====8=/==///*////*/*/*.(.((   (.(/(/*/*(/((.(.((.(/*/8@@CCCLCLLLMLLMMLMMTMSSVUVVXYXXYXYXYXYYXYXYXYYYXYXYXYVXYXYYXYVVVVVSVTOL@F===/=/==GCOTTTTTMOOOCF==/2...   . .../////////FCG@G@@G@G@@G@@@@@@F@F==@=====//.///.....(...(.. (. (..(..(////=/*////8////*//*//*//*=*/*/*/*/**/*(/(.*/(*.*.((.((.((.(.((( (               ..1.......1.........1...1....  .(..../...    (   ( (. ( (((((/(**/*8/*8/8=8=9@9@@@9@@@@@9@@9@@@@@C@@CCCCCCCCCLLOLOLOMOMLLOLLOLCOLOLOCOCGCCOCCGCCGCCCG@CG@C@CCCCC@==@==@=8====8===8=/8//*=/*//*.*.*.*./(.(/(.(  (.(/*//=*//*(.( (.(((/*==@8@@@@C@CCCCCCCLCLLOMMMTSSSTSVSVVUVSVVSVVSVSVSTVTSVTVVTVVTSTTMTMTMOLG==///././//=FCOOOOGLG@F=//.  ...........//F==F====F==F=F=======////////.....( . ...     .(/////*/*/.*.*//*//*/(/*/(.*/(.(/(.((.((((((.((.*.((( ((.               ...1.2.1....1...1.. ..... ..   .(/.... .  ( (  (( ( (   ((.((.***/*8/8*8/8=8==@9=@@@C@:@@@@@@@9@C@C@C@@CCGCC@CCLLLLLLOLLOLOLGLCLOLLCOLGLCCGCCGCG@GCCGCCCG@CG@C@CC@====@===@==8============*//*./(/.*./(/(/((.(.( .(//*===8=*/*. (.((/(==8=@@@@9@@@@C@CCCCCCCLLLOMMMTSTSSTSSTSTSSTSTSTSTSTSTTSTSTMTTTTMTMTOMOMO@=//./......//FCGLGOC@@==/..  .. ...........//@F==F================/=//////... (  .......     (.///*./*/./(/(/(/*.*.(.*(.(/(*.*.(/((.(.(((.(((((.((  (                . ..1....1....... .. .. .....   .....(.  .( (  ( (( (   (.((((/(*/8/8=*=8*==8@=@@9@@@@@@@C@@@@@9@C@@@C@CCCCCCCOCOLOLOMOMOMLOLOLOLLOLLOLGLGLOCCGCGCGCCCGCCCG@CC@@@@==@===@======@=@@@@===8==//*/.*.*/.(/(.(/(.(.(  .(/*=====/8/(((.((.((.(/*/8@=@=9@@@CCCCCCCLCLLLLMMMTSSTSSTSVSVVSVSVSVVVSVSVVSVTSVTVTVSTTSTTTTMTMOL@=///.//./////F@GOCG@G==./ .  ..../...../../...../=====F=2===/F=====/==/////////...  ( ../....     .(.//(//(//(.*.*/.*.*.(.((/((.((*.(*.(((.(((.(.(((..                    . ..1..1/..1..1.. . .. 1.. ./..(      ......  (.( ( . ( ((      (((.(((/**/*=8=8=8=8=@=@@@C@CCCCLCLLCLCCLCLLLLMLLMLOMOMMOMMTMTSTSSTSSTTSTMTMTMTTMTMMTMMTOMOMOMTLMOMOLOLOLOLCC@@@@@@@@@@@CCCCCCCCCCC@@@===//////*//*/(/.*.(.( (.(//*=/8/==/*.(.*.(.(/(/**==@@@CCCCLLLMMMMMMSMSSSVSVVXVXYXYXYXYXYXYXYXYXYXYXYXYYXYXYXYYVXYVVVVVVTVTTM@F=/=/=/=/=2==FCOOLGCF==//.  .../=====/////////.///F@FCF@@@F@F@@F@F@@@=@@=====/=/=///...(. .(//=////..  (  .(//////*//*//(/*/*.**/*/(/**/*(*/*(*.(*.((/(*.(.(((.( ( (                    . ...1..1...1. . .. ... .../=/.(     .....(  (.(.(.(.( (.(.(.(.(.( (  ( ((.(((.**/*/8=8=@@@9@C@@CCCCCCLCLLLLLLLLLLLLMMMMMMMTMMTMTTMTMSVSVSVTVVVSVVTSTVSTTSVTTSTTTTMTMTTTTMTTMMTMMOMLOCCC@CCCCC@CCLLLLLMLMLLLCL@C@@=====/=/*////*//*/(.(   (..(//*=====8=/*=/*/*/*/*/*/=@@CCCCCLLLMMTSTSVVSVUVUVUXVXYXYX[X[X[Y[X[Y[[X[YX[Y[Y[XY[YXYYXYYXYVYVVVVVVSTT@====/=2====F=F@GLGCF==//..  .../=F=F@G@==//////////F@G@CGCG@@@G@@G@@@@@@@@==========////....//=/====////.(...(...*/=/=/*//=*///*/*=*//**/**/*/8/8/*=*/**/(**/**.*.*.(.(( (((.(((                  . . . ..1....1.. . ....1......././(.        .( ( (. ( (.( ((  ( (.(((.*(/**/8=8==8@8@@@:@@CCCCCCCCCLCLCLLLLLOLOMOLMMOMLMMTMTMTMTSSTSTVTSTTSTTMTTMTMTMTMMTOMTMOMTOMOMOLMOLLC@@@@@@@@@C@CCLOCLOLGLCCC@C=@==/8///*///*.*.(.((.  (.(.(.*.*/=/*=/*/*/*/*(/*/8=@@@C@CCCLLOMLMTSSTSSSVSVUVUVXYXYXYVXYXYXYXYXYXYXYXYXYYXYXYXYYXYVVVVVSVTSTTTMO@/2=/=//2=/=2====F===/...  ./2=F=@@G@F=///.//////==F@@G@@F@=@F@@F@@==@======/=///=///./...///=//=////.(.(. ( .(/*//*/*.*/*/(/*.**/*/*(**/(*(/**(/*(.((.((.(((.(((. (( (                . . . ..1... 1 . .. ....1.../.(..(.      ...(.(..(..(( (      .((.(((/(*/8*==8=8@@=@@@9@@@@@@C@@@@@@@@C@CC@CCCCCGCGCCLCOCLOLOLOLLOLLOLLLOLOLOLOLOCGCOCOCOCCOCOCOCGCC@@=======@@@CCCCCCCCCC@@@@@====*//*/*/.(/(./(.(.  ( (./*//8/=/8/8/*/*/*.*/=8@@@@@@9@@@CCCLLLLLLOMLMMMMMTSSTSSSTSTSVSVVUVVVVVVTVVSVVVVVVTSTTTSTMTMOTLOLOCLF=//.//././/./.......  .///=F======/..... ..//==2======/=//=//=///=//*//*./(.//(/....(///.//././/..  (  .(.(.(.(.((((.((.(((.(.(((.(((.(((.((((.(((.(((.(. ( (                  . . . . 1 . . ...1...../...(...(    . (  ..(.( (..(.(.( (    .(((.*(*/*/8=8===@9@@@@@@@@C@@@C@@C@@C@C@CCC@CCCCCCCLGLLCOLCOLOLOLLOLOLOLLOLOLOLOLGLGLGCOCOLCOCOCCCC@@@@=@=@=@@C@CC@CCCC@CC@C@=@====/8//*.*/(//(./(.   . ( (.*//8/=/8//*/*/**/*/8@@=@@@=@@9@@@@CCCCLLLLLLLLMLMMMTMMTMTMTMSTSVSVSTSSTVSTTSVSTSTTTTSTMOTLOMOLOCLGCC@/......../......  ..//==2==F===//......///===/====/=///////=/////*./*./.(././/.././//.///.././(.   (./(.(.(.(.(((.((.((((/(((.(*(.(((.(.(.((.(.(((.(( (                     . . . . . .. .....1/2/..(..(..     . (..  .(.(..(.(.(..(..( ( ((  ((.(((.(***/8/=8==@@@@C@@C@@@@C@@C@@@C@C@C@CCCCCCCGCLGLLOCLGLLOLLLOLOLOLLOLLOLLOLOLLGLCLGCLGLGLCCGLGC@@@@@@@@CCCCC@CCCCCCCC@@@@@=======*//*///*//(.(   ..(//=*=/=*/=*/*//*/8=@=@@@9@@@@@@@CCCCLLLLLLLMMMMTMTSMTSSTSSSTSVSVSVVUVVVTSVVVTVVVVSVTTTTSOTMOMOLOLOLOCG/./../././... .  ../2=======F==///.//.=/===2=/=/=/=//////*//*///*./*...(./(//.///.///./.*././..( (.((.(((((.(((.(*.(/((.((.(.((.(((.(((.(.(((.(((.( ((                 . . ...1./////..(/.////(     (. (. (   ( (..(.(..(.(( ((.( ((.(.(.(.( (( (.((/*/*/*/8=8==@@@@CCCCLCLCLCCCLCCLLLLLLLLLLMLMOMMMMOMSTMMTMTTMTTMTTSTSTTSVTSTVSTTTTMTMTMOTMTMTMOMMLOLLLLLCLLLLLLLLLLLLLLGCCCC@C@CC@@@@@====/=///(.   ( (  (./*/8/=*=/=*/8/=*/*==@@@C@C@CCCCCCLLLMLMMTSTSVSVUVUVXYXVXVVXYXYXYXYXYXYXYXYYXYXYXYXYYXYVVVVVVSVTTTTTMTTMOL=/////////....  .//=F=@F@@G@@G@@=====@F@F@@=@@=@@=======/==/=====/==/=/////////=//=///////////(.  (.(*.*.(/(.*.*(/(*(*.*(/((((/(.*.((.((.(((.*.(/*/(/.((..(                       . .. ...2/2////////=/=/.     .( .(. .   .(.(..(...((.(.(.(..(.(.*.(.*.*.(.*.(/(*/*/*/*/8====@@@CCCLCLLLOLMOLOLLOLOMLMLMLLMOMTMTMTMTSTSTTTSTSTVTSVTVSVVTVVSVVVVVVVVTSTTTTSTTTTTMTTMTMMTMOSTMMTMMMOMMOMOMOLLLCCLCLCCLCCCC@@@@==//(.    .( ( (.(///=*/=/==8===*==8==@C@CCCLCLCLLLLLMLMMTMTSVUVUVUXYXXYXYXYXYXYXYXYXY[X[Y[X[Y[X[Y[YYXYXYYXYVVVVVTVSTVTTSTTTOL@=////////...   ..//=@F@@F@CGCCGCG@G@G@G@@@@@F@@@=@@=@=================/=///==/====/==////=/=/=//.(   (/(/*/**//**/***/***/***/**(*/(*/*.*.(/(/*/*/*///*/*.(.(.((.                . . ..1..2/2=2/.(..*//////.    ( ..( .(. ...( .(.*.(.(.(.(.(.((..(.(.(.(.(/(.(.(.(/(.*/*/*/8/=8=@@@CCCCCCLOLCOCLCLGLLLLLLLLLMOMLMOMMTMTMTMTMTTMTMTTSTTTTSTSTVSVVVSTTSTTMTMOTMMTOMMOMLTMOMMOMOMLOMOLMOLLLLCLC@CCCCCLCCCC@@@==/*/(       (//*//*//8/=*=//*=*/8=@@C@C@CCCLCLCLLLLOMLMMTSSSVSVUXVXYXXYXYXVVVXVVXYXYYXYYXYXYYXVYXYYYXYVVVSVTVSTTMTMTMTMOMOG=//././...   ...//===F@@F@@FC@G@@G@@@@@F@@==========/==/==/==/=/==/=/////*/////////=//////*////(  ((/*.(*.(((.((.(.*((.((.(.((.((.((((.((.*.(/(/(/(/(.(( (                 . ..////2=/.(..(.//(./.   ( .(..... . (.(.(.(.(./(.((.(.(..((.*.(.(.(.(.(.(.(.(((.((/*/(/*/8=@@=@@@CGCCG@CCCC@CC@CCC@@CCCCCCCCOCLOLOCGLGLGLOLLOOLMOLOMOMOMOMOTMOMOLOCOLGLGCOCGCGLCGLLOLCOLCLLCOCCLCCC@@@@@@CCCCC@@@==/*.(.     (/.//*//*=/*=/8/=*//8=@@@@@@@@@C@@@@C@@CCCCCLLLLMLMMMMTMSTSMTSTMSTMSTSTVUVVVUVVVVSVTSVTSTTTSMOTMMOOLOLOCOCOCOCCG==.. .   ...///=/=/==============/=/=/=////*./*/*.*/*.*/(/.*/(///(././(////*./.(..*././(...(.(((.(( ((((.((( ((.(((.(((.((.(.(.(/*/(/.*/(/.(( (            .              . . .1.2///2( (..(/././.(    .( .(...(.( .( .(..(/.(.(.(.(.(.(.(.(.(.((.((.((.((/(/(..((.*.**/*/*===@@@C@C@CCCC@CC@CCCCG@CC@CCCCCCCLCOLLLCOCGLCLOLOLOMOLLOMOLMOMTMTMOTLOLLOLLGLCOCCCCLGLLLOLLOLCOLOCLOCCCCCC@C@CC@GCC@==/*/(.(( (      (.*////*=/*/=*//8//8==@@@@@@@@C@@CC@C@C@C@@CCCCLCLLLLMLMMMMTMMTMMMMOMMTMSTSVSVTSTVTTSTTSTTTTMTMTOMOMOCGCGCGCGCG@CF=/  .....////=/=/=/==/========/=///////*//(/.*//(/(//(/(/./*././.(./.(/././.*./.(/.///(/(..((.(.((.(.((.((.(((.((.(.(.*(/(.*/.*/(//(/(.(.         ( . .               . ../././//.( .(/./.*./..     . (...(..(....(..(..(/.*.(..(.(.(.(.*.*(.(.(.(.(.*.(.*/(/(.*//(/*/*/8==@@@@@CGCG@GCCCC@CCCCC@CCCCCCCCCGLLOCOCLGLGLOLOLOLLOLOMLLOMMOTMTOMTMOMOLOLLGLCGLGLGLLGLLOLLOLLOLCLCOCLCCCCCC@CC@@==//*/.((.       (.(/.*//=/*/=*//*=/*==8@@@@@@C@@@C@CC@CCCCCCCCCCLLLLMMMMMTMTSTSTSTMTMTMTSTVVVVVVVVVSVVTVTTSTSTTTTMTMMOLLLGCLCGCGCGC@@=/.    . .././//////=/=/==========///=//////*/.(/(/*./*.*.*.(.*./*./././.(/./(//./(..(./(//(.(.(.((.(..(( ((.( ((.(.(.*(.(.(.*.*/(/*/*./(.( (           .  .            . .1....2/./.(./////////*..   ( ........(....(.. (..(./(/(..(.(.(.(./(.*..(.(/((.*/(//*///*//*/=/=8/====@@CCCCCLGLOCOLCLLLOLLLLLOMOMOMMOMMTMMMTMTMTMTTSTVTVSTSVTVSVVVVVVVVVVVTVTTMTMOMOMTMMTMTMMMTMLMOMMOMOMOLOLLOCOCOC@==////*//(.(       (..*///*/=/*//*/*/*=8=@@C@CCC@CLCLLCLLLLLMLLMMMMMMSSTSVSVSVUVUVXVXVUVVUVVXVYXXYXYXYXYYXYXYYYVVVVVVVVTSTTMMOOMOMOMOLOGC=/..     ...///======F==F==@=@@F@@F@@@============/=*/=*=/==/*=///=//8////////////////*./*///*//*.(.((.(.(((.((((.((.((((.(*./*//*/*./(/(//.*/*/*/./(        . . (            ...../1///2//////=/=/=/////(  . ..(..(......(....(...(.//(/./*//(..*//*////*/*//*///*//*=/=8/=/8=========@@C@CCLOLOMLMOMOMOMOMMOMOMMTMTMMTMTMTSTTSTTSTVTVVSVVVTVVVVVVVVVVVVVVXYVVVVSTTTTTTTSTTSTSTTSTTSTSTMTMMMMMMTMLMOLC@====/==//*.(....    ( ( (..*//=/==8=//*/=/*==8@CCCCLCCLLLLLLLMLMLTMMTMMTMSSVSVUVUVUXVXVXYXYXVVUVVUVYXX[Y[Y[Y[YX[YYYXYXYXYXYXVVVTTTTMTOMOMOMOOLOCG=/.   ...///===F=F@====@@@F@@@G@@@@@@@==========8==/===8====*==/8/===/=////=/=/=/=//=//*///=//*=/*  (.(((((((((.(((/(*/*.*/*/*//*///*/*/////=/*=//=*//.( (          ( . .        ....././/////.(/.////*////(/.   .(........(......(...(..(/..*.(.(..*..(/.*./(..*.*.(../*/*/*//*/=/8/===8/====@@@C@CCLOLGLLOLLOLLOLLLOMMOMOMMOMMTMMMTMTTMTSTTVTSTVSVSVVVSVVVVVVVVVVVVVTSTTMTMTMTMTMTSTMMMMOMOMLOMOLOMLOLOL@=/*////*//*.(( .   ( (..(///*//*//*//*/*/*==@@CCCCCCCCCCCCLLLOLLLOMLMMMTMMSSSSVSVSUVSVUVUVSVUSVVUVVVVXYXYXYXYYXYVVYVXVVVVVVVSTTMMOLOLLGLOCCGC@@=/   . .///=======F======@@@@@=@@========/=*=/=/8/*///*/8/=*=//*////*/////*/////*/(//.*/*./*/(/(((  ((.(((.(.((.*.*.*/(/(.*./*.*//*//*////*/(.           . ..               ........2./2.(..(/.(...(...(  ........./././........(../(/..*./(.(/(/(//.*/.*.(/.*.(.(.(./*/*/*.*//*///*/*=====@@@@CGCCCGCCGCCCCCCCCGLCCCCOCLGLCGLGLLLGLOMOMOMOMOMOMMOTMMTMTMTMMTTMMTOLOLOLOLOLMOMOLOLOLLGLCOCLOLLLLLCC@=*/(/(//*/.(.((   ((..(.(.(./*///*//*/=/8//*/*=/8@@@C@C@C@@@@@@@@C@CCCCCCLCLCLLLLLLMMMMMMMMMMMLMMMTMMMTMMTSTVTVSVTVTTVSTTSTTTSTMTMOMOLGCGC@G@@@G@@=F=/.  (..////////////////=/===/=/=//*/.(.(/(/(/(/(*.*.(/(.*.(/(.*./(/(/(..(.(.(../(./(..(.(/((.(. (((((.*(.((.(.*.*.(/(/.*.//(/*/////*.((            ( .                .. ......./..(...(..*../(. (   ......./.../././.../....(./.(/.*./.(//.*.(/.*../(/(/.(./(/(//(/(///=*=/8/=/8/====@=@@C@GCCCCGCCGCCCGCLGCLCGLCLOLCLGLLGLOLOLOMOMOMOMMOTMTMOTMTMTTMTTTTTMTMOLOLLOLOLMOLMOLOLLCCOCLLLLOLLGC@=/*.*/.*//((.( (   .(..(.*./.*///*./*//*//*//8/=*/8==@@C@CCC@C@@@C@C@CC@CCCCCCCLCLCLLLLLLLMLMLOLMOMOMOMOMOMMOMMTMTSTTSTSTTTMTTTMTTTMOMOOLGCGC@@@@@F==F==//.   ..././//////////////=/==/=////(/.(/(.((((.(/((.*.(.(.*.(.*..(./.(.(.(..(.*.(./(.(/.(.*.*(.(( .( (((.*(.*.(/(.*.*.*.*./*//.*//=//*/.(.        . . ..             . ......../.2.( .(...(/.(..(   . .././.././.././././.../..(/.*.*./*.*/./(//(//(///(./(.(/.*///*//*////=*//8/==8=@=@@@CCGCG@CCCGCCGCCCOCCGCCLGLLCGLLGLOCLOLMOMOMOMLOTMMOTMTTMTTTTMTTTSTTMTOMOLOLMOMOMOLLOLLGLLCLOCOLLOCC=/*/*/.*/*/(/(.(( (..(.*./////*////*//*./*//*=/8//*/8/=*=@@@CCCCC@C@C@@C@CCCCCCCCLLLLLLLLMLMLMMMMMMMLMMMMTMTMTSTTMTTSTVSVTVTSTSTTSTTTMTTTMMOLLOCGCG@@@@@@@==//.  ..././/////////////=/=//=////*./(.(.*(.*((/(.*.((*.((.*.*.*..(/(./(./(.(..(.(..(.(/(.(/.(((.(((.((.(/((.(.(.(/(/.*/(//(/*///*///*/.((          (              . . ........././/*.//./.(..(  ....//.//.//./.././/././.(/../././*/./*/.*/./*./*./*///*/.///*//=/============@@@@@@CCGLGLLGLOLLOLLOMMMTMMMMTMMTMMTMTTMTTSTVVTVTVSVVTVVVVVVVVVVVVVVVYVVVVVVTSTSTTSTMTSTSMMMOMOMMOMLMOLC@==/*/=*/=/*.(.(.*.*////////*==/=/=/*//.*//(/*///8/==*/8==8@@C@CCCLCLCCLCLLLLLLLMMMMMMSMSSMSTSVSVSVSVSVSVVSVVVVVVVUVVVVXYXYXYXYVVVVVVVVVVVVTVTTMTMOLLGLGCGC@@@=//.  ...////=/==/=/=//================/=*/*/*//*//*/8/8//*/8///*=/*///*///*/.*/.*./*///*./*/*.*/*.*(.( ((.*(/(/*.*.(/(/(/*./*.*//*///=/*///*..(     . . .              . . .........//////////////(..  . .././/.2/1//.2.././///./..//.*//////=/*//////*//=//////*/==========@=@=@@@@@@@CCCCCOLOLLOMOLOMTOOMMTTMTMTMTSTSTTMTTSTSVTVVVVVVVVVVVVXYYXYXYXYYXYXYYXYXYXYVVVSVVSVVSVSVTSTSTTSMTMTMMMLC========8//*//*//===================//*///*///8===8===8===@@CCLCLLLLLLLLMLLMLMMMMMMSTSSTUVSVUVUVXVUVXVUVUVYXVXYXYXYXYXYYXYYXYYXYXVVVVVVVVVVVVSTTTMTOLOLGLCGCG=@//  ...///=/================@=@=@======*==/=*/8=/8/=8=/8=*=/8/=8/==8/=//*//*=////*//*//*//*//*//**/**** (*.*/*/*//*/(/*///8///*//=*==/===////*.(     .           . ........2/1/.(/./.*.//.(..(   ....//2.//2/.2/././//./.././././///*///*//*//*/.//*////*////*///=*==========@=@@@@@@C@CCOLOCOLOOLOLOOMMOMOMTMMTMMMTMTTSTTSTVVSVSVTVSVVVVVVVYVYXYYXYYXYYYYVVVSVTSTTSTTSTMTMTMMMTMMOMOLC=@==8=/==*//*.(/*===8======/========*////*/(/*/=*=/=8=*=/8/8=@@CCCCCCLCLLLCLLLLLOMLMMMMMTSMSVSVSVUVSVUSVSSVUVSVVUVVVVVVVVXYXYXYYVVVSVTSVSVVSVTSTTMOMOLOCGCG@@@===/.   (.././/////=//////=/=========/=/=/8/**//*/*/*/*/*/*=*/8/*//*/*//*//*/*/*/*./(/(.*./*.*.*/(.*/(.(.((((.((.(.((.((.(*/*.*/*/*/*////*/=//*/.(.(       (              . . ..........(..(..(..(..  ..//./2/2/2/.2/././//././/././//////*////*/./*.//./*//.*//*//*/./*//===/=*===8====@=@@C@C@C@GCCGCGCGCGCGLGLGLLOCOLOLOLOLMOMTOMOMTMOMTMTTMTSTTTSTVTVTVSVSTTTMMTOMOMOMMOMMOLOLOLOLLCC@===*//*//*/*.(/*/==========/===/==/8//=/*/*/*//*/=8=/8=/8/8==@9@CCCCCCCCCCCC@CC@CCCCCCLCLCLLLMLMMMLMMLMMLMMMMOMMTMTMTSTSTTTTTSTTSTMTMMOMOMOMOTMOMOLOCCG@@@=====///.  0111110  (..././*/.//*//./*./(/.*/*/.*(.(.(.(((((.((.((.((.(.((.((.(.(/(/(.(.(.(.(.(.(.((.(.(.(.((.((.((.((.((*(.((.(((.*.*/(//*./*//=///*=///(..    . (                    .. . .......(..(...(. (  ..2/2/2//2/2/./2.2/2/./////.//////////*////*///.*///.////*//.*//*/=/=/=*=/=/======@@@@@G@GCGCGCCGCCCOCLCCOLCOLLGLOLLLOLOMTOMOMOMOMOMTMTTTTTMTTVSTVTVTVTTTSTTTMMMOMMTMMOMOMOLLLLCC@@==*/=*==*//*.(//=8==@=@==@====/=====/==//*//*//*=//=*=8/8=*=/8@@CCCCCCCCCCCCCCCCCCCCCCCCCLCLCLLLCLLLLLMOLMOLOMMOMMTMTTMTOTMTMTTTTMTMOMOLOLOLOMOMOLOLCGC@@@=@==/=/...  013FHHHHHH3310  (..././.*/../.*.///(//.*/(/.*(.((((.(.(((.((((.((*(/(((.((/(.(/(/.*.(.((.(.(.(.(..(.(*((.(((.((((.(.((*.((/(.*.*/*/*//*/=//*=////*..(.        .                     . ... .......(./(..(...(.  .//.2/2//2/2/1//.///1///////.////////*//////////////*///////*.///*=/===/=/======@=@@@@CC@G@CCG@CGCGCGCGLCOLLLGLLLOLOLMTOMTMTOMTMMTMTTMTTSTTTSTTVTSVTVTSTTTSTMOMTMMOMOMOLLLCGCC@@====/8=/=/8//(/*/===@@@@@@@======/=/=/==/8/=*//*//*=/8/=8/=*=8=@@CC@CCCCCCCCCCCCCCCCCCCCLCLCCLCLLLMLMLMLMMLMOMMMTMTOTTTTTTSTTTTTTTTTTTMOMOLLOLOLOLOLOLOCGC@@@====///...  12HHRRRRRRRRRRHH310 ....(././(/..//(/(/.*./(/*.*.((/(.(( ((.((.((.(.(.(/((*.((.(/(/(.(/(.(/(.(.((.(((((.(((.(((.(((  (((*.(((/(.*.*.*//*///*//=//=*///*.(.      ..                       . .. ......//*././//(...   ..2//2=2//2/2/2.2/2///2//////.//*//=///=/////*/////////=/==/=/=/====@==@=@==@@@@@@C@CCGLGLGLOLOOLOLOMOMOTMTMTMTMTTSTVTVVVVVTVVSVVVVVVVVVVVYVVYXYYYXYYXYYXVVVVVTSTVTMTMLOLOCCC@@@@========8//*//==@@@@@@C@@@@@=========/==/8/=*//8//*/8/=*==8==@@C@CCCCLCLCLLLLLMLMLLMLMMMLMLMMMMSSSSSVSVSVSTSTVSVVVVVVVVYVYYYYYYYYYVVVSVTMMOLTMTTMTTMTMOLOCGC@@@===//....12HHRRHHHHHHHHHHRRRH310  ..///////////*///=///*=//*=//*/*/*/*/*/*/*.*/(**/**/*/*/*/*/*/(/*///*/*.*.(.*.(.(.(.((.(/(*.(((.(.((.((( /(((/(.*.*(/*/(/*//////*//=///*//.((                          . . . .... ...//=///*///...(    ./2//2=2//2///2.///2//2/////////==///=/=====/==/========@=======@@@@@@@@@@@@@C@CCCCOLOLLOMOMOOMOTMTOTTTTTSVTTSTVSVVVVVVXVVVVVVVVXYXYXYXYXYXYXYY[X[Y[YXYYXYXYXVVVTSOMOLLCLCCC@C@@C@@@=@@===8==@=C@CCCLCLLCC@@@=======8========8=/8==8===@=@@9@CCLCLCLLLLLMLMLMMMMMMMMMMMMLMMMSTSSTSVVUVVUVVVVUVVVVYYYYYYYYYYZ[Z[Z[YYVVVVTTMMOOLTTTMTTMTMOLOCG@@@@==////2FHHRRH3H33333233HHHHRRH320 ..///=//=/===//*==/===/*=/=*=/8//*/*/*/*/*/***/*/*/*=/8=/=*/*/*=//8/8///*/*/*.*/(((.((.**(/**/**/((.(.*((.(.(  (.*/*.**/*/*//=*=//*=/=/===/=/=/*//.(            .        ... .. .........//*/./.*..(.     ...2.2=/22=2/2/2/2/2//2//////././////////=////=//=//=/=======/=/====@=@===@=@@@=@@@@@CCCGCGLOLOLOLOMOMOOMMTMTMTTMTTVTVSVVVVVVVVVVVVVVYVYYYYXYYYXYYYYXYYXYYYYXVVTSTLLCC@@C@@@@@@@=@@=@=@=8/=8/==@@=@@CCCCCCC@@==@===8====8==*==/*=/*/8/==8===@@@CCCCCCCCCLLCLLOLOLOMLMLLLLLCLLLMMTMSTSTSSVSVSSVTVSVVVYYYYZY\Z\Z\Z\Z[YYVVTSTTMOCCGCCOMOMOMOCGC@@@@===//2/2FHRRH333232232323233HHHRRH31  (..(.//*///////*///*//*/*.*//*/**/*/*/*.*/*/(*(/***/(/**/*/*/*/(/*/*/*/*/.(/((.((.((((.(((.((/(((/(((.(.(((  ((.*.*/*/*/*//*///*////*=//8///*..(             .               . . . .......*.(..(...(    (..2./2/2=22=2/2//2//2//2//1///.//////////=/=/=/=///=////=/=///=//8/======/===/=======@=@@@CGCG@GCGCOCGCGCOCOLGLLOMOLMOTMTMMTMMMTMTSTTSTTSTSTVSTVVVVVVTVVVSVSTTSMOC@@=@@=@=@=====@8=====/=/8/===@@@@CCCCC@@@@====8==/=/8=/=8=/=8=*===/8====8==@CCCCCCCCCCCCLCCLCLCLCC@CC@@8@@CCCLCLLLLLMOMMOMTMOTTTTVWYZZZ\Z\ZZZZZ\ZZTTTMOOLOC@====@GCGCGC@@====////./.2FHRHH3221323223223232333HHRHH10  .(..(..(.(.*..(.(.(/(.(.(((.(((.((.((((.(( (((.((((.*.((((.(.(.(.((.(((.(  .(((.(((.((( ((( .(( (.((.(*/(/*/(/*/*////=//*////*///(.          .               . . .. ......(..(..(..    . ..///2/2=2/2=2//2/=2//2/////.///.///////=///=/=/=////=/==/==/=///=/==/==/=/====/=====@=@=@@C@C@GCGCGCGCGLGLOLOLOLOLMOMOMTMOTMOTMTMTMTTTSTTTTSTVTVSVTVSVTVSVTVSTTLC@@@@=@=@===@=@=@=======8=====@=@@CCCGCCC@@=@@=@===8==/8==/8==/==8=====8===@@@CCCCCCCCCCLCCCCLCCLCCC@@9==@8@@CCCCCCLCOLOLOMOOTTTTWYZZZZ\ZZZZZZYZYZZZYTOTOLOLC@==//===@@@@@===///./...2FHRHH3232323333F33333323333HHHH30  ..( .( .(/./(./(.(.*(.(.(.((.((.(((.(( (( (.(((.((.(.(((.*.((.((.(*.(*(.( (((( (((.(((.((( (.(( .(. ((.*.*(//*/*//////*//=//=*=////*..       (  .              . . ...... ..*..(/.(.   .../.2/2//2=2=2/2/2/2/2/2/2/2///.//./////////=//=/=/=/=//=/==/==/=/=/====/==/======/=====@@=@@@G@GCCGCGCCGCOCOLOCOLOLOMOMTOTMTMTMTMTMTTMTTTTSTVTSVTVTVSVTVVSVVVVSTLG@@@=@==@=@@=@=@=@=@=========@@@@@CGLGLCG@@@@@@=@=@===8=/=8==========8==/===@CCCCCLCCCLCCCCLCCCLCCCC@@@8=9=@:CCLCLLLLOLMOTMTTTWYZZZZZ\ZZZZYZYYWYWYZZZZVTOMOLOCC@==///===@@@====///..2.FHRHHF3F33F3H3HH3HHH3H33322323HHH31.(..(. (..(..(/(..(.(.(.(.(((.(((.(((.(( ((( ((.(.(.(((.*(((.*((.((((.(((.(( ( ((.((.((.(.((.((.(( ((.(   ((.*.*/*.*//*//=/=/*//////8////(.(      . . (               . . . ......./(//...(..  ...//2//2/=2/2=2=2/=2=/2//2//2//././///////=///=/=/=====/=============@=@@=@@=@@@@=@@@@@@@C@CGCCCOLOLOMOOTOTTTTTTTTSVTTVTVVVVVVVVVVVVVVYVVVXYYVYYXYYXYYX[YXYXYXYXVOLCCC@C@@@@@C@@@@@@@@@@==@=@@@@G@GCOLOLGCC@@@@@@@@@@=@======8====@=====8===@@CCLLLLLLLCLCCLCCLLLLLLLCCC@CCCCLMMMMMTSTSTTTVVYYZYZ\Z\Z\ZZZZYZYZYZYZYYYZZ\YYVVTTMMOLC@===/==F@@@=@==//=/2FHRRHF3F3HH3HHHHHHHHHHHHH33323233HH31 ...*././.(///*/////*./(/(/(/(/(*/(/*/*/*/**(/**(/((/(((/(*(/*.*/*/(/*/(/(/*(/*.((.((((( (( ((.((.(((.((((.((.(.( (.( (( *(/(/(//*////=*////=/*//=///8/.(.    .. (           . .. . . . .. ....(..(/./..(..   ...///2/=2//2=2=2/2//2//2//2//2///////=//==/===============@@@@===@@@@@C@@C@@C@C@@@@C@CCCCCCCCOCOLOMTOTTTTSVTVTSVTVTVVVVVVVXYVVVXVYXVVXYXYYYXYXYX[Y[[Y[[Y[[[[[[YXVMOLGLCCCCLCCCCCCCCCC@@@@G@GG@GGGOOTMTOOOOCGCGCGLCGCC@@@=@@=@=@@@@@@@@@@@@@@@CLMLMOMMOMLLLLLLLLCLLLLCLCCCCCLMMMTSTUVTVVVVYYYZZ\Z\Z\ZZZYZYZYZYZYZYZYZYZZZZYYVTVTTMOLC@======/===/=/=//=FHRQHHFHHHHHHHHHHHRHRHHHHHHH3323233HHH0 .(/////////*.//=*/=//*/*/*/*/*/*/*/*//*/*/*=*/*/*(/**.***/**/**//*/*/**/*/*/*/**/*(.(.(.((.((.((.**.*(*/*.**.**.*.*( .((.(..(((./*//*///8/=======/=/==*/==//=*..(    ( . ( .   .......... .. ... .. ( . (     ./.2/2/2/2=/2//2=/2=2/2/2/2///2///////////=///=/===========@========@@@@=@@@@@@@@@@@G@C@C@C@GCGCOLOOMOOTOTTSTTTTSTVTSTVSVVVVVVVVVVVVVVVYXYXYYYXYYXYY[XY[XYY[YXYVLOLCCCC@C@@@@@C@C@@@G@G@G@GGGGOOOTTWTTOOOGGGCGGCGCC@@@@@===@=@=@@@@=@==8===@CLLOLMOMOLLCLCCC@@@C@C@CC@CCCCCLLMMTMTSTSTVVWYZZZ\ZZZZYZYYZYZYZYZYZYZYZYWYZ\ZZVTTTMOLOCC@==//////(..(.../2FRRQH2HFHHHHRHRHRRHRHRRHRHHHH3323123HH3 .(..(/(.(./(/*./*/*/*.((.(/(.*.*/*/*.*/*/((/(*(.(((.((.((.(((/(**(/((.*(/(((.(*(.((((((((.(((.(((.*.(.(.(((.(( ((. .(.((.(/*/*////*//=/*/////=*//=//*/.(     (           .. .... . .    ..//2/2/2=2/=2/=2/2//2//2//2////////////=//=/=/=//=/=//=/=====/=/=========/==@==/====@=====@=@=@@G@CGLGLOLOOLOLOLOLOMOMOTMMTMOMMTMMTMTMTTTTVSVVVVYVVVVVVVVVVVVLOCCGC@@@@@@@=@@@@@@G@@GGGGQOQWWWWZZZYZWWWWTQOOOGGCGCG@@@@@@=@=@=@=@@=======@@@CCLLGLCLCCCC@@=8=@=8@=@8=@8=@@:CCCLOLOTOTWWZZZZZZYZYYWZYWZZYZZZZYZWYWWWTWWYZZQOOLGC@@@@==./(. (    2HRHH3F3HHHHRHRRRRRRRRRRRHRHHHH3323113HH1 (.(.(...(..(.(.(.(.((((((.((((((.((((.((.((((.((.((.((( (((.((.((.((.((.(.(.((.((/(*.(((.(. (( .(.(.(/*./*/=/=/8//=//*=///=/*///*..(                 . . . .   ..//2///2=2/=2//2=2//2=/2/2/2///////////=/=/=/=/=/=/=/======/=/=/=====================@=@===@=@F@G@GCOCOOLOLOLOLOMOMOMTOMOTMOMTMOMTMTTMTSTTVTVVVVVVSVVVVVVVSTLCGCCCC@@@@=@@@=@FCGGGOQQWWWWZZZZZZZZZZZZZZZWWWWTQOOGGG@G@@@=@@@=@@=@=@===8@@@CCCLCLCLCLC@@===8==@=@8@@=9@@@C@CCGCOOOTWZZZZZZWYWWWWWYWZYWZZZWZWZWZWWWWWTWWZZWOOCCG@@@===/..   3RHH3F3HHHHRHRRRRRRRRRRRRRHRHHH3H31113HH30 (...(...( (.(.(.(( (..((.(.(.((.(.((.((.(( (.(.(.(( (((.(((((((( (.((((.(((/(/(*.*(.((( .((.(.(/(/*./*//=//=*/=///=*///=///*/(.(    (            . ... . .    ..//2=2//2=2/2/=2/2//2=2//=//////=///=///=/=/=/=/=//=/====/==/===/=====/======/====@========@@@G@G@GCGLGLOLOLOMOMOMOTMMTTMOTMMTMTMTTSTTTSVTVVVVVVSVVSVVVVSTLOCCCCCC@@@@=@=@@@GOQQWWWZZWZZWZZZZZZZZZZZZZZZZZZZZWWTQOGCG@F@@@@@=@=@===@=@@@@CCCCLCLCC@@@=8===8==@=@8@@@@9@CCGLOOTWYZZZZZWYWWWVWYZYZZWZZZZZZZZZZZYZWWWWTWWZZTGOC@@@=@=///(.(   2HRH32FHHHHRRRRRRRRRRRRRRRRRRRHHH333311HR31 (.(. .(( ((.((.((.((((.((.((.((.(( ((..(.(((.((( ((.(.((((((((((((.((.*((/(/(//(*.(.(   .(/(.(/(////*/=//=/*=///=/*/////*/.(.(                . . ..   .(   ..2/2=2=/2/2/2/=2/2=2///2/=////=//=//==/=/==/=/=======@=======@@=@@@=@@@C@@@@@@@C@@@C@C@@@@GCGCOOOOMOTTTTTTTSTTVTVVTVVVVVVVVVVVVVVVVXVYYXYX[Y[XYXYXYYXYXVVTMTLOMLOLCCC@C@@GOWWWZZZZWWWWWWYZYZYZYWZYWZWZWZZZZZZZZWWTQGCG@F@@@@@@@@@@C@C@CCLLOLOLLCC@@@@==8@@@@@@@CCCCLLLLMTTTZYZZZZYZVWYWYZYZZZZZZZZZZZZZZZZZZZZZYZWYWYZZWTOMOOCCC@@==//(.(   1FRHH323HHHRRRRRRWWRZRZRZRRRRRRRHHH332133HR1 (.(.((.(.((..(.*.*.(/(.*.*.*.*.*((.**(.(*.(*(*.((*.((((.(.((((((((((.((.((((((((((( .((.(((.(.(/(/*/(/*/(/(   ((/(/(/(//*/=/=*=//=/=*//=/=/8///*/*.(           . ... ....    ....   ...//2/2=/2//2=2//2//2=/==2=/==2==/==================@F@@@@@@@@@@@@C@@G@GC@@CC@CGCCGCGC@C@C@OLOLOMTOTTTTSTVVTVVVVVVVVVVVYVXVVVVXYXYXYXYX[Y[Y[[YYXYYXY[YXYUTMTSTMMMOLOLCCCOOTZZZZWWWWWWVYZYZYZWYWYWYWYWWYWWZWZZZZZZZWTQOOGCGCC@CCCCCCCCCCLLOLLLLGCC@@@@C@@@@C@CCCLCLLLLTMTVZYZZZZYZYWYWYZYZZYZZZZ\ZZ\Z\Z\Z\ZZZZZZZYZWYZZZZVTOMOLGCC@@==///((.  .2HRH323F3HHRRRRRWRZRZRZRZRZRWRRRRHHH33213HR30 .*.*.(/*./*/(/**/**/*/*/*/***/*/**/***/(**/(**/*(*/*/((((*/*.*/*(/*(*.*((.(((((((((((((.(.(/*/*/*/*///*/*/*/( (((.(///*/////8/=======/===/=/=//*///*/(.(         . . . .. ... .. .   .(..    ..//=2/=/2/=2/=2/2=/2/=/=//2=///=/=/====/==========F@@F=@=F@@@@@@@@@@@@@C@@@C@@C@@@@C@@@G@CCGLOOLOMOTOTTTTSTVTVVSVVVVVUVVVVVVVVYXYYXYYYX[Y[VXYVVVVXVVVVSTMMMMOLOLOLCCCCCOWZZWTWTWTWTWYZYWYWYWZWZWYWZWWWWVWWWYZZZZZZWTGGG@GC@C@C@@@@@@C@C@C@C@@@@@@@@@@9@@@@@CC@CCCLLOTVZZZZYYYWTWTWVWWYZYZZZZZZ\ZZZZ\ZZZ\Z\ZZZZZYWWWYZZWTOOLCCC@@==/*.(.( .HRHH233HHHRHRRRWWWWZRZZWZRZRWRRRRHHH33223HR30 (.( (.((.(.((.(.(.(/*/*(/(*(/((*.*.(*(.((/(((.*(.(((.((((((((((((.(((((((( ((((((.(((.*.*/*/*/(/(/(  ( ((/*./(/(///=/===/8///=*/=//=/*///*/((.            .         ..2/=2/2=2//2//=///=/=/=2=/=/=//2==/=/==/==/==/=/==========F=========@===========@========@@@CGCGGCGOCOOOOMOMTMOTTMTMTMTMTMTMTSTSTVSVVVVVVSTLMOMTMTMMMOLOLGLCOCCC@@@@@GLWZZTQOQTWTZYZWWZWZWZZYWZZWZWYWWWWWVWWWWZWZZWWOGG@G@@@@@=@@=@==@=@=@@@@=@8==8====8===9==8@@@CQZZWVWOQOQTOWQWWWWWZZZZZZZZZZ\ZZZ\ZZZZZZZZWWWWWWZZWOGC@@@==//(.    1HRH323F3HHRRRRWRZRZZZZRZZZRZRWRRRRHHH33133RH0  (.((((((.(((.*(.(((.((.((( ((.(((.( ((((((((..(((.(*.*.*//(/*/**.((  .(.*/.*.(/*//==/==/=/*/=//=*/=///*//(.(                        ( ...2/2=/2/=/=2/2=//2=/2//=/=/2/=/=/==2===2===/==/==F=========@==============@===========@=@@@@CGCCGCGGGLOOOMOTOMTMTTMOMTMOTMTTSTTSTVSVVVVSTMOLMOMTTTTMMOLLOLCLCCCCCCCCCOQZWWTQWVWYZYWYZYZZZZYZZZZZYZWZYWZWWWWTWWWWZZWWQOG@G@@@@@=@==@==@=@==@=@==@@=9===8====8@=8=@@OWZWOOOOTQQTQWWTWZWZZZZZZZZZZZZ\ZZZ\ZZZZZZWZWWTWWZWQCG@F@==*.  2RHH133HHHRRRRRWZRZZRZZZZRZZRZRRRRRHH3H321HRH1  (.(..(.((.(*.(((.(((.(((.((.(( ((((.(((((((((((.(((.(((/(/*//*//*/.(( (.(.*//.(.//*/===/==/=//8//=//8/=/*//(.(                     . . . ...//2////2/2=//=/=/=/=/=/2=//=/==2===2====2===2=====F=======@================@========@=@=@G@CGCGCOGOOOOMOTMTTTTTTMTTMTTMTSTSTVTSVVVVVVSOLOLOMTMTSTMTLLOLOLGLCCCCCGCCOOWZZTWVWYZYZYZZWZZZZZZZZZZZZZZZZZYZWYWWTWWWWZZWWOG@G@@=@@@=@=@@===@=9=@@=8===8==8==8==8=/8@@OWWWTOOOQTQWTWWWYWZZZZZZZ\Z\Z\ZZ\ZZZZ\ZZZZZWWWWWWZZQGCF@@==/(  1HRH323F3HHRRRRWRZZRZZZZZZZZZZRZRRRRRHH33233HR1 ( (((( ((.(.(*.*(.(.(.(.(.(((( (((.(((((((((( (.((.*.(.*/*.*///*/*/(. (( (.(/*./(../*/===/==//=/8///=//*///*..(                        .......... . ../////=/=//=2///=2=//=/=//=/==2==2====F======@F=F@@=@F@@@@F@@F@C@@@@@@@G@CG@@GC@@@@@CGCGCLOLOLOOTMTTTTVTVVVVVVVVVVVVVVVVVYXYXYYXYXY[VVSTTSTVVVVXYVUTSMTMMMOMOLLOLOLOTZZZYYZYZYZYZZZZZZZZZZZ\ZZ\ZZZZZZZZZWZWWWWVWWZZWWOOGCGCCC@C@C@@@C@@C@@@@@@@8=====9==@=@=@@@COTYZWTTWTWVWWYZYZZZZZZ\Z\Z\Z\Z\\Z\\\Z\ZZ\ZZZZYWWZZZWOOLCCC==(( .2HRH323HHHRRRRWWZRZZZZZZZZZZZZZRZRRRRHHH3323RH3  ((.((.(.((/(//*/*/*//*=*///*/(//.*((.((.(.((.((((((((((((((((.(.((*.(/*/.*//*//(/( ( (.(.(./*.(.(/./=/===/8////=/*/=/=///*/(.(              (   ...//////.........///=//2=/=/=2==2==2====2==F==F=F=F@@=@F=@F@@G@@FCFCGCGCC@GC@GCC@@CGCCG@CGCCGCG@CCGCCLOLOMOMTTTTTVVVVVVVYYYXYXYXYXYXVYXYXY[X[[[[[YXVTSTVSVVY[YXYYUTSTTTMTMMTMMMMOTTY\Z\YYZYZZZZZZZZ\Z\Z\\Z\\Z\\Z\ZZZZZZYZZYZWVWYZZZWTOOLOCLCCCCCCCCCCCCC@C@@@@@@9@@@@@@@@@@CCCLTWZZYVTYYWYZYZZZZZ\Z\Z\Z\\Z\\Z\\Z\Z\Z\ZZ\ZZZZWYWZZZTOOCCC@=.( .FRRH3F3HHHRRRRWRZZZZZZZZZZZZZRZZRWRRRRH33323HR3   (.(.(.((*.*/*/*/=*/=/========/=//=////*/**/*.**(.((.((.((.(((((((((((((.(((*/*/*/*/*/8///8//=*//((.(.(.*.//*./*//*==========/=/=/8/=///*.(.      ..( ...   . ... . . ...... .. .       ..../2/2/2///......////=//=2=//=///2==/2=/=/==/F/=====F======F@@F@@F@@@G@G@@@@G@@@@@@@@@@G@@G@CF@@@@@CGCGLLOLOLTOTTTTTTTVTVVVVYVVYVYVVVXYXYXYYXY[Y[YVSTTMTVVVXY[YXVSTTMMTMMOMOLOLOLTTZZ\YZYZYZYZZZZZ\Z\Z\Z\Z\Z\Z\Z\ZZZZZZZZZWWYWWWWWZWWTOGCOCCCC@C@@@C@@@@@8@===8====8=@=8=@@@@COMTYZZYWTWYWYWZZZZZZZZ\Z\Z\\Z\\Z\\Z\\Z\Z\ZZZZZWWWZZWOOCG@@@/(  1HRH323HHHRRRRWZZRZZZZZZZZZZZZZZRZRRRRHHH3323RH3   (.((.(.(((/*//*//8/=/====F====2=////(/.(.*(.((((((.(.((.(/(.*.(/*/*//*//*/( (.*(..(.(.(.(////(====/=//*//=//=*=//*/*.       . . ( .     .  . .       ...///2/2=/2///..../.=/2=/=//=/=/=/=2==/=2=2=====2==2===F==F=======@=F@=@=F=====@===================@=@@@@@@CGCGLOOOMOTOMTOTTSTTTTSTMTTSTVVVVVVVVVVUTLOLOLMTSVVVSVMOLLOLLGLCOCCCGCOMTYZZZYZYZYZZZZZ\ZZ\Z\Z\\Z\\\Z\Z\ZZZZZZZZZWWWWWTWWZWWOGCG@@@@@@=9===8=8==*=8==8=8==*/8/8/8=8@CGOTZZWTWTWWWWWWZZZZZZZ\Z\Z\Z\Z\Z\\Z\ZZZZZZZWWWWWWZWQG=@==/*.1HRH323F3HRRRRWRZZZZZZZ\ZZ\ZZZZZZRZRRRRH33232HR3  ( ((.(/////=/FFFGHGGHGHGFFF2//./((.(( (((.((.(/*.*.*.*//=*//*//(.*.*..(.(..(.*///*/=====/=/=*=/=/=/=*/(.(    . ..( ..                 ././2/2/2=/=2=/////./=///=2=/2==2/=2==2=/===2====2===F=====@=F@F=@=F=@F@====@=@==========@==@======@=@@=@@@@GCCOGLOOOOOOMOMOTTMTMOTMTTTSTSVSVVVVVVSTOLLOMTTVVVVTSOMOLLLGLCOCCCGLLTTTVZ\ZYZYZZZZZ\ZZ\Z\Z\\Z\\\Z\\Z\Z\ZZ\ZZZZZZWZWWWWTWZWWOGCC@@@@@===8==8/=*=8=*=8/8=*==*=*==8=@CCGOWWZTQQTWTWWZWZZZZZZZ\Z\Z\Z\Z\Z\ZZ\Z\ZZZZWWWQWWZWQGF==//*2HRH13F3HHRRRRWZRZZZZZZZ\ZZZZZZZRZRRRRHHH3323RH1 .(.(/./==FFGQQQRQWWWWWWRQQQQHFF=2/(..(( ( (((.*(.(*/(*/.*//*=//*//((.*//(..(.(..*=/=/*/==/==/=//*=/=/8///((.     ....( .(                ./////=2=2=2=/=/////////=2=//==/=/==2==/F/=F=2=F/==F===F==F=F@=@F==@F=@F@===F=F====================@=@@@@@G@CGLOLOOMOTOTTTTTMTTTTTTTSTVTVSVVVVVYXVTMMOMOTSVVVVVSTMOLOLLLLGLCCCCOMTTTVZZZZYZYZZZ[Z\Z\Z\\\\\\\\\\Z\Z\Z\ZZZZZZZZZZWWWWWWWZWWOGCG@@@@=8==8/=8==8=/=8===8===8==8==@C@CCOOWZWTQWQWWWWZZZZZZ\ZZ\Z\Z\\\Z\Z\Z\ZZZZZZWZWWQWWZQG===//*/ 2RH3233HHHRRRWRZZZZZZZ\ZZZ\ZZZZZZRZRRRRH33323RH3   (.../=FFQQQWWWWRWQRQRQRWQRWRWRQHFF=..(.((((.(((.*(/(*/(/*/*//*/=*=//(////(.(..(./*===//*===/=/=/=*=/=//=*.(.     ( ( (..                      ..///2/=2=2=/=/==/=2=/2=/=//=2=/=2===2===2====F==2==F=F=F@F@@FG@@FG@@G@@G@@G@G@CF@@@@@@@@C@G@@G@CGCCCCGCOCCOLTTSTVTVTTVTVVVVVVVVYYVYYXYYYXYY[Y[[Y[YVVVVVVYY[Y[YYVTSTMTTMTMMOMOMTVVVVVY\ZZYZZY\ZZ\Z\Z\\Z\\\\\\\\\\\Z\Z\Z\Z\ZZZZZZZYZTWYZZZTTOOCC@@@@@@@@=@@@=@9@@=@@@@@@@@@@@CLLCLLLOVZZWVWTWYWZZZZZZZ\Z\Z\\\Z\\\\\Z\Z\Z\ZZZZWWWWWZZWOG@@===*/( HRH323FHHHRRRWZRZZZZZ\ZZ\ZZZZZZZRZRRRRHHH332HHH1    ( ( ( (.//=FGQWWWWRQQQQGGQGGGGGGQHQQRQWQQGF=/.(.((.(.*(*/*.*.*/(/(//*/=/8//8/(.*///(.(/.(./=/==//*===/=//=/*===///*.((       ( ....       .         .///=2=/F/=2==2=2/=/=/=/=/=/==/F==2==F=F=F@F=@F=F=F@F@F@@G@GGCGGC@GGCGGCG@GCCGC@GCGCGCG@GCCGCCGCCGCGLCOLOLOMTTVVVVVVYVYYYYYYYYYY[YYYY[Y[[[[Y[[[[[YYYVYYY[Y[[Y[YYVVTVTSTSTSTMMVYXYYYYY\\Z[Z[Z\Z\Z\\\\\\\\\\\\\\\\\\\\Z\Z\Z\ZZZZZZZZYZWYZZZTTOLGLCC@C@@@C@C@C@@CCC@CC@CC@C@CCLLLLLOMOTZZZWVWWWYZZZZZ\ZZ\\\Z\\\\\Z\\\\Z\ZZZZZZZZWWWZZWQGC@@===**1FRH3233HHRRRRWZZZZZZZZ\ZZ\ZZZZZZZRZRRRRH33323RH1   ( .((.(((.(.((.//FFQQWWQRQQGGHGFGFFGFFGFFFFFFGGRQWRQGF=/.((.(((.((.*(/*/*/*//*/*/*/=*/=/==/8/(./=//*./(/(/===@=//======/=/==/==*//.(.        (...(.   . ..(.... .. . . (. ..  (  .   .///2/=2/=2==F/F/=2=//=2=/2==2=/F===2==2=F=F=F===F=F=F=F=FG@G@G@G@G@G@@G@@@G@@G@@@@@@@@@C@G@@@@GCCGCCGCCCOLOMTTSVTVVVVVVVYYYYZY\ZYYYXYYXYY[Y[Y[Y[YYYYYYYY[YY[YYVVTSTTTMTMTOMTUYVVVVVYZ\ZZZYZ[Z\Z\Z\\\\\\\\\\\\\\Z\\\\\Z\Z\Z\Z\ZZZZZYWWYZZZOOOCC@C@@C@@@@9@@@@9@@C@@@@@@@@CCLCCCCCLOOTWZYWTWWWWZWZZZZ\ZZ\\Z\\\\\\Z\Z\Z\ZZZZZWWWWWWZWQCF@===*/*.1HRH323HHHHRRRWRZZZZZ\ZZ\ZZ\ZZZZZRZRRRRHH3323HRH0   ..( ..=FHQQWRQGHFFFF@FF@F@F@FF@F=F==2FFFGQQRGF=/.((((.*(*/*/**/*/*/*.*//8/=8/==((/*//*.(/.(//======(===/==/=/=====//*.(.       ..       . ( .  .        .  ..//=/=/===2=2=/2=/=/=2==/=2==2==F=F=2==F=F=F=F=2===F==F=FFFGF@F@F@F@F@=FF@=F==F==F=F=@=F@==F===@@=@=@@@@@CCGLOMOTMTTTTTWTWYZZZ\ZZYYVVVYVYVYYYYYYYYZYZZYZYYYVTVTOMOMOLOLOLLOSTUVSTTVVZZ\ZYZZZZZ\Z\Z\\\\\\\\\\\\\\\\Z\\Z\Z\ZZZZZZZZWWWWWWZWWGC@@@=@=8=8=8=8=8=8=8=8==8=*8==@9@@@9@@@CGWWZWQWQWWWWZZZZZZ\Z\\Z\Z\Z\\Z\Z\ZZZZZZWWWQQWZWQF=///((.(1HR32323HHRRRRZRZZZZZZZZZ\ZZZZZZZZRRRRRH3H332HR30    ( /2FQQRQHFFFF=F=2=F==FF=2=F=2==2=2//F2FGRQQF=..(.((/(**/*/*/*/*/*//*=/=*=/=///8//(./*./*/=====/*=====/==/=/===//*(.(        .                    ..   ../2//=2=/===F2==2==2====2==2==F=F===2=F==F==F==F=F=F=F=FFG@GFGF@F@@F@F==@F@@=F=@======@=@=@=@=@F@=@@@@@@@G@COLOOOMOTTTWVZZZZZZZZZYVTVTVVVVYYYY[Z\ZZZ\Z\ZZZZYYTTTTOOMOLOLOLTVVVSVTVTVYZ\ZYZYZ\Z\Z\\\Z\\\\\\\\\\\\\\\\\\\\Z\\Z\ZZZZZYWWTWWZWOG@@@@@===8==8=8==*=8/=8/=*==8@@@@=@@@@@@GGWWWWOQWWWWWZZZZZZ\ZZ\\\\\Z\\Z\ZZZZZZWWWRQQWWWGF=/.*.(( 1HR3213F3HRRRRWZZRZZZ\Z\ZZZZZZZZRZRZRRRHH3323HR3  ../FHQRGHFF=2=2=F=F/F2F=FFFFFFFF=F/=2//=2FFGRQF2/( (*.**/**/*/*//*/*/*/=*/=/8=/=(.*//*.(/*//*====8==/=====/=======8//((.(     (     ( . (              ... .../=/==/=2=F=2=2=2===2==/2==F==F=F=F=F==F=F@=F==F=F=F=FF@FGFG@GFF@F@@F=F=@@F=@F=F@@==@=@F=@==@F@@=@=@@F@CGCGLOMOTTTTYZYZZZZZZYZ\ZZVVVVVYVYYY[Z\\Z\\ZZZZ\Z\Z\ZYWTTTOOMOLLLTVVVVVSVTVTZZZZZYZZZZ\Z\Z\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZZZWZWWTWZZWOGC@@@=@==8=8==8=8/8*/*/*===9@@@@@9@=@=@@GQWZWQWQWWWWZWZZZZZ\\Z\Z\\\Z\Z\ZZZZZZWWWWQQWWWRF=///(.(( 1HR32133HHRRRRZRZZZZZZZZZ\ZZZZZZZRRRRRHH3H313HR3   ../FHQRHFF2/F=2F=2F=2FFFHGGQQQQHGHFFF/F/2=/FFFQQH=..(.((*/(**/*=*=/*/*//8/=*=/=*=/*.(/=*/(/=*//8/==@==/======/=/=====*//((.        ( ( .( ..               /./.  . ...///2==2==2=F=2==2=2==F/F=2=F=F=F==F==F==F@F=F=F=F=FFF@GGGGGGGG@GFG@G@F@G@G@G@GCGCG@G@GCCGCG@GCCGCGCGCLGLOMOTTTVVVYZZ\Z\\\Y[ZYZ\\Y[YY[Y[Y[Z\\\\\\\[Z\YZZ\Z\Z\Z\YYVVTTVTMTVX[YXYYXYYYY\\\YZ[Z\Z\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZYWWZWZZTTOOCCCCC@CCC@@@@8@=8=8=@@CCCCCLCCCCCCC@G@OWWZWTWWWWWZZZZZ\Z\Z\\\\Z\\\Z\Z\ZZZZZZWWWQWWZQG@====*/*.(. 2HR3323FHHRRRRWZRZZZZZ\ZZZZZZZZRZRZRRRRH3323HRH2  .(./FHQQHHF=2=F2=F=FFFFFGQQQWWWWWWWWQQGHF=F/2=/FFFQQH=. ((.(**/***/=8==*=8//8/=*=/=*==/((/=/((/=*=/=8=@=@=/========/==8===/(((.     . (. .(..(.....(..( .               ///..   ....././/2==2====2=F/=2F/=F=2====F==F=F=FF=F=F@F@F@F@F@F@FGFGGGGGGOGGGGGGCG@GCGGCGOCGLGCGCCGCGCGCGLCGLGCOCLOLOMOTMTTVYYZ\[\\\Z[Z\Y[Z[\\\Y[Y[Y[\[\\\\\\[\[Z[Z[Z[Z[\\\Z\YYYVVTTVV[[[[[[Y[YYYYZ\\Z\Z\[\\Z\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZYZYZZZZTTLOLCLCLCLCCC@@@9=@=9@CCLLLLLCLCCCCC@GCGOOZZWWWWWWZWZZZZZ\Z\\Z\\\\\\\Z\Z\ZZZZZWWWWWZZWGF@====8/*.(...2HRH232HHHRRRWRZZZZZZZZZ\ZZZZZZZRZRRRRHH3H32HRH1   (.(.(./FGQQHGF=F=FFF=FFFFGGQWRWWRRQQQRQWWWWQGHFF=F/=2FGQQF=.((((.((/***/*=*=======8===/==8=/=8=//(/*/(/===8==@=@@@=/==8==/=======8/*.((      ( ( . ( ..(..(././.*./..(..(..(...  . ( ..         /.(..   ..../////2=/===2====2=2=F2=2==2=F=F==F==F=F=FF=F@F@FF=F=FFFF@GFGGGGGGGG@GG@G@@F@G@GGCGGCGCFCCGCGCGCGCCGCGCGCGLGLOMTTTTYZZ\ZZZ[ZZ[YZY\Z\Z[Z[Z[Z[\\\\\[\[\[Z\YZYZZYZYZ[Z\ZZYVTVTTYX[Y[Y[XYYXYY[Z\Z[ZZZ\Z\\Z\\\\\\\\\\\\\\\\\\\\\\\\\Z\Z\Z\ZZZZZYWYZZZTTOLLCCCCCCC@C9==8=8=8@@CCCCCCC@C@9@@@@@@GOQZZWTQWWWWZZZZZZ\Z\\Z\\\Z\Z\Z\ZZZZZZWWWQWWZRG===/*//*.(. .2HRH3133HHRRRRZRZZZZZZZZZZZZZZZRZRRRRHH3H323HRH0   (./FGRHHF=22=2F2=2F/FFQRWRQQHFFFFFFFFGRQRROFF=2=2=/FHQGF/   ((((.**/**/8/8=8===8/=8//8/8=/=8/(.*/((/===8==@=@@@//======8/=====8/*.(.      .(..(./(..(..(..(. (. (. . (           ...   ....////=/=2=2=F/F=2==2=F/F2F===F=F=F=F=F=FF=F=F@F@F=F@F@FFFFFG@GFGG@F@FF@F@=F@@F@@F@@F@F@F@=@=@==@=F@@@@=@@@@GCGCOOTWYZZZZYZYZYZYZYYZZ\ZYYYZYZ\Z\YZ[Z\YZZYZYZYZYZYZZZZZZZWTOTTVYYXVYXYYVVVVYZ\ZZZ[ZZ\ZZ\\Z\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZZZWWWWWZZWOGC@C@@@8=8=8=*=*/*/8*=8===9=8=8=8=8====@@QQZWQQQWQWWWZZZZZ\Z\\Z\Z\\Z\ZZZZZZZWWWQQQWWWF///.(.( .HRH322H3HRRRRRZRZZZZZZZZZZZZRZRRRRRRHH33313HR3 ..FHQHFF/2=2=2=2F/=FHQRQHGF2//....///2=FGRQQFF2=/2//FHQHF.((((((.***/*=/8===8==8=/=*=/8=8===*(/*/(*======@@@@@@8===8====*====8//*.(     ....(. (..(..             ( ...   . .././//=2==2===F===2==2F/F==2=F=F=F=F=F=F=F=F=F@F@F@FF@FFF@FGFGFGG@GGFG@F@FF@F@F@F@F@F@@F=F@F@F@F@@@F@F@F@@F@CG@OOOTZZZZYWYWYYZYZYZYZ\ZZYZYZ\Z\ZY\YZ\Y\ZZZZZZZZZYZYYWYZZZYWTTVVYXYXYVXYVVVVYZZ\ZZZZZZ\Z\Z\\\\\\\\\\\\\\\\\\\\\\\Z\\Z\Z\ZZZZWWWTQWZWQOCF@@@=8=8=**/***/*/8=/8=8=8@=8=8=*=====FGOWWWQQQWWRWZWZZZZ\ZZ\Z\Z\Z\ZZZZZZWWWRRQQRZRF2.(.1HRH1323HHHRRRWRZZZZZZZZZZZZZZRZRRRRHH3H3133RH1 .FHQHF2/2/2F2=2=2=FHQQHGF2..(..(.(.(..//FFQRQH=F/2=2/FHQH=. ((.(((*/**/8/=8===8==8=*=*==8==8==/((/((/8===@=@@@@@=/===8==/===8==8=*/(.      ( (..(..(. (            ( ..   ....///=2==/F=2=F==2==2=F2=F2=F=F=F=F=F=F=F=F=F@F@F@F@FFFF@FFFGFGGGFGGF@FG@F@=F@F@F@@FG@FF=@F@@F=F@F@@@F@@@F@C@GCOCOTZZZYWWYZYZYZYZYZYZ\\ZZY\Z\ZZ[ZY\Y\Z[ZZZYZZYZZZZZYZYZYZZZTVVVVYYYXYVXYVVVYY\Z\YZY\ZZ\Z\\\\\\\\\\\\\\\\\\\\\\\\\\Z\Z\ZZZZZZWWWTWZZWOOC@@@@=8=8==8/*=*8=*8/8=8==8=8==*=8=8===@GWWWWQQQWWWWZZZZZZ\Z\\Z\Z\ZZ\ZZZZWZRWQQQRWWF//...HRH3133HHHRRRRZRZRZZZZZZZZZRZRRZRRRHH33313HH30  .FHGHF2=2=2F/2=22=FHQRHF//..(  ( (.(.(..=FHQGH2=2//2=FQQF/.(((((.((*/**=*===8===8=/8=/8/=8===8=*.(/(/*@==@@@=@@@@@*====8=/8==8===*/*(     (  (...(.(.(       ( ( ./.(  ..././//=/F/==F==F=F/F/F/=F2=F=F=F=F=F=F=F2=F=F@F@F@FFF@FFGFG@GGFGGGGGGGGG@@FG@G@GGGGGGGCGGGGGGCGCGCGGLCGLOLOLOOMOTTYZZZYZYZYZY\Z[Z[Z\[\\\\\\\\[\[\[\\[\\\[Z\Z\Z\Z[ZZZZYZZZ\ZZYYY[Y[[Y[Y[YXYYYZ\\Z\YZZ\Z\\\Z\\\\\\\\\\\\\\\\\\\\\\\\\\\Z\Z\ZZZZYWWYZZZVOMOLCCC@@@@@@@9@@@=@9=@=@@9@@@@9=@=@=@@@GGOZZWWQWWWWZWZZZZZ\Z\Z\Z\Z\ZZZZZZZWWWWQQWZRG2//.(  .HRH3223HHHRRRRRZRZZZZZZZZRZRZRRRRRHHH33213HR3  (./FHQHF2=2=F2F2F2=FFHQQHF//..(.(.( ((.( (.*./FGRQFF/F/=2FHQHF.(  (((.((((.*/**==8===8==8==*=8===8===@=*((((/=8@=@@@@@@@@==8=//8/=8==8==8=*.(  . ( ( (..(.(/.(.(.  (..( (..         ../..(.   .././/=/2==F=2=F=F==2=2==2=F=F=F=F=F=F=F2=F=F@F@GFCFF@FGGFGGGGGGGOGOGGOGGGGGCGGCOGGLGOOOGOGGGOGGCGGCOLOOLOLMOMTOTSTYZZ\YZYZY\Z[Z\Z\[\[\\\\\\\[\[Z\[\\\\\\\\\Z\Z\Z\Z\Z[Z\YZ[Z\\[Y[[[[[[[[[[[[[[Y\\\Z\[Z\\Z\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZYZWYZZZTOOLLCCCCCC@@@C@C@@@@@9@@C@@@9@@@@9@@=C@CGOWZWWWWWWWWZZZZZZZ\Z\Z\Z\Z\Z\ZZZZWZWRQQWWWQ=//.(((( .HRH3232H3HHRRRRRZRZRZZRZZZRZRRRRRRHH3H313HHH0    .(./FHQGFF2=FFFF=F=F=FHQQH=////(..(.(..(((..(/.//FQQHFF=2=2=FQQH/.(((.(((((((((.((**=*=8====@8===8===*====9==@=*.((/8=@=@=@@@@@@@====*/=*=*==8===*/(.  ..(..(...(.(./*//.(..(.(.(.(..(.(..( ..(( (     ..( .(.    ...///2==2==F=F===F/===2===FF=F@F=FF=FF=F=2FF@FF@GFFFFFFF@FGFGFGGGGGGGGGGGG@FG@GGCGGGGGGGCGGGGG@GGCGLGLGLOOLOOMMTTTWY\ZZYZYZYZ\Z[Z[ZZ\Z\\\\\[Z\Z[\\[\\\\\\Z\Z\\Z\Z\Z\ZZYZZZ[\\Z[YY[Y[Y[YXY[YYY[Y\\ZZZ[ZZ\Z\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZZZYWZZZZTOLGLCC@@@9@@9@9@@@9=@=9@9@@9=@8=8=9=@@@@CGQWZWWOQWWWWWZZZZZZ\Z\Z\Z\ZZZZZZWZRWWRQWWWH=...  HRH21233HHHRRRRWRZRZRZZRRZRZRRRRRHHH33213HH3  (.FHQHFF/=2F2=2F2F=FHQQH=/..(.((.( (.(.../FQRG2=2/=2=HQQ2.( ((((((((((.*/*=8=8===8==8==8==8====@8@==*.((/=9=@@@@@@C@@@/==*//*/8===8===*/((   . ( (.(.(.*..  ( (.(.(((      ( (.   .././=/=2==F===F=F=2=2==2=F=F@F=F@F=F=F2=FF=FF@FG@FFF@GFGFFGFGFGGGGGGFGFG@FF@F@FGF@FG@G@FF@F@F@F@F@F@@G@G@CG@CGOOOOTZZZWVWYZYZZZZZZZZYZZ[ZZZZYZYZZZ\Z[\\Z\Z\ZZZ\ZZZZZZZZYZYZZ\ZYYYYYYXYXYYYYYYYYZ\ZZYZZZZ\Z\Z\\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZ\ZZZZZWWWTZZZQOC@@@=9=8=*/8/8*=8=*8/*=*8/**/**/*/8/8===@GQWWQQQQRWRWWZZZZZZZ\ZZ\ZZZZZZZWWWRRQGRWRH/.  3RH311233HHHRRRRRRZRZRRZRRRRRRRRHH3333113RH0  .2FHGF22/2F2=2F/22FFQHH/.. (      .(/2GRQF22=2/2FQRF/.(((((((((.((**/8/8====8===8==8==8=@===9=@=*/((==@@@@@@@@@@9@/==8/8//8===8==8.(.  .(.( ( (.(          .( (  ..//2=2==F=F=F=F=====2==F==F@FF@F=F=F=FF=FFF@FFFGFGFFF@FGFFGFGGHGGGGGFG@GFGF@GF@FFGFG@FG@F@F@F@F=F@G@@G@G@CG@COOOOWZZZWWVWZZZYZZZZZZZZYZZZ[ZZ[Z[Z[Z\Z\\\Z\Z\Z\ZZ\ZZZZZZZYZZ[Z\\YYYYYVVYYXYYXYYYZ\Z\ZZZ[Z\Z\\\\\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZZZWWWWWWZWO@@@===8/*=**/8/8=*=**=*/*/8/8/*****/=*===FGWWWQQQRQWWWWZZZZZZZ\ZZZZZZZZRZRWRQHHQWRH/  2RH111123H3HHRRRRRRRRRRRZRRRRRRHHH3H3113HH3  /FHQF22/2=22F22=2=FHRH/..  (   ../FQRG2=2=2/FHQHF.(((.(((((((/*/8=8=8==8====8==8==8=@@@=9=9=8/*/8@@@@@@@C@@@@=8==*/*=*=8===8=**(. .( (  (         .((   ..//=/==2=F=F=F=F=2=F/F=/F=F@F=FF=F==F=FFFFFF@GFGF@FFGFGFGFGGFGGGGGHGGGGFGF@GFGFG@GFGF@FF@GFF@F@F@FG@G@G@G@CGCOLOTWZZZYWYZWYZZZZ[Z\YZ[ZZZYZZ[ZZ\Z\\\\\Z\\Z\Z\Z\Z\Z\ZZZZZZZY\\\Z[YYYYVYXYYXYYYYYYZ\ZZYZZZZ\Z\Z\\\\\\\\\\\\\\\\\\\\\\\\\\Z\Z\ZZZZZWWTWWZWQGC@@==8=*8*/*=*=8=*=8**8/*/*/*/*/***/*///=FQWWRQGRQRWWWZZZZZZZZ\ZZ\ZZZZZRWRRRGQRWRH/.1HH3101133HHHHHRRRRRRRRRRRRRRRHHH3333133HH0  .FHRH2/2=22F=2F/22FHQH2/ ( (   ..=HWHF2/2=/2FQRF. ((((((((((***/8/8=8==8===8===8===@9=@@8@==8/*==@9@@@C@@@@@@8===*/*/=8==8==*/((   . ( (         (( (..    ../2=2==F=F=F=F=F==2==F=F=F@F@F=F=F=F=FF@FFFGFGFGFF@FGFGFGFGGHGGQGGGGGGGGFGGGG@GGGGGGGGGGGGCGCGGGLOGOOOOOOOOMOTTYZZ\ZYZZYZZ\Z\[Z\\\\Z\[\[\[\\[\\\[\\\\\\\\\\\\\Z\Z\Z\\[\\[\\\\\[[[Y[Y[Y[Y[YYYYY\\Z\Y\Z\\Z\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZYWYZZZYOOCC@@@9@=8@=9@@@@9@9=@8@9=9=8=8==8=*/8===FGWWWQQQWWWWZWZZZZ\ZZZ\ZZZZZZWZWWRQRHQWWH/...HH31011233H3HRHRRRRRRRRRRRRHHHH3H33113HH3  ..FHQHF22=2FF2FF2=FFFQRF/..( .((.. ((  (..2GRQF2=2/=2FHQH/.(((((((((((/***=*=8=8==8/=@==8==8=@=@9@=9@@=8/8=@@@@@@@@@@@@@*===8/8/=8==8=/*/((  (( (. ( ((.(... (..((.( (    .(....(   ../2==2==F=F=F===F=2=F==F=F=F@=F==F=F=FFF@GFGG@GFGGFGGGGGGGGGGQQOGQGGGOGGGOGGOGGGGOOOOGOGOOOOGCOOOOOOMOOMTOTTTTVYZ\ZZYZY\Z[Z\\Z\\[\\[\Z\\Z\[\\[\\\\\\\\\\\\\\\\\\\\\\\\\\\[\\\\[[[[[[[[[[[[[[[Y\\\[Z\[Z\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Z\\Z\ZZZZYWZZZZTOLCCC@@@9@9@@@9CCCC@9@@9@@9@8=88=8/8==8===GQWWWQQQWWWWZZZZZZZ\ZZ\ZZZZZWWWRWRQQRWWHF.(  3HH10011233H3HHHRRRRRRRRRHRHHH3H33112HHH0 (..=HQRHF=2FF2FF=FFFFFRQH=..(.(..(..(.(.( (  .(./HQRFF/2=2=FHQQF.(((((((((((*(/8**=8=8=8==8==@==8=@=8@=@9@=9@@@=8==@@@C@9C@@@@@=8==8==8/=8===8/*.(((.(( (.(.(.(.(((.(.(.((((((.((.((.(((.(.(  (    (( ((.      ..//2=F=F==F@=F=F=2===F=F@F=F@F=F=FFF=FFGFF@FGFGFFFGF@GFGFGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGOGGCGGGOGOOOOOOOOMOOTTTWZ\ZZYZZY\Z\Z[\Z\\Z\Z\[Z[\Z[\\\\\\\\\\\\\\\\\Z\\Z\Z\\\\[\\\\\\\[[[[[Y[Y[Y[YYYY[Z\\Z\Y\Z\Z\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZZWYWZZZTOCG@@@8@=8=8=9@@9@9@@9@8=8=*8*=**/**/*/(/==HQWWRQQRWWWZWZZZZZZ\ZZZZZZZRZRRRRGHQWWHF..1HH200011233H3HHHHHHHRHHHHH3H33331113HH1 ./FRQHF2F2F2F2F2F2=FHQQF...( (..(...( (    (.FRQH2=2/2/2FQRF. (((((((*(/*/8*=8==8=8==8=@@==8==9@=@@9@@@@@8=8@@9@C@@C9@@@@===@8===8===8=*/*.((   (( ( ( (  (( (.( ((..( ((.(   . ..2/=2===F=F@F=F===F=F=F=FF@FF=FF@F=F@FFF@GFGFGFGFFFFGFGGGHGHGHGGHGFGGFGF@GFGFFFG@GG@F@FG@G@F@GF@G@G@GCGCGGCOOOOTZZZZYZYZZZZZZZ\ZZ\Z[ZZZZZZZZY\Z[\\\\\\\\\Z\Z\\Z\Z\Z\Z\\[\[\\\\YYYYYYYXYVVXVYYVYZ\ZYZYZ[ZZZ\Z\Z\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZZZWWWWWZZQG@@===******/88=8=8*8/***/**/(*(((((( (./2QWRQQQQRWRWZWZZZZZZZ\ZZZZRZRRRRHHHHRWH/. 1H310 00123333H3H3HHHH3H3H333321012HH30 .2HRHF222=2F2F2F222FRQH/.  ........   .FHWH=2/2=2/FHWH/.((((((/(***/8*=8=8==8===8@8==9==9@@@9@@@9@@@=9@@@@:@@@C@9@@8====@==8====8/*.((( (.(((.     (.((  . ..//2==2=F=FF@F=F=F=2=F=F@F@F@FF@F@FF@F@FGFFGGFGFGF@FGFGHGGGGGGGGGGGGGGFGFGFGGGFG@GGGGGFCGGGFCF@GF@GFGGG@G@GGCOOOWZZZYWZYZZZZZ\ZZZ\ZZZZ[ZZ[Z\Y\Z\Z\Z\\\\\Z\\\\Z\\Z\\\\\Z\\Z\[\\[Z[YY[YXYYXYVVVVVYZZ\ZYZZZZ\ZZ\Z\Z\Z\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZZWWWWWWZQG@===*/*/*/*8=8=88/8**/***.*(*.((.( (./FRWRQHQRQWRWZZZZZZZZZZZZZZRRRRHHHFHRRH202H3100011233333H33H3H3H3333110113H30 .FRQH22=2F2F2F22F2FHRQ2..  . /22FHFHF2/.   .2QRH2/2=//2=HRG2((((((**/*8*=*=8=8=8=8=@8@=9==8=@@@@9@@@@@9@@9@@@@C@9@C@@@@8=@8@@@=@@8==8/*.(.( ( (.(.(((  ( (( (    ....2/2/F=F=F=F=FF==F/==F=F=F@FFG@FF@FF@FF@F@FGFGGGFFFFFFGFGGHGGHGGQHGHGGGFGFFGGFGGFGGGFG@GFG@GG@GF@G@GFG@GGGGCGOOOOWZZZZYZZZZZ[ZZ\Z\Z\Z\ZZ\ZZZ[Z\Z\Z\\\\\\\\Z\Z\\Z\\\Z\\\\\[\[Z\\\Z[Y[YYYXYYVVVVVYYZ\ZZZYZZ[Z\ZZ\Z\\\\Z\\\\\\\\\\\\\\\\\\Z\\Z\ZZZZZZWWTWWZWO@@===***/**=8=8=8*/8**/(*(/*(((( ./FQWWQHQQRRWWWZZZZZZZZZZZZRZRRRRHH3HRRH. 02H310 00011232333333333331110013H30 2HRHF2F2F2FF2F2F22FQRH2. . ../FHQRQRRQQH2.   .2QRHF/2/2/2=HQRF.(((((*(*/**88/8=8=@8@=8=@8@=8=9@@9@@@9@9@@9@=9@@@C@C9@C@@@@8=@=@@@@@@=8==*/((.( ( (.((  ( (.((.((.(     ....//2=2=F=F=FF=F=FF=F2==F=F@FG@GF@FF@F@FF@FFGFGGFGFGFGFGFGFGGHGGGQGGGGGGGGGFGGGOGGGGGGOGGGOGOGCGGOGGOGOOOOOMOOTOTTWYZ\ZZZZYZ\Z\\\Z\\[\\[\\[\[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[Y[[Y[Y[Y[Y\\\Y\[Z\Z\\\\\\\Z\\\\\\\\\\\\\\\\\\\\\\\Z\\Z\ZZZZWWYZZZQOC@@@==8=9@9@@9@@@9==8=*=**/*/*(((((..(/FGWWRQQQWWWWZWZZZZZ\ZZZZZZWWRRHHHFHRRH 12H3200 00111132333232311101013H30 ..HQRGF2FFFFFFFFFF2FHRRH/...(./FHQRQRQQRQRQGF.   .2QRG22=2/2/2FRQF.(((**/8/8/8=8@8@@8=8@=@8@=@8@@@9@9@@C9@@9@9@9C@@@C9@C@C@==8@@@@@9@@@==*/*((.( (( ((.(.(( (((*(/((.((((( (( .   .../2//==F=F=F=FF=F=F=F=F==FFG@FFGF@FG@FF@FF@GFGFGGGGFGFGFGFGGGOGQGQOGQGGQGGGGGGOOOOOOOOOOOOOOOOOOOOOOOOOMOTOTOTTTTTYZZ\ZZZ[Z\Z\Z\\\\\\\\\[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[\\\\[\[[[[[[[[[[[[Y[[\\\[Z[\Z[\Z\Z\\\\\\\\\\\\\\\\\\\\\\\\\\\\Z\Z\ZZZZZWWYZZWOOCC@@@@@@CC:C@C9@@88=8=****/(*.*(((((((.//=HQZWQQQRWWWWZZZZZZZZ\ZZZZZRWRRHHHHRRF.02H3F310100111111111110101123H31  .2QRRFFFFHFHHFHFFFFFHWRF/..../FQRQHGHFFFFGRRG2.  (.FQRHF/2=2=/2FQRF/ (((((*(*8/888=8=9@@9=@8@@@9=@8@@9@@:@@9@9@@@9@@9C@CC@C@C@@@8=@@@@@@CC@@=8//*(.(((.(((.(.((*.(.((*.*/**/((((.((((((((..(((.     ...2/2=2F=F=F=F=F=FF=F=F=FF=FGF@GF@FGF@FFG@GFG@GFGGFGFFGFFGFGFGHGGGQGGHGGGGGGGGGGGGOGOGOOGOGOOGGGGGGGLOOOOLOOOTOTOTWTZZ\ZYZZZ\Z\Z\Z\Z\Z\Z\\Z\[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[\\\\\[[[[[[Y[Y[Y[Y[[YZ[\\Z\YZ[ZZ\Z\Z\Z\\\\\\\\\\\\\\\\\\\\\\\\\\Z\ZZZZZWYWWZZWOC@@@@=9@@@@9@9@@8=8=****.((*((((.((.(///FQWWRQQQWRWZWZZZZZ\ZZZZZZWWRRRHHFHRRF 1HHH321110010111100100113HH30 .FRRHFFFFHFHFHFHFF2HQWHF.. ./2GRHFF2/2=22FFQRF.   .FHQH2/2/2/2/FHWH/(((**/8*8=88=9=9@@9@@@9=@9=@8@@9@@9@@9@@9@@9C@@CC@CCC@CC@@8=@@@@@@@@9==*.*((.((.(((((.((( ((((((/((((((((( (( ...//2==F=F=FF=FF=F=FF=F=FF@FF@FGF@F@FG@GF@GFGFGGFGFGFGFFGFGFGFGGHGGGGGHGGHGFGFGGGGGGGGGGGGGGG@GFCFCGFG@GCGCGGGOOOQOTWZZZZYZZZZZZZZ\Z\ZZ[ZZ[Z\\\\\\\\\\\\\\\\\Z\Z\Z\\\\\\\\\\[\[\\\\[[YYYYYYYXYYYYYYYYZZ\ZZYZZZYZZ[ZZ\ZZ\Z\Z\\\\\\\\\\\\\\\\Z\Z\ZZZZZZWWWWWWZWGF@/=8==8=8=8=*8*8/(((.(./HRWWGQQRWRWWZZZZZZZZZZZZWWRRRFHFHRR2 033HHH3322111011110133FH330 2HRQF2FFFFHFFHFFF2FFRRQ1. ..HQHF2//2/2//22HQH. ..FRQH/2=2=2//2GRH/.((((**/8*8=88=9=9@@@9@@@@9@9=9@@9@@9@@9@@9@@9@:@C@CCCCC@C@@=8@@=@@@C@@=*/*.((...(.( ((((.((( ( ..2/2=F=F=F=F=F@F=F=F=FF=F@GF@FGFFFGF@GFGFGGFGGFGGFGFFGFFGFGFGFGGGQHGGFGGGGFGGGGFGGGGGGGGGGGGGFG@GGGG@GGCGGCGCOGOOOWWZZZZWZZZZZZ\ZZZZ\ZZ\ZZ\\\Z\\\Z\Z\Z\\\ZZ\Z\\Z\Z\Z\\\\\\\\[Z\\\\YY[YYYXYXYYXYYVYYYYZ\\Z\ZYZZYZZZZZZ\Z\Z\Z\Z\\\\\\\\\\\\\\Z\Z\ZZZZZWWWWQWZWQ@==/=8=8=8==8=*=**(((.(./FQWWRHQRRWRWWZZZZZZZZZZRZRWRRHF3HRR2013HHHHH3H3H33H3H3HHH31.2RRHF2F3FHFHFHFHFF2HQRH2. .2GRF2/2.2/2/2/2HRH/  /FRRF=2/22=2/FHRQ2( ((((((((*=*88=8=9=@9@9@@9@@@9@9=@9@@9C@C9@C9@9@@9@CCCCCCCCCC@8==@@@9@@@@@=*/(.((.(( (((((.( (( ../2=2=FF=F=F=FF=F=FF=F@FF@F@FFG@FFGF@GFG@GGGGGGGFGFGFGFGFGGFGHGGGGGHGGGGGGGGGGGGGGGGGGGGGGG@GFGG@GGGGGG@GCGOOOOOTTZZ\ZYZZZZZZ\ZZ\Z\Z\ZZ\Z\\\\\\\\Z\[\\\\\Z\Z\Z\\\Z\\\\\\\[\\[\\\[Z[Y[YYYXYYXYYXYYYYYYZ\Z\Z\YZZZZZZZZZ\Z\Z\Z\Z\Z\\\\\\\\\Z\\Z\ZZZZZZWWWWQWZWQG==@==8==8=8/8/**(( (.(./=HWWRGQRQRWWZRZZZZZZZZZZRZRRRHHFHRH2 013HHHHRHRRHRHHH30 .FRRFF2FHFHHFHHHFHFFHRWH.. ..FRRF.2.2/2/2./2FRG2 ./HRQF2/=2=2=2/HQQ2.((((((**=*88=8=9@@@9@@@9@9@@9@8@9@@9@@@:@@9@9@C9CCCCCCCCCCC@8/=8=@=@@@@@=*/*(.( ((.(( (((((( (   ...2=F=F=FF=FF=F=F=F=FF@F@FFFG@FFG@FGFG@GGGGGFGGGFGGFGFGFGFGFGFGGQHGGGGGGGGGGGGGGGGOGOGGGGGGOGOGOGOOOOOOOOTOMTTTTWVZZ\ZZZZZ\Z\Z\\Z\Z\Z\\[\\\\\\\\\\\\\\\\\\\\\\\Z\\\\\\\\\\\[\\\\\[[[[[[[[[[[[Y[[[[[[[[Z\[\\\\Z[Z[\[\Z\Z\\Z\\\\\\Z\\\\\\\\\\\Z\\ZZZZZZWWWWZZWGCGCCCC@@@@@@8@=*/*((((((((((((.**(////FGWWWQQRQWWWZZZZZZZZZZZZWWWRRGHFHRR20013333331300 .2HWRFFHFHHHGHQHHHFHFHRWH2....FRGF2//2/2/2/2=HRH/ .2GRHF/2/F2=2=2GRQ2.(((((((**=*88@8@8@9C@:@C@9@@@9=@9@9@:@@@:@:@@9@CC9CLCCCLCCCC@8/=@8=@9C@@@@*/*(.((.(.((.(((((((((((((((((((.(  . /2/F=F=F=F=F=F=F=F@FF@FF@FFG@FFGFG@GFG@GGGGGGGGFGFGFGGGGGGGGGQGQGGQOQQGGOQOOOOOOOOOOOOOOOOOOOOOOOOTOTTTTTTTTVVWYZ\Z\Z[Z\Z\Z\Z\\\\\\\[\\\\\\\\\\\\\\\\\\\Z\\\\\\\\\\\\\\\\\\\\\\[[\[[[[[[[[[[[[[[[[[[[[Z\\\\\\Z\ZZ\Z\Z\Z\Z\Z\\\\\\\\\\\\\\\\Z\Z\ZZZWZWTWZZWTOCLCCCCC@@C@9=*/**/(((((((((((.((/**//*//=/=GRZWRQQRWWWWZZZZZZZZZZWZWWRRQHHHRR2  ..FRRQHFHGHQHQQHQHGHHFGRWH=1../FRRF2/2/2=2/2=FGRH/   ..FRQGF2=22=22=2GRQF.((((((((**=888@8@@9@@9C@:@@9@9@8@9@@9C@:@9@:@C9@CCCLCLLCLCLCC@9==9=@CCCCCC@8/***.(*(*.*(/(((((((((/(**(*(((((((((((((((((( . .1/=F=FFF=FF=F=FF@F@FFGFF@GFF@FGF@GFG@GGGGGGGGGFGFGFGFGHGHGHGGHGFGGGGGGGGGGGGGGGOOOGGGGGOGGGOOOOOOOOOOOOTOTTTWVWY\ZZZZZZ\Z\Z\Z\Z\Z\Z\\[\\\\\\\\\[\\\\\Z\\Z\Z\Z\\\\\\\\\\[\\\\\[\[[[[[[[[[Y[[Y[[[[[[Z[Y[YYZ\Z\\Z[Z[ZZZZ\Z\Z\Z\\\\\\\\\\\\Z\Z\Z\ZZZZZWWWWWZZOOCGC@@@@9@8=****/((.((((( (.(((.(*.*/*////=FQWWRQQWRWWWZZZZZZZZZZZRWWRRQHFHRH2  /HRQHFFHHGHQHQHQHQHGHHWRR2....FRQF2//2/2/2/FHQH2. /FRQF2/2=2F=2/FFQRF. ((((((((((**=8=8@8@9@CC9C@9@@@99@8@@9@C@:@C9@:@@:CCC:LCLCCLCCCC@8/8=8=CCCC@@8=*/(((.(((.((((((((/((((((((((((  ....2/2F=FFF=F=F@F@FFF@GF@FFGFGF@GFGFG@GGGGGGGGGFGGFGFGFGGGGFGHGGGHGGQGGGHGGGGGGGGGGGG@GFGG@GGGGGGGGOGOGOOGOOOOOOWZZ\ZZZZZZZZZ\Z\ZZZZ\ZZ\\\\\\\\\[\\\\\ZZZZ\Z\Z\Z\\\\\\\\[\[\\\[\XY[YYYYYYYYVYXYYYYYYYYYYYYYYZZZ\ZZZZYZZZZZZZ\ZZ\Z\Z\\\\Z\\Z\ZZZZZZWWWQQQWZWQG@====8=**/((.((((( (.( (.(..//FHWWRQHQRWRZRZZZZZZZZRZWRRRRHHFHRR1 2HWHHF3FHHQHQHQHGHHFHHRWH2. .2FRHFF22222FFHHHF. .2HQHF2=22=22=2=HQQF.((((%((((/888@8@9@9C@C9C@:@9@9@9=9C@9C@9@:C@:@:@CCCLCLLCLCCCCC@=**=8=@C9C@=8/((.(( (((((( . 1..2/=2F=FF=F@FF@F@FGFFGF@FGF@FGFG@GFGGG@GGGGFGGGGFGFGGHGGGHGGGGGHGGGGGGGQGGGGGGGGGFGFGG@GFG@GGGOGGOGOGGOOOOOTQTZZZZZWZZZZZ\ZZZ\Z\ZZZZZ\\\Z\\\Z\Z[\ZZZ\ZZZZZ\ZZ\\\\\\[\\[\\\\[Y[YY[Y[YXYYXYXYYXYYYXYYYVVTTWVYZZZZZYWZWZZZZZZ\Z\Z\\Z\Z\\Z\\Z\ZZZZZWWWRQQWWWQF@===*/*/(((.((.(((((  ( .(........//2GWWRQHQRWWWZWZZZZZZZZRZRWRQHFHHRH1 2HRRF2HFHHHQHRHHRHHHFHRWR2.. .2HQRHGHHHQHRQHF.  ..FRQH2=2=22=2=2=HQRF.(((%((((((**=8@8@9@@9CC@:@@9@9@@9@9@:@@:@C:@:C@:@:CCCLCLLCCLCCCC@8/8/8@@C@@9=8/*(.(.((  ....1/2/=F=FFF@FF@FF@FFG@FFGF@FGFG@GFGG@GGGGGGGGFGGFGGGFGGGHGGHGGGHGGGGQGGGQGGGGGGGGFGFG@GGFGGGGGGGGOGOGLGOOOOOOTWYZZZZZZZZZZZ\Z\ZZZ\Z\Z[Z\\\Z\\\\[\Z\ZZZZ\Z\ZZ\Z\\\\\\\[Z\[\\\Y[Y[YYYYYYXYYYYXY[YXYYYYYVVVVTTYYZZZZZZWYWZZZZZZ\Z\Z\\Z\\\\Z\Z\ZZZZZWWWWQQWWZQF==//***(.((((((.((((  . ./2/2F=2=2=2/FHWWRRQRQWRWWZWZZZZRZRZRWRRRHFFHRH1.FRRHFFFHHQHRQRQRGHHGHHQWR2.. ./FHRRRWRRQHF2.  .2QRHF/2/F2F2=2=2HQQF.( (((((((((((**=8@9@9@@:@C:@:@@9@9@9@@9C9CC:CC9CC9CC:CLCLLCLLCCLCCC@=*8=8@CC@@=8=*.(((((((  .1..1.2.2/FFF@FF@F@FFGF@GF@GFGF@GFGFG@GFGGG@GGGFGGGGFGGGGGGGGGGQGGGGGQGGGQGOOGGGGGGGGGGGGGGOGGGGOOOOOTOTOTTTTTTWTYZ\\ZZZZ\Z\\\Z\\\\\Z\Z\\\\\\\\\\\\\\[\Z\\Z\Z\\Z\\\\\\[\\\\\\\\[\[[[[[[[[[[[[[[[[[[[[[[[Y[YYYYYYYYZZZZZZZZZZZ\Z\Z\\Z\\\Z\\\\\Z\ZZZZZZWWWQWZZQG@====8/**/*/*/*/*/*/(.(...//2FFGHQQQRQQQHGHGQWZWQQQWWWZWZZZZZZZZZWWRWRGHHHHRH..HRRGFHHGRHRQRQRQRQQHHGRRWH2.. ..1=2HFHHFF2..    ./HQHF22F22F/F22/FFRQF.((((((((((((((*/8=9=@9@:@CC9C@:@9@9@@9@:@C:CC:C@:CC:C@:CLCLLCLLCCLCCC@=8=8@CCLCC@@8**.(((((((*(*(((*(((  .0..1./1/2/2/FFF@FFFGF@FFGFGF@GFFGFG@GFGFGGGGGGGGFGFGGGGGGQGQGGQQQQGGQOQOGOQOQOQOOGOOOGGGGOOOOOOOOOOOTOTTTTTTTTVTVWYZZ\Z\Y\Z\\Z\\\\Z\\\\[\Z\\\\\\\\\[\[\Z\Z\Z\Z\Z\\\\\\\\\\[\\\\[\[[\[[[[[[[[[[[[[[[[[[[[[[[Y[Y[YYYYZY\ZZYZZZ\ZZ\Z\Z\\\\\\\Z\Z\\Z\ZZZZWWWWWQWZWG@@===8=*=*/8/*8/8/**/*////=FQQQWWWWWWWWWWWQQWWWWRQWWWWWZWZZZZZZRZWWWRRRHFFRRH1 1HWRHFHHQHQRQQRQRQRQQHRQWWHF... ..../././..(   ( (.2FQRHF2=2F=F2F2=2=HQRF.((((((%(%(((((**8=9@@:@:@:C@:@:@@9@9@:@C:@CC:CCC:@C:CC:LLLLLLLLLLLLLLC=@@9CLMLLCC@@8**((((((((((((((((***/***(((((((((((((  ..1....2./1/1/2=F@FFG@FFGF@GF@FGFG@FGFGFG@GFGGG@GGGFGGFGGGGGGGGGGGQGGGGGQGGGGOGQOGGGGGGGGGGGGGOGGGOGOOOOOOTQTOTTTTTTWVZ\Z\YZZ\Z\\Z\\\\Z\\Z\Z\[\\\\\\\\\[ZZ[Z\Y\Z\Z\Z\\\\\[\\[\\\\[\[[[[[[[[[[Y[[[[[[[[[[[[Y[YY[YXYYVTVVYZZZZZYZZZ\Z\Z\Z\Z\Z\\\\\Z\ZZ\ZZZZWWWQQWZWGF===*/**/*****/*/*.*/.//=FHQRWRRQRHQHQRRQWWWWZWRQQRWRWWWZWZZWZZZRZRRRRGHHFHRH 1HRRFHFHHRQRQRWRWRQRQHGHRWRF2..       ../FHRHF2F2=2F2F2=2/2HQRF.( (((((((((((((*/*8@9@9@@:@:CC9CC9C9@9@:CC:CCC:C9CCC:CCC:LLLLLCLLLLLCLC@8=@8CLLCCC@@*/((((((((((((*(**((((( . ...2/2//2./2/.2=FF@FFGF@FGF@GFGFGFG@GGFGFGFGG@GGGGFGGFGGGGGGGQGGGQGQGGGQGOGGGOQGGGGGGGGGGFG@GGGGGGGGGGOGOOGOOOGOOOOOTWWZZZZZZZZZZ\ZZ\Z\ZZ\Z[ZZ\\\YZ\\ZZZYZZZYZZZYZYZZ[\[\\[\\\\\[\X[Y[YYYYYYYYYYYYYYYYYYYYYXYVVVVTTOOOOTWZZZZZYZZZZZZ\ZZ\Z\ZZ\ZZ\Z\ZZZZWWWRQQQWWRG2=*.*(/(((.(.(((((.(../FHQRRQHHFF2FFF2FFHHRRRRRHQHQRWRWWZWZRZWWZRWWRRRHH23HR3 2HRHFFHHQHRQRRRQRRQRHQHHRRRH2..      ..2FHQHF2F2F2FFF2F2=2=HRQ2.(((((((((((((*(=8=9@:@:@CC:CC9CC9C@:@9CC@:CC:@C:C@C:CC:CLCLLLLLLLLLCCC98=8@@CCC@@8** (((( .1.2/2//2/=2//2/2=2=FFGF@GFGFGFG@GFGFGFG@GFGG@GGGGFGGFGGFGGGGGGQGGGQGQGGGGQGQGGGOGOGGGGGGGFGFGGGG@GG@GOGOGGOOGOOGLOOOOOWYZ\ZZZZZZ\ZZ\ZZ\Z\ZZZZZZZ\Z\YZZ\ZZZYZYZYZZZYZZZZ[ZZ[\[\\[\Y[Y[YY[Y[YYYY[YYXYYXYYXYYVVVVVVSTMOMOOOOTWZZZZWZZZZZZZZZZ\Z\Z\Z\ZZZZZZZWWWRQQHRWWGF///.((.((.(((.(.(../=FHQRQHFF2F2F2=2F22FFFHHHHHHGRQRWRWWWZZRZWWWWRWRHHFF3RR22RRHF3HHHRQRRRRRWRRQRHHHHQRRH2..    ../2HQHHHF2F2FF2FFF2F/2FHWH=.( ((((((((((((((((***8=8@9@CC9CC:CC:CC9C@9C9CCC:CC:CC:CCC:CCLCJCLLLLLLLLLLC@@8=@@CCC@9=**((((((((((((((( ..1/2/2=2=F2=2/2/F=FFF@FGFGFG@GFGFG@GFGFGFG@GFGGGGGFGGFGGFGFGGQGGGGQGQGQGOGQGGGOGQGOGGGGGGGG@GGGGGFGGGGGGOGOGOOGOOOOOOTWWZZZZZZZ\Z\Z\Z\Z\Z\Z\Z[Z\\ZZZYZZZ\ZYZYZZYZYZZY\YZ\[Z\\\\Z[YY[Y[YYYYYY[YYXY[YYYXYYYYXYYVVVSTTTMOTMTTWYZZZZYZZZZZZZ\ZZ\ZZ\ZZ\ZZZZZZWWWRRQQQWWHF//*.*.((.((.((.(.//=HQRQHHFF2F2F=F2F2F=2F2FFFHFHQRQRWWWWWWZZRZWWRWRRQHHFFHR3 FRRH3HHHQRRRRWRWRRRRQRGHHHRRQH2..       ..2FGRQHHF2FFFFFFF2FF2F/FHWH2.(((((((((((((((((/*88=9@9@C:@CC:@C:CC:@C9C:@CC:CC:C@:CCC:CCLCLLJLLLLLLLLCLC@8=@CCCC@8=*((((((((((((((%(( 1./1//2==F=F==F=2=FF=FFGF@GFGGFG@GFFG@GGGFGFGG@GFGGGGFGGFGFGGGGQGGQGQOGGQGQOGOQGOOOGGGGGGGGGGGGGGGGOGOOOOOMOOTTOTMTTTTTYZ\\Z\Z\\Z\\\\\\\\\\\\\\[Z\\ZYZYZ\Z\Z\ZZYZYZZ[Z[\Z\\\\\\[\[[\[[[[[[[[[[[[[[[[[[[[[[[[Y[Y[YYXVVVVVVVVYYZ\Z\ZYZZZZ\ZZ\ZZ\Z\Z\Z\Z\ZZZZWWWRQQWWWQF===//*/*(/(/(/*///FGQRQGHFFFFFFFHFHFFFFFFFFHFHGGQQQRWWWWZWZWZWZRZRRRQHHFHRH20001111323223110  2FRRHHHGRHRQWRWWRWWWRRRQRHQHQRRGF2/.. . . ../2FGRRRGHFFFFFFFFFFFFF22=FRRG.. (((((((((((((((((((*/8*8=9@C9C@CC:CCC:@C:C@:@:C9C@:CCC:CCCC:CLCLLLLLLLLLLLMLLCC@@CMLLCC@8=*/**/*****(*(((((((((((((((( .2.2=/2F=2=F=F=F=FFF@FFGF@FGFG@GFG@FGFGG@GFGFGGG@GGGFGGGFGGGGQGQGOQOQOOQOOQOOOOQOQOOOOGOGGGGGOGOGOOOOMOOTOTTTTTTTVTVWYYZ\Z\Z[Z\\\Z\\\\\\\Z\\[\\Z\\\ZYYYZ[\\\\\\\Z\[Z\\\\\\\\\\[[\[[[\[[[[[[[[[[[[[[[[[[[[[[[[[Y[XYYXYVVYVYYYZ[\ZZZZZZZZZZZ\Z\Z\Z\Z\ZZZZZZWWWWQQRWZQG=====*/*/*/*.*//=FGQWQHGFFGFHFGHGHGHGHFFHFFFGHGHQRQRWWWWWZWZWZRZRWWRQHHFHRR133HHHHHHHHHHHHHHHH ./HWRQFHHRQRWRWWWWWWWWWRRQQHQHQRWRHF/2/...../.2/2FHGRRWQHHFFFFHFFHFHFFFF2F2FRQF/ ((((((((((((((((((((((**=88=99@@:CC@C:CC:CCC9CC9@:@:C@:CCC:CCLCLJLLMLMMMMLMMMMMMMCCCCLMMMLCC=88/8*8=*8/8*/(*((((((*((((((((%(((( 1.//2==2=F=2=F=FF@FFGF@FFGFG@GFGGFGFG@GFGFG@GFG@GGGFGGFGFGFGGGGOGQGOGQGOOQOGGQOOOOOOGGGGGGGGGGGGGGGOOOOOOMOOTOTTTTTTVWYZ\\ZZ\Z\Z\\Z\Z\Z\\\\Z\Z\YZ\ZZYZYYZYZ\Z\Z\\Z\\Z\\\\\\\[\[[[[[[[[[[[[[[[[[[[[[[[[[Y[Y[Y[Y[Y[XYVVVVSVVVYYZZ\ZZYZZZZZZ\ZZZ\ZZZZZZZZZZZWWWRQQQWZRF=///*/(/((.(.(//=HQWQHGHFHHFHGHGHGHGHFGHFFHFHFHGHQQQRRWWWWWWWWZRWWRQQHHFHRH20H333133313111113HH0.2HWRHHHQRQRRWWWWWWWWRWRWRRHHHQRRRRRGHF2=22=FFFHQRRWRRQHHFFFHFHFHFHFFFFF2FFHQRF.( (((((((((((((((((((((((((/*=*88@9@C:CCCC:CC:CCC9C@:@:@C:C@:CCC:CCCCLLLLMLLLLMLMMMMLL@@CCMOMLC@@88*/***/****((((((((((((((( ..2/2/F=2=F=2=F=FG@FGFGF@FGFGG@GGGFG@GGGFG@GFG@GGGGGFGGFGGFGGGQGGGOQGGGOGOGOGGOGOQGGGGGGGGGGGGGG@GGGGGGLGOOOOOOOOOOTOTWWZZ\ZZZZZZ\Z\Z\\ZZ\Z\Z\YZZZ\ZYTVWVWYZZZZZZ\Z\Z\ZZ\[[[[[[[Y[[Y[YYYYYYYYYYYYYYYYYVYYYYYVVVVSTTTMTMOTOTTWTZZZZZYWZZZZZZZZZZZ\ZZZZZZWWWWRRQHQRWRF//.(.(((.((..//FQRQHFFFHFHFHHHGHHGFHFFFFF2FFFFHHHHRQRRWRWRWWRWWRRRRHGFFHRR 1323H1 .HWRHHHHQRRWRWWWWWWWWRWRRQRHHHHHRWRWRRHRHQRHRRWRWRRQHHFFHFHHFHFHFHFHFFF2FFHWH2.( (((((((((((((((((((((((((**88=889@CCC9CCC:CC:CCC9C@:@:C@:CC:C@C:CLCLLLLLMLMLLLOMOMLL@@=@CLCC@@=*/((.(((((.(((((((%(((((  1.2/2=2=F=2=F=FFGF@FGFGFGFG@GFGFG@GFGFG@GFGFGGFGGGG@GGGFGGGGGGGGQGOQGQGOGOGGOGOOGGOGGGGGGG@GGGGGGGGGGLGOGOOOOOMOOTOTQTZZ\ZZZZZ\ZZ\Z\Z\Z\Z\Z\ZZWZZZZWTWTTTTTWYYZZZZZZYZ[YZ[ZYYY[Y[YYYY[YY[Y[Y[YY[YYYYYVYVXVVVVSTVTTMTOMOMOOTOTYZZZZWWWWZWZZZZZZZZZZZZZZZWWWRQQHQWWRF/..((.(.((..(/2GQRGFFHFHFHGHQHHGHHGFHFFFF2F2F3FFHGHRRRRWRWWRWRRWRQRHHF2HRH13303H0 2HWRFHHHRQRRWWWWWWWWWWRWRRRQHHHHHRRRWRWWWWRWRWRRRHHHFFHHFHHHFHHHHFHFFFF2FFQRH/.(((((((((((((((((((((((((((*.8*8=89@:@CCCCC:CCC:CC9C:@C:CC@:CC:CCCCCLCLLLMLLLMLMMLMLMLC@=@@CLGC@==*/*((((*(((((((((((((((( ../2/2==2=F=F=FF@GFGF@FGF@GFGG@GGFGFG@GFGFG@GFGGG@GGFGGG@GGGGGGOGOOGOGOGOOGOGOOGOGGGGGGGGFGGGGG@GGGGGOGOOOOOOMOOTOTQTWYZ\ZZZZZZ\Z\Z\Z\\Z\Z\ZZZZYZ\ZZVTTWTWTTTWVWVYVYYYY[[Z[[[Y[Y[Y[YXYYY[YYYYYYYYYXYYVXYYVVVVVVVTVTTTTTMTTTTWTZZZZWWWZWZZZZZZZZZZZZZZWWZRWRRQGRRWRF/...(((.(.../HQRQHFHFHGHHQGHQHGHGHHFFFF2F2F2FFFHHHQRRRRWRWWRWRRRQHGHFHHRH.33 1H1 2HWRHFHHRRRWRWWWZWZWWWWRWRRRQHHHHHHQRRRRRRRRRHHHHGFHHHHHHHGHHHHGHHGFHFF2FHQQF.( (((((((((((((((((((((((((((((*(=*8=89@C:CCCCC:CC:CCC9C9CC:CC9CC:CCCLCLCLLLLMLMMLMOMLMOLL@@=@CLLC@@==**(*((((((((((((((((((((((  1.2///F2=F=2=FF@FFGFGF@GFFG@GFGFG@GFGFG@GFGG@GGGGGG@GGGGGGGGGGGGOGOOGOGOOGOGGOOOGGGGGGGGGGGGGGGGGGGLOOOOMOTTTTTTTTTVVYZZ\Z\Z\\Z\\\\\\\\\\\\\ZZZZZZ\ZZYYVYVYYYVYYYYYY[\[\[[\[[\[[[[[[[[[[[[[[[[[[[[[[[[Y[Y[Y[YXYY[YXYVVVVVVVYVZZZ\ZZYZWZZZZZZZZZZZZZZZZZWWWWRQRGRZRF///(..(.(.(.//FQRQHGFHGHQGQQRQQQHQHGHGHFFFFFFFFFHHHQHQRQRWRWWWWRWRQRHHFFQRH 0H3 3H3  .2QWRHHHQRRWWWZWZZZWZZZWZRWWRRRQQHQHHHHQHQHHGHHHGHHHHHHQHQHQHQHQHHFHFFFFFFHWH2( ( ((((((((((((((((((((((((((((***88@89@C:CCCCCCC:CC:CCC9CC:C:CC:CCCCLCLLLLLMLMMMMMTMTSMTMCCCCMOMLC@@==8*/*****(((((((((((((((((((  0. ..2/2=2=2=F=F@FGFFG@FFFG@GFGG@GFGFGFG@GFG@GGFGGG@GGGGGGGGGGGOGOOOOQOOOQOOOOOOOOOOGOGOGGGOGGOGGOGOOOOMOTTTTTTTVTVVYVYYZ\\\Z\Z[\\Z\\\\\\\\\\\Z\ZZ[\Z\YYYYYYYYYYY[Y[[[\[\[\[[\[[\[[\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[Y[YYYYYYYYZYZZZ\ZZZZYZZZZZZZZZZZZZZZZZWZWWWRQQQRWWF=/./*.*(/*/./=HWRQGHGGQQRQRQQRQRQQGHGHGFFFFFFFFFFHGHQRQRWRWRWRWRWRQQHGHHQRH.0H3003H1  ./RWRHHQRQRWWWWZZWZZZZWZWZWWWWRRRQRGQHQHQHQHRQHQHRQHQQQQHQHQQHQHGHHGHFFFFFRRF/.(((((((((((((((((((((((((((((((**=*89=:@C:CLCLC:CCC:@C:CC:CC9CCC:LCLCLLMMLMMSTSTSSVSVSVSSLLCLMSTMMGCC@8=8=8/**(((((((((((*(((((((((((((((((  ....1/2//==F=F=FFF@GF@FGFG@FFGFGFGG@GGFGFG@FGFG@GGGGGG@GGGGGGGGOGGGOGOGOGOOOOGGOOOOGGGGGGGGGGGGCGGGGCGOOOOMOTOTTTTTTTTWVYZZ\Z\ZZ\Z\\\\\\\\\\\\\ZZZZZZ\ZZZYYVVVVYYYY[YY[[[[[[\[[[[[[[[[[[[[[[[[[[[[[[[[[Y[Y[Y[YY[YY[Y[Y[YYYZYZZ\Z\Z\ZZYWZWZYZZZZZZZZZZZZZWZRWWRQQHHQWRH//..((.((.(//FQRQHHGHQHQQRQRQRQHQHRGHHFFFFHFHFHFFFHHGHRQRRRWRWRRRQQHHFFHQRF 1H30003H3  .2HWRHGHQRRWWWZRZZZZZZZZZWZRWWWRWRRRRQRHRHRQRGRQRQRQRQHRQRRHQHHQHHGHFFFFFHRQ2.( ((((((((((((*((((((((((((((((((**8=899@C:CLCCLCCCC:CCC:@:C:CC9CCCCCLLLLLLMLMMMMMTMTMSTSTMCCCCOMMOLC@==88*****(((((((((((**(((((((((((((((  1.1.1/.2/2/F2=F=FF@FFFGF@FGF@GFGFG@GFGFGG@GF@FG@GFGG@GGGFGGGGGGGGOGOGGOOGGGOOOGOGOGOGGGGGGGGGGGGGGCGCGGGLGOGOOOOOMOOOOTOTTWVZ\ZZZZZZ\Z\Z\Z\\\\Z\ZZZZZYZZ\ZYTTQTTTVVYYYYY[[[\[[[[[[[[[Y[YYYYY[Y[YYYYYYYYYYVVYVVVYVVYYVYYYYZYZZ\ZZZZZZZWWWWWWWWWZWZZZZZZZWZWWWWWRWRGHQRWRF/... (../HQWHHFHGHQRQQRQRQHRGHHHFFFFFFHRQRHHF2FFHHHHQRQRRRRRQHHHHF2FRH21H100003H3 1HWRHHHHRQRWWWZZZZZZZZZWZWZWWRWRRRRRQRRQRQRHRRQRQRQRRRQRQRQRQHHHHHFHF2FHQRF/.( ((((((((((((((((((((((((((((((((((((**8=89@:CCCLC:CCLCC:CC:CC:C:CC:CCLCCLLLLLLMMMMMMMMMTMMOML@@@@@COCC@@=8/(*(((((((((((((((*(*((((((((((((((((  . ..1/2//2=2==2=F=FF@GF@FFGFGFG@FGFGFGG@GFGFGF@FG@GGFGGG@GGGGGGGGOGOGOGOGOGOGOGOGOGOGOGGGGGGGGGG@GGGGGCGOGGOOGLOOOOTOTOOTOWTWZZ\ZZZZZZ\Z\Z\\Z\\Z\ZZZZZZWZZZZWOTOTTTVVVVYY[Z[Y[[Y[Y[YYY[YYY[Y[YYYYY[YYXYYVYVVVVVVVVYVVYYZYZ\Z\ZZZZYWWWTWWTWTWWWWWZWZWZWWZWZWWWWWRRQHGHQWRH..( ((...FQWRFFGHQHQQRQRQRQRQHQHHHFFFHHQRRRRRHHF3FHHHHRHRQHRHQHHHF2FHHR13H100001H3 1HWRHFHRRRRWWZRZZZZZZZZZZZRZWWWWRWRRRRRRRRRRQRRRWRRRRRRRQRQHRGRGHHFFFFFHRQF.( (((((((((((((((((((((((((((((%(((((((*88=89@C:CCJCLCCJCLC:C:CC:CCC:CCCLCLCLLMLMMTMMMMMTMMTMMML@=@9CLCCC@==*/*(*((((((((((((((*((*(((((((((((((((((  .1../1/2/=2=2=F=F=FFF@FF@FGF@GFGGFG@GFGFGFG@FGF@GFGGGGGG@GFGGGGGOGOGOGOOGOGGOGOGGGGGOGGGGGGGGGGGGGCGCGGGCOGOGLOOOMOOMOOTOTTWVZ\ZZZZ\Z\Z\\\\\\\\Z\ZZZZZYZZZZZWTTTTYVYYYY[[[[[[[Y[[Y[Y[YYY[YY[YY[YYYYYXYYYXYVVVVVVVYYYYZY\Z\Z\ZZYYWWVWTWTWTWQWWWWWWWWWWZWWWWZWWWRWRRQHHQRWF1.(   (./FRRQHFHGRQQRQRQRQRQRHHHGFFFHHRQHHHQRQHHFFFHHHQHRHRHQHHHFF22HRH1331000 00 000HH0 2HWRHHHHRRWRWWZZZZZZZZZZZZZZZWWWWRWWRWRRWRWRWWWWRWWWWRWRRRRQHRHHHHFFF2HQRF/ (((((((((((((((((((((((((((((((%(((((((((**8=9@9CCCLCJCLCL:LC:C:CC:CCC:CLCCLCLLLMLTMMMTMMMMTMTMOM@@@=@CLCCC@==*/(*(*(((*(((((((((/((/(((((((((((((((((((( 1 .1.2//=2/=2=F=F=F=F@FGF@F@GFGFG@GFGFG@GFGFG@F@FG@GFGGGGFGGGGGGGGOOOOGOGOGCGGOOGGGGGOGGGGGGGGGGGGCGGGCGOGOOOOOOMOTTTTTVTVWVYYZ\\Z\Z[\Z\\\\\\\\\\Z\Z\ZZZZZZ\ZZYYYY[Y[[[[[\[[\[[\[[\[[[[[[[[[[[[[[[[[[[[[[Y[Y[Y[Y[Y[[[\\\\\\[Z[ZYZYYYWYWYWWVWWVWYWZWZWWWZWZWWWWWWRQQQHGRWRH/..(( (../HWRGHGHQQRQRWRWRRQRQQQHHHFHQQRFF/2FHQRHHHFHHGHQHQRGHQHHFF2FHRH.3H100000 000 00HH0 .2HWRHHHQRRWWWZZWZZZZZZZZZZZZZZZZWZWWWWWWWWWWWWWWWWWRWWRRWRQRQHQHHHFFFFHQQ2.( (((((((((((/(((.(((((((((((((((((((((((**889@C:CCLCJCLCLC:CC:C:CC:CCCLCLCLCLLMMMMTMMTSTSVVSVVSMCCCCCOMLLCC@=88/8*/*/(*.((((((((((*(*(((((((((((((((((( ..1/1/2/=2=2=F=2=F=FF@FF@F@FFG@FGFGG@GFGFG@GFGFFGFG@GGGGGG@GGGGGGGOOOOOOOOOOOOOOOGGOOOOOOGOGOGGGGGGOGOOLOOOMOMOTTTTTTVTVVVVYYZZ\\\Z\\Z\\\\\\\\\\\\Z\ZZ\ZZ[Z\Z\YY[[[[[[[\[[\[[\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[Y[[[Y[\[\\\\\[\[\Y[ZYZYZYZYWYWWVWWYWZWWWWZWWWWZWWWWWWRQQHGQWRG2/.(.(../FQWRGHGGQRQWWWWWWWWRQRQHGHGRRQF2././/FHQRHFHHGRHQRHRHHHHFF2FHRH 0HH100000110 00 13H1 .2GWRHHGRQRWWWZWZZZZZZZ\ZZZZZZZZZZWZWZWWZWWWWWWWWWZWWWWWWRRRQRQHGHFHFFHQRF/.((((((((.((((.((((((((((((((((%((((%(((((**=88@C:CCLCJCLCLCLC:CCCCCL:CLCCLLLMMMTSTSVSTUVVVVXYVVVLCLCLLMTMOL@@==88=*8*/**(.((((((((((*(((((((((((((((((((( .1./.2/2==2==2F=F=F=FF@F@FF@FGFGFG@GFGGFGFGFG@GF@GFG@GGG@GGGGGGGGGOOOGOOOGGCGCGGGGGGGOGGGGGGGGGGGGGCGGCGOOOOOOMOOOTTTTVTVTVWYYZ\\Z\Z\Z\Z\Z\\\\\\\Z\Z\ZZZZZZZ\ZZYYY[Y[[[[\[[\[[[\[[[[[[[[[[[\[[[[[[[[[[[Y[YY[Y[Y[Y[\\\\[\Y\YZ[ZZ[ZYZYWYWYWWVWWYWWWWWWWWWWWWWWWWRWQQQQHHQRWH/..   (.FRWRFHGHQQQRWWRWRWRRQRGHHHQRQF/.. ..1FRQHHFHHHGHHQHHHHFF22FHRF 0H31000.101100 003R1 /HRRQHHHQRRWWWZZZZZZ\ZZZ\ZZZZZZZZZZZWZZWZWZWWZWZWWWWWRWRWRQRQHHHHFFFFRQH/.((((((((((((/(*(((((((((((((((((((%((((((***=89@C:LCLCLCJCLCCC:CLCJCCCL:CLCLLLLOMMTMSTSTSVVVSVTSMC@CCCCLOLC@@==*/*=*.**.*(.(((((((.((((((((((((((((((((( ..2//2=2=F2=F=FF=FF@F@FF@FG@FGF@FGFGG@GFG@GFGFFG@GFGGGGGG@GGGGGGGOOGOOOOGCGGGCGGGGGGOGGGGGGOGGGGGGGCGOCGOGOOOOOOOOOMOTOTOTTTWYZ\ZZZZZZZZ\Z\Z\Z\Z\ZZZZZZZYZZZZZYYYYYYY[[[[[[[[[[[[Y[Y[YY[Y[Y[Y[YY[YYYYYYVYYVVYYYYZZ[ZZZYZYZYZYZYZYWWWWTWOWQTWWZZWWWQQQRWQWRWWRWRQRQHGHGWRG2. .FRRGHFHQQRQWRWWRWWRWRQHHHHRRH2.  2FRRFFFFHHHHHHHFF32222HR20H310 01011011 00 02H31FRRHFHHHRRWRZRZZZZZZZZZZZ\ZZZZZZZZZZWZWZRZWZRZRZRZRWWWRWRRQHQHGHFFFHRGF. (((((((.((.*(/((.(((((((((((((((%((((((((***8=9@C:LCJCLCLCJCCLC:LCLCLCLCCCLLLLMLMMTMMMTMTMTMTMTLC@@@@@CCCC@==/***.*/(/*.((.(((((*(*((((((((((((((((((( 1.2.2/=2==F=F=F@FF@F@F@F@FFF@FGFCFG@GGFGFGFG@GFFGGGG@GGGGGGGGGGGGGOOGOOOGGCGGGGG@GGOGGGGGGGGGGGGGGOGCGOGCOGOLOOOOOMOTOTTTOTWTYZ\ZZZ\ZZZZZZZ\Z\Z\ZZZZZZZZWZWZ\ZZYYYYYYY[Y[[Y[Y[YYY[YYYYYY[YY[YYYYYYXYYXVVVVVVYYYZ\ZZ[ZYZYZYZYZYZYZYWWWTWQTWWZZZZZZWWWQQQWRWQRWQRQQQHGHHWWH/.    (.HQRHHGHQHQRWWRWWWRWRRQHHHQRRH.  2HRHF3F2FHFHFF3F2221FHH21H3 00.011111110 03H30.FRRHFHHRQRRWWZWZZZZZZ\ZZZZZZZZZZZZZZZZZZZWZRZWZWWWZRWRWRRQRGHHHFFFHQRF2 (((((((((((.**(*((((((((%((((%((((((((((***88=9CCCL:LCJCLCLCJCCLCLCLCLLCLLLLMOMTMTMTMMTTMTMTMOL@@@@C@@C@@===//*/(/*(/(/(((((((/(((((((((((((((((((( ../2/2==2=F=FFF@F@F@FFF@F@F@GF@FG@GFG@GFGFGFGF@GFGGGGG@GGGG@GGGGOGOGOOCGOCG@GCGGGGGGOGGGGGOGOGCGGGGOGCOGOOOOOOOOLOOTOTMTTTTTWYZ\ZZZZZZZZ\Z\Z\Z\Z\Z\ZZZZZZYWZZ\ZYYYYY[Y[Y[Y[[Y[Y[YYY[Y[Y[Y[YY[Y[YXYYYYYVVVYVYYYY\Z[ZYZYYZ[ZZZZZZYZZYWWWTWQWZWZWWWWZWWRQQQQQWQRQQRQQHGHQRWH/  .HRQHHFHQQRQWWWWWRWRWRQHGHRWRF.  1HRRF2F3FHFFHFF322222RH11H30 011111111100 01HH0.2RRHFHHHRRRRWWZZZZZZZZZ\ZZ\ZZZZZZZZZZZZZZZZZWZRZWWWWWRRRRQHQHGHFFHQRH/.( ((((((.((/(*(/*.*.((((((((%((((((((((((((**/88=9CCCL:CLCLLCCLCLCLCLCLLCLLCLLLMMMMTMMTMTMTSTMTMOC9@CC@@@C@@===/*.*/.**.*((((((*((*((*((((((((((((((( 0.2//2=2=F2=F@F@FF@FG@GFF@FF@FGFGF@GGFGG@GFG@GFGG@GGGGGGG@GGGGGGOGOGGGOCGGGGGGCG@GGOGGGGGGGGGOGGOGGOGGLGOGOOOOOMOTTTTTVTVTYYYZZ\\\\Z\ZZ\Z\Z\Z\Z\Z\Z\Z\ZZZZYZ\\\Y[Y[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[Y[[Y[Y[[[\\\[Z[\[\Z\[\[\[\Z[ZZYYWYWYZZZQWQQWWWWWWQQQQQWQWQQQQQGGQRWH2.   (1HWRGHGHQQRQWRWWWWWWRRQRHQRWRH/   .HRRHFFFHFHHFFFF2222FRH 1R3 01112222121110 1HH1.FRQHHFHHQRRWWWWZZZZZZ\ZZ\ZZ\ZZ\ZZZZZZZZZZZRZZRZWWWWRWRWRQRQHHHFFHQRGF..(((((((((*.*(*.**((((((((((%((((((%((%((((***8*8@8C:CCL:LLCLCLCLCLCLLLCLLLLLLMLMTMTSTSTSVTVVVSVSMCCCMLLCCCC@C@==/*/(/(*.((((((*(*(*(*(*((((((((((((( ./2/=2==2=F=FF@F@F@FF@GFG@FGF@FG@GFGCFGFG@GFGFGGGGGGGGGGGGGGGGGOOOGOGGOGGCGCGGGGCGOOOGGGOOGOOGOOGOCOGOOOOMOMOTTTTVVVVTVVYYYYY\\\Z\[ZZ\Z\Z\\\\\\\Z\Z\Z\ZZZZ[Z\\Z[Z[[[\[[[[[\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[Z\\\[\[Z[\[\[\Z\[Z\[Z\YZZYWYZZZWOOGOGQWZWWWQQWQQWQQQQQQHGQWWH=..  ./HWRHHGHQRQWWWWWWWWWWRRQQHRWWHF..  .FRRHF3FFHFFFH3F2222HRF 2H30 01112323232111013H3 .2RRQFFHHQQRWRZWZZZZZZZZZZ\ZZ\ZZZZZZZZZZZZZZZZZWZRZRWWRWRQRGHGFHGHQQF/.(((((((.((*.*(*.*(/(((((((((((((((%((((((((***=*8=@9CCLCCLLCLCLLCLLLLLLLLLLMMMTSSVSVVVSVVVXVVYVVVMLMMTMLLCCCGC@@///*/*.(((((((*/(*/(*.*(.(((((((%((( 1./2/2=2==FF=FF@FFFG@FGF@FG@GFG@FG@GGG@GFGFGFGGG@GGGGGGGGGGGGGGGOGGCGCGGCGGGCGG@GGOGOGGGGGOGGOGGOGOCGGOGOOOOOMOTTTTTTVTVTYYYYZ\\\ZZZZZZZ\ZZ\Z\Z\Z\ZZ\ZZ[ZZZZZ\Z[Y[[[[[[[[[[[[[[\[[[[[[[[[[[[[[[[[Y[Y[YY[Y[Y[\\\[Z[Z[Z\Z\Z[\Z\Z\ZZZYZYWZZZZTGGGGGGGWWWWQQQQQQQRQQGGHGHWRQ2.(   /HWRGFHGHQRQRWRWWWWRWRQRQHQRWRF1.   1HRRF2F3F3FH3FF222.2HR23H20 01121323223111013H3 1HRRFFFHHRQRWRZRZZZZZZ\ZZZ\ZZZ\ZZ\ZZZZZZZZZRZRZRZRWRRRRRQHHHFFFHQRF2.( ((((((*.*(.((*.*(((((((((%(((((((((((((%(((***=88=9=:CCLCLCLCLCLLLLLLLLLLLLLMMMTSTSSTSTSVSVVVVSVMLLLMTMLC@@CG===/*.(.((((((((((***/****((*((((((((((( .2.2=2=2=2@FF@F@F@FG@FGF@GFG@FG@FGFGFGFG@GFGGGGGGGGGGGGGGGGGGGOGGGGGGCGGCGGGCGGCGOGGGGGOGGGOGGOGOGGOGOOCOOOOOOMOTOTTMTOTTTWVYZ\ZZZZZZZZZZZZZZZZ\ZZZZZZZZYZYZZZZYYYYYYYYYYYYY[YY[YY[Y[Y[YY[YYYYYYYVYVXYYYYYY\ZZZYZYZZYZY\ZZZZYZZYZZWWTWZZWQFF@F@FGQWZWQQQQQQQQGRHGHHQRWH/..   /HRRHFHHGRQRWRWWRWWRRWRRHGHRRRHF1.  2HRH32223F3F2F2222.2HH23H3 0011232323222110.3HH0.FRHH2FHHHRRRRWWWZZZZZZZZZZZZZZZZZZZZZZZZRZZWZRWRRRRRRRHHHHFFHHQRFF.((((((.(((*/(*.*(*(*(((((((((%((((((((((%(((((%((****88=8@@@:CCLCLLLCLLLLLLLLLLLLMLMOMMMTMTMMTMTMTSTMMMLCCLLLLC@@G@F==//(/(((((((((((**/****(.(((((((((((((((  .1.2/2=2=2=F=F=FF@GF@GF@FG@GFG@GFG@G@GFGFGG@GFGGGGGGGGGGGGGGGGGGGGCGCGGGG@GCGGGCGGGOGGGGCGOGGGGOGGOCGOGOOOOOOMOTOTMTTTOTTTTVWYZ\Z\YZZZZZZZ\Z\Z\ZZZZZZZZZWYWYWZZZYYYYYYYYXVVVYYXYYYYYYYYYYYYYYXYYVXVVVVVYVYYZ[\ZYZYZYZZ[ZZZ[ZZZZZZZYWVWWWZWOGFF@F@FGWZWQQQQQHQHQHGHGHGRWH2.(  (.HWRHFFHHQRRRWRWWWRWWRRQHHHHHRRHH2..0 .1FHR3222223F223222.12HH13H3 001123232332311112HH0 2HRHF3FHHHRRRWRWRZRZZZZZZZZZZZZZZZZZZZZZZRZRWRWRWRRRRGHHHFHHHQRF2.( ((((((((.**(*.*.(*(((((((((((%(((((((((((((((*****8=8@@9C:LCLCLCLLLLLLLLLLMLLMLMMTMTMTMMTMTMTSTMTMOLCLMOLO@@FCF@==/((.(((((((((((*(/**/*(*(((((((((((((((( .../2//=2=2=F=FF@FF@GFGF@FGFG@GFG@GFGGFG@GFGG@GGGGGGOGGGGGGGGGGGGCGGGCGGCG@GGGCG@GOGOGCGGGGGOGGGGOGOGLOOOOOOLOOTMOTOTTTTTTTTYYZ\ZZZZZZZZZZZZZZZZZZZZZZZYZWYWYZZZZYYYYYYYVVVVVXY[Y[Y[Y[Y[Y[YXYYYXYYXYYXYYYYYY\Z\YYZYZ[ZZZ[ZZZZZZYZZWYWWWZZWQF@F@F@GGWZWQQQQGQQHQHHGHFHWRG2.    .HRQHFHHGHRQRRWRWRWRRRQRQHHHHHRQRRHF2F3HRRH22123222F322211.FHH0HH1001113233F332221111HH3 .FRHF2FFHHRQRRWWWWZZZZZZZZZZZZZZZZZZZRZRZWWWWRRRRRRRHHGHFFHHQHH// (((((((.((*(/((/((((.((((((((%(((((((((((%(((%((((***8*8=8@@@:CLCLCLLLLLLLLLLLLMLLMMMMMTMTMTMMTSTTSTMTMMCLLMOLG@G@GF==//((.((((((((((*****(*((((((((((%((((((    1.1/1/2/2/=2=F=F@F@GF@FGF@GFCFGF@GFG@GFG@GFGG@GGGGGGGGOGGGGGGGGGGCGGGGGCGGG@GGCGGGGGOGGOGOGOGGGGOGOGOOOOOOLOOMTTOTTTTVTVTVVYYYY\\\\ZZYZZZ\Z\Z\Z\Z\Z\Z\ZZZZYZYZY\\Y[Y[[[YXYYYX[[[[[[[[[[[[[[[[[[[Y[Y[Y[Y[[Y[Y\\\[Z[\[Z\Z\[\\Z\[\Z\ZZZYZVWZZZQOGG@G@GQWZWQQQQHQHQHGHGFHGRWH/..  .FRWHFFHHQQRQWRWWWWWRWRRQQHHHHHRRRRRRRRRRHF22222F3F22F221.23R3 03H30 12323F33H33232112HR3  2HRHF3FHHHRRRRWWWWRZZZZZZZZZZZZZZZZZZZZRZRWRWRRRRHQHHHFHFHRHH=.. ((((((((((.**.*((*.((*((((((((((((((%(((%(((%((((%(****88=8@9@CLCLCLLLLLLMLMLMLLMMMOMTSTSSSTSTSVSVVUVSVSTMMTMMOGG@G@F==..((.(/**(*(**(***/(((((((((((((%((((( . 1..2/2/=2=/2=2=2=F=FF@FGFCFFG@GFG@GFG@GFGGG@GGGG@GGGGGOGGGGGGGOGGGGGGCGCGGOCGGGGGCGGOGOOGGOGOOGOGOGOOOOOOOMOTTMTTTTTTVVVVVVYYYYY[Z\\\[ZZZZ\ZZZ\Z\Z\Z\ZZ\Z[ZZYZYZZZ\Z[[[Y[YYYXY[Y[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\\\[Z[\[\[\Z\\[\Z\\Z[ZZZYZVWZZWOOGOGGQWZWWQQQGQQQGQHGHGFQRWH=..   ..FRRQFHHGQRQRWRWRWRWRRRQRRHHHHFHQRRWRWRRGHF3F3F32F322222112FR2 HH11012333H3H3F33222113RH0 /HQRFFFFHHHQRWRWWWZRZRZZZZZZZZZZZZRZRZRZRWWRRRRRQHHHGFHFHQRF2.. ((((((((.((((*(/*(((((((((((((((%((((((((%(((((((%(((*****88@=@@:CCLCLCLLLLLMLLMLMTMTSVSVSVVVSVSVVXVXYXYVVUTSSTTMOGGGCF==/*.**(**/(*/*(*(*((((((((((((((%(((((  . .1/2/2//2=/2=2=F=F@FF@GFG@GFG@GFG@GFG@GG@GFG@GGGGGGGGGGOGGGGOGGGGGCGGGGCGGG@G@GGGCGGGGLGGOGGOGGOGOGOOOOOOOOOOTOTMTTTTTVTVTVVYYYY\Z\\ZZZZZZZZ\ZZZZZZZ\ZZZZZYZYZZZ\YZYY[YYYVVVVY[[[[[[[[[[[[[[[Y[Y[Y[Y[Y[YY[YYY[\\Z[Z[Z\Z\[\Z[Z\Z\Y\ZZZYZTWWWZWWWOQOQWWWWQGGQGHQHGHGHGFHHQWH2.. 2GWHHFHHHQRQRWRWRWRWRRRRHQHHHHFHFHHHHHHHF3F3F3F32F32221.11HH10HH301123F3H3H3H33321112HH1 2HQHH2FFHHHRRRRRWRZRZRZRZZRZZRZRZZRZRWRWRRRRRRHHHHFFHHHQRF2. (((((.(((((.(*/(((*(((*((((((((((%(((((%(((%(((%((((%(*(***8=8=9@@CCLCLCLLLLLLMLLMOMMMMMMTSSSMTSSTSVSVVVSVSTMMMMOLGGC@G@===/(/(/***/**((((/(((((((((((((((%(((((( ..../2/2/2/2/=F=F=FF=F@FGF@FG@GFG@GFGG@GGFGG@GGGGGGGGGGOGGGGGGGGGGGGCGGCGGGGCGG@GG@GCGOGCOGOGOGOGGOGOOOOOOOMOOMOOTOTTTTTTTTTTTTYWYZ\ZZYZYZZZZZZZZZZZZZZYZYWYWZZZZYWVVVTVTLOLOMVVVVYYY[Y[Y[YYYYYYYVXVYVXVVYVVVYYZ\ZZYZYZYZZZZZZZZZZZZYZWWWTQWWWZWWWWWWWWQGHGHQGHGHGHHHFFHRWH/.   /HRRHFFGHQRQRRRRWRRRRRRQRHRHHHFHFFHFHFHF3FFF3F3F3222211 02HH00HH0011233H3H3H3H3322112HR3 2HHHF32FFHHHRRRRRRWRWRZRWZRZRZRWRWRRRRRRRRRHHHHFFHFHHRHF2. ((((((((((.(((.***((((((*(((((((%(((((((((%(%(((%(((((****88==@@9CCLCLLLLLLMLLMLMMMMMMTMTSTMSTMMMTSMSTSMTMLMOMLMGOGG@F@==/**/(*/**(**((((((*(((((((((((((((( .1.2//2//2=2=2=F=F=FF@F@GFGFG@GFG@GFGGG@GGG@GGGGGGGGGGGOGGGGGGGGGGGGCGGGCGG@GGCGG@GGGOGGCGGOGOGGOGOGOOOOOOOMOTOTMTTTTTTMTTTTTTVVYZ\\ZZYWZWZZZZZZZZZZZWZWWWWZZZZWTTOTTTOMOLOLTTVVVVXYXYYYYYYXYXVYVVVVVVVVVVVVVYYZ\ZYZYZ[ZZ[ZZZ[Z[ZZYZWWWTWQOQWWWWZWWWWQGHGGQHQGHQHGHGFFHQWH/. 1FRRHFHHGHQRQRQRRRRRRRRRRHRHHHHH3HF3HF3HFH3HF3F3F322111 3H30HH1011233F3HH3H3H3231113R3  2HHHF23F3HHHRRRRRRRRRRWRWRWRWRWRRRRRRRRHHHHHHF3FFHHQHF2.((((((((.((((((((((*.(*((*((((*((((((%(((((%(((%((((((%(((****88==@@@:LCLCLLLLLLLMLMMMMMMTMSTSTMTMTMMTSTSTMMTMLLMOMLOGGG@@==//***.*(/(*((((((((((((((((((((((((( ..2.2//2=/2/F=F=F=F=FF@FFG@FG@GF@GFGG@GGGGGGGGGGGGGGGOGGGGGGGGGGGGGCGGGCGGCG@GCGG@GCGGCGGGOGOGOGOOGOOOOOOMOOTOTOTTMTTTTTTMTTTVTYYZZ\ZYWZWYZZYZZZZZZZYWYWWYZZZZVWOTTTTTOOLOLOSVVVXYXYYX[YXYYYXYYXVYXVYVVVVVVVVYYZ\Z[ZYZYZYZZYZZZZ[ZZZYWWWTQQOQQQQQWRQGGHGHGHGHQGGHGHFFFHRWH/ (  2QRQFFHHGHQHRQRRRRRRRRRQRHQHHHHHHHHHHHHHHHHHH3F3232211 02H31H3201132H3HHHHHH3H321113HH0 .2HHHF23FFHHHHRHRRRRRRRWRRRWRRRRRRRRRHHHHHHF2FFFHRRHF1 ((((((.(((((.((.(((**(*((((((((((((%((((%(((((((((((((%(*(***=88=@@CCLLCLLLLLMLLMLMMTMTMSTSTSTMTMTMSTSSTMTMMMOMLMOLOGCGG=F=*/*(*.*(((((((((*(*((*(((((((((((((((  ...2//2/2/=/=2=F=F=F=FF@FG@FGFGFG@GGFGFGGGGG@GGGGGGGGGOGGGGGGGGGGGGGGGCGGGGG@GG@GCGG@GOGGCGGOGOGOOGOOOOOOOOMOTOTTTTTTVTTVTVVVVVYYY[\\\ZYZYZZZZZZYZZYZZYZYZZZZZYWVTVTVVTTTMTTVVX[Y[[[[[[[[[[[[Y[[Y[Y[Y[[Y[XYYYXY[Z\\\[\[\[Z\[Z\[\\Z[Z[ZYZWVWTQOOQOQGGHGHFGHGGHGHQHGHGHFFGRWF2. /HRQHFFHHQHQHRQRRQRRRRRRRQHRHRHHHHHHHHQHHHHHHHHF3F2211 1HH31HH111133FHHHHHHH33322113HH1 .FHRHHF2HFHHHHRRQRRRRRRRWRRRRRRRRRHHHHHHFF3FFHHRRF2.. (((((((((/((((((((((*.*(*((*(*(((((((%(((((%(((((((((((((***88=8@@9CLCLCLLLLLMLLMOMMTMTSMTSMSSSTSSVSVSVSSSTMMMMOMMOOGCG@@=//*.(((((((((((((((*(*(((((((%((((((  .1//=2==2=F2=F=F=FF=F@FF@F@FG@GFGFG@GGGGGGGGGGGG@GGGGOGOGGGGGGGGGGCGGGCOGCG@G@GGCGCGGGGCGGOGOGOGOOOOOOOMOTTTTTTVTVVVTYVVVVVYYYY[Y[\\\\ZYZZYZZZYZZZZYZYZZZ\Z[ZYVVVVVVVTVTTSVV[[Y[[[[[[[[[[[[[[[[[[[[[[[[Y[[[[Y[Y[\[\\[Z[\[Z\[\Z[\[Z\ZYZYYWWTWOQOGGGHGFGGHGGQGQGQGQGHGFGHWRH/.(  .FRRGHFHGHHHRHRQRRQRQRRQRRRQHRHRHQHQRHRHQHQHHHHHF32211.1HH11HH11123F3HHHHHHHHH332122HR2 2FHRHHFFFFHHHHHRHRQRRRRRRRRRRRRHQHHHHFFF3FHHRRGH2/  (((.((.(((((/(((((((((***(*((((((((%(((((%(((((%((((((((((%***888@@9CLJLLLLLMLMMMMMTSSSVSVVSVVVSUSVSVVXVVVUTSTMTMMMTLOGGG===/*((((((((((((((*(*(*((((((((((((( ..2/2/2/2==F=FF==FF=F@FF@FGFG@GFCFGFGGGGGG@GGGGGGGGGOGGGGGGGGGGGGGCGGGGGGCG@GGCGGCGGOOGCGGGOOGOGOGOOOOOOOOTOTTTTTTTVTTVTVVVVYYYYZ[\\Z[ZYZYZYZZYZYZZYZZZZZZYWVTTTTVTTTMTMTTXYX[Y[X[Y[[Y[[Y[Y[Y[YX[Y[Y[Y[YYYYY[YY[Z\\\[ZZ[ZY\Y\Z[ZZYZYZYWWVWOTOGGHGFFFHGFHGHGHGHGHGHGHFQRQF/...HQRHFFFFHHHQHRQRRRRQRRRQRHRRHRHRHRHRHRHQHHHHHHF3221.02HH02HH101323HHHHHHHHHH3H3211HHH0 .FHRHHHF3FFHFHHHHRHRHQHRHRHQHHHHHFFF3F3FHRQHH2..  ((((((((/*(*.((((((((*.**(*(((((((((%(((((%(((((%((%((%((((*%**8=8@C:CLLLCLLLLLMLLMLMTSTMMSTSSSTSTSTSSVSVSSTMMMMMOMMOMGGC@@//*((((((((((((((**(*((((((((((((((  ../2/2=2=2=F=FF=F@FF@F@F@FGF@GFG@GFGGGGGGGGGGGGGGGOGOGGGGGGGGGGCGGGCOGGG@GGCGCGGCGOGOGCOGOGOGOOOOOOOOOTOTOTTTTTTTTTTMTTTTVVVVYYYZ\ZZVWWWYWZYWZWYWWZZZZYWTTOOOTMOLOLOCOLTVVVVVVVVYVVXVVYXYVVVVVYXYYVVVVVVVVVYVYYZZZ\ZYZYZYZYZYZYZYZYWYWOTQOGGH@FFFFFHGHGHGHGHFGHFFFGQRQF.  .2HRGF2F3FHHHHQHRQRRQRRRHRRHRHRHRHHRHRHRHHHHHHF3F220.02H33H311123H3HHHHHHHH3H322113HH0 2FRHHHF32F2F3FHFHHHHHHHHHHHFF3F223F3HRRRHF2 ((.((.*(/*(/(*.((((((*(**(**(((((%((((%(((%(((((((((%%((****8=9@C:LLLLLLLLLLMLMLMMTMTSTSTMTMMMMMMTMSTMTMTMMMMMMTMOLGG@@=/((((((((((((((*(*((((((((((((*( .2./=2==F=FF=F=FF@FF@FFFCFGF@GF@GG@GGGG@GGGGGGGGGOGGGGGGGGGGGGGCGGGGGCGG@GCGGCGCOGOGGOCOGOOGOOGOOOOOOOTOTTTTTTTTTTTTTMTTVTVVVYYZ\ZZYZTWWYWWWVWWWZZZZWTOOOOOMOOLOLGCOCMTVSVVSVVSVSVVVVVVVVVVVVVVYVVVVSVVSVVVVVYYY\Z\ZZZYZYZYZYZYWYWYWVWOQOGGFGFFFFFFFHFGHGHFHFGFFFHQWRF...FHRHF2FFFHHHHRHRHRQRHRQRHRQHRHRHRHRHRHHHHHHH3F321.013H23R3101133HHHHHRHHHH3H31112HH1 1FHRRHHF323F2F3FF3FH3FFF3F3F22F3FHRQRHF1. ((((((.*/*(**(*(((*((***(*((*((((((%(((((((((%(((%((((((%**88=9C:CLLLLLLLLLMLMLMMMTSMTSMTSTMMMMMMTMSTSTMTMMMMMMTLMOGCF=*.((((((((((((((*(*(((((%((((((((  ../2/=2=2F=FF=F@FF@F@F@FG@GGF@GFG@GGGGGGGGGGGGGGOGOGOGGGGGGGGGCGGGCOGGCGGCGGCGCGOOOOCGOGOOGOOOOOOOOOOTOTTTTTTTTTTTTTTTTTTVVVVYYZZ\ZYWWVWWWVWWWYZZZYWTTOTOOMOTOMOLLGLOSVVVVVVVVVVSVVVVVXYXYVXYXYXYVVVVVVVVSVVVVYYYZZ\Z\Z[ZYZYYYWYYYWVWTTOQGGGFFFFFFFFFHFFFFFFFFFFFGQWR/.  .HHQF3F2FFHHHHHQHRHRQRHRQHRHRHRHRHRHHRHHHHHFH32220.1HH11R310123F3HHHRHHHHHH332111HH3 2HHRRHHF3F22F22F3F23F3F2F2FHHHRRHHH21 ((.(*(*(/*(**.(((.*(/(****((((((%((((%(((%(((((%(%(((((*(*88@:CJCLLLLLMLMLOMLMMMMTMMTSMSMSMMMMMMTSMSSTMMTMMMOMMOMG@@=/*(((((((((((((((*(*((((((%(((((( . ./2/=2=F=F@FF@F@FFG@FGFG@GFG@GFGG@GGGGGGGGGGGGGOGOGGGGGGGGGGGCOGGGOGGC@GGCGGCOGOOOOGOOOGOOGOOOOOOOOOTTOTTTTVTVTVTVSVVVYYVYYYY[\\\ZYYWYWYWYYZZZZZYWVTVTVTVVSVTTTMTSVYX[Y[X[YXYXYXY[X[Y[[Y[[Y[[Y[YXYY[XY[YYXY[YY[Z[Z\\\\\[Z[ZYZYYYYYVWTQOOOGFGFFFFFFFFFFFFFFFFFFFFQWR/.  /HHHHFF2HFHHHGHRHRHRHRQRRHRQRHRHRHRHRHQHHHH3F2221.2HH02HH01123HHHHHHRHHHH3H322113RH0 .1FHQRRRHHHHF3FHFHFHFHHHHRHRQRRHH2. ((((.(/*(*/*(**((*((***(**(*((((((%((%(((((%((((%%((((**&*8@9CL:LLLLLLLLMLLMOMMMMTMMTSTMTSTMTMSTSVSSTSMMMMMMTMLOL@@=//*((((((((%(((((((((((((((((((   ...1/2=2=F=FF@FF@FF@F@FGFG@GFG@GFG@GGGGGGGGGGGGOGGGOGGGGGGGGGGGOGGCGGGCGG@GGCGLGGOOOOOOOGOOOOOOOOOOOTTOTTVTTVVVVVVVVVVYVYYXYY[Y[YZ\\[ZYYWYYZYZZ\ZYYYVVVTVVVVVYVVSTTSVY[[Y[X[Y[X[Y[Y[X[[[[[[[[[[[[Y[[[[Y[[Y[[[Y[Y[Y[Y[\[\\\\\Z\YZYYZYYYYWTTQOGOGFGFFFFFFFFFFFFFFFFFGQWH=.( ./HQRHFFFFFHHHHHHQHRQRHQRQRHRQHRQHRHRHHHHHFH2F221.3HH 3R311132H3HHHRHRHHHH3H31112HH2 .2FHRRRWRRRQRQRHRQRQRRRRRRHHF2.  ((*((**(****.**.**(***(**(*((((((%((%((((((%((((%((%((**88@:CLLLMLMMMMMTMMSTSTSSVSSVSSVSUSSSVSVUVUVSTMMMMMMOLLCC@==/*.(((((((((((((((((%((((((( ..../2=2F@FF@F@F@GFG@GFGFGG@FGF@GFGGGGGGGGGGGGGGOGOGGGGGGGGGGGLGGGCGGCGC@GGCGGLOOOOOOOOOOOGOOOOOOOOOTQTTTTTTTVTVVTVVTVVYYYYVYYY[Z\ZYZTWYWZZZZZYYYTTTTVTVVVVVVSTTMVVXY[X[YX[YXYXYXY[X[Y[[Y[[[Y[YXYXYX[YX[YXY[YYYYYYYYZ[\[\\Z\Z\YZYZYWVTTQOOGGFFFFFFF=F2F=F2F2=2=2GRRG1(  2FHRHFF3FFFFHHHHQHHQRHRHRHRHRHRHHRHHHHHF3F3221.1HH32HH001233HHHHHHHHHHHH323112HH3  .2FHHRQRRWRWWRWRRRRQHHF2..(((((((/(*/***(**(*(*(**(**(((((%(((((((%(((((%((%*(***889LCLLLLLLLMLMMMLMLMMMMTMMMTMMTMSMMSSSTSSTSMMMMMMLLCCC@@==/*((((((%(((((((((((((((((  . .../2=F=F@F@FFF@GFGFG@GFGFG@GFGG@GGGGGGGGGGGGGGOGGGGGGGGGGGOGLGGOGGCGG@GCGGLGOOOOOOOOOOOOOOOOOOOOOTOTTTTTTVTTTSTTTTTTTVSVVTVVYZZ\YWTWWYZZZYWTTOTOTOMOMTVSTTMOLMTVVVVVSVVVSVSTSTSVVVXVYXYVYYVVVVVVVVYVVVVVVSVVVTVVVYYVZYZZZZZ\ZZZYZWWTWOOGGGGFF=FF2F=2F2F=F2F2FHQRF.  2FHRHHF3F2FFFHHHHHHHHHHHHHHHHHHHHHHHF3F322211 1HH23H3101123H3HHHHRHHH333221013R3  .222FHHHHHHHHH222. ((((((*(***/**(/*(**(**(*(((((((%((((%((((%(((((%%((***89@CLLLLLMLMMMMMMMMMMMMSMTSMMMMMMMMMMTSSMSMTMMMMLLLCCCC@===**(((((((((((%(((((((((  . . .2/=FF=FF@F@GFGFG@GFGGG@GFG@GFGGGGGGGGGGOGGGOGGGG@GGGGGGOGOGGGCGGG@GGCGGCGOOOOOOOOOOOOOOOOOOOOMOOTOTTTTTTVTVTVTSTVTSVTTTVVTYYZ\ZYWWYZZZWTTOTOOMOOMTTTSTTMOMOMTSVSTVSVSVTSTSTTMSVVVUVYXVVVVVVVSVVVVVVSVSVTTSTSTVSVVVVTVVYZYZZZZZZZZZWWTWQQOGHGFHFHFHFFHFHFHGHQRH/  /FHQRHFF3F3FFFHHHHHHHHHHHHHHHHHHH3H3F32221. 02FH02H3001123HHHHHHHHHHH33221102HH1 1 1 1. . ((((((((/(**/**/**(**(*(**(*((((%((((%(((%(((((%((%(*(*88@:CLLLLLMMOMMMMMMMMMMTMMTMTMMMTMMMMSMSTSSMTMMLLLCCCCCC@==/***(((((%(((((((%((((((  . .. ../2=F=F@FF@FFG@GFGFGGGFG@GGFGGGGGGGGGOGGOGGGOGCGG@GGGGGOGOOCOGGCGG@GCGCOGCOOMOOOOOOOOOOOOOOOMOOTOTTTTTTTTVTTTTVTTTTTVTVTTVTYZZ\ZZZZZWTTOTOOMOOMOTSVVVTVTMMTTVVVVVUVTVSVTSTSSVTVUVVYXYXYVVVVVVVVVVVVVVSVTVTSTVTVVTVTTTTTVVWYYZYZZZZZZZZWWWWQRQQQQRQRQRQRQRQRRQF  .2HRQRHFF22F3FFHFHFHHHHHHHHHH3HFF3F3222111 2H3 3H30 02323H3HHHHH3H3H32211 2HH2((((((((**(**/****(*((*(*(*((((((%(((((((%((((((((((((*(*8=9CLLLMLLMMMMMMMMMMMMMSTMSMMSMMSMMMMSTSTSMMMMLLLCCCCCCC@==8/*(((((((((%%(((((( . .. .......1/2=F=FF@FF@GFGFG@GFGGG@GFGG@GGGGGGGGGGGGGGOCGG@GGGGGGGOGOOGGGOGCGC@GGCOGOOOOOOOOOOOOOOOOOMOOOOTOTTOTTVTVTVVVVVVVVVVVVVVVVYYY[Z\ZZZYWTTVTTTTTTTVVYXYYXYXVVVXYXY[XYX[YXYXYXYYXYXY[X[Y[Y[YXYXY[XY[XYXYXYXYXYXYXYXYXYXYVVVVVVTTVTYWYYWYWZWWWWWWWWRWRRWRRQRQQHQHF.  .2FHRRRHHFH2F3FFHFFHFHFHHHFFHF3F3F22221. 0.3H33H3 011233FH3HHHHH3H33221111FRH (((((((((((/*(**/****(*((**(*(*(((((%(((%(((((%((((%(***8@9CLLLLMLMMMMMMMMMMMTMSMTMMMMMMMMMMMSTSMTMMLLLLLCLLCCGC@@=*8(((((((((((((((((( ...//././../1///F=FF@FF@FF@FGFGFGGG@GGG@GFGGGGGGGGOGGGGGGGCGG@G@GGOGOOGOLGOGGCGGG@GOCOGLOOOOOOOOOMOOOMOOOTOTOTTTVTVVVVVYVYVVVVVVVVVYVYYYYY[\Z[ZVTVTVTTVTVTVVVX[[[[[YXYXY[[[[Y[[[Y[[X[Y[XY[X[Y[[X[[[[[[[[[X[[Y[[[[Y[X[YXYX[Y[[[YXYXVVYVVSVTVTVTYVTVTTWOQOQQHGHGHFGHFF2F2//. .2FHRRRHHHHFFF3FH2HFFF3HF3F3FF322222.1 01FH13H30 111323HH3HH3HH3F33211.12HH2 ((((((((((((*((**/**(***(*((((((((((%((((%(%(%((((%((((((*(*8=@CMMMMTMSTSTSTSSSSSSVSVSVSSSSSSSSSSSSSTSMMLLLLLLLLLLLG@@@=8*(((((((((%(%((((( ...././//2/.//2/2=F=F@FF@FGFG@GFGGGGG@GGFGG@GGGGGGGGGGGGGCGG@GGGGGGGGOOOOCGGOG@GCGCGOGOGOOOOOOOOOOOOOOOOTOMOTOTOTTTTTVTVVTVVTVSTVTVVVVVYYYYYYZTTTTTOTTTTMTTVVYYYXYYXYYXYXYXY[XY[X[YXYXYXYXYXYXYX[Y[XYXYXY[Y[XYXYXYXYYXYXYYXYXYXYVVUVUTSTTSTTSTTTOOOGCGCF===/////......    12FHRRRQHHHHFF3F3F3F3F3F2F222222.11.012H303H3 0 113233H3H3H33H322111 12HQF (((((((((((((((((**(*/***(*(*(((*((((((%(((((((%(((((%(***88@CLLLMOMMMMMMMMMMMMSMSMSMMMMMMMMMMMTMSMMMMLLLLMLMLMOCC@@=8/(((((((((((((((((((( ...../////1//2==FF@F@FFGF@FGFG@GGG@GGFGGGGGGGGGGGGGGG@GGCGG@GGGGGOGOOOOGLGGCGGCGGOCOGOOOOOOOOOOOOOMOTOOOTOTOTTTTTTVTVTTVTSTTTTTSTTTSVTVVYYVTTOOOOLOOLOLLOMTVVYVYUVTSVVVVVVUYUVVSVVSVSVVSVVSVSVVVSVVVVVUVVVVVVVVVVSSVTSVSTUTVMTMTMTMMTMOMMMMOMMOLCC@@===/...(..  .22HHRRRRHRHHHF3F3F3222222222121222FHH13H20 0 123233F3H3H33231111 12HH1((((((((((((((((((.***(**(***(((((*((((((%(((((((%((%((((***8@@CLLLMMMMMMMMMMMTSMSMSMTMMMMMMMMMMMTMSMMMMLMMMMMMOMGCC@@/**(((((((((((((%(((((( .././/2///=2==F=FF@FF@FGFG@GFGGGGGGGG@GGGGGGGGCOGGGGCGGGCG@GGGGGOGOOOOOGLGGCGCGCOGOCOOOLOOOOOOMOOOOOTOMOTOTOTTTTTTTVTVTTVTSVTTVTSTTVVVVVVVTOOLOOOLOLGLGLTMVVUVSVTSTSTVSVVSVSVTSTSTSTMTTSTMTTSSVVSVSVSVSVVSVVSSTSTSTSTSSTSSSTMMTMMTMMMTMOMMOMMOLGC@@==*/((( (  .12FHHRRRRRRRHHHHHHHFHF3FF3HFHHHHH312H30 1112323232323211110 2HH2 (((((((((((((((/((*(*(/*(*/(*(*(*(((((((%((((%((%((%(((**8=9CCLMLMMMMMMMMMMMMMTMMTMMMMMMMMMMMMSTSTMMMMMMMMMMMOLGC@@8**((((((((((((((((((((( ...///=2=2=/=F=F=FF@FFF@GFGF@GFGG@GGGGGGGGGGGGGCGCGCFGCGG@GG@GGOGOOOOOGOOLGGCGGCGOCOGOOOOOOOOOOOTOOTOOTOMOTTTTTTTVTTVTVTSTVTTSTVTVTVTVVVVTTTOOLOLOCOLGLOMTVVVVSVTVSVVSVVSVVTVVSVSTSTSTSTSTSTSTSVTVSVSVVVVVUVVSVSVSSTSTSVSTMMTMMTMTMTMTMMMOMMMOLC@@@==**(.((  122HHHRRRRWRRRRRRHRRHRRRHRHH31 3H10 0111232323232111110 0 0FHF (((((((((((((*(*(*(.(*(**(**(**(((((*((((((%(%((%((((%(*(8=8@CLLMLMMMMMMMMMMSMMSMMMMMMMMMMMMMMMSTSTMMMMMMTMMMMOCG@==*/*(((((((((%(((((((((((  .////=/=//=2=F=F@F@FGF@FGFGFG@GGFGGGGGGGGGGGGOCGGGG@GGGCGG@GGGGOGGOOOOOOGOLGGCGGCOGOGLOOOOOOOOMOOOTOOTOTOTTOTTTTTTVSTVVVVVTVVVTVVVVVVVVYYVVVTMOOMMOMOMMTVVXYXYYXYXYXYXYXYXYXXYXYYXYVVXYVVVVVXYYXYXYXYXYX[YXYXYXYXYXYXYXYXYUVVVVUVVUVSVSTSSTMTMLCC@@==8/(((  .122FFHHHRHRHRRHRHHHHH221 2H10 01112122212121111 0 12HH2((((((((((((.(*.(((((*.**(/(*.*(((((((((%(((%((%((((((***=@@CLLMMMMMMMMMMMMSMMMMMMMMMMMMMMMMMTSSMSTMMMMSTMMTLCG@===***((((((((((((((((((((  .///==F=2=F=F=F@FF@FF@FGFG@GFGFGG@GG@GGGGGGGOGGCGG@G@GCGGGG@GGGGOGOOOOOOOOOCGGCGCOGLOOOMOOOOOOOOOTOOTOMOTTMTTTTVVVTVVYVVVVVVVVVVVYYYVYYXYYYVTTTMTTMTTMTTVX[[[[X[Y[[[[[[[Y[[X[Y[XYXYXYXYXYXYXYXYXYX[Y[[[[X[[X[X[XY[X[Y[[X[XYXVXVVXVVXVVSVSVSVSSTLCC@@@=8/((((  . 1.12222F222222.1 3H10 011111121121110.1 2HHF.(((((((*(*(*((***(*.(**(**(*(*((((((((((((%(((((%(((%(((***8@9CLMMMTSTSSSSSSSMSMSSMSSMMSMSSSMSSSSSTSTSMTMTMSMMMOC@@@=/=**(((((((((((((((((((((((  .///=2==2===F=F@F@F@FGFGFGFG@GFGGFGGGGGGGGGGOGGCGG@GGGCGGCGGGOGOGOOOOOOOOOOCGGCGOOCOOOOMOOOOOMOOOOTOTOTOTOTMTTTTTSVTVTSTVVVSVVVSVVVVVVYVVVSTOMOLOMOLOMTTVYXYYXYXYXYXYXY[XYXYXYYXYXYXYVVXVVVVVXYXYXXYXYXYXYXYXYXYXYXYXXYXVUVSVUVUVUVSSSTSTSMTMLLC@=@88/(((   1H10 0 10111110110 1 0 3QH.((((((.*(/*((/(*((((*/(*.(*(*((((((((((%((((%(%(((((**8=9CCLMLMLMMMMMMMMMMMTMMMMMMMMTMTMMTSTSSSTSSMMSTMTMLL@@@===/*/(((((((((((((((((((((((( ..//=/=/=2=F=F@FF@FGF@FGFGFG@GGFGG@GGGGGGOGGCGGGCG@GGGCGGGCGGOGOGOOOOOOOOOGCGLGOCOGLOOTOOOLOOTOTOOTOTMOTTOTTMTTTVTTTVTVTVTVSTVTVVTVSVTVTTMOOLGLGCOCOCLOMTVSVSVSVVVYXVVSVVVSVTSTTTSTSTMTMMMMMTMTMTVUVVVVVVSVTSVVSVUSVSTSTMMMMMMMMTMTMMMMMMMLLLCC@@@=8**.((1H100 0 0 0 0 0 0 0  1HH2(((((((*(*(**(*(*(*.((*(**(((.*((((((((((((((((((%(((((**8=9CLLMLMMMMMMMMMMMMMMMMMMMMMSMSMTMSSTSSSTSMTMSMMOLLG@@@==/8*(((((((((((((((((((((((((  .../=2=2=F=F=F@F@FG@FGGFG@GFGG@GFGGG@GGGGGCGOGGCGGG@GGGOCGGGOGOGLOOOOOOOOOCOGGLGOOLOOTOMOOOOMOTOMOTOTOTMTTMOTTTVTSVTTSTVSVTTVTVSVVTVTTTTTMTLOCOCOCOLGLLTMTTMTMTVUVUVVSVSTSTSTMTSTMTMTMMMTLMOMMMTSTSVSSSSTSMSTSSTSTSSTSTMMMMOMMTMMMMMMMMMMMLLLCLC@==8/*((1H3110001 0 0 0000  .2H3 ((((((((.**(/*(.*((*(((*(**((((((((((((%(((%%%(((%(*(**8=9CLLMLMMMMMMLMMMMMMMMMMMMTMSSSMSMTSSTSSSTSMTMTMLLLCCF@@==/=**((((((((((((((((((((((((  .../=/=2==F=F=F@F@FGG@GFGFGFGGGFG@GFGGGGGGGCGGGGCGGGCGOGGCGGCOGGOGOOOOOOOOOCOGOCOOOLOOTOOOMOOTOOTTMTOTTOTMTTTTTTSTTTVTTTTVTVSVTVTVVTSTTMTOMOLLCOCLCOLGLOMMMMOMSVVVVUVVVTVVSTSTMTSTMTSMTMMOMMOMTMSTSVUSTSTMSTVSVSVSSTSSSTMMMMMTMMMTMMOMMMMMLLLLCCC@=88*/((03HH3H3H33322110 0 0    1HH.(((((*((**(*(*((((((((*((*(((((((((((((((((%(%((((((((**89CCLLMLMMMMMMLMMMMMMMMMMSMSMTSTSSMTSSVSTSTSMTMMLLLCCC@@@===*/*(*((((((((((((((((((((((((  .. ...=/=2==2=F=F@F@GFGFGFG@GGFGG@GFGG@GGGGGGLGGOCGGGCGGGCOGGGOGCOGOOOOOOOOOOOOCOGOLGOOOMOTMOOTOTOTOTOTTMOTTTTTTTTSTTVTTSTVTSTTVTVVVVVSTTTTMTTMTOLOMOMMOMTMTSTTVSYXY[XYXYXXYXYXYYVXYVXVVVVSVSVSVSVVVXYXYXYUVVVXYXYXYXYXYXYUVVSVSVUVUVSSSTSVMMMLMLLLLC@=8=**((00223HHHHHRHH3H2211 0  .2HF.(((((((((/(*/(*(.*(((((((((*((*((((((((((((%((((%((*(**=9C:LMLMMMMMLMMLMMMMMMTMMTMSTSSSTSSTSSVSSVMTSMMOMLLLCLG@@@@==*/**((((((((((*(((((((((((((  (......../////F===F=F=F=F@F@GFCGGGFGG@GGGFG@GGGGG@GGGOGGGCGGGCGGOOGCGGOGLGGOOMOOOOOMOGOOCOGOLOLOTTOOOMOTTTOTTOTOTMTOTTTTSTVVTVTVTVVVVVVVVVVVXVVTSTVTTTTMTMTMTTTSTTSTSVSVV[X[[[[X[Y[Y[XYXXYXYXYXYXVVVUVVUVXYXY[XYXYXVXYX[X[XY[XXYXXYXVUVUXVXVUVUVUSVSSSMMMMMMLCC@98/* 002323HHHHHH3F2211.1 . ./HH2(((((((((*(*(*((((((((((((((((((((((%((((%%(((%((((*****88@:LMMMMMMTSTMSMTSSSSTSSSSVSSTUSSTSSTSSVSSSTMMMMMLLLLLLOCG@@=88/**((((((((((/(((*((((((((((. ..(././/.////===2=/=F=F@F@FG@GFG@GGGGGG@GGFGG@GGGGCOGCGGGGCGGGGOGOGCOGOGOOOOOOOOOOOOOOGOLGOOOOMOTTMOOTMOTTOTTMTOTTTTTTTTTTTSTTSTSTTVSTSVVVVTVTMTMTMTMTOMOLOLMMOMMTMMOMSVVXYXYXYYXYXYXYXYYXYYXVVUSSVSTSVUVVXYXVXYUVUVVXVYXYXXYXYXYUVSVUVUVUSVSSSTSSMTMMMMMLMLLC9=8*((01133HHHHHH2F22/1...2FQF (((((((((((.(*(/((((((((((*(((((((((%((((%%(((((*(*(8=99CLLMLMLMMMMLMMMMTSMTMSTSSTSVSSTSSTSSVSTSTMTMMMMLMOMLOLC@@=8*/*(((((((((/(/((((((((((((( ...(....//.//=2=/=2==F=F@F@FG@GGGGGG@GGGG@GFGGGGGGGGOGOGGCGGGCGOGOCGGOGOOGOOMOOOOMOOOOOGOLGOLOOTTTOTOTOTTMTOTTTMTTTMTTSTTTTTSTTTTVSTTTTSVTTVMTMOOLOMOLLOCOLGLOCOCCGLCCLLVVUVVVUVUVVSVVSTSTSMTMMMOMLOLLMOMMTMTMTMMTMMMTSSTSSVSSSSMMMLMMMMMMMLMMMMTMMMMMMMMLLLLLC9=**0133HHHRHHHF222=HHF (((((((((((((*(((*(((((((((((((((((%(((%((%(((((((**8=9CCJLLMLMMMMLMMMTMSSMTSSTSSTSSTSSTSVSVSVSTMSTMTMTMMMTMOLC@==**/*(.((((.*(**(/((((((((((( ( ....////////==2==F==F@F@FG@GFG@GGGGGGGGG@GGGG@GGCGGGGOGGGCGGGCOGGCGOGOOOGOOMOOMOTOOOOGOGLOGOMOTTTOTMTOTOTTTMTTTMTTTTTTSTVTTSTVTSTVSTSTTSVTSTMMOMOLOOLLGLCOCOCLOCLCCCLOSSVSVSSTSSTSSTSTSMTMMTLMLOLLLLOMMMMMMMLMMMMTMMTMSTSSTSTSMMMMMMMMMMLMMMMMSMMMMMMMMMLMLLCC9**( 22FHHHRHQHHQHF ((((((((((((((((.(*(((((((%(((((((((((%((((%%(((%(((((**=9@9CLLLMLMMMMMMMMSTSMSTSSTSSTSSTSSSTUSVSTSSTSSTMTMTMMMMOLC@=**/(*(((.*((.*.*(*(((/(*(/(( ....(///./////=2=/=2=F=F=F@@FG@GGGGGGGGGGGGGGGGGG@GGOGOGGGGGGG@GOOGOGCGOOGOOOOMOOTOTOOOOCOOGLOOOMTTTMOTOTTMTOTTTTTTMTTTTTTTSTTVTSTSTTVTSVTVTSVTTLMOLOLLOCLGLCOCOCLCGCCCCMTSVVSVSVSVSVSTSTSTMTMMOLMLLLLLLMMOMMMLMMOMTSTMTMSTSSSTSTMMMLMOMMOMMLMMMMTMSMMMMMMMLLLLL:@8/(( .12FHHGHHH.((((((((((((((((((((*(((((((((%(((((((((%((((((((*8=9@:CLLLMMMMMMMTMSMTSTSSTSSTSSTSSTSVSVSVSVTSTSSTSTSTMTMMLL@@8/**.*.*(((/(**.*/*/*(*/(*(. ..////========2=F==2==F=F=F@FGFG@G@GGGGGGGGGGGGGGGGCGGOGGGGGGGGGCGOOGCGGOOOGOOMOTOTOTOOOOGCOGOLOOTMTTTTOTMTOTTMTTTMTTTTMTTTTTSTTSTTSVTSTVTSVSVVVTTMOMLMOLOLMOLLMOMOMMOMOMSYXYXYXYXYXYXYXVVVXVVUSVSSTSSTSTSVSSTSTSTUSVUXVUVUVXYXXYXVUTSVSVSSUSSSVSSSSSSSMSMSMMMMLLLC:88(( ../2/// ((((((((((((((((*(/(((((((((((((((%(((((((((%(((((*8=9CCJLMLMMMMTMSMTSSTSSTSTSSTSSTSSTSVSVUVSSSVTSSTSTMTMTMOLC@=**/**(/(/(*(/****/**/(*/(*(   (//=====F@F=F==@=F=F=F=F=F@F@FG@GFGGGGGGGGGGGGGGCGGGCGGOCGGG@GG@GOGOGGGGOGOOOOOTTTOTOTOOOCOGOOGLOOTTTTOTMOTTMTOTMTTTTMTTTTTSTVVTSVTVSVVVVVVVVVVVVSTMTMOTMMOMTMTMMOSTMMMMTVX[[[[[X[Y[XYXYXYXYXVUVVSVUVSVSSTUVVUSVSVUVUYXXYXYXX[X[XYXXVUUVUVUVSVUVUVUVUVSUSUSSSMSSMLLC:@8*(  ((((((((((((((((((((((*((((((%(((%(((%(((((((((((((*(/8@9CCLMMMMSTSSVSVSVSUVSVSSTSSTSSTSSTSVVUTVSVSVSTSTSTMTMMMLCC@=8**/**(*/**/*/*=**/**(*.*(    .///=/==@=====F====2@F=F=F@FGF@GFG@GGGGGGGGGGGCGGCGGOGGGGGGGGGGGOGOOGGOGOOOOOMOTTOTOOOOLOGOCOOOOMTTTTTOTOTOTOTTTMTTTTTTMTTTTSTSTSTVTSTSTSTSTVSVSTMOLOMLOLOLOLOLOMOLOMOMMVXYXYXYXYXYXYVUVVUVSSVSSTSSTSSTMMMSSTMTMSTSVUVXVXVXYXYXYXVUSVSSSSSSSSSSSSSSSSSSSMMMMMMLLL9C998=8((((((*(((((((((((((((((((((((%(%((%%(((((**=9@CCLLMLMMTMSMSTSSTSSTSSTSSTSSTSVSVUVVVSVSVSVSSTSTMTMOLLC@@==**/*/**/*=*=**/***.*/(/(  (.////=/=/2///=F/F==F=F=F@FF@FG@GFGGGGGGGGGGGGCGGGCOGGGGGGGGGGGGOOOGOGGOOOOOOTTOTOMOOOOLOGOLOOOOMTTTOTOMTOTMTTMTTTMTTTTMTTSTTVTSTSTSVTSTSVSTSTSTMOLLGCCGCCLCOCOCCLCCCCLTVVUVUVSVSSTSMMMOMMOMLLLLLLMLLLLLCLLLLLCLLLLMMMMMMSSTSSSSMMMLLMLLLLLLMMMMMMMMMMMMMMLLLLJC9@9@888*((.((((((((((((((((((((((((((((%(((((*88@9CLLLMMMSMTSTSSTSSTSTSSTSSTSVSTSVVVUVVSVVTVTSTSSTMMLOLC@@@=@8*/*=*=8/8=8/8/(*.*/(*.  ..////=/=/=2===2==F=F=F@FGFG@FGFGGGGGGGGGGGCGGGGCGOGGGGGGGGGGGGGOOGGOGGOOOOTOTTOOTOMOOOOCOOOOOOTTMTTOMOTMOTOTTMTTTTMTMTMTTSTSTTSVSTSTSTSTSVSVTSTLOCLGCCCGCCCLCCCGCCCGMMVUVSVSSTSTMMOMLMLLLLLOLLLLLLLLCCCCCLCCCCCLLLMMMMMTMSSTSTMMLMLLMLLLLMMMMMMSMSMMMMMMLMLL:C9@99@888**((((((.((((((((((((((((((((%((((((((/8=@:CCLLMMTMSSSTSVSSVSTSSTSVSSSSVSVUVVVVVSVVSVTSVTSTMOLLLCC@@@@@8=8=*=8/8/8/*/*.**/(/  ...///=/=/=///=F==F=F@F=F@FG@GFG@G@GGGGGGGCGGGGCGGOGGGGGGGGGGGGGOGOOOGOGOOOOOTOMOTOMOOOLOGOLOOLOMTTTOTOTOTTMTTTMTTTMTMTMTMTTSTSTSTSVTSTSTSTSTSVTMMOCCCGCCCGLGCLGCCCCCLMVVUVSSVSSTSTMMLOLLLLLLLLMLLLLLLLLCCCCLCLCLCLLOMMMMMSTSSSTMMLLMLLLLLLMLMMMSMSMMMMMMMLLJCC:@:@9@9=88**((((((((((((((((((((%((%((((((*=8@CCLLMMMTSTSVSSVSTSSTSSVMVTVSVSVVVVUVVVSVVSVTSTTMMMOLLCCCCC@@@=8==8==*=*/*(*(/.(/(   .( .     .//===F=F===F/F==F==F@F@F@GFG@GFG@GGGGGGCGGGGCGGOGGGGGGGGGGGGGGGOOOOGOGOGOOOOOTOTOOTOOOOLOOOOOOOOTTOTOLOTOMTOTMTMTTTMTMTMTMTTSTTSTSTSSTSTSVTSVSVSTLOLGLOLOLOLLOLMOLMOSVYXYX[YXYXYXVUSTSSTMTMTSMSSSSSMSMMMMMLMMMMMMTSSTSVSVUYXYXVUVSSSSSSMSMSSSSUSSUSSSSMMMMLLJCL:C:C:C:C9=8*(((((((((((%((((((%((((((.**=@CCCLLMMTSSTSSVSVSTSSVSTSVSVSVSVUVVVUVVVSVVSVTVTTMMOMOLLCLLCC@C==8=/8=/*/*/.*.*.*(...(..(. (. ...//===F@@@@F===F@F=F@F@F@FG@GF@G@GG@GCGCGGGGGGGGCGGGGGGGGGGGGGGOGGOOOGOGOGOOOOOTMOTOOMOOOOOOOOOMOMOTTMOOMOTOTMTTTTTMTTMTMOTMTSTSTSTSTSVTSVSVSVVVVVSMMOLLOMLMLMOMMOMMTMVX[X[[X[X[XYXYXVSVSSSTSSTUVSVSVSTSSMMMMLMTMTSTSSVUVUXYXXXXXYUVUVUVSSSVSUUVUXVXUUUSSSSMMMMMLLLMLMLLL:C98**((((((((((((((%(%%(((%((%((((((((((*(*(/***=@CCLLMMSSVSSVSVVUVSVSTVSVSVSVUTVUVVVVUVVVSVTVSTSTTMMTMMOMLLLLC@@@==8/*/*/**.(/(.(/ .(. (..( (. .(.//====F=F=F======F=F@F@F@G@GG@GG@GGGGGGGGGGGCGGGGGGGGGGGGGGGGGOGOOOOGOGOOOOOOOTOOMOOOOOOOOLOOOOOMOTTOMOOMTOTMTTOTTMTMOTMTMTTSTMTSTTSMTSTSTSSTSSVTMOCLCLOLOLOLLOMOLMMVVX[YX[VXYXYXVSVSMTMTMMMMTMSMTMSMMMMLLLLLLMMLMTMSTSVSUYXYXYUUSVSSSSSTMSMSSUVSSSSSSMMMMLMLLJLLMLJLLL:9@8**((((((((((((%(%(((((((((.(*=8@@CLLMMTMTSSVSVSVSVSVSVSVVUVUSVVVVVVVVSVVSVTVSTTSTTTTMOMOLLCC@@@=*//*/*/*/.(.*.(    .  ( ..//.//////=//2=2==2=F@F@FG@G@GG@GGCGGGGGGGGGGGGGGGG@GGGOGOGGOGOGOGOOOGOGOGOOOOMOTOOOTOMOOOLOOMOOMOTMOTOMOMOTMTOTMTMTMTMTTMTMTMTSTMTSTMSTMSTSTSTSTSOLCCGCCCCCLCCCCCCGLMVVSVVSVSVSSTMMLLLLLLCCLCLCLLLLCLCCCCC@@C@CCCCLCLLLLMMMSSTMMLLLMLLMLMLMLMMMSMSMMMMLLLJLLJLLLJCLLJCCC:9=**(((((((((((((((.((((/*=9@CCLLMTSSTSVSVSVSVSVVSVSVVUVTVVVXVVVVVSVVVSVTVSVTSTSTTMMMOCCC@@=*=*/*//*/*.(.*.   ....///////=///=//F=2=F=F@F@G@G@G@GG@GGCGGGGGGGGGGGGGGGGGGGGOOGGOGOGOOOOOGOGOGOOOOTOOOTOTOOOOOMOOOMOOTOTMOMOMOTTMTMTMTMTMTMTMTTMTSTMTMTSTMSTSSTSVSTTSMOCCCCCGCLGCCCCGCLOSVUVVSVSSSTSMMMOMLLLLCLCCLCCLCLCCCCC@@C@9@@CCCCCLCCLLMMMMMMMLMLLMLLMLLMMMMSSSMSMMMLMLMLLJLLJLLJLLL:C:@98(((((((((((((((((((((((((*/8@@CLLMMTSSTSVVVSVSVSVUVVSVVUVSVVVVVVVVVVSVVVVVVVSVTVTMTTMLLCC@@==*/*=*//*.*.(.(  ( ..../////==//=/2/=/=2===F@F@F@GFGCGGGG@GGGGGGGGGGGGGGGG@GOGOGOOOGGOGOOOOOGOGOGOOOOMOTOOOMOOOOOLOOOOOMOOTTTOMOMOTMOTMOTMTTMTMTTMTSTMTMSTMTSTMSTSTSTSMTMTLLC@GCCCCCLCGCCCLTSVSVUVSVSTSTMMMMOMLLLLLCLCLCLCLLCCCC@@@@@9C@CCCLCCLCLLMMTMMMLLMLLMLLMLMLMMSSSSMSMMMLMLKLLLLLLLJLLLL:C:=8**((((((((((((.((.(.*(=8@CCLLMTMVSVSSVVSVSVVUVSVVUVVSVVXYVVVVVVVVVVVVVVVSVTVTTMTMOL@@===8/*///*/*.*.*. ( (...(../*/====@=@==F@==2===2===F@F@FCG@G@GGCGGGGGGGOGGGGGGGGGGGGGOOGOOGGOGOGOOOOOGOOGOOOOTOTOOOTOMOOOOMOOMOOMOTTMOOMMOTTMOTMTMTTMTMTMTMTSTTMTMMTSTSTSSTSTSTSSTLCCLCLOLOLLMLOMTXYXYXYXYXYXVVUVVUVSSSSMSMMMMMMMMMMMLLLLLCLCLCLMLMMLMMSTSVSVUVSSSSSSSSSSSSSUUUUUUSSSMSMMSMSMMMMMMMLMLML:C8=*(((((((((((*/*(*/((*(/(/8@@CCLMMTMSTVSVSVSVSVVSVVUVVVVSVVVXVVVVVVVVVVVVVVVTVSVTTTTLCC@@===*////*/(/.(.( (.(.//////===@@F@F@@@F@F==F=F=F=F@@F@G@GGG@GGGGGGGGOGGOGGGGGGGGGGOOGOOGOGOGOOGOOOOGOGOOOOOMOOOMOOTOOOMOOOMOOOOMTTOMOMTMOTOTMTOMTMTMTMTMTMTMTSMTSSTSVSVSVSSVSVVSTLLOLOMMMOMOMMTVX[[[X[Y[XYXYXVXVXVXVVUVSSSTMSTSSTMMMLLLLLLLLLMMMMMMMMTSMSVUVUVUVUVUVUUSVUXVXXXXXVUUUSUSUSUSSSSSSMSMSMLLC:@8**(((((((((%(((((((((((/**/8**/*/**8/=9@CLLMMSTSVSVVVVVVUVVVUVVVVUVVVVXYVVVVVVVVVVVVVVVVSVTTSTMOCC@@@===*///*//(.(/( (..*.///====@F@F@F@=F===2==2==F@F@F@G@GG@GGGGGGGGGOGGGGGGGGGGOOOGOGOGOGGOGOOOOOGOGOOGOOOTTOOOTOMOOOOMOOOMOMOTMTOMOMOTMMOTMTMOTMTMTMMTMTSMTMTMSTSMTSTMTSTSMSTMOCLLLLOLLOLOLTUYXYXYXYXYXYXVVUVUVVSUTSSTMMMMMMMMMLMLLCCCCCCLCLOMOLLMLLMLMSSSSSSSSSSSSSSSVUUXVVUUSSSMSMSMSMMMMMMMJMLLJCC:@8=*((((((((((((*/(/***(/(/*==8@CCLOMTSTSSVSVSVVUVVSVVUVVVSVVVXYVVVVVVVVVVVVVVVVTVTTMOLLCC@@====/*//*/(/(.(. (.(////==/==/==/=//2==2==F=F@F@G@GCG@GGGGGGGGGOGGGGGGGGGGGOOGOGOGGGOGOGOOOOGOOGOOOOOTOTOOTOOMOOOOLOOOOOMOTTTOMOMTOMTMOTMTMTMTMMOMTMTMMTMTMSTMSTSSTMMTSTMMLCCCCCCCCCCCCLTUVSVVVSVSTSTSMMMMMMMOLLLLLLLCCLCCCC@@@9@@8@8@CCCCCC@C@C@@@CCLCLLLLMLLMLMMMMSSSSSMMMMMMMMKLMJLJLLLCJCL:C:@988/(((((((.((**.**(/(/*==@@CCLLMTMTSTVVSVVSVVVUVVSVVVUVYYXVVVVVVVVVVVVVVVSVTTMTMOLGC@@@==/=//*/./(.(. (.../////=/=/2==/2=/=/=2==F=F=@G@G@GG@GGGGGGGGOGGGGGGGGGOGOGOGGOOGGGOGOOOOOOGOGOGOOOTTOOTOMTOOOMOOOMOOMOTMTOMOMOMOMOMTMOTMMTMMTMMMTMMTMMTSMTSMSTSMTSMTSTMMLCCCCCCCCC@CLTSVSVSVSTSSTSTMTMTMMMLMLLLLLCLLCCCCC@C@9==@8=@9@C@CC@@C9@@@@@@CLLLLMLMLMLMMSMSSSSMMMMMLKMMMMJMLL:LC:LCC:C9@9=8((((%(( (((.(*/(/*(*/=8==@@CCLMMMTMSTSVSVVSVVSVVVUVVSVXYVXVVVVVVVVVVXYVVTSTTMOTLOLCC@@===/*//*/(/(/( .(////==/====2==///==/==2=@F=F@F@G@FGGGGGGGGOGOGOGGGGOGGGOGGOGOGOGGOGOOOOOOGOGOOGOOOTOTOOTOOOMOOOOOLOOLOTMTOMOMOTLMTMOTMTMMTMMTMOMTMMTMTMTMTSTSTSMTSMTMTMOCCCCCCCCCCCLSVSVSVSSSTSSTMTMMMMTLMLLMLLLLLLCCCCC@@@@9@=@8@@CCCC@C@@@@9=9@@9CLLLMLLMLMMMMSMSSSSMMMMMMKMMLLJLLC:LCJLC:C:C988/(((((((.((.(*.*/(/*/8==8@CCLLTMMOMTSTVSVVSVVSVVVUVVVVXYYVXYVXYVYYVYVVSTTTTMTMTLOLCC@@==///*//*.((/ .../===@=@F@F@@F@=F/=F/=2=F=F=@F@F@FCGGGGGGGOGOGOGGGGGGGGGOGOGGOGGOGGOOGOOOOOGOGOOOOTOTOOTOTOMOOOOLOOMOOMOTMOMOMOMOMOMTMMOTMTMTMMMMMTMTMSTMSTMMTSTMSTMSVSTMLLLLLLLCLLOSVXYXYXYXYXYUVUVXVVUVUTUSSSSSTMMSMMLMLLLCCCCCCCCLLLLLLLLCCCCC@CCLLMSSSSSSSSUUUUUUUUUSSSSSMSMMMMLMLLKLLMLLLLJC@98**(((.(((.((/*/*.**/*====@@CCLLMOMOMTTSVSVVSVVVVUVVSVVYXYXYVYVYXYVVVUVTSTTMTTTMMOLOCC@===///*/(/(.*  ( (.//=@@@@G@@G@@F@=F=F=F==F=F=F@@F@@GGFGGGOGGGOGGGGGGOGGGOGOGOGGOGGGOGOOOOOOOOGOGOOOOTOTOOTOMOOOOOOLOOOLOMOTMOMOMOMMOMMTMTMTMTMMOMTMMMMTMSTSSTSSTSVSVSVVSVSMMOLMOMOLMOSY[X[X[X[YXXYXYXYXYXVUVVVVSVSUSSTSSMMMLLLLLLCCLCLMMLMLLLLLCCCCCCCLSMVSUUVUUUXVXXXXXXXSUUSUSSSSMMMSMMSMMSMMMMLLC@9**(((((((((((((((((((((.((.(/*/*.*/*/*//8==9@@@CLLLMTMMOMTTMVSVVSVVVVSVVVUYYXYVYXYXYVVVVSVTTSTTTTTMOMOLCC@@==//*/*../(/ .(//==@F@@F@F@@F=====/=F=F==F@F@F@GGGGGGGGOGOGOGGGGGGGGGOGOGOGGOGOGGOOOOOOOOGOOGOOOTTOTOOTOOOMOOOOOMOOMOMTOMOOMOMOMMOMTMOMMTMMTMMOMTMTMSTMTMTMMMTMSTSSTSTMOLLCLCLLLLMVXYXYXYXXYXYXVXVXVUVSUSSSSTSTSTMMMMLMLLLLCCCCCCCCLLLCLCLCC@@@9C9CCMMSSSSSMUSUUUUUUUSSSSMMMMMKLMMLMMLMMLMKLLLC:@8=((((((.((.((.*(/*/*/*/*/==8=@@@CLLOMOMOMMTSVTVVSVVUVVVVVXYYXYVYYVVVVSVTVTVTTTMTTTMTLOLCC@==/*/*/.*..*   ./.=/====/==/=2=2======F==F@@FG@GGGGGOGOGOGGGGGGGGGOGGOGOGOGOGOGOGOOOOOOOOGOOOOOOTTOTOTOTOOOOLOOOMOOLOMOMOMOMOMOMTMOTMMTMMTMMOMMMMTMTMSMTMMMLMTMMTMTSMOLCCC@CC@C@LMVUVUVSVSVSSTSTSMMMMOMLOLLLLLLLLLCCCCC@C@C@@9=8=9@@@@9@@@9=88/8=88@:LLLLMLMMMSSSSMMMMMJLJLLJLLLKLLLJLLJLLL:LC9@88*((  ((.(.((.*.*(/*/*====@@CCCLLMOMOMTTSVSVVVVVVVVVVYXYYXYVXVVVVTVSVTVTSTTTSTMOTLOLC@@==/*/./(/(.  ....///=/=2==/===2=F==F==F=F@G@GGFGGGGGGOGGGGGGGGOGGGGOGGOGOGOGOGOOOOOOOOOOGOOOOOTOTOTOTOLOOOMOOMOOOMOMOMOLMOMLMOMOMMTMMOMTMMMOMTMMTSTMTMTMOMLMMTMTMTMMLLC@C@C@CCCMSSVSVSSSTSTSSMTMMMMLLLMLLOLLLLLCLCCC@CC@@@9==8=8@@9@@@8@==8/***8=8@CLLLJLMMMSMSSMSMJLL:LJLLJLMLMLLLJLMLJLLCCC9@8**(  (.((((.(/(/*.*./*====@@@CLLMMOMOTMSVVVVVSVVVVVVVXYXYVVVVTVSVVTVVTSTTTSTTTMTOLOCC@@=/*//(/.(.  ....//=/=/==2==2=======F==F@@GFG@GGGGGOGGGGGGGGGGGGGGOGGOGGOGOOGOOOOOOOOOGOOOOOOOTTOTOMOOOOMOOOOOMOOMOOMOMOLMOMOMMTMOMTMMTMMOMTMMMTMTMSTMMMLLLOMLMMMTMOMLCC@C@CC@CLTUVSSVSTSSSTSTMMMMOMMLOLLLLLLLLLCLCCCCC@C@@@9==8=8@@@9@=9@8=*.**8=9@:LLLJLMMMMSMSMKLLJCCJLLJMMMMMMLLMLLJLLJCLC9=8*((. (..(((((/(/*/(//*====@@CCLOMTMMTMTSVTVVVVVVVVVVYXYYVVSTVTVTVSVTVSVTTSTTTMTMOLLC@@==//(/.*.(  ...(/.////=F==F@@=====2=F==F=F=@G@GFGGGGGGGGGGGGGGGGGGGGGGGOGOGGOOGOOGOOOOOOOOOOOOOOOOTTOTOOTOOOMOOMOOMOOLMOMOMOLMOMTLTMTMOMTMMTMMMOMMMTMTMSTMMMLLLLMMMTMSTMMOLCLCLLLLMVXYXYXYXYXVXVUXVUVSVSSSSTSSTSMMSMMMLLMLMLLCCCCC@@@CCCCCCCCC@88=8@9CCLMMLMMMMSSSUSSMMMMLKLLMMSMSSMMSMMMMMMLMMLLCC9=8(((((((((( ((.((.(.(( ((..(/*.*.*.(//*====@@CCLLMTMTTMTVVVVSVVVVVVVXYVVSVTVTSVVVVVVVSVTVTSTTMTOMOLGC@@=///*..(.   .(.././////=/==F@@FF=F=F=F=F=F@=F@G@GG@GGGGGGGGGG@GGGGGGGGGGOGOGOGGOOGOOOOOOOOOOGOOOOOOOTOTOMOOMOOOOMOOOOMOOOMOMOLOMOMOMOMOTMMMTMMOMTMMMTMSTSTSTSTLLLLOMTMTSSTMTMLLLLLMMMVX[[X[XXXXXYXXYXVXVUVVVSVSVSVSSSTMMMMMMMMLLLLCCCCC@:CLCLCCC:C@=8@9CLLMMSSMSSMKSSUUSSSSMMMMSUUUUUUUSSSSSSSSSMMMMLC:=8((((((((.(( ((.((.((.(((.((.*((.((..(.*/*/(//*//*/*/==8@@=@CCLOMMTTSTVSVVVVSVVVVSVVVVVSTVSVTVTVSVVVVSVTTVTTTMTOMOLC@@===/.(/(. ( .*..(////////======F=========F@F@G@G@GGGGGGGG@GGGGFGGGGGGGGGGOGOGOGOOGOOOOOOOOOOOOOOOOOTTOOTOTOOOMOOOOMOOMOLOMOMOMOMOMMOMMMTMOMMTMMMOMMMTMTMSMTMLLLCCLLLLMMMMMLLLCCLLLOLSYXYXYXYYXYXXVUVXSVSSSSSTSSSSMMMMMLMLLLLLLCCCCCC@@@9@CC:@CC9@888=9@:LLMMMLMJLLJLMMMKMMMMKLMMSSSSSSSMSMMMMMMMMLLLC@9/*((.(( (((.((((..(((.(((.(.(.(/(.*.(.(/(//8===@@CLOMMTSSTVVSVVVVVVVSVTVUVTVSVTVTVSVVVVVVSTVMTTTMTMOLOLC@===*//(.( ..(......(/.././/=2=/=2=2==F=@F=FCGGGGGGGGGGGGFG@GGGGFGGGGGOGOOOCOGOOOGOOOOOOOOOOOOOOOOOTTOOMOTOOOMOOOOMOOMOMOMOMOMLMOMMOTMOMTMMMOMTMMMMTMSTMTMMMOCCCCCCLCCLLCLC@C@@CCCCCMVSVUVSSSSSTSMMMMLMMMOMLMLLLLCLCCCCCCCC@@@9@8@=88=*88=88=8=8/****=8@9C:LC:C9:999CJLLJLLLKLMKSMSMMMMLMJMLLMLLLL:C9=8(((  (   ( (.(..(.(.(*.(.(.(/(//8===@@CLOMTTSTVSVVVSVVVTTTSVVTVSVVVVVVVVVVVVSVTTSTSTTMOTMOLG@@==/=(/.(.(...//./..(./..//=/===2====F=@F@G@G@GGG@GGFGGG@GGFGGGGGGGGGOGOGOGOOOGOOOOOOOOOOOOOOOOOOOTOTOOMOOOOMOOOOMOOMOOMOLMOLMOMOMMTMMTMMTMMMTMOMTMMTMMMTMMLCCCCCCCCCCLCCC@@C@CCCCLMSVSSTSSTSMSMMMMMOMLMMLLLLLCCCCCC@@@@9C@8@8=8=8=8/**=8=888**/**/*89@C:CL:C9@9@99CJLLJMLMMMSMSMMKMMLMLMLMLLLJLCC9@8=(((    ( (   ( (  (.(.(((.(.(.(.((.((./(/*==8=@CCLMMTMTSVTVVVVVVVTMTTVVVVSVVVVVVVVVVVVSTVTSTTMTMTOMOCC@@===/*/(  (.///////////././//=2===/F===F=@F@GGGGGGFG@GGGGFGGGGFGGGGGGCGOGOOGOGOOOOOOOOOTOOOOOOOOOMOTOOMOOOOMOOOMOOOMOOLMOMOMOMOMMOMTMOMTMMOMTMMTMMMTMMMTMMTMLCCCC@CCCCCCC@C@@@CC@CCCMMSTSSTSSTSTMMMMMMLMMMMLLLLLCCCCC@CC@9@9@@9=8=88=8*=*=88=*=***(**=9@:C:CL::999@99CJMMMMKMSMSMMMMLMMMLMMLMLMLLLCC9=8**(        . (  ( ((..((.((.((.(.(.(.*.*/8==@@CCOMMTTSVVSVVVSVSTTTTTVVVVVXYXYXVVVVVSTSTTSTTTMOTMOLOCC@===//*.  (./=/======@=/=========2===2===F@F@GFGG@GFGGGGGGGGGGGGG@GGGGGOGOGOGOOOOOGOOOTOOOOOOOOOOOOMOTOOOTOOOOMOOOMOOMOOOMOMOMOMOMMOMTMMTMTMMMTMMTMOMMTMMMTMTLLCCCCCCLCCLCLCCLCCLLLLMMVUXVXYXVXVUVUVUVUVSVUVSSSSMMMMLLLLLLCCCCCCC9@C@9@@8@8@9@98=8=8=8@:CCLJLMMLLJC:C:LMSSSUSUUUUSSSSSSSMSMSMSMMMMLLLCC9=8(((      (   (( (((.  (.((.(.(((.(((.((.((.(.(.(.(.*.(.(.((/(/8==@@CLLOMTTSVVVVTVVVTSTTTVVVVVVXYXYVVVSVTVMTMTMTMTMTMOMOLC@@===/*/   (./====@@@@@@==@=F=F==F===F==F=F=F@GG@GFGGFGG@GGGFGGGG@GGGGGGOGOOGLGGOOOOOOOOTOOOOOOOOOOOOTOOTOOMOOOOOTOOMOOMOLOMOMOMOMOMTMOMTMMMTMTMTMMTMOMMMTTSTSTMLLCLLLLLLLLLLLLLLMLMLMMSVXYXXYXXXXYXXYXVUYUVUVUVSSTMMMMLMLLLLCCLCCCCC9C@9@@9@9@@9@8888@9@:LLLMSSSSMLJLLJMSXXUXUXUXUUUUSUUUSSMMMMSSSMMMLLCC@8*(( ( (  ((..((.( (( (((.(.(((.((((.((.(((.(.((.((.(.((.(/(//*/*./*/*/(//*/*/==@@CCLLOMTSVTVSVVVVVTVTSVVVXVYXYYXVVVSVTSTTMTOTOTOMTTMOLGCC@===/*  (./=====@@=@==@F======/====2===F=FGFG@GFG@GGGGGGGGG@GGGGGGGGGOCOOGOGOOOOOOOOOTOOOOOOOOOOOOTMOOMOOTOMOOMOOMOOMOOLOMOMOMOMOMTMOMTMMTMTMTMMMOLOMMMMMTMMOCCCLCCCLCCCCCLCLLLCLLMMSVSVXXYXYXXYXVUVUSVUVSVSTMSMMMLLLCCCCC:C@:@9@@9@@9@8=88=88**/**88@9CJLLKSMMLLJLJLLSUSUSUSSSSMSSSSSMML:LCLLMMLLLL:@8=*.(  (    ((  . (((.( .(.((.(((.(((.(.((*.(.(.(.(.*.(.(.((.((/*/*==@@CCLMOTSVTVVVVVVVVSVTVVYXVYXYVVUTVTSTTMTMMOTOOOTMOTLLO@@@===*(./*//=/=====/===/=//=2=====F=F=F@FFGFGGFG@GGGGGGGGGGGGGGGGGGOCOGOGOGOOOOMOOOOOOOOOOOOOOMOOOOOOTOOOMOOMOOMOOMOMOLMOMOMOMMOMTMMOMTMSTMTMMOLLOMMMTMMTLLCC@CC@@C@9C@C@C@CC@@CCLLMMMTSSSTMSMSMMLMMMMLLLLLLCCC9@@9@9=988=88/8=8**/*8*/**((((((((**88@9C:LKLL::@::CJMSMMMMKLKLMJMMMMC:@9@9@:CLL:CC9=8*((.( (   (     (. ( ( (  ( (.( ((.((.((.(.(.(.(.(/(/.*==@@COLMTTVTVSVVVVVVVVVVVVVXYXYVVSVTSTSTTMTOMOOMOOTTMOMLCC@@=/= .////=//====/===2====/===2==F=F=GFG@GFGFGGGGGGGGGGGGGGGGGGOGGOGOGOOOOOOOOTOTOOOOOOOOOOOOMOTOMOOOOOMOOMOOMOOLOMOMOMLMOMTMOMMTMMTMTSMTMMLLLLOMOMMTMMLCCC@C@@@C@@:@CC@C@C@CCLLLLMMMSSSMTMMMMLMLLMLMLLCLCCCC9@98@8=88*=***8*/8**/***(*((((**=899CJLLJL::@:CJMMSMKLMLKLMMMKMMLC9@8=9=:CLCCC9@8/*((  .    .    (  ( (.( (( (.(.((.(.(.(.((.(.(.(.(/*.*/===@@OLTMTVVVVVVVVVVXVVVXVYXYVUVTSTTVTSTTMTOMOOOMOOTTMOLC@@==/ .////====@===/====/==2=2==F/F=F=FFGFG@GFGGGGG@GGGGGGGGGGGGLGOGOGOGOOOOOOOOOOOOOOOOOOOOOOOMOOOOTOMOOMOOOLOMOMOLOMOLMOMOMMTMOMTMTMTMTMTMOLLCLLMMMTMMOLCCC@C@@@:@@C@CCCCC@CCCLLLMMTSTSMSMTMLMLMLMLLLLLCCLCCC9@9@89=88*=*/*8*/****(**(((((((**8=9:CJLMLL:C:C:MMKMMLJMLKLMMMMMML:8@8888@9CCC:@@8/* ( (.   (   ..( ( ( ( ( (( ( (..(.(.(.(.(/(.((.(.(/(.*/*===@@LOMTVTVVVVVXVYVXYXYVVVVVSVSTSSTSTTMTMTOOTOOTOTOOMOCC@@==  ..(//==@=@@G@@G=@@=F=====/F/==F=2F@FFGFGFG@GGGGGGGGGGGGGGGGGGOGOOGOGOOOOOOOOTOTOOOOOOOOOOOMOTOMOOOOOMOOMOOLOOMOMOLMOMOMLOMOMTMMMTTMSMTMMMOLCCLOMMTMTMMLCCCCCLCCCLCLLLLLLMMMMMSSSVUXVXVXVUVSSVSSSSSSSMMMMLMLLCLC:C@9@8@89=9@8@8=8=8**8***((*(**=9@:CJLMMSSMMLKMMSSSSSSSSSSSSSUSSSMC@9@@9@9CJLLCC9=**   (  (  (( (.( (( ( ((.(.(.(.(.(.(.(.((.(((.((.(.(.(.(.((.*.(.(.((.(.(/*./*/===@@COMTVSVVVVVYXYVXYXYVVUVSVSTSTSTSTMTTMMOOMOOTOTOOLLCC@==   (.(.//===@@@GCGC@G@G@@@F=/=2==2=F=F=FFGFG@GFGGGG@GGGGGGGGGGGGGGOGGOOOGOGOOOOOOMOOOOOOOOOOOOOOMOOOOTOMOOOMOOMOOMOLOMOMOMLOMMOMMOMTMTMTTMMTMOMLCCLLOMSTSSTMMLLLLLLLLMLLMMMMMMSTSSSVUXXYXXXYXXVSVSUVSVUSSSSMSMMMLMLLCCC:@9@9@9@@9@9=88=8=8*8********8@:CLMSSSUUSSSMSUUUSUUSUUUUXUUUUUUMLC:@@:@:@CLLLC8=*(  .( ((.( (( .(.((.(.(.((.((..(.(/.(.(.((.(.((.(.(.*.(/(.(/(/*.*./(./*.*.*.(.*.(*/.*/*///===@CCOTSVVVVVXVVYXYYXYUVSVVVVSVSVSTVTSVTVMTOTTOTOOOOCCC@==  . (.///==@@@CG@@C@==F==/=/==2==F==F=FFGFGFGG@GGGGGGGGGGGGGGGGGOGOGOOOGOGOOOOOOTOTOOOOOOOOOOOOTOMOOOOOMOOMOOLMOMOLOMOMOMOMOMOMMMMTMTMTMTMMMMOLCCCLLOMTMMTMLCCCCCLCCLLLLLLMMTMSMSSVUVXXVXUVUSSMSSSSMTSMMMMMMLMLCL:CC:@@88=8=8@8888=8*********(*(((*88C:CJMSMSMMMMKSSSSSSMSSSSSSUSSSSSLC9@9@9=99@9@88((   .( (( ( ( ( ( (. ( ( (. (.(..(.(.(( (.((.(.(.(.(.(.(.(.(.(.((.((.(.(.((.(.(.((.(.*///8/==@@COMTVTVVVVVVVXYVVVSSVSSVTSTSTSTTSTSTTMOOOTOTMOOGC@@==   ..(/./=/==@========//=/F/F=F=FF=FF@FG@GFGFG@GGGGGGGGGOGGGGGOGOGOOOGOOOOOOOMQMOOOOOOOOOMOOMOOOOTOMOOMOOMOOMOOMOMOMOMOMOMOMOMTMMTMTMTMTMMTLLCCCCLLMMTMLLLC@C@@:@CCC@CCCCLLLLMLLMMMMSMTSMMLLCLLLLLLCLCLCC:C9C9@9@8888/8*****/***((((((((((((**8@9:CJLJL:LCJMMMLMLLKLMMLMMMMMLMC88=8888=88*/*(   ( ( (     (.  ....  ( (.((.(.(..(.(.(.(.((.((..(/(//*//=/==@@COTTSVVVVVVVVVUVSVSTVSVSTSTSTSTTSTTSTTOMOTOTOOCG@@==    .(././=//@==/====/=2=/=F==F=F=F=FGFGFG@GFGG@GGGGGGGGGOGGGGGOOOGOOOGOOOOOOOOTOOOOOOOOOOOOOMOTOOMOOMOOMOMOOMOMOLOLMOMOMLMOMMOMMTMMTMMTMMOMOLCCCCLOLMOMMLCC@@C@C@CCCCCCCLMLMLMLMMMSMMMMMLLCCCCLCCLCCCC:@C9C@9@9=9=*8*/*/8/**/*(((((((((((((*88@:CJLC::LLKMMLMLMLMLMMMMMMMMLMC988=88*=*8/*((    (.( (.   ( . ( (  ( (... (( ( .(.( ((( (.((.(..(.(..((.(.(.(/(///=*=/===@CCOSTVTVVVVVVUVVUTSVSVSVSTSVSTSTSTVTSTOTOMTOOOCG@C==  ..(./////====@=====/=/==/==F==F=F=FF@FG@GFGG@GGGGGGGGGGGOGGGGGOGOOOOOOGOOOOOOMOOTOOOOOOOOOOOOMOOOMOMOOOOMOOMOOMOMOOMOLMOLMOMMMMMTMMMTMMTMMMMLL@CCCLLOMLMOLLC@@C@CCC@CCCLLLMLLMMMMMTSMSMMLLCCLCLLLLLL:CCCC9@9@9@@88=8*/8***/****(((((((((%((*889:C::C::LLKMMMLMLMLMMMMMMLMMLLC8=8=888=***.(  ...( (   ..( ( . ( ( (..  .((.( (( (.(.(...(.(..( (.(.(.(.*//=/=*====@CCOTSVTVVSVVVUVVSSVSVSVSVSTVSTSTSTTVMTMOOTOOOGCGC@@  ..(.//////======@@=@GCF@@=F====/=F=F@F=FF=FFGFG@GFGFGFGGGGGGGGGGOGGGOGOOOOOOOOOOOOOOOOTOOOOOOOOMOOOOOMOMOOOMOOMOOMOMOMOMOMOMOLOMOMOMOTMMTMTMMMOMTMOMOCCCCCLLMOMMMMLLLCLLLLLLLMMSSSSSSUVUVXVXVUUSMMLMMMMMSMMMLLLLLLLLLCCC:@9@9=8@89=8=888*********(*((((((%**@9C:LL:LCJMMUUUUUUUSUSUSSSSSSSSSMLC9@9@9@8=8**((   .(.( ...(..(..(..(...(.(..(.(.( (..(.(.(.(.(.*./(.(.(.(.(./(..((.(.(.((..(.*.//===/=/==@@GCMTTVSVVVSVVVSVVVVVUVVSVVSVTSTTSTTVMTTOTOMOGCGC@@ (.(.(//=====@=@@@@@@C@@LGC@@@F=F@F=F==F@FF=F=F@G@FGGFG@GFGGGGGGGGGOGOGGOGOOOOOOOOGOOOOOMOOOOOOOOMOOOOOLOOOOMOMOOMOOMOOMOOMOMOMOMOMOMLMMMTMMMTMMOTMMTMMTMLLCGCLOMMTMTSTMMLLMLMMMMMTSSVUVUVXVXXYXXYUSSMLMMMSSSSMSMMMLMLMLLLLC:CC9@@9@@9@99=88*8***88**8(*****(***89@:LJCJLMJSSXXXXXXXUXUUUUUUUUUSUMMCCCC:C@9@8=**(  ( ..(.(..(.(.(.(..(..(...(..(././*/.(/.(.(.(..(//(/*/*//*//*//*.//(//.*.(/(..(..(.*./.*/=========@=CCOMTVVVVVVUVYXYXVYXYXYXVVVVVSVTVSVVSVTTOTOOOOLCGC  ..//======@@=@@=@@G@CG@@F=@==F===F==@F@F=F=F@GFG@GGFGG@GG@GGGGGGGOOGGOGOOOOOOOOOOOOOOOTOTOOOOOOOMOOMOOMOOMOOMOOMOTOMOMOMOMOLOLOMOMOMMOMTMMOMTMTMMOMMMOLCCCCCLOLMMMMMLLLLLLLMLLMMMTMSTSVUVXXVUUVMMLCCLLMMMMMMLLLCLJCLC:CC:@9@9@899=9=88=*8/*8*******(((%(((((**89@9:@JCJLMSVXVXVUUVSUUSSSSSSSMSMLCC:@9@9888/((    (...( ( ..(..(..(...(..(..(.(.(...(.(.(..(.(..*.*./(..*.(.(.(.(.(.(.((.(..(.(/(/==/===/===@@COMTMTSVVVSVVVVVXYXYXYVUVSVTSSTSTSTTSTOMOOOOGGCC  (.//=/==/==========C===/==/=@===F@F=F=F@F@GFGG@GFG@GFGGGGGGGGGGGOGOGOOOOOOOOOOOOOOOOOMOOOOOOOOOOOOMOOMOOOMOOLOMOOMOMOMOMOMOMOLMOMOMTMMOMTMMMMTMMTMOMLL@C@CCCCLOLLLCCCCCCCCCCCCCCLCLCLLMMTMMMLCC9=8=9CCCCCCC9@9@9@9@88=88=8*8/********(((((((((%(((*(**888@99CCMSMSMMMMMLMLMMLMLMMLLLCC9@9@8=***((  (  ( ( ( (     .( .. ( ( (.(.   ...( (.(..(.(.(.(..( (.(. (.(.(.(.(.(.(./*/==========@CGLMTVTSVTSTVSVVVXYXYXVVSVTSTSTSTVSTSTMTOTOOLOGC .(///=/=///===/=====@/==/F==F===F@=F=F=F@F@G@GFGCGFGCFGGGGGGGGOGOGOGGOOOOOOOOOOOOMOOOOTOOOOOOOOOMOOOOOMOOOLOMOOMOOMOMOMOMOMOLMOMOMMMOMTMMOMTMMOMMTMMTLCCC@@CCCLLCLCCCCCCCCCC@CCCCCCCLCLMMLLLLC@88=8=8@C:C@@9@9@9@8@888=8**=**8******(*(((((((%(*((((****889@9:CMMSMMMMLMLMMLMMLMLMMLLLCC:@C9=***((     .( ( .  . (... (. ... (.  ( (...(.(..(.(..(..(. (..(.( (.(.(. (.(//==========@@COMMTTSVSTTTTTSVYXYXYVSVSSTSTSTSTVSTTTTTMTOOOLG   .(//=/=//====@===@=@G=======@F===F====F@F=F@GFGG@GGGGG@GGGGGGGGGOGOGOGOOOOOOOOOOOOOOOTOMOOOOOOOOOOOOLOOOLOMOOLOMMOOMOMOMOMOLMOLMMOMMMMOMMMTMOMMTMMOMMMOCC@C@CCCCLCLCCCCCCCCCC@C@CC@CCCCLLMLLCC9=8=88=9CCCCCC9@@9@98=888=8**=*/*8****(*(((((((*%((%((((*8=89@99CMMMMMMLMKLMLMMMMMMMMLLLCC:C:@8/*((  (  ( .. (   . .. ( ...( .(.. (.  (..( (. (/(.(.(..(.( (. (.(..(..(.(..(.(//=========@@CLOMMTTSVTSOTTTTVXYYVVSVTSTSMSTSVSTVSTTTTTMOOOC  ( .(//==@===@@@CC@CC@GCOCG@G@F@F@F====F=F=F@F@GFCFGG@GGFGGGGGGGGGGGOOGOGOGOOOOOOOOOOOOOOOMOOOOOOOOOOOOOLOLOLOLOLOOOMOTOMTOMOMTOMLOMOMTOMOMMOMMOMTMMOMTMTMLLCCCCCCCLLLLLLLMLLMLLLLMLLLLLLLMMMMMLMCC@C9=@@CCLMLLLLCLCCCC9@@9@9@9@89@8@88=888********8*8*(((((((*****8*89@:CLLLLMSUUSSUSSUSSSSSUUUSSSMLMLMLMLC98***( . . (.(.. (. ( .(. (...(..(...(..(./.(.(.(..(...(..(./*.//*./.*...(.(.(.(..(.( (..(.(..(//=/======@@@COLTSTSVTTMTOMTTVVXVSTSTSSTSTSVTVSVVTSTTTTTOMO     .(..(//==@=@@@CGCOCOCOCGMOCGCGC@C@@F===F==F=F=F@GFG@GGGGGGGGGGGGOGGOGOGGOGOOGOOOOOOOOOOTOOOTOOOOOOOOOOOLOOLOOLOLOMOLOMOMOMOMTOMOMOMOMOMMOMMOMMOMMMOMTSMTSTSMMLCLCLLLLOMMMMMTMMMMMMMLMMLLLLLLMLMMLLCCCC@9CCCLMMMMMLLLLLC:CC9@9@@9@9@@9@989=88=8*88***888****(****888888=9C:LLJMLMSUXUUUUUXVXXXXXXXVSMMMMMMMMMLC8=8*(((((  (( .(..(...(..(..(..(...(..*...(..//(////././(..//.*///*//./*=/////////*//.*..*.(.(./(.(..(/*//======@=@@GLLMTSVVVVSTTTTTTSVYXVVVVSVSVSVVXVYXYVVTVTTMTOM      ...(/.=====@@CCGCCCCGCOLCCG@@F@F@=2===F==F=F@F@GGFG@GGG@GGGGGGOGGGGOOGGGGOOOOOOOOOOOOOMOOMOOOOOOOOLOOOLOOLGLOLOOLOMOMOTMTMOMOMMOMLMOMMOMOMOMMOMOMMMTMMMTMMOLCCCCCCLLCLLOLLMOLMLLMLLLLLCLCCLLCCCCC@9@9@@9@CLLMLLJCLC:C@9@9@99@8@88@9=8=88=8*8***********((((****8****88=9C:CCJCLMSUSUSVUUVXVXVXVSMMLC:LLMLLLC98=**(((   .. (.. (. (  .(...(........(..*..(..(..(..(.../(//*./*///.*..(.(.(.(..(.(.(.(.(..(.(.//=======@@CCGLMTSVVTTTMOMOOMTSVTMTSTSTSSVVXYVVSTTTOOOOOL     .(///===@@@@@@@@@@G@F@=F==F====2=F@F=F=F@GFG@GFGGGGGGGGGGOGOGGGOGOGGOOGOOOOOOOOOOTOOOTOMOOOOOOLOOOLOLOLOLOMOOOMOMOTMTMOTMOMMOMOMOMMLMOMOMMMOMTMMOMTMMMLCC@@@C@CCCCCCCCCCCC@C@C@@@9@@9=@@9=8=8=8=8*88=9CCCC9@9@888=*8*=*8**/******(*((((((((((((%(((*(*(((**8=89=9@9CLMLMMMMSSSSSSSMC9@88@9@:CCC9=(*(   . .. (. (   .   . (. ...(..(..( ( .( .(..(...(...(.(..(..(.(.( (( (..(...(.(./(//=/=====@@CCLOMTSVSTTMOOLOOLTMTSTSTSTSVVUYXVVTTMTOOOLOO    .(///===@@G=F@@F@CG==@=@F=F==2=F=F=F=F@F@GFG@GG@GGGGGGGOGOGOGGOGGGGGOOOOOOOOOOOOOTOMOOOOOOOLOOOCOLOGLOLOLOOMOLTOMTMOTMOMTOMMOMMOMOMOMMOMOMMTMMMTMMMMMMLCC@@C@CCCCCCCCCCCCCC@C@@@@9=@9==8=8/8/8/*/**=8@C9C@9@9=888/8**/*=**/*/***(*(((((%((((((((((%(*((((**8=8=99@:LMMMMSSSVSSSSML@88=*8@:CC:C9/*/(      ( .( ( (     (  ( .. .(....(. ( .( ..(. (...(/.(/.(..(. ( (...( (..(. (.(.(...*/=/====@@@CCOMMTSVTTMOMOLOLOMTSTVSVSVSVVXYXVTTTOTOOGLO    (   (..///=@@@@@C@@G@@GC@F======F====F@=F=F=FF@GFGFGGGGGGGGGOGGOGGGGOGOGOGOOOOOOOOOOOOOOOOTOOOOLOOOLOOCOLGLOLOMOOLOMOMOTMTMOMMTOMMOMMMOMMOMMOMMTMMOMMTMMOMMOLC@C@C@CCCCCCCCC@CCC@C@C9@=@@9@=8==8=8/8=*=8/9@CCC:@9@9=888/88=***/****(*(*(((((((%(((((*(**(*(((**88=9@9@:LMMSSSSSSSSSML9=*8**=8@:CC98=(*(   (  . (.( ..   . . . .( .......(.. (..(..(..(...(/.(..(..(..( (.(.(....(..(.(./.*//=/===@@@CCOMMTVSTTOLOLOLOOMTSVSVVSVVXYXVVVMOOOOOCOO....(..././(..(././===@CCGCOCGCLGCGLO@@GF@F=@F/=F=F@=F=F@F@GFCFG@GGGGGOGGOGGGGGGOGGGOGOOOOOOOOOOOOOTOMOOOLOOOCOOLOLOOCOLOLOMOMOOMOTMOTMMOMOMMOMOMTMOMMOMMOMMOMTMTMMMTMTMMLCCCCLCLLLLLLLMLLLLLLLLLCLCCCCCC@@@@@@@9@9=9CLMMLLLLCCCC9@@9@9@8@88=8888=88*8**********(*((((((**88*88*8*(**=8@:CCLLLMSUUVXVXXVXVUMC@98=88=:CLMLL@8=**((((   . (. .(......(.. ..(.. (......../.../...(../././/.*/.///////...(..(.(..(..(..(..(..(.(././//====@@@CLOMTSVTSOLOLOOLOMOVVVVUVUVVXVVVVTOMOOOGOG .(.(..*./*///./////==@@@GCLOLOLOLOCOLOCG@@G@F@@F===F@F=F=FF@GFG@GFGGGGGGGOGOGGOGGGOGOGOOOOOOOOOOOOOOOOOOMOOOGLOOCOGLOLOCOLOOLOOLOMOMOTMTOMTMOTMMOMMTMOMMOMMTMMTMMTSTSTSSSTMMLLLLLLMLMLMMMMMMMMLMLMLLLLLCLCCCC@@@@@@@9@CLMMMMLMLLLC:CCC9@:@9@9@8=898=88=888*8*********((((**8=8=88=****=8@C:LMMMMMSVUUXXXXXXXVSC9@9=9=9CLLMLC9@8=*(((((((((  ( (.....(..(..(...(.....(.......././/./////.//./////////////=//=/////////*..(.(.(..(.(..(.(.(//(////=/===@@CCGMMTSVVVVMOMTTTTTTVVXYXYXVXYXYXVVTOOTOOOO .(.(.(/./.*////=/===@@@GCCOCOCGCG@GLG@@F@F@F@=2=F=G=F=F=FF@GFG@GGGGGGGGGOGOGGGGOGOOGGOOOOOOOOOGOOOOOMOOOOOLGOOCOOCOLOLOLOOLOMOOOMOMOMTMOMOMTMOTMMMOMMMMOMMOMMMMMMMTMTMTSMMLCCCCLCLLLLOLOLLOLLLLLLCLCCCC@C@@:@@8@8=@8@LLMLLLL:CCC:@9@9@@9@88888=8**8*************(*((((%((***8*****(**8=9CLLLLMLMMMMMSSVXVUUSL@98=88=9@:CCC9@8=** ((    . ( .(...(..... (................./..(...../../*////////////.*/..(.(.(.(...(..( (.(..(.(..*/(//*/==@@CCOLMTTSTMOMOMOTMOMVVVVVVUVYXVVSTMOOOOGOO   ....*///======@F@@@@@@=@==@@=F==F=@F==F=F@F@F@F@F@GFGG@GGGGGGGGOGGGOGGGOGOGOGOOOOOOOOOGGOOOOOMOOOOCOGLOCOGLOOLOLOMOOLOLOMOMOMOMTMOMTMMTLTMMOTMMOMTMMTOMTMMMOMMTMOLCC@CCC@CCC@CCCCCC@@@@@9@@@9=9=8=8=*=*8**=8@C:@C:@C9@88=88=*8**/****((*((((((((%((((((((((((((**8=9@:C:CC9CCCCCLMMMLL9=***(***=89=8*/*((        .. . ( ( .. . .(. ...(...(. .(......(....(..(..(..(. ( (.( .(....( (..*.(//(//*//==@@CGLMMTTSTOLTMTOMOTSVSVSVVVVSSTSTMOOOGOO   .(..///=======@=@@F====F=F@===F==F@F==F=FCF@F@F@FGFG@GGFGGGGGGGOGGGOGGOGOOGOGOOOOOOOGOGGOOOOOOMOOOCOCOOCOOLOOOOLOLOMOLOLOMOMOMTLTMMOMMTMOMMMTMMTMMOMMTMOMTMTMMTMLL@C@CCC@CCCCCC@C@C@C@C9@@@=9==8=8/8*/*/***@9C@9@9@99@88=88*=*8****(**(((((%((((((((((((((*/88@@:C@C:CC9@9@:LMLMC9/*/*/*8*=8=8**/*(     .. ...  . ... . ( . ... . ... .(...../(.../...(/..(...( (...(. (..( (..(..(..*/./(//*==@@CGLOMTSSTMOTMOTOMTTVSTSSSTVTSTTSMOOOGO  .(../*//==@@@@=@@@F@@=F====@F@F===F=@@F==F@F@F@F@FF@GFG@GGGGGGGGGOGOGGGGOGOOGGOOOOOOOOGOGOGGOOOLOOOLGOCOOCOLOOLOOOOLOOLOLOMOMOMTMOMTMTMOMMTMMTMMOMTMMTMTMMTMMMTMMTMLLC@@CC@CC@CC@CCC@@C@@@9@9@@8@=8=8/*/***/8@@:@:@@9@@9=888/88***/***(*((((%(%((((((*((((((*8=9@9CC:@:@9@9@@:LMLLC9=***/**8/8=*8*/((       ( ... . . ( .. . .  . .( ..... ...(...../(.../.(...(..(..( (..(. (..( (...(/(./(/.*/./*==@@CCMOMTSTMOMTOMMOTSTSTTMOTMTSMTMTMOOOG (.(././/==@@CCCOCGCGCC@CG@C@G@GCG@@G=@F@@F=F@F@GF@F@F@FGG@GGGGGGGGGGGOGOGOGGOGOOGGOOOOOOOGOGOGOCOOOOLOOCOGLGLOOLOOLOLOOLOLOLOLOLMOMOTMMOMTMMTMMOMMTMTMMTMMMTMMTMTMTSSTMLLCLCLCLCLLLLLLLLLLLLLCCCCCCCCC@@@@8==8=9CLLLLLLCL:LC:@:9@9@99988=88*******(**(***(*(((*(%(((((((**888***((*=89@CLLLLLLLLLCCJCLMSSMML@9@8@@9@@9@@8==*/((    (. ( .(.............................../../../././///////////.///././(..(.(..(.(.( (...(.(..(/.*.*./(//(//==@CCOMMTSTTMTMTMOTMVTSTMMOMOMTTSTMTMOOO   (..*//===@@CGLOLOCOCOCGCCGCGCGCGLGCG@GCFGCF=F@FCF@F@FF@GGGGGGGGGGGGGGGOGGGGGOGOOGOGOOOOOGOOGGOGGLGOOOOLOCOGLOOCOOOMOOMOOLOLOLOLOMOMTMOMTMMOMTMMTMOMMMTTMTTSTSTSVSVSVSSVMMLLLLLMLMLMOLLLMLLLMLLLLLLLCLCCC@@@8=8@CLMLMMLMLLLLL:CC:C:C9@9@99=8888****************(**(**(*((**=88=8(**/*8@:CLLMLMLLMLLLLCCLSSUSUMLCC@9@C@CC@C9==**((((((((((   ...(. .(.....././..........//..........///./////.////////////////////////.*/.(.*..(/.*.(..(..(..*///*///////*/==@CCMOMSVSTSTTTTSTVVVVSTTMTOTMVTVSVSTTO .(.//===@@CGLOLCLGCGCGCG@@GC@COC@G@FC@@G==F=FCGF@F@FG@GGGGGGGGGGGGGGGGGOGGOOGOOGOGOOOOGOGOGOCGOGOLOOOLGLGGLOLOLOOOOOLOLOLOLOLOLMOMOTMMOTMTMTMMMTMTMTMTMMTMTMTMTMTMTMTMOLCCLCLCLCLLLLLLCLLCLCCCCCCCCC@@@9=8=8@:CLLLLCL:LC:C:@9@9@9@99=888=8*********(**(*((((%((*((((((((*****((((**=8@:CC:LLLLJLCC:CCLMSSSSMLLCC9C@9@@@@8=*/(((     .. . ( .......... ............... ../..../..././////////////.//.//.(.(.(..(.(.(.(..(.(.(.(..*..(/*/.*//(//*==@OCOMTSMTLMMTMTMTSTSMMOLOOOLTMTMTSTL  (.///==@@@@G@@@@@@=@@@@@@F=@@F===F@F@G==F@FCGF@FGF@GGGGGGGGGGGGOGGOGGOGGOOGOOGOGOOOGOGOGGOGGCOGLOOLOGLGCOOLOOLOLOOLOLOLOLOLOOMOMMOTMMTMMMTMTMMMTMTMTMMTMMTMMTMMTMMTLLCCCC@CC@C@@@@@@@@@9@@@@9@@8=8=8=*/**=9@C:@9@9@9@98=88888/8**8***(((((((((((((((**/88=9@9@9@9@9=8@9LLLLMLLC@C9@@8=8=***(.      ( . .. . . ..... . . ..............(....(....(....(..(..(.(.(..(...( ..(...*.*./(/.*..(/.*/=@CCCOLOLOLOMOLOMTSTTMOLOCOGMTMTSTMT .(//===@FC@@@F@@@@F@F@F@===F===F=@@G@F=F@F@GF@FF@FGGGGGGGGGGGGGGGGGGGGOGOOGOGGOGOOGOGGOGOGOGLGOOOOLGLGOCOOLOOOOLOOLOLOLOLOLMOMOTMMOMMMTMMTMTMTMTMSMTMTTMTSTMMTMMOMMLLC@C@C@CCC@C@@@@9@=9@@8@==9=8==*/**/8@@C9@:@9@88=888=*=8*8******(*(((((((%((((**=88@9@9@@9@9=9=CLLLLLLLLCCCC@=8/8/*.(     (  .. .. . .. . ... . . . . .... ... ...../......(......(...(...(..(..(.( (..( .(.(..*///*./(/.(.//8=@@CLGLCLGLOLGLMTSTSTMOLOGOCOMTSTMT  .*/===@@@G@@@@@G@@F@@@@F@=@F=F==F@F@F=F@F@GG@GF@FGGGGGGGGGGGGGGOGGOGGGGOGOGOGGOGOOGOGGOGGGCGOCOLOOLGOCOOCOLOLOOLOLOLOOLLLOOMOMOMTMOTOMTMTMTMTMTMTMTMTMTMTMTMMOMLMOLLCC@CCC@C@@@@@@@@9@@@@@@9@==8=8=8/88=@:CCC9@@9@988=88=*88/8******(*(((%((((((((%(((((**=8=9@9@9@8@9=9=CLMMLMLLMLLLLC@=8=*/*.      .. . .. . ... . . . . . ........... ...../..(../..(....(...(..(...(..(..( ( (.( (/.//////*.(./(.///@@@@CCCCCCCGLGLTSTSTMMMOLGOOMTTMTM     .//==@@GCOCGCGCGLGCOLGOLGCG@G@@F@F@G@G=F@F@G@FFGF@FGGGGGGGGGGGGGGGGGOGOGOGOGOGGGOGOGGOGCOGOCGCGOGOLOCOGLGLOOLGOLOOLOLOLOOLOLOMOMOMOMMMOMTMTMTMTSTMTMTMTSTMTSTMMOMOLLMLLLCCLLCLLLCCCLCCCCLCCCLCCCC@@@@9@@LLMLMLMLLCCC:C9@99@9@99@98888888*8*****(*(**(*(**(((*(*((((((((((((((((((*/*8=9@CCL:CCCCCLCCLSSSUSUSUSVSSSML@@@==8/((((     .(. . ( . ............................../../......////./////.//.//././(...*..(..(..(...( (..(..(//==/////.//.*//@=@@@@@@CCOCLOLMTVSTSTMOMOOOLTSTMT   ..(.//@@@GLLOLOCOLOMOOMOMOLGCGCGC@G@FCFCF=F@F@GG@FFG@GGGGGGGGOGOGGGGGGGGGGOGOGOGGGOGOGOGGGGOCGOCGOLOOOLGLGOCOOLOLOOLOLOLOLOLOLMOMOTLTMOMMTMTMTSTMTTSTSSTVSVVSVSTTMMMMOMMOMLMLMLMLLLLLLLLLLLLLLLLLCCCCC@@CLLMMSMMMMLMLLC:C:C:@:9@9@9@98=88888888********************/**(((*(((((((((*/88=9@:LLCLCLCLLLLLMVUVUVUVUUVVVUUMCC@@==/*.((((((((     .(. .(...................././/.//..../././//////.//////////////=//////////////.//*///..(.(..(.(..(.///===@===///////=@==@=@@@CCLOLMOTSVVVSVTSTMOTTTSVTS    ...*/=@CGCLGLCCGLOLOLOOLG@@@@G@F@=F@FC@F@F@FG@FGF@FGGGGGGGGGGGGGOGGOGGOGOGOGGOGGGOOGOGOGGGGCGOCGGLOOOCOGLGOLGOLOLOOLOOLOLOLOOMOMOTLTMOMMMTMTTMTTMTTTMTMTTSTMTSTMOLLCOLLLLCLLCLCLCLCCLCCCCLCLLCCCCC@@C9CCLMMMMMMLLLCC:C:C9@9@9@98=888888=8*8*****(*((*(***(*((*(*((((((((((((((((*(8=8@9CC:CCCC:CCCLSUVSUVSVSUSVUTUMC@@@8//((     ( . (. .. ( ............................/2/././...././//////.////././././.(./(...(.(..(. ( (.(.(.(.//=====///(/./*===/=*==@@CCOLLOMMTSTMTMTMOLOMTMTM   (../===@@@G@@G@GCGCCG@@F=F==F=F==FCFG=F@FF@GF@FF@FGGGGGGGGOGOGGGGGGGGGGOGOGGOGGGGOGOCGOCOGGGOCOGOOLOOCOCOOCOCOOLOOLOOLOLOMOOMOTMOMOMOMOMTMTTSTMTMSTSTMTTSTTSMMOLCCCCC@CC@C@C@@@@@@@9@@9@@@9@@9==8=8=9@@CCLCCC:C9@99=88=**8*8*8*8***(***(*(*(((%((((((((((((*/88=88=8@9@9CCMMMLMLMLMMLMMTML@==*/((      . . . .. . .. . ... .........................(....(....(...(..(..(..( ( ..(/.(/====/=//./..*/=//*///==@@CGCLOLOMSTMMMMMOMTMTTM   ..///==@@@G@@GCGCFC@F=@==F=@F=F=F@G@@FF@FFG@FG@FGFGGGGGGGGGGGGOGGGGGOGGOGOGOGGOGGOGGCGGGOCGGCOGLOOOOGLOGLOOCOOLOLOOOMOOMOMOMOMOTMMOTMTMTMTTMTTSTTMTMTMTSTMTTMMOCCCC@CCCCC@@C@@@@@@@@=@9=@@9@=9=8==8=@@:CCCC:CC9@@989=88*=*8/******(*(*(*((((%((((((**/8=8=8=8@=:CLMLMLMLMLLMOMMMMLC=*/(.    . . ( . . . . . . . . . .. ../.......................(.....(..(...(..( .....( ( (....(/=@==/=/////.*////(//8=@@@CGCOLCOMMMTMMTMOMTMTT   (...//===@@G@GCCGCCG@G@F=F===F@=F=@FCF@F=F@F@GF@FGFGGGGGGGGGGGGGGGOGGGGOGGOGOGOGGOCGOGGLGGGGOCGGOGLOOOLGOGOCOLGLOOLOOMOOLOOMOMOTMOMOMMTMOTMTMTTMTTMTSTMTTSTTMTMTLLCCCC@C@C@C@C@C@@@@@9@@@9@=@9==8=8==9@@CCLCC:CCC9@9@888=888**8**********(**((((((((((((((((/**8/8=9=9@@LMMMLMLMMMMMTMTSTSMC==*(.       . . ( . . . . .. . . .. ................./../.../...(/....(..(/..(......( (..//.(//====//////*/=//*/.//==@@@CGLGLOCOMMTMMOMTMTTM   ...(//===@@@GCOLOLOLOOLGCGCGC@F@@G@@F@F@GG@FF@FF@GFG@GFGGGGGGGGGGGGGGGGGGGOGGGOCGGLGGGOGOGGCGGCGGCGLGOOLOOOCOGOLGOCOOLOLOOOMOMOOMOMOTMTMOTMTMTMTTSTMTTSTMTSMTMTTSTTSOLLCCCLCLCLCLLCCLCCLLCLCCCCCCCC@@@@@@CCLMMMMMLMLLLLCCC::@9@99=888888888888*8*8****(*(****((***(((((((((((((((((((/*8=8=9@9CC@CLMUVUVSVSVSVUUVXVXYXVMC==*/(       . ........ ..............................//./../.././//////.//.///.////.././(...(..(. (.( .(.. (.(/..(/=======/////==///*//==@@@CCOLOLGLOLMOMOMTMTMT  (..(/./===@@@GCGLOLOOLTMOLLOGLGGCGG@GG@G@@GG@FF@F@FFG@GFGF@GGGGGGGGGGGGGOGOGGOGOGGGLGOGGCGOGOCGGGGCGGCGOCOOOOLOGLGOLGOLGLOOLOLOOOMOMOMTMOMTTMTMTMTMTTTSTSTTVSTTSTSVTSTSVTMLLOLLLLLMLLLLLLLLMLLLLLLCCCCCCC@C@CCLMMMMMSMMMMLMLLCL:C:@9:@99@88@8=8=8=88=8**********/*****(((((((**((((((*((((((**/*=8=@9CCCCLLSVUVUVUVUVXYXXXXXXXXVSL@@8/(((((((     ( (. .(.........../.........../.../..././././2//////.///////////////////////////./(./..(...(...(..(..//.//(=============@====/===@@CCOLOLOLOOOMTOTMTTSVT  ..(//===@@GCGCGCOLGLGLOGCGCGCG@@@F@G@F@F@FGCF@FF@FGFGFG@GGGGGGGGGGGGGGGGOGGCOGOCGGGGGCGGOGGOCGGCGGCGCOGOOLOOOGOLGOLOGLOOOLOOLOMOOMOMOTMTMTMTTMTOMTMTTMTTSTMTMTMTSTTMTMMTLLCCLCCLCLCLCCLCLCLLLCCCCCC@@@9@@9@@CLLMMMLLLLJLLC:C:C9C9@9898888=8888=8*8*****(*((***(*(.(((((((((*(**(((((((((((*(**8=8@9@CCCMMVUVUSVSVUUYXYXYXYXVUMLC=8/((       . ( ....................................../.../....//////////./././././././.(..(...(..(. (..(. (..(..////=///////==/=/=/*//==@@@COCGCGCGGGLOOMOTST .(./====@@@@@@@G@@@@G@@@F@F@F=F@F=@F@F@@GGF@F=F@FGFG@GFGGGGGG@GGGGGGGGOGOGCGGOGOGOGGCGGOGGGCGGGCGGCGOCOOOOOLOGOGOLOGLOLOOLOLOLOLOMOMTOTMTMOTMTMTTMTTSTMTMTMMTMMMTMTMMOMCCC@@C@@@@@@@@9@@@9@@9@=8=8=8=*/**8=8@9CC:C9@9@9@99=988=88*******(**(*(*(((((((%((((((((((((*/*=8=9@@LLMMMMMMMMMSTSSVSVMSMLLL@=8((      . . . . . . . . . .. ...... .........../.........(....(...(..( .(........( (..(..(//.*.///*////==/=/=/*//===@@CGCGCGGCGGGOOMTTS  .//===F@@@@F@@@F=F=@F@F=@=F=F=F=F@F@F@FG@GF@FFF@GF@GFGFGGGGGGGGGGGGCGGCGGGCGGCGCGCGOGCGOGGGCGGCGCOGCOGOLOOOLOOLGOLGOLOOLOLOOLOMOMOMTTMTMTTMTMOTMTTMTTTMTMTMMTMTMMTMMMMOLC@C@@@C@@@@@@9@@@@@9@=9=8==*8/8/*8=8@@:@9C@9@9@@989=888/8*/**(**((*(((((((((((((((**=8=@9@CMLLMLLLMMMMMMTMMTMMLLLL@@=*(       . .. . . . . .. .. . .. . . ... ......../.............(.......(..(. (..... (... (..(..(/..(.(./////==/=/===/(//==@@CGC@G@GGGCGGOOTS (.//==@@@GCGC@G@@G=F@@F@F@@@F@==F=F@F@F@FGCF@F@FF@GFGFGF@GGGG@GGGCGG@GGGGCGGGGGGGGGGGGGOGOGOGCGGGCGCOGOOOLOOOOLOOOOLGLOOLOLOLOLOMOOMTOTTMTMTMTTMOTMTTMTTMTMTOMTMTMMTMOMMLLC@@C@@@@@@@@8@@@9@@9==8=8=8/8/*/*8=9@@:@9@@9@99@9=99=88*8********(*((((((((((((((**((((/*/8=9@@@CLMMMMMMMTMTSSSSTSMSMMMLLC@=*(      . . . . . . . . . . . . . ... .... ....././...........(.../(...(...(.( (.....(. (...( ./(...(..*///===/=/==////===@C@G@GG@GGCGGLOOT  ..///=@GCGLOLOLOLOOCGCOGCGCGGCGCFCF@@FG@F@FGG@F@FGF@GFG@GGFGGGGGGGGGCGGCGOGGCGCGCGCGCGLGGCGGGGGGCGGCGOGLGLOOOOOOOLOOLOOLOLOOLOLOLOOMOOMTMOTTTMOTMTTMTMTTMTMTMTMTMTMTTMTSMTMTMLCCCCC@CCCCCCCLCCCCCCC@@@@@@@8@9=@CCLLLLLLLCCLCC:C:C9@9@989=88=88***8*******(*((*((((*(**((((((*/88=**(((((((.**==9@CCLLLLVSVUVSVUVXVXVXVXYXVXVSSMLC@8*(        ................................................../////.///././.../../../....(../(..( .(. ....../..(.//(...(/.///@@==/=====///==@@C@G@GGCGGGGGOMT ..///==@GCLOLOMOMOMOMOOLOOLOCGLOGCG@GG@GGCGF@GG@F@FFFFGFGFG@FGGGG@GGCGGG@GGCGGGCGGGGGGGGGCGGOGOGCGGCGGCOGOOOOOOOOOOLOOOLOOLOLOLOLOMOOMOMOTTMTOTSTTMTTTTSTTSVTTSTTTVSTSVSVSTUSSTMLLCCLCCLLCLLLCLCLCCCCCCC@@C@9@C:CLLMMLMLLLCJLLLL:LC:C:@9@9@988=88=88=*8**8/**/**************(**=888=8(((((((((((*/8=@CCLLLLLSVXVXVXYXXXXXXXYXXXYXXVUMMC@8/((( ((((        ... (.............../.../.../../............//.././//.////////////////.////////./././/..../...(...././...*//////./*///@@=====@===/=/=@GCGCGGGOGGGOOOOO  (././/==@GCOLOLOOLOMOOLOCOOCOCGCGG@@F@F@G@F@FGG@FF@GFFG@GFGFGFGGGGGGGCGGG@GGGCGG@GGCGCGCGCGGCGGOGCGGCOGGOGOGOOOOOOOOLOOOLOOOLOLOOOOLOOMOTMTOTMTTMTTMTMTMMTTMTSTMSTMTMMTTMTSMTSTMLCCC@CC@C@CCCCCCCCCC@@C9@9@9=9=@:CLCLC:LC:CCCJCC:C:@9@9@9888=88******8/*/**(*(*((****(**(*(*(.(**=88**(((((*/8@@CCCLLCMVUVUVUVUVYXYXXXYXYXVUVMLL@8*(.( ((((     . . ............................................../..////////.//.././../.../...(.....(....(....(../...(//.(..(..(.//=/=//==/==////=@@@@G@GCGCGCOOOO (..///==@@@G@CGCGCCGCGCG@@@F@@F@F=F@FF@GGF@FGG@FF@GFFGFG@GFGGGGG@GGGGCGFCGGGCG@G@GGCGGCGGGGCOGOGGOGGOCOCOGOOOOOOOOOOLOOOLOOLOOMOOMOTOMOTOMTMTTTTTTTMOTMMOTMTMTTMTMTMMMMMTLMOMLLCC@=@=9=@@9@=9@8@=8@8=8/8*/8*8=8@@9@9@9@89=9=88=88=88=8*8/***(((*((((((((((((((((((((*.((((.**=8@9@@9LMMMMMMMMSMSSVSVSSSTMMLC@8=(      . . . ... . . ..... .... ....................(....(.......(.. .(. (. ..(....(../..(..(..(..=///===/=/=*//===@@G@GGGOGOGOOO  .(..//===@@G@CGCGCGC@G@G@G@F@@F=F=F=F@FC@FG@GG@FFFGF@GFGFG@GGGGG@GGGGCF@G@GGG@GG@GCG@GGCGCGGGGOGOGCGOGOGOGOOOOOOOLOOOLOOOMOOLOOMOOMOOOMTOTTMTOTMTTMTMOTMTMTTMTMMTMOMMOMOMOMLLMLCC@@=@@==@8@==9=@=8=8==*8*/8=8@@9@9@@98@8=888=8888=88*=*8*/**(((((((((((((((((((.*=8=8@=9LLLMLLMLMMMTMSMSTMMMLLL@9=*(           . . . .. .. . . . . ... . .. .. ......../....../...(.....(.....(....( ..( .../ (../*..(..(..(.//*//==///=////===@CFCGCGGOOOOO (../////==@G@GCCGCGCGGCGCGC@F@F@@@F=F@F@GG@FFCGF@F@FGF@GFGFGFGGGGG@GGGG@F@GCGCFG@GCFCGCGGCGGCOGOGOGGCGOGOCOGOOOOOOOOLOOOMOOMOOMOOOMOOMOOOMTMTTMTTTTMTTMMOMTMTTSTMMTMOMLMOMMOMOLLLLC@@=@9=@==9==9=8==8=*=88*=8@9@@9@@9@8@889=888=888=888=***/*(/(((((((((((((((((((((((((((((.(*/8==9=@9LMMMMMMMSMSSSVSVSSSMLLC@8*((     ( . . . . ... . . . . . .. . . .. ....../...../..../../..../(........(........(.../..(/./.(...(. .(/..//====/=/=/*/===GCGCGOGOOOOO  ....///====@F@COLOOMOLOMOOLOOOOCGCGGG@G@FG@FG@F@FGGF@F@FGF@GFG@GFGGGGG@GGGCG@FGCGCFCG@GCGG@GCGCGGCOGCOGGCGGOGOGOGOOOLOMOOOLOOOOMOOMOTOMOOMOMOTOTMOTTMTTMTMOMOMTMMTMTTMMTMOMMMTMSMTMMMMLCCC@CC@CCCCC@C@@@@9@@@@9CCLLLLLCCCC:C@:@@9@@9@@9@@9@9@88=8*8/*8****8/****(****(*(*(***(*((((((***(( (((*/8=9@CCCCMSSVSVUVXVXVXXYXXYXVUMMLCC8=**( (( (.((((         .. ....... ....... .. ...............................//./////.//.////.//.//.....(...../.........///../*/..(..(..(.//(./====/=/=///===@G@GCOGOOOOO (.(.//=====F@@GCOLTTMTOTMTOMOTTOLOOGLGGGGCG@GGGCGFCG@F@FG=GFG@GFG@GGGCG@GGGG@@FCG@G@G@GG@GCGG@GGCGCOGOGCGGGOGGLGOGLOOOOOLOOMOOTOMOOOMOOMOTOTOMOTMTTMTTTSTTSTTMTMTSTSVSVTSTMMTMSTSVSVSTSTMLCLCCCCCCCCCCCC@C@:@CCLLLLMLLLMLLLCLC:CCC9C9C:@C:@C9@9@88=88/8/8=8*8=*=*=**/**/*******/****(*.***(((((((.(**=@9@CCLCSVUXXXYXXXX[X[X[YXXVUMMLLLC@8((.(.(((.(( ((.(((        ( . ( ...(.....................././/../.../././////././/././/////////////////=////////.///...///../././/./////////.///.*..///./==@=======//==@@G@OOOOOOMO  .././//===@F@@GLOMOOMOOMOOMOOOCOCGGCGCFG@F@GGG@F@GG=F@F@F@FGF@GFGG@GG@G@GG@GF@GGCG@G@GGCGGCG@GGCGGLGGGCGGCGOGOCOGOOOOOOMOOOOOMOTOMOMOTOTOMOOMOOTMOTMTTMTMTMOMOMMTTMTMTMMMOLOLMOMMTMTMMMLCCCC@CC@C@@@9@@9@@9@C:CLLLLLLLLCCC:@9@9@9@9@9@9@9@8@88=8*/****/**=******/****(**((*.(*(*.(((((((((((.**==9@C:CMSVUVXVXVXVXYXYXXVSMMMMLMLC8/( ((.(.((         ( ( . .. ... . .... ....................../.............//././///.////./././/./......././......(..//././//(..(..(..(/.(./====/=/=/////=@@@GLOMOTOO  (...////===F@FCGLGCOCGLGCOCO@G@G@G@F@F@F@F@GG@F@GF@F@F@FG@@GF@G@GGGG@G@GG@@F@GCG@FGCGG@GCGGCGCGCGOGOGCGGCGLGOGLGLOOOOOMOOOOOMOOTOOMOTOTOMOOMOMTTMOMTTMTMTTLLOLMMTMTMTMOMLCLCCLOLLLOLLLCC@@=@8@=8=8=8/8**=*=8@9@C9@:@@9@9=8=88/8*=*8/8*/8***/*((((((((((.(*(((((((((((((*/*8=8CLMMMMSMSSSVSVUVSMLLLLLLLC@8(           . .. . . ..... ........ . ................../............/...../........(//...//..(..(. (..//.../==/=//////.//@=FCOLTTMTO   . ( ..///=/===@@GCCGCGCCGCGCGCF@F@F@F@F@F@F@GG@F@FCF@F@F@F@FG@GFCGG@G@G@G@G@F@G@GG@G@GCG@GGCGGCGOCGCOCGGCGGCGOCOGOCOOLOOOMOMOOTOMOTOTOMTOOMOOTOMOTTMTMTMTMTMTLOLOMMMMMTMLOLCCCCCCLLLLLLLCC@@@===8=8=*=*/8**8=8@@9@C@:@@9=@88=8*8/*8**=***/**(((((((((((((((((((/*8=CLLMMMMMTMSMSSSSMLLCCLLLC9=*(           . . . . . . ... . . ... .... ... .. ......../...../../.../.../......../..../..(.././..///..(..(...(//...=/=/=/=////.//===@LOMTTTT  ...././====F@F@CGCGLCOCGCGLGCGG@G@G@F@F@F@FGG@F@FG=F@F@F@F@FG@FG@GGG@FG@G@GF@FCGC@FGCG@GC@GGCGGCOGCOGCGGCGLGGOCOOOLOOOOOOOOOMOMOTOMOTOTOTOMOOMOMTMOMTMTTMTTMOLLCOLMOMMTMMOLCCC@CCCCCGLCCCC@@@=9==8=*=*/*/*/*8=9@9@C@9@9@8=88/**8/*=**8/**/*((((((.*.((/(((((((((((**/8CLMMMMMMSSSVSVUVUSMCCCC:C@8/(            . . . .. .. . .. . . .. ..... ... ......./..../...../...../...././.../../......(//...///...(...(..//.../===/=/////./.=/=@GCOMTSV  ...////===@@GC@GCGLOLOMOMOTOOMTOOLOGOGCGGG@GFCGCGG=@@F@F@F@F@F@@GF@G@G@GCF@G@@G@FC@GG@@GG@GG@GCGGCGCGOCOGCGGCGOCOGOCOOCOLOOOMOOOMOTOTOTOMOTOTOMOMOTOTMTMOTMTMTMTMOCLGLMTTMTMMTMLLCCCCCLCLLLLCCCCC@@@@@@8@=@8=8=8=@9LCLLCCCCC@@9@9=8@8=9=88=8**/*((((((/***8/8*8=*******(*(((((*(*(*(((((((((((.**=9LMSUVUVUXVXX[[[[[XXSLCLCLCC8*( .(..( (((.( (             .  . . . ( . ............................2.../........././/.///./././///./././/.///././//../../././//.////.../.....///.//==/=/=///./..==/==GLOMTT   .(.////===@@GCGOLOLOLOTTMTTTTTMTOTTOOOLOOOOGGGGGGGLOF@FG@=F@=@F@F@FG@FG@GG@G@FCG@F@FG@GCF@G@G@GCGGCGGCOGCOGOCGLGGOCOLOLOOCOOOOOLOOOOOMTOTOTOTMTMOTOMTMOTMTTMTSTSTVTSOLOLOMSVSVTSTSOMLCOLCLLCLLLLLLCCCC@@C@@9@=@8=8=@9@CCLLCL:CCC@9@9@8@8=8=88*=**((((/*(*=8=88=888=8=8=*8/**/****/****(*(((((((((((((((/*=9CSSVUXXVXX[[[[[[[[[USLCCC:@@8* .(( ((((.((.(((.((           .  ( ( . ( . .... (... .../.......././/../......//1//2/2/////////////////////.//////////.////=//////////.//.//////=///.///////===//==@=====/////.=///@@OLOTS  (././===@@GCCGLOCOLOLTOMOMOMOOMTOMGOOCOOCGCGCG@GCGG@@@G=F=F@F=F@GFG@FGCG@@F@G@G@F@@G@G@FCG@G@GGCGCOGCGOCGOGOCGCGLGOLOOLOGLOLOOOMOOOOTMOTOTMOTMOMTOMOTMOTMTMTMTMTMTMOLCCLOMMMTMTMMOLCCCCCCCCCC@CCCC@@@9@@=8=8==8=8/88=8=9@@9@98=8*=*****.(*.(((.((.(((.***/**8/8*=*8*8/***/**((*(*(.*((((.(((((*=@LMSSVSVXY[[[[[[[[XXSL@9=9@8=(( . (.(((.((.(( (            (   . ... ............../...........././.1/1/....2././//////./././..//./././////./////././././//./////...//...//=///===@==/=//..../=.//=@OLTT  (....//==@FC@GCGCGCOCOCOLOCOOCGOOC@G@GCG@F@F@F@GCG@F@@F=F=F@F@F@F@G@FGCG@G@FG@G@F@G@GG@F@G@GGCGGCGCGGLGCOCOCOCOCOLOLOGLOOOLOOOOMOOMOOTOMTOTOMTOMTOMOMTMOTMTMTTMTMTMLGCCCGLOMMOMOLL@C@@@@=@@=@=9@==8=8=8=*/****(*.(*(*.***.*.(((((((((((*.*(*(.(((((((((((((8@CCLLMMSUXXXXXXXUSSLC@8*/8**(              . . . .. .1..... . ....1..1......1..../...1............../......//././//../......//.././/.../.(./.=/=./==F@===/=//..//////==@OLM      .(..(///==@@@@@CGCCGCOCGCGLGCGCGCGG@G@G@F@F@@F@FCG@F@FC==F=F@F=F@FG@FCFGG@F@G@@G@F@G@G@F@G@G@GGCGGCOCGCOCOGLGLGLGOLGOLOOOLOLOLOOOOOOMOTOTOMOTMOTMMTMOMOTMTMOMTMTTMTMMGCCCCCOLOMLOLLC@@@@=@=@=@===9==8=8/8*/*/*/(*.((((((((((((((((((((((((((((.((((((8@9CCLMSVXYXVUSSSMMLLC@8**/*((           .. . ... ... .. .. . .. ......1..../1..//../......./..../././..////.////././..././..////...///..///=//===@=/==/=/...///.//=@CGM       .(..//===@G@GCG@GCOCOLOLOCOGCGCOCGCFG@GG@@F@=F@FCGG@@F@F=@F@@F@F@FG@FCGCG@F@G@@@F@FCFG@@FG@GCGCGCGCGCGGLGLOGCGGLOLOLOOOLOOLOOOLOTOMOMOTMOTOMTMOTMOTMTMOMTMTOTMTMTMTMLOCCCC@CLOLMOLLCC@@@====8@==8===8=8=*/****.(*.((.((.((((((( ((((((*(*.((((((((((((((/*=9@CLSVXX[XXSMMMMMLML@@8=*/(((                   . . . . .... ... . .. ..1...1..../.1.//1/./2....../......././.././//./////../....///./////..//././//=///=F====2==//./.=/////=FCO       ..(./===@@GCOCOLOMOMOMOTMOTMTOMOOTOOLOOOLOG@GG@G@GCG@F@G@F=F@G=F@F@FG@G@G@@F@@FCG@@F@GG@F@GCGG@GGCGCGCGCGCOCOGCOCOGLOOLOOLOOOOOOOMOOOMOMOTTMOMOTMOTMTOMTOMTMTMOMTMTMTMMOCCCGCCLOMLMOMLCC@C@@C@@@@C@@@@@@@@8@==*8=**/***/**.*/*.*(.((((((((((((((((.(****/*8/8/8*8/8/8/********((((((((((((*8@@CMSXX[[[[XXVMSSSSSSSLL@9==*/*( .( ((.(.(( (( (.           (   . ..  .. ............1..1...1.....1...2./.2.2/.//2//2/2///////.///././//.//.//////=//////././////./////.//.././=////===F=/==/=///.=////=/=@G      . (..//==@@GCOLOMOMOTTTTSTTTTTTTTTMTTOOMOOOLOGCGCGCFOCG@F@G=F=F@@F=@F@@F@GG@G@F@@G@F@G=G@GCF@G@GCGCG@GCGCGCOCGLOCOCGLGLOLOOOLOOOLOOOMOMOOOMOTOMOMTOTMTMTMTMTMTTMTSTTTSTSTSMOLLLGLLOMTMMTLMCLCCCC@CCC@CCCC@@@@9=8==8=*=*/***/*****.**(*.(((((((((((((*.**.*.***=*=888=88=88=8=8=*=*8*.*((((((*.((/*@9CMUXX[[[[[XSSMSVSVUVSMCC@@@8=8.  (.(.((.(((.((.((.(((.(((.           . ( ... (. .( .. .. .. .........../1.//2//2/./1/1/.//2//2////2/2//2//2=2=2////2//////////////=/=/=====//=/////=///=/=///.=.////===/==2=@F=F==F==//==////=/=@   (. (  ..///==@CCGLOLOMMOMTOTMTMTOTMOTOTMOOLOOCOCG@G@@G@GC@@F@@==@FC@F=@F@F@@G@G@@F@@G@@F@@G@G@FCGCG@GCGCGCCCGCOCGLOCOCOCOLOLOOOLOOOLOLOOOMOMOMTOTMOMOTOMTOMOMOTMOMTMMOMMTMMTMOLCCCCCCCCOLLOLLCCC@@@@@@@@@9@=9==8=8*=*/**/**/**(/(/(((.(((((.(((((((.((((((((.((***=**=*8*=***/***/*(((((((**(((*8CLMSVXXXXUVSMMMMSSVSSML@C=@9==*( ((.((.(((.(( ( ( ((        (  . . ( ..  . . ............./../.2/../.2../.1./.2./2./2/2///2///2//////././////.///////==//////././/////////.//.../.=/=//=/==2===F====/==////2/==   (..( .  . (.//==@@@G@CGLOLOLOLOOOLOOLOLGOCG@@@G@F@==F@=FCGG@F@G=F=F@G=F=F@@F@FC@G@F@F@@F@F@@GGC@G@GCG@GCG@GCGCCGLGLGLGCOCOLOOMOMOOMOOLOLOMOOOMOMTOTMOTMTOMTOMTOMOTMTMOMTMOMMOMMOLG@@@@@@@CCCCCC@@@@=8=8==8=/8/8/**/*(/*(.((((((((((((((((.*((*((((((*8@9CLLMMMLLLLCLLLMMMLL@@=8=8=*/               . . ...1..1....1 ..1 ............/...1/.1./..../......../.././///2/=//////././//.=////..//.././=///=2/=/=F===F=F=F=//////// ..(..( ..  ..(.//===@@@G@GCOCOLOLOLOCGCOGCOC@F@F@@@F@=F=F@FCG@@@FC==F@@G==@F=@F@G@G@@F@F@@G@@FCGCG@@G@GCG@CG@GCGCCGLGLGLGLGLOLOLOOMOOOLOLOLOLOMOOMOMOTMOMOTMOTMMOMMOMOMTMOMMOMMOMMOLL@C@@@@@@@@C@CC@@@===8==*=8/=*/**/*(*.((.((.((((((.(((((.(((*=89@98@9C9CC:CCLMMMLCC@@9==8=*(               . . . .. ....1...... ...1. 1...1/.2.././1/.1/.2../.././..././///.//=///////././/////////.//../.=///2===//==F@F@F==F=/////=./ ( (..(.....  (...//===@@G@GCOLOLOLOOMOOOLOLGLGGC@@F@G@F==F=F@GCG@F@F@==F@G@=F=F@@F@@@G@@F@F@@F@@@G@G@G@GCG@GC@GCCCGCGCOCOCOCLOCOLOLOOMOLOLOOLOLOOMOOMOMTOMOMOTMTOTMOTMOMTMOMOMMOMOMOMLOL@@@@@@=@@=@@@@@@@===8/8/=*//*/***/(*(.((((((((.(((((.((((.(((**=888/88=9C@CCLLMMLLLC@@@@===*/(                 . . . ..1.1..1...1.. .. ........../1.2././.../././././././././////2=//////.///////=/=//.///..///=//=2==2/=F@F@@F@@F//////// . (...(. (. .(..////==@FCGLOMOMOTMTTTTTTTTTMOTOTMGOCOCCGCG@@G@@@GCG@F@G=F=F@G==F=F=@F@@G@F@@F@@@G@F@GCG@F@C@G@GC@GCGCGCGCOCOCOCOLOLOOLOLOMOLOLOLOMOOMOMOMOMOMOTMOMTMOTMOMMOMTMMOTMMOMMMTMMOCCC@@C@@@@CCCC@CC@@@@=@==9==8==*=*/8*/*/(*.*(.((((((.((.(((((((((/*8*8/*=888/****.*((((((((((((/89@9=8*8@9LCLLMMSMMMMLMLLCCC@@=8.(  ( ((..( ( (..((((.(( (           ( .. . . . . .... .....1.2.2.2./2././1.2....1/2.2//2/////2//2/2/2/2///2////.///=2//====///=/////=////=///.//..../=2=/==F=2//=F=@F@F@@F//./=./  (..(.......(...////====@GCCOMOMTTTTTSVTVTSTTTTSTTTOLOLOLOLGCGCGCG@OCG@=F@===FC@F==F=F@F@@F@F@@F@F@@G@@G@@@@G@C@G@GCGCGCCCGCOCOLGCOLGLOLOOMOLOLOLOLOMOLMOMOMOTMTMOTMOTSTMTTMTMTTTMTSTSTTMTTSTMLLCCCCCCC@CCCCCCCC@@@@@@@9=@===8=8==*=*/**/(((.(.(.(((.((.(((((((((((((((/8=8=8=88=8/8=*/***/**.*(/((((((*=8=98=*8@CCLMSMSMMMMLMLMLLCC@@==*( .(.(.(.(.(.(((((.(..(.(.(.(           (. ( . (. .. .( ... ... (... ............//1///2/2/2///.//2.//////2//2/2/2/2//2/2=2/=2=/=//=/2=/F==2=F=F====////=========//=//////==F/F=F=@=2=@F@@F@G@=/////2/.(...( ..(...(////===@@GLOLOLMTMTTTMTTTTMTTOMMOMOLGLOLGLG@@G@@FCGC@F@@F===G@F===F=F@F@C@@F@F@@F@@F@@G@G=@G@G@C@GC@CGCGLCGLGLOLGLOLOOLOLOMOMOLOLOLOLOMOOLMOMOTMOTMTMOMMOMMOMLMOMMMOMMMMMTLMMOLC@C@@@@@@@=@@=@@=8=====8=8=8/8/******/*((.((.((((.(((.(.((((((**=*8/8*=**/****.((((((((((((8*=*8/88=:LMLMLLLCLLLLCCCC@==8=/(  ( (.((.((..( (.(.(..          . . ( .. ( ( ...........1.2.1/1/1/2.2.2/1/..1.1/1/.2//1////2/2/////2//=2////////=//=====//2==/////2//2=///////..//2=2===F=F/=2=/F@F@F@F////=//  . . ( .. .(..(//////===@@CGCGLOLOLOOMOLOOLOOGLGCG@@G@CF@@==F@@=CGC@F@@=F==GC====@=F@F@G@F@@F@F@F@@FC@@F@@@G@GC@GCGCGCGLGCOCOLGCOLOLOLOLOMOLOLOLOMOMOMOLOMOMOMOMOMTMOTMOMMOMOMOMOMOMOMOLMOLLLCC@@@=@====8/=8/8=*=*=*//*/**/(*.(.(((.(( (.(*(/*.*(*.(((((((((((*(((*=9C@@9@@@9@@@@=8==8/*/*(                   .. ...........1..................1/1//..2.2//.2///.///////2=//2=/2=/=//.//=/=/=//=///=././/===2=F===2/==2=2=F=F=/////=/  .. (. ....*////=/==@F@@GCGCGLOLOOLOLGCLCOCCG@G@@FC@F=@===F=@G@G=@F@====G@=F=F=@F@F@@@F@F@@F@@F@F@G@@F@@C@GC@GCGLGCOCOCOCOLOLGLOOLOLOLOLOLOLOLOMOMOMOMOMOMOMTOMOTMMTOMMOMOMOMOMMOMLOMLMOLLLC@@@=@====*/*/*=/*=*/*/*/*/***(/((.((.( ( (((((((((((((((((((*=8@9@@9@@@8@===8===*=*/((                 . . . . 1. 1. 1.1......1......1/..1/1..2./1/./1//2./////.//////=///==/=////////=/2=///=//=/////2/F==2=F=F/=2==/=//===///2=// ( ( . (..../////====@@@GCCCOLOLOLOLOLOOLOCOCOCGC@G@G@@F===@==GC@G==@====@G@===@F@@@F@G@F@F@@F@=@@@F@@@@@G@CG@CGCGLGCOCOCOCOLOCOLLOLOLOLOMOLOMOMOMOMOMOLOMOMOMOTMOMOTMOMOMLMOMLOMMOMOLMOLLLOLC@@@=====8=/8/*/*/*/*/*/**/*/(*(/((.((.(( ((((.*/*/*/(/(((((((((((/8=8=9@@@9@@=8==8====8/*/.(    (               . . . 1.. 1.. 1.1.1....1......1../.1.2...2./2//.2///////////=/2/=/=///=//////=//=2=/=/2=//.//=2==F===F/=2=F/2/2/=2///2==. ( .. .(././/====@@GCGLLOOMOMTMTTTTTTMTTMOTTMOMOOCOLOCCG@@@F@=G@CF=F@====G@@=F==@F@F@@F@@=F=@F@F=@=@@@F@@GC@GC@GCGLGLGLOLGLGLOCOLGLOLOLOLMOLOLOMOMOMOLMOMOMOMOMOTMOMTMOMMOMLMOMMOMMMOMMOLMLLLLCCC@@@@===8==8=/*=*=*=/*8/8/*=*/***/**/(.(.(((.(((.((((*/*/8/8=*8=8*8/*/*(/(*/(*/*(/((((((*=88@8@@@:CCCCC===@@C@CC@@====/(  (..(.(..*.(.(.((..(.( (         . . . .. . . . ..............1....1..1.2./.2../2/2.//2/2//2//2/./2/2/2/=2///=/2=/==F/==F==2===//2/==/==/=/=/=/=2//2=F=2=F=F==2=F=/////2=////2=.  . .(...///===@@@@GCLOLOMOTMTTTSTVTSTTTSTTTTTMMOLOMOLOCG@G@@@@GC@F@=F=F==GCF=@=F@@@F@@F@=@===@=F@F@@@@=@@CG@GCCGCGLGLGLGLOCOLOCOLLOLOLOLOOMOLOLOMOMOMOLOMMOMTMTMTMTMTTTTMTMTTMTTMTTMTMMTMTMTMMLLCCC@C@@@@===8===*=8==8=8=8/8*=//*/*=*/**/((*.((((.((.((((((((.*/*=8=8/=8=8=8=8*8*/***/**(*/***/((((*8=9@@9@CCCCLCC@==8=CCCCCC@@@@==(   (. .(...*/(..(.(.(.(.(.(.((.(.(         . (.  ... ( .....( .. ..... ...............1././1.1/.2./1//1///2////2/2/2/2//2//2/2/==2=2==F=2===/F===F===F===F=====F===F==F==F=F//2=F=F@=F@F=F====2///2=/2//2/=/  . (..././/===@F@GCGLOLMOMOMTTMTTTMTMOTMMTMOMOCOLOLLG@@@=@==@G@@==@@===FCC=F==@F@@F@@F=F=@=F=====@@F@@F@CGCG@CGLGLGLGLOCOCOLOCOLCOLOLOLOLOMOMOLMOMOMOMOMOMOMOMOTOMOMMMOMOMOMLMOLMMOLLLOLLOLLOLCC@@@@==8==8=*/*/**/*/*/*/**/**/*/*.*.*.(/(((.(.(( ((.((/(*/*=*=8/*8/**/*/**/(*(/*.*((.(((**=888=8=9@@C@@9=/8==9@C@C@@@C@=/    ...(..(.(..(.*.(.(.(..(.(.              (. . . .. . .. ..... .......1..1..1..1.../.2.//1//1//2//2/2/2//2//2////2=/2=/=2=/==F/=2==F/==F/2//=2==/=2==/=2=//=/=F==F=F===2/F/2//2//=////=2/  . ..(/.///==/===@@@CGCGLOCLOLOLOLOLLOOLOCOCGC@@CF@@========@C@@==@=/==@G@==F=@=F=@F@===F===@=@=F@@@@@@@GC@GCCGLGCOCOLOCOLOLLCOLLOLOLOLOLOLOLOLMOMLMOLMOMLOTMTLTOMMOMMOMLMOMOMOLOMOCLC@CC@CCCCC@@==8=/8/*/*/*(/(*((.(*((.(.((((.(( ( ( ((*.(((*.*(.(*(((((((((((((((*.(**/**=*=/8/((.*=8===@=8=/(  .( .( (...                . . . . .. ... ..............1/.2./../.../2/1//2/////////=/=/=/=/=/==////==/=2==/=2==2/2/2==F==F=F=F/2==/2//2=2=2//==2    ....////=======@F@@GCGCOCOCLOLGLGLCOCOCCG@@@F@C@=@=====@=@F@@F==@====@G====F=@==@@F====@====@=@=@@F@@@CGCG@CGCLCOCOLOCLLOOLGLOCLLGLOLOLMLMOLOMOLOMOLMOMTLOMTOMOMOMOMOMOMOMOMOLLLLLCC@C@@@C@CC@@@=8=*//*/*.*(/(.*((.(((((.( (((.((. ((.(((.(((.(((.(.(((((((((((.(/*/8/*/*.(/*/=@@@@==/(     ..(                  . . . . 1 . . . ..1 .1...1../1./1/2.1/1/.2/..///2///////=/2/=/=2=/=2=//2==2==/=2==2==//2=2==F==F=2=2/F=2/2//=2=//2=2=   (.././//=/====F@@CGCCCOLGLOLOLOLOLOLOLGCCGC@@@@G@@========@G@@===@/==FC@F=====F=F=@@======@===@F@@=@@@GC@CG@CGLGLGLGLOLOLOLLGLOLGLLLOLOLOLOLLOMOMLMOMOMOMMOMMOMMOMMOMOMOLLMOMOLOLLLC@@@@@@@@@C@@@==8/*/*/*(*(/((.((.(.((.((.(.(( (  (.((.((.(.*(*.*(((.((.((((((((((.(((/*===*.((//8=@@@@=/(     ( .(... (( .(              . . . . . . . . .... ....1..2.2.2.2.2.2.=1/./2////////2=/=/=2==//F=/2/=/==/==2====2=2=/2=F==F==F==/2==2/=2/2==2./===  .(.///==F=F@FCCGLLOOLMOSTTTTTMTMTMMOMMOMOLOCOCOCG@@@F@=F==@@G=F=@=====G@===F=====@=========@==@=@@@=@@GCGCGCGCCOLCLOCOLOLOLLGLOCOLGLLOLOLLOLLOLOMOMOMOMOMOLMOMOMOMOMLMLMOLMOMOMOLMOLLC@@C@@C@C@C@@@@==8/8/8/*=*8/**/*/*(*/*(/*(/(/(.*(.((.(.(.(.((((/*(/*=*=*/8/8/8=*=***/*(.((((((/((/*(((.(/=9@@==//8=@CCCLC@=/(  .. (...(../(..(.(.(.(.(.(..         .   .  .  . . . . . ......... .......1...1..1..1...1./1/.2/2/2//2/2/2///2=///2=//2=/=======2===F===F==/2=F==2==2=2=F==2=/=2=F=F=2=F/=F==2/2/=2=//2=2=     .(///===@@G@GCOCOLMTOSTVTSVTSTVTTTTMTMOMOLOCOLOLGCC@@@@@@@GCC=@=@====@@F========F@=@===@===@=@=@=@@=@@CCCG@CGCCOCOCLLOLOLOLLGLLGLLOLLOLOLOLOLLOMLOMLMOMMOMOMTTMMTMTMOTMTMTMMMMMTMLMMLLLCCCCCCCCCCC@@@@=8=8=8==8/8/**/*/**/*/*//**/*/(/(.((((.((.((.*.(*/*/*8=8=8=8=8==8==*/*/**(.(((((((/(*(/(*/((.((/*=@@@@===@@CLLOLC@/.  .....(..//(/./.(..*..(.(..(.(.((           ... ( .. .. . (... ......... ............. 1..1............././/./1/.//2/2/===2=2/2=2/2=/F===F=2===F=F==F=@F=F@F=F===F==F=F=F@F=F=2=F@FFF=FF=FF=FF=2//2==2///=2=    ..///===F@@@GCGCOLOMTTMTTTMTMTMTMOMOOMOCOCGCCLGCC@@@@@@==@@G@===@==/=C@@=========@======@====@=@@@==@@GCCGC@GCOCLOCOCLOLLOLLGLCOLCOLLOLOLOLOLLOMLOMOLOMOMOLLOMOMOLOMOLMOLMOMOLOLOLOLLLCC@@@@@@@@8@==8==8=*=*/*8/**/***.*(.*.*(/(.*.((.((.(((.((((.((((.*(/*/*/8/8/8/*8/***((.((((((((((/(..(/*=@@@==@CCCLCC@=/(   ...(..(..*./.(/(.(.(..((.((              . . ( ( . . . . . ...... . ... .... .. .1..............2.///2/2/2=/2///F///2=2/2/=//2==2=====F=/=F===2===F==2=====F/2=2=2==F=2=F=2=F==2=2/=2=2/2==2    . .././/=/=====@@CGCGCOLOLOLOLOOLOCOCGCG@C@@@@@@@@======@==@@@@===@/===@G==/=======@======@==@=@=@@=@@@@CGCCG@CCOCOCLOLOLOLOLCGCOLOCOLLOLLLOLOLOLMOLMOMOMOLOLOLMOMOMLOLOMOLOLLOLLLLCCCCCCC@@=8==8=*=/8/*/*/***.*(.(((.((.(((.(. ( (.(*((*.*(*((.((..(.*/=*===@@@=@=/.  ......(...(.(               . .. ...0...1/2/1//2/.2/2../=///2/////=//2=2==/==F//=/=2=/F=2==2==F/2/2=F2=F==2=F==F=2//2=F//2/=2=   ( .././//=2=====@@@GCCGLLOLOLOLLGCO@CC@C@@@@@=@@@=@=====@==@@G@======/=F@@===/==========@===@===@@=@@@=@C@CGC@GCGLCOCLOLOLOLOLLCCOLLLGLLOLOLLOLLOLOMOLOMLLMOLLGLLMLOLLOLLOMLOLLOLOCLCCCCCCC@@===8=*=/**/8**/***.*((.((.((.( ((.(  .(((.(.(((.(.((((( /*/===@@=@@@=/(     . ( .( ( (                   . . . . ......1///1//1//2//.2//2///////=2===/==2==2=2/2===F===2=F=2=//2=F==F=2F=F=2F=F=2=2==2=/2===    ...././///====F@@FC@GCLOLOLOLOLOLLLGCGCCG@@@@@@@@@@@=====@===@@@===@/===@@@=/==/======@====@===@=@@@=@@=@GCCCG@@CGCOCOLLLOLLOLOCCCLGLLOCOLLOLLOLOLLOLMLOMOLLOLOCOCOLOLLOLLOLLOLLOLLCLCCCCCCCC@@==8/=*=**/***.***.(((.((.((.(.( ( (.(*.*(/*(/(*.((.( .*===@@@@=@=/.    ( .( .(..( (. (                       . . . . .1 .2.2.2/1///2=.2//2////2/////=/=/=2===2=/=/===F==F=F====2/2=/F=2=F==2F=F=F=/=2/F/F//2=2=   ( ..././//=F@F@GCLOLOLOMTMTTTMTMTMTOMLOLLOLOCGCGLGLC@@@@@=@==@@@@===@=/==@@@=/=/==/======@====@==@@@@=@@=@CGCCGC@@GCLCOLOLOLLOLOCCCLOCOLCOLLOLOLLOLLOLMOLOMOMOLOCCCCOLOLOLLOMLOLLLOLOLLLLLLLLCCC@@==8==8/=8==*=*=8/**/**/*/(/*(/(/(.(((.((.( (.(.(.(/*=*=8*==8=8=8/8*/((((((((((.((((.//=@@CCCC@@@@=/.(.   (...(..(../(/(./(..((..(         .      ( .  . . ...... . . .. .. . . .. .............../.2//2//2/2/2==2//F=/2=/=/=2/==F==F==F==F=2==F==F=F==F=2=F//2/F=F=2F=F==F==F/2=/F=2=2=2==     .....////====@@G@GLOLMTMTTTSTVTTTTTTSTMOMMOMLOCGLOLOLO@@@@@@@=@@@@@===@====F@===/=/====@====@==@=@=@@@@@@@@@CCGCC@@CCGLOLLOCOLLOLLGCCCOLOCOLOLOLOLOLOLMOLOMOMMMOMOLGLCOMMOMMTLMMMOMLOLMOMTLMOMLLLLC@@@=8=8=8=8==8=8==*8/*/**/*/*/*(/*.*.(.((((.(*(*8/8=8=8==8=8=8==*/**( ((((*(((((/(.(  (.*==C@CCC@@=@@=/..(      .(././//.*/.//*.*.(.(.(.(.(         (...(. . ( . ( .. .( . (.. .. ( .... .......... .... .... ......../../././2.///2/2=/=2=/F==2==F==2=F====F==F=F@F=F@=F=F=F@F@F@F=F=F=F=F/F=FF@F=F=FF=F=F/=2=2=F//==2=     ......//////=F=@GCGCOLOMOMTMTMTTMTMMOTMOMOMOLCCCCCGLCCC@@@==@===@@@===@==/==@@==/=//=====@====@=@=@=@@@@@@@=@GCCGC@@GCCLOLLGLOLLOLLCGCCCOLLOLOLLOLLOLOLOLLOLOOLLOLOLG@CCGLOLOLOLOLOLCLGLLLCOLCLLCCCC@@=8=8/8=8*=8/8*=**/*/*/*.(.(/(((.((((.(.(((//*/=*=*=8=8=8==*8*(( (((((. .*/=@@@@=/=/===/..(   ...(.(/..*./(.(..(.(.( (          .       .   . ...... . . . . . . . .. . ........./.../1/.//2/2//2/=F///F/F/==F/=2/=F========F==/=2=F=F==F===F==2/=2=F=F=F=2==F=F=2=2==F2=2=2==     ...././///////=/==@@@GCGCGLOLOLOLOLOLOLOCGCC@G@@@@@@@@=====@=====@@@@==@=====@@==//=/=/========@=@@==@@@@@@@@@CGCCGC@CGCOCOLCGLOLLOLCCGCCOLLOLOMLOLLOLOLOLLOLOLOLLLOLCG@@CCGLCLOLLCLCCC@@@CC@CC@C@@@@@8=***/*(/**.*(.*(.*(.(((( ( ( (.((.(((/*.**/(*.**.*(. .*//=/./(.(/=/..    (. (..( .. (                  .. ..... ...1.././1/.2/2/2/////2/=2///=/=/2=/F/==/2=2=====2==2=F/F=/2=2F=FF=F==2F=2=F/2=2==F=2==F=      ..././/////=//=/=/==F@@@CGCGCOLGLOLGLCOCCCC@C@@@@====@=@==========@@@@@=@@==/==@@==//=/====@==@==@=@@=@=@@@@@@@@CCOCCG@@CGLCOLCGLLLOLOCCCCGLOLLLOLMOLOLOLOLOLOLOLOLOLOLCC@@@@CGLCLGLGCCCC@@@@@@@@@@@@@@=@=8/**/(**(/**.(((.((..(( ( ( (( (((.(((.((*.*((.( (.////(...(./=/.    .( .(.                 . ...... .....1..../.2//./2=2//2=/=//=2===/==2===////F=2==F/F/=F=F/=2=F=F=F=2F==F=F=2=/2=2===2=2=     .././/////2=//=/=F==@G@GCCCOCOLOLLLOLLOCGLGCC@@@@@@@@===@======@==@@@@@=@@===/=@===//=/=========@=@@@=@@F@@@@@@@GCLGLC@CCGLCGLLCOLLLOLGCCCGLOLOLOLOMOLOLOLOLOLLOLOLLLOLGCG@@@C@CCLGLLGCCC@=======@8@=@=8==8/***.*(*.*(*.(((.(((.(   (.((.(((.(((.( (.*/..(./(/..//=.    . (....(..(                       .   . ...........1../..1././.2.=/////=2//2==/=2==2==/=2=2/=F=F/=F=2==F=2==2@FF=F===2F/F==2=2=2==2=F/=F     . .../////====F=F@@@G@GCOLOLOMMTMTMTMMTMTTMOMOLOLGCCGCGCC@@@===@==@=@@@@@@=@@=/===@===/=/=/====@===@=@@@=@@@@@@@@@CCGLGCG@@CGCOCOCCCOLLOLO@CCCOLLOLMOMOMOMOLOLOLOLLCOLOLOCGC@C@@@@CCLCOLOLLCCC@@=@=@==8@@=@@8=8=/8=*=8/8/8//*/*/*/(.(/((/(((.(((.((.(.((.(((.(( (.(.(((((((( (    (///////////=//==/..      ( ....(././(..(.(.(.( (                   .  . (..... . . . .. . . .. . .....././//1//1///2/2/////=2//=F=2=2==F====F==F====F==2==F=F=F=F=F=F=F=2=FF=F=F=F2==F=2F=2=2/=2==2===    .././===2=F@@@@G@GCGCOLOLOMOTTTTTSTTTTSTTSMOMOLLOLCCCOLGCC@@@@@@@@@@GC@@@@@@=/=======//=/=======@==@@@@=@@@G@@G@@GCCOCLG@@CCCOCLCCCOLLOLOCG@COLOLOOLOMOMOMOMOLOMOLOLLOLMLOLGCGCCCGCLLLLOMOLLCCC@@@@@@@@8==@===8===8=8=*=*=/*/*/***/*.**.(/(.((.(.(((.*(.(*(.((.((.(((((.((((((((.(*.((((((((((.   ( (   (.///=/////=/==/=@=/...    .......(.../.*///*./*.(.((.( ((          ... ( ( ( (.  .     ( ...... . ........... .. .. ... .............////////2//2//2/2/2/2==/2=F==F=F==F=F@@F@=F=F==F==F==F@F@F@F@F@F@F=F=F@FF@F=F=F=F==2=//2==2==F=2        . ...///2====F@F@F@@GCG@GCOLOMMOMTMOTMTMTMTMOLOLOLCGCGCCGC@@@@==@@@=@@@@@@@@=@===/==@===//=/=======@=@=@@@@@@@@@@C@@CGLGCLG@@GCCCOCCGCOLLOLOCGC@OLOLOMOMOMOMOLOLOLLOCOCLGLGCOCC@@@@@@@@CCCOCOCLCC@@====8==8=8/8=*=8/8/=*/*=*/*/***/*.**.(.((((.((.((.((.((.(((.((.(.( (((((.((((((((( ( ( (   (.(.////.////////==/. ..    ( ( .. (....*...*.(..(..(.                          . . . ...... . . . . . . . . . ...././//2/////2////2///=2//==2=/==F=2==F==F==F=====2=2@=F=F=F@F=F=FF=2=FF@F=F=F=F=F=F/2=2/F/F=2===      .( .///=/=2======F==@=@@@FCGCGLGLGLLOLOLOLOCCCC@C@@@@=@=@=@@====@@=@@@@@@=@@@@@=========///8========@@@@@@=@@C@C@C@C@LCLGLC@@CCCCLCCCCGLMOLLGCC@GLOLOLOLOLOLMOLOLOLLGCCGCCLCOCGC@@@@@@@@@@C@CC@@@@@===*=*/*/*.*.*.*.*.(((.((.(( (((.(.  (    (   .....(../././//=...     (  . (..( (.(                   . ............1/././.2=./2/2/2/2=//2==2==/=/=/2=//=/F===F=F=F=F=F=F/F=F=F=F=F=F=F=2=/2=2===2=F=F       . ....///=/==F===F===F==F=@F@G@GCOCGLGLCOCCOCG@@@@@@@====@=@=@@==@@=@@@@@===@@@@@=========//=/======@=@=@@@@@@@@C@C@C@CCOCLGCC@@GCCGLGCCGLLOLOCGC@CGLOLOLOLOLOOLOLLOLLGCC@GCCCGLCCC@@@@@@@@@@@@C@@@@@@==8//*/**/(/(.*((.*((.((.(.((.(.       .....(./.././/=//...       ( ..                       . ...../.../...1/1///=..=//2//=2/=/2===2==/2==/=2//=F=F==F=F==FF=F/2@F=F=F=F=F=F=F=2//=2=F==2==        . ...././/2==2==F===F==@F=@@@G@CGLOLLOLOLOLOCOCCC@@@@@C@@=@@@@=@@=@@=@=@@@====@@@@@=========//*===8====@@@@@@@=@@@C@CC@CCCLGLOCC@@CCLGCCCCGLOLMOCGCCGCOLOLOLOLLOLLOLCOLCGCC@@G@CCGCCCC@@@@@=@=@@=@@@@@@@@==8/*/*/**/(.*(.(.(((.(((..((.(. ( (          .........././/=@/...      . ( .. .(..(.( (                .         . .../..../1/././/./2=/1/2=/2///2//=F/==2===/==/=/2==F==F=F=F=F=F=2=F=FFF=F=F=F=F=2=2/2===2==F=        . .....././=/==F=@F@@@G@G@GCGCOLOMOMTMTMTMTMMOMMOLOLOLLLCCCGCCG@@@@@@@@@=@@@====@@C@@=======/=//*=/==@==@=@@@@@@@@@C@CCC@C@CLOCOCC@GCCCGCGC@COLOMOLGC@CGCOLOLLOLCOLOLGLGLCOCG@@C@C@GLGLGCC@@@@@@@@@@@CCCCCCCC@@====8/8//*/8/*//*/*****/(/*.*.*.(((.((((.*(.(((.((.*(.((((.(.(((((((((.(((.(((.( ( (.(.(.(   ...//...//////=FCG=/..   ..........(..(./.(..(..(.(..                    ( . . ( . ( . ........  . . ( . . ....././///2///=//2/2=/F=/===F=/2=F/==F=F==F==F===F/=2=F=F@F=F=F@F@F/=2@FF@F=F=F==F=F/=2=/F=F=F==F      . ....././/2=2=F=F@G@G@GCCGCOCOMOTTTMTTTTTTMTMTMTMOMLOMOLOLCGCLCGCC@@@@@@@C@@@==@@@@@@@========*/=/8==@=@=@@=@@@@@@@@CCCCG@CCLOCOLC@@GCCLCCG@CCOLOMOCG@@CCOLOLOLOLGLOCOLOLLOLLCGC@GCCLGLLLCC@C@@C@@@C@CCCCLCLCLCC@@===8==8/=8/8/*/*/**/*/**/*/**/*/(/*.*.(((.(/(/*.**/(/(((.((((((((((/((((/(*(/(((.((..(.(( ((( ((*.(.(.(.   ( .././/.././//==@GCC==/..  (. ...(....(.././.*./(/(.(..((.(..                  ( . .. .   ...  ..(............./.....( .. .... .. .. .......././////=2=2=2==/=2=F@=2@F=F==F==F==F@F@@F@=F=F====F@@F@F@F@F@F@F=F=FF@FF@FF=FF=F==2=2==F===F==      . . ..././/2//=====F=@@F@@G@GCGCOLOMOTMTMMTMOMOMOMOLOLOLLGLCCC@GC@@@@@@@@===@@====@@C@@@@==/8====*/8===8@=@=@@@@@@@@@@@C@CCCC@CLOLOLG@@CGCGCC@CGCGMOLOLG@G@COLOCOLOCCCCLGCOCLGCCC@@@@=@CCGCCC@@@@@@=@@@=@@@@C@CCC@C@@@==8=/8/*/***/**.*/*(/*(*.*(.*(.(((.*(.((.((/(/((.*((.(((((((((((.((.((.(.((. (.( ( (.(.(.((.   ( .......///==F@GCF=//.  .. ......(..(..(..(.(..(.(.((                                   . ..  ( ....... . ( . (  ( ( . .. ...////////=/=/2/==2=F/=F===2/=F//2====F==F======2==F==F@FF@F=F=F=2=F=F@FF=FF==F==2=/2/F=2=F==F     . ......//.////2====F========@@@G@GCOLGLOCOLCOCGLCGCCCCC@C@@@===@@@@@@=@=@===@@=====@C@@@@@==/8==8=/*===9@@=@@@@@@@@@@@@CCC@GCCCLOLOLCC@@CCGLG@@CCGLOLOLOC@GCCCOLLCOCGCCCCCOCOCGCG@@=@===@@@@C@@@=@=======8====8======8/*/*/*/(.(((.(.((.(( ((.. ( ((. (          ...=/==@F@==...      .(.(. (.( (                        . .....././../././/==1/=2=2////2//2=2=/==/=/=2=//2==F==F=F@=F=F=2=2=FF@F@FF=F==F==2=/2==F=F=2=     . ......//.2//2/=/=2=====F====F=F=@@GCGCCGCGCGCCCCCGCCG@@@@@@=@====@@@@@@=@=@==@@@====@@C@C@@===8/8==8==8=@=@@@=@@@C@@@@@@@@CCCCCGCLOLOLGC@GCCGLC@@@CGCOMOLOCC@GCCOLOCCCGCGCCCCCOCCCC@@@==@=@=@@@@@@===========*==/8/=*=/8/=*/*/**.(((.((( ((.((.((.((.((.(.(   .(    . .///==F@@==///.       ..  (                   . ......./../.2/.2=//2=2=//2=//2//=//2==/===//2/=2=F==F=F=F=F==2=F=F@FF@F=F==F==2/=2=F===F==    .  . . . ....././/.//2/=2=F=F====F===@=@FC@GLGLCOCOCOCOCCCCGCCCCC@@@@=@==@=@@@@=@=====@@@====@@C@@CC@@=*==@@8===8@@=@@@@@@@@@@@@@@@CCGCCCCLOLOLCGC@CCCGCCG@@CGLOMOLGCC@@GCLGLCCCC@GCGCCCGCCG@@@======@==@@=@========/==*=/*//*/.*/*/**.*/(/(((.((.(((.(.((.(((.(((.((.(    .  .(.   ( .////==@F@==//..    ( ......( (                 ( .           . (.../././././/.///=2/===2//=/2///=/=/=/=2=2==2=/==F==F=F=F=F=F=/=FF@FF@F@F=F=F==2=2/F==F===F   . . . . ......././2./2/=//2=======F=@@F@G@GCOLOMOMOMOMLMOMOMTLMOLOLLLCCCCC@@@@@@@@@@=@=@==@@@====@C@@CC@@==8==@@@8==@9=@@@@@C@C@@@@@@@@CCCCCGCLLLOLLCG@CGCCG@@G@C@GLOMOCGCG@@GCGLGCGCC@@@CG@C@CCG@@@@@=@=@@=@@@@@@@=@=@==@==@=====8/=/8//*/*/**/**/**/*=**=*=*/*/*/*.*.(((.((.(((.(.((((((((((((((.((( (((.(.(.(.(./(.(.   .. ..///=/=F@@F==//..   . . .........(...(..(.(..(.(.(                             .   .  . . . (.........( . . ( .. . . ...(....././///////2/=/2=F==/F=F=F/===/==2===F=====F==2=F==F=F=F@F=F@F=2=F=F@F@FF@F=F=F==2/==F==F=F=  . ( .. . .....././/.///=/2=/=/=F==F=@@F@GCGCGLGLOMOMTTMTMTMTMTTMTMMMOLOLOLLCC@C@@CC@C@@@@@@@=C@@@===@C@@C@C@=8===@C@=8=@@@@@C@@@@@C@@@@@@@CCGCLCCGLLOLOC@C@CGCCG@@G@CGCOLOLGC@@@CCGLOCOCCGC@CCGCGCCCCCGC@@@@@C@@@@@@C@@@@@@@@@@=@========8=8/=*/*8/**/**/*/***/***/*.**((/(*(.(*.(((.((.(((((((((((((*.**/*(/(..((.(((.(.*.(.((./(.*/*//(..        . ..././//=F@GC=@===//..    . ........../..(..(..*..(.(.(.(.                       (.. ( .  ( ..  . ... ( ( (...( . (...././/......(... (........(...///./////=/=/===/====F@F=F@@F==FF===F@F=F=F=F=F@F==F=F@F@F@F@G@F@FF=FF@GFGFC@FG@F@=F/=2/F=F=F==F. ( ( ... . . . ...././//2/2/=2==2==2===2====F@@@@G@GCOCOLOMOMMOMOLMOMTOMOLOLLOCCCC@@@@@=@@@@==@@=@==C@@8=8=@C@@CCCC==8@@@CC=8=@@@@@@C@@@@@@@@@@@@CCCCCCCGLOLLOCCG@CGCCGC@G@C@GCOLLOCG@@@CCCCCGCCC@@@@@@CC@GC@C@@F@@=@=@@@==@=@=@=======8===/8/8/*/8/**/(*.**.*(**.*(*.(((/((.((.(.(((.(.((.((((/(*.*(.( ( ( ((.(.(.((.(.(.(.(.(     ( ...././=@@F==////.   ( .............( .(..(.(..(.(( (                  (            .. ( ...(.../...(....( . . ( .......(././././///////=2/=/=F===F=@=2===2====F==========2==F==F=F@F@F@F@F/=FF@F@GFG@F@FF=F=2=2=F=F=F==. ( . (. . (. . .......//2//==2==F=F=F==2====2=========@@@CGCGLOCOLGLOLOCLCCCCC@@@@========@@@=@=@=@@=9=C@@==8=@C@@CCCC@==9=@CC@=8@@C@@@C@@C@C@@@@@@@CCCGLCCGLOLLOCCC@@GCCG@@@G@C@GCOLGCG@@F@@G@CCGCG@@@===@@@@G@G@@@=========/=/=//8//=*//*/*/(/.((/((.((.(((( (( ( (((((  .( (.(.( (    ..../==//////...    .  (   .(               (.. (        ( .. (......././.././.=///==2==/==///=2=/=/=2=2=/=2=/==2==F=F=F@F@F=F=FG@GF@G@F@F@F@==2/=F=F=F=F@...( . (. . .... . ../././/2===F=F=F@=F=F==F========2===@F@@CCGCOCCOCLGCLGCC@C@@@@=@=====8===@@=@=9=@@@@=C@@=8==@@C@CCCLC8=@9CCC@==9@C@C@C@@@@@C@@@@C@CCCCCOCCLOLOLGCG@CGCCGC@@@G@@CGCLGCGC@@@@@GC@CCC@@@=====@@@@@@@@@@======/==/=///*////*//*.*.*((.((.(( ( (( ((   ((   .(. ( ( .     . .//=////./...                         (        ( . ( ..(....../.././=./===2=/F/=2/=/==2==/=/=/=//2=F=2==F=F=F@F@F=F@FG@G@GF@GF@F@F=2=2=F=F=@F=...... ... .. .......././2/=2=F=F=F@F@=F=F========2=====@@@GCGCCLGLLOLLOLLCGCC@@@@@@=====@8===9@@=@@=@9@@=C@@@=8=:C@@CLCLC@=8@CLC@=@@@C@@C@C@@C@C@@@@@@@CGCCLGCGLLOLLCGCGCGCGCG@@@G@@@GCLGCG@@@@@@C@GCG@@@=======F@@C@@@@====/==///=//=*//*/.*/*.(.(.(.(((.(((( ((.(( (((( .(..( (..        ...(/////.....      . . . .( (                     .. (        ( (. ( .( ...../././/./././=//2=======/=//=2===2==/==2//2==F==F==F=F@F@=F=G@GF@FG@GF@F@F@F=2=F=F@F=@F/..................././2./2==2=F=F@@F@F===F=F===F==@=@G@GCGLOLOMTMOMTMOMMOMMOLLLLCCCC@C@@@==9=@=@@8@@=@@@=@@C@9==9@CC@CLLCC@=@8CLLC=@@@@C@@@C@@@CCC@@C@@CCCCCOCLGLMOLOLG@GCGCG@G@@@@G@@@GCGCG@G@=@@@@@@C@C@F@=====@@@@G@C@C=@====@========/==/=/8/=/8/*/***/(/(*.*(*(.*((/(.(.((.((((.(((( ((((((((****(*(((( (.(..  (.(( (.(.(.(.(..(.(...(      ..//=////./...    . . . .......(.......(..( ...( (                 . . ( . ( (           (  ...../.........*..... ( .(...(./../.*.//////=/////=/==F==@F=F@=F===F====F==F=F===F/=F==F=F=F@F@FGF=F=FG@G@G@F@G@GF@F===2@F@F=F@F//..................././///2==F==F@F@F@F=F==F=F==@F@F@@CGCLOLOMTMTTSTTSTTMTMMMOMLOLLLCCC@@@@@@@@@@@9@@@@@@@9C@@@9=@CCC9CLLLC@@=@CLLC=@@@@C@@@C@@C@CC@@@C@CCGCCOCLGLOMOLLGCC@GCCCG@G@@@G@@@CGCGC@G@@=@CGCGCGCCF@F@@=F@@@GCCGCC@@@@=@=@=============8=/8=*/*/***/**/*/**/**(/***/(*/*/(*(.(((.(.((*.*/*/*/*.(((((((.((.(( ((.((((.((.(.(.(./.*./(//(..(...(.    .  ( ..//=//////...   . . . ... .(...........(..(..(..(.(.( .((.(( (     ( ...             (  ..... (.......(.. (. .(. ( ( .. ..( (. .(..(.//////./.*.//.//(..(..(..(//.//*/.//////=/=/=====/==F@@F@@@F@@F@F==F@F@F@F@F@F@F==F=F@F@@F@F@G@G@F@FCGG@G@GG@GF@G@G=F/F@F@F@@F@=//.../.../.../././././1/2//2==F=F@=F@@F==F=========@@@@@G@LGLOLTLTMMTMMMOMMOLMOLLCLCCC@@@=8===8=9=@8@@9@@@@@CCC@@9@CCCCCLLLC@@@=@LLL=@@@@C@C@CCC@CCCC@@CC@CCCCOCOCOLMOOMGCGC@G@C@@@@G@@@@@@@C@G@@@@====@@@@@@@@=======@==@@@@@=@==========/=//*/=/*/*/*/***.(*(.*(((.(/(((.(((.((.((.((.(((.(((((((((((((( ((.(  ((/(.(.(.((.(.(..(..*..(..        ..///....(..   . . . ( . (.......(..(..(. ( ( ( (                 . ( . ( .( .( . . .     ( . ( . .(.(./...(..(..*...(......(..(../(/.///////=//=//=//=F@==F@@F=@F====F=F======F=====F=F=F=F=@F@F@G=F=F@FG@F@FG@FG@GF=F=F@F@F@F@@=///../././//.//.///././///2/2=F=F@F@F@F=F===F=2==2===/===@@@GCCCOCOLLGLCLGCLCCC@CC@@@==8==8===8=8=@@8@@=9@@@9CCCC@@@LCC9CLLLL@@==9CLL@=@9@@C@CCCC@CCCC@C@CC@GCCOCOCOLOMOLOCG@C@G@G@@@@@G@G@@@@@@@@@F@===F@F@@@@F======/===/=====/==/////*/*./*..(.((.(((.(( (.(.   (    (.( .         .//./...(.          ( . (                          ..( . ...( (.   .(.( (...(.....//.//.///=///=/===/==/==/===========2//=====F=F=F=@F=F=F@F@F@GF@FG@FG@G=F==GF@F@@F@@@////././///////./2.//1/2//2/==F@F@@F@F=F==F========/==/==@@@@G@CLCOCLGLCCCCCC@C@@@@====8==*==8=8=@9@=@9@@@@@9LCCC@@@CLC@CLLLLC=@=@CLLC=@@9@@CCCCCC@GCCGCCGC@CGCCLOCOLOMOMOLG@G@@@G@@G@@@@@@F@@@G=@@@=F=====@F==@======/==/=/=/==//=//////(/./(.(.(.((.(.  (  .((.( (   . ( (            ..//(.....                                             (  .       ....(..././././//=/=/==/===/=/2===2==2=2=F=/=2=F=2=F==F=F@F@=2=F@F@FG@G@FG@G@GF@F=G@GF@F@F@@F=//./////.//2/////2////2//2=2=F=F=@F@F@=======/=2==/====F@G@CCGLCLOLLOCLCCCCCCCC@@@@==8==8=8==8=8@@9@=@@9C@C@LCLC@@9CL@@CLLLL@@=@9CLLC=@@@@CCCCCCCCCCCCCCCG@CCGCLGLLOLOMOLLGC@G@@G@@@FCF@@@@@@@@@F@===============@====/==/==/=///=//////(/(/.(/((.(((.(((  (.( ((.(.( (   (.              (./....(.         . (. .                                    .( ( ( (....( (.  ( (.( .( ..(..//.//./////=//==/====/=/===2=====2====2//==F=F=F==F=F@F===F@F@F@FG@G@G@G@F@F@GF@@F@@FF@@F=///.////////2/2///2/2/2/2/=2@F=F=F@=F=F====F======@F@CCGCOLMOLOMMMTMMOMMOMLLMLLLCC@@@==8=8=8==8@=9@@9@@CCC@CLLCL@@CCLC@LLCLL@@@=@CLLC=@@@@CCCCCCGCCCGCGCCCG@CCGCOCLOLOMOLOLG@@@@@G@@@@@@@@@@@F@==@======/=====@=@@@@=@==============/==/=//=///*///*/*/*.(.((/(((/((.*((.((.((((.((((((((((((((((((((( ((.(.(/*/*.*.(.(.((.((.( .(..                .//(...... ( .......(..( ..( (. (. (.( ( .   .... .        ( . (. . . .......( .. ... (. ( . (    ....(...(...(../.(/.*//.(.(/(...*..(./././*//=/=/===/===@@=@@F=@=F===F=@=F=F=@F=F@===F=F@=F=F=F@=F@2==FF@F@G@GF@G@G@GF=F@GG@G@FF@@F@@@=/////////2/=//=2=/2//2=/2==2@F=F=F@F==F=2====F=@@@@CGCLOLOMMTMMTMTMTMTMMTMMMMLLMCCCC@@@@8@=9=@@@CC@C@C@CCCCCCLLL:@@CLC9CLLCLC@@=8CLLL@@@@@CCCCLCCLGCCCCGCCCGCCGCOCLOLOLOMOLGC@G@@G@@F@@@F@G@@@@@@@=@==========@@@@@C@@@@@========@========/=/=/=8//*/*/*/*/*.*.*(/*/*/(*/**/*/((*.*.(.((((((((((((((((((((((((.( (((.(*.*/*/*//*/*.(.(.((.(//(/.(...          ( .     ( (...///...  . . . . . ... ..../......(..(..(.(.(..(..(..(........ ...(.. ( .      . . . . (. ...(.... .../.....(.....(. .(.(. (... ( . (..(..(/..(.////*.//*///*///*./*///(//*///////==/========@@@@@@@@@@@==F@@F@@@F@@@G@F=F=@@@F@F@@F@F@@@F=F@@G@G@GGGGGGGGCF@=FG@G@FG@G@@F@F@==//////2//2/2/=/2=2=/2=2/=F==F@=@F=F======F=====F@@@GCCCOLOLOMOMMMMOMMMOMLMOLLLCC@@@@@8=8=8=8=9@9@@@C9CC@CC@LLLLCC@CLC@@LCLLL@@=@@LLLC@@@CCCGCOCOCLGCCCG@CCGCCGCGLCOLGMOLOMOC@G@@@@@@F@@@@@@@F=F=======/=///=/===@=@@@@@@====/===/=/=///=*//*//*//*/**.*(/((.(.(/(*.*(*(.*(.((.((.((((.(((((((((((.(((.(*.*(*.*.(*/(.(.( (.(.(.*..(..           .    ....(    . . ....(.........(..(.(.(..( ( .. . ... ( . .           ( .. .... .......... ( ..... (. .. (   ...(..(..(..(/./(/.*./.*./(/(/.(//(/.*.///*/==/=/======@F@@F@@@F@====@F@F@F@F@F@@F===F=F@F=F@F=@F@F==2@F@F@G@G@GC@G@GFF=G@GF@GFGF@F@@@=F==//////=2=/=/2=/==2=2/=2=/F==F=F=@F==F==============@@@@CCCCCCOCOCLLCCLCCC@CC@@@=8=8==8=8==9==@=9C@@C@CCCCC:LLLLCC@CCC@CCLCLLC@@=9LMLL@@@C@CCLCCOCCGCCCGCCCGCCOCGCCOLGLMOLOOLC@F@@F@@@@@F@@@@=@=======///=///////==/========//////(/./(./(.(.(.(.((.(..((.(( (( (((   (.((( (((( (( (( ((.(.(.(.      .    .(..          ......      ( (                     . ( .                   . (..( (.(.( (.( ((...(..( .(..//(.//.///=/===/====/==//==========F==F//F==F==F==F=F=F=2=F@F@F@G@GGGG@GG=F=G@GGFG@GF@@F@F@@=F/=//2////2=/=2=2=2==2==2==F=F==F=@F=======F====/=====@@@CCGCCCCLCCCCCC@@C@@@@=@==8=8==8=8=@8@=9@@C@9C@CCCCC9LLLMCC@CCL@CCLLLLC@@@@CMOM@@CCCCGLCOCOCCGCCGCCGCGCCGCGCCLGLOMOLOLGC@@@@@@F@@@F@F@=F@======///////////////===/====////////.*.(.(.(.(( ((.(. (( (( ((..(     (((.(((.(( (.( (..(( (.(.(..       . .   ....       . (. .   (  (                    .               . (. ( ..( (...( ( ../..(.././.==/===/=/===/=/======F====F=========F==F=F=F@==F@@@F@@G@G@GGG@G=@F@GFGFGFG@F@@@@F@===/2//2/=2=/2==2=2=2==2==2=F==F==F==F===2========/==@@@@CG@CCCCLCLGLCLCCC@C@C@@@===8=8==9=@=9@=@9@@@C9C@CCCCC:LLLLL@@CCCC@LLLLLL@@@@CMMML@CCCCCCCOCGCCCGCCGCGLGCLGCGCGCGLGLOLOLOC@G@@@@=@@=F=@F@=F======/=//////.//*//.//=/==/====/=/*//(/.(.(.(.(.(.((.(( (.(.(( (.( ((( (  ( .((.(((.(((.((( ( (.(.(.(.(.(.(.         .   . ( .         . (.. ... . ( ( . ( . ( (                       .. .(. .                  (..(..(.(.( (.(.( (.(..(.(....//(/.//.//=====/======/=/==F=====F==F==2==F==F==F=F=F@=F=F@F@@F@FG@GGCGGG=F=G@GFG@GFF=F@F@@F@===////2//=2=/=2==2==2=F==F=F=F=F=@F===F==/======@@CG@OLLLLMOMMLOMMMMMLLLLLLCLCCCC@@@@@@@@@9@@@@=9@@@C@CCC:CCCC:LLLLC@CLL@@LLLLLLC@@@CMTMOC@CCGCCCOCOCOCCGCCCGCGCCGCGCGCGLGLOLOLOGCG@@@@F@@===@=F==@======/=//////////=//=/======@=@========////*/*/.*/.**.*.*.*/(*/(*/(/(/(.*.(((.(((.((( (((.(.(.(.(.*.*//8//8//*/*.(.(.(.*..*.(.(.(./(..(.(..(              ..    . (.    . ........../../..(..(..(...(...(... ( .... .. . .    .  . . ..... ../.././..... (. ......(..(... (  ....(...(..(..(/.//(//.*/.*/.*/.*/.//*/////(/==//=/====@@@@@@@=@=@@===@F@@F@F@@F@@F===F@F@F@F@F@@@F@F==F@FG@G@@G@GGCG@F=F@GFGFGFG@==@@F@@F=F=/=////2/=/2=/2==2==2=2==F==F=@=F========/===@=@@CCOLOLOMMTMTMMTMTMMMMMLLLLMLLLCCCCC@C@C@C@@C@C@9C@C@CC@CC:CCCCLLMLC@CLLCCCLLLLLC@@@CLTMMCGC@CGCCLGLLGLCGCGCCGCGCCCGCG@CGCGCOLOLLCG@@@@F@F@F=@@=@F@F@=@========/=/==/===/=/=/===@@@@@@@@@======/=///8///8/*/**/*/*/*/*/**/*.**/*(/(**/(((.(/((.((.*/*/*=8=8===*=*/*/(.(.(//*/*/*//*/*/(/*..(/(.(.             . (    (......    . ( ....../...//.//./..(..(/..*..(//.(..(......(........ .. ( . .. . . .. .....  ..... ....... ././//.////./.............(...(..(...(././.*...(...//*/////*///////*//=*//=//=*///==========@G@G@@G@G@@G@@@@@G@C@G@@@G@G@F@@G@@@@@G@G@G@G@F@GCG@G@GGCGGCGGG@F=GFG@GFGFF==F@F@G@@F==2=/////2=/=2=2==2===F====F=F====F=====/===/===@@@CCLOLOMOMLOMOMMMOMOLLLLLLCCCCCC@@C@@C@@@@@9@@@9@@C9CCCCC:CC@CCLMML@CLLLCCLLLMLMC@@CLTTMLCCCCGCCCGLLGLGCCGCCGCGCGCCCG@CGCGCGLGLOCG@@F@@===F==F==========//=////*//=///=/////////============/====//*=/*/(/(/*.*/(/*.*.*(/((.((.((.((.(((.((((/*.*/*/*/*//*//*/(/(.(/(/*.*/.*.(/(.(.(.(..(..(.(             .(     .. .../../././../.*..(...(/.(...(.( . (. .....( . .  . . .   . .. . (..  ....././../..(./..(../.(....(...  (..(..*..(..(.(.(//*////(/*./*//*/*/*///*=////==//==//==@=@@@@@@@@F@@=F@@@F@F@F@F@F@==F@F@F@F@@F@F@F@F=G@G@@GF@G@G@GGG@F@=GFGFGF@GF/==F@@@@F@=F==////2//2=/==2==2=F/F=F===@F=F@=F=====//=/=======@@C@@CCCLCLCCCCLCCCC@@@@@@@=@8@@=@9@@@=9@@@9@@@9@CCC9CCCCCCC@LLMMLCCLLLCCLMOLMLLC@@CMTSTCGCCGCCCGLOLLGCCG@C@GCCG@GCG@C@G@CGCGLOLGC@G@F@==========F=====////.///.*.//.*/.//*//./(././(/.*.*.(.(/(/.(.(.(.(((((( (((.(.(((( ( (.(.*.*.(/(/((/(.(.((.( (.(.(.(.(.(.(.(..(.((.(.(.(.          ..       . .. ....(...(. .(....( . ( (                .. (. .... ... (        ....   .( (.(.(.(..(..(.(.(.((..*.(.(//.(////*.================@=F=@======F/==F==F=@F=F=F@F@=F=G@FG@@G@G@G@GGG=FFG@GFGGFGF//==@F@G@F@===2=/////=/2=/=2=F/=F===F=F==@=@=======/=/=/=======@@@CC@CCCCCCCCC@C@@C@@@=8@==@=9@@@@@@@=9@@@9@@C@9CCCC9C@CCCC@LLMMMLCLLLLCLMOMMOLCC@CTSTTLCGCCGCCGLGLOCGCG@C@G@GCCG@G@G@G@CGC@GLGLGC@@F@=F=====F===/==/=///////./*.//./.(././(/./././(..(.(..(.(.(.(.(.(..(( (.(.(( ( (( ((.((.(.*(.*.*(.(((.(.(.(.((.(.(.*.*.(.(.((..(.(.( (.(..(.        .          . ... .... (. . (. .( .                    . . (        ( .   ..(..(..(..( (.(.(./(.(.//(../(././=/==/==/====/==F=@=F==@=F===/=F===F@F=@F=@=F==F@G@@G@FCF@GFG@GF@FGGFGGFGFG///==F@@@@F@F===/2=/2///2==2==2==2===F===F@========/=//=/=====@@@CCCCCCCCLCCCCLCCC@@@C@@@@@9=@@@@@@@9@@@8@@@9@@C9C@CC:@CCCCC@LLMTMLLCMOLLLMMMMTMGCCCLTSTMCCGCCCLGLGLOCCCG@@C@CG@CG@G@@@FC@G@CGCGCOCG@F@=@====/===2==///////////./*././.(/(././(.*...*...(..(..(.(.(.(..((..(.(.( (.(.((.((.(/*.*.*.(.((.(( ((.(.(.(/*/(/(.((.(.( ((.((.(.(( (.(. ( (             .        . .............(....... (. . .              ( .. ......... . (       ..( .   ..(..(.(..(.(.(.(.((.(.(/(..(//.(/=/./*============/===@@=F@==F==F===F=F=F@F@F=@F=@@F@F@G@GFG@FG@@G@G@FF@GGGFGGGFG/./=/==F@F@@F@=2==////2//2/=F/F/F=======@===@=======/=/=/===@@CCLLOLLLLMLMMLMMLLMLLLLCCCCCCLCCC@CC@C@@@@@9@@@C9@@:@CCC@CCCCCCCCLMMTLLLLMOLOMTMMTMLGCCOSVTTCCOCOCCCCGCOCGCG@@G@G@G@G@@G@G@@@G@@GCCGCCG@@@F=F===/====/==/=/////////=//////////*/////////////////*.//*/*/(//*.*/(/(/(/((.*.*(//*/*/*/*/*//*.*.(.(.(.(.(.*.*/=/*//=*/*.*.(.(.(/(.(.((.(.( (.(( (  ..                ....../././....../././././../....(............ . .. . . .  . . .. .. .  . ( . . .. .. ....../././/.///./.../.........(.. ( .(././/(...(.../(/.*//=//*//(/*/*//*//*/=///=====/@/=/==@@@@@@@@@@@@@F@G@G@@G@@F@@F@F@@F@G@@F@F@@FG@F@G@G@GG@GFCFG@G@GFFFGGGGFGGGH.///====@G@F@F@==/2///=////2===2=======F==@==F====/==/=/===@@CCCOLLMTMMMTMTMTMMMMMLMLLLLLLLLLCLCCCLCCCC@@@@@9@C@@@C@CCCCCCCCCCCCMMTSMOLMMMOMMTMTMTMMGCLMTVTMLGCOCOCCGCGCCCGC@G@G@@@G@@@F@F@F@G@@G@GCCG@G@@@F@F=F=======/========/=/==/=////////=//=/=////=////////////=*///*//*//*//*//*=/*/8/*=//*//*.*//(/(/(//*//*/==/8====*//*/(/(/*//*.*/*.*.(.(.((.(.(.(.(/.( ( .( .          ...    . . .. ...//./////.//.///.//.//./././....................... ... . .. ............. .... ......... ....//.//////////.///.//././/......(..//*.////../*.//////=*===/*=//*//*//8/=*@==/@@@=/=@====C@CC@C@@CG@G@@@CGCCGCG@G@GCG=@GGCG@GGCGCG@G@G@@GGGGGGGGGGCGG@GGF@FGGGFGGHGH..///=2=F@@@@F@F==/=////////2/==/F=2=F==============/=/=/====@@@CCLOLLOLLMLMMMOMOMLLLLCLCLCLCCCCCC@C@@@9@@9@@C@:C@C@CCCCCCCCCCCCCLMMTSMOMTMMOMTMTSTTMGCOLTVSTLOCOCGCCGCGCGCGC@G@@G@@F@G@@G@G@@G@@F@G@@G@G@F=@======/=////////////*//=///////*//.///*////////*/////*//*./*/./*/(//*/*/*/(*/*.(.((.(.((./((.(.(/(/(/*//*//*//*/(/*.(.*/*//(/(/(.(.(.(.(( ( (...(. (               . ....././/./..././././/./.././............... . .. . . . .  . . . ..... . . ... ... .. (.......///././///./../...(.....(.....(..(./(/.(/.(././(/////*////*//*/*/*//*//=/*=====//@/=/=@@G@@@@@@@@@F@=@@G@G@@G@@F@@F=@@G@@@@G@@@FCFCF@G@G@GFG@GFG@GG@G=FGGGGGGGGFG.././/=/==F@F@@F===2///////////=/==========F=======/===/=/=/=/===@@CCCCCCCLCLCLCCCCC@@@@@@@@@@9=@@@@9@@@@@@9@@@C@C@CC@CCCCCCCLCCCCCMTSSTMMMTMMTMTSTSTSOLLOSVVTMLCLGCGC@C@CGCGCC@@@@G@@@@F@@@FCF@@@@@F@@@F@@@F=F=====2/=////.//..///./......(.......(..(.(..(....(..(.( (..(..(.(.(.((((.(.((.(.( (.(.(.(.*.*/(/(.(.(.(.(.*.*//(/(/(..(.(.(.((..(.*.   .                      ......................... . . . ..  .     .( .......... .. (. .(.( . (  . ( . .. (. .(.(.*./(.(.(.( (.(.((.8..(=/=.*/=./*/=============/======F@=@F@F==F@F@F@F@@F@F@@F@FF@FFFG@GGFG@GFG@GFFGGGGGHGGGH...//.//===F@@F@=F==//2/=///////2=/==========@======/==/==/=*=/===@9@CC@CCCCLCCCC@@@@@=9@@@=@=@9=@@@=@9@@@@@:@C@C@C@CC@CCCCLCCLCCCCCMTSTSTMTMTTMTTVTSTTTMLOSVVVTLGCCCGCG@@CGCGCGC@@@@@F@@F@@F@CF@G@F@F=@@F=@@F=@=====//////././(/././//../../../....(.....(........(....( (.(.( ((( (..((.(.(.(.(.(.(.*.*.(.(.((.(.(.(/*//*/*/(//*(/(.(.((.( ( (.(.(.  ( (                       ................... . .. . .    .     . . ( . ... .. ( ...      (  . ..(.(.(.(.((.((.(.(./(.(///(../(..*===/=/===/==/=/==@F=@F@=@F@F==F@@@@F@F@F@F@@F@F@FF@FGFGG@GFGGGF=FGGGGGGGHGG..././///===F@@@==F==////=////////=/=======@=======/==/==/=///=*==@@C@CCCCCCLCLCCCC@@C@@@@@C@@=@@=9@@@@@9@C@@C9@C@CCCCCCCLCCLCLCLCCCCMTSVSSTTSTSTSTVTSTSTMOMTSVVTMGCGCG@CG@@C@GCGCF@F@@@@@F@@F@G@F@@@=F===F===@=F===/=/=////../.././././.../...(./.../.(...(....(...(. (.( (.(.(.((.( (.( (.(.( (.(.(.(.(/(.(.(/(.*.(.(.*.*/*//*///*/*.*./(.*.(.(.(.((.((.(  (.( (   (                  . .................... .. .. .. . .. .  . . .  . . . (. ............. .. .....( .. . ( . ...(. .(.(..(.(..((.(.(..(.(.*/.*==////=/*//============/=======F@=F@=@F==@F@F@G@@@@F@F@F@F@F@FGFGGFGGGFG@GFFGGGFGGGGGH...././///=/==F@F===2=//2//////////==/==============/=====/====@@@CCCLLMLLLMLMMMLLLLLLLLLLLLLCCCCCC@C@@@@9@C@@@C9C@CC@CCCCLCLCLCLCLCCCLTSVVSSTSTSTSVVTVTSTTMMTTVSTMOCGCG@CG@@G@CGCCG@@@F@=@@F@@@@@F@F@=F===@==F==F=====/=/////////////////.///.///.//////////.///////.///*.//.*.//(/.(/(.(.*.(.(.(.(.*.*.*//*//*.*//(/*.*//*=/====*///*//*.(/(/(/(.(.(.(.(.(  (.( . (            . . ...././///////.//////./......../...../....... ...... . . . .. ......... ............. ......../././//////..//.//.//.//......./(..//.(./././*.///8/=/=*/=/*//*/*//*//==//@=@*====/==@@C@@@@@@@@@===@@@@@@G@@GC@G@FCGCGCGCGGCG@G@FG@FFGFG@GGFGFGGGHG=FGGGGGGHGGH..../././//=/=====F===/=//=/.////////=/==@==@=====/===/====8===@@CCLCLMMMMMMMTMMMMLLLLLMLLMMLMLCLCCCCCCCCC@C@C@C@@C@CCCCCCLCLLLLCLCLLCLCOSVVVSTSTSTTSVSTVTSTTTSTVVSMOCCCGC@GC@@G@C@C@@@@=@F@@F@F@=@@@@F@@F@F=@====F======/=////=/=//=/////////////=/////////////=//=/=/////*////*/////*/*/*.*/*/*.*/*/*///*/////=//=/*/====@========8/=*//8//*/(//*/*./*//(  .(.(.(.((..(..(            . .. .. .....//.////=//////////////././//../.././................... ................ ............. ././///./////////////////////=/////.././////*./////*////*=/=/===8//=*///*/=/8=====@@@===@===@CCC@@C@@@@@C@@@@G@GCGCGCGCGLGCGCOGCOGCOGLGGGCGG@GFGGGGGGGGGGGGGFGGGGGHGGGHG..../././////=/=F======////////////==/=============/===/8=/=8===@=@CCCCOLMLLMLMMLLLLCLCCLLLLLLLCCCCCC@@@@C@@C@C@C@:@CCCCLCCLCLLLLCLLLOLLLMTSVVVSVTSTVTVSVTVTSTTSTSVTTMGCGCG@GC@@@G@@G@@@@@=F@@F@@F@F=@=============/=/=////////////////////././././///////////*////////*//./(./*//(/(/(..(/(..(.(/(.(.(.*./*/*//*/*//=*===========//*/*/*/(/(//(/*.*//8/(. ((((.( (                     . .. ....././///////////////......../../.../...../...0. ... .. .. ...........  .............  /./...././././/////..//./////////../../.*./../(/.//(//*///*/=/*//8///*//*//*/==/*/@@@/==@/==@@@@@@@@@@@@@==@@@@@@@C@G@G@G@GCGCGCGCGCGCG@G@FGFGFG@GFGFGFGFGFGFFGGFGGGGGGG../.../../////==/=====//=///////////==/==========/=8==*==/8=/8/*/8=8=@@@C@CCCCCCC@C@@8@@@@C@C@@@@@@=@@C@@@@@C@C@9C@C@CCCLCLCLCLLLLLLOLLOLLMOSVVVUTVTSTVTVVSVTSTSTTSVTTTLCGC@CG@G@@@F@@@G@F@==F=@=@=@F=@F===F====2=/=/=////.//../././../..../...(....(....(....(..(.(...(.(..( ..(..(.(.(..((.*.(.(.(.(.(..(./(///=//=*//=/8/=//8///*/*//*/*/*/(//*=/*.(( (.(.((( (...                        . ....././///.././.................. .... . . .  . .  . .  ..... ....... .... ......../...(...( ..( (.( .( (.( (.(.(.(..*.*.(*.(.*.(.(*.8./(=/=(//=*./*============//=====F==@=@=@@=F@@F@@G@@G@@GF@FF@FF@FGFGFGFGGGFGHFFGGGGHGHGGH......./.././///==/====2/=////////=/===/==========/=8/==8/=/=*=/*/*==8=@@@9@@C@@@9@=@8=8@@@@@@@9@@@@@@@@@@C@@C@CC@@C@CCCLCLLCLLLLLLLLLLLMOLMMTVVVUTSTVTSVVVVSTTSTTTMVVVTLGCG@C@@@@G@@=@@@@@F@=F==F===@==F=========/=///////.//../..../../...(.....(.......(. .( ... .(.. (...( .(.( .(.(.(.(.((.((/((.(.*./*/=/=/8/=/=/=*=/=/=*/=*//*/*//*/*//*/=/*/(.(.(.*.(((.(((   ((                            . ...././././....... . . .. . . .. . . 0 .0  .  . . . . . ... .... .... .........(... ( ..  ..( ( ( ( .(.(.((.(.((.(.(.(/(.//*=.(//.(./=/=8/==/==/=//=======@=F=@F@=F@@@G@@G@@G@@GF@FFGFFG@GFGFGGFGHGFFGGHGGGGGHGF.../../././././///==2===//=/////=/=/=/====/====/==8/=/==/8=*=/8/8/=*=@=9C@CC@C@C@@@9@@@8@@CCC@C@@@@@@@@C@@@@C@C@C@C9C@CCLCLLLLLLLLMOMOMMOMLOMOMTSVVVTSTTSVVVVVSTTTTTSTVVVMOC@G@G@@@@@@F@F@@@@F@====@F=======F=2==/=/=/=/////.//..../(./...(..../(.....(... .( .(. (.. .(...(. .....(.(..(.(/.(/(.(.(.(//*//==/==/=/=*=///=/=*==///8///*/*//(/*=/*=.*.(.(/8/*.(((.(.( ( (                        .. .. .././/.////.//./....... ............ . .. . . . .  . . . . .  . . . .  ....................................(......(...( (.(.(.(..(.(..((./(.(.(.(/(.(///(/==///*=//(====/========//======F===F=@F=@F@F@@F@G@G@G@FGF@FG@GFGFGFGFGHGFGFGHGHGGHGGFG/...(../.../././///==/==/=////=//=/===/====/==/==/=8/==*=/8/=8===8@@@@CCLCLLLLLLCLCCCCCCLCLLLMLLCCCCCCC@C@C@@C@C@C@C@C@CCLCLLLLLLOLMMMMTMMOMOMLMMVVVSTSVTSVVVVVSTTSTTTSVTVTMG@C@@@@@F@@@=@=F@=F@=F====F===F======/=2=//////////.//./././/./././../././././/.//../././/././././.(../(./.(.(./*.//(/*//*//8/=================/======8=//*//*/*.*/=*=/*/(/*/8//*/*/((.(  (  (                      . ......././///=///=2/2////./../..././...1...1..1..1.1.1..1.1. ..0............ ....../..... ././//////.///.////..///././//////////=//////.//*.//(///*./*///=/=*==*=/=*//=/==8/@=@===@=/===@@@@@@@@@@@@==@@@@@@C@C@CF@CFC@GCGCGCGGCGGGGGGGGGGGGGGGGGGHGFGHGHGGGHGGGFGG/..../(../../././///==/=///=////====/====/==/=/8==/8==/=8==8===9=@=@9CCCLLLLMLLLLLLLCLLCLLMMMMLMLLLLCLCLCLCCC@@C@@CCCCCCCLLLLLMLMLMLMTMMMTMOMOMOMOMVVVVTSTTSVVVVVSTTTSTTSVVTSOC@@@@@@@@@@F@========F=======================//////.//////////////.//////////////////////////=/////*./////*////*//=/=/=========@=@@==@========@=@=@======*//*/*/=/=*/*/*/=8==8=/8/(.((((.( (.(.                 . . . . .. ...././/.//////2==F/==/2/2//2./2///.2//2///2./.2..2.2./.2..2.. 1 ....1......... ......//.//.. //////=///==////=//..=//////////=//=/=/===//=////=///*//=////8/=/======8====*=@@=/@@@8==@@===@@@@@@@@CC@C@@@C@CC@GCGCGCGCGCGCGCGLGOOOOLOOOOOOGGOGGGQGGQGGHGGHGGHGGGGGGGGG/......(.../...///////=/=/////=/=/==========///=*=/==/8=*=/8/8=8=8==9@@@CCCLCLCLLCCCCCCCCCLCLOLLLCCLCCCCCC@@C@C@C@C@CCCCCCLLLOLMOMLMMTMTMMTMMOLMOMLMTVVVSTSTTSVVVVVMTTTMTTSVTVTCCF@@@F@@=@=@==============/=/=////////=//=/=///.//..././../...../../././/././/.//././///////./.(/././(/./*.//=*/=/*=*/=*=/======================8==/8//*/*///8/8//*/==8==*==*/*/((.((( ( (  ..(                 ........././//2//2/=2/2/=2//./../.1//./2..2./..1.2....1/1.1..1. .1 1...........  ....../.... ././///=//////.//=/../////////////////=/=/=/////*/////*///*///*/=/8/=/8=/*/=/*==/8=@=@/=@=*/==@@@@@@@@@@@===C@@@@@@@G@C@G@CGCCG@GCOCGLGOGOGGGGGGGGGGHGGHGGHGHGHGHGHGGGGGF.//..././..(../././//////=///=//==/========/=8//=/8===/8=*=/8/8/8/*=**=8=9@@@9@@@9@=8=8=9@@@@C@@C@@@@C@C@CC@CCC@C@CCCCCCLCLLLMOMMMMMOMMTMTMTMMOMOLOMMTSYVVSTVTTVVVVVTMMTMTTMVTSTTC@@@@@F@=@=@=@=====F=/==2==//=///=/=//=///////////././...(....(...(....(....(....(....(....(...(..(../*./*///////8//*///=/8/=/=/=/=/=/==8========/8///*//*==/=*==8=====8=8/=*.((.((.(.(( (  .( (.(           .      .. .........///.///2....1..1....1........1....1..1. .. 1 .0 0 .. . .   .... ...  ........./....../.. .../........././././/../.(..(.(.*.(.(.(.(.(.(/.*/*/(/*.(/(=/*.*/=*.*/(/(/*=/=/8/=8===/=/=====@===@=@@F@=F@=@@F@G@GGGGGGG@G@GFGGHGGHGHGGHGHGHGGGHGGFGG../...(../...././/.////////=/////============/=/8/==*===*=*=*=*8/8*/*/*=8=8=@9@9@=8=8==8=8@@9@@@@C@C@CC@CC@CCCCCC@CCCCLCCLCLOLMMOMMMTMTMTMSMTMMMOMOMOMTSYVVSTTSTVSVVVVTMOMMTMTTSTTTC@F@=@@F==========/====//=///////////////////////////./...(.. ( .(......(.. ( ....(....././../(./(/.//(//*//*///*////*=/=/=/==/=========8===/8=//*//*====8===8====8===8/8(/(((/*/(((.((..(.(..                 . . . .......//1//./.1... .. ........1...1 1..0..0.1 . 0  0. . .  . . .. . . ........./....... ................./../..(/.(. (.(.(./(.(. (.(.(.(.*.(.(.(.(/*.(/*//(//(.(./*/*=/8//=8=//========@=F@@@=@F=@F@F@@G@GGFGGGGGFGG@GGGGGGGGHGGHGHGGFGGGGGGG../.(/...../(....//././////*//=//=/==========/==/8===8=/8=*=*=*=*=8=*8/*=8=@9@@9@@9@=8=8@=@@@@@C@@@@@CCCCCC@CCCCCCCCCLCLLCLLLLLMMMMMTMMTMTMTMTMTMOMMMTMOSVYVVMTTTVSVVVVVMOLMOMTTSTTTMC@@@=@========/==2=/=//////////////////////////////////......(....(........( .(.....(....(....(../(/.*./*./*////*/=/=/==/========8======*==/=*=/8===========8==@=8=8/*/(((/**/**.((.((  (.(.(.(..            .. .  . ........././/1//1/2./..1....1...1..1...1.....1..1.1.1.1. 0 ... ..   . ... ..  ...././..//.....//. ../........./././//.///./.(.(.*..*.*..(.(.(.(/*/*//*/*/.*//*.(=/*/(/*/*.*=/=*=//8====*/=======@=@=@@@F@@@F@@@FG@GFGGGGG@GGFGGFGGHGGHGGHGGHGGGHGHGGFGG.*./.../(./.././.././//./////////*=/=======/==*===/8==/=8/8=*=*8=8=8==@9@@CCCCLCCCCCCC@CCC@LCLCCLCLLCCCLCCCCCCCCCCLCLCLLLLOLOLLMOMMTMTMMTMTMTMMMMMMOMTMTMTMVYVTMTTTSVTVVVSTLOLLTMTTSTTO@@@=F@=======2===/=/=//////././/////////.//.////////=///////./././/./././././.././///.////.//.//./*///*////=*=/=/===/========8======8===8===8==@@@@@=@=@@==9=8==***((.**/*/****.*(.(.(.(..(...           ( . . . . . . . ......././1///2/2///2=2/2/2/.2/1./.1/.2///2/.2/2/2/1/.2./1..1.0 0 .1.......... .././1/./.. ..//////////=/.//=/../=///////////////===/=/=////=//=/======/=*=//8=/===/==*=====*==@====@=/*==@@@=@=@@@@@==@@@@@@C@C@GCGCCGCGCGCGGGGOGOGGGOGGGGGGGGGGGGGHGGHGGHGHGGGHGGFG..(.(......./.././././.*/././*//=//=======/====*=====8=/8=*==8==8==9@@9@@@C:LLCLLLLCLCLCCCCCLLLLLLLLLMLLLLLLLLCCLLLLCLLLLOLLLOLLMOMMTMTMMTMSMTMTTMTMMTTMTTMTMVVVTMTTSVVSVVVTMGLOLTMTTTSTT@@@==========/====/=/////////////////////////////=//=//=///=/=/=====/=///=//////=/=/=//=///=/===/========/=======@=@=@=@@=@=@@=@=@======@@@@C@@@@@@@@@=@==8=**/(/**==*=*8/*/**.(  (.(.(.(.( ( ( .         .. . .. . . .. . ... ...... ......//////2////2///=2=/2/=2//2/2//2.2/2/.2/2/2/2/2//2/2//2//2/.1. ..0 .1/2/.2./1. . .///2/2/2. .////=/F/==2=/.2===./=/===/==////=/=/=========/=/===============8===========8==@===@@@==@@8===@@@@@@@@@@@C@@@@CCCCGCGCLGCOLCOLCOGLOOOOOOOOOOOOOGOGGGOGQGGQGQGQGGQGGQGGGGGG..(/..*./.././.././././.(/.////*//=/=/==/==8/===8==/==8=/8/=*=*=8=8=8==8=9@@C:CCCCL:CCCC@@C@C@CCCCCLLCCLLCLCCCLCLLLLLOLLOLLMOMLMOMOMMTMTSMTMMTMMTMTTSMTTMTMTTMTVVSTOTSVTSTVSVTLGLOLTMTTMTTMG@=====/=====//=//=/////./////////////...././/../..//.////////////=/=////////=/=/=//=//=/////=/=//*////*/=/=============8====8====8@@@C@C@@@@@@@@@@@@=8=*/*(/(*=*=8/8/*/**/*((.(((.((.(.(...(.(     (       . ( . . . . . . . . .. . . ...././/./.2/./2/2/2/=2//2/1/.2.2..1.2.2/.2.2/2/2//2.2/2/1/1/.0 1 ...1/......  ..2.//./.. //2/2///2/2=2/./2=2.//=2/=///=///////=/=/=/=//=/////*========8====/8/===8===/8/=/*===@==@@/8/@@@@@@@@=@@@@==@@@@@@C@CCGCCCGLCGCOCGGGOOGOOGGGGGGGGGGGGHGGHGGHGHGGHGGHGHGGGG..(../..(/..//./././..(/./(/(///*///=/====/=8=/=*==*=/8/8/8/8*=*=*=*/*8/**88=8=9=9@@9@=8@8=9=@@@@9C@CCCCCCCLCLCLLOLOLLMOLLOLMLOLMLTMMTMSTMTMTMTMTSTMTTMTSTTMTMOMTVVTMOTSVTSTTVTTLGCOMMTTMTMTMG@====/=2====/=////////./././/////././.........(..(......(//.///././..././/./////////////=////=/=/=*=/=/=/============*==/===8=@CCCC@C@@@@@@@@@@@@8=/*/(/**/8=8=*=*/8*/**.((.*.*(.((.( (..( .(     (     . . (. . . . . . . . .  ............../..2...1/1..1...1......1......1/1..1.1.1.1.1  0...0.....    ....1... ....../.././. .//. ..//././/...././././/////(..(/*./*///*/*//*/*/*/(/*/*.*.*.*=(.8//8/*=//(/8/8=/=*=8/8/=*/==========@=@@@@G@@@G@GFG@GFGG@GGFGGGHGHGGHGGHGGGHGHGGHGGGGGFG..(..(..../..//././/./..*./(//(///*=//=/==8/==8==*=/8=/8/8/8/8*=*=*=8*/8*/**/8=8=8==8=@=8@==9=@@@@@C@CCCCCCLCLLLLLLMLOMLMOMLOMMOMMOMTMMTMSMTMMMTMTSTSTSTTMTTMTMOMTTVVTMMTVTSTTSTTMOLGLOTTMTOMMOC==/===//==2=///////.///.//.//.//./../......... ( .. ......../././..././///////////.////=/////=///=/=/===========/====8==@CCCCCCC@@@==9=@@@@===**/*(*/8=8==8=8*/8/***.((/**/*/(.((..(..( .( (   .  (    ... . ( . . . .. . . . . . . . ..../....1..1.....1....1..1. .1 1....1.1./.1.2..1.1...1 0 0 .0.. . .   . 1.....  ...../....... .... .../../../.......././../.(..(..*./(//*/*/*/.*.*./(/(.*.(.(//(.*/*//*//(.(/=/8/8/*/*=/=*/===========@=@@@@FG@FFG@GFGGFGFGGGGHGGGHGGGHGGGHGGHGGHGGHGHGGG../(../././././/././/./(/./(/.*//*///=*=====*==/8=/8/=8/=*/8/8/8/8=*=*8*=*8/88==9@@@9@@9=@9@=@@@@CC@CCCCCCLCCLLLLOLMOMLMOMLMMOMMMMTMMMTMTMTMTMTTMTSTSTTMTTMTTMOTMMOTVSVOMTVTVTMTTTSTOLCLOMTMOOMOOL@/=/=/=2=/==/////.//.///.//../.../.../......... (. .. ..........(../././//////.///.///=/=/=///=/=/===============/=@@@CCLCCCC@@@=8==8===@8=*/=**/*===9==8=8/*=*/*/((*/*/*/*/((.(.(.(...(.   ..  .   . .. .... . . .. ... . . . .. . . . ..../1......./.2/1//1/1/..1..1....1.1./1..1./1/1./1.1.1..0 1...1 .. .   .......1. .../../..//.. ./. ././//.///.//././/.///////(./*./(//*///*//*=/*/*/*/*//(/*/*=(.*//*//=*/*/=*===*=8=/8/=/8========@===@@=@G@G@G@GFGFG@GFGGFGFGGFGGGHGGHGGHGHGGHGGHGGGGGF..../.(..././..//./../../(./(//(///*=///=*===/8==*=/8/=*//8/8/8=8=8=8=8=8=9@8@@@CCCLCCCCC@@@C@CCCCLLCLLCLLLLLCLLLMLOMLMMMOMMOMMMOTMMMTMMTMTSTMTSTMTSTMTTMTMTMTTMOTMMOMVVTTMTTSTTMTMTTMOLGLOMTLOLOLOLF=/=/=/=/=/=////./..//.////././../.././................/....././..///.///////////////=///=///=/===============@@CCCLCLCCC@@=8=*==*==8===*=*//*=@=9@@8==8=*/***((/**/**/*/*.(( (( (.(.(..(  (  ..   ( ... .... ..... ... ... . . . .. .. .. .. ......../2///2//1/2///2/2/2//2/2.2..2.2./2/2./2/2/2//2/2//1//1. .1. 0 /1........ .1//1////. . .//2/2=/2/2=//..2=/..///=/==/==////////==/==/==///=/======@@=@@===========8=/8==@*==@=@/@==/=8=@@@=@@@@@@@@@@@@@@@@C@@CCCCGCGCOGOGOGOOOGGGGGGGGGGGGGGGGGGGGHGHGGHQGHGHGGHGG/../.../../.././././/./(./.*.//(//*///=*/==*===/=8/8/=*=*=**=8=8=@8@==9=9@@9@CCCCLLLLLCCCLCCCCCLLLLLMLMLMMLMMLOMLMMMLMOMOMMTMMOTMMTMTMTMTMTMTSSTSTMTMTSMTTMTMOTTMMOOMOMOSVTTMTVTTTMTMTTTMGLGLOMOOLOLOCO@F=/=2=/=/=/=///////./////////.///.///////.//././///./////././/.//.//.//.//./////=/===/=========@@=@=@@CCLCLLOLOLLC@@=@=8===*==8==*==*==8@@@@@@@@9==8=**/*.((*/**/8*/(((.((..(.(..(.(.(.  ( .... (. ( .. ....... ..... .......... . ..................../////2//2//2/2/2=/=2=2=2//2/2/2./22/2/2/2/2=2/2/2/2/22//1.1.1..1/2/2.2/1/ . /1//2///.... .///==2//==2=...==/../==2=2=======/=================/===@@@@@@@@@@@=====8=====8@@=@9@@@=@@===@@@@@C@@@@@@C@@CCCCCCCCCCGCGCLGLOOOOOOOOOOOOOOOOGOOOOGQGQGQGQQOQGQQGQGQGQGQGGG./.../../../././././././.*./(/./*///*=//=*==/8==/=*==*/8/=/8/8=8=8=*=8=8=8=8@@@9@CCCCCCCCCC@@CCCCCLLLLLLLLLLOMLLOMOMOMMOMMMMOMTMSTMTMTMTMTMTSTTSTSTTMTMTTMTTTMMOTTMOMOMOOMTVTTMTVTTTMTMTMOMOGLOLOOLOCOCGCCF=//////////////./../.../................../././././././././..././../../.././/////=/=/=/======@@@@CCGCGCCCCC@======8==8/8=*=/8==8===@@@@@@@9@@@@8=8=*(.*(/**/**/(((.((.(.(.(.(.(.(..( ( (   .... . . (.. ....... .. .. ... .. .. . . .. ...... .. . ....2///1//2.///2//2//2=2/2//1/1/1/./2/2/2/2/2/2//2//2./2.1. 1 .2.1...... //.2///.. ..../2/2/=/.2///. ./2/ //////=/==2////////=======/=/=*=/=8====@=@=@=====8===8=8=8=@@*=@=@@=@==*==@@@@@9@@@@@@@=C@@@@@@@@@@@CCGCGCOGGOGOGOGGGGGGGGGGGGGGGGGGGGGGHGGGHGGHGHGGHGG.../.(/.../.../...//././/././*./(////*/=/=*==/=8=/=*/8//8/8/8=/8/8==8/8=8*=8*=8=8=9=9@8@=9@@C@@CCCCCCCCCCCLCLLLLLLMMMMMTMOMTMMMTSMTSTMTSTSTTSTTSTTSTTMTMTTMTTTTMMOMTOMOMOMOMTTSTTTVTTTOMOTTLMOGLOLOLGCOCGCCG@@=//////////////./...........................................././///.//////=/==/=/=/====@@C@CCGCCCCC@@@====@===8===8=/8==8====@@C@@@@@@@@@@@@@8=*/*(*.**.**((.(((.((((.(.(.(./(.(.(. ( ( ( .(. (. (. (. ............. ... ...... ... . .. . .. . . .. .........1......2/./1/1..1..1.1..1.2.2.2/..1.1.1.1.1..0. 0 .0...1...   .1...... ..././....//. .... .//.././///../.././//////*/(//(/*//*/=*=*=/*=*/*/**.*.*/(*=*.*=*=*/=*.*.8=*=8/=8/8=8==8====@==@==@=@=@@F@F@G@G@GF@G@GFGG@GFGGGGHGHGHGHGGHGHGHGHGGHGHGH...(..../.../../..././/.//*.//*./*//=/=*//=*==8/==*=/*=*=/8/=8=8=/8=8==*=8==8/8/8=8==8=9=@@C@@CC@CCCCCCLCLCLCLLMOMLMMOMMMTMMTMTSTSTSTSTMTSTMTMTSTSTSTMTMTMTMTTMTOMOLTOMOMOLOLTTVTSTTTTTTMOMOTLOOLGLGLGLGCGCCGC@F=///././//.//////./............... .. ... ...//.////////=//=//=/=//=/=/=/=/========@@@CGCGCC@@F==============8===8==8==@9@CC@@@C@C@@C@@@@@@8=**/**(/(*(.(**.*((.(.((.(.*.*..(.(..(. ( .. (..(. .... .............. ...... ... ... ... ... .. . . . .. . .. .1. ....1..2.2./1/..1..1.1..1...2.1/1.1.1...1.1 . 0 0..1 .. .    .. ....  .. /......... ... .........../..(...///////.*./(/.*/*/*//*///*//*/(.*.*(.*.*/*(=*//*///(.(/*=/8/*=*=/8/*/=8===========F@F@F@FF@GFGF@GFG@GFGFGGFGGGGFGGGGHGGHGHGHGGHGHGFG../../(.../.././././../././*//.*////*=/=*=/=*=/=8/=*=/*=/8=*==8/8=8=8=*=8=8=8==8=8=@9=@@9@@@@C@CCCCCCLCCLCLLCLLMLMOMMMMTMMOMTMTSTSSTSTSTTSTTSTTSTTSTTSTMTMTMTTTMTMOMOMOLOLOMOOLOTTSTTTMTTTOMOMOMOOLGCCGLCGCGCGCCG@==//...///.//////./......... ........ ..... ......///.//./////////////////=/====@=@@@@=============@=======8====8=@@@CCC@C@C@@@@C@@@C@@9=8/8/*/**(.((.(/(*.((.(((.(.*./(.*.(.(...( ( .(..(..(. ....( ............... .......... ... .. .. ... . . . ...........1././/1//2./2.1.1..1.1./1/1/.2./1/..1.1..1 1 0.1... 1..   ........ . ...././1.../.. ... ../././/././...../////////*///*.*///*//*=*=*=*/*/**/*.**/(==*//*/8/=*=.**==*==8==8===8========@=@=@=@=@@F@F@F@F@FGF@G@GFG@GFGGGGGGFGGFGGHGHGHFGHGHGGFGF...(.../..../../././././.*/.////*/=/=/=/=*==/==/=*=/8=/*=/8==8/8==8=8==8=8@=@9@CC@CCCCCCCCC@CCCCCLLLLLMLMMMMLMMOMLMLMMMMOMTMMTSTMTSVTSTSTTSTSTSTTSTMTTSTMTTMTTMTMOTMOLOLOMOLOMOLOLTTTTTMTTMTOMOOOLOLOCCGCCGC@G@G@G@G@=///..././//.///////......................../..../../././/.//////////////=/=========================@===@=8@=@@@CCC@CCCC@C@C@@C@C@9==8/8=8*/*.((.(*((/(*.(((.((.(.*/*./*.(.(.(..(...(............././.......................... ................/../././2/2.//2/2/=2/=2/2/2/.2..2.2/2//2=2/2/2/2/2/2/.1.1.0..2.2.1/.2. 2/1/2/2. .......2=2//./2//. .//.. //=////=/////=////=/========/========@=@=@=@=@=@=8===8/==8=@=8@=@=@@=@//8@=@@@@@@@@@@@@@@CCCCCCCC@CCGCGCGGGOGGGOGGOGGGGOGOGOGGGGGGGGGGGGGGGHGHGHGGHGGGG.(..(/../..(..../.....*././/(////=/*==/=/=*==*==/==*=/8=8=/8==8=8==8==9==@9@@CCCLCCLCCLLCLCLCCLLLLLMMTMTMTMTSTMTMMMMMOMTMMMTMMTSTSTSTSTTSTTSTTSTSTTTSTTSTTMTTTMTMTOMMOMOLOLOLOLOLOLGMTTTMTOTMTOMOOLOCOCCGCCGCGCCGCG@G@G===/////.//////////////////////./../..//./././..../././/.////////////=/==/=================@@@=@@@@@@@@@@@C@CCCCCCCC@CC@C@C@C@@=8=8=8==8/*((((*.(/(*(/(/(.(.(/(/(/(/*./(/(.(..(.(...(..(.......(..././././........./././............../../..../././/2/.2/////2/2/=2=F/F/F/2=2/2/1/2/2=2=2=2=2=2/2//2/2./2.1.1./2/2.2/2. . ...../2//2//.....././=2=//./=2/...//...=/=/==/===///=/=/=====@=@=========@@@@@@@@@@@@@@@@====8===C@8@@@@@@@@@8==@@C@@C@C@@CCC@CCCLCCLCCCLCCGCGLGLGOOOOOOOOOOOOOOOOOQOOOOOOGGOGQGQGGGGGGQGQGQGG..(/../.././../..././(..(..////*///=/8/=*==/=/8/=/8=*=/8/8==8==8=8==8=8=8==9@@:C@CCCCCCCCCCCCC@CCLLLOLMMMMMMMMMMOMOMMMMTMTMTMTSTTSSTVTSTTSTTSTTSTTSTSTMTTMTTMTTTMTMOTOLOLOLOLOOLOLOLGLOOMTTMOTMOMOOOLGCGCFC@G@G@@@@G@F@F=F=/////././/.//.///.////////././................. ......././//.//./////=/=============@===@@@CC@@C@@@@CCCCCCCCCCCCC@CC@CC@=8=8=8==8=8**/*/(.((*(/(**(/(*/(*.*./*/(/*/.*.(.(..(.(...(..(...(.. .../././/.............../............................//.//1/2.///2/2/2=2=/=2//2.2/.2./2/2/2=2/2/2/2.2/1.1... .1/.2./1/.1 . .2///2//2. /...../2//2/.2=/.. /// ..//=////////////////===================8@@@@8@@@@8===8==8==@9=@@@@=@@@=/8=@9@@@@@@@@@@@9@CCCCCCCCCCGCCCGCGCGGCGGCGGGOGGGOGGOGOGGGGGGGGGGGGHGGHGHGHGGHGGH..(...(/......(/../...(/.(/./*.//=/*//=/=*=/8=/8=/==*===8/8==8==8=8=8=8==8=8@==8=9=9@@8@=@@@@C@CCCCLCLLLOLLOMOMLMMMLMTMMTMMTSTMTSTSSTVTSTSTSTMTTSTSTTTTMTTMTTTSTTMTOMOMOLOLOLOLGLOLOCGLCOOOTMTOTOOOLOGCCG@G@@@@G@G@@F@@F@=F===////.../......//////////././../../.../............////.///.//./////==/==========@@@@CCCC@C@@@@@CCCCCCCCCCCC@CCC@C@@8===8=8=8==8=***/**(*.*(*.*/*/(/*.*.*.*.*//*/*/(/..(.(..(.(..(..(....(..../././/./.......././././............/../.... ... .... ......1..2/2.2/1/2/2....1..1..1/2/1/2.2..1/.1...0 1 1.1....1. ........ . . /........ ... ......././....(..././(/////*///*//*/*/*/8/*=8/8/8/**/*/(/(/8=*==*=8/8//*.*==*=8=8==8=8======@=@@==@@@=@@@F@@F@F@F@F@F@G@FG@GFGGFGFGFGFFGFGFGHGFGHGHGGHGF..(./.(/././../../../.(...(/.///*//=/=*/=/8/=/=/8=/==*===8===8==8==8=8=8=9=@8@@8@=9=@=8==9=@@@CCCCCLCLLLLMLMOMMMMMOMMMMTMMTMTTSSTSTSTTSTSTTTSTTSTTTTSTTTSTTSTTTMTTMTLOLOLOLOLOLOOLGLOCGLGCOCOOTOMOOOLGGCCG@@G@G@@G@@@F@@F@=F=====///./../.....././///////.//./..//../.........//.////////.//.////=========@@@C@CCG@@@@@@@@@C@CCCCCCCCCCCCCCC@C==8==8==8=8=8=8/8/***/*(/*.**.**/*/**/*/*/*.*/*./*/*/(/.*.(..(..(...(....(../././//../...../..//./././......../.......... .. .. ......1...1../1//2./1.1.1..1.1.1...2./.2.1./1..0.1 0 .1..0....  .1...1.... ..... .... ..  .../.......(......(..(/./*./*//*/.*.*/*/*/*/*/*//**/(*.(*.8/*/=*/*=*/*(/(/8/=*=8/=*=/8==8=====@=@=@=@@F@=F@F@F@F@F@F@FG@GFGG@GFG@GFGFGFGFGFGFGFFGFHGFGF..(...(./././../../(...*..*./.*////*//=/*=/=8/==/8=====8==8===8==8=8==8@8==9=@=9@@@@@@@@@=9@@@@CCCCLCLLLLMOMMLMMTMMMMOMMTSTSTSTSTSVTSTTSTSTSTSTTMTTTTSTTTTTTSTTTMTMOTLMOOLOLOCOLOCOCLGLGCGCGCOLOOOLOOLGCG@G@@G@@G@F@F@F@F===F=F=F==////...././../.././.../..../././../......././/./////.//.////=/====@=C@@C@CG@@@@@@==@@@CCCCCCCCCCCCCCCCC@@=@==8==8=*==8=*=**/**/**/*(**.***/*/*/*/*/*//*/*//*/*/./*./(/(./(/./(..(....././././///../.......//.//............././....... ... ........../1/2.2/.2//2.2..1.....1/2/1/2./.1/1.1...1 ..1.1..1.1 .//1/... .1 ..... .... .. .//.././../.....(../*.//*./*//////8/*/*/*=8/8==8*=***/**/(/8=/8/==8=*=*/*=8===8===8===8====@=@@@@@@@@@@@F@F@F@@F@F@F@F@F@GFG@GFGFGFG@GFGFGFGFGFFGHFGFGFG..(./(..(/././/./.(..*..(..(/./.*///=*/=/*/=/==*=/=8=====8==8/=8/===8==8=@9=@@CCCCLLLLLCCCC@@C@CCCLLLOLMMMMMMTMMMMTMMTMTMTSTSTSTSTTSTSTTSTTSTTSTTTSTTTSTSTTTTSTTMTMTMOMOLOLOLOLGLOLGLGCOGCOCGCGCGLGLGCGCGC@G@@G@F@G@@F@F=F@F===F=@F@F=////./././///././/..././././//..../......//./////////.////==F@FC@G@@@@@=@=====@@@CCCCCCCCCCCCCCCCC@@8=9=8==8=8==*=**=**=*8*8/**/*.***/**/*/*/*/*/*/*/*/*//*/*//(//.*.*./(/./.*../..././///.///././../..//1///............//1//./.../../././2//2/2/2/2/=/2=2/2///2//1/1/2/2/2=2/2/2/2/2/1/1.1.1.2//1/.2/ . .. .2/2/=2=/ .//.. ..///2..///.. ///.../=/=///=////////.////=//=/=====@=@====@=@=@@@=@@@@==8==8=8=@@@@@@@@@@@=*=@@@@@@@C@@@@@@@@C@CCCCCCCCCCLCCCOGGCGGGGCGGGGGGGGGGGGGGGGGGGGGGGFGGFGFGFGFGGFGG..(...(..(././././//..(/.(./.*.//(////=*=/8/=/=/8=====8/==8==8==8==@=@9@=@9@@CCCLLMLLLLMLLLCCCCCCLLLMLMMTTSSTSSTSTSTSTMMTMSVTSVTSTSTTTSTTMTTSTSTSTTTSTTTVTSTTTMTTMOTMOMOMOOLOLGLGLGLGOCOCGCGGCGCGGCG@@@F@F@@G@G@CG@G@@@@@F@@F@@@F@F@@F@=F=====/////////.//././/.////.///.././/.///////////////==F@=@@F==========@@@CCCCCCCCCCCCCCCCCC@9=@8@@=9@=@8==8=8*=**/8**=***/****/**/*=*8/8//*/**/*/*//*////*///*.//(//.//*././../././////////./../.././/.2///........//1////////2.//2/2///2//2/2/2=2=2=2===F/2/2/2/2/.2/2=2=2=2=2/2=.2..1.1.2/2/2/2/2 ..1 .../2=2=/2/.1/......2///../=/...///...=/=========//////=/==/=======@=@@@@@@@@@@@@@@C@@9C@@@9=@8=C@C@CC@C@C@@==@CC@CCCCCCCCCCCCCCCCCLCCLOCLOLOLOLOOOOOOOOGOGOOGOGOGOOGOOGOGOGOGOQGGOGGGGGGGGGGG..*..(...(./././/.*.//..(/.(../(//*/////8/=/==*====*=====8=/=8===8=8===9==9@@9@CLLLLLLLLLCCCC@C@CCCCLLLOLMMMMTMTMTMTMMTMTSTSTVMTVTSTSTTSTSTSTTTVTVTSTTSTTTTSTTTMTMTMOTMOOLOLOLOLGOCOCOCOCGOCGCGGCGCGCF@F@=F==F=F@@@@F@FF==F==F=F=F=F==F==2====/==////./.........../...........././/.////////=///=/==/=========@@CGLCCLCCCCCCCCCC@C9@=@8@@=9=@8@@@@9@=8/**/*8*=8/*=***/*/*/*/8*=8=/8=*=*//*/(/*//*//=/*//*.//(//*.///../././//////////./.../.././///././..../.../././.2./.../././2/2///////2/2=2/=2=2/=2/2/2/2./2/2/2/2/2/2/1./2..1..2/2//2/2.. . .1 ./2=/2=2../2 . . //2// .//. . /...../=/=/=/=////////////=///*=/=/===@=@===@8=@=@9=@@@9=9=@8=8=@@@@@@@@@@@@8==@@C@C@C@@@@C@@@C@@CC@CCCCCCCCCGLGLGOGGOGCGCGGCGGGGGGGGGGGGGGGGGGGGGGFGFGF@FFGFG..(...(..(..*././/.*/.//./(././.*./*//=//8==/===8=====*===/8==8===8==@8@=@8@=@9@@@9CCC@@@C@@@@@C@CCCCLLLLLMMOMMTMMTMTSMTSTSTSTVSTTTSTTSTTSTTSVTSVTVTVTTMTTTTMTTMTMOTMOMOMOOLOLOOLGLGCGGCGLGCGCGCGGCG@G@@F=F=====F=F=@F@@F==F=F==F===F==2==2=2==2==F===/=/////././/././.../../.././///////////////=/==2====F@@CCGCLGLGCCCCC@C@@@=9=@@@9@@9=@9@@@C@C@8=8/*=*=8*/*8**=*8/8***/8/8/8=8/=8/*/*/*//*/=*=////*//*//.*/////*/././/.////////////./.././/.///2//.../..././.1/............././.1..1..././.2/2./2./1....1 1.1/1/2/1/./1.1.1. 1.1//1/1/. 0 /..2./. .. /.... .. ..  ../././////....(.(./(.(.*.(./(/*//8/=*/8/*=*/8/**/*=**/**/*=8==8=8==8==(/8=8==8==8@==8====8===@===@=@@@@@@F@G@FC@F@F@F@F@F@F@F@F@GFGFGHGHGFGHGFGFFFF@F@F@..(..(...(...(//.*/.//.*/..(./(/.*/.*//=/=/==/===8/=====8/=8==8==8===8@=9@=@@@9@@@@9@@@C@@@@@C@@@C@CLCLLLOMLMMTMTSMTMTSTSTSVTSTTVSTTSTSTSTSTTSTVTVTSVTSTTMTMTTMTMTMTMOTOMOMOOLOLOOCOCGCGCGCGGCGGCGGC@G@G@@@F===2===2===2=F==F=2==F=2=F==F==/==2==2==2==/==/===/==/==/////////.////.//////.////=/=/===@F@@G@CCGCCCGCCCC@@@@@==9=@@9=@@@9=@8@@9C9C@9@=8=8*8*=**8/8/8*=***/*8/*=*=8==8=/8/*/*/*//*=/=*==////*//*///*///////.///////=//////././././/.////2//.../../.././/.........1...1./..../.1.2./1/2.2.1./1.1 ..1...1../1.1.. 1.0 1.1.1./1.0 0 1.2/.... ...  ../. ... . ......././../.(...(...(.(..(.(.(/*///*//*/*/*/*/**/**/*(*((/8/8/=*=*=/*/(==8===8==8===8=8===8====8===@=@@@F@FG@FGF@FG=FGF@FF@FGFGFGFGGFGGGHGF@FF@FF@FF@FF..(...(./(..(..//./*.////.//.(.*..*////*=/====/===8=/=8====/8/=8==8==@8@@8@@9@@@@9@@CCCCC@C@@C@C@CCCCLCLLMLMMMMTSTSSTSTSTSTTSTVSTVSTTSTTSTTVTVTSVTVVTSTTTMTMTMTMTMOTMTLOMOOLOLOLOLOGLGGCGCG@GG@GGCG@G@F@@F@F@F===2==2=2=//2/===F=2==F=2=2=F/===/===2==/=2==2=/==2==2===/==///=////=/////=/=/==F@@F@G@G@G@@@F@=@=@@@@@@@@===@=@8@@@9@@8@9@C:C@CC9@@9@88=8/**/***=*8=*8=*8/**8/8=8=8=8=8=/8//*//=*===/=*=///*//////////////./////=//=//////./././//.///////././../..././..2...1../.2./.2..2.././.2//2//2/1..1. 1./1.2.2.2.2/1.1...0...2/2.2/1. ././1/. ... ..... ... .././/./////..(..(././(.(.(.(/.*//8/=*==*=/*/8/8/**/**/*/**==8=8=8==8=**/8======8===8====8===@===@=@@@@@@G@G@@G@FCF@FG@FF@FF@FFGFGFGGGGFGGFGFGFFF@FF@F=F@. (..(...(...(..*/.//.*/.*////(//.*///=/==*=/===/8/==/=8/=8==8==8===8=@=@9@@@@@@CCLLLMLMLLLLCCC@C@CCCLLCLLOLMMTMSSTSTSTSVTSTVTSTVTSVTVSTTSVTSTVTTVTSVTTTTTMTMOTMOTMTOMOTOMOOLOLOOLOOLGCGGCGG@G@G@GCG@G@G@F@F@=F=F==2==/2=///2/2/=/=2==F==2=2=2=/F/==/=2==/===2=/====/==/=/==/=/===2==F===F=@@F@@F@@=F==========@=@=@@@=@=@=@@=@@9=@@CCCC@C9C@9@@9@@9@8=8**=*8/88=88=*8=*8/8*=8/=8=8==8==*//8/=/=8===/=//8////*/=/=//////////////=//////////.//.///////////.2./././2/.2//./1/.//2//2/2/=2/2=2/2=/2=/2=/2=2//1..2/2//2/2/2//.1/2.1.1.2/2=2=2=2.1.. .1.2/2=/2/..//.. ./2//2..//. . .. . //////=/==/=///=//=/=///////=/*=/=====@@@@@=@@@=@8@=8==8=8=@9@@@@@C@@@@8==@@CC@@C@CCCCCCCCCCCCCCCCCCCCCCCOCGCOGGOOOGOGGGOGOGGGOGGGGGOGGOGGGGGGGG@GF@F@F@F@. (. .(..(..(./.(/.//.*//.*/.*//*/./*///=/=8==/==/8=/===8==8==8==8==@8@@@9@@@@CCCLLLMTMTMMMLLLLCCCCCCLLLLMMMMTSVVVUVVVSVTSTVTSTVTSVTVTTVSTTVSVTVSTVTTSTTTTTMTMTOMTOMOMOMOOMOLOLOLOLOOLOGCGG@GCGCF@G@GG@G@G@F@F@F@F=F=F=/2=2=/2/2/2/=2/=2==F=F====F===F===F=======F===F==2==2==2==2====F=====2==/==/=====F====@====@=@@=@@=@=@@8@@CCCCCCC9@@9@@8@8@9=8=8=8/8*8=*=8=8/8=8=*8/8=8=8=8=8==8==8//8/==/=8==/=///*////*/=/==/////////=//=/=////////.///./////////////.2////2/2/2//2/2/2=2=2==2==2=2=/F/=2==2F=/2/1.1/2//22/2/2=22//2/1..1=2=F/F=2=1.1.1.../2==2=2/.1//... ./=/=/.///. .......///=/=========/==========/=/8/====@=9@@@C@@@@@@@@@@@9@=@9@=C@@C@CCCCCCC=8@CCCCCCCCCCCCCLCCLCCLCCLCCLCLLOLLOLOOOOOOMOOOOOOOOOOOOOOOOOOOOOOOOOGGOGGG@GGGCGG@. (...(..*..(...(/./.*/.*///*.//*///=*/=/=/=8=/=/=8/=*==8==8==8===9=@=@@@9@@@@@CCCLLLMLMOLLLCCCCCCCCCLGLLOLMOMMSTVSVSVTSTVTSTVTSTVTVVSVVSVTVTSVTVTSTTVTTMTTMOTMOMOMOMOOMOOLOLOLGOLGLOGOGCGCG@G@GG@G@@G@G@F@F@==F===2=2=/2=2/////////////.//./2//=/=2=/=2==2=2=2=/=2=/=2==/=/2///////////2/=/===/==2============@==@=@@=@=@=@@CCCCCCCC@@9@8@8=9=9=9=9=8=88=8/8=8=8=8=88/88*8/8==8=8=8===8====8/=====8=/=////*/=/=/=/=/=/////////=/=/=//=//////////////=2////./././././//.2/./.2///2/2=/2=/2/2=2/2=2/=/2=/2...1/1//2//2/2=.1/.1.1.1/=22=2=2/.1... 1.2/2=2/=1.//1. . ./2/2../// .... ../////////=///////=/==/=///8//*/*/===8==@@@@8@@@@8==8=8=8=8=C9@@@@9@@@@9==9@@@@@@@CCCCCCCCCCCCCCCCCCCCCCCGCCGCGLGOOGOGLGOCGOGGOGGGGGOGOGGGGGGGGG@GF@G@@G@@F..(...(..(/.(/..(.(/.*/.*/./*//*////=*=/=*=/=8/==/8/==*====8===8@==@@8@@@@@@@@@@@@@CCCCCCCCCCCCCCCCLCLCLLMOMTMTSSVSVTVTSTSTVTSVTVTVVVSVTVSVTVTSTTTSTTTTTTMTTMOTOMOMOTOLOMOOLOLOCOOCOOCOGGCGG@G@GGCG@FG@F@@@FF=F=F==2=2=/2/2/2/2//.2//1///.2///././///////=/=/=/////2/////.//.//././///=//=/=/==2====F=F=@=@=@========@=@@CCCCCCCCC@9@8=88=8=88@8@8@9=8=8=8=88=8=8=8=88=8=8=8==9=@@8=====8======8=====/=*/=///*=/====/=//////=////=/=//////////.////////////2/./1//1/2.//.2.../1/.//1//1//././2/./2/2/1.. .1..1..1.1//1.1.1... .2/2/2/2/1.. .2/1/2..... /./.. ..   ....//.//.//..*..(//.*/(/.((.(.(/(*/*/*/*=*/*=*/8/**/**/***==8=8=8=8=8=(*=8==8=8==8==8=@==9=@=@8@=@@@@=@@@@@@FCF@G@G@F@FG@GFG@G@G@GFGFGFGF@FG@FF@F@F@F=F@= ..(.(...(..(..*..(./(//*///(///8///=/=*==/==/8=/==/=8===8====8=@=@@@@=@@@@@9@@@@C@C@CCCCCCCCCCCLCOCLLOLOMMMTMTSTVSVVSVTVSTVTVSVVTVSVVVSVTVSTVTVTSVTTSTTTTMTTMOMOTOMOMOOLOLOGLOGLGOCGOGLGGCG@G@GF@GGC@F@FF@F=F=F===2=2=/2=///.2/.///.//2//././././././//.//./././/.//.2//.//.///./////=//=/=2==/=========@=========@@CCCCCCCCC@@9=8=89=889=9@8@9@9=9@=8=88=8=88=88=8=8/8/8=8@=9=@=@9==============8====//=*=//==/===/==//=////=//=/===//////////=//=/2=//2//.//.//2//1//2.2./.2/1//.2./1/1/./.2././1/1. 0 .1 1.1.1.1.1..1..0.0.2./1/2.1. .0. 0.1/2.//. ...  ..... ...   ....../../.....(..(/...(.(.(.(.(.(/(/(/*/*/*/*/*/**.*(**.*/8*=*/8/8/8=**/*=8/=/8==8===8===8@=@=@===@=@==@=@@F@@F@F@FG@FG@FG@GFGFGFG@GFG@FGFGF@FG@F@=F@==@=....(.(/././(.(.(.(.*.//*./*////*=/=*==/=8/=/=8=/=8/==8===@8=@=@8@=@@9@@@@@@@@@@@@CC@CCCCCCCLCLCLLCLLLLLMOMTMTSTSVTVVVSVVTSVTVTVSVVVVTVVSVTVTSTTVTTSTTTTTTMOTOTLOMOOOLOLOLOCOCOGLGOCOGCGCGGG@GFCF@G@GG@F@F=F=F=F=F==2/2=2/2//./.2/./2//.//2./..//.//.///.2//.2././2//.//////.///////2/=/=/=/=/=2====F=@F=@======@@@CCC@CC@@@@8=8=88=888=98@8@99=9@9=9=9=8=88=8=8=8=8=8=8=8=8@@8@=@=@9@=@==@==@=======/=*=//=/=======/==////=///=/=/=/=/=////////=/2=///2////.2/2///2//2/2.2/1/.//1///2.//1/2/./2/2/... ...1.1.1./2/.1./1. 1../2//2/2..1 . . ./1/2./. 2.. ../.. ... .  ....//.//././..(././(///.*/.(..(.*/*.*/*/*/*/8/*/*/***/***/8==8=8=8=8=8=**===8==8===8===@=@@=@9@@@@@@@@@@=@@@@FG@FG@G@GF@FCFGFCFG@GFGFGFF@F@F@F@F@F@F@====@ (..(..(.*..(.(..(.(/.*.//*//*//*//*/==/8=/==*==/8==8/==8===9==@=@@8@@@C@@@@@C@CCLLLLLMLLMLLLCLCOCLLOLLOLMMTMTSTTSVVSVVVVVSVTVSVVTVVSVVVVTVSTVTSVTTVTVTSTTTTMTMOTOLOMOLOLOCOCOGLGOCOGGCGGCGCGG@GG@GFG@F@G@F@F===F=/F/F=/2/2//1/2././/.////.//.//.//.////2///.///.2////2./2///1//2/////=/2/=/=/=/=========@===@=@@=@@@@@@@@8@@=9=8=@88@8@8@89@9@99=9=9@8@8=8=8=88=8=88=88=8=8=@8@@@8@@@@@==@===@=@========/=/==/=/===/==/==////=/=/=====////////=//=//==////2/////2/2/2//2//2//2/2=/2=2==2=/2=2=2=2/=2.1..2.2./.2/2//2./2/1.1.2/2=2=2==1...1.1.1/2=/2=2../2/. ./2//.../. ... . ..///=/=/==/=///////=/=/=/=//=/*=/=8/8==8====8==@=@@==8==8==8@@C@@@@@@@@@8=8@@@@@@@@CC@CC@CCCCCCCCCCCCCCCCCCCGLOCGOCOGOGOGOGOCOGOGGOGGGGCGGGGG@GGGGGCG@@@C@@@ ( .( (./(.*./(.(/(..(.*.*./*//*//*//8//8/==*=/=*===/8====8@==8@=@=@@8@@@C@C@C@CLCLLLMMMMMMMOMLOLLLLLLLOMMOMTSVTVVVVVVSVVVVVVSVTVTVVSVVVTVSVVTSVTTTSTTTTTTTTTTMOTMOTOLOLOOCOCOCGLGCOGOCOGCGG@GG@G@G@G@FGF@FGF@F@F=F=F==2F=//2///./2/2///2/2//2//.//////2////2//2/////2///2//2///2/.///=2/=/=/=/=/=/=2==@=@=@@@@=@======@8@@=@8=@8=88@8=98=9=98@9=99@8@9=9=8=8=8=88=8=88=88=8@=9=@@@@@@=@@@@==@==@=@=@======/=/=/=========/=/=//=/==/==/==/=//////=2/==2==2=//2/2/2/=/==2==2=/2=2==2==2==F/F==2=====2=2...2/2/2/2///22/2/2//2/.2=F2=FF=2.2/1.....==2==2=/2=/.... ////...//.........////========/=/=/==/=====/==/==/=====8==@@9=@@@@9@C@@=9==9==CC@CCCCCCCCC=9@CCC@CCCCCCCCCCCCCLCLCLLLLLLLLLLOLOLOOLOOOOOOOOOOOOOOOOOOOOOGOCGCGGGGCGGCGLGCCCGC@.. (.(.(/.(/.(.(..(.(/.*/./*///*//8//8/====/8=/=8=/====8==8===@8@=@@@@@C@C@@C@@CCCLCLLOLOMOMLCLCLLOCOLLOMMMTMTSTSVTVSVVVVVVVVVVSVTVTVVSVVSVTVVTVSVTVTVSTVTTTTMTOMOMOOLOLOLGLGGCGLGGLGGCGCGCGG@GG@GG@G@@F@FF=F=FF=F=2F=2=2=2/2/1/./1/.2/./.2././../1//.//2/.//.//.2.///////2//2/////////=/=////=/=2======F=@===========@=@8@@=9=88=88=9=9@8@8@8@8=89=8@8@888=888=*=88=8=@8@=8=@9@@@@@@@@@=@=8=@==@=@=@======/===/=========/=/=//==/====/=///////=/=/=2==2=2=/=2/2=2/2=2/2/=2/2//2=2/2=2=2=/2=/=2=2=2=....2//2.2.2.2/2./1/2/.2.2=2=2=F2=1/1..1.1/2/=2/=1./2=1 . ../2/..... .... .. /////=2====/////////=/////*/=//8/=8===8=8==*=8==@==8=8=8=8=8@@C9@@@@9@@@8=@@@@@@@@@@@CCCCCC@CCCCCCCCCLCCCCCCCGLOCGLGOGOCOCGOGGLOGOGCGCGCGGCG@GCGCGCCGC@C@@@@ ...(../(.(.*.((.(/(/.*/.*.//*/*///*=/8==/=/=8/===8/==8==@8==@=@9=@@@@@C@C@C@C@C@CCCCCCCLCLOCLLLLLLLMOMOMMTTTSTTVTVVSVVVVVVVVVVSVVTVTVSVVVSVVTVTVTSTVTTSTTTTMTOMOMOOLOLGOCGCGCGOCGLGOCGGCG@G@GG@G@GFG@FF@FF==F=2=F=2==2//2//.2/./.2//1//./../././/.///.//.2/.2//1/2/2/2//////////2/=////=/=///=/=/=====@==@========8=@@=@8==8=88=888@89@8@8@88@88@88@8=988=88=88=8=8@8=8@=9@=@@@@@@@@@@@=@==@=@@@=@=@=====/=/==========/=//=/=========/=/=/=////===/F=/==2/=/=2/=2/=2=2/2//2//1//////.////2//1///1.. .1........1.1.2..1..1/2.2/2/2. 1. . .2/2./2/ ./1/ ./.. .  ... //.//.///../..(./(./(.(/(.(./(/*.*.*/*/*.*/*/*==*/**/**(/88=8=8=8=8=8**=8=8=8=8=8==8===8@===9@@@@@@@=@@@@@@@@G@@G@G@GF@F@@F@F@F@G@FG@F@F@F@F@F@@@@@@=@=@=. ( (.(/.(..(.(.(.(/(/(///(//(//*//8/=/=8===*===*====8==8====8@=@@@@@@C@@CCCCCCCC@CCCCCLCCOCLLLOLLOLOMOMMTMTMTSTTSVTVVVVVVVVVVVVVSVVTVSVVTVTVVVSVTVTVTSTTTTTTTOTOMOOOOLOGCGCGCGCGGCGGCGGCG@GG@G@G@GFG@GFGF@F=F=F=2==2=2=2//2//.2.2.//1//1//./..././/.2/./2/.//./2///////=/2//2./2////2=/=/////=///=/======@=====/=====8@=@=98=8=*8=8=9@8@98=88=88=8@8898=888=88=8=8=9=9@8@=@9@@@@@@@@@@@@==@@=@@=@@@@========/===========/=/=/=========//=///=/=2=2====2=2=/2/2/2/=2==2/=/2///2//2/2/.2/././2./.2... ...2.1.1 .1...1.1.1.0./2..2/2/0..1 . ..2./.// .2.. .....    .. ./././/./...(...(..(..(.(..(.(.*.*.(/((/(/**/*=*/**/((/(/*/*=*=*=*=*/*(=8/8=8===8===8===8====8===@=@===@=@@F@@F@G@F@FG@@F@GF@G@F@GF@F@F@@F@@F@@@=@@@@=@=@ ( ((..(.(/(/((.(.(.(.*/(/*.*.*.*//*//=8=/====*=====8===8===9==@=9=@@@@@C@CCCC@CCCCCCCCCCLCLCLLLLLOLLLMLMMOTMTTSTVTVVSVVVVVVVVVVVVVSVVVTVSVVVVSVVVTVSTTTTSTTTMTTMOTOMOOLOLGLGCGGCGCGGCGCG@GG@G@G@GFGG@GFG@FF@FF=2=F2==2=2=2/2/1/././2/./2./2.././.1/././/.//.2/1/./2/2/2/2///2//.//.///////=////////=/============/=8===@8@=8=8=8/88=89=98@9=988=88@8=8=88=888=8888@@8@9=@9@=@9@@@@@@C@@@@@@=@@@=@@@@@@@====/===============/=/==========//=//=/====F=2===/=2=/=/2=2=2==2=2/2/2//////2/.//2.///2//.. . .2/.1....1..1 .2.1.1.1//1/2=2/.1... 1 2//1/1/ /./. ..... .   .. .//.//////./../././/(.(..(.(.(/*./*/(*/*/(*//*/=8/**/***(=88/8=8=8=8=(/*=8==8=8===8===8====@==@8@@@=@@@@@@@@@@G@G@GG@G@FF@F@@F@FG@@G@@F@F@@F@@@F@@@@=@=@=@( (.(.(.(.(/(.(.((.(.*.*/.*/*./*.*//8//==8======8/====8===8===8=@=@@9@@@C@CCCCCCCLCLLLLLMOMLOLCOLLLLOMOMOMTTSTSVTSVTVVVVVVVVVVVVVVVVVVSVVVVSVVVTVSVTVTVSTTTTTTMTOTOMOOOLOGLGCGCGGCGG@GGGGC@GG@G@GFCGFGFCFF@FFF=FF==F/F/F/2=2/2/1/1//.2/.//1//2./2///2//2//2/2/2/2/2///2/2//2////./2/////2=/////////=/=/========/=/===8===@8==8=8/8*=888@8@8@8=8=898=8888=88=888=8@8@8@9=@9@@@@@@@C@C@@@@@@@@@@@@@@@@@@@@=8====/=====@========/============//=/2==2===F=F=F/=//2/2=2=2=2==2==2=/2=2=2=/==2=/=2==2=2/....2=2=/2/2./2..2/.2../2/2/2=F=F.2.2.1...2/2=/2=.1/2/ .. .2/// .. .. . . (./..//==/====/=/=/=/==/=///=////*=/==*===/=8==8==@=C===8@=8=*@@@@@@@@@@@@8=9@@@@CC@C@@C@@C@CC@CCCCCCCCCCCCCCCCGLOCLOLOOGOGOGOGCGGCGOCGGCGGCGCG@G@GCC@CCC@@C@@@( ( (..(.(/(.(.(.((.(.*.*//(/*/(//*//8/=*====8==/==8===8====9==@=8@@@@@@CC@CCCLCLLLLMMMTMMTMMMOLLOLMOLMMTTSTVVVVVVVXVVVVVVVVVVVVVVVVVVVVSVVVVSVVTVVVSVTTTTTMTTTOTTOTOMOOLGLGGCGCG@GCGG@G@G@GFCFG@GFGG@GG@GFF@FF=FF=F=2F/2=2///2/./2.//2/2//.2./././///=/2=/==2=/=2=2==/F/=2///2/2//////////=//=//////=//=/==/==/==/8===8@=8=88=88/888=8=9=98@8@88=899=888=88=88=88=9@9@9=@9@@@@@@@@@C@@C@@@@@@@=@@@@@@@@=@==================/===============/==/===F==F==F=2=/=2=2===2=F==F==2==2===F/F/==F==F/F=/2..1/===2=2//2//1/.2//2/2/2/2=FFF=2/2/1.2..===2==2.=2//...../2//.... ... ..../...==/===F===/============///8/=/=8======8====@8@@C@@@@9==8@@@9@@C@CC@C@==CC@CCCCCCCCCCCCCCCCCCCCCLCCCLCLCLLOLOLOMOLMOLOOOOOOOLOOLOCOOLOLGOGGOGLGOCOCCLCCCGLC( ( (.(.((.*.((.(.(.*.*/(/*//*/(/*/*/=/=8======8=====8===8==@8==@@=9@@C@CCCCCCLCLCLLOMLMOMOLOLLLLOMLMOMMMMTTSTVSVTVTVVSVVVVVVVYVYXYXVVVVVVSVVVVVSVVTVTSTTTTMTMTOTMOTOOOLGOCGCGGCG@G@GGG@GG@G@GFG@GFG@GFGFGFF@FF=F2=F2==2/2/2//2.//1//.2./1/./1./.1./.2//1/2.//2//2/2/2/2=/2////././/.///=/////////=//=/=/==/=/=/==/8===8==9=88/88*=8888@8@89=9=899=98@898=88=889=8@8@=9@@9@@@@@@@C@C@@C@@@@@@@@@@@@@@@@@==========@=@==========================2=F=F==F==2=2=////2/==2=2==2==2=2=2=2==2=2=2=2==2/..../2=2=2/2/2/2.1/1.1/1/2/2/F=FF..2/.....1/2/2/2/.2/2/ . .=//. . .. ....././/=/===/=/=//=///=/=///*//*//*//*//*=/8/8=8===C8==8==8=8=@@8@@9@@@9@@8=@9@@C@:@C@@@C@@CCC@C@CCCCCC@CCCCCCCCLGLOLOCOLGLGOGGGGCGCGLGCOCGCGCGCGCCGCCCCC@C@CG@..(.(.(.(.(/(.(.(.(.*/(//*.*//*//*/=*====8======8===8==@8@==@=9@@@@@@C@CCCLCCCLCLLLCLLLLLLLLLOLLMOMOMMOMTMTSTTVSVTVSVVVVVVVXYYXYVYXYVVVVVVSVTVVVSVTVTTSTTTTOMTOTMOTLOOLGOCGCGCGFCFG@G@G@GFG@GFG@GFG@GFGF@FFFFF=F2=F2=2=2//2/2.2./1/.//1/.2./.../.2./.2/./2./1///./2///1//1/./././//./////=////=/////=/=/====/=/=/8/8==8=8=8=8=*=8=8=88@8@89=9=899@99=989=88=8=98=99@@9@@8@@@@C@@C@C@CC@C@@@@@@@@@@@@@@@@@=======@=@=@==================F=F========F==F==F=/2=2=2=2==2==2=2=2/=2///2//////2//2/. .. /2////2...1. .1.1.1..2./1/F//1..1... ../2//./. /... ....   ( ../././//./././.*/./(/(/.(.((.*.(/(.*.*.*.*/*/*==**.8*(/(=*/8*=*8/8=8/**=8=8=8=8=8==8==8==@==8====@==@=@@@@@@@@@@@G@@@@F@@F@@F@@F@@@@@F@@F@F@F@@@@=@=====@=.( (...(.(.(.((.(.*.*/*.*//*//*//*/=/8=======8===8==8==@=9=@=@=@9@C@CCCCCCCCLCLLLLLLLLLLLLLLLLOLMOMMOMTMTTSTSVTVSVTVTVVVVVYYXYVYXYYXYVVVVVVVSVTVVSTVTTTTMTTOTMOTOOMOOOLOGOCGG@G@G@GFCFG@GFG@GFGF@FGFGF@GFF=FF=F=F2=2=2=2/2//2/1/.2.2.//1./.2...2./2.//1//1//1/2//./2/./2/.2/.///.////////////////=////=/=/=/=/=*=/8=8=8=8=8=8=8=888=88@8@8989@9=9@9@9@898=988=89=9@@9@@@9@@@@@C@CCCCCCC@C@@@@@@@@@@@@@@@@==@@=@@=@@=@============@=======F====F===F==F==F/=///2/2=2==F=2===2//2=/=/2//2///./.. ..1//2.2..1.. 1. . .1./1.2//2/..1. . 2/..2/...... ....     (..../.....(..(../(/.(.(.(.(.(.(.((.(.(.((/(.(*=*.*(=((((/8*/*/8/*=*=*(=*=*=*=*=8===8===8==8===8===8======@=@@@@@@@@@F@@F@@F@@F@@F@F@@F@F@F@@@@=@@@==@====@( (( (( ((.(.((/(.(.(.*.*//*/*/*///*=/*=/8========8==8==8==@=@8@@=@@@@@@CCCCCLCLCLLLLLLOLLLOLLOLLMOMLMTMMTMMTTSTVSVTVTVVSVVVYVXYYXYYXYYXYXVVVVSVVTVSVTTVTSTTTMTOTTOMOOMOOOLOGOCGG@GF@FG@GFG@GF@FGF@GFG@FGF@FFF=FF=F2=F/F/2/2/2/.2.2.2./.2/./1./.2./.2/.2/./2.//.//1/2.//2.//1/./2.//././///////=//////=//=//=/=*/==*=*==8=8=8=8=88=8=889=8@8@9@8@99@9@9@98@888=98=9@89@@9@@@9@@C@C@CCCCCCCC@C@C@@@@@@@@@@@@@@==@=@=@@=@===@========F==@F=@F=@=F===F=F==F=F==F/2=/=2=2=2==2==2=2=/=2/2//=2///2/2... ../2//2/.2.2. . .1.1..1.1./F=2.1.... . ../2..2. 1... ../..     ../..///../././/(//(//.(.(.(.(/(/(.(.(.(/(*/*/*=*/*/=/*.**/8/8=*=8/8=**=8=8=8=8==8==8==8=====8==@======@@@@@@@@@@@@F@@F@@F@G@FGF@F@@F@@F@@=@@@@=@@=@==@====( .(  ( (( (.((.(/(.*./(/*/*//*///=///*=/8========8==8===9=@=@=@9@@@@@C@CCCCLCLCCLLMMMMMTSMMMLMOLMLOMMTMMTMTTSVTVVVVSVVVVVYVYYXYYXYYXYYXYVVVVVVTVVTTVTSTTTTTMTTOMOTOMOOOLOOLGGCGG@GG@GF@GF@FGF@FGF@FFFG@FFF@FF=FF==2F/2=2=/2/2/.2.2.2./.2./..2./1/./.2./2./.2/2.//./2.2/.2.//2.//.//.//.////=/////////=//=//=/=/8/=*=8/=8=8=8=8=88=88=88=9=999@9@99@99@999=988=9=9=9@9@@9@@@@C@@CCCCCCCCCCC@C@@C@@@@@@@@@@@@@=@=@@=@=@=@=@======@==@==@F@@F@@@F@==F=F==@=F=F==2////=2==F==2===2===F==F==F====//1..2/==2==2/=2/1..1...1/2/2/2=F==2.=1../1.2=2/2=/..//2. . /2//.. . .. .......////=////////=//=/==/=/=/=*/=/==/*/=*///*==8/=@@8==@@8=*=@9=@@9@@@9@@=8@@@@@@@@9@@@@@C@C@C@CC@CC@CCCCCC@CCCCCOLCCOCCCGCOCOCGOOGOCOCOGGCGGCGCGCCGCCCCCCCCC@@(  ( (.((( (.(.(.*.*//(//*//*=//*=/=*=/=8=======8==8===@8@@=@@@8@@@C@CCCCLCLLLMMTMTSTSVSSTSTMMOMMTMTMTSTVSVVVVVYXYVVVVVVXYXYYXYXYYXYYXYVVVVVVSVTSTTVTVTTTMTOTTOMOOOMOOOOOLGGGGCGF@FGFG@GF@F@F@FF@FGFF@FFFFF=F=FF=2=2=22//2/2./2./.2.2./2././1/2/1//.1//2././2.2/1/2/1///1///2/.//..///////=///=//////=//=/=/=/8/=*=*==8=88@8@8=8@88=98@9@9@99@9@9@:9@9@89=88=9=9@9@9@@9@C@@C@CCCCCCCCCCCCC@@@C@@@@@@@@@@@@@@=@@=@@=@@=@=@==@==@@=@F=@@F@@F@@F=F===F=F@F@=F/==2=2==2==F=F=F=F=F==F=F=F@F=F=2///2/F=F=F==F2=/.1//1.2/1/2//=FFF=/2=//2...=2==/F..2/2/.. . ////...../.. ....(././///=/===/=/=/=/========/====8====8=/=8/8/===8=@C==8C@==8@@@9@@@@@@@9@=9@@@@9@@@C@CCCCCCCCCCCCCCCCCCCCCCLCLLOLLOLLCOLOLLOLOLOLOOLOLOOOLGOOOLOLOLCOCOCLGCCCCC.( (  ...((.(.(/(.*.*/*//*/=/*=/=/=*/=8=/====8==8===8===@=9@@@@@@@@C@C@CCCLCLCOLMMMMMTMTMMMMMTMMOMMTMMTMTTSTVVVVVVXVVVVVVYYXYYXYYXYXYYXYVVVVVTVSTVTSTTSTTTMTOTOOMOOOOLOOOOCOGCGG@GFG@FGFFF@FFFFFF@FF@FF@F@FFF=F=2F/2=2=2//2/2./1.1.2.2./2.2/.2.2..2/..2/.2/.///1//.2/1///2.////1/./././/////=////=//=/=//=/8/=/8/8/*=*8=8=8@8@8@8@9=9=9=99@9@9@99@9@9@9989=988@9@9@@9C@@9C@C@CCCCCCCCCCCCC@C@@@@@C@@C@@@@@@@@=@=@=@@=@@@=@@=@==F@F@@F@=@F@@F@F=F=F@=@F=F=F==2==/=2==2==2==2==2==F==F=F=F==/..../=2=2=2=/=2.1.1..1../2/2/2@F=2//2/./...=/2=/2..//./ . .2/2. . .... ......(.////////////////=*=//==/*//8/==/8=/8///*/=*/*@@/8/=9/8=*@9=@9@@9@@@@8=@9@@@9@@9@@9@@@@@C@CCC@C@@C@CC@CCC@CCCCCCCGCCCCCGCOCGLGLGOCOCGOCGCGCOCGCGCCGCCCCCC@CC.(( ( ( ((.((.((.(/(/*/*//*//=/8/=/=8/===8====8===8==@8@8@@@@@@@@@@@C@CCCCCLCLLLLOLOLMMMMMOTMMTMTMTMTMTMTMTSTSTSVVVVVVXYVXYYXYYXYXYYXYVYVVVVVVVVTSTTVTTTTTTMTOTOMOMOOOOOLOOGGGCGGFG@FGF@GFF@FF@FFF@FFF@FFFF@FF=F2=2=2/2/2//2/1/1/...2.2/2.2/1/1/1/.1/./.2/.2/1//1/2./2.2//2/2.///././/.//=/////=//=////=/=/=*=/*//*=*/8*=8=8=8=8==9@89@8@9@99@9=99@89@9@998=9@8@9@9@@9C@@@:@CCCCCCCCCCCCCCC@C@C@@C@C@@C@@@@@@==@=@@@@=@@@@F@=F@@@=@F@@F@@F@@F@=@F=F@F@F@F=F===2=2=2==2=F===2==2/2/===/F/2/ ....2//.///2/2.. .. . .1.....=F=2../.1.. /1//.// .... /./. . .   (...(.(..(.(/.(/(/.(/(/(/.*.*/*.*/(/(/(.((/*(.*=/*(/8.*.*=*=8/8/8*=*8/(/*8/8/*=*8/8==8=8===8===8========@=@=@@@@@@@@=@@@@@@@G@@@@@@@F@F@@F@@@@@@@@=@=@@=@===..(.(  .(.(.(./(/(//*//=*=/=/8/=/=8/====8====8==@=8==9@=9@@@@@@@C@C@CCCLCLLLLLLLLMLMOMTMMTMTSTMTMTMTMTTSTTTVTVSVVVVYVVYVVYXYYXYXYYXYVXYVVVVVSVTVTSTTTTTTTMTOOOMOOOOOLOOOOCGGGGG@GF@FGF@FFF@F=FFFF@FFF@FFFF=FF=2=2=2=2=2/2//1/1.2..2.2.2/1//.2.1/.2.2.//1///1/2./2./2//2/.///.//././/.////=///////=/=/=/=/8/=*=*/**/*8=8=8=9=9=9=9=9@89@9@99@8989@98@9@99=98@9=9@@:@@C9CCCC@CCCCCCCCCCCCCC@C@C@@C@C@C@@@@@@=@=@=@@@@@@@@@@@=@F@F@@F@@G@@F@@F@F=@F@@F@@=F@F=F==2===2=F=2=F/=2==/2=2==2=//. . /1/1/2/.2...0. 1 . ..1.1.2=2..1..... ...././ .... ../.. .    .( ..(...(..(..(...(.*..(.(.(..(///(/(/(.((.(*.((/*/((//(.*.8/*/**/*/8/*(**//8/***/**/*/*=8=8==8=====8====8===@==@==@=@=@=@@@@@@@F@F@F@@F@F@@F@F@@@=@=@==@=@=@=.(.( . (..(.((.(/(/*//8/=/8/=8/===8=====8====9=8=8=@8@@@@@@@@@@@C@CCCCCLLGLLLLLLOMMMOMTMSTSTSSTSTSTTMTSTSVTVSVVVVVXYYXYXYYXYYYYXYYXYVVVVVVVVSVTVTTVTTMTTTMTOMOOOOOLOOOOOOCOGGGGFGGF@FGF@FF=FF=F=FF=FFFFFFF=F2=2=2/2=2/2/2./1.2.1..2.//1/2.2./1..1.//1//1/2.2/2./2./2///2//1//../.././///////////////8/==/=/8/*/***/*8/8=8=8=9=9==98@9@8@9@98@989@99@9@999@8@9@9@@:@CC@CCCCCCCCCCCCCCCCCCC@C@CC@CC@CC@@@@@====@=@@@@G@@@@F@@F@@F@G@G@FCF@F@F=F@F@F@F@F@F@F==F=/F==F==F==2==2=2===2===2...1..2///2//2/.1..1. .1 .1...2=F/..//.2.. /./1//. ../. ./... .. .  . .(..(...(..(..(..(..(/.(.*.(/.*/.*./(/(.(.*.(((==(/*=**/*==8=8=/8/*/*=(/=*=**=*/*/*8/8/8===8===8@===@=@@=@@@=@@@@=@@=@@@@@@@@F@@@F@@F@@F@F@@F@F@@@@=@=@@@@@@=.( ((( ( .((( (.( (.(.(/(=//8/=8/=/=8=/===8=====9==8=@=8=@8@@9@C@C@C@@@CCCCCCLLLOLOMMMTMTSMSTMSSTSTSTSTSTTSVVVVVVYXYVVVYXYVYYXYYXYXYYXYYVXYVVVVVVVVSVTVTSTTTTMOTOMOMOOOOLOOOOGOGGGGGG@GFGF@FF=FF=F=FF=FFFFFFF=F=F=2=2/2=2/2/2/2..1...2..2.2/.2/.1..1/..2.2/2.///.2.2/2.2/2///2//././.../././////////////=/=/8/=*/*/*/***/88=88=9=8=8@8=8@89@998@99=989@99@9@9@9@9@@9C@@C@CCCCC@CCCCCCCCCCCCCCCC@C@CCC@CCCC@@@==@==@@@@@@G@G@@@F@@F@@G@@@G@@@F@F@F@F@@@F@@@F@F@F==F=2=F===F==F=2===F=F=FF=///1/.2=2=2==2=2/../.1/1.2./2/2@F=/2/2/2//..///2//2.//2/. . ////.. ./.. ... ..//.//.///////.///////8////=////==/==/===*///8=/8/=@=8/=8==8=@@@@=@@@8=@==*@=@=9==8=8@=8=9=@@@@@@CC@@C@C@CCCCCCCCCCCCCCCCCCGCGLGLGLGOCGGCGGCOGLGLGLGLCGCCCCCCCCCC.(( (.( (  ( (.(.((.(.(/*/=*=/===8/===8=====8@==8@=9=@=9=@9@@@@@@C@@@C@CCCLCLOLMMMTMTMSSVSVSVSVSVSVVVSVVVVVXYXY[YYXYXYVVYXYXYVYVYYXYYXVYVVYUVVVVVSVTVSTVTTTTTMTOOTOOOOOOLOOOOGGGGGGGG@GFGFF@FF=F=F2F=FF=F=FF=F2=2=2=2=2/2=2//2.2..1..2.1/.2/.2..2...1/1/.2/.2/1//2.2/2./2/2///././...../././///.///////*=/=/8//8/***/(**/8*=8=88=8=888@8@89@9@98@99=99=9@9@9@9@@9@@9@:C@CCCCCCC@CCCCLCLCCLCCCCCCC@CCC@CCC@@@@=@=@=@@@G@@C@G@@@F@@FC@G@G@G@G@@@F=@@F@@@FF@@F@@F@F=F=F=FF=F@F=F=F=F=F=F@F@2////2==/==F==F//2/1/2//2.2/1/=FG=2=2===//..2///==/.////... /=2=.....//. ./..(./././/=(/=//////////=/=/=/=*=/=/=====8==/==8==@=8=@@@=8@@===8C@C@C@@@@@@@@8@@@@@@@@@8@=@8@@@CCCCCCCCCCCCCCCLCLCLLLCLOCGLCCLLOLLOLOLOOOOOGCOOGLOOLOLLOLLLCLCCOCLOL.(.((.   (.((.( ((.(.(/*//*===/==8===@=@=@==@8==8@=9=@9=@@9@C@C@@C@@C@CCCLCLLOLLMOMMTMTSTSTSTSTSVSTVSVVVVVYYXYXYYYVVVVXYVYXYXYXVYVVYVVXVVYVVVVSVVVTVVTSTTTTOTMOOMOOOOOOOOOGOGGGGGGGGG@GFFF@FF2F=F2F=2FFF=FF=F=F2=2=2=2=2/2//2.2./1..1/1./1/1...1...1/1/.2/.//.2/./2/2//2//2///../../..///././////.////*=/=/8//*/***/**8/8=88=8=88=888=9=9@89@999@89@98@9@9@9@9@9@C@:@CCCC@CCCCCCCCLCCLCCCCCCCCCCCCCCCCC@@@@@=@=@@@@@C@G@@G@F@@F@@G@@@G@@@F@F@F@F@@F@G@F@G@F@F@==F===F==F=F===2===F=F=2/.2./=2//2==2==2.././.2.///1/2/F@//2=2/=2...//.///..////... ////.. ../. (./ ../.(////(////./*///*//=///////*//==/=//8//*//8=@=*/@9==*@@=8==@@@@@@9====8==8=@=9=8=8=8=8=8=9@@@@@C@C@C@@CCCCCCCCCLGCCCCGCCCCCGLCGLGLGCGCGCGCGCGCGCOCOCCCCCCCCCCCL.((.( ((  (( ( ((( (.((.(.*/*/=/8======@=@@@8@@==@=@8@=9=@9@@@9@@@C@@C@CCCCLLOLLOMOLMLOMMMTMSTSSVTSVVSVTVSVSVVVVVVVVUVVVVVYXYYVYVYXYVYXVVVVVVVVVVVVTVSVTTTTSTTTTOTTOOMOOOOOOOOGOGGGGGGGGFG@FFF=FF2=2F2F=F=F2F=2F2=F/F/F/2/2=2/2//.1..2..1/1.1..1../1...2.2/.2/1//.2/2.//2//2///////./.../././//.//.//./*///=*=/8/8/*/**/**8=8=8=88=8=8=98=9@9@9@9=999=99@9@9C@:@9@@9@C@CC@CCCC@CCCCCLCLCCLCCCCCCCCCCCCCCCCC@@@@=@=@@@@GC@GC@G@@F@@@G@FCG@G@G@@@F@@@G@G@G@G@G@F@@F=F=F=F@F==F==F/F/2//2=/....././..//2/2/...1.....1.....2=2...//2/. ... ... ././.. /... .... ( ( .( .(. .(.(...(.(.(.(..(.(.(.(.*.*/(.(.(.(.*=(/*.=8.*/8=.*/*==8=*==*=*/*(/*=*/*/**/**/**/8/8/8==8====@8===@=@@@@@@@@@@@@@@@@@@@@@@@@G@F@F@F@F@@@@@@@@@@@@=@@@@@@(.(.(( ((  ( ((..( (( (((.(/*//=/8===@=@=@@@@@@9@=@=8@@@9=@@9@@@C@@C@CC@CCCCLLOLMLMOLMLMTMMTSTSTSVSVTVVSVVVVVVVVVVVVVVVVVXYYVXYXYYVVXYVVVVVXVVVVVSVVTVTVSVTTTTTTTMOTOOOMOOOOOGOGGGGGGGG@GFGFGFFF=F2F=2=F2F2=F2=F/F2=2=2/=2=2/2/2/1/1.1/1..2./1.2.1..1.....2/.//2/.2///2//2//2//2///../..../././/.//./////*//=*=/8/*/*/*/8/8*=8=8=8=8=888=9=9=9@9@9@999=9@@9@9C9@C9C@9C@C@CCC@CCCCCCCCCLCLCLCCCCCCCCCCCCCCCCC@@@@@@=@@@@CG@G@@FC@F@F@@G@@G@G@F@G@GFCFG@G@G@G@G@F@F@@F@F@=@F@=F=2==2=/=///...../....2////..1... 1 .. ...2//...2.//.. ... .... .//.... ./... ... .. .......(...(..(.(..*.(.(..(/(/./(/.*.((.(.=(/(===*/.8//(/=*=/8/=*/*/*/(/*/*=*/8/*/***/**/*=*==8===8=====8=@=@@=@@@@=@@=@=@=@@@@@F@F@=F@F=@==F=@=@====@=@@=@@@@.(.(.((.( (  ( ((((.(( ((.(/(*//8=====@=@@@9@=@@@@9@@=9=@@@@9@C@@C@C@CCCCCCCLLLLOMLMOMOMMTMTSTSTSVTSVVVVVVVVVVVVVVVVVVVVVVYXYYVYXYXYYXYVVVVVVVVVSVVVTVSTVTTSTTTTMTTOTMOOOMOOOOGGGGGGGGGG@GFGFFFF=F=2F2F=2F=2F2=2=2=2=2/2=2=2/2//2/1/1.1/1..1.1..1..1..1.1.2.2/./2.//1//2//2=/2///2//./././/.//.//.//./*.///*/=*=/*=*/8/**8/8=88=8=8=8=8888@9@9@99@9@9@9@9@@9C9C9@:@C@:C@CC@CCCC@CCCCLCLCCLCCCCCCCCCCCCCCCCCCC@@@@@@@@C@G@C@C@G@F@@FCF@G@@G@G@G@G@GG@GG@G@GG@G@G@F@F@@F@F@F@=F==2==2=2=/....../.../=/2/2...........1.../=2..2.2/// ... ... ././/.. /./. . //. ( ( ..( .( ...(..( (.(..(.(.(./(.(..*/(.*..(.(.*.=*/(===.*==(//(====*=8/8//*/(/*/*/8//****/***/8/8=8=========@=@=@@@@@@@@@@@@@@@@@=@@@@@@@F@@F@F@F@@@@@=@@@@=@@@@@@@@(.(.(.(.( (  (..(( ((.((((.*.*/*=8==@=@@@=@@@@@@@@=@@@9=@@@@@@C@@C@CC@CCCLCLOLMOLMLTMTSTSTSVSVVSVVVVVVXVXYXYXYXYXYXVVVXVYVYXYXYVYXYYVXVVVVVVVSVVTVSVTVTTVTTTTTTTMTTOTTOOOOOOOGGGGGG@GFGFGFFFF=FFFF=2F2=F2F/F2=2=2=2/2=22/2=2/2///1//.2.1/1/.1..1...1.....2.2/.//1///2/2/2=2=2//////.//..//.//.//.//.//(///8//8/8/=*/8/8=8=8=8=888889=8@88@9@9@9@9@9@9@@9@9@@9C9C@:C@:C@CC@CCCCCCCCCLCLCCLCCCLCCCCCCLCLCCCCCC@C@@@@@@@@CG@G@@G@F@@FC@@G@G@G@FG@G@GCG@G@GGCGG@G@G@F@F@@F@@F==F===F/==F...../2/2/2=F=F=/2//2.2//1///.2/F=2/2===F/= ///..//../////.. ///... .///. (./ ..../(/./..(//./.*/.//8////*////*//=//=//*=/*/=/==8==@@@==@@====@@@@@@@=@@==8==8=====8@=8=8==8@=@@=@@@@@@C@C@CCCCCCCLCCCCCCCCCCCCCCCGCOCOCGCGCGCGGCGCGCCCC@CCCCCOCLGL(.*.(.((.((  ( ((( (.(.(.(/(*/*/8===@8@@@@@@@@@@@@@9@@@9@@C@@:@@@C@CCCCCCCLCLLOMMMTMSVSVVUVVVVVXVVXYXYXY[Y[[[[[[[Y[YXYYXYXYYXYYXYYVXYVVVVVVVSVTVTTVTVTSVTTTSTTTTTTTTOTTOOOOOOOGGGGGG@GFGF@FFFF=FF=FF2=F2F=2=2=2=2=2=2/2=2/2=2/2/2.2/1./1/.1/1.1.1....1.2..2.2/1//.2/////2//2=2//////.//.//.///.//./.*./*//*/*=/*=*=8=8/88=8=9@8@8=88=888=8@9@9@9@@9@9@9@9C9C@:@:@@:@CCCCC@CC@CCC@CCCCCLCCCCCCCCCCLCLCCLCCCCCCC@C@@G@G@C@G@G@@F@@F@@G@G@G@GG@G@GGCGGCGGCGCGCG@G@G@G@@@@F@F@F=F=F==F==../.2/////@F@F@F///2///2//2/2//F=F/2=2=F=F../=..///..//=//// =/=...../=/...//..../////(..////*//*///=/8////=*//=====/===/*=/=8@===CCC@=@C====@C@@@C@@@@@9@===8@=@@@=9=@=9=@@@@@@@@@CCCCCCCCCCLCLLLOLLLLLLLLCLCCLGCLLOLOLLGLOGLOGLOLGCGCCOCOLOLLOLLO(.(.((.(( ((. ( ( (.( (.((((/(/*/*==8@=@@@@@@C@C@@@@@@@@@9@@@C@C@9C@CCCCCCLCLOLLLOMMTMTMTSTSVSVVVVVVVVYXYYXYX[Y[Y[YXYYXYYVYXYYXYYVXYYVVVVVVVVTVTSVTTSTTVTTSTTTTTTTMTTTTOTOOOOOGOGGGG@GFGFFF@FFFFFFF=FF2=F2=F2F/2=2/2=2=2/2=2//2/2/.2//2./1.1..1..1.1...1....2.2/.2/./2/2//2=/2=2//////././/.//.//..(./(/.*//*/=*=/8=8=8=8=88@=9=9=9=89=8@88@9@9@@9@9@@9@9@@9@9@9C@9C@C:@CCCCC@CCCCCCCLCCCCCCCCLCLCCLCLLCCLCCCCCCC@G@@@@G@C@@G@@F@@F@@G@G@G@GGCGG@GCGGCGGCGGCGG@G@G@F@F@@F@F======2=//.....//./2==F==//2///////1//.2/=F=.//=F=F=.///.../..//////...///... //// (//...(.(././(./(/...(.*.*.*///*//*//*.//*=//*//*/*/=@=8/@@@=8@@@=8=@@@@@@@@8@===8=*=8=*=8==8=8=8==8@@@@@@@@@@@C@CCCCCCCCLCCLCCCCCCCCCCCCCCCLCGCGCCGCGCGCGCGCCC@CCCCGCLGCL(.((.(.((..(( ( ((.(( (.(.(.(/(/*/8===@8@@@@@C@@C@@@@@@@@@@:@@C@CC@C@CCCCCLCLLLOMLMMOSTMTTSSTVSVSVVSVVVVVXYXYVXYXVYYXYYVXYXYYYXYXYYXYVXVVVVVSVVTTTSTVTTTSTTTVTTTTTTTTTOTTTOOOOOOGGGGFGF@FFFFFFFF=FFF=F2F/F2=22=2=2=2/2/2/2/2/2/2/2/.2./21.2.2./1.1..1....2.../.2/./2././2/2/2////2///./././././././.(..(/.*//*/8/=8==8=8=8@8@9@9@9@9=88=888@8@9@9@9@9@@9@9@9C@9C9C@:@CCC:C@CCCC@CCCCCCCCCCCCLCCLCLLCLCLCLCCLCCCGCC@C@C@@@G@@@G@@F@@G@FCFGCGCGGCGCGGCGCGCGOGCGCGG@@G@@G@F@F@=F=F===//........../2=/=1................2/..2./=/=. ... ... .../.. ///. /..  .... (. (. ...( .( (..(.(.(.(.(..(//*./*.*.(.(.8/*.*===*/=8//(===8/=8=*=*=*/*/*/*.*/****/**/*/8/*=*=8=8==8=8===@@@@@@@@@@@@@@@=@=@=@=@@@@=@=F=@=F@=F@@=@F@=@@@@@@@@@@(.(.(.((.(((.( (.((.( (( ((((*/(/*==8=@@=@@@@9C@@C@@C@@@@@@@CCCC@CC@CCCCCCLCCLLLMOMTMTMTSTSVTVSVVSVVVVVVVVVVVYVXYXYXYYXYYYYXYYYXYYXYYVVVVVVVVSVTVTTVTTTTTTTVTTTTTTTTTTTOTOTOTOOOGOG@GFGFF@FFFF=FFFF=F2F=2F2F=2F/2=2/2=22=2/2//2/./2.2/1/2/1..11.2.1.1.1...1.1.2./1/./2/.///2//2//////.//../././../..*..(/(/.*/*/=*=8==8=8=@8@8@@9=99@8@8@888=9@9@9@9@9=9@@9@9C9@@9@@:CC@CCCCC@CCCCCCCCCCCCCCCLCLCLLCLCLGLCLCGLCCCCGC@G@G@@G@G@@F@F@@G@G@G@GGCGCGGCGGCGGCOGLGGCGCGG@@F@@@F@F==F==F=// .. ....../=/2=................//..../2=2/.... . ..../.. //... ..// ./. .....(  . .( ...(.(.(..(.(.(//(/.(/.(.(*.(//*.=8/=/*==/.*/8/==8/==/8/=*/*/*/*/(/*/***/**/*/=*=*==/8===8===8==@=@@@=@@@=@@@==@=================F==F======@=@@@@@@/(.((.(((..(( (( (( ((.( ((.(.(.*/*/8/==9=@@9@C@@C@CC@C@C@C@:@C@CCCCCC@CC@CCCLLLOLOMLMTMTMTSTVSVTVSVTVVVVVVVVXVXYVYVYVXYYXYXYYXYXYYXYYXVVVVVVVTVSVTTSTTTTTSTTTTTTTTTTTTTTTOTTOOOOOOOGGGGF@FFFF=FF=FF=FFF2F=2F2=F2=F/2=22//2/2/2/2/2.2/1/2.2/1/1./1..2..2..1/../1./1//2./2.2///2////.///././...././...*..(..*.*.*/*/=8==8=8@=9=@9=@9@@99@89=9=88=9@8@9@9@9@9@9@@9@9C9C@C9CCC:@CCCCCC@CCCCCCCCCLCLCLLLLLCLCLCLGLCOCOCCCGC@@@@G@@@G@G@@F@F@@G@GCGGCGOCGGCGCGOGOGLGGOCGCG@G@F@F@=F@=F===... ....././F/==.................=/../.2=/=/../. /. . .....( .//. .//. (./.( .(. .( ..( ( .( ( (..(.(.(..(.(//.*/.*.(/(.(/*/.*/===(==///*/==/==8/==*/*/*/**/(*/*(*/(**/*/*=*/==8==8====8=@=@@=@@@@@@=@@@=@@=@=@=@@=@@@=@====@=@F@@@@@@@@@@@@@@@@/((.(((.((( ((.(.( (.( (( (((.(((/*/*=8=8=@9=@@9@C@CCCC@CC@@C@@CCC@CCCCCCCCCCCCLLLLLMOMTMTMSTVTVSVVVVXVVVXVXYXY[Y[[X[[YYXYYVYXYYXYYXYYXYYXVVVVVSVTTVTTTTTMTTTTTTTTTTTTTTTTTTOTTOTOOOOGGGG@FGFFFF=F2F=F2F=F2=2=F2=F22=2/2=2/2//2/1/2.2/1/2/1/2.1/1.1/1.1..1...1../1//1///1//.2////1//////.//.../...../..(./(.(./*.*/8/=8=8==8==9=9@@8@9@@9@8@88=8889@8@9@8@9@9@9@@:@@C9@@:@CC@CCCC@CCC@CCCCCCCCLCLLLLLLLLOCCLCLLLCLCOCCC@CG@C@@G@@G@@G@@G@FG@GGCGGLGGCGCGGCGLGOGLGOGCGCG@G@F@F=@F==F=2/...../.../==F=F///./////////2//F/2//2==F@F//=/..//. ///////..///..( ////./// /(//..*....*../..(/.(./(/./(/.*///*//=////*/*./*==/==@@@@=@@==/=@@@@@=@@@@==@=8==8/8=/=*=8/=8=8====@=@@@@@@@@C@CCCCCC@CCCCCCCCCLCCCCCCCC@CCCCCGC@G@C@GCCGCGCCCCCLGCOCGC/*/(/(((.(.((.(.(..(((.((.(((.(/*/*=8==8@@@9@@C@CC@CCCCCCC@@CC@C@CCCCCC@CCCCCLCLOLMOMMMTTSVVSVVVYXYXYXYYXY[Y[[Y[[[[[[[[Y[YXYYYXYYXYXYYVVVVVVVSVTVSTTVTSTTTTMTTTTTTTTTTTTTTTTOTOTOOOOOOGGFGFF=FF=2F=2F=2F2F2F2=2=2F=2F/2/2//2/2//1///1/2.2/1/2.1/1.1./1.2.2.2..1./1//.2///2/.2/1////1////./......./...*..(..(.*.*/*/8=/8=8=@8=9=8@9@9@8@9@99=888=8=9@8@9@99=9@@9C@:@@:@C@:@:C@CCCCC@CCC@CCCCCCLCLLLLLLLLLCLOLCOCOLCOCGCGC@G@G@CG@@G@@F@F@G@G@GGCGCGCOGOCOGCOGLGGLOOCOGCG@@@F@F@@F=@F=....././///F=@F=//////////=2=/=F=F////F@F@=//=//.=/.///=////./==.....===/../=/(/.//////.(///./*///(///*/.*////*//===//=*=//*///@==/@@@@=@@C===@@@@@@C@@@@@@@==8====8==8=8=8@=@8@@@@9@@CCCCCCCCCCCLCLCLGCLGCLGLLOCLGCCCCLCOCGCCGCCCCGCCGCOLOLOLOLOLOLLO/(/(*.(.(((.((.( (((.(.(.((.(*(/(/**=*=8=8@@9@@@CCCCC@CCCCCCC@@C@CCCCCCCCCCCCLCLLOMLTMTMTSSTTSVSVVVYXYYXYYXYXY[XY[Y[Y[Y[YXYYXYYYYYXYYXYVVVVVVTVVSVTVTSTTTTTTTTTTTTTTTTTTTTTOTTTOOTOOOOGGGGFFFFFF=2F2=F2=F2=F/2F2=F2F/F2=2/2/2/2//21/2/2.2.2.1/1.2..2./1..1/.1./1/2.2//.2/./2.//./2.////./........../../(..*..(/(/*//8==8=8=8=8@8=@9@9@9@8@98=98=988@98@9=9@9@9@9@CC@:C@C:@CC@CCC@CCC@CCC@CCLCLLCLLLLLOLLLCLCLLCLOLCOCCCGC@@@CF@G@G@G@G@G@G@G@GGCOGOCOGOCOGOGCOGOLOOGLGCG@F@@F==F=F=/........../=F==////////////////F=//2//F==F////../// ///////../=...(..///.///(../*./(// /(/(..(..(.(./(.(.(..(/*///*///*/*//*/=///=@@@=@@@===@@@@@=@=@@=@==8==8/8/*/*/=*=8=8==8===8@@@@@@@C@CCCCCCCGCCCCCCCCCCCCCCCCGCCCCCCCG@CC@@@@CCGCCGCLGCOCGLGCC/(/(//*/*.((.((.(..((.((.(((.(/(.**/8/8/8=@8@@@@C9@CCCCCCCCCCCC@C@C@CCCCCCCCCCCLCLLLMOMMTMSTSSVVTVSVVVVVVVVXVVYXVYVVVVVVVVXYYXYXYYXYVVVVVVVVVVVSVTVTVTSTTTTTTTTTTMTTTTTTTTTTOTTOTOTOOOOOGGGG@GFF=FF=F2F2=F2=22=2=22=2=22=2/2/2/2/2/2/2/2/2.2/1.2.1.2..1..2..1/.1.2./2//2///2/./2/.////.///./...../..(/.././(..*.(/*/*/=*==8=8=8=8=9=9=9=9@9@9@8=888=9=9=99@9=9@9=@:@:@CC9C@C:@CCCCCC@CC@CCCCCCLCLLLLLOLCLLOCLLGLOLLLOCOCCGC@GC@GCCG@G@G@G@G@GGGCGGCGLGGOGGLGGLGOOOOOOLOGCG@@F@@F====/./.../....//==F/./..........././/2....//=/=../..../.../././. //. ( ./*// .*..(..(.(.( ...(.(.( (.( .(.(.(.(..(//(/(/(..(..*=/(///=*/==//*/=/======/8==/8/*/*/*/*/**.**/(**/*/*/*/8/8==9=@=@=@@=@=@@==@=@=@=@@@=@=@=@=@=@==@==F======@@@@@C@@@@@C@@/(/*.*/.*/*.((.(( ((.((.(((.(((/(*.**/*8=8=8@9=@@@C@CCCCLCLCCCCCCCCC@CC@CLCCCCCLCLGLOLMMTMTSTSTVSVTVVSVVVVVVVVXYVVVVVYVXYVYVXYYXYYYYXYXYVVVVVVVVTVVSVTVTTVTSTTTTTTTTTTTTTTTOTTOTOTOOOOOOOOGGGFF@FFFFF2=F2=2=2=2F/2=2F/F2=22/2/2/2/2/2/22/2.2/1/1.2.1.2.1/1.2.2.2.2.2./2//2///1//.//./2/2////./../....././././(..(/(/*/*/8*=/8=*=8=8=8=9@8@9@8@89=9=9=88@9=98@9=9=9@@@:@C9CC@:C@:@CCCCCC@CC@CCCLCLCLLLLCLLLCLLCOLCLOLOLLCOCCG@GCGCG@CGCG@@@G@G@GCGCOGOGOOCOGOCOGCOLOOLOOOOCGC@@F===F==/........../F==/////............//./...///2/........ .(..//.. .// ..//// ./( .(.(.(.( .(.( (..(.( .(.( (. ( (.(/(./(/.(.(.(///(//=/=/===*///=====/===/8==/=*//*/*/(/*(/***/*/**/=*/8/=8==8==@@=@=@@==@=@@=@=@=@@=@========@=============@@@@@@@@@@F@/(/*./*/*//*/((.((.(( (((.(((.((.(/*/*8/*=8=9@9@@@9CCCCCCLCCLCCCCC@CCC@CCCCCLCCLCLCLLLOMOMMTSTSVTVSVSVVVVVVVVVVVVXVYXYXYYXYXYYXYYXYYXYYVVVVVVSVTVVSVTVVSVTTTTTTTTTMTTTTTTOTOTOTOTOTOTOOOOOGGGGGGFFFF=F2F/F2F2=2F22=22=2=22=2//2/2/1/2/2/2/2/12/1.2..2.1..2./1./1/..2.2/.2//2/2//1//2.////2//././.......././.(/.*.*.(/*/*/=*8=*=*8=*8=8@8=99=9@9=98=8=9=98@8@99=9=@9@9@@9CC@:@C9CC@:CCC@CCCCCCCCCLCLCLLLCLOCLLGLCLOLLOLOLGCCGCGCG@CGCGCG@GC@G@GGCGGCGOOOGLOOLOGCOOOOOOMOOOOCGCG@F=F===//./../..../===2///./../..../././//././/=2=/../...//.././/./. /.. (.//// (/..(.*..(..( (.(.( .(.(....(...(/.(./*./(./(//=.(==/=/==//*/=======/=*==/8=/=*/*/**/(/***/***/*/*/8/=*==8=@=@@@@@@@@=@=@=@@@@@@@@@@=@=@=@=@==@@==@==@=@@@@@@@@@@G@@@@*/(/*/(/*/*///*(.((( (..((.((.((.*(/(/**=8=8=9@@9C@CCCCCLCCLCLCLCCCCC@CCCCLCCLCLCLCOLLOMMMTMTVTSTVTVSVVVVVVXVXYXYYXYY[Y[Y[[Y[YYXYYXYYYYVVVVSVVTVVTVTVVSVTTVTSTTTTTTTTTOTTTOTTOTOTOOTOOOOOOOGGGG@GFFFFF=F2=F2=22/22/22/22=22=22/2/2/2/22/22/2/1/1.11.1./1..2..2./1/2./1/2/2//2//.//.///2///2//./....../...../.(/..(/(.*/*/*=*/8*=**=88=8=9=9=98@8=9=98=9=99@9=9@8=9=9@@9@@C:@C@:@CCCC:CC@CCCCCCCLCLCLLCLOLCLCOCLGLCOLLOLOLCGCCCGCGCCGCGCGC@G@GCGCGGGOGOOOOLOOOOGLOOLOMOOMOOOCGC@=F=F=//././....../=F=//./////////////===//=/=F=F==///.//=/./==/==//./// .(..////..//(.(///*./(..//(/./(//.(/.*.(..(.(.(/.*//*///*//(/===/===@===@=/==@@=@@@=@========8===8//*=*/=*==/=8====8=@=@@@CCCCCCCCCCCCCCCCCCCCCCCCCCCCC@@@C@CCCCC@C@C@C@GCGLGLGLOLOLGL/*.*/*/(//*//*/(/(.((.(((.((.((.(*.***=*8/88@=9@:@CCCCCCCCCCLCLCCCCCCCCCCCLCLCLCLCLCLLLLOMOSTSTSTVSVVVYXYXYXYXY[Y[Y[[Y[[[[[[[Y[Y[YYYYXYVYXVVVTVSVTVVSVTVTVTSTTTTTTTTMTTTTOTTOOTOOOOOOOOOOOOGOGGGGG@GFF=FF=2F2=2F2=2F/2=22=2/22/2/2/2/2/2/2/2/22.2.2.1/1.2.1.2.1/1/1/2./1//2/.//2.//.2/.//2////../......../(../(..*.(/(/(/8/*=*=**8/*8/8=8=8=9=98@8=8=98@8@8@9@9=9@8@=9@@9@@C:@C9C@:CCCCCCCCCCCCCCCLLCLLCLCLGLCLGLCOLOLLOLOCLGCGCCCGCCGCGCGGC@GCGG@GGOOOOOOOOLOGCOOOOOOOTOOOLOGG@F=@F=/////.///./.=F==.//=//===////==/=F==2==F@G@F///////=/========//=//.(..==/=(..=*./(/=//=/(..*/./*///*//*///.*./*..(//*/////=//*=/==@//@@=@@@@@===@@@@@@@@@@@@@@@=@===8==8===8==8====8=@@@@@@@@CCCLCLCLLOCLOLCGLCGLLOCCOCCOCCCCCCCCCOCCCCGCCCCCOLOLMOLLOLOLO//(/*/*/*//*//*/(.(.((..(((.((.(((.(/(*/**8=8=8@@9@CC@CCLCLCLCCCLCCCCCCCCCCCLLLLLLOLLOLOMMMTMTTSVTVSVVSVYXYXYXYVYXYYXYYY[YY[Y[YXYYXYYYYYVVVVVVVTVSVTVTVTSTVTTTTTTTTTTTTTTOTOTOOOOOTOOOOOOOOOGGGGG@GFFFFFFF=F2=F/22=22=22=22=2/2/2/2.2/22/22/2/1/1.1/1.1..1/.1./1/1/./2./2./2/2././2.///1///././.............(..(.(.(.((/*.*/*8/*/*8*/8=*8=98=8@88@89=9=9=9@9@9@8@8@8@89@@9@@9C@C9CCCC:CCC@CCCCCCCLCLCCLLLGLCLGLCLGLLOLOLLLOCGCCGCGCGCGCGCGCGGCGGCGGOCOOOOOOOOCOGOMOTOMOOOMOOLOCF=@F=///.///../../==/////////=2/////2/==2/=/=@@@F=//.///==/========.//(....//=/ /./.(///*//( (./(..(.(/.(./(/(.(..(.(.(/.*.*//(/./*/==//=======@*/==@@@=@=@=====8====8=/8/8/8/=*=/8=8==8==8=8=@@@@@CCCCCCCCCCCCCCCCCCCCCCCCC@@@@@@CCC@CC@@C@@CG@CCLGLOLOCOCOC//*./(/*/*//*///*(/((.((( (((.((.(((/**/*8=8=8@9@@CCCCCCLCCLCLCCCCCCCCCLCLCLLLLLOLLLLOMOMMMTTSTTVSVTVVVVVVVVYVVVVVVYXYVVYXYYYYYXYYYXYXYXYVVVVVSVTVTSVTTVTTSTTTTTTTMTTTTOTTTOMOOOOOOOOOOOOGGOGGGGGFGG@FFFFF/F2F2=F2=222=22/22/2/1/2/2.2/2/22/2/1/1.1.1/1..1./1./1/1/2.2./2.///./1/.//.///.2//./........ (....(.(.(.((.*.****=*8/8*/*8*8*=8=88=88=8=9=9=98@9@8@9@9@8@8@89@@9C@9@CC@:CCCCCCCCCCCCCCCCLCLOCLLCOCLCOCLOLLOLOLOLGLGCGCCGCGCGGCGCGCGG@GCGGOOGOOOMOOOGMOOOMOOTOMOOOOCG=@F@=////////....=/=/././///=2/.../././/.//./F===......//..=/==/=/. *.  ( *//.( (.*.(.*./(/..(.(.(.(.(..(.(..(.( ( (./(.(./(./(//*/=.*/=/=/8/=//*.=======/==//*=/*=/*/*/*/*/*/**//*/*/*/*//*=*=*==8=@=@=@=@=@@=@@@=@@==@==@=@=======@=========@=@@@@@@@@@@@@//*.*/(*.*//*//*/(*(.((.(((.((.(((.(((/**=*8=8=@8@=@@C@CCCLCLCCCLCLCCCLCCLCLLCLLLLLOLMLOMOMTMTSTSVTVUVVVVVVVVVVVVVVVVVVYYYYXYYXYYYXYYYVYYVVVVVVTVVSVTTVTSTTTTTTTTTTTTTTMTOTOOOOOOOOOOOOOGGOGGGGGGGG@GFGFFFF=F2=2F2=2=2=22/2/2/2/2/1/2/22/2/2/2.1.2..1.2.1/.1.2.2./1/.2/1/1/1/2././/.2/./2/././....... ....( ..(.(.(((.*.**/*/**/**/*/8*888=89889=88@8@98@9@8@9@8@98@8@8@9@9C@9CC@C:CCCCCCCCCCCLCLCLCLCLLGCLGLCLOLOLLMOLOLLOCGCGCCGCGCGCGGCGGCGGCGLGOOOOOMOOGOOTOMTOOOTOOMOOC@F@@F/////////././==/..//////////./...//.../.=/==//...../../==/=///..   //*/ (/...*./(.( (.( (.(.(..(.(.(.(..(.(.(.(/.*./.(.(/./==/*/=/=/=*=./*/=/==/===/==//*/=*/=*/8//*/*/*=*=/*=*//*=*/*//=*===@=@=@@=@=@@=@@@=@=@=@========================@@@@@@@@@@@/.*/.*./*./*//.*/(/(*(.((.((.(((.((.(.(**/*8=8=8=@9@@9@@CCCCCLCLCLCLCCLCLCLCLLOLOLMOMLOMLMOMTMTTSTVSVTVVVVVVVVXVVVVVVVVXVYXYYYYYYXYYYVYVVVVVVVVVVSVTTVTSTTTTTTTTTMTTTTTTTOTTOTOOOOOOOOOOGOGGGGGGGG@GFGFGF@FFF=F2F/F2F2=22/22/2/1/2/2/1/2/2/2/2/2.2.1/.1.1/1.2..2.1/.2./1/1/./././.././/././/./../... .... .....(.(*.*(/*/8*=***=**8*=*=888=8=88@88=8@99=9@9@9@8@9=89=9@9@9@C9C@CC:CCCCCCCCCLCLCCLLGLCLCLCCLGLLOLOLOLOLOLLGLCGCGCGCGCGCGGLGGCGCGOGOOOOMOOGOMOTOTOTOTOMOTOLFC@G==/=////////./=//./././//=/////././././//=F==F/.....//.========..(.   */.*/./((../(/(.( (.(.(.(..(.(.(..(.(.(..(..*.(..*./(./(/*==//==*//=/=(/.===/=/=/8/=/8/=*//*//*/8/8//8/*//==*/=*/*=/8/=*=====@=@=@=@@=@@=@=@@=@==@=====================@@@@@@@@G@@@G/*.**.*./(.*./*.(*.*.(((.(.((.(((.((((.(**/8/8=8@=9=@@@9@C@CCCCLCCLCLCCLCLLLOLLLMOLLLOMOMOMMTMTMTSTVVVVVVVXYXYYXYYXYY[YYYX[Y[Y[[Y[YYXYYXYYVVVVVVVVTVSTVTTTSTTTTMTTTTTTTTMTOTOOMOOOOOOOOOOGOGGGGGG@GGGFG@FFFFFF=F2F=2F=2=2=2/22/2/2.2/2/1/2/2/2.2.2.1.1/1.1.2.1..1/1/1/1/./1../1.././../2././......... .. ( ( ..((.((.*(**/**8/***/**/8*8=88=8888=98=9=99@9=9@9@9=9@8@9=9@9C@:@CCCC@CCCLCCLCCLCLCCLCLCOCGLGLCLOLLOLOLOLOLOLGCCGCGGCGGLGOCGGCGGGOGOGOOOOOGOOOMOTOOMOTOTTOOCG@G@==2/=/=///////=//..././////////=//=/=/=/=G@G@@=/=///==/@@@@C@@@./=.(. (/=//( *// (.*//.*..(.*.(/.(..*.(/.*/.(..(...*.//*.//(./(///===/=========///======8=====/8/=*=/8/=/8//8/8===8===========@=@@=@@@CC@CCCC@CCCCCCCCCCCC@@C@@@@@@@@@C@@@@@@@C@CG@GCGLGCOCOC/*/(/*/(./(.(.(*.*(.*.*.*(((.(.*((/*.**/*/8=8=@@9@@@@@@=9@@@@CCCCCCLCLCLLCLOLLOMLMOMMMOMOMMTMTTMTTVSVVVVXYYY[Y[Y[[Y[Y[[[Y[[[Y[[[[Y[[[[Y[YYYYYVVVVVVTVTSTTTTTTTMTTMOTTTTTOTTOTOOOOOOOOOGOOGGGGGGGGGFG@GFGGF@FFFFF=2F2=2F2=22/2/2/2/2/2/1/2/1/2/2.2.2.2.1/1/1.2.2..1.1../1/../1......./.../...../....... ..  ( ( ( ((.(((/(**/***/**/8**=*8*=8*8=888=88@8=99@99@89@99=99@9=9@9CCC@:CCCCCCCCLCLCCCCLGLCLCLGLCLLOCLOLOLOLOLLOLOLGGLGCGLGCGOCOGOCGOGOGOGOOOOCGOMOTOMOOOTOTOMOOC@G@F===/=2=/=////==/.../././=//==/=/====/===GCCCG@===/===/=GCOCCGC=/==.(..(====/.*/=(..*////(.(/.*/////*///*///*//(//*////=//*//////*//@===@@=@=@===/=*@@@@@@========8=====8/=8==8======@=@@=@@@@@@@@@@C@@CCCCCCCCCCCCCCCCCCCCCCC@CCC@CCCCC@CCCC@C@CGCCCLGLOLOLOLO/(/**.//*.(.*.(((.(((.(((.(((((.((.*((.(***/8=8=@8@@@8@@@@@@@C@CCCCLCOLCOLLLLLLOLMLMOMMOMMOTMTTSTSTVTVVVVVXYXYYXYYY[YYXYYYYYX[YY[Y[YY[YYYYXYYVVVVVVTVTVTSTTTTTTTTOTMTOTMTOTOOMOTOOOOOOOGGGGGGGGGG@GGGFGFGFFFFFF=F2=F2F=22=22/22/2/2/1/2/1/2.2/1/1.1/1.2.1.2.2..2..2..1..1...../../........./........ .( (   ( (.((.((.(/(*/**/***/*8*/88*=88=8=89=88=9=98@9@9@8@9@8@9@9@:@C9CCCC@CCCCCLCCLCLCLCLCLCGLCLGLLLOLLOLOLOLOLOLOCOCGLGCGOCOGGLGGCOGOGOGOOOOCGCOOTTOTOTOTMOTOOCG@G@=F/==2=/=///===//.../../////////=/=/=/===CGCGC=/////=/=@CGCGC@C/==/(.(. */=/(.(//.(.(//(.(..(.*.*/(..(/(.*./(.(..(.(./*./*//*./(//*/==/*========/*/========8==*//*//*//*/*//*/*=*=/8====8=======@@=@@=@@@@@@@@C@@C@C@@C@C@@@@C@@@@@@@@@@C@@@@C@@@@@CGCCGCCCGLGC*/(/*//(//.(.(.(.((.(((.((.(.((.*((.*(*.*.*=*=8=@@9@@@@@=@9@@@C@CCCCLCCLCLLOLOLMOMOMMOMMMTMTMTMTTVTSVTVVVVYXYYYYVXYVYYYYXYYYYVYYYYYYYVYYXYYYVVVVVVTVTVTTTTTTTTMTOTTOTMTOTTOTOOOOOOOOOGOGOGGGGGGGGGG@GGFGF@GFFFFF=F2F/F2F/2=22/2/22/2/2.2/1/2.2/1/1/1/1/1/1/1.2.2.1.1./.1./1........../.../..........( . ( .   ( (( ((((/(*.**/**/*/**=*8/888=8888=888=98@8@9@9=9@9@9@9@@:@C9CCCCCCCCCLCLCLCLCLCLGLCLGLLGLOCOLLOLLCOLOLOLOLGLGOGLGOCOOGLGOGCOGOOGOOCFGOOMTOTOOMOTTOTMOG@G@F@=F=2===2=/=/F=//../..////////////////./=F@@@F////././===@@@=@=//.../(//.*.(.(./(/.( .((.(.(.(..(.(.(..(.*.(..*./*./*./(././*/==.========//(///8/*=/8//=*=/=*//*//8/*=*=/*/*//*=/8/=*/=8=/============@===@===@==================================@@@@@@@@*/*/*///(//*.(.((.((.(((.(.((/((/*(/(**/**/8==8@=@@@@@@@@@@=@@C@CCCCLCLCOCLLLMOLMOMMTMOMTMTMTTSTSVTVVVVVVVVVYVXYYYYYXYYYYYXYYYYVYYYYVYVYVYVYVVVVVVTVTVTTTTTTTTMTTOTOOTOTOTOMOTOOOOOOOGOGGGGGGGG@GGFGGFGFFF@FFF=F=F2F/F2=22/2/2/2/22/2/1/2.2/1/2.2/1/1/1/1.2.2/.2./.1....1.............................     ((.(((.*(**/****/**=*8/888=8=888=88=8989=9@9@9@9@@9@9C9@CC9CCCCCCCCLCLCLGLCLGLCCOCLCLOLOLOLLGLOCOLOLOLOOCOCOGLGOGLOGOCOOOGOGOOGC@GLTOTTOOMTTOTTOOGCGC@F===F==2=//=/===///./..//////.///////////==F@F///.././.===@=@@=/./(.  *./(../* (..*/.(..( (/.*..(.(..*.(.*..(.(.*./*/./*./(//./==/*========/.*///8/=*=/8//=*//*///*/*/*//*/*=/8//*=/=/=8/=/8=/==/=========@=======@===@============/=================@F=@@=//*//*/////.*.*..(.((.((.(((.*(*(/**/(**/*/*==8=@@@@@@@@@@@@@@@CCCCCGCLCLLOLOLMOMOMOMMMTMOTTMTSTVTVSVVVVVVVXYVYYVYXYYYYXYYYYYXYYYXYVYVYVYVVVVVVVVTVVTVTVTTTTMTTOTMOTOOMOTOOOTOOOMOOOOOGGGGGGGGGGGFG@GFG@FFFF@FF=F=F=2F2=2=2/2/2/2/2/2.2/2.2.2.2/1/1.2/1/2.2./1//1.1.1.1.....1......./.... .. ...... .(      (((((((/*(*/*/***/8*=8*=*8*8/888=888=98@98@9@9@9@@:@:@C9CC@CCCCCCLCLGLCLCOCLCGLCLOCOLLLOLOCOCOCOLGLOLOOLGOCGOGLOOOLGOOGOOGOO@GFGOOMTOOOMOTOTOTOCGCG@F=F=======/=/F==//////.////./////////////=F@@@=////////==@@@@@@=/=/(.( //(/.((//(..(//(/ ((.(.*.(.(/(.(..(/.(.(..*./*./*//././.*//==/=========/*.=*/=*/=*=/8///8/=*//*/*/*/*/8/*//8//*/==/=8==/===/=========@===@===========@==@======================@=@=@@F@///*/////*/*.*/(/(((.((.(.(((/(/**/**/***/8/8/==@@@@@@C@@@@@@@C@CCCLCLCLGLOLLOLMOMMMMOMTMTMTSTTSVTVVTVVVVVYYXY[Y[Y[Y[Y[YY[YY[Y[Y[[Y[Y[Y[YYYYVVVVVVVTVTTTTTTTTTMTOTTOMOOOOMOOOOMOOOOOOOOGGGGGGGGGG@GFGFFFGF@FFF=FF=2F=2=2=2/2/2/2/2/2/2.2/1/1/2.2/1/2.2.2/1/1/1/1/2../....1......./...... .. ..... (.      ((.((/**/***/***=*8*8=8=88/88*=88=898@998@9@@9C9@:@CC9CCC@CCCCCLCLCLOCLCOCLCOCLOLOLOLLGLCOCOCOLGLOLOOLGOCOGOLOOOOLOOOOGOGCF@GLOTOMOOOTTTOTOOCGG@F@F@F=F==2======/=//////////.//////=/====@GCGCO=======/@C@CCCCCC===/==.(===/=(.*=/((.*/*.*.(.(.(.(/*/(/.*./*/.*./*./(.*/.*/.//*..////===/===@=@===//*===/=*==8====/=*/=*//*/=*/8/*/8/=/8/===8=====@==@@=@=@=@@@@@@C@@@@@@@@@@@@@@@C@C@@@@@@@@@@@@@@@@@@@@@F@CG@GCC/////*/*//(//*.*//(/((.((.((.**/*=*8/8*=*=====8=@=@@CC@@C@@@@C@C@CCLCLCOLLLLOLOMOMMTMOMMTMTTMTTSTVVSVVVVVVXY[Y[Y[[[[[Y[Y[Y[[[Y[[[[[[[[[[Y[YYYYYVVVVTVTVTVTTTTTTTMTOMOOOTOOOOOMOOOOOOOOOGOGGGGGGGG@GGFG@GFFFFF@FF=FF=2=F/2/2=2//2/2/2/2/2.2/1/1/2.2.2./1/1/1//1.2.2.2.1.1..... 1........... . ... ....     (((((/*(*.***/***=*8/8*8=8*8=*=88=889=99@9@9@9C@9C@C:@CCCC@CLCCLGLCLGLCLCGLCOLLGLOLOCLGCOCOCOCOLOOLOOCOOGLOOOOOOOOOOOOGCF@GGOMOOOOOTTMTOTGGCG@G@F@=@F=F===2==F=/=//=///=///.////==/=F@=FLLGLOC@@=@@===COCOLOLLO=@====//@@===*/==*/(/=/*//(.(.(.*/=///*///*///*///*////*////////////==@@=@@@@@@@@==/=======8=====8====/===8/8==*==8===/==8===@@@@@@@@@@@@@@@@@@CCC@C@@@@@@@@C@CC@CCCCCC@@@@C@C@CCGCGCG@G@GC@GCGCOC//////*/(//(/*//*/*.*.(((.((.(***/*=*/8/*/8/====@@@@@C@@@C@C@CCCCLCOLLOLOLOLMOMMOMTMTMTTMTTSTSTVTVTVVVVVVVVYXYYYYYY[YY[YYYYY[Y[Y[[Y[YY[YYYYYYVVVTVVTVTVTTTTTTMTTOTOOMOOOOOOOOOOOOOOOOGOGGOGGGGGGGGFGFF@FF@FFF=FF=FF/F2=2=2/2=2/2/2/1/2/1/2.1/1/2.2/1./1/2.1//1/./1.1.....1............. .. . . (. ( .   ((.((*.**(/(**/**=*88=*8*=*8*88/88=89@89@9@:@9C@:@C@:@CCCCCCCLCLGLCLGCGLCOCOLOLCLOCOCOCOCOCOLGLGOLOOOLOOOOOOOOOOOOOOOCF@FCOOOOLGOMTTOTTOGCGGC@F@F@F@@=F=2====/=/=/////=/./////////====@GCCGC=====@==@CCCGCCGL====@=/*@@====(/=*.(/*//*/((.(.(./*/(/./*./(/.*..(/.(.*./(//*//./*///==========@===/*====/8//8/=*=/8//*/*//*//*/*/*//*/8//=8=======@====@=@@=@@=@@@@@@@@=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@C@@@@@@@CCCG/////*/*/(/*/(/*//*/***.(((.((/**/8/*=*=*==/==/==@@@C@CCCCCCCCCCLGLLOLLOMOMOMLOMMTMTMTMTSTMTTSTSVTVVVVVVVVVVYYXYYYXYYYYYXYYXYYYYYYYYYYVVYVYVVVVVVTVVTVTTVTTTTTTTMTTOOOOOOOOOOOOGOOGOGOGGGGOGGGGGGG@GFGFGFF@F=FF=F=F2=2=2/2=2/2/2/2//2.2/1/2.2/1/2.//1/.2.2/1/.1.1/../1...... .......... . . .. ( .(   (((((.**(*/**/**8*8*=8*8*8*8*88=88=989@9@9@@:@@:@C@C@CCCCCLCCOCLGCLCCOCLOCOLGLOCLGCOCLGLGLOLGLOOLOOOOOOGOOOOMOMOOOLF@@GOOLOOGCOTTTTTOOGCG@F@F@@F@F@F========/=/==/===///.///=//=====@@@=@=//=//=/=@@@@@=@@@/=(=//(.==*//(.(/(.(/*/*.(.(( (/./(/.*/.*/.*./(/.*..*./*/./.*/.//.//==@====@=====//===*=/=*//8//*=/*=//*//*=*=*=/8/=*//*///*=/=========/====/===========/=========@=======/======@==============@@//=//**.*.*/.*/*//*/*/**/(((.((.**/**=*=/=8/=/===@=@@CCCCCCCCCCLCLLOMLOLMOMLMOMTMOTMTSTTMTTMTTTSTVVSVVVVVVVXYYYXYY[YY[YYY[YYYYYYXYYYVYVVVVVVVVVTVTVVTVTTVTTSTTTTTTMOTOMOOOOOOGOOGOGOGGGGGGOGGGGGGGGFG@FGF@FFF=FF=FF=2=2=2=2/2//2/2/2//2/1/2/1/1/2/1/1/1./1./1.2/1.1/1..1...1..0...... ... . . ( ( (   ((.(((/((*(**/**=*8**=*8*8**88*8=88=98@@9@9@C9C@9C@CCCCCCCGLCCOCCLCCLGCLGLCOCLGCOCGLOCOLOCOLGOLOOOOOLOOOOOOOOOTOO@G@GGLOOGCGOMTTTTOOGGCG@F@@F@@F@F=F==F====/===/===///////=//====/=@F@=@///*///==@@=@=@=@=///=*.*/==*//((/(.(.*/*./*.(.(.(/*/.*//*/.*//(/.*./(//*./*////(/.////@===@====@==///=====*/=*//*=/*/=*//*/*//*/8/*/=*/=/8/=*/=/==/====/==/=/===/==========/======@==@=======/====================== \ No newline at end of file diff --git a/data/icons/recording.raw b/data/icons/recording.raw new file mode 100644 index 000000000..f5123ea2c Binary files /dev/null and b/data/icons/recording.raw differ diff --git a/data/icons/right.raw b/data/icons/right.raw new file mode 100644 index 000000000..5022257aa Binary files /dev/null and b/data/icons/right.raw differ diff --git a/data/icons/rot.raw b/data/icons/rot.raw new file mode 100644 index 000000000..8d0b5386c Binary files /dev/null and b/data/icons/rot.raw differ diff --git a/data/icons/scan.jpg b/data/icons/scan.jpg new file mode 100644 index 000000000..7b7f62f1d Binary files /dev/null and b/data/icons/scan.jpg differ diff --git a/data/icons/scan.pal b/data/icons/scan.pal new file mode 100644 index 000000000..bd5edc061 --- /dev/null +++ b/data/icons/scan.pal @@ -0,0 +1 @@ +e+AH,]GH&E]ba&fFL pir5#:G`6PP#o$06mD)b2.O@|'@@O,^2#V`}zkŽzk]O@2ˆ#]O@2##S##>#668‰z$1—59Vk#k]#O#}#]&7ƒ’˜³%2bLSj5«@#O#k2Ž2r#]2#@(M‘3M{#3O G›#O2]kž5pEj•Odb³"Ci#@#2O#2H}#2?7]*]†U‘¶5Oh˜„¾,k‘E~ #22@ª¯²¼ÄÇc…,¤+z–e¨Àf˜¨4@~œ'ªÊE™­,™«Oz‚˜ª{‡R‰22##2YY##32%wPw}zAoS‘¨•]]}˜}12#ª¨sÝÛËÛ΋ܷHÛ»k¼™H·™jÙE]E"Å«‡Ò†,o7¸€?H4סcbBªˆb–|`”Žˆ×„CćZ¶g4Ôb$ªN†C+#K#TLK}KG***,,*,,**,***,****************************)*************************************************,**31*,,............,,,.,,,,,***,***,*,,,*,,,,,,,,,,.,..............,,,******************,*,,,,,,,,***1***************,,*,*,,,,,*,,,,,,,,,*,,,,*.,.,....,.,,,,,,.,,.. \ No newline at end of file diff --git a/data/icons/scan.raw b/data/icons/scan.raw new file mode 100644 index 000000000..d4894dee8 --- /dev/null +++ b/data/icons/scan.raw @@ -0,0 +1 @@ +Ð@ÿjwjwjwzcziNNNiixNxQQQxQxQQz|PQxIxQQNQNNNNNNiN…N…ziwwwwwjwjwwwjwjdwjwjwjwwwwwwjjjjjPjLjLa‡¤¤¤µVQNPPLzNNNjLLNNLNLLLNNNNNNNNNNNNLP8P8NNNNNzNzNzNNNNiNNNNNNNNN2NNNP.<.22282NINN2QQNQNNNNNNziwjjjjjwjwwjjjjjjjojwdoddodwojojojojowjwwjwjjwjwjwjwjwjwjowwodododdddwddddjjjjjjjjjziN…NNi…NxxzzzQxxQxxQxxxQQxQxQxxQQxNxxxxxxixxxNxiNixQixxiNizNiQiiQixNzzii……N…N…Ni…N…N…i…i…i…i…i…zwzcw…wjwwwwwcimtaVjicjwwwjjmdjcjjjwwjjjj…c…wj…i…iiiiiixiixiiiiiii…iiiiii…iwwwwwwwwowdododdodododoowowojwwwwwjwwwwwwjwwjwjjjdjjcjVtq_µt|LjLjmmjjwjjjjwjwjjjjwjjojdddjddddjjjjjjjjjjjjjjjjjwjjj…N…NzNzNzLzLPLPLPjNj…jwjjjjwjwwwwwjwjjjjjjwjwj…jjjjjzN…zLzLjjjwwwwijwiijmmmdjcjjjwjjwjjwjjwjjwLjjjwjjjwNjjjjjPjPjjjjjjjjjjjjwjjjjLjNjNwzLzzzNNNzNzNzNNNNNNNNNiNiNzNNNQ%%wLwjwiwzczwN…NiNiQixQQxQxQNPPzQQIxQxNQQNQ…N…iN…N…ziw…wwwjwjcwwdwjwwjwjwjwjwjwwjjjjjPjLNa_¤¤ˆµVQNPjzNijNjzLLNNLNLN5GNGNNNNNNNN2LP8P2NNNNjzNzNzNziNNNNNNNN2NNNNN2P(.82222NQiQ2NQQixzNNzNjzijjwjwLwLwwwjjjjdwowdjodjodwojojojojowjwwLwjjwwjjwLwjwdwwowdojodydojdodddwjjjjLLwNwziNz…Ni…xQzPNQIxQxQxQxxxxQxQxQxxxQxNxQixxxxxixxxNixxzQiiiNizxzxNiQiNN…L…c……i…N…Ni…N…N…N…izi…N…N…iwzcL…wjiwwL…imaa|jizwjwijjmdjjwjwjwwjjwciwNwi…ii…iiixixiixiii…i…i…ii…i…ii…w…c…cwwdowjojoydojodwojojojodwjwwwjwwjwjwjwwjwdjjjjLdVtµ_qamLLjjmmjiwLwjwLwNwwjojwjwdŽwojwjjdjPdjjLwjjjjjLwjwjjiwNj…N…zi…N…zLzLz2PNjziL…zwjwjwwjwjcjcjwcjwwjjwNwL……jzjzzczwLwLjjwwwiwwjwLjmmmjLjwjwjwjjwjjwjjwjjcjjjjjjjjcjjPLjLPjPjjjjzwjjjjcjcwL…jiwNwNwzcNjiiiNNNzNNšzNNNNizzx˜iNiNQNjwwwjwwj…L…iN…NiiizNxxxNQxxxQQšPPzQMMxQNzQNxNxN…iN…iwNwL…wwcwjwjwdwojwwjwwjwwjwjwjLjjPPPNVq¤¤ˆ-VNNPjLLziLNLLNiLNLLLNNNNNiGNNNNNLNP8PNPNNzNLzzNNzNziNzNPNNNNNNNNNNPP<.25N2NGQN,QQNQNxNNNNzNj…jjjjwjwjjLwjjjwjjdwododojojojojowwjwojjwjLwjwcjwjwwjwdwwwdddjdwyddwdwdojjwjjjjjwN…i…NNizNxxQzzQIxxQxQxQIMMxQNQNQQxxxxixxQxxxNxxxNiixQxzxziiiiQxNxNiQ…Nii…jiiiNiiziN…iii…iii…ii…izwzc……jiwjwjwL…LjjLzjcjwwijdmjjcwjww…cjczwi…izwii…i…ixixixxixixixiiiiii…iiwzcwjwwjwowdod€dwoyoyoyd€oo†odwdwwjwcjwwwwwwwjwjwdjdjLjOaqa|iLjmmjwjijwjjjjwLjjjjowwwjojwwdjjdjjjjjjjjjjjjLwLwijjwzLzjizNizLzjPPLLPNLi…jwNjjwjjwjwjcwwjjcjjj…jwj…jLwLjjzijijjjjLwwwjwiizymmjciwjjcjcjcwLwcjcjcjwjjdjjLwjjjLLjPjjjjjjjjjLjLzjzjwjzjcjjjwzczLzjjNxIINNzzNNNzNzNzNizxxxNNzNjLwzcw…wwwzwwL…i…NzixIxNQQxMIMQP.|NQIIxQxQxQiNiNN…N…Nww…wwiwwwwwdwwjwwjdwjwwdwdjjLjjPPPdPVa__µa|2PjLNzzLzNjNLLNLNLNLNNNNNNixGNNNN8N8NNNNNNzNzNzNzNzNNLzN2NNNNQN2N28.V.2NNNQNxIQNQNQNNzNzNwzNL…wjjjwjwwjjwjddwowddjojojojojdwjowowjwjjwjwwjwjjcjwjwwwoydydodddodwyoowwjjLjcjj……izxz…NixxxzPNxQNxIxQQxMIQQQQQQxQxQxxxQixxxxxxxxNxxxNzNixixN˜ixNzQzNiiijw…ix…iziN…izizii…i…N…izwzc…jwiwjwwjcwjiIxijjjwwcwjymjjcjwwwcj…wjiwiwiii…iiiiiixixixiiiiiii…ii…ii……cw…wwjwjwdojojoydoddojodwyodwdwwjwwjwwwjwjwjwwjjjjjjjjjVataVjiLmmjcwijwLjwjwjjwjojwjwjowwwjwjjjjjjjjcjjjLwjzj……NwzNziziziN…NzNPNPNPNLzizczwjczLwjjjLwjwjwjjwcwj…j…L…zzjjcjwjjjLjwwwjwzcjdmmjwiijjcwwjwjjwjjwjwjwjLjmmjwjjjjjjLjjLjjjjjjLjjjjLwjwNwcwj…L…LzczjNLNNNQQzNNLjNNzNzNzšzQxxizzQwjjwwwjw…c…wN……Ni…iiNxixNxIQQxQxQP.|zQMIxQNxišNzii…i…wzwjww…wjwjwwjwwdwwjwojjdwjjjjjjOdPPPVVaaPPPjNjjjcjiLNLNLNLLNLNNLNLNiNNNNNNPLNNNNNNzzNjNzNNzNizNzNNzNNNNQN82828<//00/00000000000<ƒ‘„s„„„„„–‘t;9966666O<///0//////6///++4s„‘„„„„„„–s–‘t60966:888K8L8d8LLLLLLLddjKddcccdm``LLiy~„~~vvvv~s„lyKjyddydddddydyddyydddydddmjNyv~‰{~ƒ‰vyLLjwwwiN…w…cwciiiiiiiGIivƒƒvvvƒ~wIMIGIMIx……Nj†OPLiiIIm–Ÿ£¾GGi……cwcw…cccccwcwcwcwcwcwcwcwdwLwLwcLjdKwija_ˆˆ-VNLLjjdOLjLwLwjcjcwLwjcjjLLjLjLjLoodjdodjcjojjwjcwjwdwdjdjwdwwwwwwwdjdjdwdGw}‰•••‰pcLjoLdjdjowjdjdwodmp€}}}}Lor•pL8OddddddddddKocwowoojowwdowocoj[wwwwwwwwcwwjwjjjjjwjjjNiwvŠ„ƒ~ƒŠ„„vjNjmmmmmmmmmOmjmmdjNNmƒƒŠ‹‹ƒ„‹Š„„viIjjciicciiiiiiiiiiiiiiiiiiiiiiLjjjd|//4//////0;00:0:0;6/<0+lŠŠ„Šƒ„ƒs‹‹„„„v95LLLLLLLLLLLddddddOOOOOddddddocwwwcGov‹‹{v{vp~ƒƒ~yjdmdyjdyddowwcccccicccccccGcwv•‰••{wGccwccwcccwcLc[LjwwwjKNj{~~v{‰~{}d¾´³³´¾4;/;;;:0;;3474/;00:0::6;;;3600:0;0;0;;000;/4744/;;6::9::9Oƒ’ŠŠŠŠŠ„ŠƒŠŠŠƒpGGLLcccFGFcccLdOm`m]ddddccccc[cccccGG}•‹‹•‹vyLdod[[[o[o[cc[c[ccKLow[oocFop{‰{{‰{{€KLo]]O]pXmp`ppp]dodd[ccc}‰•‰‰••‰}FcccocFGF}•••‰}KFjddOyddddddddddwwcwccccccccccwccccccccccccocw[w[[w[wdwKKoKddd[cj[KdjKddddojoojo[j[wKwoK[Loddo[w[o[o[c[cKoc[o[[d[j[co[ccLK[[woo[EEO-®­¸®¯¯¯¶ª³“u~«»¯¯³·±¦¦¥µJDYodo[[o€€}}€o[o{‹Šlsa`FFFO`^……¥ßï ""++//(001110(/.......././///((001111))**''22 33þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 22''**))111100((//////////./..../(011111(&/&("" áß¹¥…………¥¥ïï #"(/&/(011111(/.....//////////&&((0011))****'22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2''**))111100((////.////&/(/(//.../&001110(///(," ïߥ¥……………¥ßï "",+//(001110(.....//(/(////././/&&((0011))**''22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 22''**))1100((&&////.//&&((0(0((//../(011110(&/+&""ßß……………¥¥ßï "(///(011110(/...((0(0((((////.////((0011))))**'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''**))110000////./././/((0(00000((//./(001110(///(( ïߥ¥……>……¥ßï ""++./(001110(//./&0000000((/&//./././/((0011))***'22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2''**))1100((/&//.&/&&((00101011100((///(0111#0(&/&("" áß¹¥…………¥¥ïï #"(/&/(0111#0(/./&001#1010100((&(&&/////((0011))****'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**))11##((&///.///&((000000101110100&///(001110(///(," ïߥ¥……………¥ßï "",+//(001110(///((00101#1010000((&&//././/((0011))**''2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**))1100((//.////((((00##1#11111111#((///(0111#0(&/+&""ßß……………¥¥ßï "(///(011110(&/&&001111111#1#10#"0((&&/&.//&&0011)))*''22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22''))))0#00//././/&/((0"00####111111100&/./(001110(///(( ïߥ¥……>……¥ßï ""++./(001110(///((0011111###0#"0((((//././/((0011))**'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 22'*)*)100((/////&&((0"00####11)111)11110(///(011100(&/&("" áß¹¥…………¥¥ïï #"(/&/(011100(&/&(001111)11)#11####"0(((&/&///&(0011))**'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ33 ''**))1100((//.//&&((0"####111#100&///(001110(///(," ïߥ¥……………¥ßï "",+//(001110(///((0#111####"0""((//././/((#011))*'22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2''**))110(&////&/((""###1)111#10(///(0111#0(&/+&""ßß……………¥¥ßï "(///(011100(&//(001111))####"0((&&/&.//((0011))**'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22**))1100((//.//&/((0"###1100(/./(001110(///(( ïߥ¥……>……¥ßï ""++./(001110(///(0#011##"0""((//././/0011))**'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22**))1100((///&/((00#####)1##0(/&/(011100(&/&("" áß¹¥…………¥¥ïï #"(/&/(011100(&/&(001#11###00((&&/&///(011))**''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**))1100//////&((0"####00(///(001110(///(," ïߥ¥……………¥ßï "",+//(001110(///((##1#"0""(&//.//((0011)*''2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**))110(/////((""#"#1 1##"(///(0111#0(&/+&""ßß……………¥¥ßï "(///(011100(&/&(00#1 ###"0((/&///((0011))''22 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2''*)1100((//.//((""##  #"0(&./(001110(///(( ïߥ¥……>……¥ßï ""++./(001110(///((#  #"0((&&.////(011))**'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ ''**)100((/&/&/((0"###   1##"(///(011100(&/&("" áß¹¥…………¥¥ïï #"(/&/(011100(&/&(001     1###00((/&/&&(011))**'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 22'*))1100&/.//&&((0"# ïï #"0(///(001110(///(," ïߥ¥……………¥ßï "",+//(001110(///((# áïï ###"0((/////((#01)**'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'*))1100&//&/((0"### ïïïïïáá 1##((///(0111#0(&/+&""ßß……………¥¥ßï "(///(011100(&/&(0"# ïïïïïïï ##"0((&&///((01))**'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22**))110(//.//(&""##  ïïßïß¹ßïïá #""(&./(001110(///(( ïߥ¥……>……¥ßï ""++./(001110(///((# ïïß¹ßïßïïáï #""((/&//./(0011**'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22'*))110(///(&((00#1  áïï¹ïß½ßïßïï ###"(///(011100(&/&("" áß¹¥…………¥¥ïï #"(/&/(011100(&/&(001 ïïßßßïßïïïï ###"0((/&/&(0011**'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**))1#((///&(((0"# ïïß¹ßߥßßñßïï #"0(///(001110(///(," ïߥ¥……………¥ßï "",+//(001110(///((### ïïßßßßßßßßßïïï ##"0((//./&0011))*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**))10((///((0"### ïïßïßߥßßßßïï 1##"(///(0111#0(&/+&""ßß……………¥¥ßï "(///(011110(&/&(00#1 ïïß½ßߥßßßßïïïï ##"0((/&/&&0011)*'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''**)100(&///&(""## ïïßïßßßߥßßßß¹½ïï #00(/./(001110(///(( ïߥ¥……>……¥ßï ""++./(001110(///((### ïïßßßߥߥßßßßïïá #""((+&.//(011))*'22 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**))10((/&/((0"### ïï¹ßß¹ßߥ¹ßßßïï )1##0(///(0111#0(&/&("" áß¹¥…………¥¥ïï #"(/&/(0111#1(&/&(001#1 ïïßïßßßßßßßßßïßïï "#""((/&/0011)**'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''**1100((/&/((0"#ïïßߥߥߥßßßßïïá 1#00&/./(001110(///(," ïߥ¥……………¥ßï "",+//(001110(///((##1 ïïßïßߥߥ¥¥é¥ééñßïï "-",&///(011))*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**))00((//&((0"## áïßïßߥߥߥßßï½áï 11##((///(011110(&/+&""ßß……………¥¥ßï "(///(011110(&//&001#1  ïïßñé¡¥¥Ý¡¢ééñßïñ #"",(+&/(011))*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''**1100///&/((0"# ïïßߥߥé¥ß¥ßßïßïá 1###((//./(001110(///(( ïߥ¥……>……¥ßï ""++//(001110(//./(00##1  ïïé颢ݢݢݢ¢é¥ñßï -",(++/((11))*'22þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**))00((/&(""### ïïß¹ßߥߥßß½¹ïï )1#1#100&/.//(011111(&/&("" áß¹¥…………¥¥ïï #"(/&/(011111(/.//((0#1#11 ¹¹éé¢éÝ¢¶¢Ý¢¢ééñßïï #"",(+&/(011))''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''**1100&&/&&((0"# áïßïßߥ¥¥¥¥ßßßßïï ###0#0(&/.../(011110(///(," ïߥ¥……………¥ßï "",+//(0011100/....((00### ñßñééÝݶ¶¶¢¶ÝŸ¢Ýééññï$",(+&/((11))*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**)100((/&(""0# ïáïßßߥߥߥßßïïá 1###00((&/.../&0011)1#((/+&""ßß……………¥¥ßï "(///(011)110(/..//((00#0###ññé¡é¢ÝݶݶŸ¶¢¶¢Ýééññïï"",(+&/(011))*' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**1100///&/("0"# ½ïßߥ¥¥¥¥¥¥ßßïïá ##"0"0((//..../(011)110(///(( ïߥ¥……>……¥ßï ""++//(0011)00(&.....&&((0"## ââñâñééÝéÝŸè¶Ø¶ ¶¶Ý¶¢¢¡éï$",(+&/((11))*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 22**))#0((&((0"## ïïßߥ¹¥¥¥¹ßßßïï ####"0((&&//././/(011)))11(&/&("" áß¹¥…………¥¥ïï #"(/&/001))))10((//.//&/((""""#òââßñé¬é韢¶¶ØŸØŸ¶¢Ÿ¢éññïï#""((+&/(011)*'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**)100(&/&&("## ïïßߥ¥¥¥¥¥¥ßßïï ##"0((((//././///0011)))1100///(," ïߥ¥……………¥ßï "",+/&(01)))1)00((//././/+,(,"$òÑâââââñééééÝݶŸØ¶ØØ ¶ Ÿ¶ÝÝééññ$",(+//(011))'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**))10((/&(0"### ïïßߥ¥¥¥¥ß¥¹ßáá ##"0((///&.//&&((0011))*))11((/+&""ßß……………¥¥ßï "(///001)*)*))1100((/+++.+,,$Òâѽâߥßââ¨ñééé¡ÝݶŸ¶¶ ŸØ¶ Ÿ¶¢Ý¡éññ ",(+(+(011)*'û ý44ööö4ööööööööööööööööööööööööööööööööþöþöþöþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22**)100(//&/("# ááßߥ¥¥¥…¥¥¥¥ßßïá  #"0((+&//...//((000011))***)10(///(( ïߥ¥……>……¥ßï ""++//(11))*)*))1100((,,-.--%ÒѨ>¨¨¨•…¨¥•é¨é•éÝõèÝèŸØØ ¶   ¶¶¶¶ééßñï$"-,,,,"$1)!úûüvÊêxÊxÊóxóxóxóxóxóxóxóxóxóxóxóÊóxóxóxóxóxóxôxôxô4ô4ö4ö4öôööööööööþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'*))10((/&&0"## áïïßߥ¥¥¥¥¹ßïï ###"0((&&/&.//&&001011))**'*'**11((/&("" áß¹¥…………¥¥ïï #"(/&/00))**'**)*))11#0$0--ÒѨ¨•¨}>}>•…•……Ý•ÝõݬݟèÁØØØ؆ؠŸØŸ¶¡éññ$",,,"#1)!úûîîÊÊÊÊÊÊóÊÊÊÊÊÊçóÊóçóÊóÊóÊóÊóÊóÊóÊÊÊóÊóÊóÊóÊóÊóÊóÊóxóÊóxóxóxôxôxôôôxôôöôööööööööþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ32'*))10((/&/((0"# ïßߥ¥…¥…¥¥¥ßßßï ##""((//././/((0011))))**'''**)100///(," ïߥ¥……………¥ßï "",+/&(11)*'''****!)1%%¨¨DDCDCDCCCDfww}}»»Ý•ÝèõèŸèèØ؞؞  Ø ¶èÝÝéñï$$-----"$)!úyîyîvççççççççççççççççççççççççççççççççççççççççççççÊçÊçÊçÊÊÊçÊÊÊçÊÊÊÊÊÊÊÊxÊóxóxóxôxôxô4ööööþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ ''))1#((///("0# ïß¹¥¥¥¥¥¥¥ßß½ï #"0("(&/&.//((0011))*)**''22 2'**11((/+&""ßß……………¥¥ßï "(///00))''222''ú*!!ã½>?CB7B777B7A7BBCCww}»Ý•ÝèõèŸèèØ؆؞†ž† ¶¶¢Ýééï$$---#1)!úúì’vvìvìvçìçìçìçìçìçìçççççççççççççìçìçìçìçìççççççççççççççççççÊçÊçÊçÊçÊçÊÊóÊóÊóÊóÊóxôxôôöôööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''))11((/&/((0"# áïßߥ¥…¥…¥…¥¥½ß #"0((//...//(,#01)****'' 2 2'*))00///(( ïߥ¥……>……¥ßï ""++//(11)*'2 üüûú©©¾ѨDC77@777777777;7;77BCww»»èèŸØèØ؞ܞžžžžžžØØŸèõéññò%$$$--$!©ÏÏyy’’’’’’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ìvìvìvìvììçìçvçvçìçìçìçìççççççççççÊçÊÊóxóxôôööööööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**110(/&/((0## ïß¹¥¥¥¥¥¥¥¹ßïï ###"0((/&///((001)))!*ú'û2 3 22**11((/&("" áß¹¥…………¥¥ïï #"(/&/00))*û2üîyyϦ¾\>6B7<7UB=CdC=C6BBAU77;UC„w »èèÁèèØÀÜÜž¿žžžØžØØŸÝééñò $$-$$#!!úÞìÉ’’í’í’í’í’í’í’í’í’í’í’í’í’í’í’í’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’çìç’ç’çìçìçìçìççççççÊçÊÊóÊóxôôôôööööööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'*)110(///((0"# ïßߥ¥…¥…¥…¥ßïï #"""((//.+/(,0#1)!!úúûyüü33 '')100///(," ïߥ¥……………¥ßï "",+++,#1)úûyvee¦©PP>?7<7IB=aTaTdfff6fCdCc7A;7Bdw »ÜØèÜØÜØžžµžµžžžžØØŸ¶õéññò%$$$%$$!©ÏÏ’Þ’É’É’É’É’É’É’É’É’É’É’É’É’É’É’É’É’É’É’É’É’’í’í’í’í’í’í’íÉì’ìÉì’ì’ì’ì’ì’ììççççÊÊÊÊóxóxô4öôööööþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ '**)100///((0"# ïß¹¥¥…¥…¥¥ßßïï #"#""&&/+/++""##))!ú©úÏÞÞîî4þþþ 2**11((/+&""ßß…¥………¥¥ßï $",+,"#)!*úyee‹tnPO6<<<==ZTZZbbbbbbbfbffdaBU;7Bfw »èÜèØèÜÀÜÜžžµžžžžØØŸÝééïò $$$$-$$#!ÏÞÞ’É’É’ÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉíÉí’í’í’í’í’í’í’í’í’í’í’ì’ììççççÊçÊÊóÊóxôxôôööööööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22**)10(//.&(0"# ïßߥ¥…¥…¥…¥¥½ï #""((/&./-,,"$11!©Ï©Ï¦Ì¦Ì’ìêþþþþ3 '*))00///(($ ï¹¥¥……………ßßï $"-,-,$#!!Ϧ¦ttP\N67LI7IIllZZLZLZ[L[[M?[?[b?bbfTffBA;ACw£Ü»èèèØØÜܞܞžžžž  Ø¶ÝÝéñïò%$--%$$©ÏÏÌÞɌɌÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÉÉÛÉÉÉÛÉÉÉÛÉÉ’Éí’ì’ìvììççççÊÊÊÊóxóxô4öôööööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''))11(&/&/("### ï便¥¥¥¥¥ßßïï #"0((++,,-"11©©ÏΦβ²²ÇÇÇDz³vöþþþþþ 2**11((++," ßߥ¥Ý¢Ýé¥ññ %$-$%÷ä÷¾¾mLB6<;<=llllZZLL[?MMMMMMNMMMMbbbbffd=A7;cb£»è»èèèØÀØ؞ܞžžžž  ¶èõéññ%%$---$©©ÏÏŒŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛŒÛ³Û³ÛŒÉŒÉŒÉÉ’Éì’ìvççÊçÊÊxxóxôxô4ööööþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ2'**110(/&/((0## ïïßߥ¥¥¥¥¹ßïï #""((,+,,$#ÎÎà΂˜±±ˆÆ°Ö°Æ±Ú’öþþöþ44ü2ú)11",,,-ñ¹é¡Ýééééññ%%$%ämrL<;VWkl{ZZZ[L[MNMNN€NNNNMNMMMMb?TTd=77B„} »ÝèõèèèèØØØ؞؞† ¶ØŸÝ¡¡ï$$-$$)!©ÌÌÛŒÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÉÛÉÛÛÛÛŒæŒæ³Œ³³³³³³³³³Œ³ŒŒÉe’É’’ìvççÊÊóÊóxôxôôôôööööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 22**110(///((0"# ïïßߥ¥…¥¥¥ßïï "",,-,-$$÷ξËËˤ±ˆ°›››¯¯¯¯°‚’xxxxxxêîû*!1"-,-"$¹éߢéÝééßßïò%%%%%ãͽr[<;O>O>OOOONNNN[M?bbTc<7c”£»ÝÝéÝÝéÝõÝõè¶Ø؞ؠØØŸŸÝéññï òãòÒÒÒã¾¾§Ë²Ç²Ç²Ç²ÇåÇåÇåDz²åÇåDzÇåÇå²Ú²Ú²Ú²ÚàÚàÚ²Ú²²Ç‚tœtt‡tnšmm|m\\\\>\>\>\\\\mmmPnn‡‡ˆˆˆˆÆƱƱ××±ÙÆÙÆ×±ÙÙ××åÇàÇå²ÚÚæÛë³ÛæÛÛÉÉííììççóÊóxôóöôööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'*)11((///((0 ïߥ¥¥¥¥¥ßßï $"-$-$$$$ää¾Í¸·¯šš‘‘™™rrO†M[ZZJLMrmt‹³È³³³¦¦Î©¾%%%$%òòâïññïñâòòãòÒ%ÒÒ¥•N=<;I=lZLZ[?MMNNONOO>O>O>OOOONNNNMM?[Zba=77B”}»»Ý•Ý•Ý»õèÝèèØØØ؞؞†Ø¶è¢Ýñßñââ½âòÑÑÑÑÒÒÒòòãã¾¾ËËלללל××לٱٱٱٱ±±Ù±Ùœ×œÇ×ÇÇǜǜœ±±ˆˆ‡‡nnm|rr>ONN??6?666K666??MNOO>>r\||š|šš¯¯Å›ÖÅÖ°°Å°°ÆÖÆÆٜללà²ÚÈÚÚÈÛæ³æŒÉ’ÉÉí’ìçççÊÊôxó4ööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**)10(///((0##ïïß¹¥¥¥ßßßï "$$-$$$%äͤ·¸·š®|‘™r†M[==I<<<<=N\nœ²ÚÚÈÚÚ‹Î÷%$%%%òãòòòãòã%%%Ò½¨»bI;<=lZ[Z[[MMNNOO>O>O>>>>>>>OONNNNM[L[ZTc<;Ud£»•»ÝÝÝÝÝÝõèÝèèØؠ؞ؠØØŸ¶ÝÝ¡éññâßââÑâÑÑÒÑÒòãͤ¤ËƱ±±±±ÆÆÖÖ°ÖÅÖÅ°ÅÆ°Ö°ÖÖÆ°ÆÆÙÙٱٱ±±±ˆˆ‡›Pš‘\rN[66=6BIPˆ‚²²²‹²‹§Îää%%%%%%%ããòòòââÑâÑòòòòãòò%%ÒѨ>wa;7O>>>>>>>OOOONNMM[[ZZa^SAB”w»»••Ý»Ý•Ý»è•è»ØÜ؞؞؞؞ØØØèÝèÝ•é¨ß¨â¨Ñ¨ÑùÑÑòÑáḸ°¸Å¯ÕįÄÄÄÄÄÄÄÄÔ¯ÄÕÄÕ›ÅÅ°ÅÖÅ°°Ö°ˆÅ›¯š||\rON[L=I7<7<mˆ±ÇDz²²§§¾÷%%%%%òãòòòòòò òãÒѨ…}MI<O>>>>>>>>>>>OONONNMM[[ZlI<;=„££•»••Ý•Ý»Ý»è£ £žž žžž¿žžµ¿ÜØÜèèè•ÝÝ¥¨¥¨Ñ¨ÑÑÑѽ½ººš®®ÃÃÃÃÂÃÃÃÃÔÃÔÃÔÔÔ®ÄÔšÔÄÔÔÔÔ®ÔîÃÑ‘­†[ZII<<;<>>>>>>>>>>OOOONNMM[[ZZJI;Ac„w£»»}»»»»»££w„dƒƒ“µµµµµµŠµµµµžµÜ»»»•»••¨•¨•¨•¨¨¥¥¡¡™¡­­Ó™Â™ÂÂÃÂÃÃÃÃÃÃÃÃÃÂÂÓÓ­Ó­Ó¬¬Á†N[=I;;;<;>>>>>\>>>>>>OONNMNM[L{lXH;A`„ £»»»»»} wwddBAS^ƒ´´µ´µ´—´´´µ“µ“µ“£w£N}N}}}}•}»»…¶¢Ÿ¬¬­¬Ó­Ó­ÓÓÂÂÂÓÓÓÓ¬Ó¬Ó¬¬¬¬¬¬ÁÁ««†«€ZY<;;<š‡ˆ±œœ×œœ¾¾ääòÒ%Ò%Ò%òòòòòòòòòÑòÑòÑòÑòÒѨ¨••}wC;;=JZZ[?MMNNOO>O>>>>>>>>>>>OONONNM[ZZlJI;;_aMwž}£}£¼}ffBAR@5@Ruƒ´´´ŽŠƒƒƒuduupcUcUcCdCdfww“£  Ÿ«Á˜¬Á¬¬¬¬Ó¬¬¬¬Á¬ÁÁ«ÁÁÁ˜Á«Á«˜«À—{{XV;;GHVXXYXkklYXI<;;:;;<O>>>>\>r>>>>O>OONNMM[{ZlXV;HW{€ž£ ££wwdcAA@;RA@Rpƒ´Š‰‰ji__SGRGRGR;RARAApcƒ„““†««ÁÁÁÁÁÁÁÁ«Á«Á«««ÁÀ«ÀÁÀ«À«ÀÀ——{W<;;;VWXYkYkkkYXI<;;;>>>>>>>>>>OOOONNMM[[ZZYW;;HkŠµ€ž““„”c_@@@;S_SR@osƒƒƒ‰‰hhgg99999:9GRGRG@R@@@;ScdŠ“žž†À««««ÁÀ«ÀÀÀÀÀÀ¿ÀÀÀ¿À¿À¿¿¿€€lqH;G;HIWkYkklllY=<<;<>>>>>>>>>>O>OONNNM[[ZZlY<;;W€€—´´ƒƒ_S@:@SApp_RRRsu‰s~ggF989E9FggHHh_VH_SS;;@GRUu„Š—ÀÀÀÀÀÀÀÀ¿À¿À¿¿¿¿¿¿¿¿¿À€€lXH;;<™|š¯Å°ÆÆÙ±×××ÇåÇåàåàȲàÚààÚ²ÚàÚàÚÚÚÚÈÚÈÚëÚÈÚëÚëÛÛÛÉÛÉÉììççÊÊóÊóxôxôôöôööþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöööööööööþöþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**110(///(("" ïïßߥ¥¢é¥ßßïñ%$%%%Òòѽ¥rž[X<<;<<==lYlYkXXWjiihhghgG:VM\š°°±±œ±×±±¤¤ÍäòòÒÑÒÒÒ%Ò%Ò%ÒÒÒÒÒÒÑÑù¨¨¨•¨¨¨¨¨¨¨•••»}“ƒ^;;VYkZZ[?MMNNOO>O>>>>>>>O>OONNNN?[ZZlkVH:Hj{ŽŽŽŽ‰uoRQ@RSApU^_S@RSoggEE8E8EEFFgghhhhisWs^_VSS@@@A^ƒŠµ€—¿¿—¿ª¿ª¿ª¿ª¿ª¿¿¿¿¿€€kW;;;\|n›°°±±×œÇÇÇDzÇಲÇÇÇàÇåÇàÇà²à‹à²à²à²à²à²Ú³Ú‹ÈÚ³ÈæŒÛŒ’Éí’çìççççÊçÊçÊÊxÊxxóxô4ôôööööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöööööôôôxôxôóôöööþþþþþþþþþþþþþþþþþþþöþöööööööööööööþöþöþöþöþöþöþööööööý2'*))#0+++(,""# ßßéé¥é¥ßßï %%$%%Òã½½¥¡ ZX<7O>>>>>>>>>OONONNMM[[ll=VG;hŽ–Ž‰oG9GS__^p^psS:9FFFE9EEEgFgg~g~hzhisuWjWX^^U_;;@ApƒŠ—€——¿—¿—¿—¿ª¿ª¿—¿¿¿¿À¿¿€€kI;<O>>>O>OONNNNM[L[llXVG:Gzz–––hG9GS__pps_hHg998E8EEgEgggggghghhisjWjjXuX^u^U;;@;HXƒŽŽ—ª—ªªª—ªªª¿ª¿—¿ª¿¿€€kW;;HX=llZlZllllYXH;;WZ€«†˜˜ÁÁ¬¬¬Á¬¬¬¬­¬­¬­†MJ7<=L[M?K<<=N>|m¯›ÖƱœ×œÇ‚ÇÇÇÇಲÇà²à²ÚÚÚ²Ú²Ú²Ú²à‹Ú²²²ÚÚà²à²ÚȳÈæŒæ³ÛÛÉÉ’Éí’í’í’ìÉì’ì’ì’ìvçvçìççççççÊçÊÊÊÊÊÊxxxxóxóxô4ô4ö4ööööþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþööööööôöôöôööööþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöôxôxóçÊÊçççìììçìììççÊóööþþþöþööööôôôôóôxóÊóÊóÊóÊóÊóÊóÊóÊóÊóÊóÊóÊóÊÊÊÊçîûûú)1",-+,"$ïñé¡¥¥¢ééñßïï%$%%Òò½ß¹rMX;<} wwwwwww£} } » £ž´´‰HGGiXklZL[MNNONOO>O>>>O>OONONNMM?[ZlYjHGGhz––––zH9GHhVsss_hhhgg99EFEgggggggggg~hiijiX^qXk`J``^^A;:;HjkŽŽ—ªªªªªªª—ª¿ª¿ª¿———€X;;wwdaUcUUUccafŠwž“µŠ´zh9GhXXkJZLMMNNNNOOOOOOOOONNNN[[L[ZZkXHG9gh––zhG:GhhshV_h_VohggFFEgggggggggggghhiiW^X`Y`aYa``=^AS:;HiqŽ–ªªª–ªªªªªª—ª——¿Ž€X;;;WYZZZlZZZlZllI<;‘®Ä¯°ÅÖÅÖÅÖÅÖ°Ö°ÖÖÆÆٱٱÙÙ××××××Ç×DzÚÇå²ÈàÚàÚÚÈÈææÛæÉÛÉÉí’ì’ì’ì’ì’ì’í’í’íÉíÉÉÉíÉÉÛÉÛÉÛÉÛÉÛÉÛÉÛÉÉí’í’ì’çìççççÊÊÊÊóxôxôôööööþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöööôxóçÊìç’’É’Éí’ÉÉíÉ’Éì’’’í’íÉìÉì’ì’ìvçvçìççççççÊçÊÊxÊxxóxô4ööööþöþþþþþþþþþþþþþþþööôôxÊçÊçì’íÛÉŒæ³ëÈÈÚæÚÚ²²²Ç×Ç×Ùœ±ÆٱײÈÛ’vçvì’í’’É’ÉÉÉÉÉ’É’É’É’É’É’É’ÉÉÉɌ泳¦¦ÎÎ÷$$----$$ññééÝ¢Ý颡ßïò%%%%ù%%òãẹ¡€=;;IXkYlYllZZZZZllkkXjiihH:;=€rššÅ›Å›Õš®‘™N{YIVZNr‘¹‘r†[X;;:;;VVjWXXXWjWVHHGGFhh~hF9GhiXXkJZL[?MMNMNMNMMMM[[LZllkkWVG:9h~–––hG9GhijjWj^W^WsiihghggFgEgEgEgggghhiWXXkJlZZTLTZTZaa``VH:;HzŽ–––ª–ªªªªªŽŽjHG;rmP‡ˆ‚‹³³ŒŒÛŒÛŒæ³ÈÚÚ²²‚œË¤Íäã%%%%%%%òòÑâééݥݢ¶¢Ý¢¢éßïòòòòòÒÒÒÒÒòòãẹÙ­˜†[I;|nˆ±×œÇ‚ǜǂלױ±±±±±°ÆˆÖ°°ÅÅ›ÅÅÕįÄÄÔÔÄÄÃÃÃÙ™†[J<<<==ZZLZ[Z[[[[[[M[[?LJ=<<=N>™|š¯ÕįÄÄšÔ®®¹¹ßߨ¨¨¨ù¨••DfBA@AR@;dwž£ ØŸèõéññâѽÑÑÒÑÒÑÑÑâ½¹º¹Â­­Á˜€{V;;WXkYlZ[L[?[?[LLllXXhH:;W{€ÀÀ—khEFFgghghghhhhhHHgHghhjWXYlZL?MMNMNMNMNMMLLZlYYjiHGFzŽ–ªªªŽªŽ—ŽŽ{Žk{{[€N€N†O­¬ÁÁ˜Á««ÀÀ¿À¿ŽŽq<;<=lZZL[?[?[bLbbd`<;@Hsƒ‰–––––zhG:;WYlZ[bMMM?N?M?wbLZZYXHG:hzzhGHVYlZZ[MNMNNNNNNNMMM[KI;€K=rr‘\||š®ÄšÄÄÄÄÄÔÄÔÔîÃÔÃÃÃÙ­Nl<<™‘®ÃÔÔÔÔšÔÄÔšÄÕÄÄÄÕÄÕÄÕÄկկկկ՛֯śÖÖ°°Ö°ÖÆÙ±Ùœ×DzÇà²ÚÚ³³æ³æ³æ³æ³æ³æ³æ³æŒÛŒÛŒÉÛÉÉíÉì’ìvçìççççÊçÊçÊçÊçÊÊóxóxô4ô4ô4ô4ô4ô4ô4ô4ööööööþþþþþþþþþþþþþþþþööööôôôôxóxóÊóÊÊççççìç’ì’íÉíÉÉÛÉÛÛæÛææ³æ³ëÈëÈëÈëÈëÈëÈëÈëÈëÈÈÚÈÚÈÚÚÚÚ²åÇÇ××±ÙÆÆ°Æ°Ö°ÖÅůÕÄÕÄšÄÔÃÔÃÃÃÃÂÂÓÂÓÂÓÓ¬¬¬Ó¬¬¬¬ÁÁ˜˜†{XO>O>OOOONNM€[[Z{kqWVGGHqŽŽªª´Š{uUAA;_U^^u^usshhG9F~~–‰‰oS@@@_d££»»»»Ø «««À«ÀÀ¿¿——Žh;GVjqYllLZ[[[L[ZlkkWVGGhŽ¿¿——ŽqF9FhizjjjqXqXqjjhH9GG;:;HjXkYlllZZZ{ZZllYqXqjjVHGVq€—¿À««ÁÁ¬ÁÁ««€HG:G:GG;GHHhhhHG:Hz––ªªªªªªª–ªªªªªªªzGGHWXllZZ[L[[[L[bZaa`X^VgG9Fg~~–~GGGVXklZZ[[[[M[[bLZlYkXjHg9Ggzhg9GHjXkkZZ[[MMNNON†NNNNMM[ML[Z{ZlllYYXX=XWX=XXYYll{Z[Z[Z[L[Z[Z{lZl{JXHO>O>OOOONNMM?[ZlYXVH9GhŽ––‰s_R@@_Uccu^^sshhgF8Fg~~~~~]]Q@@@@c”£}££Ü»ØžÀØÀÀÀ¿¿ª—ŽŽzV:GhXXYYZZLL[Z[ZZYkXWHGGi——¿—¿—¿€ŽqGEGgiijjXXqXqjjiVG:GHG::HVXXqXYYlYlYlYYXqjjjjhHG;hŽ««Á˜Á««ŽhG9GGHHhHhhihiihGFGhz––ª–ªªª–ª–ª–ª–ª––zH:GVXYllZZ[L[L[LLKJ``^jVhG9EFg~~hg9GHWXkJZZ[?[?[ZLTZYYXXihG:9gh~gF9HhjXkJZL[[MMNNNNNNNNNMM[[L[Z[ZZZZlllllllllllZZZZLZ[L[Z[L[ZZZZZZJYVH;X{«˜«ÁÁ¬¬­¬Ó™ÂÂÂÂÃÃÃÃÔÚÔÔÔšÔÄÄÄÄÄÄÕÄÕ¯ÖÅÅÅÖ°Æœ±ÆٜלDzà²ÚÚ³³æ³æŒæŒæŒæŒæŒæŒæŒæŒÛŒÛŒÉÛÉÉ’Éí’ì’ìvçvçvçvççççççÊçÊÊxxóxóxóxóxóxóxóxô4ôôööööþþþþþþþþþþþþþþþþööööôôôôxóÊóÊóÊóÊóÊóÊóÊÊççççìç’ì’íÉÉÛÉÛÛæÛæÛ³æ³æ³ë³ëÈëÈëÈÈÚÈÚÚàÚ²à²ÇÇ×Ù×±ÙÆÆÖÖÅÅÅÅÕÅÄÄÄÄÔÄÔÔÔÔÃÔÂÃÂÂÓÓÓÓ¬Ó¬¬Á¬ÁÁÁÁ«Á««†{W;HiqXqjkXjVVHHHVWXXkYkYkkkYlkkqXVH;>>>>>>O>O>OONNMM[[ZlXjHG:Hz––ho::R>>>>>>O>OONONNM[ZZlYWVG:Ghzhg9:RH_^^^^WsWhshhGFEgg~~~ggEE8]]o]:5Spƒ”““µµÜžÀ¿À¿¿¿¿ªªŽŽzh:;HXXYYlZLZLZZZlYqWiHGGj——¿¿—¿€€qGEGgiijjXXqXXXXWiH::HHH9:HVijWjjjjXjjjjiihiHHGGGj——ÀÀ«ÀÀÀÀ¿¿——ŽhG9HhihiiihiiihiHH9GhŽ–ª–ª–ª–ª–ª–ª–ŽzgGGVXkllZZZLZ[ZZaJ``^WsshgE8Eg~~h99GiWYYlJZZLZLKZaaYXWjiigFEGg~hg9:GVWXYlZL?MMNNNNNNNNNNNMMMM[M[[?[[[L[L[Z[Z[Z[L[L[?[[[[[LLZ[ZZllYI;HV{€««««Á«ÁÁÁÁ¬¬­¬Ó­ÂÓ™ÃÂÃÃÃÃÔ®ÔÔÄÔÄÄÕÄ°ÅÅÅ°ÅÖ°ÖÖÆÆ×××Dz²ÚÚÈÈëÈæŒæŒÛŒÛŒÛŒÛŒÉÛÉÉÉÉ’É’ÉìÉì’ììçìççççççççççççççÊçÊÊóxóxóxóxóxóxóxóxô4ôôööööþöþþþþþþþþþþþþþþööööôôôôxóÊóÊóÊóÊóÊóÊóÊÊçÊççççìì’í’íÉÉÛÉÛÛæÛæÛ³æ³æ³æ³æ³æ³ëÈëÈÈÚÈÚÚ²à²Ç××ÙÙÆÆÆÖÅÖÅÕ¯ÕÄÄÄÄÔÔ®Ô®ÔÃÔÃÃÃÃÂÂÓÓ­Ó¬¬Á¬¬¬ÁÁ«Á««—kVGVWqXqXqXqXXjXXqXkXqXkYkXkYkYkYqjWH;:VqŽŽ¿¿¿À¿À¿«À«À«€<;>>>>>>>>>>>>OOOONNM[ZZYqiH9Ggzzh:9GhhW^j^X^jsjs~hHE9F~~~ggEEEF]ooo]Q]p”´„µµ¿žÀÀÀ¿À¿¿—¿ªªŽhGGVjqYllZZ{L[ZZllYqVH9HzŽ—¿¿À¿À¿€{G9FhijjqXkYkXqXjWV::HVhH:;HjWjizjjjjjzizhhgHFG;z——ÀÀ««Á««ÀÀ¿¿—ªzGGghhzijizijiziVHGFhz––ª–ªªª–ªªªªªªªŽŽqV:;O>>>>>>>>>>>OONNMM[[ZlXjHG9ghz~F9FHhss^^X^jsWsihhgF8gg~ggE88FEggooG8Qo‰”´“µµ¿žÀ¿¿¿¿ª¿ª—ŽŽzh:GhjXkYllZZLZZllYqjVG:HqŽ—À¿À¿€kHEFgiijjqXYXqXXjWH;9HhiHG9HHihihihihihhgHGG9GGj€««Á˜Á«ÁÀÀ¿¿ªªŽhG:gHihiijijWjijhhGFGzŽ–ªªª–ª–ªªªªª–ª–hH:HVYYllZZLZLZZaJ``^^phGG9Fg~~–~~G9:hiquYYlaZaZaJYY`XWiHgF99ghzzgG9GhjXkkZZ[[MMNNNNNNNNNNNNNMNMNMMMMMMMMMM[MMMMMMM[M[M[[L[ZLZLlYI<;IZ€««««Á«ÁÁÁÁ¬Á¬Á¬¬­¬Ó¬Ó­ÂÓÂÂÂÂÃîÃÔ®ÔÃÔÔÕÄÄÄÕ›ÅÅÖ°ÆÖÙ±ÙœÇÇà²ÚÚÈȳÈæ³æ³æŒæŒæŒÛŒÉÛÉÛÉÉ’Éì’ììççççÊÊxÊxÊxÊÊÊÊÊÊÊóÊóxóxóxóxóxóxóxóxóxô4ôôööööþþþþþþþþþþþþþþþþööööôôóôxóÊóÊóÊóÊóÊóÊóÊÊÊÊççççìì’ì’íÉíÉÉÛÉÛÛæÛ³Û³Û³Û³Û³æ³ëÈëÈÈÚÈÚÚÚÚ²ÇÇÇÙ×ÙÙÆÆÖÖÅÅÕÕÄÕÄÄÔÔÄÄ®ÔÃÔÃÔÃÃÃÃÂÃÓÓ¬Ó¬¬Á¬ÁÁÁÁ««€qH;VjqXqXkXkXkXqXkXXXkXqXkYkYkYYXqXjiVG:GzŽª—ª—ª¿ª¿ª¿ª—Ž€lW;>>>>>\>>>r>>O>OONNMM[{lkjVG9F~zhg9GHiiWWXuXjjWiizhgE9g~~~gE8gggg~oo]9Qopƒ´´¿žÀ¿À¿¿¿¿—¿ª—ŽhGGVjkYllZZLZZZZYkXjHHGhq—¿¿ÀÀÀÀÀ€{H9FhhzjqXkqkXkXXjiH:GVjiHGGHHVhihihhHhgGFG:;Hq{†˜˜ÁÁÁ˜Á«ÀÀ¿—¿ªªzGGGhhjijjjjjjjjjVH:;h–ªªªªªªªªªªªªªªŽqHGGVXklllZZZZZKZaa``^sHG9Gg~––~H9GHijqXkalaZaJaJ`X^WHHF:FHh–zzGG:HVjXklZZ[[MMNNNNNNONNNNNNNNNNMNMNMNMNMNMMMMMMMMMM[M[[L[ZZllI<;VY{€««««ÁÁÁÁÁÁ¬Á¬¬Ó¬Ó­Ó­ÓÓÓÓÂÂÂÂÃîÃÔ®Ô®Ô®ÄÔÕÄÄÄÕÕÖÅÖ°ÖÖÙ±××ÇÇåàÚÚÈÚÈÈë³æ³æ³ææÛæÛÛÉÛÉÉíÉí’ììçìççÊÊóÊóÊóÊóÊóÊóÊóxóxóxóxóxóxóxóxóxóxôôôôööööþþþþþþþþþþþþþþþþþöööôôxôxóxxÊÊçÊçÊçÊçÊçÊçÊççççìì’ìÉíÉ’ÉÉÛɌیæŒæ³æ³æ³æ³æ³æȳÈÈÚÈ‹Ú‹Ú²àÇǜלÙÆÆÖÖÅ°ÅůկÕÔÔÄÕÔÔÃÔÃÔîÃÃÂÃÓÓ™Ó­¬¬¬ÁÁÁ¬««{X;;VXXqXqXXjXXXXXXXXXXYXYXYXYXYXYXXjjiH::gzŽŽªŽªªªªªªªŽŽqH;HXlZZ[[MMNNOO>O>>>>>>>>>>>>>OONONN[[ZZkqVH5Fgz~hF9FhhWsWjXjXWjiihhG9Egg~gg88EggggogGQ5]p‰ƒ´´¿ž¿¿¿¿¿¿¿ªªŽŽzhG;HjXkYllZZZZZJkXXiHGGh€¿ÀÀ««†[i9FgiijjXXqXYXXjjVH:GHjjiGG9GGHgHgHGGFF9:GHW{€††˜˜Á«Á««À«À¿——ªªŽiH9GHihiijjjjXjXjWHG9HjŽª–ªªªªªªªªªªªŽŽqiGGHWYllZJZZZKZaa``^pSGQGg~~––zgF9HhjuX`aaaaaaa``^IH;:FFhh––zhG:9HiXXkJZZ[[MMMMNMNNNNNNNNNNNMNMNMNMNMNMNMMMMMMMM[[[[Z[ZLll=I;HI{€††««˜«Á«ÁÁÁÁ¬Á¬¬Ó¬Ó¬ÓÂÓ­ÂÂÂÂÃÃÃÃÃÃÔÃÔÃÔÄÄÔ¯ÄÄÄÕÄÅÅÅÅÖ°ÆÆÙœ×DzÇà²Ú‹ÚÚÈȳȳȳ³æŒæŒÛŒÉÛÉÉí’ì’ìvççççÊçÊÊÊÊÊÊÊÊxÊxÊxÊxÊxÊxÊxÊxÊóxóxóxô4ôôööööþþþþþþþþþþþþþþþþööööôôóôxóÊóÊóÊóÊóÊóÊóÊóÊÊççççìçìì’íÉíÉÉÛÉÛÛÛÛ³Û³Û³Û³Û³æ³ëÈëÈÈÚÈÚÚÚÚ²åÇÇ××±ÙÆÆÖÖ°ÖÅůÅÄÄÔšÔšÔÔ®ÔÔÔÃÔÃÃÃÃÂÂÓÓ­Ó¬¬¬¬ÁÁ««€X;;WXkXqXqXkYqXqXqXqXqXkXkXkYkYkYXXqjjVH:GH–ªŽªªªªªªªªªŽiH;VY{Z[[€MNNOOOO>>>>>>>>\>>>>>>O>OON€[[ZlqjHG9HhzhG9HhjWXXXXkXXWjiihH99g~~~gE8gg~gog~gF8Fo‰‰´´——¿¿À¿À¿¿ª¿ª—Žh;GVjqXklZlZZZllYkXjH;Gj{««««Á«˜†€WF9HhzjqXqYkXqXqjjHH:HiqjVgG:GFGGGFG9F:HO>>>>>>>>>>>O>OONNMMLZlkWVF9Fhhh99GhijWX=YXXjXWjhhgFEg~~ggEEEggggggg]98opƒ´´——¿¿¿¿¿—¿ª—ŽŽiGGHjXqYllZlZJlJYXXiH:GjŽ€««Á«˜«˜«€l99GhhjjqXYYYXXXXWVH::VjziHHGGFG9GGHHIY{M«†«««À«À«ÀÀÀÀ¿¿—¿ªªŽŽzhFGHiijjXXqXYXqXXWV::HqŽŽªªªªªªªªªªªªª–iH:HIYYllZJZlZaa`^A;@RSs‰–––––hg9GHW^`u``aaa``cU;;@;HqŽŽªŽª–ª–zhGGGhVXYllZZ[[M[MMNMNNNNNNNNNNNNNNNMNNNMNMNMMMM[M[[L[Z[ZZYW;;O>>>>>>>>>>>>>O>OONNM[Zlkqi;9Gg~gG9HhzjXXYYkYkXjjzhH9Fg~~~gE8ggggggoggQ9]~‰Ž——¿¿À¿À¿¿—¿ª—ŽiHGVWqYkkllZlZllYkjiH;Hq{†«˜˜Á˜˜†lGEghzWjXkYkYkXqjjiVG;Hjq{qjjiVhiiXk{[€€††ÀÀ«À«À«À«À«ÀÀ¿À¿¿ª¿ªª–hGGhijjqXkYkYkYkXqVH:HiŽªª—ª—ª¿ªªª¿ª—ªªŽV;;V=llZlZZZZZa=_A@;Suƒ´ª–ª–––zgGGhsuu``aaadacU;7@<^ƒ{—€———ª—ªªŽ–zhGGGViqYll{Z[[MMMMNNNNNNNNONNNNNNNNNNNNNNMNMM[M[M[[[[Z{J=HHO>O>>>>>>>O>OONNMM[[lkXiG99HgH99GVijWXXYYYXXjjiiGF9gg~~gE8Eggggggg]E8]o‰‰Ž´—ª¿¿¿¿¿¿¿ª—ªŽiGGHjXXXkJllZJlYYXXhH:HX€†˜˜Á˜˜˜˜O[;9FhhjjXXkYYYYXXjWhH:;hqŽ{Ž{{Z{[€M€€€ÀÀÀ«ÀÀÀ«ÀÀÀÀÀÀ¿¿ª¿ª—ŽŽiGGHiiXXqXkYYYkYkXXH;:Hq{Ž—ª—ªªª—ªªªªªªŽŽqH;;IYllZlZZZa`UA@;Au”´ƒ´´´ª–so9:Ss^uudddddCU@;;Uc„Mµ€¿——ª—ŽªŽ–zhGG:HVXYllZZL?M[MMNMNMNNNNNNNNNMNNNMNMNMMMM[[[[L[L[ZZY=;;HXl€À«˜˜Á«Á«ÁÁÁÁ¬Á¬Á¬¬¬¬Â¬ÓÓÓ™ÂÂÂÂÃÃÃÃÃÃÔ®ÔÔÔÔÄÄÄÄÕ¯Õ¯ÅÅÅÅ°°ÆÆÆƱ±Ùœ×œ×œÇ×ÇÇÇÇÇDzDz²à²Ú²Ú‹ÈȳÈæŒÛŒÉÛÉ’íÉìvççççççÊçÊçÊçÊçÊçÊçÊçÊçÊÊóxóxô4öôööööþþþþþþþþþþþþþþþþööööôôóôxóÊóÊÊÊÊÊÊÊÊÊÊÊÊÊÊçÊççìçìì’í’íÉÉÛÉÛÛÛÛæÛ³Û³Û³Û³æ³ëÈëÈÈÚÈÚÚàÚ²àÇÇ××±Ù±ÙÆÆÖÖ°ÖÅůÕÄÕÄÕÄÄÔÄÔšÔšÔÔ®ÔÃÃÂÃÂÓ­Ó­Ó­­Á˜†€I<O>>>O>>>>>>>O>OON€MML{kqih:Fg~gF9HhjjXXkYlYkXqjjVHFFg~~~gg8Eg~gggogg]9Qo~–ªª¿¿¿¿À¿¿¿¿——ŽiH:VWqXkYllZllJlYqjiH;H€˜˜˜˜˜˜[V9GHijXXqYkYkYkYqjjH;:Hj{Ž†††††À«À«À«À«À«À«À«À«À«ÀÀ¿À¿¿——ŽŽiHGHiXXqXkYlllllYlXWH;;W————¿—¿ª¿ª¿ª¿————{XH<O>O>OOOONNNM[[ZlXWHG9ggH99giWXXYYlJlYYXXWigFFg~~~~EEEggg]ggg]FE9]~‰–ªª¿¿¿¿À¿¿——ªŽzGGHWjXXYYlllJlYYXXVHGO>O>OOOONNMM[ZlkjhG:GhgG9HhjXXYlklllYqjjVH:Fg~~~gg8EEggggggo]F8Foªª——¿¿À¿¿¿¿——ŽŽjHGHiXXYYlJlllllYkjiH;Hl€†{q€††NXF9giiXXkYlYlJlYkXXWV;:;q{——À†«À«À«À«À«À«ÀÀÀ«À«ÀÁ«««Á««À«ÀÀ¿¿——ŽŽqhGHVjXkYllZZZZZZZllWV;;•¨¨¨¨¨¨é¨éèÝØØÜܵµŠ{jH@;S_SA7Cf••¨¨Ñ¨ÑÑò½··¯·¯ÄÕÄÄÔÔÃÃÂÓ¬­˜˜†€ZX<<;<<=JLL[[M[MMMMNMMMMMMMMMM[M[[[[ZJI<;;;IY{N†˜¬¬¬¬¬¬¬¬Ó­Ó­Ó­ÓÓÂÓÓÂÂÂÂÃÃÂÃÃÃîÃÔÚ®ÔÔÄÄÄÄÕÄÕÄÕÕÅÅÅÅÅÅÖ°ÖÖÆÆٱٜٜללÇ×ÇDzÇà²àÇà²à²à²Ú²ÚÚÚÚÈȳȳ³æ³æŒÛŒÛŒÉÛÉÉ’Éí’ì’ì’ììççççÊÊÊÊóxóxô4öôööööþþþþþþþþþþþþþþþþþþööööôôôôxóÊóÊÊçÊçÊçÊçÊçÊçÊççççìç’ì’íÉíÉÉÛÉÛÛæÛ³æ³ë³ë³ë³ëÈëÈÈÚÈÚÚÚÚàà²àÇ×Ù×ÙÙ±ÙÆÆ°Ö°ÖÅ°°°¯ÕÄÄÄÄÔÄÔÄÄÄÔÔÔÔÃÔÃÃÃÃÃÃÙ­­†€I<¥¨½ÑÑÑÑÑâââõ¬èØžžµµŠƒ_;@ASAB”w•¨âÑÑÒòÒòÍ͸¸°°°ÅÖÅÅÅůÕÄĮÑ™N[=I<<OMK>>\½Pãäã%%%%%òñ顶¶ †ž€„„ddb •âòò%%%$%÷Χڲà²å²àÇÇÇå×Ù±±ÆÆ°ˆ›š|\>O??==>N?667B>N?6?66=6B6=6=6=KKL?€N†­­­­Ó™ÂÂÂÂÃÃÃÂÔ®ÔÃÔÃÔÃÔÔÔ®ÔÔÔ®ÔÄÄÔÄÄÄÕÕÕÕÕÅÅÅÅÖÅÖ°Ö°ÆÖÆÆÆÖÆÆÆÆÙ±ÙÙ××ÇÇÇÇÇÇåÇå²à²à²Ú²ÚÚÚÚÚÚÚàÚàÚÚÈÚÈÚÈÈëÈë³ææÛæÛæÛÛÉÛÉÉíÉí’ì’ììççççççÊÊóÊóxôxôôööööööþþþþþþþþþþþþþþþþþþþþþöööôô4ôxóxxÊÊçÊççìçìçìçìçìçìì’ìÉíÉ’ÉÉÛɌییæ³æȳȳȳȳȳÈÈÚÚ‹Ú²Ú²àDz×לÙƱÆÆÖÆ°°ÅÅÅÅÅÕÄÄÔÄÔÔÔÔ®ÔÃÔîÃÔÃÔîÃÃÂÂÂí­NJ;<=ZZ[ZZZZlZlY<;;kŽ¿——Ž{i;:HWXXkYkYlYkYkXXWH:;i–ŽŽŽzhGGHijXjXXYXkYYWIH;:G:;:G;VWJl[L[[MMMMM[[[[ZlYXiH9GGHF9GhiXXYYlJlYkXXjiHG:gh~~gEEEgghgogogogG5:HŽ——ÀÀÁÁ¬ÁÁ«À—€k<:HiXXYYllZZZZZJlYXWihhghggggE88gk€N€XF8GhjjYYllZZLL[ZZllYYjjhHG:9Hj{Ž—«˜¬¬Ó¬Ó™Â™Â‘ÂÂÃÂÃÂÂÓÓ¬¬ÁÁ˜«€€X<;VXllZZ[Z[L[?[L[ZZZZlZ=I;7I[N™™ÃÃÔÔÕÅÖÅÖ°Öˆ±t‚§¦Î©#$$---$$ïéé……O¶ ¶»ÝÝß$$---$$!©ÏÌÛ³æŒæ³æÈëȳÈÈȳȳ‹³‹³‹¦‹‹ttˆtPnPm\\>>O>OONONOOOO>rrr™™‘­™™ÂÂÃÂÃÃÔîÃÔîÃÔ®ÔÃÔÔÄÔÔÔÄÄÄÄÕÄÄÄÕÅÕÅ°ÕÅÅ°Å°°Ö°ÆÖÆÖÆÖ±ÆƱٱٱٜלÇÇÇÇåDzÇà²à²à²Ú²Ú‹Ú‹Ú‹Ú‹Ú²Ú‹Ú‹ÈÚÈȳȳÈæ³æŒæŒÛŒÉÛÉÉÉÉ’’ì’ì’ìvçìççÊçÊÊxxóxô4ôôööööþöþþþþþþþþþþþþþþþþþþþþööööôôôôxóÊóÊÊçÊççççççìçççççìç’ì’íÉíÉÉÛÉÛÛæÛæÛ³ëÈëÈëÈëÈëÈÈÈÈÚÈÚÚàÚ²àÇÇ××ÙÙÆÆÖÆÖÖÅÖÅÅÅÕÄÕÄÄÔš®Ô®šÔÔ®ÔÔÔÃÔ®®ÃÔÃÃÃí­†J<¶¶Ÿ…¥éï$$-----#!©yÞ’’ì’ì’ì’ì’ì’íÉ’É’Éí’ì’ì’ìÉ’É’ÉÉeɌɌeŒŒŒŒŒeŒeŒÉeÉe’É’Œæ³Ú²²ÇÙ±±ÆÆ°ÆÖ±œ±Ö±×לٱÙÆÙ±ÙœÙÆÙ±±ÆÆÆÙ±²œ×œ×ÇàÇÇÇÇDzÇåÇå²à²à²Ú²Ú‹ÚÚÚ‹ÈÚÈÚÈȳȳÈëÈæȳȳȳȳȳÈÈÈÈÈÈȳÈëÈæ³æŒæŒÛŒÛÛÉÛÉÉ’’ìÉì’ìvçìççÊçÊçÊÊóxóxô4öôööööþþþþþþþþþþþþþþþþþþþþþþþþöþööööôôxôxóÊóÊÊçÊçÊçÊçÊççççççìì’í’íÉÉÛÉÛÛæÛæÛ³ëÈëÈÈÈÈÈÈÈÈÚÈÚÚÚÚàÚ²àÇÇ××ÙÙÆÆÖÖ°ÖÅůÕÕÕÄÄÔš®Ô®ÃÃÃÃÃÃÃÃÃÂÃÃÃÂÃÂÂÂÂÂÂÂÓ¬¬˜†Z<;XZ[Z[ZZZ{ZZllW<;Vk€——¿——j;;HXXkkkkllZllklYW;;H{ŽŽiH:HVjijjjjjjiHGGVqŽŽªŽª–iH:HWlZ[L[[M[[[[ZZYqWVGGGhhH:GHijqYkklllJlYqjjHG9h~~gE9GhhshhhhhhhhHG9HzŽŽ¿À««Á˜Á«À—€lV:;VXYllZZ[L[L[ZZllXqWzh~ggggFE8Eh{€†€jF9GViqYkJZZ[Z[ZZZlYYjjizhzHH9Hq€†­ÂÂîĚÄÄÕÄÕÕÕÕÅÅ°ÅÖÅÕÄÔÃÃÂÓ˜€J<……ééïï $$----$1!ÏyÞ’’’’’’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ì’ìÉì’ìÉì’ìÉí’ìÉì’ì’ìvçìççÊçÊÊÊçç’’ŒæÈÚdzÇàÇÚÚÚ²ÚÚÚÚÈÚÈÚÈÚëÈÈÈÉÈÈÈÚȳ³æÈÈÚÈÈÈÈÈÈëÈëȳÈæÈæ³æÈæ³æ³æ³æŒæŒæŒæŒÛŒæŒæŒæ³æ³æ³æ³æ³³È³ÈëÈæ³æŒæŒÛŒÉÛÉÛÉÉ’’ì’ìvìvçìççççÊÊÊÊxxóxô4öôööööþþþþþþþþþþþþþþþþþþþþþþþþþþöþööööôôxôxóÊóÊÊÊÊÊÊÊÊÊÊçÊçÊççççìì’í’íÉÉÛÉÛÛæÛæÛ³ë³ë³ëÈëÈëÈÈÈÈÚÚÚÚ²àÇÇ××ÙÙÆÆÆÖÅ°ÅůÅÕÄÄšÄÔ®ÔÃÃÃÃÃÃÃÃÂÃÃÃÂÃÂÂÂÂÓÓ™Ó­Ó¬­˜†[I;=l{L[Z[L[Z{ZZYW;;V{Ž—————{H;;WXqXkkllZllllkY<;;WŽŽjH:HhzijizijiVGGgzŽŽªªª–ŽqiG;VYlZZ[L[[[L[llYqiHFGg~hhF:GViXXkklllllYkXjhH9Gh~~F9FhhVhihihzhihhG:Hq{——¿¿«À«ÀÀ——{X;;HXYllZZ[L[L[LZZlYqjjhhggEE8EFhk††˜†€WGEghjjkYllZZZZZllYqjjiziVH;;X€«Á­ÂîįÅÅ°ÅÖ°ÖÖÆÆÆÆÙ±ÙÆÖÅÅÄÄÔ®™™€I<­‘šÄˆÆDzÈȳ³æ³æŒæŒÛŒÉÛÉÛÉÉ’É’ÉìÉì’ì’’ÉÉŒŒ‹tnm>>O>O>O>>>>>>>>OO>O>>>rrr\‘mšÄÕÅŇ°¸¤¾÷$$%--"- ßߥ¥………¥¥ïï ""(///(01)*' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöööö4ô4ôxôxxxóxóxô4ôôööööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöö4ô4ôxóÊóxxxóxóxôxôôô4öôööööþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöþöþöþöþöþööööööööööööôôôôxóÊóÊÊÊóÊÊçÊçÊçÊççççççççççççìçìç’ç’ììíÉÉææÈÈÚÚ²å××××ÆÖ°ÆÅÖ°Ö°ÅÄÄÄÕÄÄÄÄÔÄÄšÔÔÔÔ®ÔÃÔÂí­†J<[JLN­|š›±Çڳɒì’ì’ì’ì’ì’ìçççÊÊóxô4ööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ32**110(.//(( áïßߥ¥¥¥ßïï #""&/./(01**2 þþþþþþþþþþþþþþúÒ%þþþþþþþþþþþþþþþþüþþþþþþþþþþþþþþþþþþú!ùþþþþþþþþþþþþþþþþþþÒþþþþþþþþþþùúþþÒÒþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþööôôÊóççìí’í’íìÛÉíæÛææÈëÈëÚÈÈÚàÚ²ÚÚÇ××ÆÙÖÖ°ÖÅÅšš|­N6<=LMMM[[K=™‘®|®®Ô®®Ã®‘™r†K<r|m›š››ÅÅÅÕÕÄÄ®®\rMInˆ²‹ÈÈæŒæŒÛŒÉÛÉÛÉÉÉÉ’É’É’’ɌےììççÊÊóxôöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ%þþþþþþ3 '*)101ùïߥºÑùäÍ ""(&///1ú' þ3þþþþþþþþþþ%þþþúþþþþþþþþþþþûþþþþþþþþþþþþþþþþþþþþþþþþúþþþþþþþ!þþþþþþþþþþþþþþþþüùþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöööôóóôç’ÊÛíæÛÈȲLj‡mr?66?Nr\šn‡‡ˆ°Æ°ÆÖÖ°°Å¯nš\OBI6MM€MMLKI<\mn‡ˆtÇœ²œ×œÙ±±ÆƇ‡š|O6?76?N?6<66N>\\®®š®®ÃÔÃÃÃÙӭӭ­¬­NL<<;=JLZ[Z[ZZZ[ZJ<66666?N>\Pn‡‡ˆ°Ö°°›ÕÄÄÔÔ®ÔîÃÃÃÃî||™­OM6<;?666NO\m‡ˆœœÇÇ×××±ÆÖÖÅ°¯ÕÄÕÄÕÄÄšÕ¯¯š®|™r†L6<<<6K[[€MMK=<[O™™®ÃÔ®Ô®ÔÔÔÃÔ®Ô®šºº½½âÑÑÑÑÑÑòââéñéõŸ¶Ø؞؞ܞÀØèèõè軶}}DDD¨¨ÑÑããä¾Ë˲ÇÇDz²à²à²ààÚ²Ú²Úàà×ÙÆ°›¯®‘rMJ<;;H‡‚³ŒÉÉì’ì’ì’ì’ììçãçóùòöþþþþþþþ!!þþþþþþþþùþþþþþþþþþþþþþÒúþþþþþþþþþþþþþþþþþþþý!úþ 2'))10//0- ïßߥ¹ºáïá))##0(((011**2 þþþþûûûûúúúúúû!ú!!!!!!!!úúúúúúûûüûüþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöþöþööööööööööôö4öôö4öôööööô4öôöôôxôÊÊ’ŒtP>NN>>mntt¦‹³‹³ÈÈ‹Ú²à×ǜưְÖÅÖ°°ÅÖ‡›nš||rNL7<7==LMM[K<=Mr™®®šÄÕÄկů¯ÄÄį·¸áá½òÒÒÒÒÒÑÑòÑâââééÝÝØ؆؞؞ØØèèÝ•Ý•¥•¨¨¨ùÒÒ%Ò¾¾§§²²Ú‹Ú‹Ú‹Ú‹Ú‹Ú‹Ú‹ÚÚàÇ×±Ö¯¯|‘rNZI<;;;N66<6=LL?6I=†\šš¯ÅÖÅÖ°ÖÖÆÆְƈƤ¤ääÒ%ÒÒòòòâññÝ¢¶¶ØØØØØÁèõÝñâãÑÑÒ%%%%÷÷ÎΦ¦ÈȳȳÈëÈëÈëÈëÈÈÈÈÚÈàDZƛ¯®Ã™†€JI<;;<;H<€\t‹ŒÉ’’ì’ì’ììçìççÊðîÒÒþþþþþþþþùùÒ!þþþþþþþþþþ!!þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþÒÒ%þþþþþÒ'*)10(///(01) Ẻºáá¾¾ë÷÷)%÷!úüûüûþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ4xve©tt‹¦eexxxxxxóççìíÉÉŒæŒÚ²Ú²à²àÇà²åœ×œ±ˆ°‡¯m|r>?6|š°°Æ±Ùœ××ÇÇÇDzÇÇ˧¾¾%Ò%ÒÒòòâééÝÝè¶ØØØèèõõââòòÒ%%-Ò%%÷©¦Ì³ŒŒæ³Œ³æ³æ³³³³È³ÈëÈë²ÇÆƇ›š®™™†[ZII<<N66BBB6N\Pˆ±ÇÇÚÚÚÚÈÈÈÚÈÚڋڧξ%%%%%òïñéÝ¢¶¶Ø¶èÝÝññ%$%$-$$1©©ÏÌÞŒÉÛÛÛÛæÛæÛæÛæÛ³ÛæÛææÚàœ±°›š®|‘rrO†M[Z{Nrn‹³ÉÉì’çìççççóÊóxôþþþþþþþþÒúûÒþþþþþþþþþþùûû%ùþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ2'**11000#)))!ú!ú!úúúúûûûûüüýüýýýýýýýýýýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþýýýýüüüüüúúú!ú!ú©©úþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ44xxÊxx44þþþþþþþööxxçÊçìÉÉÛɌیÛÉÉÉæŒæ³³ÈÈ‹Ú‚‚ˆˆnm\>ON??Nrmˆ‚Ú‹³ŒæŒæŒæŒæ³³ÈȦ¦ÎÎ÷%$%-%%%òòïééÝÝè¶èÝÝéßïò%$$----$!©ÌÌތɌɌɌییییæŒÛŒëÈà×Ùˆ°šš®®\™rr>‘t‹Ée’’ìvççççÊxó4ööùùþþþþþþþþ©ùþþþþþþþþþþþþþþþþ!ùùþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'))1%%%%ä111)!**2ü33þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ4þ44üüú!!úþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöööþþþþþþþþþþþþöôôxÊççííììíí’í’çìç’í’’ÉÉŒŒ³Œ‹‹ttnP\\\\mt‹ŒŒÉÉí’í’í’íÉÉÉÉŒÛÌÌ©©$-$-$%ïïßéݬݢݡéïï$---,-#)!úÏyÞ’É’É’ÉíÉíÉÉÛÉÛÉÛÉÛÉÛÛ³ÚÇDZְ›šš®®‘‘™‘‘¯ÇŒÉíìççççóxóxôööþþÒùþþÒþþþþþþþþþÒüþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþû2úú!!äääääää÷ ÷))1100(((11)*'2þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþýüú!!!©þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþööxóçÊÊÊÊÊÊÊçÊÊÊxóÊÊçÊççv’ÉÉŒŒ‹¦ttntnt‹Œe’vçççççìçççv’’’ÞÞÏÏ©$----$$ïñééݢݥ¥ñßï $$---,-#)!úyîy’’’ÉìÉíÉ’É’ÉÉÉÉÛÉÉÉÛÉŒ³‹²ÇÙ°°›¯šš®®®š°ÚŒ’’ççÊÊxxô4ööþþþþúüþþýÒþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûûû!ú÷ ÍÍááºááÍá #0((///(01)*' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ44ýýûû!!!þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöxöôôôôôöööööööööööxôxÊçç’’ee¦e¦eŒeevvÊçÊÊÊÊÊÊÊçÊççvv’yÏú1"---$$ïïé¡¢ééééïï-",,."#1)úûyîvçvçvçìììì’í’í’íÉíÉí’ÉÛÛÈÚÇ×±ÖÅևśÅÅ×ÈíìÊÊóxôxööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûüûû!!1#1))) áºß¹ß¹ßïïã #"(/&/((11**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöþöþþþþþþþþþöþööôôxxÊÊ’v’’eeev’ççÊÊxÊxÊxÊxÊÊÊÊçÊvvÞyú!$,----$ ññ¥¥¥é¥ßßïï -"-,-,,"$1*úûyçvçvçvçvì’ì’ì’ì’í’ìÉìÉíÛ۳ڲǜ±Æ±Æƈ±²ÛìÊÊóxôôööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûüúú!©ú!ú!)!)#000000# ïïßߥßßßß #"0+/.//01))'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþööööxôxxÊÊÊÊvÊÊÊÊóxôxôxôxôxôxóÊóÊxîÊûû!)#,,.,-"" ñ¹¡é¥ß¡¹ñ #"",+,+,#1)!*ûîîÊÊÊçÊççççççìçççìçìì’ì’í’ÉÛëÚÚÚåÇÇÇDz³’óxôôööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþúûú!!!!úûüüý 2'*))00///((0## ïßßßß¹ß 1#0((///(0))'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþööööxôxóxxÊxxxxóxôxôxôxôxôxóxxxxÊÊîîûú!)",,-,-"$ ïïßߥé¥ßßïï-(,+.+,#)!'ûîîÊÊÊÊÊçÊçÊççççìçvì’ì’ì’ìÉÉŒæ³æÈæÈë³ëÉçxööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþüúú©©úúûüý4þþþþþþ 2'*)100//./(0"#ïïßߥßßïï #((//.&(11**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþööööööôö4ô4ôôöôôôôôôôôôôôôôô4ôxôxxî2**)1"(,+,,"# ïïßñ¥é¥ßßï "((+++("11*ú'üêêôxóxxÊóÊÊçÊççççìç’ììçìçìçìí’ÉÉíÉÉ’çxöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûúú!©©!!úûýýþþþþþþþþþþþ ''))10(/.&&""# ïïßßßßßïï #"0&/.&(01)*'2þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþööööööööööööööôöôöôöôöôô4ô4ô4ô4ôêýü'!)#,+.+,," ññéߥééñßï "",+.++(01*ú'üêêxxxÊÊÊÊçÊççççììvìvììççççÊçÊÊççÊÊÊ4þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþüûû!!©úúüüý4þþþþþþþþþþþþþþþþ3 ''*)10(&.//((" áïßߥߥßß #"0(&../001)*' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöþöþöþöööööööööööööööö4öý ü'))#0(+,+,""# ïñéߥßßïï #""(+//(01))*'2ýýxôxóxóÊóÊÊÊÊçÊçÊçÊçÊÊóxóxôôööööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûüú!©!!úúüýþþþþþþþþþþþþþþþþþþþþþ2'**110(/&/((### ïïßßß¹ßï ###"(/&/(01)**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþöþöþöþöþöþöþöþöö4ö44ü2û*)10(.+/(,"" ïßߥߥßßïï #((//./(01)!*û2ü4xxxxÊóÊÊÊÊÊÊÊóÊóxxxóxô4ööööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûûú©!!úúûý44þþþþþþþþþþþþþþþþþþþþþþþþþþ 22**110(///&&""# ïïßߥßßïï #"(//./(01)*'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**11((/++("# ïïßߥßßßß ###((/&/((11)*'û ýöýôôôxôôôôôôôôôôôôööööþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþüúú!!úûüýý4þþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'*))00///&(0"# ïïßߥßßïï #"0(&///0#))'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'*)10&/./&""#ïïßߥßßßï #""((///((11)ú'ü3ý44ö4ö4ööööööööþöþöþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûû!úúüý4þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ32'*))00//.//("# ïïßߥßßßßï "0((//.(01)*'23þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 '*))#0///&(0## ïïßߥ¹ßïï ##0((///(01)**22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûû!!!ûüþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''))10(&/&/""#1 ïßßßßßßï 1##"(&&.((11**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ32**110(///((0 áïßߥߥßßïï #""(&///001)**2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûú!úüýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''))11(&///((0 ßߥߥßßïï#""&/./&00))'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ2'*)11(&.&/("## ïßߥߥßßï #""&&//&00))*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþúü!!úüýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**11((///((0##ïïßߥßßïï ##0(&///00))*' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''))00//.//""# ïïßߥßßßßï #((//./(00))**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûû!©üýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'*)110(//.&(0"#ïïßߥߥßßá #0((../(011**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ '*))00///((0##ïïßßéßßïï ###"(/&/((11))''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûüú©!!ü4þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**)100///((0"# ïß¹ßߥ¹ßï #0(/&/&(11)*'2þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**110(.//((0## ßßßߥßßïï #"0((///&(11))''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþüû!÷÷!!üýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**)100&//&(""# ïßߥߥßßïï #""&/./&0#))*' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ2'*)1#(&/&/("#1 áßߥ¹¥ßßïï #"0((/&/((11)*'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûú!!!üýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**)100&&/(&""## á¹ßßߥßßïï ##0(&///001)*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 '*))00&/./&""# ïïßߥߥßßïï #"0((///(011)*'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ!ûýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22**))00&/.//((# ßߥߥßßßß 0((//.((11**22þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ '*))00///&(0## ïïßߥßßßßï #"0((/&/(011**'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûü!!!úýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**))10(&/&&("### ïïßߥßßßß 1##"(&&.&(11**'2þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**110(///((0# ïߥߥߥßßïï #""&(/&/(011)*'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþûû!!ûþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2**))00((///(("# ïïßߥ¥¥ßßïï #""&/./&00))'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'*)11((/&/("### ¹¹¥ß¥ß¥ß¹ #"0((/&&001))*'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþû!!ýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**))11((/&/((#"# ïïßߥߥßßïï #"0(&///00))*' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''))00//.//("# ïïßߥ¥¥ß¥ßß "#""&&/&/(011)*'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþüýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22**))00((///((""# ïïßߥ¥¥ß¥ßï #"0((.//(011**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ ''))00&//&(0"# ïß¹¥¥¥ßßïï ##"0((/((001)**'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2**))11((/&&((### ïïß¹¥¹¥ßßïï ###"(/&/((11**'2þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**110(///&(0"# ïïßߥ¥¥ß¥¹ï #""((/&&0011)*''23þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**))00((///((""# ïïßߥ¥¥¥¥ßßïá #"(//./(01))'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ '**11((///((##1ï½ßߥ¥¥¹ßïï ##"0((/&(0011)*''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**))11((/&/((## áßߥߥ¥¥¹ßïá #""(&//&01))'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''*)10(/.//((# ßߥ¥¥¥¥ßß¹ï "#""+&/&/(011))*'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''**))00((///((""# ïïßߥ¥¥¥¥ßßïï #"0(&///(01)**23þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''))10(&/&&0"#1 ßߥ¡¥¥¥¹ßïï ###"0((/((0011))''2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**))1#((/&&((#"# ßߥ¹¥¥¥¹ßïï ##0((///(01)**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ32'*))00////(""# ïßߥ¥…¥¥ßßïï #""((/&/(011))**22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2''**)100((///((""# ïßߥ¥¥¥¥¥¥ïï ##((//.((11)*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**)10(///&(0"# ïïßߥ¥¥¥¥¹ßïï ##"0((/&/(011))**'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ ''**)100((/&/((#"# ßߥ¥¥¥¥ß¥ñ½ 1##"(&//((#1)*'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'*)110(//.((0"#ïïß饥…¥¥ßßïï "#""+&///((00))**'' 33þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22'*))1100&&///((""# áïßߥ¥…¥…¥¥ßßï #"(&/.//00))*' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'*)110(/&&((### ïïßߥ¥¥¥¥¹ßïï ###"0((/&/((11))**'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 22'*))1100(&/&&((### ïߥ¡¥¥¥¥¥ßß 1#"0(&//&00))*' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''))1#(&/&/((# ïߥ¥…¥…¥¥ßßïï #""((///((0011))*'22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ33 ''**))110(/////((""# áïßߥ¥…¥…¥¥ßßïï #"0(&.//(01)**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ ''))10(&/&&""###½ß¥¥¥¥¥¥¥¹ßïï ##"0((/&/((0011))**'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2''**))1#((///&/((## ïߥ¥¥¥…¥¥ßßïï #"0((///(01)**' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'*)100///&/""# ïßߥ¥…¥…¥¥ßßïï "#""((//.//0011))**''2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22**))1100((//./&((""# áïßߥ¥…¥…¥¥ßßïï#""((///((11)*'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**)100&//((0"# áß¹¥¥…¥¥¥¥¹ßïï #"0((/&///(011))**''22 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**))1100((/&/((""## ïߥ¡¥¥…¥¥ßßïï ###"(/&/((11)*'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**110(///&(0"# áïßߥ¥…¥…¥¥ßßïï #"0((/////((0011))**'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ33 22''**))1100/////(("""# ïßߥ¥…¥…¥¥¥¥¹ï ##"(///&(01))*' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**110(///((0"# ïßߥ¥…¡…¥¥¹ßïï #"0((/&///((0011))**''22 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''**)*)101((/////((""## ïߥ¥¥¥…¥¥¥¥ïï ##"(&&/&(01))''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''*)11((///((""# ïïßߥ¥…¥…¥¥ßßïï #"0((+&././/((0011))**''2 33þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 3 22''**))1100((././/((0"# áïßߥ¥…¥…¥…¥¥ßï #""/////001)**22þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''*)11((/&/("0## ïßߥ¥¥¥¥¥¥¹ßïï ##"0((/&///((0011))**''22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''****))1100(//&/&/((0"# ïߥ¡¥¥…\¥¥¥ïï #"0((//&001)**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ '*))10((//&((""# ïïßߥ¥…¥…¥¥ßßïï ##"0((//.///&000011))**''22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2''*'**))1100((//.//&+((0"# áïßߥ¥…¥…¥…¥¥ßï #"0(&///0011**'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ '*))10((/&&("### ïïßߥ¥…¥¥¥¥¹ßïï ##"0((&&/////((0011))****''22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22''**)))11100&&//.&/((0"## ááßߥ¥¥¥…¥¥ß¥ïï #"0((///0011**'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2**))00(&//&((" ïïßߥ¥…¥…¥¥ßß¹ï #""((+&//.//&/(00011))****''22 333þþþþþþþþþþþþþþþþþþþþþþþþþþ33 22''''**))111100((//././/((""# ïïßߥ¥…¥…¥¥¥¥ßï #"0((///(011)*'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'*))10((/&(0"## ïß¹¥¥¥¥¥¥¥¹ßïï ###"0((/&//.&/((0011))))****''22 33þþþþþþþþ3 22''''**)*))110000(&//.&/((((0"## ïïßߥ¡¥¥¥¥¥ßßïï #00((&&/(011**'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 '**)100(//&("(# ïïßߥ¥¥¥…¥¥ß¥¹ßá ##"0((&&//././/((001111))****'*''2222 3 3333 3 3 3 22''''****))))110000((//././/(("(0"# ïïßߥ¥¥¥…¥¥ßßïï #"0((/&/((11)*'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**)100&&/((0"## á¹ïßߥ¥¥¥¥¹ßß½ ###"#""((//././/((((0011)1))*)**'*''''2'2222 2 2 2 2 22'2''''*'****))))111#00((////.&/&&((0"### ïïßߥߥ¥¥¥¥ßßïï #"0((&&/((11))'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**1100&//&(""# áïßߥ饥…¥¥ß¥ßßïï #"#""((////.../.&&((001011)1))*)******'*'*'''''''''*'*'******)*))))11110000((//..././/((((0"# ïïßߥ¥¥¥¥¥¥ßßïï #"0((/&/((01))*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**)100&(&((0"## ïïßߥ¹¥¥¥ßß¹ßïï ###0"0((+&/&././/((((001011)1))))*)*)*****************)*)*))1)11110000((/&//.&/&/(&((0"## ïïßߥ¹¥¥¥¹ßßßï #"0((&&/(011))'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'*)1100&//&(""## ïïßߥ¥¥¥¥ß¥ßßïï #"#"0((((//./././//&((0(00101#11)1)1)1)))))))))))1)1)1111010#00((/(//./...//&/((""""# ïß¹ßߥ¥¥¥¥ßßßßï #"0((&&/((#1))**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**1100&(&((0"### ïïßߥߥߥߥßßïï ###"#"0((&(/&//././/&/(&((0(00#01011111111111111111010000(0((&&////.&///&/((0"0"#### ïïß½ßߥߥߥßßïï #"0((&&/((#1))*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''*)110(&//&("(0# ïïßßßߥ¥¥ß¥ßßïßïï ##""("((+(////./././///&&((((0(0(00000000000(0((((/(/&////..././/&/((((""#"#  ïïßßßߥ¥¥ß¥ßßïï #"0((/&/((0#))**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**1100&(&((00#1 ïïß¹éߥßéßßïïïï ####"#"0("((/&/&/&/&.////&/&/(&(((((&(((&(((/(/&/////&/&.&/&/(&((0(0"#### ïïß¹ßߥ¹¥ßßï¹ïï ##"0((&&/((11))**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''*)1100&//&(((""# ïïßߥߥߥßßßßïïá ##"#""""((((/&/&//////././////////////////////.////////(&(("(""""## ïïßïßߥߥ¥¥ßßßßïï #"0((/&/((##))**2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ ''**1100&&/&&"(0## ïïßïßߥ¹¥ßßßßïï ####"#""("((((+&/&/+/&/+/&///&///&///&/+/&/&/&+(&((((""0"### ïïßßß¹¥ß¥ß¥ßßïï ##"0((&&/((#1))**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''*)1100&////((0"# ïïß½ßߥߥߥßßßßïï  #"#""""("("((((,(+(+&+&+&+&+&+&+&+&+(+(,(((("(""""#"#  ïïßïßߥߥߥߥßßïï ##""(&///((01))**22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ ''**)100((/&/((0"### ïïßßßßßߥ¹ßßßïïá ###"#"#""""("("("("("&"("("("("(""""""#"#"### ïïïïßßßßßߥ¹ßïïïï ###"0((///(011))**2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''**1100(&///((0"# ïïßßßߥߥߥßßïßïïï """"""""""""""""""""""""""""  ïïïïßßßߥߥߥßßï¹ï #"0((&&///((11))**2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''**))00((///((0"### ïïïßßßߥßßßßßßï½áï "#"""""" ïïß½ßßßߥßßßßïßïï 1#"0((&(///(011))*'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**)100((///&+("#"# ïïßßßߥߥßßßßßßï½ïï $   ïïïß¹ßߥߥߥߥßß¹ßïï #"0((/////(011))**2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**))11((///((""###1 ïïïïßßß¹ßßß¹ßßßïïïï   ïïïßïßßß¹ßßß¹ßïßïï 1##"0((/&//&0011)*''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**))00((///&/((0"## áïïßßßߥߥߥßßñß¹ßïïïïá      ïïïßïßßßßßߥߥߥßßïßïï ###""((///&&0011)*''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22**))11((///&&((0"### ïáïïß¹ßߥߥߥßß¹ßïßïïáïá          ïáïï½ïß½ßßßߥߥßßßßïßïï ##"0(0(&///&(0011**'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22**))110(/////&("(0"# ïïßßßߥߥߥߥߥßßßßïßïïïïïï½              ïïïïïßïßßßßßߥߥߥߥßßßß¹ßïï ##"0((/&.//((0011)*'' þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2''))1100(&/&/&(0"0"### áïïßßß¹ßߥßéߥßßßß¹ßïßïïïïïïáïïïïïïïïïïïïßïßßß¹ßߥßéߥßßßß¹ßïïïï ###"0((&&///((11))**'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**)1100(&////&((0"##  áïïßïßñ¥ß¥ß¥ß¥ß¥ß¥ß¥ßßßßßßßß¹ßïßïßïßïßïßïßïßïßïßïßïßï¹ïßïßïßïßßßßßߥߥߥߥߥߥߥߥßßßßïïïï  #"0""(&//.//((01))**'' 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ ''**)100((/////((0"###1 ïïßïßßßߥߥߥߥߥߥߥߥߥߥ¹ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßߥߥߥߥߥߥߥߥߥßßßßïïïï 1##"0((&&///&&0011))**'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ ''**)110((//.//&/((0"##  ïïïïßßßߥߥߥ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ß¥ßßßßïßïï½ ##""((//././(0011))*'22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**))1100&&///&&((0"##1# ïïïßïßßßߥߥ¹¥¥¥¥¥¥¥¥¥¥¥¡¥¥¥\¥¥…¡…¥…¥…¥…¡¥¥¥\¥¥¥¥¥¥¥¥¥¥¥¡¥¥¥¹¥ß¥¹ß¹ßïïïï  ##"0"0((/&///((00))**''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**))1100((//.//&("(0"##  ïïïïßßßߥߥ¥¥¥¥¥…¥…¥…¥…¥………¥………………………………………¥…¥…¥…¥…¥…¥¥¥¥ß¥ß¥ßßïßïïï  ###"0((&&//.//((#01)**''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2''*)1)10((//.&/&/((0"###1  ïïïßïßßßߥߥ¥¥¥¥¥¥¥…¥…¥…¥……………………………¥…¥…¡…¥…¥¥¥¥¹¥ß¥¹ßñßïïïï 1##"#"0((&////&&0011))**'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22''**))1#0(//././/((((0"## ïïïïß¹ßߥߥߥ¥¥¥…¥…¥………¥……………………………¥…¥…¥…¥¥¥¥ßßßßßßïßïïï   ##""((&///.//((0011))**'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ ''**))1100((/&/&/(&((0"#####  ïïïï¹ïß¹ßߥߥ¥¥¡¥¥¥¥¥¥¥\¥¥¥¥¥¥¥¡¥ß¥ßßßßïßïïïïáï  1###00"0((/&///&&(011))**''2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2'**))1100((//././/((((""#"#   ïïïßïßßßߥߥߥ¥¥¥¥¥¥¥¥¥¥ß¥ßßßßßßïßïïïï  ##"0"0((/&//.//&(0011))**''2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 2''**))1100((//.//&/((""#"####  ïïïïïïïßïßßßßßß߽߽ßïßï½ïïáï   #####"0((((///////((0011))**'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 ''**))1100((//././/&&((0(""##   ááïïïïïïïïïïïïïïïï   #"""0((((////.//&/(0111)*)*'22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 22''**))1100((/////&/(("(0"######            #####"0"0((&&/&.////((0#11))**''2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22''**))1100((//././///((((0"0"###      ##"#"0("((/&//././/((0011)1))**'2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'**)*))1100((//./.&/&&((0(0"#"########"#"0""((((/&//.//&&((0011))**''2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22''**))1100(0////..././/(+(("(""""##"##"#"""0((((/&//./././/((00111)))**'' 3 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 2'*'**))11000(&(//.//&/&+(("(0(0"0"##########"#"0"0("((&&/&/&.////((001111))**''22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22''**))111100((////././///(/(((("(0"""#""#""#"#"#"#"""0""("((&(////./././/(((0#011))****'2 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 22''**))1)1100((&(////.//&/&/(&(("("(0"0"#"#"#""#""#""##"#"#"#"""#"""0("((((/(//////.////((001011))))**''2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22''**)*))110100((////./././///+/(+(((&(("("("("""""""""""""""("("((((,(&(/&////././././/(/((0011)1))**''22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 22''****))1)110000((///&//.&///&/&/(&(&(((("((("("("("("((("((((&(/(/&/&/&///////(&((001011))))**''22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ 3 22''**))))11110000((&(//////.//////////&/&/&+(/&+(/&+&/&/&////////././/////((((001011)1))****''2 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22''**)*))1)110100(0((&(/&/&///////&///&///&/&/&/&/&///&///////&/(/((((00001111))))**'*'222 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ33 2 22''**)*))1)11010000(0((((/&/&////////.///.///.////////&/(/((((0000101111))))****''22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 22''''****))))1)11#1010000(0(0((((&(((&(((&((((0(0(000010101111)1))*)****'''222 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ33 22''''****))))1)1111110101000#00000000000#000101010111111))))*)****''2'2 3 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 222''*'****)*)*))1)))1)111111111111111)111)1)1))))*)*)****''''22 þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ333 22'2''*'****)*)*)))))))))))))))))))))))*)*)******''''22 2 3 33þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3 222''''''*'*'*'***************'*'*''''''2'22 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ33 3 3 2 22'2'2'2'''''''''''''''''2'2222 3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3   3þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ3333333333333þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ \ No newline at end of file diff --git a/data/icons/softupdate.raw b/data/icons/softupdate.raw new file mode 100644 index 000000000..f56892173 Binary files /dev/null and b/data/icons/softupdate.raw differ diff --git a/data/icons/streaming.raw b/data/icons/streaming.raw new file mode 100644 index 000000000..f551a5389 Binary files /dev/null and b/data/icons/streaming.raw differ diff --git a/data/icons/subt.raw b/data/icons/subt.raw new file mode 100644 index 000000000..341ace228 Binary files /dev/null and b/data/icons/subt.raw differ diff --git a/data/icons/subt_gray.raw b/data/icons/subt_gray.raw new file mode 100644 index 000000000..d21fbba9b Binary files /dev/null and b/data/icons/subt_gray.raw differ diff --git a/data/icons/timer.raw b/data/icons/timer.raw new file mode 100644 index 000000000..788c83e40 Binary files /dev/null and b/data/icons/timer.raw differ diff --git a/data/icons/up.raw b/data/icons/up.raw new file mode 100644 index 000000000..a6df634d6 Binary files /dev/null and b/data/icons/up.raw differ diff --git a/data/icons/upnp.raw b/data/icons/upnp.raw new file mode 100644 index 000000000..4526efc8b Binary files /dev/null and b/data/icons/upnp.raw differ diff --git a/data/icons/video.raw b/data/icons/video.raw new file mode 100644 index 000000000..9c561cde8 Binary files /dev/null and b/data/icons/video.raw differ diff --git a/data/icons/volume.raw b/data/icons/volume.raw new file mode 100644 index 000000000..64fbc9c12 Binary files /dev/null and b/data/icons/volume.raw differ diff --git a/data/icons/volumebody.raw b/data/icons/volumebody.raw new file mode 100644 index 000000000..2f2a8e779 Binary files /dev/null and b/data/icons/volumebody.raw differ diff --git a/data/icons/volumeslider2.raw b/data/icons/volumeslider2.raw new file mode 100644 index 000000000..2f584e91a Binary files /dev/null and b/data/icons/volumeslider2.raw differ diff --git a/data/icons/volumeslider2alpha.raw b/data/icons/volumeslider2alpha.raw new file mode 100644 index 000000000..24744c390 Binary files /dev/null and b/data/icons/volumeslider2alpha.raw differ diff --git a/data/icons/volumeslider2blue.raw b/data/icons/volumeslider2blue.raw new file mode 100644 index 000000000..2a07eadf8 Binary files /dev/null and b/data/icons/volumeslider2blue.raw differ diff --git a/data/icons/volumeslider2green.raw b/data/icons/volumeslider2green.raw new file mode 100644 index 000000000..8d55d33ca Binary files /dev/null and b/data/icons/volumeslider2green.raw differ diff --git a/data/icons/volumeslider2red.raw b/data/icons/volumeslider2red.raw new file mode 100644 index 000000000..e89cba548 Binary files /dev/null and b/data/icons/volumeslider2red.raw differ diff --git a/data/icons/vtxt.raw b/data/icons/vtxt.raw new file mode 100644 index 000000000..42a2f7216 Binary files /dev/null and b/data/icons/vtxt.raw differ diff --git a/data/icons/vtxt_gray.raw b/data/icons/vtxt_gray.raw new file mode 100644 index 000000000..e00777956 Binary files /dev/null and b/data/icons/vtxt_gray.raw differ diff --git a/data/inetradio/radio-stations.xml b/data/inetradio/radio-stations.xml new file mode 100644 index 000000000..f5f121944 --- /dev/null +++ b/data/inetradio/radio-stations.xml @@ -0,0 +1,892 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/iso-codes/Makefile.am b/data/iso-codes/Makefile.am new file mode 100644 index 000000000..e5ddfc030 --- /dev/null +++ b/data/iso-codes/Makefile.am @@ -0,0 +1,5 @@ +installdir = $(datadir)/iso-codes + +install_DATA = \ + iso-639.tab + diff --git a/data/iso-codes/iso-639.tab b/data/iso-codes/iso-639.tab new file mode 100644 index 000000000..445b0f32f --- /dev/null +++ b/data/iso-codes/iso-639.tab @@ -0,0 +1,489 @@ +## iso-639.tab +## +## Copyright (C) 2004 Alastair McKinstry +## Released under the GNU License; see file COPYING for details +## +## Last update: 2004-03-29 +## +## This file gives a list of all languages in the ISO-639 +## standard, and is used to provide translations (via gettext) +## +## Status: ISO 639-2:1998 + additions and changes until 2003-03-05 +## Source: http://lcweb.loc.gov/standards/iso639-2/englangn.html +## +## Columns: +## iso-639-2 terminology code +## iso-639-2 bibliography code +## iso-639-1 code (XX if none exists) +## Name (English) +## +## Notes to translators: +## Please translate Bøkmal using a-ring (U+00E5) +## Please translate Proveçal using c-cedilla (U+00E7) +## +aar aar aa Afar +abk abk ab Abkhazian +ace ace XX Achinese +ach ach XX Acoli +ada ada XX Adangme +ady ady XX Adyghe; Adygei +afa afa XX Afro-Asiatic (Other) +afh afh XX Afrihili +afr afr af Afrikaans +aka aka ak Akan +akk akk ak Akkadian +alb sqi sq Albanian +ale ale XX Aleut +alg alg XX Algonquian languages +amh amh am Amharic +ang ang XX English, Old (ca.450-1100) +apa apa XX Apache languages +ara ara ar Arabic +arc arc XX Aramaic +arg arg an Aragonese +arm hye hy Armenian +arn arn XX Araucanian +arp arp XX Arapaho +art art XX Artificial (Other) +arw arw XX Arawak +asm asm as Assamese +ast ast XX Asturian; Bable +ath ath XX Athapascan language +aus aus XX Australian languages +ava ava av Avaric +ave ave ae Avestan +awa awa XX Awadhi +aym aym ay Aymara +aze aze az Azerbaijani +bad bad XX Banda +bai bai XX Bamileke languages +bak bak ba Bashkir +bal bal XX Baluchi +bam bam bm Bambara +ban ban XX Balinese +baq eus eu Basque +bas bas XX Basa +bat bat XX Baltic (Other) +bej bej XX Beja +bel bel be Belarusian +bem bem XX Bemba +ben ben bn Bengali +ber ber XX Berber (Other) +bho bho XX Bhojpuri +bih bih bh Bihari +bik bik XX Bikol +bin bin XX Bini +bis bis bi Bislama +bla bla XX Siksika +bnt bnt XX Bantu (Other) +bos bos bs Bosnian +bra bra XX Braj +bre bre br Breton +btk btk XX Batak (Indonesia) +bua bua XX Buriat +bug bug XX Buginese +bul bul bg Bulgarian +bur mya my Burmese +byn byn XX Blin; Bilin +cad cad XX Caddo +cai cai XX Central American Indian (Other) +car car XX Carib +cat cat ca Catalan +cau cau XX Caucasian (Other) +ceb ceb XX Cebuano +cel cel XX Celtic (Other) +cha cha ch Chamorro +chb chb XX Chibcha +che che ce Chechen +chg chg XX Chagatai +chi zho zh Chinese +chk chk XX Chukese +chm chm XX Mari +chn chn XX Chinook jargon +cho cho XX Choctaw +chp chp XX Chipewyan +chr chr XX Cherokee +chu chu XX Church Slavic +chv chv cv Chuvash +chy chy XX Cheyenne +cmc cmc XX Chamic languages +cop cop XX Coptic +cor cor kw Cornish +cos cos co Corsican +cpe cpe XX English-based (Other) +cpf cpf XX French-based (Other) +cpp cpp XX Portuguese-based (Other) +cre cre cr Cree +crh crh XX Crimean Turkish; Crimean Tatar +crp crp XX Creoles and pidgins (Other) +csb csb XX Kashubian +cus cus XX Cushitic (Other) +cus cus XX Portuguese-based (Other) +cze ces cs Czech +dak dak XX Dakota +dan dan da Danish +dar dar XX Dargwa +dsb dsb XX Lower Sorbian +del del XX Delaware +den den XX Slave (Athapascan) +dgr dgr XX Dogrib +din din XX Dinka +div div dv Divehi +doi doi XX Dogri +dra dra XX Dravidian (Other) +dua dua XX Duala +dum dum XX Dutch, Middle (ca. 1050-1350) +dut nld nl Dutch +dyu dyu XX Dyula +dzo dzo dz Dzongkha +efi efi XX Efik +egy egy XX Egyptian (Ancient) +eka eka XX Ekajuk +elx elx XX Elamite +eng eng en English +enm enm XX English, Middle (1100-1500) +epo epo eo Esperanto +est est et Estonian +ewe ewe ee Ewe +ewo ewo XX Ewondo +fan fan XX Fang +fao fao fo Faroese +fat fat XX Fanti +fij fij fj Fijian +fin fin fi Finnish +fiu fiu XX Finno-Ugrian (Other) +fon fon XX Fon +fre fra fr French +frm frm XX French, Middle (ca.1400-1600) +fro fro XX French, Old (842-ca.1400) +fry fry fy Frisian +ful ful ff Fulah +fur fur XX Friulian +gaa gaa ga Ga +gay gay XX Gayo +gba gba XX Gbaya +gem gem XX Germanic (Other) +geo kat ka Georgian +ger deu de German +gez gez XX Geez +gil gil XX Gilbertese +gla gla gd Gaelic; Scottish +gle gle ga Irish +glg glg gl Gallegan +glv glv gv Manx +gmh gmh XX German, Middle High (ca.1050-1500) +goh goh XX German, Old High (ca.750-1050) +gon gon XX Gondi +gor gor XX Gorontalo +got got XX Gothic +grb grb XX Grebo +grc grc XX Greek, Ancient (to 1453) +gre ell el Greek, Modern (1453-) +grn grn gn Guarani +guj guj gu Gujarati +gwi gwi XX Gwichin +hai hai XX Haida +hat hat ht Haitian; Haitian Creole +hau hau ha Hausa +haw haw XX Hawaiian +heb heb he Hebrew +her her hz Herero +hil hil XX Hiligaynon +him him XX Himachali +hin hin hi Hindi +hit hit XX Hittite +hmn hmn XX Hmong +hmo hmo ho Hiri +hsb hsb XX Upper Sorbian +hun hun hu Hungarian +hup hup XX Hupa +iba iba XX Iban +ibo ibo ig Igbo +ice isl is Icelandic +ido ido io Ido +iii iii ii Sichuan Yi +ijo ijo XX Ijo +iku iku iu Inuktitut +ile ile ie Interlingue +ilo ilo XX Iloko +ina ina ia Interlingua +inc inc XX Indic (Other) +ind ind id Indonesian +ine ine XX Indo-European (Other) +inh inh XX Ingush +ipk ipk ik Inupiaq +ira ira XX Iranian (Other) +iro iro XX Iroquoian languages +ita ita it Italian +jav jav jv Javanese +jbo jbo XX Lojban +jpn jpn ja Japanese +jpr jpr XX Judeo-Persian +jrb jrb XX Judeo-Arabic +kaa kaa XX Kara-Kalpak +kab kab XX Kabyle +kac kac XX Kachin +kal kal kl Greenlandic (Kalaallisut) +kam kam XX Kamba +kan kan kn Kannada +kar kar XX Karen +kas kas ks Kashmiri +kau kau kr Kanuri +kaw kaw XX Kawi +kaz kaz kk Kazakh +kbd kbd XX Kabardian +kha kha XX Khazi +khi khi XX Khoisan (Other) +khm khm km Khmer +kho kho XX Khotanese +kik kik ki Kikuyu +kin kin rw Kinyarwanda +kir kir ky Kirghiz +kmb kmb XX Kimbundu +kok kok XX Konkani +kom kom kv Komi +kon kon kg Kongo +kor kor ko Korean +kos kos XX Kosraean +kpe kpe XX Kpelle +krc krc XX Karachay-Balkar +kro kro XX Kru +kru kru XX Kurukh +kua kua kj Kuanyama +kum kum XX Kumyk +kur kur ku Kurdish +kut kut XX Kutenai +lad lad XX Ladino +lah lah XX Lahnda +lam lam XX Lamba +lao lao lo Lao +lat lat la Latin +lav lav lv Latvian +lez lez XX Lezghian +lim lim li Limburgian +lin lin ln Lingala +lit lit lt Lithuanian +lol lol XX Mongo +loz loz XX Lozi +ltz ltz lb Luxembourgish +lua lua XX Luba-Lulua +lub lub lu Luba-Katanga +lug lug lg Ganda +lui lui XX Luiseno +lun lun XX Lunda +luo luo XX Luo (Kenya and Tanzania) +lus lus XX Lushai +mac mkd mk Macedonian +mad mad XX Madurese +mag mag XX Magahi +mah mah mh Marshallese +mai mai XX Maithili +mak mak XX Makasar +mal mal ml Malayalam +man man XX Mandingo +mao mri mi Maori +map map XX Austronesian (Other) +mar mar mr Marathi +mas mas XX Masai +may msa ms Malay +mdf mdf XX Moksha +mdr mdr XX Mandar +men men XX Mende +mga mga XX Irish, Middle (900-1200) +mic mic XX Micmac +min min XX Minangkabau +mis mis XX Miscellaneous languages +mkh mkh XX Mon-Khmer (Other) +mlg mlg mg Malagasy +mlt mlt mt Maltese +mnc mnc XX Manchu +mno mno XX Manobo languages +moh moh XX Mohawk +mol mol mo Moldavian +mon mon mn Mongolian +mos mos XX Mossi +mul mul XX Multiple languages +mun mun XX Munda languages +mus mus XX Creek +mwr mwr XX Marwari +myn myn XX Mayan languages +myv myv XX Erzya +nah nah XX Nahuatl +nai nai XX North American Indian (Other) +nap nap XX Neapolitan +nau nau na Nauru +nav nav nv Navaho +nbl nbl nr Ndebele, South +nde nde nd Ndebele, North +ndo ndo ng Ndonga +nds nds XX German, Low +nep nep ne Nepali +new new XX Newari +nia nia XX Nias +nic nic XX Niger-Kordofanian (Other) +niu niu XX Niuean +nno nno nn Norwegian Nynorsk +nob nob nb Bøkmal, Norwegian +nog nog XX Nogai +non non XX Norse, Old +nor nor no Norwegian +nso nso XX Sotho, Northern +nub nub XX Nubian languages +nwc nwc XX Classical Newari; Old Newari +nya nya ny Chewa; Chichewa; Nyanja +nym nym XX Nyankole +nyo nyo XX Nyoro +nzi nzi XX Nzima +oci oci oc Occitan (post 1500) +oji oji oj Ojibwa +ori ori or Oriya +orm orm om Oromo +osa osa XX Osage +oss oss os Ossetian +ota ota XX Turkish, Ottoman (1500-1928) +oto oto XX Otomian languages +paa paa XX Papuan (Other) +pag pag XX Pangasinan +pal pal XX Pahlavi +pam pam XX Pampanga +pan pan pa Panjabi +pap pap XX Papiamento +pau pau XX Palauan +peo peo XX Persian, Old (ca.600-400 B.C.) +per fas fa Persian +phi phi XX Philippine (Other) +phn phn XX Phoenician +pli pli pi Pali +pol pol pl Polish +por por pt Portuguese +pon pon XX Pohnpeian +pra pra XX Prakrit languages +pro pro XX Proveçal, Old (to 1500) +pus pus ps Pushto +que que qu Quechua +raj raj XX Rajasthani +rap rap XX Rapanui +rar rar XX Rarotongan +roa roa XX Romance (Other) +roh roh rm Raeto-Romance +rom rom XX Romany +rum ron ro Romanian +run run rn Rundi +rus rus ru Russian +sad sad XX Sandawe +sag sag sg Sango +sah sah XX Yakut +sai sai XX South American Indian (Other) +sal sal XX Salishan languages +sam sam XX Samaritan Aramaic +san san sa Sanskrit +sas sas XX Sasak +sat sat XX Santali +scc srp sr Serbian +sco sco XX Scots +scr hrv hr Croatian +sel sel XX Selkup +sem sem XX Semitic (Other) +sga sga XX Irish, Old (to 900) +sgn sgn XX Sign languages +shn shn XX Shan +sid sid XX Sidamo +sin sin si Sinhalese +sio sio XX Siouan languages +sit sit XX Sino-Tibetan (Other) +sla sla XX Slavic (Other) +slo slk sk Slovak +slv slv sl Slovenian +sma sma XX Southern Sami +sme sme se Northern Sami +smi smi XX Sami languages (Other) +smj smj XX Lule Sami +smn smn XX Inari Sami +smo smo sm Samoan +sms sms XX Skolt Sami +sna sna sn Shona +snd snd sd Sindhi +snk snk XX Soninke +sog sog XX Sogdian +som som so Somali +son son XX Songhai +sot sot st Sotho, Southern +spa spa es Spanish (Castilian) +srd srd sc Sardinian +srr srr XX Serer +ssa ssa XX Nilo-Saharan (Other) +ssw ssw ss Swati +suk suk XX Sukuma +sun sun su Sundanese +sus sus XX Susu +sux sux XX Sumerian +swa swa sw Swahili +swe swe sv Swedish +syr syr XX Syriac +tah tah ty Tahitian +tai tai XX Tai (Other) +tam tam ta Tamil +tao tso ts Tsonga +tat tat tt Tatar +tel tel te Telugu +tem tem XX Timne +ter ter XX Tereno +tet tet XX Tetum +tgk tgk tg Tajik +tgl tgl tl Tagalog +tha tha th Thai +tib bod bo Tibetan +tig tig XX Tigre +tir tir ti Tigrinya +tiv tiv XX Tiv +tkl tkl XX Tokelau +tlh tlh XX Klingon; tlhIngan-Hol +tli tli XX Tlinglit +tmh tmh XX Tamashek +tog tog XX Tonga (Nyasa) +ton ton to Tonga (Tonga Islands) +tpi tpi XX Tok Pisin +tsi tsi XX Tsimshian +tsn tsn tn Tswana +tuk tuk tk Turkmen +tum tum XX Tumbuka +tup tup XX Tupi languages +tur tur tr Turkish +tut tut XX Altaic (Other) +tvl tvl XX Tuvalu +twi twi tw Twi +tyv tyv XX Tuvinian +udm udm XX Udmurt +uga uga XX Ugaritic +uig uig ug Uighur +ukr ukr uk Ukrainian +umb umb XX Umbundu +und und XX Undetermined +urd urd ur Urdu +uzb uzb uz Uzbek +vai vai XX Vai +ven ven ve Venda +vie vie vi Vietnamese +vol vol vo Volapuk +vot vot XX Votic +wak wak XX Wakashan languages +wal wal XX Walamo +war war XX Waray +was was XX Washo +wel cym cy Welsh +wen wen XX Sorbian languages +wln wln wa Walloon +wol wol wo Wolof +xal xal XX Kalmyk +xho xho xh Xhosa +yao yao XX Yao +yap yap XX Yapese +yid yid yi Yiddish +yor yor yo Yoruba +ypk ypk XX Yupik languages +zap zap XX Zapotec +zen zen XX Zenaga +zha zha za Chuang; Zhuang +znd znd XX Zande +zul zul zu Zulu +zun zun XX Zuni diff --git a/data/lcd/Makefile.am b/data/lcd/Makefile.am new file mode 100644 index 000000000..5de814315 --- /dev/null +++ b/data/lcd/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = clock icons diff --git a/data/lcd/clock/Makefile.am b/data/lcd/clock/Makefile.am new file mode 100644 index 000000000..9dbe826bd --- /dev/null +++ b/data/lcd/clock/Makefile.am @@ -0,0 +1,8 @@ +installdir = $(DATADIR)/lcdd/clock + +install_DATA = \ + d_a.bmp d_b.bmp d_c.bmp d_d.bmp d_e.bmp d_f.bmp d_g.bmp d_h.bmp d_i.bmp d_j.bmp \ + m_a.bmp m_b.bmp m_c.bmp m_d.bmp m_e.bmp m_f.bmp m_g.bmp m_h.bmp m_i.bmp m_j.bmp m_k.bmp m_l.bmp \ + t_a.bmp t_b.bmp t_c.bmp t_d.bmp t_e.bmp t_f.bmp t_g.bmp t_h.bmp t_i.bmp t_j.bmp \ + w_a.bmp w_b.bmp w_c.bmp w_d.bmp w_e.bmp w_f.bmp w_g.bmp + diff --git a/data/lcd/clock/d_a.bmp b/data/lcd/clock/d_a.bmp new file mode 100644 index 000000000..754645dea Binary files /dev/null and b/data/lcd/clock/d_a.bmp differ diff --git a/data/lcd/clock/d_b.bmp b/data/lcd/clock/d_b.bmp new file mode 100644 index 000000000..235d6f938 Binary files /dev/null and b/data/lcd/clock/d_b.bmp differ diff --git a/data/lcd/clock/d_c.bmp b/data/lcd/clock/d_c.bmp new file mode 100644 index 000000000..662c4fc03 Binary files /dev/null and b/data/lcd/clock/d_c.bmp differ diff --git a/data/lcd/clock/d_d.bmp b/data/lcd/clock/d_d.bmp new file mode 100644 index 000000000..2003e3d79 Binary files /dev/null and b/data/lcd/clock/d_d.bmp differ diff --git a/data/lcd/clock/d_e.bmp b/data/lcd/clock/d_e.bmp new file mode 100644 index 000000000..a166428dd Binary files /dev/null and b/data/lcd/clock/d_e.bmp differ diff --git a/data/lcd/clock/d_f.bmp b/data/lcd/clock/d_f.bmp new file mode 100644 index 000000000..556a29fe7 Binary files /dev/null and b/data/lcd/clock/d_f.bmp differ diff --git a/data/lcd/clock/d_g.bmp b/data/lcd/clock/d_g.bmp new file mode 100644 index 000000000..8f7009fd9 Binary files /dev/null and b/data/lcd/clock/d_g.bmp differ diff --git a/data/lcd/clock/d_h.bmp b/data/lcd/clock/d_h.bmp new file mode 100644 index 000000000..194cac11f Binary files /dev/null and b/data/lcd/clock/d_h.bmp differ diff --git a/data/lcd/clock/d_i.bmp b/data/lcd/clock/d_i.bmp new file mode 100644 index 000000000..ec0c0025a Binary files /dev/null and b/data/lcd/clock/d_i.bmp differ diff --git a/data/lcd/clock/d_j.bmp b/data/lcd/clock/d_j.bmp new file mode 100644 index 000000000..3be6c6c78 Binary files /dev/null and b/data/lcd/clock/d_j.bmp differ diff --git a/data/lcd/clock/m_a.bmp b/data/lcd/clock/m_a.bmp new file mode 100644 index 000000000..3a7996b27 Binary files /dev/null and b/data/lcd/clock/m_a.bmp differ diff --git a/data/lcd/clock/m_b.bmp b/data/lcd/clock/m_b.bmp new file mode 100644 index 000000000..45be0f8e4 Binary files /dev/null and b/data/lcd/clock/m_b.bmp differ diff --git a/data/lcd/clock/m_c.bmp b/data/lcd/clock/m_c.bmp new file mode 100644 index 000000000..a8a68c8af Binary files /dev/null and b/data/lcd/clock/m_c.bmp differ diff --git a/data/lcd/clock/m_d.bmp b/data/lcd/clock/m_d.bmp new file mode 100644 index 000000000..a9219b646 Binary files /dev/null and b/data/lcd/clock/m_d.bmp differ diff --git a/data/lcd/clock/m_e.bmp b/data/lcd/clock/m_e.bmp new file mode 100644 index 000000000..b43b8402f Binary files /dev/null and b/data/lcd/clock/m_e.bmp differ diff --git a/data/lcd/clock/m_f.bmp b/data/lcd/clock/m_f.bmp new file mode 100644 index 000000000..5d456fe92 Binary files /dev/null and b/data/lcd/clock/m_f.bmp differ diff --git a/data/lcd/clock/m_g.bmp b/data/lcd/clock/m_g.bmp new file mode 100644 index 000000000..516bd75d7 Binary files /dev/null and b/data/lcd/clock/m_g.bmp differ diff --git a/data/lcd/clock/m_h.bmp b/data/lcd/clock/m_h.bmp new file mode 100644 index 000000000..55e1a8308 Binary files /dev/null and b/data/lcd/clock/m_h.bmp differ diff --git a/data/lcd/clock/m_i.bmp b/data/lcd/clock/m_i.bmp new file mode 100644 index 000000000..1943d42c2 Binary files /dev/null and b/data/lcd/clock/m_i.bmp differ diff --git a/data/lcd/clock/m_j.bmp b/data/lcd/clock/m_j.bmp new file mode 100644 index 000000000..07e4f8449 Binary files /dev/null and b/data/lcd/clock/m_j.bmp differ diff --git a/data/lcd/clock/m_k.bmp b/data/lcd/clock/m_k.bmp new file mode 100644 index 000000000..0176fe995 Binary files /dev/null and b/data/lcd/clock/m_k.bmp differ diff --git a/data/lcd/clock/m_l.bmp b/data/lcd/clock/m_l.bmp new file mode 100644 index 000000000..968658e09 Binary files /dev/null and b/data/lcd/clock/m_l.bmp differ diff --git a/data/lcd/clock/t_a.bmp b/data/lcd/clock/t_a.bmp new file mode 100644 index 000000000..2b086f452 Binary files /dev/null and b/data/lcd/clock/t_a.bmp differ diff --git a/data/lcd/clock/t_b.bmp b/data/lcd/clock/t_b.bmp new file mode 100644 index 000000000..86e227b84 Binary files /dev/null and b/data/lcd/clock/t_b.bmp differ diff --git a/data/lcd/clock/t_c.bmp b/data/lcd/clock/t_c.bmp new file mode 100644 index 000000000..bb3ce9530 Binary files /dev/null and b/data/lcd/clock/t_c.bmp differ diff --git a/data/lcd/clock/t_d.bmp b/data/lcd/clock/t_d.bmp new file mode 100644 index 000000000..75ec0544d Binary files /dev/null and b/data/lcd/clock/t_d.bmp differ diff --git a/data/lcd/clock/t_e.bmp b/data/lcd/clock/t_e.bmp new file mode 100644 index 000000000..ea506c38d Binary files /dev/null and b/data/lcd/clock/t_e.bmp differ diff --git a/data/lcd/clock/t_f.bmp b/data/lcd/clock/t_f.bmp new file mode 100644 index 000000000..3b9179667 Binary files /dev/null and b/data/lcd/clock/t_f.bmp differ diff --git a/data/lcd/clock/t_g.bmp b/data/lcd/clock/t_g.bmp new file mode 100644 index 000000000..a2f4ca2b8 Binary files /dev/null and b/data/lcd/clock/t_g.bmp differ diff --git a/data/lcd/clock/t_h.bmp b/data/lcd/clock/t_h.bmp new file mode 100644 index 000000000..95994b027 Binary files /dev/null and b/data/lcd/clock/t_h.bmp differ diff --git a/data/lcd/clock/t_i.bmp b/data/lcd/clock/t_i.bmp new file mode 100644 index 000000000..cf9e49a1a Binary files /dev/null and b/data/lcd/clock/t_i.bmp differ diff --git a/data/lcd/clock/t_j.bmp b/data/lcd/clock/t_j.bmp new file mode 100644 index 000000000..38afd4770 Binary files /dev/null and b/data/lcd/clock/t_j.bmp differ diff --git a/data/lcd/clock/w_a.bmp b/data/lcd/clock/w_a.bmp new file mode 100644 index 000000000..2f9acf744 Binary files /dev/null and b/data/lcd/clock/w_a.bmp differ diff --git a/data/lcd/clock/w_b.bmp b/data/lcd/clock/w_b.bmp new file mode 100644 index 000000000..5e3897290 Binary files /dev/null and b/data/lcd/clock/w_b.bmp differ diff --git a/data/lcd/clock/w_c.bmp b/data/lcd/clock/w_c.bmp new file mode 100644 index 000000000..1923a853a Binary files /dev/null and b/data/lcd/clock/w_c.bmp differ diff --git a/data/lcd/clock/w_d.bmp b/data/lcd/clock/w_d.bmp new file mode 100644 index 000000000..a04b31800 Binary files /dev/null and b/data/lcd/clock/w_d.bmp differ diff --git a/data/lcd/clock/w_e.bmp b/data/lcd/clock/w_e.bmp new file mode 100644 index 000000000..675363b41 Binary files /dev/null and b/data/lcd/clock/w_e.bmp differ diff --git a/data/lcd/clock/w_f.bmp b/data/lcd/clock/w_f.bmp new file mode 100644 index 000000000..d5ed8d3a5 Binary files /dev/null and b/data/lcd/clock/w_f.bmp differ diff --git a/data/lcd/clock/w_g.bmp b/data/lcd/clock/w_g.bmp new file mode 100644 index 000000000..953556262 Binary files /dev/null and b/data/lcd/clock/w_g.bmp differ diff --git a/data/lcd/icons/Makefile.am b/data/lcd/icons/Makefile.am new file mode 100644 index 000000000..f5f510c6e --- /dev/null +++ b/data/lcd/icons/Makefile.am @@ -0,0 +1,10 @@ +installdir = $(DATADIR)/lcdd/icons + +install_DATA = \ + lcd.png \ + lcd2.png \ + lcd3.png \ + power.png \ + setup.png \ + rclock.raw + diff --git a/data/lcd/icons/lcd.png b/data/lcd/icons/lcd.png new file mode 100644 index 000000000..3db34a961 Binary files /dev/null and b/data/lcd/icons/lcd.png differ diff --git a/data/lcd/icons/lcd2.png b/data/lcd/icons/lcd2.png new file mode 100644 index 000000000..27c8a4ee7 Binary files /dev/null and b/data/lcd/icons/lcd2.png differ diff --git a/data/lcd/icons/lcd3.png b/data/lcd/icons/lcd3.png new file mode 100644 index 000000000..b2a32acc2 Binary files /dev/null and b/data/lcd/icons/lcd3.png differ diff --git a/data/lcd/icons/power.png b/data/lcd/icons/power.png new file mode 100644 index 000000000..a3667e75c Binary files /dev/null and b/data/lcd/icons/power.png differ diff --git a/data/lcd/icons/rclock.raw b/data/lcd/icons/rclock.raw new file mode 100644 index 000000000..948fd5726 Binary files /dev/null and b/data/lcd/icons/rclock.raw differ diff --git a/data/lcd/icons/setup.png b/data/lcd/icons/setup.png new file mode 100644 index 000000000..091945c21 Binary files /dev/null and b/data/lcd/icons/setup.png differ diff --git a/data/locale/Makefile.am b/data/locale/Makefile.am new file mode 100644 index 000000000..b47235c3a --- /dev/null +++ b/data/locale/Makefile.am @@ -0,0 +1,46 @@ +installdir = $(DATADIR)/neutrino/locale + +install_DATA = \ + bayrisch.locale \ + bosanski.locale \ + ch-baslerdeutsch.locale \ + ch-berndeutsch.locale \ + deutsch.locale \ + english.locale \ + francais.locale \ + italiano.locale \ + nederlands.locale \ + polski.locale \ + portugues.locale \ + russkij.locale \ + suomi.locale \ + svenska.locale + + +if MAINTAINER_MODE + +locals: locals.h locals_intern.h + +ordercheck: deutsch.locale + cut -d' ' -f1 deutsch.locale | LC_ALL=C sort | uniq > /tmp/log + cut -d' ' -f1 deutsch.locale | uniq | diff - /tmp/log || \ + (echo "ERROR: deutsch.locale not ordered or contains empty lines" && false) + +locals.h: ordercheck deutsch.locale + cut -d' ' -f1 deutsch.locale | LC_ALL=C sort | uniq | tr [:lower:] [:upper:] | tr \. \_ | tr \- \_ | tr -d \? | ./create.locals.h + +locals_intern.h: ordercheck deutsch.locale + cut -d' ' -f1 deutsch.locale | LC_ALL=C sort | uniq | ./create.locals_intern.h + +check: locals.h locals_intern.h + diff locals.h ../../src/system + diff locals_intern.h ../../src/system + +install-locals: locals.h locals_intern.h + cp locals.h locals_intern.h ../../src/system + @echo "Consider committing .../neutrino/src/system/[locals.h,locals_intern.h]" + +locals-clean: + rm -f locals.h locals_intern.h + +endif diff --git a/data/locale/_readme.txt b/data/locale/_readme.txt new file mode 100644 index 000000000..97044e9d4 --- /dev/null +++ b/data/locale/_readme.txt @@ -0,0 +1,67 @@ +Format of .locale files: +------------------------ +character encoding: UTF-8 +filename suffix : .locale + +Files must be strictly alphabetically ordered, and must not contain +any empty lines. + +Destination of .locale files: +----------------------------- +directory: /var/tuxbox/config/locale or /share/tuxbox/neutrino/locale + +Master file: +------------ +deutsch.locale is considered the master file. + + +Verfication of .locale files: +----------------------------- +Use the check.locale.files shell script for detecting +- violations of the sorting order, +- missing translations and +- legacy strings. + + + +How do I add a new locale string? +--------------------------------- +1.) +First of all, add the new string to deutsch.locale while preserving +the ordering. Do not add any empty lines. Use `make ordercheck' to for +verification. + +2.) +Enter the directory apps/tuxbox/neutrino/data/locale. + +3.) +Create new versions of the files apps/tuxbox/neutrino/src/system/locals.h +and apps/tuxbox/neutrino/src/system/locals_intern.h +using the command `make locals.h locals_intern.h'. + +4.) +Check the modifications with `make check', or with +diff locals.h ../../src/system/locals.h +diff locals_intern.h ../../src/system/locals_intern.h + +5.) +Copy the replacement file to their destination with `make install-locals', +or with +cp -p locals.h ../../src/system/locals.h +cp -p locals_intern.h ../../src/system/locals_intern.h + +6.) +To the extent possible, update other locale file. For this, the +Perl-script create-locals-update.pl may be useful. + +7.) +If committing the changes to CVS, commit both the involved +locale-files, apps/tuxbox/neutrino/src/system/locals.h, and +as apps/tuxbox/neutrino/src/system/locals_intern.h. + +Useful tools: +------------- +- emacs (add '(file-coding-system-alist (quote (("\\.locale\\'" . utf-8-unix) ("" undecided)))) to .emacs or use "C-x c utf-8 C-x C-f deutsch.locale") +- iconv +- sort +- uxterm diff --git a/data/locale/bayrisch.locale b/data/locale/bayrisch.locale new file mode 100644 index 000000000..693b7265b --- /dev/null +++ b/data/locale/bayrisch.locale @@ -0,0 +1,708 @@ +EPGMenu.epgplus Vorschau Ãœbersicht +EPGMenu.eventinfo Info zur Sendung +EPGMenu.eventlist Vorschau aktuells Programm +EPGMenu.head EPG - Programm Informationa +EPGMenu.streaminfo technische Informationa +EPGPlus.head Vorschau Ãœbasicht (EPG Plus) +EPGPlus.record Aufnema +EPGPlus.refresh_epg Aktualisiern +EPGPlus.remind Vormerkn +EPGPlus.scroll_mode Roin +EPGPlus.stretch_mode Streckn +GENRE.ARTS.0 Kunst / Kultur +GENRE.ARTS.1 Darstellende Künste +GENRE.ARTS.10 Kunst-/Kultur-Magazin +GENRE.ARTS.11 Mode +GENRE.ARTS.2 fine arts +GENRE.ARTS.3 Religion +GENRE.ARTS.4 Volkskunst +GENRE.ARTS.5 Literatur +GENRE.ARTS.6 Film/Kino +GENRE.ARTS.7 experimental film/video +GENRE.ARTS.8 Rundfunk/Presse +GENRE.ARTS.9 Neue Medien +GENRE.CHILDRENs_PROGRAMMES.0 Kinder / Jugendprogramm +GENRE.CHILDRENs_PROGRAMMES.1 Programm für Vorschulkinder +GENRE.CHILDRENs_PROGRAMMES.2 Unterhaltungsprogramm für 6 bis 14-Jährige +GENRE.CHILDRENs_PROGRAMMES.3 Unterhaltungsprogramm für 10 bis 16-Jährige +GENRE.CHILDRENs_PROGRAMMES.4 Informations- und Bildungsprogramm +GENRE.CHILDRENs_PROGRAMMES.5 Trickfilm +GENRE.DOCUS_MAGAZINES.0 Doku/Magazin +GENRE.DOCUS_MAGAZINES.1 Natur/Tiere/Umwelt +GENRE.DOCUS_MAGAZINES.2 Naturwissenschaft und Technik +GENRE.DOCUS_MAGAZINES.3 Medizin/Physiologie/Psychologie +GENRE.DOCUS_MAGAZINES.4 Ausland/Expeditions +GENRE.DOCUS_MAGAZINES.5 Sozial- und Geisteswissenschaften +GENRE.DOCUS_MAGAZINES.6 Weiterbildung +GENRE.DOCUS_MAGAZINES.7 Sprachen +GENRE.MOVIE.0 Spielfilm / Drama +GENRE.MOVIE.1 Kriminalfilm/Thriller +GENRE.MOVIE.2 Abenteuerfilm/Western/Kriegsfilm +GENRE.MOVIE.3 Science-Fiction/Fantasy/Horror +GENRE.MOVIE.4 Comedy +GENRE.MOVIE.5 Soap/Melodram/Folklore +GENRE.MOVIE.6 Romantik +GENRE.MOVIE.7 serious/classical/religious/historical movie/drama +GENRE.MOVIE.8 adult movie/Drama +GENRE.MUSIC_DANCE.0 Musik/Ballet/Tanz +GENRE.MUSIC_DANCE.1 Rock/Pop +GENRE.MUSIC_DANCE.2 serious music/Klassik +GENRE.MUSIC_DANCE.3 Volksmusik +GENRE.MUSIC_DANCE.4 Jazz +GENRE.MUSIC_DANCE.5 Musical/Oper +GENRE.MUSIC_DANCE.6 Ballet +GENRE.NEWS.0 Nachrichten +GENRE.NEWS.1 Nachrichten/Wetter +GENRE.NEWS.2 Nachrichtenmagazin +GENRE.NEWS.3 Dokumantation +GENRE.NEWS.4 Diskussion/Interview/Debatte +GENRE.SHOW.0 Show / Gameshow +GENRE.SHOW.1 Gameshow/Quiz +GENRE.SHOW.2 varietee +GENRE.SHOW.3 Talkshow +GENRE.SOCIAL_POLITICAL.0 Sozial & Politikereignisse / Wirtschaft +GENRE.SOCIAL_POLITICAL.1 Magazin/Report/Dokumentation +GENRE.SOCIAL_POLITICAL.2 Wirtschaft und Soziales +GENRE.SOCIAL_POLITICAL.3 Besondere Menschen +GENRE.SPORTS.0 Sport +GENRE.SPORTS.1 Großereignisse (Olympische Spiele, Weltmeisterschaften usw.) +GENRE.SPORTS.10 equestrian +GENRE.SPORTS.11 martial sports +GENRE.SPORTS.2 Sportsmagazine +GENRE.SPORTS.3 Fußball +GENRE.SPORTS.4 Tennis +GENRE.SPORTS.5 Mannschaftssport +GENRE.SPORTS.6 Leichtathletik +GENRE.SPORTS.7 Motorsport +GENRE.SPORTS.8 Wassersport +GENRE.SPORTS.9 Wintersport +GENRE.TRAVEL_HOBBIES.0 Reise & Freizeit +GENRE.TRAVEL_HOBBIES.1 Reisen und Tourismus +GENRE.TRAVEL_HOBBIES.2 handicraft +GENRE.TRAVEL_HOBBIES.3 Motor +GENRE.TRAVEL_HOBBIES.4 Fitness und Gesundheit +GENRE.TRAVEL_HOBBIES.5 Kochen +GENRE.TRAVEL_HOBBIES.6 Einkauf +GENRE.TRAVEL_HOBBIES.7 Garten +GENRE.UNKNOWN Kenninet +apids.hint_1 Gems de APIDs zu streama getrend +apids.hint_2 mid ' ' in hexadezimol ei +apidselector.head Sproch auswaehn +audiomenu.PCMOffset Lautstärknabsenkung PCM +audiomenu.analogout Analog-Ausgong +audiomenu.avs avs +audiomenu.avs_control Eistain avs/ost +audiomenu.dolbydigital Dolby Digital +audiomenu.head Audio-Eistellunga +audiomenu.lirc lirc +audiomenu.monoleft mono links +audiomenu.monoright mono rechts +audiomenu.ost ost +audiomenu.stereo stereo +audioplayer.add dazuadoa +audioplayer.artist_title Interpret, Titl +audioplayer.defdir Start-Verz. +audioplayer.delete löschn +audioplayer.deleteall olle löschn +audioplayer.display_order Ozoagn +audioplayer.fastforward schnei vieri +audioplayer.follow aktuelle Liad +audioplayer.id3scan ID3-Tags durchsuacha +audioplayer.keylevel Tasdn-Umschoitung +audioplayer.pause Pause +audioplayer.play obspuin +audioplayer.playing Spuin +audioplayer.rewind rewind +audioplayer.screensaver_timeout Buidschirmschona (minutn, 0=aus) +audioplayer.shuffle wias kumt +audioplayer.stop stopn +audioplayer.title_artist Titl, Interpret +audioplayerpicsettings.general Musi spuin / Buidl schaugn +bookmarkmanager.delete Löschn +bookmarkmanager.name Lesezeichn +bookmarkmanager.rename Umbnenna +bookmarkmanager.select Auswäihn +bouqueteditor.add Dazuamacha +bouqueteditor.bouquetname Nama vom Bouquet +bouqueteditor.delete Wegmacha +bouqueteditor.discardingchanges D Änderunga wern verworfa. Kloana Moment ... +bouqueteditor.hide Vastecka +bouqueteditor.lock Sperrn +bouqueteditor.move Vaschiam +bouqueteditor.name Bouquets verwoitn +bouqueteditor.newbouquetname Da neie Nama vom Bouquet +bouqueteditor.rename Umnenna +bouqueteditor.return Jetz hammas +bouqueteditor.savechanges? Soin de Änderunga gspeichat wern? +bouqueteditor.savingchanges D Änderunga wern gspeichat. An Moment ... +bouqueteditor.switch Senda dazuadoa/wegmacha +bouqueteditor.switchmode TV/Radio +bouquetlist.head Bouquets +cablesetup.provider Kabiobieta +channellist.head Olle Senda +channellist.nonefound Es san koane Senda gfundn worn!\nMachas bittschön a Sendersuach\n(dbox-Taste -> Service) +channellist.since seid %02d:%02d +colorchooser.alpha alpha +colorchooser.blue blau +colorchooser.green grea +colorchooser.red rot +colormenu.background Hintergrundfarb +colormenu.background_head Hintergrundfarbe +colormenu.fade Menüs faden +colormenu.font Schriftgräßn +colormenu.gtx_alpha Alpha überblendunga +colormenu.head Farb-Eistellunga +colormenu.menucolors Menüfarbn +colormenu.statusbar Statusboikn +colormenu.textcolor Textfarb +colormenu.textcolor_head Textfarb +colormenu.themeselect Theme auswähn +colormenu.timing OSD Timeouts +colormenusetup.head Menüfarbn +colormenusetup.menucontent Fenstainhoit +colormenusetup.menucontent_inactive Fenstainhoit deaktiviert +colormenusetup.menucontent_selected Fenstainhoit ausgwähit +colormenusetup.menuhead Titelleistn +colorstatusbar.head Statusboikn-Farbn +colorstatusbar.text Statusboikn +colorthememenu.classic_theme Klassik +colorthememenu.head Theme auswähn +colorthememenu.neutrino_theme Neutrino Theme +date.Apr Apr +date.Aug Aug +date.Dec Dez +date.Feb Feb +date.Fri Fr +date.Jan Jan +date.Jul Jul +date.Jun Jun +date.Mar Mär +date.May Mai +date.Mon Mo +date.Nov Nov +date.Oct Okt +date.Sat Sa +date.Sep Sep +date.Sun So +date.Thu Do +date.Tue Di +date.Wed Mi +epglist.head Vorschau - %s +epglist.noevents Koa EPG do. +epgviewer.More_Screenings Des kumt no auf dem Senda... +epgviewer.nodetailed Koane bessan Informationen gfundn +epgviewer.notfound Koa EPG gfundn +favorites.addchannel Der Senda werd zum \n"De Meina" dazuado. \nDes Speichan dauert a bissl... +favorites.bouquetname De Meina +favorites.bqcreated Bouquet "De Meina" is oglegt worn...\n +favorites.chadded Der Senda is zu Eanare Favoriten dazuado worn...\n +favorites.chalreadyinbq Der Senda ist scho in Eanare Favoriten...\n +favorites.finalhint \nWans Eana vahaut ham\nder Bouquetverwaltung korrigiert werden.\n +favorites.menueadd Kanal Favoriten dazuadoa +favorites.nobouquets Favoriten genga nur wann Bouquets aktiviert san +filebrowser.delete Löschn +filebrowser.dodelete1 Soi +filebrowser.dodelete2 glöscht wern? +filebrowser.filter.active Fuita o +filebrowser.filter.inactive Fuita aus +filebrowser.head Datiesucha +filebrowser.mark markiern +filebrowser.nextpage Seitn viri +filebrowser.prevpage Seitn zruck +filebrowser.scan Verzeichnisse durchsuacha +filebrowser.select auswaehn +filebrowser.showrights Dateirechte ozoang +filebrowser.sort.date (Datum) +filebrowser.sort.name (Nama) +filebrowser.sort.namedirsfirst (Dateinama2) +filebrowser.sort.size (Greaß) +filebrowser.sort.type (Typ) +flashupdate.actionreadflash flash lesn +flashupdate.cantopenfile kon de Datei ned aufmacha +flashupdate.cantopenmtd kon des MTD-Device ned aufmacha +flashupdate.checkupdate nach ner neien Versio suacha +flashupdate.currentreleasecycle Releasezyklus +flashupdate.currentversion_sep De Version host +flashupdate.currentversiondate Datum +flashupdate.currentversionsnapshot ImageTyp +flashupdate.currentversiontime Uhrzeit +flashupdate.erasefailed Flash löschn is schiafganga +flashupdate.erasing lösch des Flash +flashupdate.experimentalimage Sie ham an Schnappshuss ausgwaiht,\nbitte bedenkens, dass de Version ned durchprobiert is.\nWenns bled laft, geht Ihr Box danoch nimma.\n\nWoins de Version wirklich hernemma? +flashupdate.expertfunctions Experten-Funktionen +flashupdate.fileis0bytes de Datei hod 0 Byte +flashupdate.fileselector Datei auswähn +flashupdate.flashreadyreboot Des Imag is gflasht worn.\nJetz start ma de Box nei. +flashupdate.getinfofile hoi grod de Versionsinfo +flashupdate.getinfofileerror find nix +flashupdate.getupdatefile Update werd glon +flashupdate.getupdatefileerror kon des Update ned lon +flashupdate.globalprogress Ois: +flashupdate.head Aktualisiern +flashupdate.md5check Image obchecken +flashupdate.md5sumerror Des Image is hi +flashupdate.msgbox Des Image hob i gfundn:\nDatum: %s, %s\nBasisImage: %s\nImageTyp: %s\n\nWoins des Image runterlon \nund installiern? +flashupdate.msgbox_manual A neas Image hob i gfundn:\nDatum: %s, %s\nBasisImage: %s\nImageTyp: %s\n\nWoins des instaliern? +flashupdate.mtdselector Partition auswähn +flashupdate.programmingflash programmier des Flash +flashupdate.proxypassword Passwort +flashupdate.proxypassword_hint1 Gems as Proxy-Passwort ei +flashupdate.proxypassword_hint2 +flashupdate.proxyserver Proxyname +flashupdate.proxyserver_hint1 Gems an Proxynama oderd IP ei (Host:Port) +flashupdate.proxyserver_hint2 Wans nix eigem, hams a koan Proxy +flashupdate.proxyserver_sep Proxyserva +flashupdate.proxyusername Benutzernama +flashupdate.proxyusername_hint1 Gems ihrn Proxy-Benutzernama ei +flashupdate.proxyusername_hint2 Wans nix eigem wer koa Authentifizierung gmacht +flashupdate.readflash ganzes Flashimage aussalesn +flashupdate.readflashmtd einzelne Partition aussalesn +flashupdate.ready hobs +flashupdate.reallyflashmtd Woins echt flashen?\n\nWann was schiaflaft oder des Image hi is\wer de Box nimma startn.\n\nImagenama: %s\nZiel: %s +flashupdate.savesuccess Des Image is unter\nDateinamen %s gspeichat worn. +flashupdate.selectimage Vorhandne Images +flashupdate.titlereadflash Flash auslesn +flashupdate.titlewriteflash Flash schreim +flashupdate.updatemode Updatemodus +flashupdate.updatemode_internet internet +flashupdate.updatemode_manual manuell (ftp) +flashupdate.url_file Eistellungsdatei +flashupdate.versioncheck Version obcheckn +flashupdate.writeflash ganzes Flashimage eispuin +flashupdate.writeflashmtd einzelne Partition eispuin +flashupdate.wrongbase De Releasezyklus hot net de richtige Version, bitte an andres Komplett-Image installiern +fontmenu.channellist Kanallistn +fontmenu.epg EPG +fontmenu.eventlist Eventlistn +fontmenu.gamelist Spuilistn +fontmenu.head Schriftgrössn Eistellunga +fontmenu.infobar Infoleistn +fontsize.channellist Kanallistn +fontsize.channellist_descr Beschreibung +fontsize.channellist_number Numma +fontsize.epg_date EPG Datum +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Titl +fontsize.eventlist_datetime Eventlistn Datum/Zeid +fontsize.eventlist_itemlarge Eventlistn groß +fontsize.eventlist_itemsmall Eventlistn kloa +fontsize.eventlist_title Eventlistn Titl +fontsize.filebrowser_item Dateibrausa +fontsize.gamelist_itemlarge groß +fontsize.gamelist_itemsmall kloa +fontsize.hint Schrift werd glodn,\noan Moment bitte... +fontsize.infobar_channame Nama +fontsize.infobar_info Infobar Info +fontsize.infobar_number Numma +fontsize.infobar_small Infobar kloa +fontsize.menu Menutext +fontsize.menu_info Menu Info +fontsize.menu_title Menutitl +gtxalpha.alpha1 tr1 +gtxalpha.alpha2 tr2 +infoviewer.epgnotload Informationen no ned glon... +infoviewer.epgwait Wart no aufs EPG... +infoviewer.eventlist Programm +infoviewer.languages Tonwahl +infoviewer.motor_moving Antennenpositionierung +infoviewer.nocurrent Koa Information zum Programm +infoviewer.noepg Koa EPG do +infoviewer.notavailable Senda grod ned do +infoviewer.selecttime Ofangszeitn +infoviewer.streaminfo Spuizeig +infoviewer.subservice Bildregie +infoviewer.waittime Wart no aufd Uhrzeit... +ipsetup.hint_1 Nemmas 0...9 oda auffi oda obe +ipsetup.hint_2 Mit OK speichan, mit HOME obbrecha +keybindingmenu.RC Fernbedienung +keybindingmenu.addrecord neie Aufnahm +keybindingmenu.addrecord_head neie Aufnahm +keybindingmenu.addremind neia Umschoittermin +keybindingmenu.addremind_head neia Umschoittermin +keybindingmenu.allchannels_on_ok Sendalistn +keybindingmenu.bouquetchannels_on_ok Bouquet-Senda +keybindingmenu.bouquetdown Bouquet zruck +keybindingmenu.bouquetdown_head Bouquet zruck Dasdn +keybindingmenu.bouquethandling OK-Dasdn für +keybindingmenu.bouquetlist_on_ok Bouquetlistn +keybindingmenu.bouquetup Bouquet weida +keybindingmenu.bouquetup_head Bouquet weida Dasdn +keybindingmenu.cancel Sendalistn zuamacha +keybindingmenu.cancel_head Sendalistn zuamacha +keybindingmenu.channeldown Senda obe +keybindingmenu.channeldown_head Senda obe Dasdn +keybindingmenu.channellist Sendalistn +keybindingmenu.channelup Senda aufi +keybindingmenu.channelup_head Senda aufi Dasdn +keybindingmenu.head Dasdn-Eistellunga +keybindingmenu.modechange Modus wexln +keybindingmenu.pagedown Seitn obiblatln +keybindingmenu.pagedown_head Seitn obiblatln +keybindingmenu.pageup seitn aufiblatln +keybindingmenu.pageup_head Seitn aufiblatln +keybindingmenu.quickzap Schneiumschoitung +keybindingmenu.repeatblock Wiederholungsverzögerung +keybindingmenu.repeatblockgeneric Ofangsverzögerung +keybindingmenu.sort Sortierfoige ändan +keybindingmenu.sort_head Sortierfoige ändan +keybindingmenu.subchanneldown Untersenda zruck +keybindingmenu.subchanneldown_head Untersenda zruck +keybindingmenu.subchannelup Untersenda weida +keybindingmenu.subchannelup_head Untersenda weida +keybindingmenu.tvradiomode Fernseh-/Radio-Modus +keybindingmenu.tvradiomode_head Fernseh-/Radio-Modus +keychooser.head Neie Dasdn eistein +keychooser.text1 Dasdn drucka +keychooser.text2 Wanst ne wuist, wartn +keychoosermenu.currentkey Jetzdige Dasdn +keychoosermenu.setnew Neie Dasdn eistein +keychoosermenu.setnone Koa Dasdn +languagesetup.head Sprocheistellunga +languagesetup.select Sproch +lcdcontroler.brightness normale Helligkeid +lcdcontroler.brightnessstandby Standby Helligkeid +lcdcontroler.contrast Kontrast +lcdcontroler.head LCD Eistellunga +lcdmenu.autodimm Automatisch dimma +lcdmenu.head LCD Eistellunga +lcdmenu.inverse Invertieren +lcdmenu.lcdcontroler Kontrast / Helligkeid +lcdmenu.power Pauwa +lcdmenu.statusline Statuszeiln +lcdmenu.statusline.both change me +lcdmenu.statusline.playtime Spuizeit +lcdmenu.statusline.volume Lautstärkn +mainmenu.games Spuin +mainmenu.head Hauptmenü +mainmenu.movieplayer Fuimspuia +mainmenu.pausesectionsd EPG aussalesn +mainmenu.pictureviewer Buidlschauga +mainmenu.radiomode Radio hern +mainmenu.recording Streaming (aufnemma) +mainmenu.recording_start ofanga +mainmenu.recording_stop aufhearn +mainmenu.scartmode Scart hernemma +mainmenu.service Service +mainmenu.settings Eistellunga +mainmenu.shutdown Ausmacha +mainmenu.sleeptimer EischlofTimer +mainmenu.tvmode Fernseh schaugn +mainsettings.audio Audio +mainsettings.colors Forbn / Themes +mainsettings.head Eistellunga +mainsettings.keybinding Tasdn-Eistellunga +mainsettings.language Sproch +mainsettings.lcd LC-Disbläi +mainsettings.misc No a boar Eistellunga +mainsettings.network Netzwerk +mainsettings.recording Streamingserva +mainsettings.savesettingsnow Eistellunga jetz speichan +mainsettings.savesettingsnow_hint De Eistellunga wern jezt gespeichat,\noan Moment bitte... +mainsettings.streaming Movieplayer +mainsettings.video Video +menu.back Zruck +messagebox.back Zruck +messagebox.cancel Abbrecha +messagebox.discard Woins de Änderunga verwerfa? +messagebox.error Bläd glaffa +messagebox.info Information +messagebox.no Ned +messagebox.yes Scho +miscsettings.bootinfo Informationa beim Startn zoang +miscsettings.fb_destination EXPERT! Boot-Konsole +miscsettings.general Allgemein +miscsettings.head Diverse Eistellunga +miscsettings.infobar_sat_display Satelitn Informationsleistn +miscsettings.shutdown_real bissi ausmacha +miscsettings.shutdown_real_rcdelay verzögats Ausschoitn +miscsettings.startbhdriver BH-Mode Treiba lon +motorcontrol.head Motor-Eistellunga +movieplayer.bookmark Vormerka +movieplayer.bookmarkname Merkal Nama +movieplayer.bookmarkname_hint1 Bitte gems den Nama fürs neie Merkal o. +movieplayer.bookmarkname_hint2 movieplayer.skipping Umsortiern bitte wartn +movieplayer.buffering Buffern.. +movieplayer.defdir Start-Verz. +movieplayer.dvdplayback DVD +movieplayer.fileplayback Fuim mim VLC +movieplayer.goto Spring zu ... +movieplayer.goto.h1 = -> absoluter Sprung +movieplayer.goto.h2 +,- -> relativer Sprung +movieplayer.head Fuimspuia +movieplayer.nostreamingserver Koa Vabindung\nzum Streamingserva möglich. +movieplayer.pesplayback PES Abspuin (Experiment) +movieplayer.pleasewait Oan Moment, de Verbindung\nzum Streamingserva werd hergsteaid +movieplayer.toomanybookmarks Sie ham scho zvui Merkal oglegt.\nEs muas erst a andas glöscht wern. +movieplayer.tsplayback TS Abspuin +movieplayer.vcdplayback (S)VCD +movieplayer.vlchelp ROT/Hoam Stop\nGREA Resync\nGELB Pause/Weida\nBLAU Merkal setzn\n1 ca. 1 Minutn zruck\n3 ca. 1 Minutn viri\n4 ca. 5 Minutn zruck\n6 ca. 5 Minutn viri\n7 ca. 10 Minutn zruck\n9 ca. 10 Minutn viri\nHuif: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.wrongvlcversion Des is mit ehnara VLC-Version ne drin +networkmenu.broadcast Broadcast +networkmenu.gateway Standard Gateway +networkmenu.head Netzwerk Eistellunga +networkmenu.ipaddress IP-Adressn +networkmenu.nameserver Nameserva +networkmenu.netmask Netzmaskn +networkmenu.setupnow Netzwerkeistellunga jetz macha +networkmenu.setuponstartup Beim Startn Netzwerk setzn +networkmenu.show aktive Netzwerkeistellunga zoign +networkmenu.test Netzwerk ausprobiern +nfs.alreadymounted Verzeichnis is scho gmounted +nfs.automount Beim Startn mountn +nfs.dir NFS/CIFS Verzeichnis +nfs.ip NFS/CIFS Serva IP +nfs.localdir Verzeichnis auf da Box +nfs.mount NFS/CIFS Verzeichnis mountn +nfs.mount_options Mount-Optionen +nfs.mounterror Mount-Fähla +nfs.mounterror_notsup Mit dem Dateisystem kon i nix ofanga +nfs.mountnow Jetzad mountn +nfs.mounttimeout Mount-Fehla: Timeout +nfs.password CIFS Passwort +nfs.remount Verzeichniss nomoi mountn +nfs.type Typ +nfs.type_cifs CIFS +nfs.type_nfs NFS +nfs.umount NFS/CIFS Verzeichnis freigem +nfs.umounterror Fähla beim Freigem +nfs.username CIFS Benutzanama +nfsmenu.head NFS/CIFS Eistellunga +nvod.percentage (%d%% vorbei) +nvod.starting (Fangt in %d min o) +nvodselector.directormode Bildregie-Modus +nvodselector.head Anfangszeid auswaehn +nvodselector.subservice Perspektiven +options.default Voreistellunga nema +options.fb framebuffa +options.null null +options.off ausmacha +options.on omacha +options.serial seriell +parentallock.changepin PIN-Code eistain +parentallock.changepin_hint1 Gems jetz Eanan PIN-Code ei! +parentallock.changetolocked Bei vorgsperrde Bouquets +parentallock.head Jugendschutz PIN +parentallock.lockage Sendunga +parentallock.lockage12 ab 12 Jahr sperrn +parentallock.lockage16 ab 16 Jahr sperrn +parentallock.lockage18 ab 18 Jahr sperrn +parentallock.lockedchannel Gsperrda Senda +parentallock.lockedprogram Gperde Sendung(FSK ab %d) +parentallock.never Nia +parentallock.onsignal Wann a Vorsperre gsendet werd +parentallock.parentallock Jugendschutz +parentallock.prompt PIN eigem +pictureviewer.defdir Start-Verz. +pictureviewer.head Buidlschauga +pictureviewer.scaling Skalierung +pictureviewer.show Ozoign +pictureviewer.slide_time Diaschaugn-Ozoagdaua +pictureviewer.slideshow Diaschaugn +pictureviewer.sortorder andre Reihenfoign +pictureviewer.sortorder.date (Datum) +pictureviewer.sortorder.filename (Dateinama) +ping.ok kumt wos (ping) +ping.protocol kumt nix (Host or protocol error) +ping.socket kumt nix (Socket error) +ping.unreachable kumt nix (unreachable) +pinprotection.head PIN-Abfrage +pinprotection.wrongcode Gems den Code nomoi ei! +rclock.lockmsg D Fernbedienung von da dbox2 werd gsperrt.\nUm die Sperrn aufzhem, bitte\n und auf da Fernbedienung\ndrucka. +rclock.menueadd FB sperrn +rclock.title Fernbedienung sperrn +rclock.unlockmsg Fernbedienung reaktiviert... +recordingmenu.head Streamingserva Eistellunga +recordingmenu.no_scart Scart Umschoita untadrucka +recordingmenu.off aus +recordingmenu.recording_type Grät zum Aufnemma +recordingmenu.server Serva +recordingmenu.server_ip Aufnahmeserva IP +recordingmenu.server_mac MAC-Adressn +recordingmenu.server_port Aunahmeserva Port +recordingmenu.server_wakeup Serva zum Aufnemma (WOL) +recordingmenu.setupnow los moachs ! +recordingmenu.stopplayback Fuim ohoitn +recordingmenu.stopsectionsd Sectionsd ohoitn +recordingmenu.vcr Video Recorda +recordtimer.announce In weniga Minutn werd aufgnomma +repeatblocker.hint_1 Mindestzeit (ms) zwischn zwoa Dasdndrucka +repeatblocker.hint_2 0 schoitt an Blocka aus (Rot is " ") +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-Wiederholunga +satsetup.extended DiSEqC-Eistellunga +satsetup.extended_motor Motor-Eistellunga +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Manuelle Motor-Eistellunga +satsetup.nodiseqc Koa DiSEqC +satsetup.satellite Satellit +satsetup.savesettingsnow Eistellunga jetz speichan +satsetup.smatvremote SMATV Remote Tuning +scants.actcable Kabi: +scants.actsatellite Satellit: +scants.bouquet Bouquets +scants.bouquet_create nei macha +scants.bouquet_erase wegmacha +scants.bouquet_leave ned olanga +scants.bouquet_satellite Satelliten-Bouquet +scants.bouquet_update nei macha +scants.channel Kanal: +scants.failed Sendasuacha is gescheitat +scants.finished Senda sand gfundn worn! +scants.freqdata Frequenz: +scants.head Senda suacha +scants.numberofdataservices Data +scants.numberofradioservices Radio +scants.numberoftotalservices Gesamt +scants.numberoftvservices TV +scants.provider Anbieter: +scants.startnow Ofanga mim Senda suacha +scants.transponders Transponder: +screensetup.lowerright grün = Buidlrand untn, rechts +screensetup.upperleft rot = Buidlrand om, links +servicemenu.head Service +servicemenu.reload Sendalistn nei loan +servicemenu.reload_hint Sendalistn wern nei glon,\noan Moment... +servicemenu.scants Senda suacha +servicemenu.ucodecheck UCodes obcheckn +servicemenu.update Software-aktualisiern +settings.missingoptionsconffile Es gibt neie Eistellunga.\nDe stenga jetz erstmoi auf Standard. +settings.noconffile De Eistellunga von Neutrino san ned\ngfundn worn. Mia nemma de Standardwerte. +shutdowntimer.announce De Box werd in oana Minutn runtagfahrn.\nObbrecha? +sleeptimerbox.announce Eischloftimer in min +sleeptimerbox.hint1 Einschlofzeit in Min. (000=aus) +sleeptimerbox.hint2 De Box schoit si noch der Zeid aus. +sleeptimerbox.title Eischloftimer +streamfeatures.head Features +streaminfo.aratio Verhältnis +streaminfo.aratio_unknown Verhältnis: ken i ned +streaminfo.audiotype Audiotyp +streaminfo.audiotype_unknown Audiotyp: ken i ned +streaminfo.bitrate Bitrate +streaminfo.framerate Bildrate +streaminfo.framerate_unknown Bildrate: ken i ned +streaminfo.head Informationen +streaminfo.not_available kumt nix +streaminfo.resolution Auflösung +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Fuimspuia Eistellunga +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Ausgschoitn +streamingmenu.on Eigschoitn +streamingmenu.server_ip Streamingserva IP +streamingmenu.server_port Streamingserva Port +streamingmenu.streaming_audiorate Datenrate Audio +streamingmenu.streaming_force_avi_rawaudio AC3 bei avi erzwinga +streamingmenu.streaming_force_transcode_video Transcod. a mpg/vcd Video +streamingmenu.streaming_resolution Auflösung +streamingmenu.streaming_server_cddrive DVD Laufwerk +streamingmenu.streaming_server_startdir Verzeichnis (VLC) +streamingmenu.streaming_transcode_audio Transcod. Audio (dvd/vcd/mpg) +streamingmenu.streaming_transcode_video_codec MPEG Video Codec +streamingmenu.streaming_type Streamingserva +streamingmenu.streaming_videorate Datenrate Video +streamingserver.noconnect Kao Verbindung zum Streamingserva.\nDe Aufnahme werd obbrocha. +stringinput.caps Groß-/Koabuchstobm +stringinput.clear Ois löschn +timer.eventrecord.msg De Sendung is zum Aufnemma vorgmerkt +timer.eventrecord.title Aufnemma vormerka +timer.eventtimed.msg De Sendung is vorgmerkt +timer.eventtimed.title Sendung vormerka +timerbar.channelswitch Umschoitn +timerbar.recordevent Aufnemma +timerlist.alarmtime Alarmzeid +timerlist.apids Audio PIDs +timerlist.bouquetselect Bouquet auswäihn +timerlist.channel Kanoi +timerlist.channelselect Senda auswäihn +timerlist.delete wegmacha +timerlist.menumodify Timer bearbeitn +timerlist.menunew Neia Timer +timerlist.message Nochricht +timerlist.moderadio Radio hern +timerlist.modeselect Modus auswäihn +timerlist.modetv Ferhsegn +timerlist.modify ändan +timerlist.name Timerlistn +timerlist.new Neia Timer +timerlist.program.unknown Kenn den Senda ned +timerlist.reload akualisiern +timerlist.repeat Widahoin +timerlist.repeat.biweekly olle zwoa Wocha +timerlist.repeat.byeventdescription wia da timer +timerlist.repeat.daily jeden tog +timerlist.repeat.fourweekly alle vier Wocha +timerlist.repeat.friday Fr +timerlist.repeat.monday Mo +timerlist.repeat.monthly jeden Monat +timerlist.repeat.once oimalig +timerlist.repeat.saturday Sa +timerlist.repeat.sunday So +timerlist.repeat.thursday Do +timerlist.repeat.tuesday Die +timerlist.repeat.unknown Kenn i ned +timerlist.repeat.wednesday Mi +timerlist.repeat.weekdays Wochatogs +timerlist.repeat.weekly jede woch +timerlist.save Speichan +timerlist.standby SB +timerlist.standby.off Ausm Standy aufwacha +timerlist.standby.on In Standy geh +timerlist.stoptime Stopzeid +timerlist.type Timertyp +timerlist.type.nextprogram Nächsta Senda +timerlist.type.record Aufnemma +timerlist.type.remind Erinnern +timerlist.type.shutdown Ausmacha +timerlist.type.sleeptimer Eischloftimer +timerlist.type.standby Bissl Ausmacha +timerlist.type.unknown Kenninet +timerlist.type.zapto Umschoitn +timerlist.weekdays Wochentog +timerlist.weekdays.hint_1 Mo Die Mi Do Fr Sa So +timerlist.weekdays.hint_2 'X'=Timer '-' koa Timer +timersettings.record_safety_time_after Aufnahmeend Korretua +timersettings.record_safety_time_after.hint_1 Korrekturzeid in Minutn (00=aus), de aufd +timersettings.record_safety_time_after.hint_2 Endzeid vom jeweilign Timer aufigrechent werd +timersettings.record_safety_time_before Aufnemma - Korrekturzeid +timersettings.record_safety_time_before.hint_1 De Zeid in Minutn (00=aus) werd beim Startn +timersettings.record_safety_time_before.hint_2 vom Timer obzogn +timersettings.separator Timer Eistellunga +timing.chanlist Kanalliste +timing.epg Epg +timing.filebrowser Filebrausa +timing.head OSD Timeouts +timing.hint_1 Einblendzeit in Sek., die das OSD +timing.hint_2 auf dem TV angezeigt wird +timing.infobar Infobar +timing.menu Menu +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head UCodes obcheckn +ucodecheck.ucode UCode +ucodes.failure Obacht, de µCodes san ned gfundn worn!\n\nLoans de doch bittschen mit FTP \nauffi, und startns de Box numoi! +videomenu.csync Sync.-Korrigiern +videomenu.head Video-Eistellunga +videomenu.rgb_centering RGB-Zentriern +videomenu.screensetup Bildbereich eistein +videomenu.vcrswitch Scart-Eigang automatisch +videomenu.videoformat Bildschirmformat +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect automatisch +videomenu.videosignal Video Signalart +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce In na Minutn is schluss diff --git a/data/locale/bosanski.locale b/data/locale/bosanski.locale new file mode 100644 index 000000000..f4dbae3bd --- /dev/null +++ b/data/locale/bosanski.locale @@ -0,0 +1,722 @@ +EPGMenu.epgplus pregled predvidanja +EPGMenu.eventinfo informacije o emisiji +EPGMenu.eventlist predvidanje trenutacnog programa +EPGMenu.head epg - informacije o programu +EPGMenu.streaminfo tehnicke informacije +EPGPlus.head pregled predvidanja (epg plus) +EPGPlus.record snimanje +EPGPlus.refresh_epg obnoviti +EPGPlus.remind zapamtiti +EPGPlus.scroll_mode scroll modus +EPGPlus.stretch_mode stretch modus +GENRE.ARTS.0 umjetnost / kultura +GENRE.ARTS.1 umjetnost +GENRE.ARTS.10 magazin za umjetnost / kulturu +GENRE.ARTS.11 moda +GENRE.ARTS.2 umjetnost +GENRE.ARTS.3 vjera +GENRE.ARTS.4 umjetnost +GENRE.ARTS.5 literatura +GENRE.ARTS.6 film/kino +GENRE.ARTS.7 eksperimentalni film/video +GENRE.ARTS.8 rtv/Å¡tampa +GENRE.ARTS.9 nove medije +GENRE.CHILDRENs_PROGRAMMES.0 program za djecu / mlade +GENRE.CHILDRENs_PROGRAMMES.1 program za predÅ¡kolsku djecu +GENRE.CHILDRENs_PROGRAMMES.2 program za 6-o do 14-o godiÅ¡njake +GENRE.CHILDRENs_PROGRAMMES.3 program za 10-o do 16-o godiÅ¡njake +GENRE.CHILDRENs_PROGRAMMES.4 informativni i nauÄni program +GENRE.CHILDRENs_PROGRAMMES.5 crtani film +GENRE.DOCUS_MAGAZINES.0 dokumentacija/magazin +GENRE.DOCUS_MAGAZINES.1 priroda/životinje/okolina +GENRE.DOCUS_MAGAZINES.2 nauka i tehnika +GENRE.DOCUS_MAGAZINES.3 medicina/fisiologija/psihologija +GENRE.DOCUS_MAGAZINES.4 inozemstvo/ekspedicije +GENRE.DOCUS_MAGAZINES.5 nauka +GENRE.DOCUS_MAGAZINES.6 nauka +GENRE.DOCUS_MAGAZINES.7 jezici +GENRE.MOVIE.0 igrani film / drama +GENRE.MOVIE.1 kriminalni film / triler +GENRE.MOVIE.2 avanturni/kaubojski/ratni film +GENRE.MOVIE.3 nauÄna fantastika/fantazija/strava +GENRE.MOVIE.4 komedija +GENRE.MOVIE.5 soap/melodramatika/folklora +GENRE.MOVIE.6 romantika +GENRE.MOVIE.7 ozbiljno/klasiÄno/vjerno/povijesni film/drama +GENRE.MOVIE.8 film za odrasle/drama +GENRE.MUSIC_DANCE.0 muzika/balet/ples +GENRE.MUSIC_DANCE.1 rok/pop +GENRE.MUSIC_DANCE.2 ozbiljna muzika/klasika +GENRE.MUSIC_DANCE.3 narodna muzika +GENRE.MUSIC_DANCE.4 džez +GENRE.MUSIC_DANCE.5 musical/opera +GENRE.MUSIC_DANCE.6 balet +GENRE.NEWS.0 vijesti +GENRE.NEWS.1 vijesti/vrijeme +GENRE.NEWS.2 vijesni magazin +GENRE.NEWS.3 dokumantacija +GENRE.NEWS.4 diskusija/ispit/debata +GENRE.SHOW.0 show / gameshow +GENRE.SHOW.1 gameshow / kviz +GENRE.SHOW.2 variete +GENRE.SHOW.3 talkshow +GENRE.SOCIAL_POLITICAL.0 socialni & politiÄki dogadaji / privreda +GENRE.SOCIAL_POLITICAL.1 magazin/report/dokumentacija +GENRE.SOCIAL_POLITICAL.2 privreda i socialno +GENRE.SOCIAL_POLITICAL.3 naroÄiti ljudi +GENRE.SPORTS.0 sport +GENRE.SPORTS.1 veledogaÄ‘aji (olimpijada, svjetsko prvenstvo itd.) +GENRE.SPORTS.10 jahanje +GENRE.SPORTS.11 borilaÄki sportovi +GENRE.SPORTS.2 sport magazin +GENRE.SPORTS.3 nogomet +GENRE.SPORTS.4 tenis +GENRE.SPORTS.5 ekipni sport +GENRE.SPORTS.6 atletika +GENRE.SPORTS.7 motorni sport +GENRE.SPORTS.8 vodeni sport +GENRE.SPORTS.9 zimski sport +GENRE.TRAVEL_HOBBIES.0 odmor +GENRE.TRAVEL_HOBBIES.1 odmor i turizam +GENRE.TRAVEL_HOBBIES.2 ruÄni rad +GENRE.TRAVEL_HOBBIES.3 motori +GENRE.TRAVEL_HOBBIES.4 sposobnost i zdravlje +GENRE.TRAVEL_HOBBIES.5 kuhanje +GENRE.TRAVEL_HOBBIES.6 kupovina +GENRE.TRAVEL_HOBBIES.7 vrt +GENRE.UNKNOWN nepoznato +apids.hint_1 Utipkajte heksadecimalne apids +apids.hint_2 za streaming razdvojene sa ' '. +apidselector.head izbor jezika +audiomenu.PCMOffset smanjivanje glasnoce pcm +audiomenu.analogout analogni izlaz +audiomenu.avs avs +audiomenu.avs_control upravljanje glasnosti avs/ost +audiomenu.dolbydigital dolby digital automaticno +audiomenu.head namjestiti ton +audiomenu.lirc lirc +audiomenu.monoleft mono lijevo +audiomenu.monoright mono desno +audiomenu.ost ost +audiomenu.stereo stereo +audioplayer.add dodati +audioplayer.artist_title pjevaÄ, pjesma +audioplayer.defdir pocetni direktorij +audioplayer.delete izbrisati +audioplayer.deleteall sve izbrisati +audioplayer.display_order redoslijed +audioplayer.fastforward brzo naprijed +audioplayer.follow izabjere ovu pjesmu +audioplayer.id3scan Äitaj id3-tag +audioplayer.keylevel promijeniti tipke +audioplayer.pause pauza +audioplayer.play igrati +audioplayer.playing pjesma +audioplayer.rewind brzo natrag +audioplayer.screensaver_timeout Å¡tititi ekran (min, 0=ugaÅ¡eno) +audioplayer.shuffle sluÄaj +audioplayer.stop zaustaviti +audioplayer.title_artist pjesma, pjevaÄ +bookmarkmanager.delete izbrisati +bookmarkmanager.name zapamcena mjesta +bookmarkmanager.rename preimenovati +bookmarkmanager.select izabrati +bouqueteditor.add dodati +bouqueteditor.bouquetname ime buketa +bouqueteditor.delete izbrisati +bouqueteditor.discardingchanges Pobacuju se promjene. ÄŒekajte molim ... +bouqueteditor.hide sakriti +bouqueteditor.lock zabraniti +bouqueteditor.move pomaknuti +bouqueteditor.name namjestiti buket +bouqueteditor.newbouquetname novo ime buketa +bouqueteditor.rename preimenovati +bouqueteditor.return gotovo +bouqueteditor.savechanges? Hoćete li memorisati promjene? +bouqueteditor.savingchanges MemoriÅ¡u se promjene. ÄŒekajte molim ... +bouqueteditor.switch preuzeti/izbaciti kanal +bouqueteditor.switchmode tv/radio +bouquetlist.head buketi +cablesetup.provider snabdjevaÄ +channellist.head svi kanali +channellist.nonefound Nije naÄ‘en nijedan kanal!\nNapravite traženje kanala\n(dbox2-tipka -> servis) +channellist.since od %02d:%02d +colorchooser.alpha alfa +colorchooser.blue plavo +colorchooser.green zeleno +colorchooser.red crveno +colormenu.background boja pozadine +colormenu.background_head boja pozadine +colormenu.fade izblijediti izbore +colormenu.font veliÄina slova +colormenu.gtx_alpha providnost (gtx) +colormenu.head namjestiti boje +colormenu.menucolors boja izbora +colormenu.statusbar statusna traka +colormenu.textcolor boja teksta +colormenu.textcolor_head boja teksta +colormenu.themeselect izabrati teme +colormenu.timing osd tajm-aut +colormenusetup.head boja izbora +colormenusetup.menucontent sadržaj prozora +colormenusetup.menucontent_inactive deaktiviran sadržaj prozora +colormenusetup.menucontent_selected izabran sadržaj prozora +colormenusetup.menuhead izborno zaglavlje +colorstatusbar.head boja statusne trake +colorstatusbar.text statusna traka +colorthememenu.classic_theme klasiÄno +colorthememenu.head izabrati teme +colorthememenu.neutrino_theme neutrino tema +date.Apr apr +date.Aug aug +date.Dec dec +date.Feb feb +date.Fri pet +date.Jan jan +date.Jul jul +date.Jun jun +date.Mar mar +date.May maj +date.Mon pon +date.Nov nov +date.Oct okt +date.Sat sub +date.Sep sep +date.Sun ned +date.Thu Äet +date.Tue uto +date.Wed sri +epglist.head pregled - %s +epglist.noevents Nema epg informacije. +epgviewer.More_Screenings drugi termini na ovom kanalu +epgviewer.nodetailed nema opÅ¡irnih informacija +epgviewer.notfound nisu naÄ‘ene informacije o programu (epg) +favorites.addchannel Dodaje se trenutaÄni kanal\nbuketu"moji ljubimci".\nMemorisanje traje trenutak... +favorites.bouquetname moji ljubimci +favorites.bqcreated stvoren je buket "Moji ljubimci"...\n +favorites.chadded trenutaÄni kanal je dodan vaÅ¡im ljubimcima...\n +favorites.chalreadyinbq trenutaÄni kanal je već u vaÅ¡im ljubimcima...\n +favorites.finalhint \nSluÄajno dodati kanali mogu se\nizbrisati u namješćenju buketa.\n +favorites.menueadd dodati kanal ljubimcima +favorites.nobouquets moji ljubimci su samo u aktiviranim buketima mogući +filebrowser.delete izbrisati +filebrowser.dodelete1 Hocete +filebrowser.dodelete2 li izbrisati? +filebrowser.filter.active upaljen filter +filebrowser.filter.inactive ugaÅ¡en filter +filebrowser.head pretraživaÄ datoteka +filebrowser.mark oznaÄiti +filebrowser.nextpage strana naprijed +filebrowser.prevpage strana nazad +filebrowser.scan pretraži direktorije +filebrowser.select izabrati +filebrowser.showrights prava datoteke pokazati +filebrowser.sort.date (datum) +filebrowser.sort.name (ime datoteke) +filebrowser.sort.namedirsfirst (ime datoteke 2) +filebrowser.sort.size (velicina) +filebrowser.sort.type (tip) +flashupdate.action akcija: +flashupdate.actionreadflash uÄitaje se fleÅ¡ +flashupdate.actionwriteflash piÅ¡e se fleÅ¡ +flashupdate.cantopenfile nemože se otvoriti datoteka +flashupdate.cantopenmtd nemože se otvoriti mtd-uredaj +flashupdate.checkupdate tražiti novu verziju +flashupdate.currentreleasecycle release imidž +flashupdate.currentversion_sep instalirana verzija +flashupdate.currentversiondate datum +flashupdate.currentversionsnapshot vrsta imidža +flashupdate.currentversiontime vrijeme +flashupdate.erasefailed brisanje flesa nije uspjelo +flashupdate.erasing briÅ¡e se fleÅ¡ +flashupdate.experimentalimage Izabrali ste snapshot,\novo je verzija za pokusavanje i mozda vas\ndbox2 poslije obnavljanja nece vise raditi.\n\nHocete li stvarno sa ovom verzijom obnoviti softver? +flashupdate.expertfunctions funkcije za majstore +flashupdate.fileis0bytes veliÄina datoteke je 0 bajtova +flashupdate.fileselector izbor datoteke +flashupdate.flashreadyreboot Imidž je uspjeÅ¡no fleÅ¡ovan.\nVaÅ¡ dbox2 startuje sada ponovno. +flashupdate.getinfofile Äita se informacija o verziji +flashupdate.getinfofileerror nemože se dobiti informacija o verziji +flashupdate.getupdatefile uÄitaje se najnoviji softver +flashupdate.getupdatefileerror nemože se dobiti najnoviji softver +flashupdate.globalprogress glavni status: +flashupdate.head obnavljanje +flashupdate.md5check provjera imidža +flashupdate.md5sumerror imidž ima greÅ¡ke +flashupdate.msgbox NaÄ‘en je novi imidž:\nDatum: %s, %s\nOsnovni imidž: %s\nvrsta imidža: %s\n\nHoćete li ovu verziju sada preuzeti\nsa interneta i instalirati? +flashupdate.msgbox_manual NaÄ‘en je novi imidž:\nDatum: %s, %s\nOsnovni imidž: %s\nVrsta imidža: %s\n\nHoćete li ovu verziju sada instalirati? +flashupdate.mtdselector izbor particije +flashupdate.programmingflash programira se fleÅ¡ +flashupdate.proxypassword lozinka +flashupdate.proxypassword_hint1 utipkajte lozinku za proxy +flashupdate.proxypassword_hint2 +flashupdate.proxyserver proxyname +flashupdate.proxyserver_hint1 utipkajte ime proxya ili ip adresu (host:port) +flashupdate.proxyserver_hint2 prazno znaÄi da nema proxya +flashupdate.proxyserver_sep proxyserver +flashupdate.proxyusername korisnik +flashupdate.proxyusername_hint1 utipkajte ime korisnika za proxy +flashupdate.proxyusername_hint2 prazno znaÄi da nema provjere +flashupdate.readflash uÄitati Äitav fleÅ¡imidž +flashupdate.readflashmtd uÄitati jednu particiju +flashupdate.ready gotovo +flashupdate.reallyflashmtd Hoćete li stvarno nastaviti fleÅ¡ovanje?\n\nAko se desi greÅ¡ka ili imidž nije\nu redu, onda vaÅ¡ dbox2 neće viÅ¡e raditi.\n\nIme imidža: %s\nPozicija: %s +flashupdate.reboot startuje se dbox2 ponovno +flashupdate.savesuccess Imidž je uspjeÅ¡no memorisan \npod imenom %s. +flashupdate.selectimage izbor imidza +flashupdate.titlereadflash uÄitati fleÅ¡ +flashupdate.titlewriteflash pisati fleÅ¡ +flashupdate.updatemode softver se obnavlja +flashupdate.updatemode_internet sa interneta +flashupdate.updatemode_manual ruÄno (ftp) +flashupdate.url_file datoteka za konfiguraciju +flashupdate.versioncheck provjeriti verziju +flashupdate.writeflash pisati Äitav fleÅ¡imidž +flashupdate.writeflashmtd pisati jednu particiju +flashupdate.wrongbase Verzija release imidža ne paÅ¡e viÅ¡e,\ntreba se instalirati novi komletni imidž! +fontmenu.channellist lista kanala +fontmenu.epg epg +fontmenu.eventlist lista dogaÄ‘aja +fontmenu.gamelist lista igara +fontmenu.head namješćenje veliÄine slova +fontmenu.infobar informativna traka +fontsize.channellist lista kanala +fontsize.channellist_descr opis +fontsize.channellist_number broj +fontsize.epg_date epg datum +fontsize.epg_info1 epg informacija 1 +fontsize.epg_info2 epg informacija 2 +fontsize.epg_title naslov epgea +fontsize.eventlist_datetime lista dogaÄ‘aja za datum / vrijeme +fontsize.eventlist_itemlarge velika lista dogaÄ‘aja +fontsize.eventlist_itemsmall mala lista dogaÄ‘aja +fontsize.eventlist_title naslov liste dogaÄ‘aja +fontsize.filebrowser_item dio pretraživaÄa datoteka +fontsize.gamelist_itemlarge veliko +fontsize.gamelist_itemsmall malo +fontsize.hint slova se namješćaju,\nÄekajte molim ... +fontsize.infobar_channame infromativna traka za kanal +fontsize.infobar_info infromativna traka za informaciju +fontsize.infobar_number infromativna traka za broj +fontsize.infobar_small mala infromativna traka +fontsize.menu tekst u izboru +fontsize.menu_info izbor za informaciju +fontsize.menu_title naslov izbora +gtxalpha.alpha1 alpha 1 +gtxalpha.alpha2 alpha 2 +infoviewer.cantdecode kanal se ne može deÅ¡ifrovati +infoviewer.epgnotload informacije joÅ¡ nisu pristupaÄne... +infoviewer.epgwait Äeka se na epg informacije... +infoviewer.eventlist program +infoviewer.languages izbor tona +infoviewer.motor_moving namješćenje antene +infoviewer.nocurrent nema informacije o ovom programu +infoviewer.noepg nema epg informacije +infoviewer.notavailable kanal (trenutaÄno) nije pristupan +infoviewer.selecttime poÄetak +infoviewer.streaminfo osobine +infoviewer.subservice režija slike +infoviewer.waittime Äeka se na vrijeme ... +ipsetup.hint_1 upotrijebite 0..9 ili gore/dole +ipsetup.hint_2 ok memoriÅ¡e, home prekida +keybindingmenu.RC daljinska +keybindingmenu.addrecord dodati vremenski brojaÄ za snimanje +keybindingmenu.addrecord_head dodati vremenski brojaÄ za snimanje +keybindingmenu.addremind dodati vremenski brojaÄ za prebaciti +keybindingmenu.addremind_head dodati vremenski brojaÄ za prebaciti +keybindingmenu.allchannels_on_ok lista kanala +keybindingmenu.bouquetchannels_on_ok buket kanali +keybindingmenu.bouquetdown buket nazad +keybindingmenu.bouquetdown_head tipka za buket nazad +keybindingmenu.bouquethandling ok-tipka za +keybindingmenu.bouquetlist_on_ok lista buketa +keybindingmenu.bouquetup buket dalje +keybindingmenu.bouquetup_head tipka za buket dalje +keybindingmenu.cancel zatvoriti listu kanala +keybindingmenu.cancel_head zatvoriti listu kanala +keybindingmenu.channeldown kanal dole +keybindingmenu.channeldown_head tipka za kanal dole +keybindingmenu.channellist lista kanala +keybindingmenu.channelup kanal gore +keybindingmenu.channelup_head tipka za kanal gore +keybindingmenu.head namjestiti tipaljku +keybindingmenu.modechange promijeniti stanje +keybindingmenu.pagedown stranu dole +keybindingmenu.pagedown_head stranu dole +keybindingmenu.pageup stranu gore +keybindingmenu.pageup_head stranu gore +keybindingmenu.quickzap brzo prebacivanje +keybindingmenu.repeatblock Äekanje pri ponavljanju +keybindingmenu.repeatblockgeneric poÄetno Äekanje +keybindingmenu.sort promijeniti smjer sortiranja +keybindingmenu.sort_head promijeniti smjer sortiranja +keybindingmenu.subchanneldown podkanal nazad +keybindingmenu.subchanneldown_head podkanal nazad +keybindingmenu.subchannelup podkanal dalje +keybindingmenu.subchannelup_head podkanal dalje +keybindingmenu.tvradiomode tv/radio +keybindingmenu.tvradiomode_head tv/radio +keychooser.head namjestiti novu tipku +keychooser.text1 pritisnite tipku +keychooser.text2 Äekati na prekid... +keychoosermenu.currentkey sadaÅ¡nja tipka +keychoosermenu.setnew namjestiti novu tipku +keychoosermenu.setnone nijedna tipka +languagesetup.head izabrati jezik +languagesetup.select jezik +lcdcontroler.brightness normalna svjetlost +lcdcontroler.brightnessstandby svjetlost u pripravnosti +lcdcontroler.contrast kontrast +lcdcontroler.head namjestiti teÄni kristal +lcdmenu.autodimm automaticno smanjiti svjetlost +lcdmenu.head namjestiti teÄni kristal +lcdmenu.inverse invertirati +lcdmenu.lcdcontroler kontrast / svjetlost +lcdmenu.power struja +lcdmenu.statusline statusna linija +lcdmenu.statusline.both glasnost i trajanje +lcdmenu.statusline.playtime igrano vrijeme +lcdmenu.statusline.volume glasnost +mainmenu.games igre +mainmenu.head glavni izbor +mainmenu.movieplayer promatraÄ filmova +mainmenu.pausesectionsd Äitati epg +mainmenu.pictureviewer promatraÄ slika +mainmenu.radiomode radio +mainmenu.recording snimanje +mainmenu.recording_start start +mainmenu.recording_stop stop +mainmenu.scartmode av-scart ulaz +mainmenu.service servis +mainmenu.settings namješćenje +mainmenu.shutdown ugasiti +mainmenu.sleeptimer vremenski brojaÄ za ugasiti +mainmenu.tvmode tv +mainsettings.audio ton +mainsettings.colors boje / teme +mainsettings.head namješćenje +mainsettings.keybinding namjestiti tipku +mainsettings.language jezik +mainsettings.lcd teÄni kristal +mainsettings.misc namjestiti razne stvari +mainsettings.network mreža +mainsettings.plugins namješćenje plugina +mainsettings.recording snimanje +mainsettings.savesettingsnow namješćenje sada memorisati +mainsettings.savesettingsnow_hint memoriÅ¡e se namješćenje,\nÄekajte molim ... +mainsettings.scan namjestiti traženja kanala +mainsettings.streaming promatraÄ filmova +mainsettings.video video +menu.back nazad +messagebox.back nazad +messagebox.cancel prekid +messagebox.discard Hoćete li pobaciti promijenito? +messagebox.error greÅ¡ka +messagebox.info informacija +messagebox.no ne +messagebox.yes ja +miscsettings.bootinfo pokazati informacije pri startovanju +miscsettings.boxtype proizvoÄ‘aÄ dbox2 +miscsettings.fb_destination majstori! boot konsola +miscsettings.general generalno +miscsettings.head namjestiti razne stvari +miscsettings.infobar_sat_display informativna traka sateliti +miscsettings.shutdown_real pripravnost +miscsettings.shutdown_real_rcdelay ugasiti sa zastojanjem +miscsettings.startbhdriver startovati bh-mode driver +motorcontrol.head namješćenje motora +movieplayer.bookmark oznaka +movieplayer.bookmarkname ime zapamcenog mjesta +movieplayer.bookmarkname_hint1 Imenujte novo zapamceno mjesto +movieplayer.bookmarkname_hint2 +movieplayer.buffering predraditi... +movieplayer.defdir poÄetni direktorij +movieplayer.dvdplayback dvd +movieplayer.fileplayback datoteka preko vlcea +movieplayer.goto Skacem prema ... +movieplayer.goto.h1 = -> absolutni skok +movieplayer.goto.h2 +,- -> relativni skok +movieplayer.head promatraÄ filmova +movieplayer.nostreamingserver Nije bilo moguće\nuspostaviti vezu sa streamingserverom. +movieplayer.pesplayback odigrati pes (eksperimentalno) +movieplayer.pleasewait Uspostavlja se veza sa streamingserverom.\nÄŒekajte molim ... +movieplayer.toomanybookmarks Previse mjesta su zapamcena.\nMora se prvo jedno drugo izbrisati. +movieplayer.tsplayback odigrati ts +movieplayer.vcdplayback (s)vcd +movieplayer.vlchelp crveno/kuci stop\nzeleno resync\nzuto pausa/dalje\nplavo zapamtiti mjesto\n1 oko 1 minuta nazad\n3 oko 1 minuta naprijed\n4 oko 5 minuta nazad\n6 oko5 minuta naprijed\n7 oko 10 minuta nazad\n9 oko 10 minuta naprijed\npomoc:http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.wrongvlcversion funkcije nije moguca sa trenutacno upotrijebito verziji vlca +networkmenu.broadcast broadcast +networkmenu.gateway standard gateway +networkmenu.head namjestiti mrežu +networkmenu.ipaddress ip adresa +networkmenu.nameserver nameserver +networkmenu.netmask netmask +networkmenu.setupnow sada namjestiti podatke mreže +networkmenu.setuponstartup namjestiti mrežu pri startu +networkmenu.show pokazati aktivne podatke mreže +networkmenu.test provjeriti mrežu +nfs.alreadymounted direktorij je već montiran +nfs.automount pri startu montirati +nfs.dir nfs/cifs direktorij +nfs.ip ip nfs/cifs servera +nfs.localdir lokalni direktorij +nfs.mount montira nfs/cifs direktorij +nfs.mount_options opcije za montiranje +nfs.mounterror greÅ¡ka pri montiranju +nfs.mounterror_notsup ne podnosi se sistem datoteka +nfs.mountnow sada montirati +nfs.mounttimeout greska pri montiranju: tajm-aut +nfs.password lozinka za cifs +nfs.remount direktorije ponovno montirati +nfs.type tip +nfs.type_cifs cifs +nfs.type_nfs nfs +nfs.umount nfs/cifs direktorij sada demontirati +nfs.umounterror greÅ¡ka pri demontiranju +nfs.username ime korisnika za cifs +nfsmenu.head namješćenje nfsa/cifsa +nvod.percentage (%d%% proÅ¡lo) +nvod.starting (poÄetak za %d minuta) +nvodselector.directormode režija slike +nvodselector.head izabrati poÄetak +nvodselector.subservice perspektive +options.default standardno namješćenje +options.fb framebuffer +options.null null +options.off ugaÅ¡eno +options.on upaljeno +options.serial serijski +parentallock.changepin izabrati pin-broj +parentallock.changepin_hint1 Utipkajte novi pin-broj! +parentallock.changetolocked kod zabranjenih buketa +parentallock.head pin-broj za Å¡tićenje omladine +parentallock.lockage emisije +parentallock.lockage12 zabraniti od 12 godina +parentallock.lockage16 zabraniti od 16 godina +parentallock.lockage18 zabraniti od 18 godina +parentallock.lockedchannel ako je kanal zabranjen +parentallock.lockedprogram zabranjen program (od %d godina) +parentallock.never nikada +parentallock.onsignal ako ima privremena Å¡pera na kanalu +parentallock.onstart pri startu +parentallock.parentallock Å¡tićenje omladine +parentallock.prompt pitati za pin-broj +pictureviewer.defdir poÄetni direktorij +pictureviewer.head promatraÄ slika +pictureviewer.scaling skaliranje +pictureviewer.show pokazati +pictureviewer.slide_time trajanje pokazivanja slika +pictureviewer.slideshow pokazivanje slika +pictureviewer.sortorder promijeniti smjer sortiranja +pictureviewer.sortorder.date (datum) +pictureviewer.sortorder.filename (ime datoteke) +ping.ok pristupan (ping) +ping.protocol nije pristupan (host or protocol error) +ping.socket nije pristupan (socket error) +ping.unreachable nije pristupan (unreachable) +pinprotection.head kontrola pin-broja +pinprotection.wrongcode Utipkajte pin-broj ponovno! +rclock.lockmsg Speruje se daljinska dbox2.\n Za prekid spere, molim\n i na daljinskoj\n pretisnuti. +rclock.menueadd fb sperovati +rclock.title daljinsku sperovati +rclock.unlockmsg daljinska je reaktivirana... +recordingmenu.head namjestiti snimanje +recordingmenu.no_scart nema mijenjanja scarta +recordingmenu.off ugaÅ¡eno +recordingmenu.recording_type vrsta snimanja +recordingmenu.server server +recordingmenu.server_ip ip servera za snimanje +recordingmenu.server_mac mac adresa +recordingmenu.server_port port servera za snimanje +recordingmenu.server_wakeup server za snimanje wol +recordingmenu.setupnow namješćenje sada preuzeti +recordingmenu.stopplayback zaustaviti playback +recordingmenu.stopsectionsd zaustaviti sectionsd +recordingmenu.vcr video rikorder +recordingmenu.vcr_devicename ime video rikordera (lirc) +recordtimer.announce snimanje poÄinje za jednu minutu +repeatblocker.hint_1 vrijeme (u ms) izmedu 2 pritiska tipke +repeatblocker.hint_2 0 ugasi blokera (crveno je " ") +satsetup.diseqc diseqc +satsetup.diseqc10 diseqc 1.0 +satsetup.diseqc11 diseqc 1.1 +satsetup.diseqc12 diseqc 1.2 +satsetup.diseqcrepeat ponavljanje diseqca +satsetup.extended diseqc namjestiti +satsetup.extended_lnb namješćenje lnb-ea +satsetup.extended_motor namješćenje motora +satsetup.minidiseqc mini-diseqc +satsetup.motorcontrol namješćenje motora +satsetup.nodiseqc nema diseqca +satsetup.satellite satelit +satsetup.savesettingsnow namješćenje sada memorisati +satsetup.smatvremote smatv remote tuning +scants.actcable kablo: +scants.actsatellite satelit: +scants.bouquet bukete +scants.bouquet_create novo sastaviti +scants.bouquet_erase izbrisati +scants.bouquet_leave ne promijeniti +scants.bouquet_satellite satelitski buket +scants.bouquet_update obnoviti +scants.channel kanal: +scants.failed Neuspjesno traženje kanala! +scants.finished UspjeÅ¡no izvrÅ¡eno traženje kanala! +scants.freqdata frekvencija: +scants.head traženje kanala +scants.numberofdataservices data +scants.numberofradioservices radio +scants.numberoftotalservices ukupno +scants.numberoftvservices tv +scants.provider snabdjevaÄ: +scants.services servisi: +scants.startnow poÄeti traženje kanala +scants.transponders transponderi: +screensetup.lowerright zeleno = ekran dole, desno +screensetup.upperleft crveno = ekran gore, lijevo +servicemenu.head servis +servicemenu.reload liste kanale obnoviti +servicemenu.reload_hint obnavljaju se liste kanala,\nÄekajte molim ... +servicemenu.scants tražiti kanale +servicemenu.ucodecheck provjeriti ucodese +servicemenu.update obnoviti softver +settings.missingoptionsconffile Neutrino je opÅ¡iren.\nNove stvari su namješćene na standardne podatke. +settings.noconffile Podaci o neutrinu nisu naÄ‘eni.\nMeću se standardni podaci. +shutdowntimer.announce Dbox2 će se ugasiti za 1 minutu.\nPrekinuti gaÅ¡enje? +sleeptimerbox.announce vremenski brojaÄ Ä‡e ugasiti za 1 minutu +sleeptimerbox.hint1 ugasiti za XXX minuta. (000=ugaÅ¡eno) +sleeptimerbox.hint2 Dbox2 će se ugasiti za to vrijeme. +sleeptimerbox.title vremenski brojaÄ za ugasiti +streamfeatures.head osobine streama +streamfeatures.info informacija o streamu +streaminfo.aratio odnos +streaminfo.aratio_unknown nepoznat odnos +streaminfo.audiotype vrsta tona +streaminfo.audiotype_unknown nepoznata vrsta tona +streaminfo.bitrate bitrate +streaminfo.ecm_invalid nevažeći ca sistem +streaminfo.framerate framerate +streaminfo.framerate_unknown nepoznat framerate +streaminfo.head informacije +streaminfo.not_available nije pristupno +streaminfo.not_crypted nije Å¡ifrovano +streaminfo.resolution rezolucija +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head namješćenje promatraÄa filmova +streamingmenu.mpeg1 mpeg1 +streamingmenu.mpeg2 mpeg2 +streamingmenu.off ugaseno +streamingmenu.on upaljeno +streamingmenu.server_ip ip streamingservera +streamingmenu.server_port port streamingservera +streamingmenu.streaming_audiorate brzina audia +streamingmenu.streaming_force_avi_rawaudio prisili ac3 kod avia +streamingmenu.streaming_force_transcode_video transkod. i mpg/vcd video +streamingmenu.streaming_resolution resolucija +streamingmenu.streaming_server_cddrive dvd +streamingmenu.streaming_server_startdir direktorij (vlc) +streamingmenu.streaming_transcode_audio transkod. audio (dvd/vcd/mpg) +streamingmenu.streaming_transcode_video_codec mpeg video vodec +streamingmenu.streaming_type streamingserver +streamingmenu.streaming_videorate brzina videa +streamingserver.noconnect Ne postoji veza sa streamingserverom.\nPrekid snimanja. +stringinput.caps velika/mala slova +stringinput.clear sve izbrisati +timer.eventrecord.msg emisija je zapamćena za snimanje +timer.eventrecord.title zapamtiti snimanje +timer.eventtimed.msg Emisija je zapamćena.\nDbox2 će se automatiÄno upaliti i prebaciti na emisiju. +timer.eventtimed.title zapamtiti emisiju +timerbar.channelswitch prebaciti +timerbar.recordevent snimati +timerlist.alarmtime vrijeme za uzbunu +timerlist.apids audio pids +timerlist.bouquetselect izabrati buket +timerlist.channel kanal +timerlist.channelselect izabrati kanal +timerlist.delete izbrisati +timerlist.empty trenutaÄno nema vremenskih brojaÄa +timerlist.menumodify obraÄ‘ivati vremenski brojaÄ +timerlist.menunew novi vremenski brojaÄ +timerlist.message obavijest +timerlist.moderadio radio kanali +timerlist.modeselect izbor +timerlist.modetv tv kanali +timerlist.modify obrada +timerlist.name lista vremenskih brojaÄa +timerlist.new novi vremenski brojaÄ +timerlist.program.unknown nepoznati program +timerlist.reload obnoviti +timerlist.repeat ponavljanje +timerlist.repeat.biweekly dvosedmniÄno +timerlist.repeat.byeventdescription vidi vremenski brojaÄ +timerlist.repeat.daily dnevno +timerlist.repeat.fourweekly ÄetvorosedmiÄno +timerlist.repeat.friday pet +timerlist.repeat.monday pon +timerlist.repeat.monthly mjeseÄno +timerlist.repeat.once jedanput +timerlist.repeat.saturday sub +timerlist.repeat.sunday ned +timerlist.repeat.thursday Äet +timerlist.repeat.tuesday uto +timerlist.repeat.unknown nepoznato +timerlist.repeat.wednesday sri +timerlist.repeat.weekdays ovim danima +timerlist.repeat.weekly sedmiÄno +timerlist.save memorisati vremenski brojaÄ +timerlist.standby pripravnost +timerlist.standby.off buÄ‘enje iz pripravnosti +timerlist.standby.on idi u pripravnost +timerlist.stoptime vrijeme za stop +timerlist.type vrsta vremenskog brojaÄa +timerlist.type.nextprogram drugi program +timerlist.type.record snimanje +timerlist.type.remind podsjećanje +timerlist.type.shutdown ugasiti +timerlist.type.sleeptimer vremenski brojaÄ za ugasiti +timerlist.type.standby pripravnost +timerlist.type.unknown nepoznato +timerlist.type.zapto prebaciti +timerlist.weekdays dani +timerlist.weekdays.hint_1 pon uto sri Äet pet sub ned +timerlist.weekdays.hint_2 'X'=vremenski brojaÄ '-' nema vremenskog brojaÄa +timersettings.record_safety_time_after ispravljanje kraja snimanja +timersettings.record_safety_time_after.hint_1 vrijeme u minutama koje se odbija od +timersettings.record_safety_time_after.hint_2 kraja vremeskog brojaÄa (00=ugaÅ¡eno) +timersettings.record_safety_time_before ispraviti poÄetak snimanja +timersettings.record_safety_time_before.hint_1 vrijeme u minutama koje se odbija od +timersettings.record_safety_time_before.hint_2 poÄetka vremeskog brojaÄa (00=ugaÅ¡eno) +timersettings.separator namješćenje vremenskog brojaÄa +timing.chanlist lista kanala +timing.epg epg +timing.filebrowser pretraživaÄ datoteka +timing.head osd tajm-auti +timing.hint_1 vrijeme u sekundama u kojemu +timing.hint_2 će biti pokazana informativna traka +timing.infobar infromativna traka +timing.menu izbor +ucodecheck.avia500 avia 500 +ucodecheck.avia600 avia 600 +ucodecheck.cam-alpha cam-alpha +ucodecheck.head provjera ucodesa +ucodecheck.ucode ucode +ucodes.failure Pažnja, nisu naÄ‘eni ucodesi!\n\nMolim sa ftpeom (ili dbox-bootmanagerom)\npostaviti, i dbox2 ponovno startovati! +videomenu.csync namjescenje sinkronizacije +videomenu.head namjestiti video +videomenu.rgb_centering centriranje rgbea +videomenu.screensetup namjestiti ekran +videomenu.vcrswitch automatiÄni av-scart ulaz +videomenu.videoformat format ekrana +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (lb) +videomenu.videoformat_431 4:3 (ps) +videomenu.videoformat_autodetect automatiÄno +videomenu.videosignal vrsta video signala +videomenu.videosignal_composite cvbs +videomenu.videosignal_rgb rgb + cvbs +videomenu.videosignal_svideo s-video +videomenu.videosignal_yuv_c yuv + cvbs +videomenu.videosignal_yuv_v yuv + vbs +zaptotimer.announce za jednu minutu će se dbox2 prebaciti diff --git a/data/locale/ch-baslerdeutsch.locale b/data/locale/ch-baslerdeutsch.locale new file mode 100644 index 000000000..201532198 --- /dev/null +++ b/data/locale/ch-baslerdeutsch.locale @@ -0,0 +1,722 @@ +EPGMenu.epgplus Vorschau Ãœbersicht +EPGMenu.eventinfo Info zuer Sendig +EPGMenu.eventlist Vorschau aktuelles Programm +EPGMenu.head EPG - Programm Information +EPGMenu.streaminfo technische Information +EPGPlus.head Vorschau Ãœbersicht (EPG Plus) +EPGPlus.record Uufnahm +EPGPlus.refresh_epg Aktualisiere +EPGPlus.remind Vormerke +EPGPlus.scroll_mode Scroll Mode +EPGPlus.stretch_mode Stretch Mode +GENRE.ARTS.0 Chunschd / Kultur +GENRE.ARTS.1 Darstellendi Chünschd +GENRE.ARTS.10 Chunschd-/Kultur-Magazin +GENRE.ARTS.11 Mode +GENRE.ARTS.2 fine arts +GENRE.ARTS.3 Religion +GENRE.ARTS.4 Volkskunst +GENRE.ARTS.5 Literatur +GENRE.ARTS.6 Film/Kino +GENRE.ARTS.7 experimental film/video +GENRE.ARTS.8 Rundfunk/Presse +GENRE.ARTS.9 Neui Mediä +GENRE.CHILDRENs_PROGRAMMES.0 Chinder / Jugendprogramm +GENRE.CHILDRENs_PROGRAMMES.1 Programm für Vorschuelchinder +GENRE.CHILDRENs_PROGRAMMES.2 Unterhaltigsprogramm für 6 bis 14-Jährigi +GENRE.CHILDRENs_PROGRAMMES.3 Unterhaltigsprogramm für 10 bis 16-Jährigi +GENRE.CHILDRENs_PROGRAMMES.4 Informations- un Bildigsprogramm +GENRE.CHILDRENs_PROGRAMMES.5 Trickfilm +GENRE.DOCUS_MAGAZINES.0 Doku/Magazin +GENRE.DOCUS_MAGAZINES.1 Natur/Tiere/Umwelt +GENRE.DOCUS_MAGAZINES.2 Naturwissenschaft un Technik +GENRE.DOCUS_MAGAZINES.3 Medizin/Physiologie/Psychologie +GENRE.DOCUS_MAGAZINES.4 Usland/Expeditions +GENRE.DOCUS_MAGAZINES.5 Sozial- un Geischeswissenschaften +GENRE.DOCUS_MAGAZINES.6 wiiderbildig +GENRE.DOCUS_MAGAZINES.7 Sprooche +GENRE.MOVIE.0 Spielfilm / Drama +GENRE.MOVIE.1 Kriminalfilm/Thriller +GENRE.MOVIE.2 Abenteuerfilm/Western/Kriegsfilm +GENRE.MOVIE.3 Science-Fiction/Fantasy/Horror +GENRE.MOVIE.4 Comedy +GENRE.MOVIE.5 Soap/Melodram/Folklore +GENRE.MOVIE.6 Romantik +GENRE.MOVIE.7 serious/classical/religious/hischorical movie/drama +GENRE.MOVIE.8 adult movie/Drama +GENRE.MUSIC_DANCE.0 Musik/Ballet/Tanz +GENRE.MUSIC_DANCE.1 Rock/Pop +GENRE.MUSIC_DANCE.2 serious music/Klassik +GENRE.MUSIC_DANCE.3 Volksmusik +GENRE.MUSIC_DANCE.4 Jazz +GENRE.MUSIC_DANCE.5 Musical/Oper +GENRE.MUSIC_DANCE.6 Ballet +GENRE.NEWS.0 Nachrichte +GENRE.NEWS.1 Nachrichte/Wetter +GENRE.NEWS.2 Nachrichtemagazin +GENRE.NEWS.3 Dokumantation +GENRE.NEWS.4 Diskussion/Interview/Debatte +GENRE.SHOW.0 Show / Gameshow +GENRE.SHOW.1 Gameshow/Quiz +GENRE.SHOW.2 varietee +GENRE.SHOW.3 Talkshow +GENRE.SOCIAL_POLITICAL.0 Sozial & Politikereignisse / Wirtschaft +GENRE.SOCIAL_POLITICAL.1 Magazin/Report/Dokumentation +GENRE.SOCIAL_POLITICAL.2 Wirtschaft un Soziales +GENRE.SOCIAL_POLITICAL.3 Bsunderi Mänsche +GENRE.SPORTS.0 Sport +GENRE.SPORTS.1 Großereigniss (Olympische Spiele, Weltmeischerschafte usw.) +GENRE.SPORTS.10 equestrian +GENRE.SPORTS.11 martial sports +GENRE.SPORTS.2 Sportsmagazine +GENRE.SPORTS.3 Fußball +GENRE.SPORTS.4 Tennis +GENRE.SPORTS.5 Mannschaftssport +GENRE.SPORTS.6 Leichtathletik +GENRE.SPORTS.7 Motorsport +GENRE.SPORTS.8 Wassersport +GENRE.SPORTS.9 Wintersport +GENRE.TRAVEL_HOBBIES.0 Reise & Freizeit +GENRE.TRAVEL_HOBBIES.1 Reisen un Tourismus +GENRE.TRAVEL_HOBBIES.2 handicraft +GENRE.TRAVEL_HOBBIES.3 Motor +GENRE.TRAVEL_HOBBIES.4 Fitness un G'sundheit +GENRE.TRAVEL_HOBBIES.5 Choche +GENRE.TRAVEL_HOBBIES.6 Iichauf +GENRE.TRAVEL_HOBBIES.7 Garte +GENRE.UNKNOWN Unbekannt +apids.hint_1 Gib z'erschd d'zschdriemendi APIDs ii, +apids.hint_2 abdrennd durch ' ' in hexadezimaler Form +apidselector.head Sproochuswahl +audiomenu.PCMOffset Lutstärkeabsänkig PCM +audiomenu.analogout Analog-Usgang +audiomenu.avs avs +audiomenu.avs_control Luutstärgi Stüürig avs/os +audiomenu.dolbydigital Dolby Digital automatisch +audiomenu.head Audio-Iischdellige +audiomenu.lirc lirc +audiomenu.monoleft mono lings +audiomenu.monoright mono rächts +audiomenu.ost ost +audiomenu.stereo stereo +audioplayer.add A'hänge +audioplayer.artist_title Interpret, Titel +audioplayer.defdir Start-Verz. +audioplayer.delete Lösche +audioplayer.deleteall Alles lösche +audioplayer.display_order Anzeig' +audioplayer.fastforward schnälle Vorl. +audioplayer.follow Selektiere akt. Track +audioplayer.id3scan scänn ID3-Tags +audioplayer.keylevel Taschde-Umschaldig +audioplayer.pause Pause +audioplayer.play Abspiele +audioplayer.playing aktuelle track +audioplayer.rewind schnälle Rückl. +audioplayer.screensaver_timeout Bildschirmschoner (min, 0=aus) +audioplayer.shuffle Zuefällig mische +audioplayer.stop A'halte +audioplayer.title_artist Titel, Interpret +bookmarkmanager.delete Lösche +bookmarkmanager.name Bookmarks +bookmarkmanager.rename Umbenenne +bookmarkmanager.select Uuswähle +bouqueteditor.add d'zuemache +bouqueteditor.bouquetname Name vom Bouquet' +bouqueteditor.delete Lösche +bouqueteditor.discardingchanges Änderige werde verworfe. Bitte warte ... +bouqueteditor.hide Verstäcke +bouqueteditor.lock Spääre +bouqueteditor.move Vschiebe +bouqueteditor.name Bouquet-Verwaltig +bouqueteditor.newbouquetname Neue Name fürs Bouquet' +bouqueteditor.rename Umbenenne +bouqueteditor.return Feddig +bouqueteditor.savechanges? Solle die Änderige g'speicheret werde? +bouqueteditor.savingchanges Änderige werde gspeicheret. Bitte warte ... +bouqueteditor.switch Kanal uffneh/entferne +bouqueteditor.switchmode TV/Radio +bouquetlist.head Bouquets +cablesetup.provider Kabelabieder +channellist.head Alle Kanäle +channellist.nonefound M'r hänn keine Kanäl g'funde!\nMach e Kanalsüchi\n(dbox-Taste -> Service) +channellist.since sidd %02d:%02d +colorchooser.alpha alpha +colorchooser.blue blau +colorchooser.green grien +colorchooser.red rot +colormenu.background Hintergrundfarb +colormenu.background_head Hintergrundfarb +colormenu.fade Menüs faden +colormenu.font Schriftgrössi +colormenu.gtx_alpha Transparänz (GTX) +colormenu.head Farb-Iischdellige +colormenu.menucolors Menüfarb +colormenu.statusbar Statusbalke +colormenu.textcolor Textfarb +colormenu.textcolor_head Textfarb +colormenu.themeselect Theme usswähle +colormenu.timing OSD Timeouts +colormenusetup.head Menüfarbe +colormenusetup.menucontent Fenschderinhalt +colormenusetup.menucontent_inactive Fenschderinhalt deaktiviert +colormenusetup.menucontent_selected Fenschderinhalt selektiert +colormenusetup.menuhead Titelleischde +colorstatusbar.head Statusbalken-Farbe +colorstatusbar.text Statusbalken +colorthememenu.classic_theme Klassik +colorthememenu.head Theme usswähle +colorthememenu.neutrino_theme Neutrino Theme +date.Apr Apr +date.Aug Aug +date.Dec Dez +date.Feb Feb +date.Fri Fr +date.Jan Jan +date.Jul Jul +date.Jun Jun +date.Mar Mär +date.May Mai +date.Mon Mä +date.Nov Nov +date.Oct Okt +date.Sat Sa +date.Sep Sep +date.Sun Su +date.Thu Du +date.Tue Ts +date.Wed Mi +epglist.head Vorschau - %s +epglist.noevents Keini EPG-Informatione verfuigbar. +epgviewer.More_Screenings wiidere Termine uf dämm Kanal +epgviewer.nodetailed Keini usführliche Informationen verfuigbar +epgviewer.notfound keini Programminformatione (EPG) g'funde +favorites.addchannel De aktuelle Kanal wirdm Bouquet \n"Mieni Favoridde" a'ghängt. \nS'speichere gooht e Moment... +favorites.bouquetname Mieni Favoridde +favorites.bqcreated Bouquet "Miini Favoridde" isch a'gelegt...\n +favorites.chadded De aktuelle Kanal isch Ihre Favoridde hinzugefuegt worde...\n +favorites.chalreadyinbq De aktuelle Kanal isch bereits in Ihre Favoridde...\n +favorites.finalhint \nVersehentlich dezuefügti Kanäl chönne mit\nd'r Bouquetverwaltig korrigiert werde.\n +favorites.menueadd Kanal Favoridde d'zue'due +favorites.nobouquets Favoridde sin numme mit aktivierte Bouquets mäglich +filebrowser.delete Lösche +filebrowser.dodelete1 Soll +filebrowser.dodelete2 glöscht werde? +filebrowser.filter.active Filter aah +filebrowser.filter.inactive Filter uus +filebrowser.head Filebrowser +filebrowser.mark Markiere +filebrowser.nextpage Sidde vor +filebrowser.prevpage Sidde zruck +filebrowser.scan Verzeichnisse durchsürche +filebrowser.select Usswähle +filebrowser.showrights Dateirechte a'zeige +filebrowser.sort.date (Datum) +filebrowser.sort.name (Dateiname) +filebrowser.sort.namedirsfirst (Dateiname2) +filebrowser.sort.size (Größe) +filebrowser.sort.type (Typ) +flashupdate.action Aktion: +flashupdate.actionreadflash lese flash +flashupdate.actionwriteflash schrieb grad s'flash +flashupdate.cantopenfile ka Datei nidd uffmache +flashupdate.cantopenmtd ka's MTD-Device nidd uffmache +flashupdate.checkupdate nach neuer Version sueche +flashupdate.currentreleasecycle Releasezyklus +flashupdate.currentversion_sep Installierdi Version +flashupdate.currentversiondate Datum +flashupdate.currentversionsnapshot ImageTyp +flashupdate.currentversiontime Uhrzit +flashupdate.erasefailed Flash lösche fehlg'schlage +flashupdate.erasing lösch' grad s'Fläsh +flashupdate.experimentalimage Sie henn ä Snapshot usgwählt, bitte beachte Sie, dass\ndie Version untestet isch un u.U. Ihre Box nach dem Update\nnümmi funktionsfähig isch.\n\nSoll die Version wirklich installiert werde? +flashupdate.expertfunctions Experte-Funktione +flashupdate.fileis0bytes d'Dateigrößi isch 0 Byte +flashupdate.fileselector Datei-Usswahl +flashupdate.flashreadyreboot S'Image isch erfolgriich g'flasht.\nd'DBox wird jetz neu g'starded. +flashupdate.getinfofile lade Versioninfo +flashupdate.getinfofileerror ka Info nidd lade +flashupdate.getupdatefile lade Öpdate +flashupdate.getupdatefileerror ka Öpdate nidd lade +flashupdate.globalprogress G'samtstatus: +flashupdate.head Aktualisierig +flashupdate.md5check Imagepruefig +flashupdate.md5sumerror Des Image isch fehlerhaft +flashupdate.msgbox S'het folgendi neui Images:\nDatum: %s, %s\nBasisImage: %s\nImageTyp: %s\n\nWillsch die neui Version jetz abelade\nund installiere? +flashupdate.msgbox_manual S'het s'folgend neu Image:\nDatum: %s, %s\nBasisImage: %s\nImageTyp: %s\n\nWillsch die neui Version jetz installiere? +flashupdate.mtdselector Partitions-Usswahl +flashupdate.programmingflash programmier grad s'Fläsh +flashupdate.proxypassword Passwort +flashupdate.proxypassword_hint1 Gib's Proxy-Passwort Ii +flashupdate.proxypassword_hint2 +flashupdate.proxyserver Proxyname +flashupdate.proxyserver_hint1 Gib de Proxyname oder d'IP ii (Host:Port) +flashupdate.proxyserver_hint2 E leere Iintrag bedüded kei Proxy +flashupdate.proxyserver_sep Proxyserver +flashupdate.proxyusername Benutzername +flashupdate.proxyusername_hint1 Gib de Proxy-Benutzername ii +flashupdate.proxyusername_hint2 E leere Iintrag bedüded kei Authentifizierig +flashupdate.readflash ganzes Flashimage usläse +flashupdate.readflashmtd einzelni Partition usläse +flashupdate.ready ferdig +flashupdate.reallyflashmtd Willsch dä Flashvorgang wirklich mache?\n\nFalls es e'Fehler gitt odder s'Image nidd\nfunktionfäähig isch, wird d'DBox nümmi boote.\n\nImagename: %s\nZiel: %s +flashupdate.reboot Die DBox wird neu g'starded +flashupdate.savesuccess S'Image sich erfolgriich unterm \nDateiname %s gspeichrt. +flashupdate.selectimage Verfügbari Images +flashupdate.titlereadflash Flash ussläse +flashupdate.titlewriteflash Flash schriibe +flashupdate.updatemode Öpdatemodus +flashupdate.updatemode_internet internet +flashupdate.updatemode_manual manuell (ftp) +flashupdate.url_file Konfigfile +flashupdate.versioncheck Versionsueberpruefig +flashupdate.writeflash ganzes Flashimage i'spile +flashupdate.writeflashmtd einzelni Partition i'spile +flashupdate.wrongbase Die Releasezyklus Version weicht ab, bitte\nzuerst neues Komplett-Image installieren! +fontmenu.channellist Kanallischde +fontmenu.epg EPG +fontmenu.eventlist Eventlist +fontmenu.gamelist Gameliste +fontmenu.head Schriftgrössen Iischdellige +fontmenu.infobar Infobar +fontsize.channellist Kanallischde +fontsize.channellist_descr Beschriebig +fontsize.channellist_number Nummere +fontsize.epg_date EPG Datum +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Titel +fontsize.eventlist_datetime Eventlist Datum / Ziit +fontsize.eventlist_itemlarge Eventlist gross +fontsize.eventlist_itemsmall Eventlist chlei +fontsize.eventlist_title Eventlist Titel +fontsize.filebrowser_item Dateibrowser-Iidrag +fontsize.gamelist_itemlarge gross +fontsize.gamelist_itemsmall chlei +fontsize.hint Font wird initialisiert,\ne'Moment warde... +fontsize.infobar_channame Infobar Kanal +fontsize.infobar_info Infobar Info +fontsize.infobar_number Infobar Nummere +fontsize.infobar_small Infobar chlei +fontsize.menu Menutext +fontsize.menu_info Menu Info +fontsize.menu_title Menu Titel +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.cantdecode Kanal ka nidd entschlüsselt werde +infoviewer.epgnotload Informatione no'nidd g'lade... +infoviewer.epgwait Wart' uf EPG-Informatione... +infoviewer.eventlist Programm +infoviewer.languages Tonwahl +infoviewer.motor_moving Antennepositionierig +infoviewer.nocurrent Kei Info zuem laufende Programm +infoviewer.noepg Kei EPG-Information verfuigbar +infoviewer.notavailable Kanal (zur Zit) nidd verfieegbar +infoviewer.selecttime Startzite +infoviewer.streaminfo Fiitschrs +infoviewer.subservice Bildregie +infoviewer.waittime Wart' uff'd Uhrzeit... +ipsetup.hint_1 Nimm 0..9 odder abe/uffe +ipsetup.hint_2 OK speichert, Home bricht ab +keybindingmenu.RC Fernbedienig +keybindingmenu.addrecord Uffnahme-Timer d'züfüge +keybindingmenu.addrecord_head Uffnahme-Timer d'züfüge +keybindingmenu.addremind Umschald-Timer d'züfüge +keybindingmenu.addremind_head Umschald-Timer d'züfüge +keybindingmenu.allchannels_on_ok Kanallischde +keybindingmenu.bouquetchannels_on_ok Bouquet-Kanäl +keybindingmenu.bouquetdown Bouquet z'ruck +keybindingmenu.bouquetdown_head Bouquet z'ruck Taste +keybindingmenu.bouquethandling OK-Taste für +keybindingmenu.bouquetlist_on_ok Bouquetlische +keybindingmenu.bouquetup Bouquet widder +keybindingmenu.bouquetup_head Bouquet widder Taste +keybindingmenu.cancel Kanallischde zuemache +keybindingmenu.cancel_head Kanallischde zuemache +keybindingmenu.channeldown Kanal abe +keybindingmenu.channeldown_head Kanal abe Taste +keybindingmenu.channellist Kanallischde +keybindingmenu.channelup Kanal uffe +keybindingmenu.channelup_head Kanal uffe Taste +keybindingmenu.head Tasten-Iischdellige +keybindingmenu.modechange Modus wäggsle +keybindingmenu.pagedown Sidde abe blätter +keybindingmenu.pagedown_head Sidde abe blättere +keybindingmenu.pageup Sidde uffe blättere +keybindingmenu.pageup_head Sidde uffe blättere +keybindingmenu.quickzap Schnällumschaldig +keybindingmenu.repeatblock Wiederholigsverzögerig +keybindingmenu.repeatblockgeneric Afangsverzögerig +keybindingmenu.sort Sortierreihefolg ändere +keybindingmenu.sort_head Sortierreihefolg ändere +keybindingmenu.subchanneldown Underkanal z'ruck +keybindingmenu.subchanneldown_head Underkanal z'ruck +keybindingmenu.subchannelup Underkanal wiider +keybindingmenu.subchannelup_head Underkanal wiider +keybindingmenu.tvradiomode Fernseh-/Radio-Modus +keybindingmenu.tvradiomode_head Fernseh-/Radio-Modus +keychooser.head Neue Taste Iistelle +keychooser.text1 Bitte Taste drucke +keychooser.text2 Zuem abbreche warde.. +keychoosermenu.currentkey Derzitige Taste +keychoosermenu.setnew Neue Taste Iistelle +keychoosermenu.setnone Kei Taste +languagesetup.head Sproochischellige +languagesetup.select Sprooch +lcdcontroler.brightness normale Helligkeit +lcdcontroler.brightnessstandby Standby Helligkeit +lcdcontroler.contrast Kontrast +lcdcontroler.head LCD Stettings +lcdmenu.autodimm Automatisch dimme +lcdmenu.head LCD Iistellige +lcdmenu.inverse Inverdiere +lcdmenu.lcdcontroler Kontrast / Hälligkeit +lcdmenu.power Pfuus +lcdmenu.statusline Statusziile +lcdmenu.statusline.both change me +lcdmenu.statusline.playtime Sendigsfortschritt +lcdmenu.statusline.volume Lutstärki +mainmenu.games Spiele +mainmenu.head Haupdmenü +mainmenu.movieplayer Movieplayer +mainmenu.pausesectionsd EPG uss'läse +mainmenu.pictureviewer Bildbedrachder +mainmenu.radiomode Radio-Modus +mainmenu.recording Sdreaming (ufnehh) +mainmenu.recording_start un los +mainmenu.recording_stop hald +mainmenu.scartmode Scart-Igang +mainmenu.service Sörvis +mainmenu.settings Iischdellige +mainmenu.shutdown Usschalde +mainmenu.sleeptimer Schloofschalder +mainmenu.tvmode TV-Modus +mainsettings.audio Audio +mainsettings.colors Farbe / Theme / Schrifd +mainsettings.head Iischdellige +mainsettings.keybinding Taste-Iischdellige +mainsettings.language Sprooch +mainsettings.lcd LC-Display +mainsettings.misc Diversi Iischdellige +mainsettings.network Netzwärk +mainsettings.plugins Plugin Iischdellige +mainsettings.recording Sdreamingsörfer +mainsettings.savesettingsnow Iischdellige jetz speichere +mainsettings.savesettingsnow_hint Iistellige wärde jetz g'speichered,\ne'Moment warde... +mainsettings.scan Iischdellige Kanalsürch +mainsettings.streaming Movieplayer +mainsettings.video Video +menu.back z'ruck +messagebox.back z'ruck +messagebox.cancel Abbruch +messagebox.discard Willsch d'Änderige verwärfe? +messagebox.error Fehler +messagebox.info Informatione +messagebox.no Nei +messagebox.yes Jo +miscsettings.bootinfo Infos bim Boote a'zeige +miscsettings.boxtype DBox Hersdeller +miscsettings.fb_destination EXPERT! Boot-Chonsole +miscsettings.general Allg'mein +miscsettings.head Diverse Iischdellige +miscsettings.infobar_sat_display Infobar Satellite-A'zeig +miscsettings.shutdown_real Sdändbymodus +miscsettings.shutdown_real_rcdelay V'rzögerede Shudown +miscsettings.startbhdriver BH-Mode Triiber lade +motorcontrol.head Motor-Setup +movieplayer.bookmark Bookmarks +movieplayer.bookmarkname Bookmark Name +movieplayer.bookmarkname_hint1 Gib de Name für's neue Bookmark ii +movieplayer.bookmarkname_hint2 +movieplayer.buffering Puffere... +movieplayer.defdir Start-Verz. +movieplayer.dvdplayback DVD +movieplayer.fileplayback Datei via VLC +movieplayer.goto Spring' zue ... +movieplayer.goto.h1 = -> absolute Sprung +movieplayer.goto.h2 +,- -> relative Sprung +movieplayer.head Movieplayer +movieplayer.nostreamingserver Es het kei Verbindig\nzuem Streamingserver herg'stellt werde chönne. +movieplayer.pesplayback PES Abspiele (Experimendell) +movieplayer.pleasewait Bitte warde.\nD'Verbindig zuem Streamingserver wird herg'stellt. +movieplayer.toomanybookmarks D'hesch bereits z'viel Bookmarks a'glegt.\nEs mueß erscht e anderes g'löscht werde. +movieplayer.tsplayback TS Abspiele +movieplayer.vcdplayback (S)VCD +movieplayer.vlchelp ROT/Home Stop\nGRÃœN Resync\nGELB Paus/Widdr\nBLAU Bookmark setze\nd-box Ziit iiblände\nv Sprung\n1 ca. 1 Minute zruck\n3 ca. 1 Minute vor\n4 ca. 5 Minute zruck\n6 ca. 5 Minute vor\n7 ca. 10 Minute zruck\n9 ca. 10 Minute vor\nHilfe: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.wrongvlcversion Funktion isch mit dr benutzte Version vom VLC nit möglich +networkmenu.broadcast Broadcast +networkmenu.gateway Standard Gateway +networkmenu.head Netzwäerk Iischdellige +networkmenu.ipaddress IP-Adress' +networkmenu.nameserver Nameserver +networkmenu.netmask Netzmaske +networkmenu.setupnow NetzwärkIischdellige jetz zuewiise +networkmenu.setuponstartup Bim Starte Netzwärk setze +networkmenu.show aktive NetzwärkIischdellige zeige +networkmenu.test Netzwärk deschde +nfs.alreadymounted Verzeichnis bereits a'ghängt +nfs.automount Biem Start i'hänge +nfs.dir NFS/CIFS Server Verzeichniss +nfs.ip NFS/CIFS Server IP +nfs.localdir lokales Verzeichniss +nfs.mount NFS/CIFS Verzeichniss i'hänge +nfs.mount_options Mount-Optionen +nfs.mounterror I'häng - Fehler +nfs.mounterror_notsup Dateisystem-Typ wird nit understützt +nfs.mountnow Jetz i'hänge +nfs.mounttimeout Mount-Fehler: Timeout +nfs.password CIFS Passwort +nfs.remount Verzeichnisse erneut mounte +nfs.type Typ +nfs.type_cifs CIFS +nfs.type_nfs NFS +nfs.umount NFS/CIFS Verzeichniss abhänge +nfs.umounterror Abhäng-Fehler +nfs.username CIFS Benutzername +nfsmenu.head NFS/CIFS Iischdellige +nvod.percentage (%d%% umme) +nvod.starting (Goht los in %d min) +nvodselector.directormode Bildregie-Modus +nvodselector.head Anfangszit usswähle +nvodselector.subservice Perspektive +options.default Voristellige nee +options.fb frembaffer +options.null null +options.off us +options.on ii +options.serial säriell +parentallock.changepin PIN-Code feschdlege +parentallock.changepin_hint1 Gib de neu PIN-Code ii! +parentallock.changetolocked Bi vorgsperrte Bouquets +parentallock.head Goofe'schutz PIN +parentallock.lockage Sendige +parentallock.lockage12 ab 12 Joohr sperre +parentallock.lockage16 ab 16 Joohr sperre +parentallock.lockage18 ab 18 Joohr sperre +parentallock.lockedchannel Vorgesperrte Sänder... +parentallock.lockedprogram Gspärrtes Programm (FSK ab %d) +parentallock.never Nie +parentallock.onsignal Bi gsendeter Vorsperri +parentallock.onstart Bim Start +parentallock.parentallock Goofe'schutz +parentallock.prompt PIN-Iigab +pictureviewer.defdir Start-Verz. +pictureviewer.head Bildbedrachder +pictureviewer.scaling Skalierig +pictureviewer.show A'zeige +pictureviewer.slide_time Diaschau-A'zeigeduur +pictureviewer.slideshow Diaschau +pictureviewer.sortorder Sort.reihenf. äändere +pictureviewer.sortorder.date (Datum) +pictureviewer.sortorder.filename (Dateiname) +ping.ok isch erreichbar (ping) +ping.protocol isch nidd erreichbar (Host or protocol error) +ping.socket isch nidd erreichbar (Socket error) +ping.unreachable isch nidd erreichbar (unreachable) +pinprotection.head PIN-Abfroog +pinprotection.wrongcode Gib de Code nonemol ii! +rclock.lockmsg D'Fernbedienig der dbox2 wird gsperrt.\nUm'd Sperre uufz'hebe, bitte\n und uff dr Fernbedienig\ndrucke. +rclock.menueadd FB sperre +rclock.title Fernbedienung sperre +rclock.unlockmsg Fernbedienig reaktiviert... +recordingmenu.head Streamingserver Iischdellige +recordingmenu.no_scart Scart-Umschaldig underdrugge +recordingmenu.off uss +recordingmenu.recording_type Uffnahme g'rät +recordingmenu.server sörfer +recordingmenu.server_ip Uffnahmesörfer IP +recordingmenu.server_mac Mac Adräss +recordingmenu.server_port Uffnahmesörfer Port +recordingmenu.server_wakeup Uffnahmesörfer WOL +recordingmenu.setupnow Iinsdellige jetz überneh +recordingmenu.stopplayback Abspiele a'halde +recordingmenu.stopsectionsd Sectionsd a'halde +recordingmenu.vcr Videorecorder +recordingmenu.vcr_devicename VCR Name (lirc) +recordtimer.announce D'Ufnahm beginnt in weniga Minudde +repeatblocker.hint_1 Mindeschtzit (in ms) zwüsche 2 Tastedrück' +repeatblocker.hint_2 0 schaldet de Blocker us (Rot isch " ") +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-Widderholigge +satsetup.extended DiSEqC-Iinstellig +satsetup.extended_lnb LNB-Iistellige +satsetup.extended_motor Motor-Iistellige +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Motor-Setup +satsetup.nodiseqc Kein DiSEqC +satsetup.satellite Sadellid +satsetup.savesettingsnow Iischdellige jetz speichere +satsetup.smatvremote SMATV Remote Tuning +scants.actcable Kabel: +scants.actsatellite Sadellid: +scants.bouquet Bouquets +scants.bouquet_create neu mache +scants.bouquet_erase lösche +scants.bouquet_leave nidd ändere +scants.bouquet_satellite Satellite-Bouquet: +scants.bouquet_update erneuere +scants.channel Kanal: +scants.failed Kanalsuechii fehlg'schlage! +scants.finished Kanalsueche erfolgrich beändet! +scants.freqdata Frequenz: +scants.head Kanalsuechi +scants.numberofdataservices Data +scants.numberofradioservices Radio +scants.numberoftotalservices Alli zämme: +scants.numberoftvservices TV +scants.provider Abieter: +scants.services Services: +scants.startnow Kanalsuechi starde +scants.transponders Transponder: +screensetup.lowerright grün = Bildrand unde, rechts +screensetup.upperleft rot = Bildrand obe, links +servicemenu.head Sörvis +servicemenu.reload Kanallischde neu lade +servicemenu.reload_hint Kannallischde wärde neu g'lade,\ne'Moment warde... +servicemenu.scants Kanalsürchi +servicemenu.ucodecheck UCodes tschegge +servicemenu.update Software-Öbdaede +settings.missingoptionsconffile D'Neutrino-Iischdellige wurde erwiidered.\nDie neue Wärt werde uff Standard g'setzt. +settings.noconffile D'Neutrino-Iischdellige wurde nidd\ngfunde. S'werde d'Standardwert gno. +shutdowntimer.announce In einere Minudde wird d'Chischte abe'gfahre.\nShutdown abbräche? +sleeptimerbox.announce Ussschaltzit in 1 min +sleeptimerbox.hint1 Ussschaltzit in Min. (000=aus) +sleeptimerbox.hint2 D'dbox2 schaltet sich nach dere Zit uss. +sleeptimerbox.title Schloofuhr +streamfeatures.head Fiitschrs +streamfeatures.info Stream-Informatione +streaminfo.aratio Verhältnis +streaminfo.aratio_unknown Verhältnis: unbekannt +streaminfo.audiotype Audiotyp +streaminfo.audiotype_unknown Audiotyp: unbekannt +streaminfo.bitrate Bitrate +streaminfo.ecm_invalid igüldiges CA-Syschdem +streaminfo.framerate Bildrate +streaminfo.framerate_unknown Bildrate: unbekannt +streaminfo.head Informatione +streaminfo.not_available nidd verfuigbar +streaminfo.not_crypted nidd verschlüssld +streaminfo.resolution Uflösig +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Movieplayer Iistellige +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Deaktiviert +streamingmenu.on Aktiviert +streamingmenu.server_ip Streamingserver IP +streamingmenu.server_port Streamingserver Port +streamingmenu.streaming_audiorate Daterade Audio +streamingmenu.streaming_force_avi_rawaudio Erzwinge AC3 bii avi +streamingmenu.streaming_force_transcode_video Transcod. auch mpg/vcd Video +streamingmenu.streaming_resolution Auflösung +streamingmenu.streaming_server_cddrive DVD Laufwerk +streamingmenu.streaming_server_startdir Verzeichniss (VLC) +streamingmenu.streaming_transcode_audio Transcod. Audio (dvd/vcd/mpg) +streamingmenu.streaming_transcode_video_codec MPEG Video Codec +streamingmenu.streaming_type Streamingserver +streamingmenu.streaming_videorate Daterade Video +streamingserver.noconnect Kei Verbindig zuem Streamingsörver.\nd'Uffnahm' wird abbroche. +stringinput.caps Groß-/Chleiueuchstabe +stringinput.clear OSD Timeouts +timer.eventrecord.msg D'Sendig isch zuer Aufnahm vorgmerkt +timer.eventrecord.title Uffnahm vormerke +timer.eventtimed.msg Die Sendig isch vorgmerkt +timer.eventtimed.title Sendig vormerke +timerbar.channelswitch Umschalte +timerbar.recordevent Ufneh +timerlist.alarmtime Alarmzit +timerlist.apids Audio PIDs +timerlist.bouquetselect Bouquet wähle +timerlist.channel Kanal +timerlist.channelselect Kanal wähle +timerlist.delete Lösche +timerlist.empty S'git momentan kei Timer +timerlist.menumodify Timer bearbeitde +timerlist.menunew Neue Timer +timerlist.message Noochricht +timerlist.moderadio Radio-Kanäl +timerlist.modeselect Modus Usswahl +timerlist.modetv TV-Kanäl +timerlist.modify Öpdate +timerlist.name timerliste +timerlist.new Neue Timer +timerlist.program.unknown Programm chenne m'r nid +timerlist.reload Aktualisiere +timerlist.repeat Widderholig +timerlist.repeat.biweekly alli 2 wuche +timerlist.repeat.byeventdescription lueg under timer +timerlist.repeat.daily jede daag +timerlist.repeat.fourweekly alli 4 wuche +timerlist.repeat.friday Fr +timerlist.repeat.monday Mä +timerlist.repeat.monthly jede moned +timerlist.repeat.once eimalig +timerlist.repeat.saturday Sa +timerlist.repeat.sunday Su +timerlist.repeat.thursday Du +timerlist.repeat.tuesday Ts +timerlist.repeat.unknown chenne m'r nid +timerlist.repeat.wednesday Mi +timerlist.repeat.weekdays An Wuchedaag +timerlist.repeat.weekly jedi wuche +timerlist.save speichere +timerlist.standby SB Modus +timerlist.standby.off Uff Standby goh +timerlist.standby.on Uffwache us Standby +timerlist.stoptime Stopzit +timerlist.type Timertyp +timerlist.type.nextprogram Näggschdes Programm +timerlist.type.record Uffnahm +timerlist.type.remind Erinnerig +timerlist.type.shutdown Abe fahre +timerlist.type.sleeptimer Schloofuhr +timerlist.type.standby Standby +timerlist.type.unknown chenne m'r nit +timerlist.type.zapto Umschalte +timerlist.weekdays Wuchedaag +timerlist.weekdays.hint_1 Mä Ts Mi Du Fr Sa Su +timerlist.weekdays.hint_2 'X'=Timer '-' kei Timer +timersettings.record_safety_time_after Uffnahmeänd-Korrekdur +timersettings.record_safety_time_after.hint_1 Korrekdurzit in Min. (00=aus), die uff'd End- +timersettings.record_safety_time_after.hint_2 zit vom jewilige Timer dezuezellt wird +timersettings.record_safety_time_before Uffnahmestart-Korrekdur +timersettings.record_safety_time_before.hint_1 Korregdurzit in Min. (00=aus), die bim Start +timersettings.record_safety_time_before.hint_2 vom jewilige Timer abzoge wärde +timersettings.separator Timeriischdellige +timing.chanlist Kanallischde +timing.epg Epg +timing.filebrowser Filebrowser +timing.head OSD Timeouts +timing.hint_1 Iinbländzit in Sek., di's OSD +timing.hint_2 uffem TV a'zeigt wird +timing.infobar Infobar +timing.menu Menu +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head UCode Ueberpruefig +ucodecheck.ucode UCode +ucodes.failure Achtig, die µCodes wurde nidd gefunde!\n\nBitte per FTP (oder DBox-BootManager)\nöploaden, un d'DBox neu starte! +videomenu.csync Sync.-Korrektur +videomenu.head Video-Iischdellige +videomenu.rgb_centering RGB-Zentrierig +videomenu.screensetup Bildbereich ischelle +videomenu.vcrswitch Scart-Eingang audomaddisch +videomenu.videoformat Bildschirmformat +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect audomaddisch +videomenu.videosignal Video Signalart +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce In einere Minudde wird umgeschalde diff --git a/data/locale/ch-berndeutsch.locale b/data/locale/ch-berndeutsch.locale new file mode 100644 index 000000000..9e5b26f97 --- /dev/null +++ b/data/locale/ch-berndeutsch.locale @@ -0,0 +1,896 @@ +EPGMenu.epgplus Vorschou Ãœbersicht +EPGMenu.eventinfo Info zur Sändig +EPGMenu.eventlist Vorschou aktuells Programm +EPGMenu.head EPG - Programm Informatione +EPGMenu.streaminfo Technischi Information +EPGPlus.actions Aktione +EPGPlus.bybouquet_mode bouquetwiis +EPGPlus.bypage_mode sitewiis +EPGPlus.change_font_size Schriftgrössi ändere +EPGPlus.change_font_style Schriftstil +EPGPlus.change_size Größe ändere +EPGPlus.channelentry_font Kanäu +EPGPlus.channelentry_separationlineheight Höchi Linie zwüsche Kanäuiträg +EPGPlus.channelentry_width Breiti vo de Kanäuname +EPGPlus.channelevententry_font Sändige +EPGPlus.edit_fonts Schrifte ischtöue +EPGPlus.edit_sizes Abmässige ischtöue +EPGPlus.font_style_bold Fett +EPGPlus.font_style_italic Kursiv +EPGPlus.font_style_regular Normau +EPGPlus.footer_fontbouquetchannelname Selektierte Bouquet~/Kanauname +EPGPlus.footer_fontbuttons Buttons +EPGPlus.footer_fonteventdescription Titu 1 selekt. Sändig +EPGPlus.footer_fonteventshortdescription Titu 2 selekt. Sändig +EPGPlus.head Vorschau Ãœbersicht (EPG Plus) +EPGPlus.header_font Menütitu +EPGPlus.horgap1_height Höchi hor. Lücke 1 +EPGPlus.horgap2_height Höchi hor. Lücke 2 +EPGPlus.next_bouquet Bouquet vor +EPGPlus.options Optione +EPGPlus.page_down Site zrugg +EPGPlus.page_up Seite vor +EPGPlus.prev_bouquet Bouquet zrugg +EPGPlus.record Ufnahm +EPGPlus.refresh_epg Aktualisiere +EPGPlus.remind Vormerke +EPGPlus.reset_settings Ischtöuige zruggsetze +EPGPlus.save_settings Ischtöuige schpichere +EPGPlus.scroll_mode Scroll Mode +EPGPlus.select_font_name Schrift wähle +EPGPlus.settings Ischtöuige +EPGPlus.slider_width Breiti vom Slider +EPGPlus.stretch_mode Stretch Mode +EPGPlus.swap_mode Blättere +EPGPlus.timeline_fontdate Zytscala Datum +EPGPlus.timeline_fonttime Zytscala Zyt +EPGPlus.vergap1_width Breiti ver. Lücke 1 +EPGPlus.vergap2_width Breiti ver. Lücke 2 +EPGPlus.view_mode Modus +GENRE.ARTS.0 Kunscht / Kultur +GENRE.ARTS.1 Darschtöuendi Kunscht +GENRE.ARTS.10 Kunst-/Kultur-Magazin +GENRE.ARTS.11 Mode +GENRE.ARTS.2 Fine Arts +GENRE.ARTS.3 Religion +GENRE.ARTS.4 Voukskunscht +GENRE.ARTS.5 Literatur +GENRE.ARTS.6 Föum/Kino +GENRE.ARTS.7 Experimental Föum/Video +GENRE.ARTS.8 Rundfunk/Presse +GENRE.ARTS.9 Nöi Mediä +GENRE.CHILDRENs_PROGRAMMES.0 Chinder / Jugendprogramm +GENRE.CHILDRENs_PROGRAMMES.1 Programm für Vorschouching +GENRE.CHILDRENs_PROGRAMMES.2 Ungerhautigsprogramm für 6 bis 14-Jährigi +GENRE.CHILDRENs_PROGRAMMES.3 Ungerhautigsprogramm für 10 bis 16-Jährigi +GENRE.CHILDRENs_PROGRAMMES.4 Informations- und Böudigsprogramm +GENRE.CHILDRENs_PROGRAMMES.5 Trickföum +GENRE.DOCUS_MAGAZINES.0 Doku/Magazin +GENRE.DOCUS_MAGAZINES.1 Natur/Tiär/Umwäut +GENRE.DOCUS_MAGAZINES.2 Naturwüsseschaft und Technik +GENRE.DOCUS_MAGAZINES.3 Medizin/Psüchologie/Psychologie +GENRE.DOCUS_MAGAZINES.4 Usland/Expeditions +GENRE.DOCUS_MAGAZINES.5 Soziau- u Geischteswüsseschaft +GENRE.DOCUS_MAGAZINES.6 Witerböudig +GENRE.DOCUS_MAGAZINES.7 Schprooche +GENRE.MOVIE.0 Spöuföum / Drama +GENRE.MOVIE.1 Krimi/Thriller +GENRE.MOVIE.2 Abentürföum/Western/Chriägsföum +GENRE.MOVIE.3 Science-Fiction/Fäntäsy/Horror +GENRE.MOVIE.4 Comedy +GENRE.MOVIE.5 Soap/Melodrama/Folklore +GENRE.MOVIE.6 Romantik +GENRE.MOVIE.7 serious/classical/religious/historical movie/drama +GENRE.MOVIE.8 adult movie/Drama +GENRE.MUSIC_DANCE.0 Musik/Ballet/Tanz +GENRE.MUSIC_DANCE.1 Rock/Pop +GENRE.MUSIC_DANCE.2 serious music/Klassik +GENRE.MUSIC_DANCE.3 Vouksmusik +GENRE.MUSIC_DANCE.4 Jäzz +GENRE.MUSIC_DANCE.5 Musical/Oper +GENRE.MUSIC_DANCE.6 Ballet +GENRE.NEWS.0 Nachrichte +GENRE.NEWS.1 Nachrichte/Wätter +GENRE.NEWS.2 Nachrichtemagazin +GENRE.NEWS.3 Dokumentation +GENRE.NEWS.4 Diskussion/Interview/Debatte +GENRE.SHOW.0 Show / Gameshow +GENRE.SHOW.1 Gameshow/Quiz +GENRE.SHOW.2 varietee +GENRE.SHOW.3 Talkshow +GENRE.SOCIAL_POLITICAL.0 Sozial & Politikereigniss / Wirtschaft +GENRE.SOCIAL_POLITICAL.1 Magazin/Report/Dokumentation +GENRE.SOCIAL_POLITICAL.2 Wirtschaft u Soziales +GENRE.SOCIAL_POLITICAL.3 Bsungeri Mönsche +GENRE.SPORTS.0 Schport +GENRE.SPORTS.1 Grossereigniss (Olympischi Schpiu, Wäutmeischterschaft usw.) +GENRE.SPORTS.10 Equestrian +GENRE.SPORTS.11 Martial Sports +GENRE.SPORTS.2 Schportmagazin +GENRE.SPORTS.3 Schutte +GENRE.SPORTS.4 Tennis +GENRE.SPORTS.5 Mannschaftsschport +GENRE.SPORTS.6 Liächtathletik +GENRE.SPORTS.7 Motorschport +GENRE.SPORTS.8 Wasserschport +GENRE.SPORTS.9 Winterschport +GENRE.TRAVEL_HOBBIES.0 Reise u Freizyt +GENRE.TRAVEL_HOBBIES.1 Reisen u Tourismus +GENRE.TRAVEL_HOBBIES.2 Handicraft +GENRE.TRAVEL_HOBBIES.3 Motor +GENRE.TRAVEL_HOBBIES.4 Fitness u Gsundheit +GENRE.TRAVEL_HOBBIES.5 Chochä +GENRE.TRAVEL_HOBBIES.6 Iichouf +GENRE.TRAVEL_HOBBIES.7 Garte +GENRE.UNKNOWN Unbekannt +apids.hint_1 Gib diä z'streamende APIDs i, +apids.hint_2 trennt dür ' ' i hexadezimaler Form +apidselector.head Schproochuswau +audiomenu.PCMOffset Lutschterkisänkig PCM +audiomenu.analogout Analog-Usgang +audiomenu.avs avs +audiomenu.avs_control Volume Schtüürig avs/ost +audiomenu.dolbydigital Dolby Digital outomatisch +audiomenu.head Audio-Ischtöuige +audiomenu.lirc lirc +audiomenu.monoleft mono links +audiomenu.monoright mono rächts +audiomenu.ost ost +audiomenu.stereo stereo +audioplayer.add Dezuefüege +audioplayer.artist_title Interpret, Titu +audioplayer.building_search_index Erstöue Suechindex +audioplayer.button_select_title_by_id Sueche n. ID +audioplayer.button_select_title_by_name Sueche n. Name +audioplayer.defdir Start-Verz. +audioplayer.delete Lösche +audioplayer.deleteall Aui lösche +audioplayer.display_order Azeige +audioplayer.enable_sc_metadata Aktiviere Shoutcast Meta-Daten Parsing +audioplayer.fastforward schnäue Vorl. +audioplayer.follow Selektiere akt. Track +audioplayer.head Audio Playlist +audioplayer.highprio Höchi Decodier-Priorität +audioplayer.id3scan Scanne ID3-Tags +audioplayer.jump_backwards rückw. schpringe +audioplayer.jump_dialog_hint1 Bitte Schprungziu igä +audioplayer.jump_dialog_hint2 (relativ, i Sekunde) +audioplayer.jump_dialog_title Sprungziu igä +audioplayer.jump_forwards vorw. schpringe +audioplayer.keylevel Taschte-Umschautig +audioplayer.name Audioplayer +audioplayer.pause Pouse +audioplayer.play Abschpiele +audioplayer.playing Aktuelle Track +audioplayer.playlist_fileerror_msg Datei cha nid erschtöut wärde: +audioplayer.playlist_fileerror_title Fähler +audioplayer.playlist_fileoverwrite_msg Söu diä Datei überschriebe wärde: +audioplayer.playlist_fileoverwrite_title Ãœberschribe? +audioplayer.playlist_name Dateiname vo de Playlist +audioplayer.playlist_name_hint1 Gib de Dateiname vo de Playlist i +audioplayer.playlist_name_hint2 d'Erwiterig .m3u wird outomatisch agheicht +audioplayer.reading_files Lise d'Metadate ii +audioplayer.repeat_on Repeatmodus aktiviere +audioplayer.rewind schnäue Rückl. +audioplayer.save_playlist Playlist schpychere +audioplayer.screensaver_timeout Böudschirmschoner (min, 0=aus) +audioplayer.select_title_by_name Titusuechi noch Name (SMS) +audioplayer.show_playlist Playlist azeige +audioplayer.shuffle Shuffle +audioplayer.stop Stopp +audioplayer.title_artist Titu, Interpret +audioplayerpicsettings.general Audioplayer / Böudbetrachter +bookmarkmanager.delete Lösche +bookmarkmanager.name Bookmarks +bookmarkmanager.rename Umbenenne +bookmarkmanager.select Uswähle +bouqueteditor.add Dezuäfüäge +bouqueteditor.bouquetname Name vom Bouquet +bouqueteditor.delete Lösche +bouqueteditor.discardingchanges änderige wärde verworfe. Bitte warte ... +bouqueteditor.hide Vörschteckä +bouqueteditor.lock Schperre +bouqueteditor.move Vürschiäbe +bouqueteditor.name Bouquet-Verwautig +bouqueteditor.newbouquetname Nöiä Name vom Bouquet +bouqueteditor.rename Umbenänne +bouqueteditor.return Fertig +bouqueteditor.savechanges? Söue d'änderige gschpicheret wärde? +bouqueteditor.savingchanges änderige wärde gschpicheret. Bitte warte ... +bouqueteditor.switch Kanau ufnä/entfärne +bouqueteditor.switchmode TV/Radio +bouquetlist.head Bouquets +cablesetup.provider Kabuabiäter +channellist.head Aui Kanäu +channellist.nonefound äs si kei Kanäu gfungä wordä!\nBitte füär ä Kanausuächi dürä\n(dbox-Taschtä -> Service) +channellist.since sit %02d:%02d +colorchooser.alpha alpha +colorchooser.blue blau +colorchooser.green grüän +colorchooser.red rot +colormenu.background Hingergrundfarb +colormenu.background_head Hingergrundfarb +colormenu.fade Menüs faden +colormenu.font Schriftgrössi +colormenu.gtx_alpha Transparänz (GTX) +colormenu.head Farb-Ischtöuige +colormenu.menucolors Menüfarbe +colormenu.statusbar Schtatusbauke +colormenu.textcolor Textfarb +colormenu.textcolor_head Textfarb +colormenu.themeselect Theme uswähle +colormenu.timing OSD Timeouts +colormenusetup.head Menüfarbä +colormenusetup.menucontent Fäischterinhaut +colormenusetup.menucontent_inactive Fäischterinhaut deaktiviert +colormenusetup.menucontent_selected Fäischterinhaut selektiert +colormenusetup.menuhead Tituleischte +colorstatusbar.head Schtatusbaukä-Farb +colorstatusbar.text Schtatusbaukä +colorthememenu.classic_theme Klassik +colorthememenu.dblue_theme DarkBlue Theme +colorthememenu.dvb2k_theme DVB2000 Theme +colorthememenu.head Theme uswähle +colorthememenu.neutrino_theme Neutrino Theme +date.Apr Apr +date.Aug Aug +date.Dec Dez +date.Feb Feb +date.Fri Fr +date.Jan Jan +date.Jul Jul +date.Jun Jun +date.Mar Mär +date.May Mai +date.Mon Mo +date.Nov Nov +date.Oct Okt +date.Sat Sa +date.Sep Sep +date.Sun So +date.Thu Do +date.Tue Di +date.Wed Mi +epglist.head Vorschou - %s +epglist.noevents Kei EPG-Informationä verfüägbar. +epgviewer.More_Screenings Witäri Termin uf däm Kanau +epgviewer.nodetailed Kei usfüärlichi Informationä verfüägbar +epgviewer.notfound kei Programminformationä (EPG) gfunge +eventlistbar.channelswitch Umschaute +eventlistbar.eventsort Sortiere +eventlistbar.recordevent Ufnä +favorites.addchannel Dr aktuell Kanau wird zum Bouquet \n"Mini Favorite" däzuägfüegt. \ns'Schpichere bruucht ä Momänt... +favorites.bouquetname Mini Favorite +favorites.bqcreated Bouquet "Mini Favorite" isch aagleit worde...\n +favorites.chadded Dr aktuell Kanau isch zu dä Favoritä däzuägfüegt worde...\n +favorites.chalreadyinbq dr aktuell Kanau isch bereits i dä Favorite...\n +favorites.finalhint \nUs Versehä däzuegfüegti Kanäu chöi mit\ndr Bouquetverwautig korrigiert wärde.\n +favorites.menueadd Kanau i d'Favorite däzuefüege +favorites.nobouquets Favorite si nume mit aktivierte Bouquets müglech +filebrowser.delete Lösche +filebrowser.denydirectoryleave Startverzeichnis absolut +filebrowser.dodelete1 Söu +filebrowser.dodelete2 glöscht wärde? +filebrowser.filter.active Föuter a +filebrowser.filter.inactive Föuter us +filebrowser.head Filebrowser +filebrowser.mark Markiere +filebrowser.nextpage Site vor +filebrowser.prevpage Site zrugg +filebrowser.scan Dürsueche Verzeichnis +filebrowser.select Auswähle +filebrowser.showrights Dateirächt aazeige +filebrowser.sort.date (Datum) +filebrowser.sort.name (Dateiname) +filebrowser.sort.namedirsfirst (Dateiname2) +filebrowser.sort.size (Grössi) +filebrowser.sort.type (Typ) +filesystem.is.utf8 Dateisystem +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +flashupdate.actionreadflash lisä Flash +flashupdate.cantopenfile cha Datei nid öffnä +flashupdate.cantopenmtd cha s'MTD-Device nid öffnä +flashupdate.checkupdate noch nöiere version suäche +flashupdate.currentreleasecycle Releasezyklus +flashupdate.currentversion_sep Installierti Version +flashupdate.currentversiondate Datum +flashupdate.currentversionsnapshot ImageTyp +flashupdate.currentversiontime Uhrzyt +flashupdate.erasefailed Flash lösche fäugschlage +flashupdate.erasing lösche Flash +flashupdate.experimentalimage Du hesch ä Snapshot usgwäut, bitte beacht,\ndass diä Version nid teschtet isch u\neventuell dini Box nochem Update\nnüm funktionsfähig isch.\n\Wosch diä Version würklech installiere? +flashupdate.expertfunctions Expertä-Funktione +flashupdate.fileis0bytes d'Dateigrössi isch 0 Byte +flashupdate.fileselector Datei-Uswau +flashupdate.flashreadyreboot s'Image isch erfougrich gflasht worde.\nd'Box wird jetzt nöi gschtartet. +flashupdate.getinfofile lade Versionsinfo +flashupdate.getinfofileerror cha s'Update nid läse +flashupdate.getupdatefile lade Update +flashupdate.getupdatefileerror cha s'Update nid ladä +flashupdate.globalprogress Gsamtschtatus: +flashupdate.head Aktualisiärig +flashupdate.md5check Imageprüäfig +flashupdate.md5sumerror s'Image isch fählerhaft +flashupdate.msgbox äs isch fougendes nöis Image gfunge wordä:\nDatum: %s, %s\nBasisImage: %s\nImageTyp: %s\n\nWosch diä Version jetzt abelade\nu inschtaliäre? +flashupdate.msgbox_manual äs isch äs nöis Image gfunge worde:\nDatum: %s, %s\nBasisImage: %s\nImageTyp: %s\n\nWosch diä Version jetzt inschtalliäre? +flashupdate.mtdselector Partitions-Uswau +flashupdate.programmingflash programmierä Flash +flashupdate.proxypassword Passwort +flashupdate.proxypassword_hint1 Gib s'Proxy +flashupdate.proxypassword_hint2 Passwort i +flashupdate.proxyserver Proxyname +flashupdate.proxyserver_hint1 Gib ä Proxyname oder IP i (Host:Port) +flashupdate.proxyserver_hint2 ä läre Iitrag bedütet kei Proxy +flashupdate.proxyserver_sep Proxysörver +flashupdate.proxyusername Benutzername +flashupdate.proxyusername_hint1 Gib ä Proxy-Benutzername i +flashupdate.proxyusername_hint2 ä lääre Iitrag bedütet kei Authentifizierig +flashupdate.readflash ganzes Flashimage usläse +flashupdate.readflashmtd einzelni Partition usläse +flashupdate.ready fertig +flashupdate.reallyflashmtd Wosch dä Flashvorgang würklech düräfüere?\n\nFaus ä Fähler uftritt oder s'Image nid\nfunktionstüchtig isch, wird dini Box nüm bootä.\n\nImagename: %s\nZiel: %s +flashupdate.savesuccess s'Image isch erfougrich ungerem\nDateiname %s gschpicheret worde. +flashupdate.selectimage Verfüegbari Images +flashupdate.squashfs.noversion Bi SquashFS Updates wärde Versionsüberprüefige momentan nur bi Web-Updates ungerstützt.\nWosch s'usgewäute Image würklech installiere? +flashupdate.titlereadflash Flash usläse +flashupdate.titlewriteflash Flash schribe +flashupdate.updatemode Updatemodus +flashupdate.updatemode_internet internet +flashupdate.updatemode_manual manuell (ftp) +flashupdate.url_file Konfigfile +flashupdate.versioncheck Versionsüberprüäfig +flashupdate.writeflash ganzes Flashimage iischpile +flashupdate.writeflashmtd einzelni Partition iischpile +flashupdate.wrongbase s'Releasezyklus wiicht ab, bitte\nzersch äs nöis Komplett-Image inschtaliäre! +fontmenu.channellist Kanaulischte +fontmenu.epg EPG +fontmenu.eventlist Eventlist +fontmenu.gamelist Gamelischte +fontmenu.head Schriftgrössi Ischtöuige +fontmenu.infobar Infobar +fontsize.channel_num_zap Diräktuswau +fontsize.channellist Kanaulischte +fontsize.channellist_descr Beschribig +fontsize.channellist_number Nummer +fontsize.epg_date EPG Datum +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Titu +fontsize.eventlist_datetime Eventlist Datum / Zyt +fontsize.eventlist_itemlarge Eventlist gross +fontsize.eventlist_itemsmall Eventlist chlii +fontsize.eventlist_title Eventlist Titu +fontsize.filebrowser_item Dateibrowser-Itrag +fontsize.gamelist_itemlarge gross +fontsize.gamelist_itemsmall chlii +fontsize.hint Font wird initialisiert,\nbitte warte... +fontsize.infobar_channame Infobar Kanau +fontsize.infobar_info Infobar Info +fontsize.infobar_number Infobar Nummer +fontsize.infobar_small Infobar chlii +fontsize.menu Menütext +fontsize.menu_info Menü Info +fontsize.menu_title Menü Titu +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.epgnotload Informatione no nid glade... +infoviewer.epgwait Warte uf EPG-Informatione... +infoviewer.eventlist Programm +infoviewer.languages Tonwau +infoviewer.motor_moving Antennäpositioniärig +infoviewer.nocurrent Kei Infos zum loufende Programm +infoviewer.noepg Kei EPG-Informationä verfüegbar +infoviewer.notavailable Kanau (zur Zyt) nid verfüägbar +infoviewer.selecttime Schtartzyte +infoviewer.streaminfo Features +infoviewer.subchan_disp_pos Ungerkanauazeig +infoviewer.subservice Böudregie +infoviewer.waittime Warte uf d'Uhrzyt... +ipsetup.hint_1 Benutz 0..9 oder uäche/abä +ipsetup.hint_2 OK schpicheret, Home bricht ab +keybindingmenu.RC Färnbediänig +keybindingmenu.addrecord Ufnahm-Timer däzuäfüege +keybindingmenu.addrecord_head Ufnahm-Timer däzuäfüege +keybindingmenu.addremind Umschaut-Timer däzuäfüege +keybindingmenu.addremind_head Umschaut-Timer däzuäfüege +keybindingmenu.allchannels_on_ok Kanaulischtä +keybindingmenu.bouquetchannels_on_ok Bouquet-Kanäu +keybindingmenu.bouquetdown Bouquet zrugg +keybindingmenu.bouquetdown_head Bouquet zrugg Taschte +keybindingmenu.bouquethandling OK-Taschte für +keybindingmenu.bouquetlist_on_ok Bouquetlischtä +keybindingmenu.bouquetup Bouquet witer +keybindingmenu.bouquetup_head Bouquet witer Taschte +keybindingmenu.cancel Kanaulischtä schliässe +keybindingmenu.cancel_head Kanaulischtä schliässe +keybindingmenu.channeldown Kanau abä +keybindingmenu.channeldown_head Kanau abä Taschte +keybindingmenu.channellist Kanaulischtä +keybindingmenu.channelup Kanau uäche +keybindingmenu.channelup_head Kanau uäche Taschte +keybindingmenu.head Taschtä-Ischtöuige +keybindingmenu.lastchannel Letschte Kanau +keybindingmenu.lastchannel_head Letschte Kanau +keybindingmenu.modechange Modus wächsle +keybindingmenu.pagedown Sitä abäblettere +keybindingmenu.pagedown_head Sitä abäblettere +keybindingmenu.pageup Sitä uechäblettere +keybindingmenu.pageup_head Sitä uechäblettere +keybindingmenu.quickzap Schnäuumschautig +keybindingmenu.repeatblock Widerhouverzögerig +keybindingmenu.repeatblockgeneric Aafangsverzögerig +keybindingmenu.sort Sortierreiäfoug ändere +keybindingmenu.sort_head Sortierreiäfoug ändere +keybindingmenu.subchanneldown Ungerkanau zrugg +keybindingmenu.subchanneldown_head Ungerkanau zrugg +keybindingmenu.subchannelup Ungerkanau witer +keybindingmenu.subchannelup_head Ungerkanau witer +keybindingmenu.tvradiomode Fernseh-/Radio-Modus +keybindingmenu.tvradiomode_head Fernseh-/Radio-Modus +keybindingmenu.zaphistory Zapping-History Bouquet +keybindingmenu.zaphistory_head Zapping-History Bouquet +keychooser.head Nöii Taschte iischtöuä +keychooser.text1 Bitte Taschte drücke +keychooser.text2 Zum abbräche wartä.. +keychoosermenu.currentkey Momentani Taschte +keychoosermenu.setnew Nöii Taschte ischtöuä +keychoosermenu.setnone kei Taschte +languagesetup.head Schproochiischtöuige +languagesetup.select Schprooch +lcdcontroler.brightness normali Häuigkeit +lcdcontroler.brightnessstandby Standby Häuigkeit +lcdcontroler.contrast Kontrascht +lcdcontroler.head LCD Ischtöuigä +lcdmenu.autodimm Outomatisch dimme +lcdmenu.head LCD Ischtöuigä +lcdmenu.inverse Invertierä +lcdmenu.lcdcontroler Kontrascht / Häuigkeit +lcdmenu.power Power +lcdmenu.statusline Schtatuszilä +lcdmenu.statusline.both Lutschterchi / Fortschritt +lcdmenu.statusline.playtime Sändigsvortschritt +lcdmenu.statusline.volume Lutschterchi +mainmenu.audioplayer Audioplayer +mainmenu.games Schpili +mainmenu.head Houptmenü +mainmenu.movieplayer Movieplayer +mainmenu.pausesectionsd EPG usläse +mainmenu.pictureviewer Böudbetrachter +mainmenu.radiomode Radio-Modus +mainmenu.recording Ufnäh +mainmenu.recording_start Schtart +mainmenu.recording_stop Schtopp +mainmenu.scartmode Scart-Iigang +mainmenu.scripts Skripte +mainmenu.service Service +mainmenu.settings Ischtöuige +mainmenu.shutdown Usschaute +mainmenu.sleeptimer SleepTimer +mainmenu.tvmode TV-Modus +mainsettings.audio Audio +mainsettings.colors Farbä / Themes / Schrift +mainsettings.head Ischtöuige +mainsettings.keybinding Taschtä Ischtöuige +mainsettings.language Schprooch +mainsettings.lcd LC-Display +mainsettings.misc Diversi Ischtöuige +mainsettings.network Netzwärk +mainsettings.recording Ufnahm +mainsettings.savesettingsnow Ischtöuige jetzt schpichere +mainsettings.savesettingsnow_hint Ischtöuige wärde jetzt gschpicheret,\nbitte wartä... +mainsettings.streaming Movieplayer +mainsettings.video Video +menu.back Zrugg +messagebox.back Zrugg +messagebox.cancel Abbruch +messagebox.discard Wosch d'änderige verwärfe? +messagebox.error Fähler +messagebox.info Informatione +messagebox.no Nei +messagebox.yes Jo +miscsettings.bootinfo Infos bim Boote azeige +miscsettings.bootmenu Bootmenü azeige +miscsettings.driver_boot Triber- u Bootoptione +miscsettings.fb_destination EXPERT! Boot-Konsole +miscsettings.general Augemein +miscsettings.head Diversi Ischtöuige +miscsettings.hwsections HW-Sections verwände +miscsettings.infobar_sat_display Infobar Satelliteazeig +miscsettings.noaviawatchdog AVIA-Watchdog aktiviere +miscsettings.noenxwatchdog eNX-Watchdog aktiviere +miscsettings.pmtupdate PMT Update verwände +miscsettings.shutdown_real Standbymodus +miscsettings.shutdown_real_rcdelay Verzögerte Shutdown +miscsettings.sptsmode SPTS-Mode Triber lade +miscsettings.startbhdriver BH-Mode Triber lade +motorcontrol.head Motor-Setup +movieplayer.bookmark Bookmarks +movieplayer.bookmarkname Bookmark Name +movieplayer.bookmarkname_hint1 Gib ä Name für's nöie Bookmark i. +movieplayer.bookmarkname_hint2 +movieplayer.buffering Puffern... +movieplayer.defdir Schtart-Verz. +movieplayer.defplugin Start-Plugin +movieplayer.dvdplayback DVD +movieplayer.fileplayback Datei via VLC +movieplayer.goto Schpringe zu ... +movieplayer.goto.h1 = -> absolute Schprung +movieplayer.goto.h2 +,- -> relative Schprung +movieplayer.head Movieplayer +movieplayer.nostreamingserver Verbindig zum\nStreamingsörver fäugschlage. +movieplayer.pleasewait Bitte warte.\nd'Verbindig zum Streamingsörver wird härgschtöut. +movieplayer.toomanybookmarks Du hesch scho zviu Bookmarks aagleit.\nEs muess zersch äs Angers glöscht wärde. +movieplayer.tshelp1 Stop +movieplayer.tshelp10 ca. 10 Minute zrugg +movieplayer.tshelp11 ca. 10 Minute vor +movieplayer.tshelp12 Höuf: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Uswau vo de Tonspur +movieplayer.tshelp3 Pouse/Witer +movieplayer.tshelp4 Bookmark setze +movieplayer.tshelp5 Zyt iblände +movieplayer.tshelp6 ca. 1 Minute zrugg +movieplayer.tshelp7 ca. 1 Minute vor +movieplayer.tshelp8 ca. 5 Minute zrugg +movieplayer.tshelp9 ca. 5 Minute vor +movieplayer.tsplayback TS Abschpile +movieplayer.tsplayback_pc TS Abschpiele mit PIN +movieplayer.vcdplayback (S)VCD +movieplayer.vlchelp1 Stop +movieplayer.vlchelp10 ca. 10 Minute zrugg +movieplayer.vlchelp11 ca. 10 Minuten vor +movieplayer.vlchelp12 Höuf: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Resync +movieplayer.vlchelp3 Pouse/Witer +movieplayer.vlchelp4 Bookmark setze +movieplayer.vlchelp5 Zyt iblände +movieplayer.vlchelp6 ca. 1 Minute zrugg +movieplayer.vlchelp7 ca. 1 Minute vor +movieplayer.vlchelp8 ca. 5 Minute zrugg +movieplayer.vlchelp9 ca. 5 Minute vor +movieplayer.wrongvlcversion Funktion isch mit dere Version vom VLC nid müglech +networkmenu.broadcast Broadcast +networkmenu.dhcp DHCP +networkmenu.gateway Schtandard Gateway +networkmenu.head Netzwärk Ischtöuige +networkmenu.ipaddress IP-Adrässi +networkmenu.mount NFS/CIFS +networkmenu.nameserver Namesörver +networkmenu.netmask Netzmaske +networkmenu.setupnow Netzwärkischtöuigä jetzt zuäwise +networkmenu.setuponstartup Bim schtartä Netzwärk setze +networkmenu.show aktivi Netzwärkischtöuigä zeigä +networkmenu.test Netzwärk teschte +nfs.alreadymounted Verzeichnis bereits gemountet +nfs.automount Bim Schtart mounte +nfs.dir NFS/CIFS Verzeichnis +nfs.ip NFS/CIFS Sörver IP +nfs.localdir lokaus Verzeichnis +nfs.mount NFS/CIFS Verzeichnis mounte +nfs.mount_options Mount-Optione +nfs.mounterror Mount-Fähler +nfs.mounterror_notsup Dateisystem-Typ wird nid ungerstützt +nfs.mountnow Jetz mounte +nfs.mountok Mount erfougriich +nfs.mounttimeout Mount-Fehler: Timeout +nfs.password CIFS Passwort +nfs.remount Verzeichnisse erneut mounte +nfs.type Typ +nfs.type_cifs CIFS +nfs.type_lufs FTPFS +nfs.type_nfs NFS +nfs.umount NFS/CIFS Verzeichnis unmounte +nfs.umounterror Umount-Fähler +nfs.username CIFS Benutzername +nfsmenu.head NFS/CIFS/FTPFS Ischtöuige +nvod.percentage (%d%% verbi) +nvod.starting (Beginn i %d min) +nvodselector.directormode Böudregie-Modus +nvodselector.head Aafangszyt uswähle +nvodselector.subservice Perschpektivä +options.default Vorischtöuige bruuchä +options.fb framebuffer +options.null nou +options.off aus +options.on ein +options.serial seriell +parentallock.changepin PIN-Code feschtlege +parentallock.changepin_hint1 Gib do dä nöi PIN-Code i! +parentallock.changetolocked Bi vorgschperrte Bouquets +parentallock.head Jugendschutz PIN +parentallock.lockage Sändige +parentallock.lockage12 ab 12 Johr sperre +parentallock.lockage16 ab 16 Johr sperre +parentallock.lockage18 ab 18 Johr sperre +parentallock.lockedchannel Vorgschperrte Sänder... +parentallock.lockedprogram Gschperrts Programm (FSK ab %d) +parentallock.never Niä +parentallock.onsignal Bi gsändeter Vorschperri +parentallock.parentallock Jugendschutz +parentallock.prompt PIN-Igab +pictureviewer.decode_server_ip Decoding-Server IP +pictureviewer.decode_server_port Decoding-Server Port +pictureviewer.defdir Schtart-Verz. +pictureviewer.head Böudbetrachter +pictureviewer.help1 Menü-Modus +pictureviewer.help10 Anzeige-Modus +pictureviewer.help11 Böud nöi iläse +pictureviewer.help12 vorhäriges Böud +pictureviewer.help13 nöchscht's Böud +pictureviewer.help14 Zoom out +pictureviewer.help15 Zoom in +pictureviewer.help16 Scroll obsi +pictureviewer.help17 Scroll links +pictureviewer.help18 Scroll rächts +pictureviewer.help19 Scroll nidsi +pictureviewer.help2 Böud azeige +pictureviewer.help20 Sortierig ändere +pictureviewer.help21 Bild unskaliert iläse +pictureviewer.help22 Modus verloh +pictureviewer.help3 Sortierig ändere +pictureviewer.help4 Böud unskaliert iläse +pictureviewer.help5 Diashow-Modus +pictureviewer.help6 vorhärigs Böud +pictureviewer.help7 nöchscht's Böud +pictureviewer.help8 Sortierig ändere +pictureviewer.help9 Modus verloh +pictureviewer.resize.color_average Ufwändig +pictureviewer.resize.none Keni +pictureviewer.resize.simple Eifach +pictureviewer.scaling Skalierig +pictureviewer.show Azeige +pictureviewer.slide_time Diaschou-Azeigduur +pictureviewer.slideshow Diaschou +pictureviewer.sortorder Sort.reiäfoug ändere +pictureviewer.sortorder.date (Datum) +pictureviewer.sortorder.filename (Dateiname) +ping.ok isch erreichbar (ping) +ping.protocol isch nid erreichbar (Host or protocol error) +ping.socket isch nid erreichbar (Socket error) +ping.unreachable isch nid erreichbar (unreachable) +pinprotection.head PIN-Abfroog +pinprotection.wrongcode Gib dä Code nomou i! +plugins.result Pluginusgab +rclock.lockmsg d'Färnbedienig vo de DBOX2 wird gschperrt.\num d'Schperri ufzhebe, bitte\n u uf dr Färnbedienig\ndruecke. +rclock.menueadd FB schperre +rclock.title Färnbedienig schperre +rclock.unlockmsg Färnbedienig reaktiviert... +recordingmenu.choose_direct_rec_dir Bi Sofortufn. Verzeichnisuswau +recordingmenu.defdir Ufnahmeverzeichnis +recordingmenu.epg_for_filename langi Dateiname (mit EPG-Date) +recordingmenu.file Diräkt (Datei) +recordingmenu.filesettingsseparator Diräktufnahm +recordingmenu.head Ufnahm Ischtöuige +recordingmenu.help Aufnahmegeräte:\n-----------------------\nServer:\nuf PC mit Höuf vomene Streaming-Programm\n\n(analoge) Videorekorder:\nüber VCR-Usgang\n\nDiräkt (Datei):\nuf es per NFS gemountetes Verzeichnis\noder ä interni Feschtplatte\nTS: SPTS-Mode Triber lade\nPES: SPTS-Mode Triber nid lade\n\n\nMaximali Dateigrössi:\n----------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: fasch unändlech (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart Ungerdrücke Scart-Umschautig +recordingmenu.off aus +recordingmenu.recording_type Ufnahme Grät +recordingmenu.ringbuffers Anz. Ringpuffer +recordingmenu.server Sörver +recordingmenu.server_ip Ufnahmesörver IP +recordingmenu.server_mac Mac Adrässi +recordingmenu.server_port Ufnahmesörver Port +recordingmenu.server_wakeup Ufnahmäsörver WOL +recordingmenu.setupnow Ischtöuigä jetzt übernää +recordingmenu.splitsize Max. Dateigrössi (MB) +recordingmenu.stopplayback Playbäck aahaute +recordingmenu.stopsectionsd Sectionsd aahaute +recordingmenu.stream_all_audio_pids Aui Audiopids ufzeichne +recordingmenu.stream_vtxt_pid Videotext ufzeichne +recordingmenu.use_fdatasync Synchrones Schribe (fdatasync) +recordingmenu.use_o_sync Synchrones Schribe (O_SYNC) +recordingmenu.vcr Videorekorder +recordtimer.announce d'Ufnahm beginnt i wenige Minute +repeatblocker.hint_1 Mindeschtzyt (in ms) zwüschä 2 Taschtädrück +repeatblocker.hint_2 0 schautet dä Blocker us (Rot isch " ") +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-Widerholige +satsetup.extended DiSEqC-Ischtöuige +satsetup.extended_motor Motor-Ischtöuige +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Manuells Motor-Setup +satsetup.nodiseqc Keis DiSEqC +satsetup.satellite Satellit +satsetup.savesettingsnow Ischtöuigä jetzt schpichere +satsetup.smatvremote SMATV Remote Tuning +scantp.abort_scan Breche Scan ab +scantp.fec FEC +scantp.fec_1_2 1/2 +scantp.fec_2_3 2/3 +scantp.fec_3_4 3/4 +scantp.fec_5_6 5/6 +scantp.fec_7_8 7/8 +scantp.freq Frequänz +scantp.pol Polarisation +scantp.pol_h H +scantp.pol_v V +scantp.rate Symbol rate +scantp.scan Manual Scan +scantp.scanmode Schnäu Scan +scants.actcable Kabu: +scants.actsatellite Satellit: +scants.bouquet Bouquets +scants.bouquet_create nöi erschtöuä +scants.bouquet_erase lösche +scants.bouquet_leave nid ändere +scants.bouquet_satellite Satelliten-Bouquet +scants.bouquet_update erneuere +scants.channel Kanau: +scants.failed Kanausuächi fäugschlage! +scants.finished Kanausuächi erfougrich beändet! +scants.freqdata Frequänz: +scants.head Kanausuächi +scants.numberofdataservices Data +scants.numberofradioservices Radio +scants.numberoftotalservices Gsamt +scants.numberoftvservices TV +scants.provider Aabieter: +scants.startnow Kanausuächi schtartä +scants.transponders Transponder: +screensetup.lowerright grün = Böudrand ungä, rächts +screensetup.upperleft rot = Böudrand obä, links +servicemenu.head Service +servicemenu.reload Kanaulischtä nöi lade +servicemenu.reload_hint Kanaulischtä wärde nöi glade,\nbitte wartä... +servicemenu.scants Kanausuächi +servicemenu.ucodecheck UCodes überprüäfe +servicemenu.update Software-Aktualisierig +settings.help Höuf +settings.missingoptionsconffile d'Neutrino-Ischtöuige si erwitert worde.\nDi nöiä Wärt wärde uf Standart gsetzt. +settings.noconffile d'Neutrino Ischtöuige si nid gfungä\nworde. äs wärde d'Standartwärt bruucht. +settings.pos_bottom_left unge links +settings.pos_bottom_right unge rächts +settings.pos_top_left obe links +settings.pos_top_right obe rächts +shutdowntimer.announce d'Box wird i einer Minute abägfahre.\nShutdown abbräche? +sleeptimerbox.announce Sleeptimer i 1 min +sleeptimerbox.hint1 Usschautzyt i Min. (000=aus) +sleeptimerbox.hint2 d'Box schautet sich noch derä Zyt uus. +sleeptimerbox.title Sleeptimer +streamfeatures.head Features +streaminfo.aratio Verhäutnis +streaminfo.aratio_unknown Verhäutnis: unbekannt +streaminfo.audiotype Audiotyp +streaminfo.audiotype_unknown Audiotyp: unbekannt +streaminfo.bitrate Bitrate +streaminfo.framerate Böudrate +streaminfo.framerate_unknown Böudrate: unbekannt +streaminfo.head Informatione +streaminfo.not_available nid verfüegbar +streaminfo.resolution Uflösig +streaminfo.signal Empfangssignau +streaming.buffer_overflow d'Ufnahm isch leider abbroche,\ndo d'Date nid schnäu gnue gschribe hei chöne wärde. +streaming.busy Eine oder mehreri Aufnahmprozäss si aktiv.\nSöt d'Ufnahm eigentlech beändet si,\nschafft ä Neustart vo Neutrino Abhiuf. +streaming.dir_not_writable s'Ufnahmeverzeichnis isch ni beschribbar.\ns'Ufnä isch wäg däm nid müglech. +streaming.success d'Ufnahm isch erfougrich beändet worde. +streaming.write_error d'Ufnahme isch leider abbroche,\ndo ä Fähler bim Schribe vo de Date ufträte isch. +streaming.write_error_open d'Ufnahm isch leider abbroche,\ndo diä entsprächend Datei nid zum Schribe g'öffnet cha wärde. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Movieplayer Iischtöue +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Deaktiviert +streamingmenu.on Aktiviert +streamingmenu.server_ip Streamingsörver IP +streamingmenu.server_port Streamingsörver Port +streamingmenu.streaming_audiorate Daterate Audio +streamingmenu.streaming_force_avi_rawaudio Erzwinge AC3 bei avi +streamingmenu.streaming_force_transcode_video Transcod. ou bi mpg/vcd Video +streamingmenu.streaming_resolution Uflösig +streamingmenu.streaming_server_cddrive DVD Loufwärk +streamingmenu.streaming_server_startdir Verzeichnis (VLC) +streamingmenu.streaming_transcode_audio Transcod. Audio (dvd/vcd/mpg) +streamingmenu.streaming_transcode_video_codec MPEG Video Codec +streamingmenu.streaming_type Streamingsörver +streamingmenu.streaming_videorate Daterate Video +streamingserver.noconnect Kei verbindig zum Streamingsörver.\nd'Ufnahm wird abbroche. +stringinput.caps Gross-/Chlibuächschtabe +stringinput.clear Aues lösche +timer.eventrecord.msg d'Sändig isch zur Ufnahm vorgmerkt worde +timer.eventrecord.title Ufnahm vormerke +timer.eventtimed.msg d'Sändig isch vorgmerkt +timer.eventtimed.title Sändig vormerke +timerbar.channelswitch Umschaute +timerbar.recordevent Ufnä +timerlist.alarmtime Alarmzyt +timerlist.apids Audio PIDs +timerlist.bouquetselect Bouquet wähle +timerlist.channel Kanau +timerlist.channelselect Kanau wähle +timerlist.delete Lösche +timerlist.menumodify Timer bearbeite +timerlist.menunew Nöie Timer +timerlist.message Nachricht +timerlist.moderadio Radio Kanäu +timerlist.modeselect Modus-Uswau +timerlist.modetv TV Kanäu +timerlist.modify Bearbeite +timerlist.name Timerlischte +timerlist.new Neuer Timer +timerlist.plugin Plugin +timerlist.program.unknown Programm unbekannt +timerlist.recording_dir Ufnahmeverzeichnis +timerlist.reload Aktualisiere +timerlist.repeat Widerholige +timerlist.repeat.biweekly 2-wöchentlech +timerlist.repeat.byeventdescription siehe timer +timerlist.repeat.daily täglech +timerlist.repeat.fourweekly 4-wöchentlech +timerlist.repeat.friday Fr +timerlist.repeat.monday Mo +timerlist.repeat.monthly monetlech +timerlist.repeat.once eimalig +timerlist.repeat.saturday Sa +timerlist.repeat.sunday So +timerlist.repeat.thursday Do +timerlist.repeat.tuesday Di +timerlist.repeat.unknown unbekannt +timerlist.repeat.wednesday Mi +timerlist.repeat.weekdays A Wochetäg +timerlist.repeat.weekly wöchentlech +timerlist.repeatcount Wiederholige +timerlist.repeatcount.help1 Azau vo de Timerusfüehrige +timerlist.repeatcount.help2 0 für unbegränzti Azau +timerlist.save Timer spichere +timerlist.standby SB Modus +timerlist.standby.off Ufwache us Standby +timerlist.standby.on Uf Standby go +timerlist.stoptime Schtoppzyt +timerlist.type Timertyp +timerlist.type.execplugin Plugin usführe +timerlist.type.nextprogram Nöchschts Programm +timerlist.type.record Ufnahm +timerlist.type.remind Erinnerig +timerlist.type.shutdown Shutdown +timerlist.type.sleeptimer Sleeptimer +timerlist.type.standby Standby +timerlist.type.unknown Unbekannt +timerlist.type.zapto Umschaute +timerlist.weekdays Wochetäg +timerlist.weekdays.hint_1 Mo Di Mi Do Fr Sa So +timerlist.weekdays.hint_2 'X'=Timer '-' kei Timer +timersettings.record_safety_time_after Ufnahmeändi-Korrektur +timersettings.record_safety_time_after.hint_1 Korrekturzyt i Min. (00=us), diä uf d'änd- +timersettings.record_safety_time_after.hint_2 zyt vom jewilige Timer addiärt wird +timersettings.record_safety_time_before Ufnahmeschtart-Korrektur +timersettings.record_safety_time_before.hint_1 Korrekturzyt i Min. (00=us), diä bim Schtart +timersettings.record_safety_time_before.hint_2 vom jewilige Timer abzoge wärde +timersettings.separator Timerischtöuige +timing.chanlist Kanaulischtä +timing.epg EPG +timing.filebrowser Filebrowser +timing.head OSD Timeouts +timing.hint_1 Ibländzyt i Sek., wiä lang s'OSD +timing.hint_2 uf äm TV aazeiget wird +timing.infobar Infobar +timing.menu Menü +timing.numericzap Umschaute mit Ziffertaschte +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head UCode überprüäfig +ucodecheck.ucode UCode +ucodes.failure Achtung, d'µCodes si NID gfunge worde!\n\nBitte per FTP (oder DBox-BootManager)\nuploade, u d'Box nöi schtarte! +videomenu.csync Sync.-Korrektur +videomenu.head Video-Ischtöuige +videomenu.rgb_centering RGB-Zentrierig +videomenu.screensetup Böudbereich ischtöue +videomenu.vcrswitch Scart-Iigang outomatisch +videomenu.videoformat Böudschirmformat +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect outomatisch +videomenu.videosignal Video Signauart +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce I einer Minute wird umgschautet diff --git a/data/locale/check.locale.files b/data/locale/check.locale.files new file mode 100755 index 000000000..ef63e8cfd --- /dev/null +++ b/data/locale/check.locale.files @@ -0,0 +1,9 @@ +#!/bin/sh +cut -d' ' -f1 deutsch.locale | sort | uniq > /tmp/log +for i in *.locale; do \ + echo $i:; \ + echo "----------------"; \ + cut -d' ' -f1 $i | diff -u - /tmp/log; \ + echo; \ +done +rm /tmp/log diff --git a/data/locale/create-locals-update.pl b/data/locale/create-locals-update.pl new file mode 100755 index 000000000..7abc7aaad --- /dev/null +++ b/data/locale/create-locals-update.pl @@ -0,0 +1,50 @@ +#! /usr/bin/perl + +# This proggie takes a (possibly outdated) locale file as its (only) +# argument, and creates a new version, with `-work` appended. The thus +# created tile contains all keys of the master file, and is intended +# to, after manual editing, replace the outdated locale file. + +# Written by Barf on 2005-12-10. + +$masterfilename = "deutsch.locale"; + +$#ARGV == 0 || die("Usage: create-locals-update.pl file.locale."); + +$no_errors = 0; +$last_was_ok = 1; +$localefilename = @ARGV[0]; +$outfilename = $localefilename . "-work"; + +open(masterfile, $masterfilename) || die("Could not open master file"); +open(localefile, $localefilename) || die("Could not open locale file"); +open(outfile, ">" . $outfilename) || die("Could not open output file"); + +while () { + $masterline = $_; + ($masterkey) = /([^ ]+)/; + ($junk, $mastertext) = /([^ ]+)[ ]+([^\n]+)/; + if ($last_was_ok) { + $localeline = ; + chop $localeline; + ($localekey) = ($localeline =~ /([^ ]+)/,$localline); + ($junk, $localetext) = ($localeline =~ /([^ ]+)[ ]+([^\n]+)/); + }; + if ($masterkey eq $localekey) { + print outfile $localeline, "\n"; + $last_was_ok = 1; + } else { + $no_errors++; + #print "|", $masterkey, "|", $mastertext, "|", $localekey, "|", $localetext, "|\n"; + print outfile $masterkey, " TRANSLATE ", $mastertext, "\n"; + $last_was_ok = 0; + } +} + +close(outfile); + +print "There were ", $no_errors, " error(s).\n"; + +if ($no_errors == 0) { + unlink($outfilename); +} diff --git a/data/locale/create.locals.h b/data/locale/create.locals.h new file mode 100755 index 000000000..6f0bbb788 --- /dev/null +++ b/data/locale/create.locals.h @@ -0,0 +1,43 @@ +#!/bin/bash +# usage: cut -d' ' -f1 deutsch.locale | LC_ALL=C sort | uniq | tr [:lower:] [:upper:] | tr \. \_ | tr \- \_ | tr -d \? | ./create.locals.h +cat > locals.h < + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +typedef enum +{ + NONEXISTANT_LOCALE, +EOF +while read id; do + if [[ \ + "$id" != "CAM_WRONG" \ + ]] ; + then + echo $'\t'"LOCALE_$id," >> locals.h; + fi +done +cat >> locals.h < locals_intern.h < + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +const char * locale_real_names[] = +{ + "INTERNAL ERROR - PLEASE REPORT", +EOF +while read id; do + if [[ \ + "$id" != "cam.wrong" \ + ]] ; + then + echo $'\t'"\"$id\"," >> locals_intern.h; + fi +done +cat >> locals_intern.h < Service) +channellist.since seit %02d:%02d +channellist.start ab %02d:%02d +colorchooser.alpha alpha +colorchooser.blue blau +colorchooser.green grün +colorchooser.red rot +colormenu.background Hintergrundfarbe +colormenu.fade Menüs faden +colormenu.font Schriftgröße +colormenu.gtx_alpha Transparenz (GTX) +colormenu.head Farb-Einstellungen +colormenu.menucolors Menüfarben +colormenu.statusbar Statusbalken +colormenu.textcolor Textfarbe +colormenu.themeselect Theme auswählen +colormenu.timing OSD Timeouts +colormenusetup.head Menüfarben +colormenusetup.menucontent Fensterinhalt +colormenusetup.menucontent_inactive Fensterinhalt deaktiviert +colormenusetup.menucontent_selected Fensterinhalt selektiert +colormenusetup.menuhead Titelleiste +colorstatusbar.head Statusbalken-Farben +colorstatusbar.text Statusbalken +colorthememenu.classic_theme Klassik +colorthememenu.dblue_theme DarkBlue Theme +colorthememenu.dvb2k_theme DVB2000 Theme +colorthememenu.head Theme auswählen +colorthememenu.neutrino_theme Neutrino Theme +date.Apr Apr +date.Aug Aug +date.Dec Dez +date.Feb Feb +date.Fri Fr +date.Jan Jan +date.Jul Jul +date.Jun Jun +date.Mar Mär +date.May Mai +date.Mon Mo +date.Nov Nov +date.Oct Okt +date.Sat Sa +date.Sep Sep +date.Sun So +date.Thu Do +date.Tue Di +date.Wed Mi +epglist.head Vorschau - %s +epglist.noevents Keine EPG-Information verfügbar. +epgviewer.More_Screenings Weitere Termine auf diesem Kanal +epgviewer.nodetailed Keine ausführlichen Informationen verfügbar +epgviewer.notfound keine Programminformationen (EPG) gefunden +eventlistbar.channelswitch Umschalten +eventlistbar.eventsort Sortieren +eventlistbar.recordevent Aufnehmen +favorites.addchannel Der aktuelle Kanal wird dem Bouquet \n"Meine Favoriten" hinzugefügt. \nDie Speicherung benötigt einen Moment... +favorites.bouquetname Meine Favoriten +favorites.bqcreated Bouquet "Meine Favoriten" wurde angelegt...\n +favorites.chadded Der aktuelle Kanal wurde Ihren Favoriten hinzugefügt...\n +favorites.chalreadyinbq Der aktuelle Kanal ist bereits in Ihren Favoriten...\n +favorites.finalhint \nVersehentlich hinzugefügte Kanäle können mit\nder Bouquetverwaltung korrigiert werden.\n +favorites.menueadd Kanal Favoriten hinzufügen +favorites.nobouquets Favoriten sind nur mit aktivierten Bouquets möglich. +filebrowser.delete Löschen +filebrowser.denydirectoryleave Startverzeichnis absolut +filebrowser.dodelete1 Soll +filebrowser.dodelete2 gelöscht werden ? +filebrowser.filter.active Filter an +filebrowser.filter.inactive Filter aus +filebrowser.head Filebrowser +filebrowser.mark Markieren +filebrowser.nextpage Seite vor +filebrowser.prevpage Seite zurück +filebrowser.scan Durchsuche Verzeichnisse +filebrowser.select Auswählen +filebrowser.showrights Dateirechte anzeigen +filebrowser.sort.date (Datum) +filebrowser.sort.name (Dateiname) +filebrowser.sort.namedirsfirst (Dateiname2) +filebrowser.sort.size (Größe) +filebrowser.sort.type (Typ) +filesystem.is.utf8 Dateisystem +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +flashupdate.actionreadflash lese Flash +flashupdate.cantopenfile kann Datei nicht öffnen +flashupdate.cantopenmtd kann das MTD-Device nicht öffnen +flashupdate.checkupdate nach neuer Version suchen +flashupdate.currentreleasecycle Releasezyklus +flashupdate.currentversion_sep Installierte Version +flashupdate.currentversiondate Datum +flashupdate.currentversionsnapshot ImageTyp +flashupdate.currentversiontime Uhrzeit +flashupdate.erasefailed Flash löschen fehlgeschlagen +flashupdate.erasing lösche Flash +flashupdate.experimentalimage Sie haben einen Snapshot ausgewählt, bitte beachten Sie,\ndass diese Version ungetestet ist und u.U. Ihre Box\nnach dem Update nicht mehr funktionsfähig ist.\n\nSoll diese Version wirklich installiert werden? +flashupdate.expertfunctions Experten-Funktionen +flashupdate.fileis0bytes die Dateigröße ist 0 Byte +flashupdate.fileselector Datei-Auswahl +flashupdate.flashreadyreboot Das Image wurde erfolgreich geflasht.\nIhre Box wird jetzt neu gestartet. +flashupdate.getinfofile lade Versioninfo +flashupdate.getinfofileerror kann Info nicht laden +flashupdate.getupdatefile lade Update +flashupdate.getupdatefileerror kann Update nicht laden +flashupdate.globalprogress Gesamtstatus: +flashupdate.head Aktualisierung +flashupdate.md5check Imageprüfung +flashupdate.md5sumerror Das Image ist fehlerhaft +flashupdate.msgbox Es wurde folgendes neues file gefunden:\nDatum: %s, %s\nBasisImage: %s\nTyp: %s\n\nWollen Sie diese Version jetzt herunterladen\nund installieren? +flashupdate.msgbox_manual Es wurde ein neues Image gefunden:\nDatum: %s, %s\nBasisImage: %s\nImageTyp: %s\n\nWollen Sie diese Version jetzt installieren? +flashupdate.mtdselector Partitions-Auswahl +flashupdate.programmingflash programmiere Flash +flashupdate.proxypassword Passwort +flashupdate.proxypassword_hint1 Geben sie das Proxy-Passwort ein +flashupdate.proxypassword_hint2 Ein leerer Eintrag bedeutet keine Authentifizierung +flashupdate.proxyserver Proxyname +flashupdate.proxyserver_hint1 Geben Sie den Proxynamen oder IP ein (Host:Port) +flashupdate.proxyserver_hint2 Ein leerer Eintrag bedeutet kein Proxy +flashupdate.proxyserver_sep Proxyserver +flashupdate.proxyusername Benutzername +flashupdate.proxyusername_hint1 Geben Sie den Proxy-Benutzernamen ein +flashupdate.proxyusername_hint2 Ein leerer Eintrag bedeutet keine Authentifizierung +flashupdate.readflash ganzes Flashimage auslesen +flashupdate.readflashmtd einzelne Partition auslesen +flashupdate.ready fertig +flashupdate.reallyflashmtd Wollen Sie den Flashvorgang wirklich durchführen?\n\nFalls ein Fehler auftritt oder das Image nicht\nfunktionfähig ist, wird Ihre box nicht mehr booten.\n\nImagename: %s\nZiel: %s +flashupdate.savesuccess Das Image wurde erfolgreich unter dem\nDateinamen %s gespeichert. +flashupdate.selectimage Verfügbare Images/Files +flashupdate.squashfs.noversion Bei SquashFS Updates werden Versionsüberprüfungen derzeit nur bei Web-Updates unterstützt.\nWollen Sie das ausgewählt Image wirklich installieren? +flashupdate.titlereadflash Flash auslesen +flashupdate.titlewriteflash Flash schreiben +flashupdate.updatemode Updatemodus +flashupdate.updatemode_internet internet +flashupdate.updatemode_manual manuell (ftp) +flashupdate.url_file Konfigfile +flashupdate.versioncheck Versionsüberprüfung +flashupdate.writeflash ganzes Flashimage einspielen +flashupdate.writeflashmtd einzelne Partition einspielen +flashupdate.wrongbase Abweichende release Info\nFortfahren? +fontmenu.channellist Kanalliste +fontmenu.epg EPG +fontmenu.eventlist Eventlist +fontmenu.gamelist Gameliste +fontmenu.head Schriftgrössen Einstellungen +fontmenu.infobar Infobar +fontsize.channel_num_zap Direktauswahl +fontsize.channellist Kanalliste +fontsize.channellist_descr Beschreibung +fontsize.channellist_number Nummer +fontsize.epg_date EPG Datum +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Titel +fontsize.eventlist_datetime Eventlist Datum / Zeit +fontsize.eventlist_itemlarge Eventlist groß +fontsize.eventlist_itemsmall Eventlist klein +fontsize.eventlist_title Eventlist Titel +fontsize.filebrowser_item Dateibrowser-Eintrag +fontsize.gamelist_itemlarge groß +fontsize.gamelist_itemsmall klein +fontsize.hint Font wird initialisiert,\nbitte warten... +fontsize.infobar_channame Infobar Kanal +fontsize.infobar_info Infobar Info +fontsize.infobar_number Infobar Nummer +fontsize.infobar_small Infobar klein +fontsize.menu Menutext +fontsize.menu_info Menu Info +fontsize.menu_title Menu Titel +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.epgnotload Informationen noch nicht geladen... +infoviewer.epgwait Warte auf EPG-Informationen... +infoviewer.eventlist EPG/Vorschau +infoviewer.languages Tonwahl +infoviewer.motor_moving Antennenpositionierung +infoviewer.next später +infoviewer.nocurrent Keine Info zu laufendem Programm +infoviewer.noepg Keine EPG-Information verfügbar +infoviewer.notavailable Kanal (zur Zeit) nicht verfügbar. +infoviewer.now jetzt +infoviewer.selecttime Startzeiten +infoviewer.streaminfo Features +infoviewer.subchan_disp_pos Unterkanalanzeige +infoviewer.subservice Bildregie +infoviewer.waittime Warte auf Uhrzeit... +ipsetup.hint_1 Benutzen Sie 0..9 oder hoch/runter +ipsetup.hint_2 OK speichert, LAME! bricht ab +keybindingmenu.RC Fernbedienung +keybindingmenu.addrecord Aufnahme-Timer hinzufügen +keybindingmenu.addremind Umschalt-Timer hinzufügen +keybindingmenu.allchannels_on_ok Kanalliste +keybindingmenu.bouquetchannels_on_ok Bouquet-Kanäle +keybindingmenu.bouquetdown Bouquet zurück +keybindingmenu.bouquethandling OK-Taste für +keybindingmenu.bouquetlist_on_ok Bouquetliste +keybindingmenu.bouquetup Bouquet weiter +keybindingmenu.cancel Kanalliste schließen +keybindingmenu.channeldown Kanal runter +keybindingmenu.channellist Kanalliste +keybindingmenu.channelup Kanal hoch +keybindingmenu.head Tasten-Einstellungen +keybindingmenu.lastchannel Letzter Kanal +keybindingmenu.modechange Modus wechsel +keybindingmenu.pagedown Seite runterblättern +keybindingmenu.pageup Seite hochblättern +keybindingmenu.quickzap Schnellumschaltung +keybindingmenu.repeatblock Wiederholungsverzögerung +keybindingmenu.repeatblockgeneric Anfangsverzögerung +keybindingmenu.sort Sortierreihenfolge ändern +keybindingmenu.subchanneldown Unterkanal zurück +keybindingmenu.subchannelup Unterkanal weiter +keybindingmenu.tvradiomode Fernseh-/Radio-Modus +keybindingmenu.zaphistory Zapping-History Bouquet +keychooser.head Neue Taste einstellen +keychooser.text1 Bitte Taste drücken +keychooser.text2 Zum Abbrechen warten.. +keychoosermenu.currentkey Derzeitige Taste +keychoosermenu.setnew Neue Taste einstellen +keychoosermenu.setnone Keine Taste +languagesetup.head Spracheinstellungen +languagesetup.select Sprache +lcdcontroler.brightness normale Helligkeit +lcdcontroler.brightnessstandby Standby Helligkeit +lcdcontroler.contrast Kontrast +lcdcontroler.head VFD Einstellungen +lcdmenu.autodimm Automatisch dimmen +lcdmenu.head VFD Einstellungen +lcdmenu.inverse Invertieren +lcdmenu.lcdcontroler Kontrast / Helligkeit +lcdmenu.power Power +lcdmenu.statusline Statuszeile +lcdmenu.statusline.both Lautstärke / Fortschritt +lcdmenu.statusline.playtime Sendungsfortschritt +lcdmenu.statusline.volume Lautstärke +mainmenu.audioplayer Audioplayer +mainmenu.games Spiele +mainmenu.head Hauptmenü +mainmenu.movieplayer Movieplayer +mainmenu.pausesectionsd EPG auslesen +mainmenu.pictureviewer Bildbetrachter +mainmenu.radiomode Radio-Modus +mainmenu.reboot Neustart +mainmenu.recording Aufnehmen +mainmenu.recording_start Start +mainmenu.recording_stop Stopp +mainmenu.scartmode Scart-Eingang +mainmenu.scripts Skripte +mainmenu.service Service +mainmenu.settings Einstellungen +mainmenu.shutdown Ausschalten +mainmenu.sleeptimer SleepTimer +mainmenu.tvmode TV-Modus +mainsettings.audio Audio +mainsettings.osd OSD Einstellungen +mainsettings.colors Farben / Themes / Schrift +mainsettings.head Einstellungen +mainsettings.keybinding Tasten Einstellungen +mainsettings.language Sprache +mainsettings.lcd VFD-Display +mainsettings.misc Diverse Einstellungen +mainsettings.network Netzwerk +mainsettings.recording Aufnahme +mainsettings.savesettingsnow Einstellungen jetzt speichern +mainsettings.savesettingsnow_hint Einstellungen werden jetzt gespeichert,\nbitte warten... +mainsettings.streaming Movieplayer +mainsettings.video Video +menu.back Zurück +messagebox.back Zurück +messagebox.cancel Abbruch +messagebox.discard Wollen Sie die Änderungen verwerfen? +messagebox.error Fehler +messagebox.info Information +messagebox.no Nein +messagebox.yes Ja +miscsettings.bootinfo Infos beim Booten anzeigen +miscsettings.bootmenu Bootmenü anzeigen +miscsettings.driver_boot Treiber- und Bootoptionen +miscsettings.fb_destination EXPERT! Boot-Konsole +miscsettings.general Allgemein +miscsettings.head Diverse Einstellungen +miscsettings.hwsections HW-Sections verwenden +miscsettings.infobar_sat_display Infobar Satellitenanzeige +miscsettings.noaviawatchdog AVIA-Watchdog aktivieren +miscsettings.noenxwatchdog eNX-Watchdog aktivieren +miscsettings.pmtupdate PMT Update verwenden +miscsettings.shutdown_real Standbymodus +miscsettings.shutdown_real_rcdelay Verzögerter Shutdown +miscsettings.shutdown_count Komplett ausschalten nach +miscsettings.sptsmode SPTS-Mode Treiber laden +miscsettings.startbhdriver BH-Mode Treiber laden +motorcontrol.head Motor-Setup +movieplayer.bookmark Bookmarks +movieplayer.bookmarkname Bookmark Name +movieplayer.bookmarkname_hint1 Geben Sie den Namen für das neue Bookmark ein +movieplayer.bookmarkname_hint2 +movieplayer.buffering Puffern... +movieplayer.defdir Start-Verz. +movieplayer.defplugin Start-Plugin +movieplayer.dvdplayback DVD +movieplayer.fileplayback Abspielen (Multiformat) +movieplayer.goto Springe zu ... +movieplayer.goto.h1 = -> absoluter Sprung +movieplayer.goto.h2 +,- -> relativer Sprung +movieplayer.head Movieplayer +movieplayer.nostreamingserver Es konnte keine Verbindung\nzum Streamingserver hergestellt werden. +movieplayer.pesplayback PES Abspielen (Experimentell) +movieplayer.pleasewait Bitte warten Sie.\nDie Verbindung zum Streamingserver wird hergestellt. +movieplayer.toomanybookmarks Sie haben bereits zu viele Bookmarks angelegt.\nEs muß erst ein anderes gelöscht werden. +movieplayer.tshelp1 Stop +movieplayer.tshelp10 ca. 10 Minuten zurück +movieplayer.tshelp11 ca. 10 Minuten vor +movieplayer.tshelp12 Hilfe: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Auswahl der Tonspur +movieplayer.tshelp3 Pause/Weiter +movieplayer.tshelp4 Bookmark setzen +movieplayer.tshelp5 Zeit einblenden +movieplayer.tshelp6 ca. 1 Minute zurück +movieplayer.tshelp7 ca. 1 Minute vor +movieplayer.tshelp8 ca. 5 Minuten zurück +movieplayer.tshelp9 ca. 5 Minuten vor +movieplayer.tsplayback TS Abspielen +movieplayer.vcdplayback (S)VCD +movieplayer.vlchelp1 Stop +movieplayer.vlchelp10 ca. 10 Minuten zurück +movieplayer.vlchelp11 ca. 10 Minuten vor +movieplayer.vlchelp12 Hilfe: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Resync +movieplayer.vlchelp3 Pause/Weiter +movieplayer.vlchelp4 Bookmark setzen +movieplayer.vlchelp5 Zeit einblenden +movieplayer.vlchelp6 ca. 1 Minute zurück +movieplayer.vlchelp7 ca. 1 Minute vor +movieplayer.vlchelp8 ca. 5 Minuten zurück +movieplayer.vlchelp9 ca. 5 Minuten vor +movieplayer.wrongvlcversion Funktion ist mit der benutzten Version des VLC nicht möglich +networkmenu.broadcast Broadcast +networkmenu.dhcp DHCP +networkmenu.gateway Standard Gateway +networkmenu.head Netzwerk Einstellungen +networkmenu.ipaddress IP-Adresse +networkmenu.mount NFS/CIFS/FTPFS +networkmenu.nameserver Nameserver +networkmenu.netmask Netzmaske +networkmenu.ntpenable Syncronisieren via +networkmenu.ntprefresh NTP/DVB-Refresh +networkmenu.ntprefresh_hint1 NTP/DVB-Time-Sync in minuten +networkmenu.ntprefresh_hint2 braucht reboot oder epg-reset +networkmenu.ntpserver NTP-Server +networkmenu.ntpserver_hint1 NTP-Server Beispiel: ntp1.ptb.de +networkmenu.ntpserver_hint2 braucht reboot oder epg-reset +networkmenu.ntptitle Time-Syncronisation +networkmenu.setupnow Netzwerkeinstellungen jetzt zuweisen +networkmenu.setuponstartup Beim Starten Netzwerk setzen +networkmenu.show aktive Netzwerkeinstellungen zeigen +networkmenu.test Netzwerk testen +nfs.alreadymounted Verzeichnis bereits gemountet. +nfs.automount Beim Start mounten +nfs.dir Verzeichnis/Freigabe +nfs.ip Server IP +nfs.localdir lokales Verzeichnis +nfs.mount Netzwerk Verzeichnis mounten +nfs.mount_options Mount-Optionen +nfs.mountok Mount erfolgreich +nfs.mounterror Mount-Fehler +nfs.mounterror_notsup Dateisystem-Typ wird nicht unterstützt. +nfs.mountnow Jetzt mounten +nfs.mounttimeout Mount-Fehler: Timeout +nfs.password Passwort +nfs.remount Verzeichnisse erneut mounten +nfs.type Typ +nfs.type_cifs CIFS +nfs.type_lufs FTPFS +nfs.type_nfs NFS +nfs.umount Netzwerk Verzeichnis unmounten +nfs.umounterror Umount-Fehler +nfs.username Benutzername +nfsmenu.head NFS/CIFS/FTPFS Einstellungen +nvod.percentage (%d%% vorbei) +nvod.starting (Beginn in %d min) +nvodselector.directormode Bildregie-Modus +nvodselector.head Anfangszeit auswählen +nvodselector.subservice Perspektiven +options.default Voreinstellungen benutzen +options.fb framebuffer +options.null null +options.off aus +options.on ein +options.serial seriell +parentallock.changepin PIN-Code festlegen +parentallock.changepin_hint1 Geben Sie hier Ihren neuen PIN-Code ein! +parentallock.changetolocked Bei vorgeperrten Bouquets +parentallock.head Jugendschutz PIN +parentallock.lockage Sendungen +parentallock.lockage12 ab 12 Jahren sperren +parentallock.lockage16 ab 16 Jahren sperren +parentallock.lockage18 ab 18 Jahren sperren +parentallock.lockedchannel Vorgesperrter Sender... +parentallock.lockedprogram Gesperrtes Programm (FSK ab %d) +parentallock.never Nie +parentallock.onsignal Bei gesendeter Vorsperre +parentallock.parentallock Jugendschutz +parentallock.prompt PIN-Eingabe +pictureviewer.defdir Start-Verz. +pictureviewer.head Bildbetrachter +pictureviewer.help1 Menu-Modus +pictureviewer.help10 Anzeige-Modus +pictureviewer.help11 Bild neu einlesen +pictureviewer.help12 vorheriges Bild +pictureviewer.help13 nachstes Bild +pictureviewer.help14 Zoom out +pictureviewer.help15 Zoom in +pictureviewer.help16 Scroll hoch +pictureviewer.help17 Scroll links +pictureviewer.help18 Scroll rechts +pictureviewer.help19 Scroll herunter +pictureviewer.help2 Bild anzeigen +pictureviewer.help20 Sortierung andern +pictureviewer.help21 Bild unskaliert einlesen +pictureviewer.help22 Modus verlassen +pictureviewer.help3 Sortierung andern +pictureviewer.help4 Bild unskaliert einlesen +pictureviewer.help5 Diashow-Modus +pictureviewer.help6 vorheriges Bild +pictureviewer.help7 nachstes Bild +pictureviewer.help8 Sortierung andern +pictureviewer.help9 Modus verlassen +pictureviewer.resize.color_average aufwendig +pictureviewer.resize.none keine +pictureviewer.resize.simple einfach +pictureviewer.scaling Skalierung +pictureviewer.show Anzeigen +pictureviewer.slide_time Diaschau-Anzeigedauer +pictureviewer.slideshow Diaschau +pictureviewer.sortorder Sort.reihenf. ändern +pictureviewer.sortorder.date (Datum) +pictureviewer.sortorder.filename (Dateiname) +ping.ok ist erreichbar (ping) +ping.protocol ist nicht erreichbar (Host or protocol error) +ping.socket ist nicht erreichbar (Socket error) +ping.unreachable ist nicht erreichbar (unreachable) +pinprotection.head PIN-Abfrage +pinprotection.wrongcode Geben Sie den Code nocheinmal ein! +plugins.result Pluginausgabe +rclock.lockmsg Die Fernbedienung der Coolstream wird gesperrt.\n Um die Sperre aufzuheben, bitte\n und auf der Fernbedienung\n druecken. +rclock.menueadd FB sperren +rclock.title Fernbedienung sperren +rclock.unlockmsg Fernbedienung reaktiviert... +recordingmenu.choose_direct_rec_dir Bei Sofortaufn. Verzeichnisauswahl +recordingmenu.defdir Aufnahmeverzeichnis +recordingmenu.epg_for_filename lange Dateinamen (mit EPG-Daten) +recordingmenu.file Direkt (Datei) +recordingmenu.filesettings Direktaufnahme Einstellungen +recordingmenu.head Aufnahme Einstellungen +recordingmenu.help Aufnahmegeräte:\n-----------------------\nServer:\nauf PC mit Hilfe eines Streaming-Programmes\n\n(analoger) Videorekorder:\nüber VCR-Ausgang\n\nDirekt (Datei):\nauf ein per NFS gemountetes Verzeichnis\noder eine interne Festplatte\nTS: SPTS-Mode Treiber laden(dbox2)\nPES: SPTS-Mode Treiber nicht laden(dbox2)\n\n\nMaximale Dateigröße:\n----------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: fast unendlich (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart Unterdrücke Scart-Umschaltung +recordingmenu.off aus +recordingmenu.recording_type Aufnahme Gerät +recordingmenu.ringbuffers Anz. Ringpuffer +recordingmenu.server Server +recordingmenu.server_ip Aufnahmeserver IP +recordingmenu.server_mac Mac Adresse +recordingmenu.server_port Aufnahmeserver Port +recordingmenu.server_wakeup Aufnahmeserver WOL +recordingmenu.setupnow Einstellungen jetzt übernehmen +recordingmenu.splitsize Max. Dateigröße (MB) +recordingmenu.stopplayback Playback anhalten +recordingmenu.stopsectionsd Sectionsd anhalten +recordingmenu.stream_vtxt_pid teletext aufzeichnen +recordingmenu.use_fdatasync Synchrones Schreiben (fdatasync) +recordingmenu.use_o_sync Synchrones Schreiben (O_SYNC) +recordingmenu.vcr Videorekorder +recordtimer.announce Die Aufnahme beginnt in wenigen Minuten. +repeatblocker.hint_1 Mindestzeit (in ms) zwischen 2 Tastendrücken +repeatblocker.hint_2 0 schaltet den Blocker aus (Rot ist " ") +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-Wiederholungen +satsetup.extended DiSEqC-Einstellungen +satsetup.extended_motor Motor-Einstellungen +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Manuelle Motor-Einstellung +satsetup.nodiseqc Kein DiSEqC +satsetup.satellite Satellit +satsetup.savesettingsnow Einstellungen jetzt speichern +satsetup.smatvremote SMATV Remote Tuning +scants.actcable Kabel: +scants.actsatellite Satellit: +scants.bouquet Bouquets +scants.bouquet_create neu erstellen +scants.bouquet_erase löschen +scants.bouquet_leave nicht ändern +scants.bouquet_satellite Satelliten-Bouquet +scants.bouquet_update erneuern +scants.channel Kanal: +scants.failed Kanalsuche fehlgeschlagen! +scants.finished Kanalsuche erfolgreich beendet! +scants.freqdata Frequenz: +scants.head Kanalsuche +scants.numberofdataservices Data +scants.numberofradioservices Radio +scants.numberoftotalservices Gesamt +scants.numberoftvservices TV +scants.provider Anbieter: +scants.startnow Kanalsuche starten +scants.test Empfang Test +scants.transponders Transponder: +scants.select_tp Wählen Sie Transponder +screensetup.lowerright grün = Bildrand unten, rechts +screensetup.upperleft rot = Bildrand oben, links +servicemenu.head Service +servicemenu.reload Kanallisten neu laden +servicemenu.reload_hint Kanallisten werden neu geladen,\nbitte warten... +servicemenu.scants Kanalsuche +servicemenu.ucodecheck UCodes überprüfen +servicemenu.update Software-Aktualisierung +settings.help Help +settings.missingoptionsconffile Die Neutrino-Einstellungen wurden erweitert.\nDie neuen Werte werden auf Standard gesetzt. +settings.noconffile Die Neutrino-Einstellungen wurden nicht\ngefunden. Es werden Standardwerte benutzt. +settings.pos_bottom_left unten links +settings.pos_bottom_right unten rechts +settings.pos_top_left oben links +settings.pos_top_right oben rechts +shutdowntimer.announce Die Box wird in 1 min runtergefahren.\nShutdown abbrechen? +sleeptimerbox.announce Sleeptimer in 1 min +sleeptimerbox.hint1 Ausschaltzeit in Min. (000=aus) +sleeptimerbox.hint2 Die box schaltet sich nach dieser Zeit aus. +sleeptimerbox.title Sleeptimer +streamfeatures.head Features +streaminfo.aratio Verhältnis +streaminfo.aratio_unknown Verhältnis: unbekannt +streaminfo.audiotype Audiotyp +streaminfo.audiotype_unknown Audiotyp: unbekannt +streaminfo.bitrate Bitrate +streaminfo.framerate Bildrate +streaminfo.framerate_unknown Bildrate: unbekannt +streaminfo.head Tech. Information +streaminfo.not_available nicht verfügbar +streaminfo.resolution Auflösung +streaminfo.signal Empfangssignal +streaming.buffer_overflow Die Aufnahme wurde leider abgebrochen,\nda die Daten nicht schnell genug geschrieben werden konnten. +streaming.busy Ein oder mehrere Aufnahmeprozesse sind aktiv.\nSollte die Aufnahme eigentlich beendet sein,\nschafft ein Neustart von Neutrino Abhilfe. +streaming.dir_not_writable Das Aufnahmeverzeichnis ist nicht beschreibbar.\nAufnahmen sind daher nicht möglich. +streaming.success Die Aufnahme wurde erfolgreich beendet. +streaming.write_error Die Aufnahme wurde leider abgebrochen,\nda ein Fehler beim Schreiben der Daten auftrat. +streaming.write_error_open Die Aufnahme wurde leider abgebrochen,\nda die entsprechende Datei nicht zum Schreiben geöffnet werden konnte. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Movieplayer Einstellungen +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Deaktiviert +streamingmenu.on Aktiviert +streamingmenu.server_ip Streamingserver IP +streamingmenu.server_port Streamingserver Port +streamingmenu.streaming_audiorate Datenrate Audio +streamingmenu.streaming_force_avi_rawaudio Erzwinge AC3 bei avi +streamingmenu.streaming_force_transcode_video Transcod. auch mpg/vcd Video +streamingmenu.streaming_resolution Auflösung +streamingmenu.streaming_server_cddrive DVD Laufwerk +streamingmenu.streaming_server_startdir Verzeichnis (VLC) +streamingmenu.streaming_transcode_audio Transcod. Audio (dvd/vcd/mpg) +streamingmenu.streaming_transcode_video_codec MPEG Video Codec +streamingmenu.streaming_type Streamingserver +streamingmenu.streaming_videorate Datenrate Video +streamingserver.noconnect Keine Verbindung zum Streamingserver.\nAufnahme wird abgebrochen. +stringinput.caps Groß-/Kleinbuchstaben +stringinput.clear Alles löschen +timer.eventrecord.msg Die Sendung wurde zur Aufnahme vorgemerkt. +timer.eventrecord.title Aufnahme vormerken +timer.eventtimed.msg Die Sendung wurde vorgemerkt. +timer.eventtimed.title Sendung vormerken +timerbar.channelswitch Umschalten +timerbar.recordevent Aufnehmen +timerlist.alarmtime Alarmzeit +timerlist.apids Audio PIDs +timerlist.bouquetselect Bouquet wählen +timerlist.channel Kanal +timerlist.channelselect Kanal wählen +timerlist.delete Löschen +timerlist.menumodify Timer bearbeiten +timerlist.menunew Neuer Timer +timerlist.message Nachricht +timerlist.moderadio Radio Kanäle +timerlist.modeselect Modus-Auswahl +timerlist.modetv TV Kanäle +timerlist.modify Bearbeiten +timerlist.name Timerliste +timerlist.new Neuer Timer +timerlist.plugin Plugin +timerlist.program.unknown Programm unbekannt +timerlist.recording_dir Aufnahmeverzeichnis +timerlist.reload Aktualisieren +timerlist.repeat Wiederholung +timerlist.repeat.biweekly 2-wöchentlich +timerlist.repeat.byeventdescription siehe timer +timerlist.repeat.daily täglich +timerlist.repeat.fourweekly 4-wöchentlich +timerlist.repeat.friday Fr +timerlist.repeat.monday Mo +timerlist.repeat.monthly monatlich +timerlist.repeat.once einmalig +timerlist.repeat.saturday Sa +timerlist.repeat.sunday So +timerlist.repeat.thursday Do +timerlist.repeat.tuesday Di +timerlist.repeat.unknown unbekannt +timerlist.repeat.wednesday Mi +timerlist.repeat.weekdays An Wochentagen +timerlist.repeat.weekly wöchentlich +timerlist.repeatcount Wiederholungen +timerlist.repeatcount.help1 Anzahl der Timerausführungen +timerlist.repeatcount.help2 0 für unbegrenzte Anzahl +timerlist.save Timer speichern +timerlist.standby SB Modus +timerlist.standby.off Aufwachen aus Standby +timerlist.standby.on Auf Standby gehen +timerlist.stoptime Stoppzeit +timerlist.type Timertyp +timerlist.type.execplugin Plugin ausführen +timerlist.type.nextprogram Nächstes Programm +timerlist.type.record Aufnahme +timerlist.type.remind Erinnerung +timerlist.type.shutdown Shutdown +timerlist.type.sleeptimer Sleeptimer +timerlist.type.standby Standby +timerlist.type.unknown Unbekannt +timerlist.type.zapto Umschalten +timerlist.weekdays Wochentage +timerlist.weekdays.hint_1 Mo Di Mi Do Fr Sa So +timerlist.weekdays.hint_2 'X'=Timer '-' kein Timer +timersettings.record_safety_time_after Aufnahmeende-Korrektur +timersettings.record_safety_time_after.hint_1 Korrekturzeit in Min. (00=aus), die auf die End- +timersettings.record_safety_time_after.hint_2 zeit des jeweiligen Timers addiert wird +timersettings.record_safety_time_before Aufnahmestart-Korrektur +timersettings.record_safety_time_before.hint_1 Korrekturzeit in Min. (00=aus), die beim Start +timersettings.record_safety_time_before.hint_2 des jeweiligen Timers abgezogen werden +timersettings.separator Timereinstellungen +timing.chanlist Kanalliste +timing.epg Epg +timing.filebrowser Filebrowser +timing.head OSD Timeouts +timing.hint_1 Einblendzeit in Sek., die das OSD +timing.hint_2 auf dem TV angezeigt wird +timing.infobar Infobar +timing.menu Menu +timing.numericzap Umschalten mit Zifferntasten +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head UCode Ãœberprüfung +ucodecheck.ucode UCode +ucodes.failure Achtung, die µCodes wurden NICHT gefunden!\n\nBitte per FTP (oder DBox-BootManager)\nuploaden, und die box neu starten! +videomenu.csync Sync.-Korrektur +videomenu.head Video-Einstellungen +videomenu.rgb_centering RGB-Zentrierung +videomenu.screensetup Bildbereich einstellen +videomenu.vcrswitch Scart-Eingang automatisch +videomenu.videoformat Bildschirmformat +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 +videomenu.43mode 4:3 Content mode +videomenu.panscan Pan&Scan +videomenu.letterbox Letterbox +videomenu.fullscreen Full screen +videomenu.videoformat_autodetect automatisch +videomenu.videosignal Video Signalart +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YPbPr auf component +videomenu.videosignal_yuv_v YPbPr auf SCART +zaptotimer.announce In einer Minute wird umgeschaltet. +extra.auto Auto +extra.valid Valid +extra.all Alle +extra.sep_extra Extras +extra.save_settings Einstellungen speichern +extra.dvbsnoop DVB Stream Info +extra.dvbsnoop_pat Zeige PAT +extra.dvbsnoop_cat Zeige CAT +extra.dvbsnoop_tsdt Zeige TSDT +extra.dvbsnoop_nit Zeige NIT +extra.dvbsnoop_sdt Zeige SDT +extra.dvbsnoop_eit Zeige EIT +extra.dvbsnoop_rst Zeige RST +extra.dvbsnoop_tdt Zeige TDT +extra.dvbsnoop_sit Zeige SIT +extra.dvbsnoop_pid Zeige manual PID +extra.dvbsnoop_scan Scan PIDs +extra.dvbsnoop_band Zeige pid Bandbreite +extra.logview Lass Log sehen +extra.english Englisch +extra.dboxinfo Box Info +extra.scan_mode Scan Modus +extra.start_tostandby Starten zum Standby +extra.rotor_swap Rotor dreht Ost/West +extra.use_log Loge nach /tmp/log +extra.spts_mode SPTS Modus +extra.hw_sect Hardware Sectionen +extra.logo Logo Nummer +extra.scan_full Total +extra.scan_fast Schnell +hdd_slow Langsam +hdd_middle Mitte +hdd_fast Schnell +hdd_ext3 Ext3fs +hdd_reiser Reiserfs +hdd_1min 1 min. +hdd_5min 5 min. +hdd_10min 10 min. +hdd_20min 20 min. +hdd_30min 30 min. +hdd_60min 60 min. +extra.logo1 1 +extra.logo2 2 +extra.logo3 3 +hdd_sleep Schlaf Zeit +hdd_noise Laerm +hdd_activate Aktiviere Einstellungen +hdd_fs Filesystem +hdd_format Formatiere HDD +hdd_check Check Dateiesysteem +hdd_settings HDD Einstellungen +extra.clear_log Logdatei löschen +extra.zap_cycle Zap Zyklen +extra.sms_channel Sms-Modus Kanal +extra.manual_scan Manual Ansehen +extra.tp_freq Frequenz +extra.tp_rate Symbolrate +extra.tp_pol Polarization +extra.tp.pol_v V +extra.tp_pol_h H +extra.tp_fec FEC +extra.fec_1_2 1/2 +extra.fec_2_3 2/3 +extra.fec_3_4 3/4 +extra.fec_5_6 5/6 +extra.fec_7_8 7/8 +extra.timezone Zeit-Zone +extra.zapit_menu Zapit Optionen +extra.zapit_make_bouquet Mache restliche Kanalliste +extra.zapit_save_last_chan Speicher letzten Kanal +extra.zapit_motor_speed Rotor Geschwindigkeit (10 = 1deg/sec) +extra.zapit_fe_timeout Tune timeout +extra.add_to_bouquet dem Bouquet hinzufuegen +extra.chadded Der aktuelle Kanal wird dem selektierter Bouquet hinzugefügt....\n +extra.chalreadyinbq Der aktueller Kanal ist bereits in selektiertem Bouquet....\n +extra.menu_left_exit "links" = Menu zurück +extra.zapit_write_names Schreibe Kanalname +extra.update_dir Update-Verzeichnis +extra.zapit_fast_zap Fast Zap +extra.cache Cache +extra.debug Debug +extra.zapit_sort_names Sort Kanal nach Name +extra.zapit_delete Lösche Kanal +extra.zapit_backup Sichere Kanelliste nach /tmp +extra.zapit_restore Stelle Kanalliste wieder von /tmp wieder her +pictureviewer.decode_server_ip Decode Server IP +pictureviewer.decode_server_port Decode Server Port +scants.abort_body Scanvorgang wirklich abbrechen? +scants.abort_header Breche Scan ab +recordingmenu.record_in_spts_mode in SPTS-Modus aufnehmen +servicemenu.getplugins Plugins neu laden +servicemenu.getplugins_hint Plugins werden neu geladen,\nbitte warten... +zapit.scantype Service-Auswahl +zapit.scantype.all Alle Services +zapit.scantype.radio Nur Radio +zapit.scantype.tv Nur TV +zapit.scantype.tvradio Nur TV & Radio +colorthememenu.red_theme Simply Red +lcdmenu.dim_brightness Helligkeit nach Dimm-Timeout +lcdmenu.dim_time Dimm-Timeout +timerlist.overlapping_timer Timer überschneiden sich. Neuen Timer trotzdem anlegen? +extra.audio_run_player Audio Taste startet Player +mpkey.rewind Rücklauf +mpkey.forward Vorlauf +mpkey.pause Pause +mpkey.stop Stop +mpkey.play Play +mpkey.audio Audio-Track +mpkey.time Zeitanzeige +mpkey.bookmark Speichere Bookmark +mpkey.plugin Starte Plugin +extra.key_click Tasten-Klick +extra.loadcolors Lade Farben von +extra.savecolors Speicher Farben als +extra.loadkeys Lade Tastenbelegung von +extra.savekeys Speichere Tastenbelegung als +extra.loadconfig Lade Einstellungen von +extra.saveconfig Speichere Einstellungen als +videomenu.videomode Videosystem +videomenu.videomode_ntsc NTSC +videomenu.videomode_pal PAL +videomenu.videomode_palm PAL-M +extra.key_timeshift Timeshift +extra.key_plugin One-touch-Plugin +extra.timeshift_pause Timeshift Pause +rfmod.rfmod RF Modulator +rfmod.carrier Unterträger-Frequenz +rfmod.carrier4500 4.5 +rfmod.carrier5500 5.5 +rfmod.carrier6000 6.0 +rfmod.carrier6500 6.5 +rfmod.enable Sound aktivieren +rfmod.channel Kanal +rfmod.finetune Feintuning +rfmod.standby Modulator aktivieren +rfmod.test Testpattern +extra.zapit_scanpids Scan/Use Pids +extra.zapit_hvoltage High (13.5/18.5) Voltage +extra.key_unlock Entsperrtaste +servicemenu.imageinfo Image-Info +imageinfo.creator Ersteller: +imageinfo.date Datum: +imageinfo.dokumentation Dokus: +imageinfo.forum Forum: +imageinfo.head Image Info: +imageinfo.homepage Homepage: +imageinfo.image Image: +imageinfo.license Lizenz: +imageinfo.version Version: +extra.cache_txt Teletext zwischenspeichern +extra.use_gotoxx Benutze gotoXX +extra.latitude Breitengrad +extra.longitude Längengrad +extra.ladirection Breitengrad-Ausrichtung +extra.lodirection Längengrad-Ausrichtung +extra.south Süden +extra.north Norden +extra.east Osten +extra.west Westen +epgextended.actors Darsteller +epgextended.director Regie +epgextended.guests Gäste +epgextended.original_title Original Titel +epgextended.presenter Moderator +epgextended.year_of_production Produktionsjahr +recordingmenu.save_in_channeldir Speichere im Kanalverzeichnis +servicemenu.restart Neutrino neu starten +servicemenu.restart_failed Neustart von Neutrino schlug fehl +servicemenu.restart_hint Neutrino wird neu gestartet... +servicemenu.restart_refused_recording Aufnahme läuft. Restart nicht möglich. +extra.tp_mod Modulation +extra.tp_mod_16 QAM/16 +extra.tp_mod_32 QAM/32 +extra.tp_mod_64 QAM/64 +extra.tp_mod_128 QAM/128 +extra.tp_mod_256 QAM/256 +moviebrowser.book_head Markierungen +moviebrowser.book_lastmoviestop letzter Wiedergabestop: +moviebrowser.book_movieend Filmende: +moviebrowser.book_moviestart Filstart: +moviebrowser.book_name Name: +moviebrowser.book_new Neue Markierung +moviebrowser.book_position Position: +moviebrowser.book_type Sprung (<0 zurück , >0 vor): +moviebrowser.book_type_backward Wiederholung +moviebrowser.book_type_forward Ãœberspringen +moviebrowser.edit_book Bookmark Ändern +moviebrowser.edit_book_name_info1 Neuer Markierungsname +moviebrowser.edit_book_name_info2 +moviebrowser.edit_book_pos_info1 Neue Position (s) +moviebrowser.edit_book_pos_info2 +moviebrowser.edit_book_type_info1 Neue Sprunglänge (s) +moviebrowser.edit_book_type_info2 <0 zurück , >0 vor, 0: kein +moviebrowser.edit_serie Name der Serie +moviebrowser.error_no_movies Keine Filme gefunden +moviebrowser.foot_filter Filter: +moviebrowser.foot_play Film starten +moviebrowser.foot_sort Sortieren: +moviebrowser.head TS Filmarchiv +moviebrowser.head_filter Filme nach Kategorie filtern: +moviebrowser.head_playlist Zuletzt gesehen: +moviebrowser.head_recordlist Zuletzt aufgenommen: +moviebrowser.hint_jumpbackward Rücksprung in 5 s\n '0' zum Weitersehen +moviebrowser.hint_jumpforward Werbung überspringen in 5 s\n '0' zum Ansehen +moviebrowser.hint_movieend Filmende in 5 s\n '0' zum Weitersehen +moviebrowser.hint_newbook_backward Neue Wiederholung\n 'blue' für Endposition +moviebrowser.hint_newbook_forward Neuer Werbesprung\n 'blue' für Endposition +moviebrowser.info_audio Audio +moviebrowser.info_channel Kanel +moviebrowser.info_filename Name +moviebrowser.info_genre_major Genre +moviebrowser.info_genre_minor Genre +moviebrowser.info_head Film Informationen +moviebrowser.info_info1 Info 1 +moviebrowser.info_info2 Info 2 +moviebrowser.info_length Spieldauer (Min) +moviebrowser.info_parental_lockage Altersfreigabe +moviebrowser.info_parental_lockage_0year immer +moviebrowser.info_parental_lockage_12year 12 Jahre +moviebrowser.info_parental_lockage_16year 16 Jahre +moviebrowser.info_parental_lockage_18year 18 Jahre +moviebrowser.info_parental_lockage_6year 6 Jahre +moviebrowser.info_parental_lockage_always nie +moviebrowser.info_path Verzeichnis +moviebrowser.info_prevplaydate Letzte Wiedergabe +moviebrowser.info_prodcountry Land +moviebrowser.info_prodyear Jahr +moviebrowser.info_quality Qualität +moviebrowser.info_recorddate Aufnahmedatum +moviebrowser.info_serie Serie +moviebrowser.info_size Dateigrösse (MB) +moviebrowser.info_title Titel +moviebrowser.info_videoformat Bild +moviebrowser.menu_directories_head Verzeichnisse +moviebrowser.menu_help_head Hilfe +moviebrowser.menu_main_bookmarks Markierungen +moviebrowser.menu_main_head Einstellungen +moviebrowser.menu_main_movieinfo Film-Info +moviebrowser.menu_main_saveandback Speichern und verlassen +moviebrowser.menu_nfs_head NFS Einstellung +moviebrowser.menu_parental_lock_activated aktiviert +moviebrowser.menu_parental_lock_activated_no nein +moviebrowser.menu_parental_lock_activated_yes ja +moviebrowser.menu_parental_lock_activated_no_temp nein (temporär) +moviebrowser.menu_parental_lock_head Jugendschutz +moviebrowser.menu_parental_lock_rate_head Filme sperren ab +moviebrowser.scan_for_movies Suche Filme ... +moviebrowser.serie_existingname Vorhandene Serie +moviebrowser.serie_head Serie +moviebrowser.serie_name Name ändern +moviebrowser.short_audio Audio +moviebrowser.short_book Marker +moviebrowser.short_channel Kanal +moviebrowser.short_country Land +moviebrowser.short_filename Name +moviebrowser.short_format Format +moviebrowser.short_genre_major Genre +moviebrowser.short_genre_minor Genre +moviebrowser.short_info1 Info 1 +moviebrowser.short_info2 Info 2 +moviebrowser.short_length Min +moviebrowser.short_parental_lockage FSK +moviebrowser.short_path Pfad +moviebrowser.short_prevplaydate Zuletzt +moviebrowser.short_prodyear Jahr +moviebrowser.short_quality * (Qualität) +moviebrowser.short_recorddate Datum +moviebrowser.short_serie Serie +moviebrowser.short_size MB +moviebrowser.short_title Title +moviebrowser.start_head Film starten von Position: +moviebrowser.start_record_start Aufnahmestart +options.on.without_messages ohne Msg +extra.zapit_scan_sdt Scan SDT für Updates +extra.zapit_sdt_changed Kanalliste wird neu geladen. +miscsettings.channellist Kanalliste +miscsettings.channellist_epgtext_align Ausrichtung des Programmtextes +miscsettings.epg_head EPG Einstellungen +miscsettings.epg_cache EPG-Cache (Tage) +miscsettings.epg_cache_hint1 EPG-Daten im Voraus cachen? +miscsettings.epg_cache_hint2 Angabe in Tagen +miscsettings.epg_dir EPG Speicherverzeichnis +miscsettings.epg_max_events Max. Events +miscsettings.epg_max_events_hint1 Wieviele Events sollen max. gespeichert werden? +miscsettings.epg_max_events_hint2 Standard 6000, 0 (ohne Limit) +miscsettings.epg_old_events EPG verwerfen nach (Std.) +miscsettings.epg_old_events_hint1 Wie lange abgelaufene EPG-Daten aufheben? +miscsettings.epg_old_events_hint2 Angabe in Stunden +miscsettings.epg_save EPG zwischenspeichern? +miscsettings.virtual_zap_mode Virtual Zap +shutdown.recoding_query Aufnahme läuft. Trotzdem beenden? +recordingmenu.apids Voreinstellung für Tonspuren +recordingmenu.apids_ac3 AC3 Tonspuren aufnehmen +recordingmenu.apids_alt Alternative Tonspuren aufn. +recordingmenu.apids_std Standard Tonspur aufnehmen +recordingmenu.stream_pmt_pid PMT aufnehmen +recordingmenu.zap_on_announce Umschalten bei Ankündigung +timerlist.apids_dflt Voreingestellte Tonspuren aufn. +videomenu.osd OSD +videomenu.tv-scart TV Scart +videomenu.vcr-scart VCR Scart +videomenu.vcrsignal VCR-Ausgang Signalart +videomenu.vcrsignal_composite CVBS +videomenu.vcrsignal_svideo S-Video +moviebrowser.option_browser Anzeigeoptionen +moviebrowser.book_clear_all Lösche alle +moviebrowser.menu_save Veränderungen speichern +moviebrowser.menu_save_all Starte Ãœbernahme in allen sichtbaren Filminfos +moviebrowser.info_head_update Inhalte in allen sichtbaren Filminfos speichern +moviebrowser.update_if_dest_empty_only Ãœbernehmen nur wenn Ziel leer +moviebrowser.serie_auto_create Serien automatisch zuordnen +moviebrowser.load_default Lade Voreinstellung +moviebrowser.browser_row_head Spalten Einstellungen +moviebrowser.browser_row_nr Anzahl Spalten +moviebrowser.browser_row_item Spalteninfo +moviebrowser.browser_row_width Spaltenbreite [Punkte] +moviebrowser.reload_at_start Filminfos neu laden bei Start +moviebrowser.remount_at_start Filmdepot verbinden bei Start +moviebrowser.dir_head Zusätzliche Verzeichnisse +moviebrowser.dir Pfad +moviebrowser.use_dir Verzeichnis verwenden +moviebrowser.use_rec_dir Aufnahmeverzeichnis verwenden +moviebrowser.use_movie_dir Wiedergabeverzeichnis verwenden +moviebrowser.hide_series Verstecke Serien +moviebrowser.last_record_max_items Zeilen 'zuletzt gesehen' +moviebrowser.last_play_max_items Zeilen 'zuletzt aufgenommen' +moviebrowser.browser_frame_high Anzeigehöhe oberes Fenster [Punkte] +extra.auto_timeshift Automatische Ausnahme, Sekunden (0 = deaktiviert) +extra.auto_delete Automatische Löschung +extra.auto_to_record Timeshift zu den Aufnahmen hinzufügen +extra.record_time Timeshift Aufnahmezeit in Stunden +audioplayer.spectrum LCD Skala +extra.temp_timeshift Temporäres Timeshift +AUDIOSelectMenue.head Auswahl der Tonspur +infoviewer.languages Audio +mainmenu.clearsectionsd Lösche EPG Cache +moviebrowser.edit_book_name_info2 +usermenu.button_blue Benutzermenü 'blau' +usermenu.button_green Benutzermenü 'grün' +usermenu.button_red Benutzermenü 'rot' +usermenu.button_yellow Benutzermenü 'gelb' +usermenu.head Benutzermenü +usermenu.item_bar ---- Trennung ---- +usermenu.item_epg_misc EPG Funktionen +usermenu.item_none +usermenu.item_vtxt Videotext +usermenu.name Name +extra.fec_s2_qpsk_1_2 1/2 s2 qpsk +extra.fec_s2_qpsk_2_3 3/2 s2 qpsk +extra.fec_s2_qpsk_3_4 3/4 s2 qpsk +extra.fec_s2_qpsk_5_6 5/6 s2 qpsk +extra.fec_s2_qpsk_7_8 7/8 s2 qpsk +extra.fec_s2_qpsk_8_9 8/9 s2 qpsk +extra.fec_s2_qpsk_3_5 3/5 s2 qpsk +extra.fec_s2_qpsk_4_5 4/5 s2 qpsk +extra.fec_s2_qpsk_9_10 9/10 s2 qpsk +extra.fec_s2_8psk_1_2 1/2 s2 8psk +extra.fec_s2_8psk_2_3 3/2 s2 8psk +extra.fec_s2_8psk_3_4 3/4 s2 8psk +extra.fec_s2_8psk_5_6 5/6 s2 8psk +extra.fec_s2_8psk_7_8 7/8 s2 8psk +extra.fec_s2_8psk_8_9 8/9 s2 8psk +extra.fec_s2_8psk_3_5 3/5 s2 8psk +extra.fec_s2_8psk_4_5 4/5 s2 8psk +extra.fec_s2_8psk_9_10 9/10 s2 8psk +channellist.edit Bearbeiten +channellist.favs Favoriten +channellist.provs Provider +channellist.sats Satelliten +channellist.history History +channellist.current_tp Aktueller Transponder +video_mode_ok Video-Einstellungen ok ? +moviebrowser.edit_book_name_info2 book name info2 +satsetup.sat_setup Setup LNB-Konfiguration +satsetup.do_scan Satelliten scannen +satsetup.lofl LNB Low Offset +satsetup.lofh LNB High Offset +satsetup.lofs LNB Switch Offset +satsetup.diseqc_input Diseqc Einspeisung +satsetup.uncomm_input Uncommited +satsetup.motor_pos Rotor-Position +satsetup.auto_scan Ausgewählten Satelliten scannen +satsetup.auto_scan_all Alle Satelliten scannen +satsetup.manual_scan Manuller Frequenzscan +satsetup.use_nit Benutze NIT +satsetup.diseqc_advanced Erweiterte Auswahl +satsetup.diseqc_order Einspeisungsfolge +satsetup.diseqc_com_uncom Commited/Uncommited +satsetup.diseqc_uncom_com Uncommited/Commited +satsetup.comm_input Commited Input +satsetup.use_usals Benutze Usals +motorcontrol.user_menu Benutzermenü +motorcontrol.install_menu Motor Installation +motorcontrol.step_west Fahre/Schrittsetze Motor nach Westen (b,c) +motorcontrol.step_east Fahre/Schrittsetze Motor nach Osten (b,c) +motorcontrol.halt Stope Motor +motorcontrol.west_limit Setze westliches (soft) Limit +motorcontrol.east_limit Setze östliches (soft) Limit +motorcontrol.enable_limit Aktiviere (soft) Limit +motorcontrol.disable_limit Deaktiviere (soft) Limit +motorcontrol.ref_position Gehe zu Referenz Position +motorcontrol.calc_positions (Neu)-Berechne(n)) Positionen +motorcontrol.pos_increase Motor Position rauf (a) +motorcontrol.pos_decrease Motor Position runter (a) +motorcontrol.step_drive Umschalten Schrittsetzungs/Fahr Modus (b) +motorcontrol.store Speichere Motor Position (a) +motorcontrol.step_increase Schrittweite rauf (c) +motorcontrol.step_decrease Schrittweite runter (c) +motorcontrol.goto Gehe zu Motor Position (a) +motorcontrol.notdef Not used +motorcontrol.motor_pos (a) Motor Position: +motorcontrol.settings Motor Einstellungen +motorcontrol.movement (b) Bewegung: +motorcontrol.step_mode Schrittsetzungs Modus +motorcontrol.drive_mode Fahr Modus +motorcontrol.drive_mode_auto Fahr Modus/automatischer Stop +motorcontrol.timed_mode Zeitgesteuerter Schrittweiten Modus +motorcontrol.step_size (c) Schrittweite: +motorcontrol.stop_moving Stope bei guten Signal(moving) +motorcontrol.stop_stopped Stope bei schlechtem Signal(stopped) +motorcontrol.no_mode keine Sorge +motorcontrol.msec Millisekunden +motorcontrol.status Status +motorcontrol.sat_pos Satellitenposition (Step Mode): +mainsettings.timezone Zeitzone +scrambled_channel Verschlüsselung aktiv +neutrino_starting Neutrino wird gestartet... +reset_channels Lösche Kanäle +reset_settings Zurückstellen auf Werkseinstellungen +reset_all Werkseinstellungen zurücksetzen +reset_confirm Sind Sie sich sicher? +cam.settings CI CAM +cam.empty Steckplatz leer +cam.inserted In der Steckplatz befindet sich ein Cam +cam.removed CAM von der Steckplatz entfernt +cam.init_ok CAM Initialisierung vollendet +subtitles.head Untertitel +subtitles.stop Stop Untertitel +favorites.copy Kopiere Bouquet zu Favoriten diff --git a/data/locale/dutch.locale b/data/locale/dutch.locale new file mode 100644 index 000000000..8116729ff --- /dev/null +++ b/data/locale/dutch.locale @@ -0,0 +1,1237 @@ +EPGMenu.epgplus Elec. Programma Gids +EPGMenu.eventinfo Details aktuele uitzending +EPGMenu.eventlist Programma gids aktuele zender +EPGMenu.head EPG - Elec-Programma-Gids +EPGMenu.streaminfo technische informatie +EPGPlus.actions Akties +EPGPlus.bybouquet_mode per bouquet +EPGPlus.bypage_mode per pagina +EPGPlus.change_font_size font grootte +EPGPlus.change_font_style font stijl +EPGPlus.change_size grootte +EPGPlus.channelentry_font kanaal font +EPGPlus.channelentry_separationlineheight afstand tussen de lijnen +EPGPlus.channelentry_width breedte +EPGPlus.channelevententry_font programma font +EPGPlus.edit_fonts edit fonts +EPGPlus.edit_sizes edit afmeting +EPGPlus.font_style_bold stijl bold +EPGPlus.font_style_italic stijl italic +EPGPlus.font_style_regular stijl normaal +EPGPlus.footer_fontbouquetchannelname selekteer bouquet/kanaalnaam +EPGPlus.footer_fontbuttons selekteer buttons +EPGPlus.footer_fonteventdescription selekteer aktuele uitzending +EPGPlus.footer_fonteventshortdescription selekteer verkorte uitzending +EPGPlus.head Programma gids Overzicht (EPG Plus) +EPGPlus.header_font kop font +EPGPlus.horgap1_height hoogte 1 +EPGPlus.horgap2_height hoogte 2 +EPGPlus.next_bouquet volgend bouquet +EPGPlus.options opties +EPGPlus.page_down pagina neer +EPGPlus.page_up pagina op +EPGPlus.prev_bouquet vorig bouquet +EPGPlus.record opnemen +EPGPlus.refresh_epg aktualiseren +EPGPlus.remind Herinnering +EPGPlus.reset_settings reset instellingen +EPGPlus.save_settings sla instellingen op +EPGPlus.scroll_mode Scroll Mode +EPGPlus.select_font_name font naam +EPGPlus.settings instellingen +EPGPlus.slider_width slider breedte +EPGPlus.stretch_mode Uitstrek Mode +EPGPlus.swap_mode swap mode +EPGPlus.timeline_fontdate font datum +EPGPlus.timeline_fonttime font tijd +EPGPlus.vergap1_width breedte 1 +EPGPlus.vergap2_width breedte 2 +EPGPlus.view_mode kijk mode +GENRE.ARTS.0 kunst / kultuur +GENRE.ARTS.1 uitvoerende kunst +GENRE.ARTS.10 kunst/kultuur series +GENRE.ARTS.11 mode +GENRE.ARTS.2 klein kunst +GENRE.ARTS.3 geloof +GENRE.ARTS.4 volks kunst +GENRE.ARTS.5 literatuur +GENRE.ARTS.6 film/bioscoop +GENRE.ARTS.7 experimentele film/video +GENRE.ARTS.8 radio/pers +GENRE.ARTS.9 nieuwe media +GENRE.CHILDRENs_PROGRAMMES.0 kinder / jeugd programma +GENRE.CHILDRENs_PROGRAMMES.1 kleuter programma's +GENRE.CHILDRENs_PROGRAMMES.2 ontwikkelings programma's voor 6 to 14 +GENRE.CHILDRENs_PROGRAMMES.3 ontwikkelings programma's voor 10 to 16 +GENRE.CHILDRENs_PROGRAMMES.4 informatie/educatie/school programma's +GENRE.CHILDRENs_PROGRAMMES.5 teken/poppen +GENRE.DOCUS_MAGAZINES.0 documentatie / series +GENRE.DOCUS_MAGAZINES.1 natuur/dieren/omgeving +GENRE.DOCUS_MAGAZINES.2 technologie/natuur wetenschappen +GENRE.DOCUS_MAGAZINES.3 medisch/physiologie/psychologie +GENRE.DOCUS_MAGAZINES.4 buitenland/expedities +GENRE.DOCUS_MAGAZINES.5 sociale/geestelijke wetenschappen +GENRE.DOCUS_MAGAZINES.6 verdere ontwikkeling +GENRE.DOCUS_MAGAZINES.7 talen +GENRE.MOVIE.0 film/drama +GENRE.MOVIE.1 detective/thriller +GENRE.MOVIE.2 avontuur/western/oorlog +GENRE.MOVIE.3 science fiction/fantasy/horror +GENRE.MOVIE.4 komedie +GENRE.MOVIE.5 soap/melodrama/folklore +GENRE.MOVIE.6 romantiek +GENRE.MOVIE.7 serieus/klassiek/geloof/histories film/drama +GENRE.MOVIE.8 volwassen film/drama +GENRE.MUSIC_DANCE.0 musiek / ballet / dans +GENRE.MUSIC_DANCE.1 rock/pop +GENRE.MUSIC_DANCE.2 serieuze muziek/klassieke muziek +GENRE.MUSIC_DANCE.3 volks/traditionele muziek +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musical/opera +GENRE.MUSIC_DANCE.6 ballet +GENRE.NEWS.0 nieuws +GENRE.NEWS.1 nieuws/weer verslag +GENRE.NEWS.2 nieuws serie +GENRE.NEWS.3 documentatie +GENRE.NEWS.4 discussie/interview/debat +GENRE.SHOW.0 Show / Spelshow +GENRE.SHOW.1 spel show/quiz/wedstrijd +GENRE.SHOW.2 varietee show +GENRE.SHOW.3 praat show +GENRE.SOCIAL_POLITICAL.0 sociaal & politieke evenement / zakelijk +GENRE.SOCIAL_POLITICAL.1 series/verslag/documentaire +GENRE.SOCIAL_POLITICAL.2 economisch/sociaal advies +GENRE.SOCIAL_POLITICAL.3 buitengewone mensen +GENRE.SPORTS.0 sport +GENRE.SPORTS.1 speciale uitzendingen (Olympische Spelen,Wereld Cup etc.) +GENRE.SPORTS.10 equestrian +GENRE.SPORTS.11 vecht sporten +GENRE.SPORTS.2 sport series +GENRE.SPORTS.3 voetbal +GENRE.SPORTS.4 tennis/squash +GENRE.SPORTS.5 team sport (uitgezonderd voetbal) +GENRE.SPORTS.6 athletiek +GENRE.SPORTS.7 motor sport +GENRE.SPORTS.8 water sport +GENRE.SPORTS.9 winter sport +GENRE.TRAVEL_HOBBIES.0 reis & recreatie +GENRE.TRAVEL_HOBBIES.1 tourisme/reisen +GENRE.TRAVEL_HOBBIES.2 handwerken +GENRE.TRAVEL_HOBBIES.3 motor +GENRE.TRAVEL_HOBBIES.4 fitness & gezondheid +GENRE.TRAVEL_HOBBIES.5 koken +GENRE.TRAVEL_HOBBIES.6 advertentie/shopping +GENRE.TRAVEL_HOBBIES.7 tuinieren +GENRE.UNKNOWN onbekend +apids.hint_1 Geef APIDs om te streamen +apids.hint_2 in HEX in gescheiden door ' ' +apidselector.head Selecteer taal +audiomenu.PCMOffset Verlaag Volume PCM +audiomenu.analogout Analoge Output +audiomenu.avs avs +audiomenu.avs_control Volume Kontrole avs/oost +audiomenu.dolbydigital Dolby Digital +audiomenu.head Audio Instellingen +audiomenu.lirc lirc +audiomenu.monoleft mono links +audiomenu.monoright mono rechts +audiomenu.ost oost +audiomenu.stereo stereo +audioplayer.add voegtoe +audioplayer.artist_title Artiest, Titel +audioplayer.building_search_index building search index +audioplayer.button_select_title_by_id zoek op ID +audioplayer.button_select_title_by_name zoek op naam +audioplayer.defdir start dir. +audioplayer.delete verwijder +audioplayer.deleteall verwijder alles +audioplayer.display_order Laat volgorde zien +audioplayer.fastforward snel vooruit. +audioplayer.follow auto selecteer aktuele +audioplayer.head Audio afspeellijst +audioplayer.highprio Hoge decodeeer prioriteit +audioplayer.id3scan Scan ID3 tags +audioplayer.jump_backwards spring terug +audioplayer.jump_dialog_hint1 Geef aub sprong doel in +audioplayer.jump_dialog_hint2 (relatief, in seconden) +audioplayer.jump_dialog_title Geef sprong doel in +audioplayer.jump_forwards spring vooruit +audioplayer.keylevel toets stand +audioplayer.name Audiospeler +audioplayer.pause pause +audioplayer.play Afspelen +audioplayer.playing Aktuele Track +audioplayer.playlist_fileerror_msg File niet gemaakt: +audioplayer.playlist_fileerror_title File fout +audioplayer.playlist_fileoverwrite_msg Wil je deze file overschrijven: +audioplayer.playlist_fileoverwrite_title Titel overschrijven? +audioplayer.playlist_name filenaam van de afspeellijst +audioplayer.playlist_name_hint1 Geef aub de filenaam van de afspeellijst in +audioplayer.playlist_name_hint2 De extensie .m3u wordt aut. toegevoegd +audioplayer.enable_sc_metadata enable shoutcast meta data parsing +audioplayer.repeat_on herhaal mode inschakelen +audioplayer.rewind opnieuw spoelen +audioplayer.save_playlist sla afspeellijst op +audioplayer.screensaver_timeout screensaver timeout (min, 0=off) +audioplayer.select_title_by_name zoek titel bij naam (SMS) +audioplayer.show_playlist Toon afspeellijst +audioplayer.shuffle schudden +audioplayer.stop Stop +audioplayer.title_artist Titel, Artiest +audioplayerpicsettings.general audiospeler / plaatjeskijken +bookmarkmanager.delete wissen +bookmarkmanager.name bookmarks +bookmarkmanager.rename hernoem +bookmarkmanager.select selecteer +bouqueteditor.add voegtoe +bouqueteditor.bouquetname Naam van het bouquet +bouqueteditor.delete wissen +bouqueteditor.discardingchanges Herstel veranderingen. Geduld aub. +bouqueteditor.hide Verberg +bouqueteditor.lock Vergrendel +bouqueteditor.move Beweeg +bouqueteditor.name bouquet bewerker +bouqueteditor.newbouquetname Nieuwe naam van het bouquet +bouqueteditor.rename Hernoem +bouqueteditor.return klaar +bouqueteditor.savechanges? Wil je de veranderingen opslaan? +bouqueteditor.savingchanges Sla veranderingen op. Wacht aub ... +bouqueteditor.switch voegtoe/verwijder +bouqueteditor.switchmode TV/Radio +bouquetlist.head Bouquets +cablesetup.provider kabel provider +channellist.head All Onderhoud +channellist.nonefound Geen kanalen gevonden!\nVoer aub een scan uit\n(DBOX-key -> onderhoud) +channellist.since start tijd %02d:%02d +colorchooser.alpha alpha +colorchooser.blue blauw +colorchooser.green groen +colorchooser.red rood +colormenu.background Achtergrond +colormenu.fade Fade menu's +colormenu.font Font grootte +colormenu.gtx_alpha Transparentie (GTX) +colormenu.head Color Settings +colormenu.menucolors Menukleur +colormenu.statusbar Infobar +colormenu.textcolor Textkleur +colormenu.themeselect selecteer thema +colormenu.timing OSD Timing +colormenusetup.head Menu Kleuren +colormenusetup.menucontent Window-Inhoud +colormenusetup.menucontent_inactive Window-Inhoud inaktief +colormenusetup.menucontent_selected Window-Inhoud selekteren +colormenusetup.menuhead Menu Kop +colorstatusbar.head Infobalk kleur +colorstatusbar.text Infobalk text +colorthememenu.classic_theme Klassiek Thema +colorthememenu.dblue_theme Donkerblauw Thema +colorthememenu.dvb2k_theme DVB2000 Thema +colorthememenu.head Thema Kiezer +colorthememenu.neutrino_theme Neutrino Thema +date.Apr Apr +date.Aug Aug +date.Dec Dec +date.Feb Feb +date.Fri Vrij +date.Jan Jan +date.Jul Jul +date.Jun Jun +date.Mar Maart +date.May Mei +date.Mon Maan +date.Nov Nov +date.Oct Okt +date.Sat Zat +date.Sep Sep +date.Sun Zon +date.Thu Don +date.Tue Dins +date.Wed Woens +epglist.head programma-gids- %s +epglist.noevents EPG niet aanwezig... +epgviewer.More_Screenings Volgend scherm +epgviewer.nodetailed Geen gedetaileerde informatie aanwezig +epgviewer.notfound geen epg gevonden +eventlistbar.channelswitch markeren +eventlistbar.eventsort sorteer +eventlistbar.recordevent neemop +favorites.addchannel Het aktuele kanaal wordt toegevoegd \naan het bouquet"My Favorites".\nDit duurt enkele seconden... +favorites.bouquetname My Favorites +favorites.bqcreated Bouquet "My Favorites" is gemaakt...\n +favorites.chadded Het aktuele Kanaal is aan je favorieten toegevoegd...\n +favorites.chalreadyinbq Het aktuele kanaal is reeds in je Favorieten...\n +favorites.finalhint \nGebruik de bouquet bewerker om je Favorieten aan te passen.\n +favorites.menueadd voeg Kanaal toe aan favorieten +favorites.nobouquets Favorieten zijn alleen beschikbaar bij geactiveerde Bouquets . +filebrowser.delete Wis +filebrowser.denydirectoryleave weiger dir teverlaten +filebrowser.dodelete1 Wis +filebrowser.dodelete2 ? +filebrowser.filter.active Filter aan +filebrowser.filter.inactive Filter uit +filebrowser.head Filebrowser +filebrowser.mark Markeer +filebrowser.nextpage volgende pagina +filebrowser.prevpage vorige pagina +filebrowser.scan Scanning folder +filebrowser.select Selecteer +filebrowser.showrights Toon file rechten +filebrowser.sort.date (datum) +filebrowser.sort.name (filenaam) +filebrowser.sort.namedirsfirst (filenaam2) +filebrowser.sort.size (grootte) +filebrowser.sort.type (type) +flashupdate.actionreadflash Flash lezen +flashupdate.cantopenfile kan de file niet openen +flashupdate.cantopenmtd kan mtd-device niet openen +flashupdate.checkupdate zoek naar nieuwe versie +flashupdate.currentreleasecycle Release cycle +flashupdate.currentversion_sep Aktuele versie +flashupdate.currentversiondate Datum +flashupdate.currentversionsnapshot ImageType +flashupdate.currentversiontime Tijd +flashupdate.erasefailed flash wissen mislukt +flashupdate.erasing flash wissen +flashupdate.experimentalimage De geselecteerde image is een ongeteste versie,dit betekend\nbootup van de Box kan mislukken na update.\n\nWilt U werkelijk updaten naar deze versie? +flashupdate.expertfunctions Expert-functies +flashupdate.fileis0bytes De filegrootte is 0 Bytes +flashupdate.fileselector File-Kiezer +flashupdate.flashreadyreboot De image was succesvol geflashed.\nDe ruDbox gaat nu herstarten. +flashupdate.getinfofile haal versie info op +flashupdate.getinfofileerror Kan versie info niet ophalen +flashupdate.getupdatefile haal update file op +flashupdate.getupdatefileerror kan update niet ophalen +flashupdate.globalprogress voortgang: +flashupdate.head Software Update +flashupdate.md5check Image testen +flashupdate.md5sumerror Image heeft fouten +flashupdate.msgbox Volgende nieuwe image gevonden:\nDate: %s, %s\nBaseImage: %s\nImageType: %s\n\nWil je deze versie nu downloaden en installeren? +flashupdate.msgbox_manual De volgende nieuwe file gevonden:\nDate: %s, %s\nBaseImage: %s\nType: %s\n\nWil je deze versie nu installeren? +flashupdate.mtdselector Partition-Kiezer +flashupdate.programmingflash Flash programmeren +flashupdate.proxypassword Paswoord +flashupdate.proxypassword_hint1 geef de proxyserver paswoord in +flashupdate.proxypassword_hint2 niets ingeven betekend geen proxy-auth. +flashupdate.proxyserver Hostname +flashupdate.proxyserver_hint1 geef proxyserver naam of ip in, gebruik host:port +flashupdate.proxyserver_hint2 niets ingeven betekent geen proxy +flashupdate.proxyserver_sep Proxyserver +flashupdate.proxyusername Gebruikersnaam +flashupdate.proxyusername_hint1 geef de proxyserver gebruikersnaam in +flashupdate.proxyusername_hint2 niets ingeven betekent geen proxy-auth. +flashupdate.readflash Lees hele image +flashupdate.readflashmtd lees een partitie +flashupdate.ready ready +flashupdate.reallyflashmtd Wil je werkelijk flashen?\n\nAls een fout optreed of de image is niet\ngeldig, de Box wil niet booten na het flashen.\n\nImagenaam: %s\nTarget: %s +flashupdate.savesuccess De image was succesvol opgeslagen \nonder %s. +flashupdate.selectimage Beschikbare Images/Files +flashupdate.squashfs.noversion SquashFS versie test momenteel alleen ondersteund bij update via het Web.\nWeet je zeker dat je deze image wilt installeren? +flashupdate.titlereadflash Flash lezen +flashupdate.titlewriteflash Flash schrijven +flashupdate.updatemode Update mode +flashupdate.updatemode_internet internet +flashupdate.updatemode_manual handmatig (ftp) +flashupdate.url_file config file +flashupdate.versioncheck test versie +flashupdate.writeflash schrijf hele image +flashupdate.writeflashmtd schrijf een partitie +flashupdate.wrongbase Your Release cycle differs.\nTo continue? +fontmenu.channellist Kanalen lijst +fontmenu.epg EPG +fontmenu.eventlist Programma gids +fontmenu.gamelist Spelen lijst +fontmenu.head Fontgrootte instellen +fontmenu.infobar Infobar +fontsize.channel_num_zap directe selectie +fontsize.channellist Kanalen lijst +fontsize.channellist_descr Beschrijving +fontsize.channellist_number Nummer +fontsize.epg_date EPG Datum +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Titel +fontsize.eventlist_datetime datum / tijd +fontsize.eventlist_itemlarge groot +fontsize.eventlist_itemsmall klein +fontsize.eventlist_title Titel +fontsize.filebrowser_item filebrowser item +fontsize.gamelist_itemlarge groot +fontsize.gamelist_itemsmall klein +fontsize.hint Initialiseer font,\naub wachten... +fontsize.infobar_channame Kanaal naam +fontsize.infobar_info info +fontsize.infobar_number Nummer +fontsize.infobar_small klein +fontsize.menu Menutext +fontsize.menu_info Menu Info +fontsize.menu_title Menu Titel +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.epgnotload EPG niet geladen.... +infoviewer.epgwait wacht op EPG... +infoviewer.eventlist Prg,s overzicht +infoviewer.languages Talen +infoviewer.motor_moving Motor aan het werk +infoviewer.nocurrent Geen info over aktueel programma beschikbaar +infoviewer.noepg EPG niet beschikbaar +infoviewer.notavailable Kanaal niet beschikbaar +infoviewer.selecttime Tijd kiezen +infoviewer.streaminfo Stream info +infoviewer.subservice Subservices +infoviewer.waittime Wacht op de tijd... +ipsetup.hint_1 Benut 0..9, of benut Op/Neer, +ipsetup.hint_2 OK slaat op, HOME breektaf +keybindingmenu.RC Key repeat-blocker +keybindingmenu.addrecord voeg record timer toe +keybindingmenu.addremind voeg zapto timer toe +keybindingmenu.allchannels_on_ok alle-kanalen +keybindingmenu.bouquetchannels_on_ok aktueel bouquet +keybindingmenu.bouquetdown bouquet terug +keybindingmenu.bouquethandling Bouquet-control +keybindingmenu.bouquetlist_on_ok bouquet-lijst +keybindingmenu.bouquetup volgende bouquet +keybindingmenu.cancel Kanalen lijst sluiten +keybindingmenu.channeldown kanaal omlaag +keybindingmenu.channellist kanalen lijst +keybindingmenu.channelup kanaal omhoog +keybindingmenu.head Toetsen Aanpassen +keybindingmenu.lastchannel Laatste kanaal +keybindingmenu.modechange Mode's wissel +keybindingmenu.pagedown pagina omlaag +keybindingmenu.pageup pagina omhoog +keybindingmenu.quickzap Vlug zappen +keybindingmenu.repeatblock herhaal vertraging +keybindingmenu.repeatblockgeneric begin vertraging +keybindingmenu.sort verander sorteer volgorde +keybindingmenu.subchanneldown subkanaal omlaag +keybindingmenu.subchannelup subkanaal omhoog +keybindingmenu.tvradiomode TV/Radio-mode +keybindingmenu.zaphistory Zap History Bouquet +keychooser.head verander Toets +keychooser.text1 Druk aub de nieuwe toets +keychooser.text2 wacht een paar seconden op abort +keychoosermenu.currentkey aktuele toets +keychoosermenu.setnew setup nieuwe toets +keychoosermenu.setnone geen toets +languagesetup.head Taal Keuze +languagesetup.select Taal +lcdcontroler.brightness normale Helderheid +lcdcontroler.brightnessstandby Standby Helderheid +lcdcontroler.contrast Kontrast +lcdcontroler.head LCD Instellingen +lcdmenu.autodimm Auto dimmer +lcdmenu.head LCD Instellingen +lcdmenu.inverse Omgekeerd +lcdmenu.lcdcontroler Kontrast / Helderheid +lcdmenu.power Verlichting +lcdmenu.statusline status lijn +lcdmenu.statusline.both volume / speelduur +lcdmenu.statusline.playtime speelduur +lcdmenu.statusline.volume volume +mainmenu.audioplayer Audiospeler +mainmenu.games Spellen +mainmenu.head Hoofd Menu +mainmenu.movieplayer Filmspeler +mainmenu.pausesectionsd Lees EPG +mainmenu.pictureviewer Plaatjeskijker +mainmenu.radiomode Radio-Mode +mainmenu.recording Opnemen +mainmenu.recording_start start +mainmenu.recording_stop stop +mainmenu.scartmode Scart-Mode +mainmenu.service Onderhoud +mainmenu.settings Instellingen +mainmenu.shutdown Uitzetten +mainmenu.sleeptimer SleepTimer +mainmenu.tvmode TV-Mode +mainsettings.audio Audio +mainsettings.colors Kleur / thema / font +mainsettings.head Instellingen +mainsettings.keybinding Toets Aanpassen +mainsettings.language Taal +mainsettings.lcd LC-Display +mainsettings.misc Diverse instellingen +mainsettings.network Netwerk +mainsettings.recording Opnemen +mainsettings.savesettingsnow sla instellingen nu op +mainsettings.savesettingsnow_hint Sla instellingen op,\nwacht aub... +mainsettings.streaming Filmspeler +mainsettings.video Video +menu.back terug +messagebox.back terug +messagebox.cancel herroep +messagebox.discard Niet uitvoeren? +messagebox.error Fout +messagebox.info Informatie +messagebox.no Nee +messagebox.yes Ja +miscsettings.bootinfo Toon info bij start +miscsettings.bootmenu Toon boot menu +miscsettings.driver_boot driver en boot opties +miscsettings.fb_destination Expert! Boot-Console +miscsettings.general Algemeen +miscsettings.head Diverse instellingen +miscsettings.hwsections hardware secties gebruiken +miscsettings.infobar_sat_display Satelliet display op infobar +miscsettings.pmtupdate enable pmt update +miscsettings.shutdown_real Schakel standby in +miscsettings.shutdown_real_rcdelay Vertraagde shutdown +miscsettings.sptsmode gebruik spts mode +miscsettings.startbhdriver laad BH-Mode drivers +motorcontrol.head Motor-Setup +movieplayer.bookmark Bookmarks +movieplayer.bookmarkname Bookmarknaam +movieplayer.bookmarkname_hint1 Geef een naam in voor je nieuwe bookmark +movieplayer.bookmarkname_hint2 +movieplayer.buffering Buffering... +movieplayer.defdir start dir. +movieplayer.dvdplayback DVD +movieplayer.fileplayback File via VLC +movieplayer.goto Spring naar ... +movieplayer.goto.h1 = -> absolute sprong +movieplayer.goto.h2 +,- -> relative sprong +movieplayer.head Filmspeler +movieplayer.nostreamingserver De stream server niet te bereiken. +movieplayer.pesplayback Speel PES (Experimenteel) +movieplayer.pleasewait Aub wachten.\nVerbind met stream server... +movieplayer.toomanybookmarks Er zijn teveel bookmarks.\nWis er eerst een van. +movieplayer.tsplayback Speel TS +movieplayer.vcdplayback (S)VCD +movieplayer.wrongvlcversion Deze functie wordt niet ondersteund door deze versie van VLC +networkmenu.broadcast Broadcast +networkmenu.dhcp DHCP +networkmenu.gateway default gateway +networkmenu.head Netwerk Instellingen +networkmenu.ipaddress IP adres +networkmenu.mount NFS/CIFS +networkmenu.nameserver server naam +networkmenu.netmask netmask +networkmenu.setupnow netwerk veranderingen uitvoeren +networkmenu.setuponstartup netwerk bij startup +networkmenu.show Toon actief netwerk instellingen +networkmenu.test test netwerk nu +nfs.alreadymounted directory reeds gemounted +nfs.automount mount bij startup +nfs.dir directory/share +nfs.ip NFS/CIFS Server IP +nfs.localdir local dir +nfs.mount Mount NFS/CIFS volume +nfs.mount_options mount opties +nfs.mounterror mount fout +nfs.mounterror_notsup filesysteem type niet ondersteund +nfs.mountnow mount nu +nfs.mounttimeout mount fout: timeout +nfs.password CIFS paswoord +nfs.remount remount directories +nfs.type type +nfs.type_cifs CIFS +nfs.type_nfs NFS +nfs.umount Unmount NFS/CIFS volume +nfs.umounterror unmounting volume fout +nfs.username CIFS gebruikersnaam +nfsmenu.head NFS/CIFS instellingen +nvod.percentage (%d%% over) +nvod.starting (start in %d min) +nvodselector.directormode Director-Mode +nvodselector.head Selecteer start-tijd +nvodselector.subservice Selecteer Subservice +options.default Reset naar defaults +options.fb framebuffer +options.null nul +options.off uit +options.on aan +options.serial serieel +parentallock.changepin verander PIN code +parentallock.changepin_hint1 Geef de nieuwe jeugd-bescherm pin code hier in! +parentallock.changetolocked bij gesloten bouquets +parentallock.head Geef Lock PIN code in +parentallock.lockage gesloten programma's +parentallock.lockage12 tot aan 12 jaar +parentallock.lockage16 tot aan 16 jaar +parentallock.lockage18 tot aan 18 jaar +parentallock.lockedchannel gelockt kanaal... +parentallock.lockedprogram GeLockt programma (tot aan %d jaar) +parentallock.never nooit +parentallock.onsignal bij uitgezending lock +parentallock.parentallock Jeugd bescherming +parentallock.prompt prompt voor PIN +pictureviewer.defdir start dir. +pictureviewer.head Plaatjes kijker +pictureviewer.resize.color_average uitvoerig +pictureviewer.resize.none niet +pictureviewer.resize.simple eenvoudig +pictureviewer.scaling scaling +pictureviewer.show Tonen +pictureviewer.slide_time diashow speel duur +pictureviewer.slideshow diashow +pictureviewer.sortorder verander sorteer volgorde +pictureviewer.sortorder.date (datum) +pictureviewer.sortorder.filename (filenaam) +ping.ok is bereikbaar (ping) +ping.protocol is onbereikbaar (host of protocol fout) +ping.socket is onbereikbaar (socket fout) +ping.unreachable is onbereikbaar +pinprotection.head Geef PIN code in +pinprotection.wrongcode PIN-Code was verkeerd! Probeer opnieuw. +rclock.lockmsg Je ruDbox A-fstand B-ediening is vergrendeld.\nOm je A-B te ontgrendelen, druk en \nop je A-fstand B-ediening. +rclock.menueadd Vergrendel A-B +rclock.title Vergrendel Afstand Bediening +rclock.unlockmsg A-fstand B-ediening gereactiveerd. +recordingmenu.defdir opneem directory +recordingmenu.file direct (file) +recordingmenu.head Opneem instellingen +recordingmenu.help Recording devices:\n--------------------------\nserver:\ngebruik stream software op een PC\n\n(analoog) vcr:\ngebruik de vcr uitgang\n\ndirect (file):\ndirect in een NFS mounted directory\nof op een interne hard disk\nTS: gebruik spts mode(dbox2)\nPES: niet spts mode(dbox2) gebruiken\n\n\nMax. file grootte:\n---------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: bijna ongelimiteerd (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart onderdruk scart mode schakelen +recordingmenu.off uit +recordingmenu.recording_type opneem device +recordingmenu.server server +recordingmenu.server_ip opneem server IP +recordingmenu.server_mac MAC adres +recordingmenu.server_port opneem server poort +recordingmenu.server_wakeup opneem server WOL +recordingmenu.setupnow activeer veranderingen nu +recordingmenu.splitsize Max. file grootte (MB) +recordingmenu.stopplayback stop terug spelen +recordingmenu.stopsectionsd stop sectionsd +recordingmenu.stream_vtxt_pid neem videotext op +recordingmenu.use_o_sync schrijf synchroon (O_SYNC) +recordingmenu.vcr vcr +recordtimer.announce Opname start over enkele minuten +repeatblocker.hint_1 Kortste tijd (in ms) tussen 2 toets aanslagen +repeatblocker.hint_2 0 schakeld de blocker uit (rood is space) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-herhalingen +satsetup.extended DiSEqC-Instellingen +satsetup.extended_motor Motor-Instellingen +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Motor handmatig instellen +satsetup.nodiseqc geen DiSEqC +satsetup.satellite Satelliet +satsetup.savesettingsnow sla instellingen nu op +satsetup.smatvremote SMATV Remote Tuning +scants.actcable Kabel: +scants.actsatellite Satelliet: +scants.bouquet Bouquet +scants.bouquet_create creeer nieuw +scants.bouquet_erase wissen +scants.bouquet_leave niet veranderen +scants.bouquet_satellite Satelliet-Bouquet +scants.bouquet_update update +scants.channel kanaal: +scants.failed Transponderscan mislukt! +scants.finished Transponderscan succesvol beeindigd! +scants.freqdata Frequentie: +scants.head Scan transponder +scants.numberofdataservices Data +scants.numberofradioservices Radio +scants.numberoftotalservices Totaal +scants.numberoftvservices TV +scants.provider Provider: +scants.startnow start scan +scants.transponders Transponders: +screensetup.lowerright groen = rechts onder instellen +screensetup.upperleft rood = links boven instellen +servicemenu.head Onderhoud +servicemenu.reload lees kanaallijst opnieuw in +servicemenu.reload_hint Lees kanaallijst opnieuw in,\ngeduld aub. +servicemenu.scants Scan onderhouden +servicemenu.ucodecheck Check ucodes +servicemenu.update Software Update +settings.help Help +settings.missingoptionsconffile De neutrino-instellingen zijn geupdated.\nNieuwe opties worden op default gezet. +settings.noconffile Geen neutrino-instellingen gevonden.\nGebruik default. +shutdowntimer.announce Box gaat shutdown over 1 min.\nShutdown afbreken? +sleeptimerbox.announce Sleeptimer over 1 min +sleeptimerbox.hint1 Shutdown tijd in min. (000=uit) +sleeptimerbox.hint2 De ruDbox gaat shutdown na deze tijd. +sleeptimerbox.title Sleeptimer +streamfeatures.head Features +streaminfo.aratio verhouding +streaminfo.aratio_unknown verhoudig: onbekend +streaminfo.audiotype Audiotype +streaminfo.audiotype_unknown Audiotype: onbekend +streaminfo.bitrate Bitrate +streaminfo.framerate Framerate +streaminfo.framerate_unknown Framerate: onbekend +streaminfo.head Stream-Informatie +streaminfo.not_available niet beschikbaar +streaminfo.resolution Resolutie +streaminfo.signal Ontvangst signaal +streaming.buffer_overflow De opname is helaas afgebroken,\nomdat de data niet snel genoeg geschreven kon worden. +streaming.busy Een of meerdere opneem processen zijn aktief.\nAls je dit bericht krijgt en geen opname is aktief,\nherstart Neutrino aub. +streaming.dir_not_writable De opneem directory is niet beschrijfbaar.\nOpname zal niet gaan. +streaming.success De opname is succesvol beeindigd. +streaming.write_error De opname was afgebroken,\nomdat er een fout optrad gedurende het schrijven. +streaming.write_error_open De opname is afgebroken,\nomdat de file niet geopend kon worden. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Filmspeler Instellingen +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off uit +streamingmenu.on aan +streamingmenu.server_ip Streamserver IP +streamingmenu.server_port Streamserver Poort +streamingmenu.streaming_audiorate Datarate Audio +streamingmenu.streaming_force_avi_rawaudio Forceeer AC3 bij AVI +streamingmenu.streaming_force_transcode_video Transcode MPG/VCD video +streamingmenu.streaming_resolution Resolutie +streamingmenu.streaming_server_cddrive DVD Drive +streamingmenu.streaming_server_startdir Directory (VLC) +streamingmenu.streaming_transcode_audio Transcode audio (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec MPEG video codec +streamingmenu.streaming_type Streamserver +streamingmenu.streaming_videorate Datarate Video +streamingserver.noconnect Geen verbinding met streamserver.\nOpname gestopt +stringinput.caps Hoofd- / kleine letters +stringinput.clear alles schoonmaken +timer.eventrecord.msg ... DOEN, of LATEN +timer.eventrecord.title Markeer uitzending +timer.eventtimed.msg De uitzending is gemarkeerd.\nDe ruDbox zal aan gaan en\nnaar dit kanaal schakelen op de aangegeven tijd. +timer.eventtimed.title Uitzending markeren +timerbar.channelswitch markeren +timerbar.recordevent Opnemen +timerlist.alarmtime Alarm tijd +timerlist.apids Audio PIDs +timerlist.bouquetselect kies bouquet +timerlist.channel Kanaal +timerlist.channelselect kies kanaal +timerlist.delete Wis +timerlist.menumodify Pas timer aan +timerlist.menunew Nieuwe timer +timerlist.message Bericht +timerlist.moderadio Radio kanalen +timerlist.modeselect Mode kiezen +timerlist.modetv TV kanalen +timerlist.modify Pas aan +timerlist.name Timer lijst +timerlist.new Nieuwe timer +timerlist.program.unknown Onbekend programma +timerlist.reload Herladen +timerlist.repeat Herhaal +timerlist.repeat.biweekly twee wekelijks +timerlist.repeat.byeventdescription zie timer +timerlist.repeat.daily dagelijks +timerlist.repeat.fourweekly vier wekelijks +timerlist.repeat.friday Vrij +timerlist.repeat.monday Maan +timerlist.repeat.monthly maandelijks +timerlist.repeat.once eens +timerlist.repeat.saturday Zat +timerlist.repeat.sunday Zon +timerlist.repeat.thursday Don +timerlist.repeat.tuesday Dins +timerlist.repeat.unknown onbekend +timerlist.repeat.wednesday Woens +timerlist.repeat.weekdays door de week +timerlist.repeat.weekly wekelijks +timerlist.save Save timer +timerlist.standby SB mode +timerlist.standby.off Leave standby +timerlist.standby.on Enter standby +timerlist.stoptime Stop tijd +timerlist.type Timer type +timerlist.type.nextprogram volgend programma +timerlist.type.record Neemop +timerlist.type.remind Herinner +timerlist.type.shutdown Shutdown +timerlist.type.sleeptimer Sleeptimer +timerlist.type.standby Standby +timerlist.type.unknown Onbekend +timerlist.type.zapto Zap naar +timerlist.weekdays Dagen van de week +timerlist.weekdays.hint_1 Maan Dins Woens Don Vrij Zat Zon +timerlist.weekdays.hint_2 'X'=timer '-' geen timer +timersettings.record_safety_time_after Opname stop tijd correctie +timersettings.record_safety_time_after.hint_1 Correctie tijd in min. (00=uit). Deze tijd +timersettings.record_safety_time_after.hint_2 word opgeteld bij de stop tijd van elke opname timer. +timersettings.record_safety_time_before Opname start tijd correctie +timersettings.record_safety_time_before.hint_1 Correctie tijd in min. (00=uit). Deze tijd +timersettings.record_safety_time_before.hint_2 word afgetrokken van elke opname timer. +timersettings.separator Timer instellingen +timing.chanlist Kanaallijst +timing.epg Epg +timing.filebrowser Filebrowser +timing.head OSD Timeouts +timing.hint_1 Tijd in sec. Na deze tijd zal de +timing.hint_2 infobar wegfaden. +timing.infobar Infobar +timing.menu Menu +timing.numericzap Nummer Zap +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head UCode check +ucodecheck.ucode UCode +ucodes.failure ATTENTIE, µCodes NIeT gevonden!\n\nAub uploaden via FTP (of DBox-BootManager),\nen herstart je ruDbox! +videomenu.csync sync correctie +videomenu.head Video Instellingen +videomenu.rgb_centering RGB centrering +videomenu.screensetup Scherm aanpassen +videomenu.vcrswitch Schakel Scart automatisch +videomenu.videoformat Formaat +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect autodetecteer +videomenu.videosignal VideoOutput +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce Zap naar timer in een minute +extra.auto Auto +extra.valid Valid +extra.all Alles +extra.new_keys Nieuwe keys +extra.all_keys Alle keys +extra.vartmp /var/tmp +extra.varkeys /var/keys +extra.algo Algo pids +extra.gbox_emu Emu +extra.gbox_softcam Softcam +extra.gbox_net Netwerk +extra.gbox_mix Mixed +extra.gbox_info Gbox Info +extra.sep_extra Extras +extra.save_settings Sla Instellingen op +extra.extra_menu Addons +extra.ecm_info Ecm Info +extra.pid_info Pid Info +extra.emm_info New Keys +extra.emu_type Emu Type +extra.camd Camd +extra.restart_camd Herstart camd +extra.mg_settings Mgcamd instellingen +extra.netmode Netmode +extra.autoupdate Autoupdate +extra.show_ecm Toon Ecm +extra.show_emm Toon Emm +extra.keyupdate Key update +extra.osd OSD +extra.keyfolder Key dir +extra.hash_pids Hash pids +extra.gbox_settings Gbox instellingen +extra.gbox_mode Mode +extra.newcamd_settings Newcamd instellingen +extra.show_cw Toon CW +extra.debug_ecm Debug Ecm +extra.disable_cam Disable CAM +extra.show_cat Toon CAT +extra.show_pmt Toon PMT +extra.update_pmt Update PMT +extra.report_emm Meld verkeerd EMM sig. +extra.debug_emm Debug Emm +extra.show_allca Toon alle ca sys. +extra.reload_keys Herlaad keys bij zap +extra.reload_cfg Herlaad config bij zap +extra.cw_delay Default CW delay +extra.dvbsnoop DVB Stream Info +extra.dvbsnoop_pat Toon PAT +extra.dvbsnoop_cat Toon CAT +extra.dvbsnoop_tsdt Toon TSDT +extra.dvbsnoop_nit Toon NIT +extra.dvbsnoop_sdt Toon SDT +extra.dvbsnoop_eit Toon EIT +extra.dvbsnoop_rst Toon RST +extra.dvbsnoop_tdt Toon TDT +extra.dvbsnoop_sit Toon SIT +extra.dvbsnoop_pid Toon manual PID +extra.dvbsnoop_scan Scan PIDs +extra.dvbsnoop_band Toon pid bandbreedte +extra.logview Bekijk Log +extra.ru ruDREAM +extra.english Engels +extra.dboxinfo Box Info +extra.scan_mode Scan mode +extra.start_tostandby Start tot standby +extra.rotor_swap Swap rotor oost/west +extra.use_log Log to /tmp/log +extra.spts_mode SPTS mode +extra.hw_sect Hardware Secties +extra.logo Logo nummer +extra.scan_full vol +extra.scan_fast snel +extra.hdd_slow langzaam +extra.hdd_middle Middel +extra.hdd_fast Snel +extra.hdd_ext3 Ext3fs +extra.hdd_reiser Reiserfs +extra.hdd_1min 1 min. +extra.hdd_5min 5 min. +extra.hdd_10min 10 min. +extra.hdd_20min 20 min. +extra.hdd_30min 30 min. +extra.hdd_60min 60 min. +extra.logo1 1 +extra.logo2 2 +extra.logo3 3 +extra.hdd_sleep Sleep time +extra.hdd_noise Lawaai +extra.hdd_activate Activeer instellingen +extra.hdd_fs Filesysteem +extra.hdd_format Formateer HDD +extra.hdd_check Check filesysteem +extra.hdd_settings HDD instellingen +extra.clear_log Clear Log +extra.zap_cycle Zap cyclus +extra.sms_channel sms-kanaal +extra.manual_scan Manuele scan +extra.tp_freq Frequentie +extra.tp_rate Symbol rate +extra.tp_pol Polarisatie +extra.tp.pol_v V +extra.tp_pol_h H +extra.tp_fec FEC +extra.fec_1_2 1/2 +extra.fec_2_3 2/3 +extra.fec_3_4 3/4 +extra.fec_5_6 5/6 +extra.fec_7_8 7/8 +extra.timezone Tijd zone +extra.zapit_menu Zapit opties +extra.zapit_make_bouquet Maak bouquet +extra.zapit_save_last_chan Sla laatste kanaal op +extra.zapit_motor_speed Motor snelheid (10 = 1 graad/sec) +extra.zapit_fe_timeout Timeout melodie +extra.add_to_bouquet voeg to aan bouquet +extra.key_list_start begin +extra.key_list_end einde +extra.chadded het aktuele kanaal is aanhet geselecteerde buoquet toegevoegd.....\n +extra.chalreadyinbq het aktuele kanaal is reeds in het geselecteerde bouquet....\n +extra.menu_left_exit "Left" = terug in menu +extra.zapit_write_names Schrijf Kanaal namen +extra.update_dir Directory for updates +extra.cache Cache +extra.debug Debug +extra.zapit_backup Backup channels to /tmp +extra.zapit_delete Delete channels +extra.zapit_fast_zap fast zap +extra.zapit_restore Restore channels from /tmp +extra.zapit_sort_names Sort ch. by name +filesystem.is.utf8 file system +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +infoviewer.subchan_disp_pos Subchannel display +mainmenu.scripts Scripts +miscsettings.noaviawatchdog enable AVIA watchdog +miscsettings.noenxwatchdog enable eNX watchdog +movieplayer.defplugin Start-Plugin +movieplayer.tshelp1 Stop +movieplayer.tshelp10 approx. 10 minutes back +movieplayer.tshelp11 skip approx. 10 minutes +movieplayer.tshelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Select audio track +movieplayer.tshelp3 Pause/Continue +movieplayer.tshelp4 Create bookmark +movieplayer.tshelp5 Show progress +movieplayer.tshelp6 approx. 1 minute back +movieplayer.tshelp7 skip approx. 1 minute +movieplayer.tshelp8 approx. 5 minutes back +movieplayer.tshelp9 skip approx. 5 minutes +movieplayer.vlchelp1 Stop +movieplayer.vlchelp10 approx. 10 minutes back +movieplayer.vlchelp11 skip approx. 10 minutes +movieplayer.vlchelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Resync +movieplayer.vlchelp3 Pause/Continue +movieplayer.vlchelp4 Create bookmark +movieplayer.vlchelp5 Show progress +movieplayer.vlchelp6 approx. 1 minute back +movieplayer.vlchelp7 skip approx. 1 minute +movieplayer.vlchelp8 approx. 5 minutes back +movieplayer.vlchelp9 skip approx. 5 minutes +nfs.mountok mount successful +nfs.type_lufs FTPFS +pictureviewer.help1 menu mode +pictureviewer.help10 show mode +pictureviewer.help11 reread image +pictureviewer.help12 previous image +pictureviewer.help13 next image +pictureviewer.help14 Zoom out +pictureviewer.help15 Zoom in +pictureviewer.help16 scroll up +pictureviewer.help17 scroll left +pictureviewer.help18 scroll right +pictureviewer.help19 scroll down +pictureviewer.help2 display image +pictureviewer.help20 change sort order +pictureviewer.help21 reread image (no scaling) +pictureviewer.help22 exit +pictureviewer.help3 change sort order +pictureviewer.help4 do not scale picture +pictureviewer.help5 diashow mode +pictureviewer.help6 previous image +pictureviewer.help7 next image +pictureviewer.help8 change sort order +pictureviewer.help9 exit +plugins.result plugin output +recordingmenu.choose_direct_rec_dir choose dir on imm. recording +recordingmenu.epg_for_filename long filenames (with EPG data) +recordingmenu.filesettings direct recording settings +recordingmenu.ringbuffers no. of ringbuffers +recordingmenu.use_fdatasync write synchronous (fdatasync) +settings.pos_bottom_left bottom left +settings.pos_bottom_right bottom right +settings.pos_top_left oben top left +settings.pos_top_right oben top right +timerlist.plugin Plugin +timerlist.recording_dir recording directory +timerlist.repeatcount repeats +timerlist.repeatcount.help1 amount of timer repeats +timerlist.repeatcount.help2 0 for unlimited repeats +timerlist.type.execplugin Execute plugin +audioplayer.reading_files reading files +pictureviewer.decode_server_ip decode server ip +pictureviewer.decode_server_port decode server port +scants.abort_body Should the search really be aborted? +scants.abort_header Onderbreek Scan +recordingmenu.record_in_spts_mode switch to spts mode before recording +servicemenu.getplugins Reload plugins +servicemenu.getplugins_hint Reloading plugins,\nplease be patient. +zapit.scantype scan for services +zapit.scantype.all all services +zapit.scantype.radio only radio +zapit.scantype.tv only tv +zapit.scantype.tvradio tv & radio +colorthememenu.red_theme Simply Red +lcdmenu.dim_brightness Brightness after dim timeout +lcdmenu.dim_time Dim timeout +timerlist.overlapping_timer Timer conflict. Create the timer anyway? +extra.audio_run_player Audio key start player +mpkey.rewind Rewind +mpkey.forward Forward +mpkey.pause Pause +mpkey.stop Stop +mpkey.play Play +mpkey.audio Audio track +mpkey.time Show time +mpkey.bookmark save bookmark +mpkey.plugin Run plugin +extra.key_click Key click +extra.loadcolors Load colors from +extra.savecolors Save colors as +extra.loadkeys Load keys from +extra.savekeys Save keys as +extra.loadconfig Load settings from +extra.saveconfig Save settings as +videomenu.videomode Video system +videomenu.videomode_ntsc NTSC +videomenu.videomode_pal PAL +videomenu.videomode_palm PAL-M +extra.key_timeshift Timeshift +extra.key_plugin One touch plugin +extra.timeshift_pause Timeshift pause +rfmod.rfmod RF modulator +rfmod.carrier Subcarrier Frequency +rfmod.carrier4500 4.5 +rfmod.carrier5500 5.5 +rfmod.carrier6000 6.0 +rfmod.carrier6500 6.5 +rfmod.enable Enable sound +rfmod.channel Channel +rfmod.finetune Fine tune +rfmod.standby Enable modulator +rfmod.test Test pattern +extra.zapit_scanpids Scan/Use pids +extra.zapit_rezap_time Re-Zap on emu switch time +extra.zapit_hvoltage High (13.5/18.5) voltage +extra.key_unlock Unlock key +extra.mg_netoptions Network options +extra.mg_ecm_timeout Network ecm timeout +extra.mg_reconnect Shares reconnect +extra.mg_priority Share priority +extra.mg_osd_options Osd options +extra.mg_reread Reread files on zap +servicemenu.imageinfo Image info +imageinfo.creator Creator: +imageinfo.date Date: +imageinfo.dokumentation Docs: +imageinfo.forum Forum: +imageinfo.head Image info: +imageinfo.homepage Home page: +imageinfo.image Image: +imageinfo.license License: +imageinfo.version Version: +extra.cache_txt Cache teletext +extra.use_gotoxx Use gotoXX +extra.latitude Latitude +extra.longitude Longitude +extra.ladirection LaDirection +extra.lodirection LoDirection +extra.south South +extra.north North +extra.east East +extra.west West +epgextended.actors Actors +epgextended.director Director +epgextended.guests Guests +epgextended.original_title Original Title +epgextended.presenter Presenter +epgextended.year_of_production Year of Production +recordingmenu.save_in_channeldir Save in channel dir +servicemenu.restart Soft restart +servicemenu.restart_failed Restart failed +servicemenu.restart_hint Restarting, please wait +servicemenu.restart_refused_recording Cant restart, recording in progress +extra.cs Cardserver +extra.restart_cs Restart cardserver +extra.tp_mod Modulation +extra.tp_mod_16 QAM/16 +extra.tp_mod_32 QAM/32 +extra.tp_mod_64 QAM/64 +extra.tp_mod_128 QAM/128 +extra.tp_mod_256 QAM/256 +moviebrowser.book_head Bookmarks +moviebrowser.book_lastmoviestop Last play stop: +moviebrowser.book_movieend Movie end: +moviebrowser.book_moviestart Movie start: +moviebrowser.book_name Name: +moviebrowser.book_new New Bookmark +moviebrowser.book_position Position: +moviebrowser.book_type Jump (<0 back , >0 for): +moviebrowser.book_type_backward Repeat +moviebrowser.book_type_forward jump over +moviebrowser.edit_book Bookmark change +moviebrowser.edit_book_name_info1 Enter new Bookmark name +moviebrowser.edit_book_name_info2 +moviebrowser.edit_book_pos_info1 Enter new Position (s) +moviebrowser.edit_book_pos_info2 +moviebrowser.edit_book_type_info1 Enter new jump length (s) +moviebrowser.edit_book_type_info2 <0 back , >0 for, 0: none +moviebrowser.edit_serie Enter name of serie +moviebrowser.error_no_movies No movies found +moviebrowser.foot_filter Filter: +moviebrowser.foot_play Start movie +moviebrowser.foot_sort Sort: +moviebrowser.head TS MovieBrowser +moviebrowser.head_filter Filter movies by category: +moviebrowser.head_playlist Last played: +moviebrowser.head_recordlist Last recorded: +moviebrowser.hint_jumpbackward Jump back in 5 s\n '0' to cancel +moviebrowser.hint_jumpforward Jump forward in 5 s\n '0' to cancel +moviebrowser.hint_movieend Filmende in 5 s\n '0' zum weitersehen +moviebrowser.hint_newbook_backward New jump back\n 'blue' for endposition +moviebrowser.hint_newbook_forward New jump forward\n 'blue' for endposition +moviebrowser.info_audio Audio +moviebrowser.info_channel Channel +moviebrowser.info_filename Name +moviebrowser.info_genre_major Genre +moviebrowser.info_genre_minor Genre +moviebrowser.info_head Film Informationen +moviebrowser.info_info1 Info 1 +moviebrowser.info_info2 Info 2 +moviebrowser.info_length Length (Min) +moviebrowser.info_parental_lockage Parental Lock age +moviebrowser.info_parental_lockage_0year always +moviebrowser.info_parental_lockage_12year 12 years +moviebrowser.info_parental_lockage_16year 16 years +moviebrowser.info_parental_lockage_18year 18 years +moviebrowser.info_parental_lockage_6year 6 years +moviebrowser.info_parental_lockage_always never +moviebrowser.info_path Path +moviebrowser.info_prevplaydate Last play date +moviebrowser.info_prodcountry Country +moviebrowser.info_prodyear Year +moviebrowser.info_quality Quality +moviebrowser.info_recorddate Record date +moviebrowser.info_serie Serie +moviebrowser.info_size File size (MB) +moviebrowser.info_title Titel +moviebrowser.info_videoformat Picture +moviebrowser.menu_directories_head Paths +moviebrowser.menu_help_head Help +moviebrowser.menu_main_bookmarks Bookmarks +moviebrowser.menu_main_head Settings +moviebrowser.menu_main_movieinfo Movie info +moviebrowser.menu_main_saveandback save and back +moviebrowser.menu_nfs_head NFS settings +moviebrowser.menu_parental_lock_activated activated +moviebrowser.menu_parental_lock_activated_no no +moviebrowser.menu_parental_lock_activated_yes yes +moviebrowser.menu_parental_lock_activated_no_temp no (temporary) +moviebrowser.menu_parental_lock_head Parental Lock +moviebrowser.menu_parental_lock_rate_head Lock movies from +moviebrowser.scan_for_movies Scan for Movies ... +moviebrowser.serie_existingname Existing series +moviebrowser.serie_head Serie +moviebrowser.serie_name Change name +moviebrowser.short_audio Audio +moviebrowser.short_book Book +moviebrowser.short_channel Channel +moviebrowser.short_country Country +moviebrowser.short_filename Name +moviebrowser.short_format Format +moviebrowser.short_genre_major Genre +moviebrowser.short_genre_minor Genre +moviebrowser.short_info1 Info 1 +moviebrowser.short_info2 Info 2 +moviebrowser.short_length Min +moviebrowser.short_parental_lockage Age +moviebrowser.short_path Path +moviebrowser.short_prevplaydate Last +moviebrowser.short_prodyear Year +moviebrowser.short_quality * (quality) +moviebrowser.short_recorddate Date +moviebrowser.short_serie Serie +moviebrowser.short_size MB +moviebrowser.short_title Title +moviebrowser.start_head Start movie from: +moviebrowser.start_record_start Movie start +options.on.without_messages Without msg +extra.zapit_scan_sdt Scan SDT for updates +extra.zapit_sdt_changed Channels changed, reload settings. +miscsettings.virtual_zap_mode Virtual zap +miscsettings.epg_head Epg settings +miscsettings.epg_cache_days EPG-Cache (days) +miscsettings.epg_old_hours Events old after (hours) +miscsettings.epg_dir Dir for epg cache +miscsettings.epg_save Save/Restore epg on reboot +shutdown.recoding_query Box in record mode, you really want to shutdown ? +recordingmenu.apids default audio streams +recordingmenu.apids_ac3 record AC3 streams +recordingmenu.apids_alt record alternative streams +recordingmenu.apids_std record standard stream +recordingmenu.stream_pmt_pid record PMT +recordingmenu.zap_on_announce zap on recording announce +timerlist.apids_dflt record default audio streams +videomenu.osd OSD +videomenu.tv-scart TV Scart +videomenu.vcr-scart VCR Scart +videomenu.vcrsignal VCR Output Signal Type +videomenu.vcrsignal_composite CVBS +videomenu.vcrsignal_svideo S-Video +moviebrowser.option_browser Browser Options +moviebrowser.book_clear_all Clear all +moviebrowser.menu_save Save changes +moviebrowser.menu_save_all Start update of movie info files +moviebrowser.info_head_update Save changes in all movie info files +moviebrowser.update_if_dest_empty_only Copy if destination is empty only +moviebrowser.serie_auto_create Serie auto create +moviebrowser.load_default Load default settings +moviebrowser.browser_row_head Row settings +moviebrowser.browser_row_nr Number of rows +moviebrowser.browser_row_item Row item +moviebrowser.browser_row_width Row width +moviebrowser.reload_at_start Reload movie info at start +moviebrowser.remount_at_start Remount at start +moviebrowser.dir_head Additional paths +moviebrowser.dir Path +moviebrowser.use_dir Use directory +moviebrowser.use_rec_dir Use record directory +moviebrowser.use_movie_dir Use movie directory +moviebrowser.hide_series Hide series +moviebrowser.last_record_max_items Number of lines last record +moviebrowser.last_play_max_items Number of lines last play +moviebrowser.browser_frame_high Browser hight [Pixel] +extra.auto_timeshift Auto-record, sec (0 = disable) +extra.auto_delete Auto-delete +extra.auto_to_record Move timeshift to records +extra.record_time Fast/timeshift record time(hours) diff --git a/data/locale/english.locale b/data/locale/english.locale new file mode 100644 index 000000000..7bef3513e --- /dev/null +++ b/data/locale/english.locale @@ -0,0 +1,1349 @@ +EPGMenu.epgplus Eventlist overview +EPGMenu.eventinfo Details current program +EPGMenu.eventlist Eventlist current programm +EPGMenu.head EPG - Program Information +EPGMenu.streaminfo technical information +EPGPlus.actions Actions +EPGPlus.bybouquet_mode by bouquet +EPGPlus.bypage_mode by page +EPGPlus.change_font_size font size +EPGPlus.change_font_style font style +EPGPlus.change_size size +EPGPlus.channelentry_font channel font +EPGPlus.channelentry_separationlineheight separation line height +EPGPlus.channelentry_width width +EPGPlus.channelevententry_font event font +EPGPlus.edit_fonts edit fonts +EPGPlus.edit_sizes edit sizes +EPGPlus.font_style_bold style bold +EPGPlus.font_style_italic style italic +EPGPlus.font_style_regular style regular +EPGPlus.footer_fontbouquetchannelname footer bouquet +EPGPlus.footer_fontbuttons footer buttons +EPGPlus.footer_fonteventdescription footer event +EPGPlus.footer_fonteventshortdescription footer event short +EPGPlus.head Eventlist Overview (EPG Plus) +EPGPlus.header_font header font +EPGPlus.horgap1_height height1 +EPGPlus.horgap2_height height2 +EPGPlus.next_bouquet next bouquet +EPGPlus.options options +EPGPlus.page_down page down +EPGPlus.page_up page up +EPGPlus.prev_bouquet prev bouquet +EPGPlus.record Record +EPGPlus.refresh_epg Refresh +EPGPlus.remind Schedule +EPGPlus.reset_settings reset settings +EPGPlus.save_settings save settings +EPGPlus.scroll_mode Scroll Mode +EPGPlus.select_font_name font name +EPGPlus.settings settings +EPGPlus.slider_width slider width +EPGPlus.stretch_mode Stretch Mode +EPGPlus.swap_mode swap mode +EPGPlus.timeline_fontdate font date +EPGPlus.timeline_fonttime font time +EPGPlus.vergap1_width width1 +EPGPlus.vergap2_width width2 +EPGPlus.view_mode view mode +GENRE.ARTS.0 arts / culture +GENRE.ARTS.1 performing arts +GENRE.ARTS.10 arts/culture magazines +GENRE.ARTS.11 fashion +GENRE.ARTS.2 fine arts +GENRE.ARTS.3 religion +GENRE.ARTS.4 popular culture/traditional arts +GENRE.ARTS.5 literature +GENRE.ARTS.6 film/cinema +GENRE.ARTS.7 experimental film/video +GENRE.ARTS.8 broadcasting/press +GENRE.ARTS.9 new media +GENRE.CHILDRENs_PROGRAMMES.0 children / juvenile program +GENRE.CHILDRENs_PROGRAMMES.1 pre-school children's programmes +GENRE.CHILDRENs_PROGRAMMES.2 entertainment programmes for 6 to 14 +GENRE.CHILDRENs_PROGRAMMES.3 entertainment programmes for 10 to 16 +GENRE.CHILDRENs_PROGRAMMES.4 informational/educational/school programmes +GENRE.CHILDRENs_PROGRAMMES.5 cartoons/puppets +GENRE.DOCUS_MAGAZINES.0 documentation / magazine +GENRE.DOCUS_MAGAZINES.1 nature/animals/environment +GENRE.DOCUS_MAGAZINES.2 technology/natural sciences +GENRE.DOCUS_MAGAZINES.3 medicine/physiology/psychology +GENRE.DOCUS_MAGAZINES.4 foreign countries/expeditions +GENRE.DOCUS_MAGAZINES.5 social/spiritual sciences +GENRE.DOCUS_MAGAZINES.6 further education +GENRE.DOCUS_MAGAZINES.7 languages +GENRE.MOVIE.0 movie/drama +GENRE.MOVIE.1 detective/thriller +GENRE.MOVIE.2 adventure/western/war +GENRE.MOVIE.3 science fiction/fantasy/horror +GENRE.MOVIE.4 comedy +GENRE.MOVIE.5 soap/melodrama/folkloric +GENRE.MOVIE.6 romance +GENRE.MOVIE.7 serious/classical/religious/historical movie/drama +GENRE.MOVIE.8 adult movie/drama +GENRE.MUSIC_DANCE.0 music / ballet / dance +GENRE.MUSIC_DANCE.1 rock/pop +GENRE.MUSIC_DANCE.2 serious music/classical music +GENRE.MUSIC_DANCE.3 folk/traditional music +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musical/opera +GENRE.MUSIC_DANCE.6 ballet +GENRE.NEWS.0 news +GENRE.NEWS.1 news/weather report +GENRE.NEWS.2 news magazine +GENRE.NEWS.3 documentary +GENRE.NEWS.4 discussion/interview/debate +GENRE.SHOW.0 Show / Gameshow +GENRE.SHOW.1 game show/quiz/contest +GENRE.SHOW.2 variety show +GENRE.SHOW.3 talk show +GENRE.SOCIAL_POLITICAL.0 social & politic events / business +GENRE.SOCIAL_POLITICAL.1 magazines/reports/documentary +GENRE.SOCIAL_POLITICAL.2 economics/social advisory +GENRE.SOCIAL_POLITICAL.3 remarkable people +GENRE.SPORTS.0 sports +GENRE.SPORTS.1 special events (Olympic Games,World Cup etc.) +GENRE.SPORTS.10 equestrian +GENRE.SPORTS.11 martial sports +GENRE.SPORTS.2 sports magazines +GENRE.SPORTS.3 football/soccer +GENRE.SPORTS.4 tennis/squash +GENRE.SPORTS.5 team sports (excluding football) +GENRE.SPORTS.6 athletics +GENRE.SPORTS.7 motor sports +GENRE.SPORTS.8 water sports +GENRE.SPORTS.9 winter sports +GENRE.TRAVEL_HOBBIES.0 travel & recreation +GENRE.TRAVEL_HOBBIES.1 tourism/travel +GENRE.TRAVEL_HOBBIES.2 handicraft +GENRE.TRAVEL_HOBBIES.3 motoring +GENRE.TRAVEL_HOBBIES.4 fitness & health +GENRE.TRAVEL_HOBBIES.5 cooking +GENRE.TRAVEL_HOBBIES.6 advertisement/shopping +GENRE.TRAVEL_HOBBIES.7 gardening +GENRE.UNKNOWN unknown +apidselector.head Select language +audiomenu.PCMOffset Volume Decrease PCM +audiomenu.analogout Analog Output +audiomenu.avs avs +audiomenu.avs_control Volume Control avs/ost +audiomenu.dolbydigital Dolby Digital +audiomenu.head Audio Settings +audiomenu.lirc lirc +audiomenu.monoleft mono left +audiomenu.monoright mono right +audiomenu.ost ost +audiomenu.stereo stereo +audiomenu.hdmi_dd Encoded DD on HDMI +audiomenu.spdif_dd Encoded DD on SPDIF +audiomenu.avsync A/V sync +audiomenu.avsync_am Audio master +audioplayer.add Add +audioplayer.artist_title Artist, Title +audioplayer.building_search_index building search index +audioplayer.button_select_title_by_id search by ID +audioplayer.button_select_title_by_name search by name +audioplayer.defdir start dir. +audioplayer.delete Delete +audioplayer.deleteall delete all +audioplayer.display_order display order +audioplayer.enable_sc_metadata enable shoutcast meta data parsing +audioplayer.fastforward fast forw. +audioplayer.follow auto select current +audioplayer.head Audio Playlist +audioplayer.highprio High decode priority +audioplayer.jump_backwards jump backwards +audioplayer.jump_dialog_hint1 Please enter jump target +audioplayer.jump_dialog_hint2 (relative, in seconds) +audioplayer.reading_files reading files +audioplayer.jump_dialog_title Enter jump target +audioplayer.jump_forwards jump forwards +audioplayer.keylevel key level +audioplayer.name Audioplayer +audioplayer.pause pause +audioplayer.play Play +audioplayer.playing Current Track +audioplayer.playlist_fileerror_msg File could not be created: +audioplayer.playlist_fileoverwrite_msg Do you want to overwrite this file: +audioplayer.playlist_fileoverwrite_title Overwrite? +audioplayer.playlist_name filename of the play list +audioplayer.playlist_name_hint1 Please enter the filename of the playlist +audioplayer.playlist_name_hint2 The extension .m3u will be added automatically +audioplayer.repeat_on enable repeat mode +audioplayer.rewind rewind +audioplayer.save_playlist save play list +audioplayer.screensaver_timeout screensaver timeout (min, 0=off) +audioplayer.select_title_by_name search title by name (SMS) +audioplayer.show_playlist Show Playlist +audioplayer.shuffle shuffle +audioplayer.stop Stop +audioplayer.title_artist Title, Artist +audioplayerpicsettings.general audioplayer / picviewer +bookmarkmanager.delete delete +bookmarkmanager.name bookmarks +bookmarkmanager.rename rename +bookmarkmanager.select select +bouqueteditor.add Add +bouqueteditor.bouquetname Name of bouquets +bouqueteditor.delete Delete +bouqueteditor.discardingchanges Discarding changes. Please be patient. +bouqueteditor.hide Hide +bouqueteditor.lock Lock +bouqueteditor.move Move +bouqueteditor.name bouquet editor +bouqueteditor.newbouquetname New name of bouquets +bouqueteditor.rename Rename +bouqueteditor.return ready +bouqueteditor.savechanges? Do you want to save the changes? +bouqueteditor.savingchanges Saving changes. Please wait ... +bouqueteditor.switch add/remove +bouqueteditor.switchmode TV/Radio +bouquetlist.head Bouquets +cablesetup.provider cable provider +channellist.epgtext_align_left left +channellist.epgtext_align_right right +channellist.head All Services +channellist.nonefound No channels were found!\nPlease execute a scan\n(MENU-key -> service) +channellist.since since %02d:%02d +channellist.start starts %02d:%02d +colorchooser.alpha alpha +colorchooser.blue blue +colorchooser.green green +colorchooser.red red +colormenu.background Background +colormenu.fade Fade menus +colormenu.font Font size +colormenu.gtx_alpha Transparency (GTX) +colormenu.head Color Settings +colormenu.menucolors Menucolor +colormenu.statusbar Infobar +colormenu.textcolor Textcolor +colormenu.themeselect select theme +colormenu.timing OSD Timing +colormenusetup.head Menu Colors +colormenusetup.menucontent Window-Content +colormenusetup.menucontent_inactive Window-Content inactive +colormenusetup.menucontent_selected Window-Content selected +colormenusetup.menuhead Menu Header +colorstatusbar.head Infobar +colorstatusbar.text Infobar +colorthememenu.classic_theme Classic Theme +colorthememenu.dblue_theme DarkBlue Theme +colorthememenu.dvb2k_theme DVB2000 Theme +colorthememenu.head Theme Selector +colorthememenu.neutrino_theme Neutrino Theme +colorthememenu.gray Gray Theme +date.Apr Apr +date.Aug Aug +date.Dec Dec +date.Feb Feb +date.Fri Fri +date.Jan Jan +date.Jul Jul +date.Jun Jun +date.Mar Mar +date.May May +date.Mon Mon +date.Nov Nov +date.Oct Oct +date.Sat Sat +date.Sep Sep +date.Sun Sun +date.Thu Thu +date.Tue Tue +date.Wed Wed +epglist.noevents EPG is not available... +epgviewer.More_Screenings More Screenings on this Channel +epgviewer.nodetailed No detailed informations available +epgviewer.notfound no epg found +eventfinder.head Search in EPG +eventfinder.keyword Keyword +eventfinder.start_search Start Search +eventfinder.search_within_list Search within +eventfinder.search_within_epg Search within +eventfinder.search Search +eventfinder.searching Search for keyword in EPG... +eventlistbar.channelswitch schedule +eventlistbar.eventsort sorting +eventlistbar.recordevent record +favorites.addchannel The current channel will be added \nto the bouquet "My Favorites". \n This will take a few seconds... +favorites.bouquetname My Favorites +favorites.bqcreated Bouquet "My Favorites" has been created...\n +favorites.chadded The current channel has been added to your favorites...\n +favorites.chalreadyinbq The current channel is already in your favorites...\n +favorites.finalhint \nUse the bouqueteditor to modify your favorites.\n +favorites.menueadd add channel to favorites +favorites.nobouquets Favorites are available with activated Bouquets only. +filebrowser.delete Delete +filebrowser.denydirectoryleave Absolute start directory +filebrowser.dodelete1 Delete +filebrowser.dodelete2 ? +filebrowser.filter.active Filter on +filebrowser.filter.inactive Filter off +filebrowser.head Filebrowser +filebrowser.mark Mark +filebrowser.nextpage Next Page +filebrowser.prevpage Prev. Page +filebrowser.scan Scaning folder +filebrowser.select Select +filebrowser.showrights Show file rights +filebrowser.sort.date (date) +filebrowser.sort.name (filename) +filebrowser.sort.namedirsfirst (filename2) +filebrowser.sort.size (Size) +filebrowser.sort.type (type) +filesystem.is.utf8 file system +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +flashupdate.actionreadflash reading +flashupdate.cantopenfile can't open file +flashupdate.cantopenmtd can't open mtd-device +flashupdate.checkupdate search for new version +flashupdate.currentreleasecycle Release cycle +flashupdate.currentversion_sep Current version +flashupdate.currentversiondate Date +flashupdate.currentversionsnapshot ImageType +flashupdate.currentversiontime Time +flashupdate.erasefailed erasure of flash failed +flashupdate.erasing erasing flash +flashupdate.experimentalimage The image you have selected is an untested version, this means\nyour box maybe fail to boot after update.\n\nDo you really want to update to this version? +flashupdate.expertfunctions Expert-functions +flashupdate.fileis0bytes the filesize is 0 Bytes +flashupdate.fileselector File-Selector +flashupdate.flashreadyreboot The image was successfully flashed.\nThe box will be rebooted now. +flashupdate.getinfofile getting versioninfo +flashupdate.getinfofileerror can't get versioninfo +flashupdate.getupdatefile getting update +flashupdate.getupdatefileerror can't get update +flashupdate.globalprogress Global Progress: +flashupdate.head Software Update +flashupdate.md5check checking image +flashupdate.md5sumerror image has errors +flashupdate.msgbox Found the following new file:\nDate: %s, %s\nBaseImage: %s\nType: %s\n\nDo you want to download and install this version now? +flashupdate.msgbox_manual Found the following new image:\nDate: %s, %s\nBaseImage: %s\nImageType: %s\n\nDo you want to install this version now? +flashupdate.mtdselector Partition-Selector +flashupdate.programmingflash programming flash +flashupdate.proxypassword Password +flashupdate.proxypassword_hint1 enter the proxyserver password +flashupdate.proxypassword_hint2 a empty entry means no proxy-auth +flashupdate.proxyserver Hostname +flashupdate.proxyserver_hint1 enter proxyserver name or ip, use host:port +flashupdate.proxyserver_hint2 a empty entry means no proxy +flashupdate.proxyserver_sep Proxyserver +flashupdate.proxyusername Username +flashupdate.proxyusername_hint1 enter the proxyserver username +flashupdate.proxyusername_hint2 a empty entry means no proxy-auth +flashupdate.readflash Read whole image +flashupdate.readflashmtd Read one partition +flashupdate.ready ready +flashupdate.reallyflashmtd Do you really want to flash?\n\nIf a error occurs or the image is not\nvalid, the box will not boot after flashing.\n\nImagename: %s\nTarget: %s +flashupdate.savesuccess The image was successfully saved \nunder %s. +flashupdate.selectimage Available Images/Files +flashupdate.squashfs.noversion SquashFS version checks are currently only supported when updating over the web.\nAre you sure that you wish to install this image? +flashupdate.titlereadflash Reading Flash +flashupdate.titlewriteflash Writing Flash +flashupdate.updatemode Updatemode +flashupdate.updatemode_internet internet +flashupdate.updatemode_manual manual (ftp) +flashupdate.url_file config file +flashupdate.versioncheck checking version +flashupdate.writeflash Write whole image +flashupdate.writeflashmtd Write one partition +flashupdate.wrongbase Your Release cycle differs.\nTo continue? +fontmenu.channellist Channellist +fontmenu.epg EPG +fontmenu.eventlist Eventlist +fontmenu.gamelist Gamelist +fontmenu.head Fontsize settings +fontmenu.infobar Infobar +fontsize.channel_num_zap direct selection +fontsize.channellist Channellist +fontsize.channellist_descr Description +fontsize.channellist_number Number +fontsize.epg_date EPG Date +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Title +fontsize.eventlist_datetime date / time +fontsize.eventlist_itemlarge large +fontsize.eventlist_itemsmall small +fontsize.eventlist_title Title +fontsize.filebrowser_item filebrowser item +fontsize.gamelist_itemlarge large +fontsize.gamelist_itemsmall small +fontsize.hint Initialising font,\nplease wait... +fontsize.infobar_channame Channel name +fontsize.infobar_info info +fontsize.infobar_number Number +fontsize.infobar_small small +fontsize.menu Menutext +fontsize.menu_info Menu Info +fontsize.menu_title Menu Title +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.epgnotload EPG not loaded.... +infoviewer.epgwait waiting for EPG... +infoviewer.eventlist Event-List +infoviewer.motor_moving Antenna positioning +infoviewer.next next +infoviewer.now now +infoviewer.nocurrent No info for current program available +infoviewer.noepg EPG not available +infoviewer.notavailable Channel not available +infoviewer.selecttime Timeselection +infoviewer.streaminfo Features +infoviewer.subchan_disp_pos Subchannel display +infoviewer.subservice Subservices +infoviewer.waittime Waiting for time... +ipsetup.hint_1 Use 0..9, or use Up/Down, +ipsetup.hint_2 OK saves, LAME! aborts +keybindingmenu.RC Key repeat-blocker +keybindingmenu.addrecord add record timer +keybindingmenu.addremind add zapto timer +keybindingmenu.allchannels_on_ok all-services +keybindingmenu.bouquetchannels_on_ok current bouquet +keybindingmenu.bouquetdown bouquet back +keybindingmenu.bouquethandling Bouquet-control +keybindingmenu.bouquetlist_on_ok bouquet-list +keybindingmenu.bouquetup next bouquet +keybindingmenu.cancel close channellist +keybindingmenu.channeldown channel down +keybindingmenu.channellist Channellist +keybindingmenu.channelup channel up +keybindingmenu.head Keybinding Setup +keybindingmenu.lastchannel Quick Zap +keybindingmenu.modechange Modechange +keybindingmenu.pagedown page down +keybindingmenu.pageup page up +keybindingmenu.quickzap Quickzap +keybindingmenu.repeatblock repeat delay +keybindingmenu.repeatblockgeneric generic delay +keybindingmenu.sort change sort order +keybindingmenu.subchanneldown subchannel down +keybindingmenu.subchannelup subchannel up +keybindingmenu.tvradiomode TV/Radio-mode +keybindingmenu.zaphistory Zapping History Bouquet +keychooser.head Setup new Key +keychooser.text1 Please press the new key +keychooser.text2 wait a few seconds for abort +keychoosermenu.currentkey current key +keychoosermenu.setnew setup new key +keychoosermenu.setnone no key +languagesetup.head Language Setup +languagesetup.select Language +lcdcontroler.brightness normal Brightness +lcdcontroler.brightnessstandby Standby Brightness +lcdcontroler.contrast Contrast +lcdmenu.autodimm Auto dimm +lcdmenu.head VFD Settings +lcdmenu.inverse Invert +lcdmenu.lcdcontroler Contrast / Brightness +lcdmenu.power Power +lcdmenu.statusline status line +lcdmenu.statusline.both volume / playtime +lcdmenu.statusline.playtime playtime +lcdmenu.statusline.volume volume +mainmenu.audioplayer Audioplayer +mainmenu.games Games +mainmenu.head Main Menu +mainmenu.movieplayer Movieplayer +mainmenu.pausesectionsd Read EPG +mainmenu.pictureviewer Picture viewer +mainmenu.radiomode Radio-Mode +mainmenu.reboot Reboot +mainmenu.recording Recording +mainmenu.recording_start start +mainmenu.recording_stop stop +mainmenu.scartmode Scart-Mode +mainmenu.scripts Scripts +mainmenu.service Service +mainmenu.settings Settings +mainmenu.shutdown Shutdown +mainmenu.sleeptimer SleepTimer +mainmenu.tvmode TV-Mode +mainsettings.audio Audio +mainsettings.osd OSD settings +mainsettings.head Settings +mainsettings.keybinding Key Setup +mainsettings.language Language +mainsettings.lcd VFD-Display +mainsettings.misc Misc settings +mainsettings.network Network +mainsettings.recording Recording +mainsettings.savesettingsnow save settings now +mainsettings.savesettingsnow_hint Saving settings,\nplease wait... +mainsettings.streaming Movieplayer +mainsettings.video Video +menu.back back +messagebox.back Back +messagebox.cancel Cancel +messagebox.discard Discard changes? +messagebox.error Error +messagebox.info Information +messagebox.no No +messagebox.yes Yes +miscsettings.bootinfo Show infos at start +miscsettings.bootmenu Show boot menu +miscsettings.channellist Channellist +miscsettings.channellist_epgtext_align Programtext Align +miscsettings.driver_boot driver and boot options +miscsettings.fb_destination Expert! Boot-Console +miscsettings.general General +miscsettings.head Misc settings +miscsettings.hwsections use hardware sections +miscsettings.infobar_sat_display Satellite display on infobar +miscsettings.noaviawatchdog enable AVIA watchdog +miscsettings.noenxwatchdog enable eNX watchdog +miscsettings.pmtupdate enable pmt update +miscsettings.shutdown_count switch off after +miscsettings.shutdown_count_hint1 time (in minutes) to switch from standby +miscsettings.shutdown_count_hint2 to deep standby (0 = off). +miscsettings.shutdown_real Enable standby +miscsettings.shutdown_real_rcdelay Delayed shutdown +miscsettings.sptsmode use spts mode +motorcontrol.head Satellite finder +movieplayer.bookmark Bookmarks +movieplayer.bookmarkname Bookmarkname +movieplayer.bookmarkname_hint1 Enter a name for your new bookmark +movieplayer.bookmarkname_hint2 +movieplayer.buffering Buffering... +movieplayer.defdir start dir. +movieplayer.defplugin Start-Plugin +movieplayer.dvdplayback DVD +movieplayer.fileplayback File play +movieplayer.goto Jump to ... +movieplayer.goto.h1 = -> absolute jump +movieplayer.goto.h2 +,- -> relative jump +movieplayer.head Movieplayer +movieplayer.nostreamingserver The streaming server could not be reached. +movieplayer.pesplayback Play PES (Experimental) +movieplayer.pleasewait Please wait.\nConnecting to the streaming server... +movieplayer.toomanybookmarks There are too many bookmarks.\nYou need to delete one of them first. +movieplayer.tshelp1 Stop +movieplayer.tshelp10 approx. 10 minutes back +movieplayer.tshelp11 skip approx. 10 minutes +movieplayer.tshelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Select audio track +movieplayer.tshelp3 Pause/Continue +movieplayer.tshelp4 Create bookmark +movieplayer.tshelp5 Show progress +movieplayer.tshelp6 approx. 1 minute back +movieplayer.tshelp7 skip approx. 1 minute +movieplayer.tshelp8 approx. 5 minutes back +movieplayer.tshelp9 skip approx. 5 minutes +movieplayer.tsplayback Play TS +movieplayer.vcdplayback (S)VCD +movieplayer.vlchelp1 Stop +movieplayer.vlchelp10 approx. 10 minutes back +movieplayer.vlchelp11 skip approx. 10 minutes +movieplayer.vlchelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Resync +movieplayer.vlchelp3 Pause/Continue +movieplayer.vlchelp4 Create bookmark +movieplayer.vlchelp5 Show progress +movieplayer.vlchelp6 approx. 1 minute back +movieplayer.vlchelp7 skip approx. 1 minute +movieplayer.vlchelp8 approx. 5 minutes back +movieplayer.vlchelp9 skip approx. 5 minutes +movieplayer.wrongvlcversion This feature is not support by your current version of VLC +networkmenu.broadcast Broadcast +networkmenu.dhcp DHCP +networkmenu.gateway default gateway +networkmenu.head Network Settings +networkmenu.ipaddress IP address +networkmenu.mount NFS/CIFS/FTPFS +networkmenu.nameserver name server +networkmenu.netmask netmask +networkmenu.ntpenable Syncronisation via +networkmenu.ntprefresh NTP/DVB-Refresh +networkmenu.ntprefresh_hint1 NTP/DVB-Time-Sync in minutes +networkmenu.ntprefresh_hint2 need reboot or epg-reset +networkmenu.ntpserver NTP-Server +networkmenu.ntpserver_hint1 NTP-Server example: ntp1.ptb.de +networkmenu.ntpserver_hint2 need reboot or epg-reset +networkmenu.ntptitle Time-Syncronisation +networkmenu.setupnow setup network now +networkmenu.setuponstartup setup network on startup +networkmenu.show show active network settings +networkmenu.test test network now +nfs.alreadymounted directory already mounted +nfs.automount mount on startup +nfs.dir directory/share +nfs.ip Server IP +nfs.localdir local dir +nfs.mount Mount Network volume +nfs.mount_options mount options +nfs.mountok mount successful +nfs.mounterror mount error +nfs.mounterror_notsup filesystem type not supported +nfs.mountnow mount now +nfs.mounttimeout mount error: timeout +nfs.password password +nfs.remount remount directories +nfs.type type +nfs.type_cifs CIFS +nfs.type_lufs FTPFS +nfs.type_nfs NFS +nfs.umount Umount Network volume +nfs.umounterror error umounting volume +nfs.username username +nfsmenu.head NFS/CIFS/FTPFS settings +nvod.percentage (%d%% over) +nvod.starting (starting in %d min) +nvodselector.directormode Direct-Mode +nvodselector.head Select starting-time +nvodselector.subservice Select Subservice +options.default Reset to defaults +options.fb framebuffer +options.null null +options.off off +options.on on +options.serial serial +parentallock.changepin change PIN code +parentallock.changepin_hint1 Enter your new youth protection pin code here! +parentallock.changetolocked on locked bouquets +parentallock.head Enter Parental Lock PIN code +parentallock.lockage lock program +parentallock.lockage12 from 12 years up +parentallock.lockage16 from 16 years up +parentallock.lockage18 from 18 years up +parentallock.lockedchannel Locked sender... +parentallock.lockedprogram Locked program (from %d years up) +parentallock.never never +parentallock.onsignal on broadcasted lock +parentallock.parentallock Youth protection +parentallock.prompt prompt for PIN +pictureviewer.defdir start dir. +pictureviewer.head Picture viewer +pictureviewer.help1 menu mode +pictureviewer.help10 show mode +pictureviewer.help11 reread image +pictureviewer.help12 previous image +pictureviewer.help13 next image +pictureviewer.help14 Zoom out +pictureviewer.help15 Zoom in +pictureviewer.help16 scroll up +pictureviewer.help17 scroll left +pictureviewer.help18 scroll right +pictureviewer.help19 scroll down +pictureviewer.help2 display image +pictureviewer.help20 change sort order +pictureviewer.help21 reread image (no scaling) +pictureviewer.help22 exit +pictureviewer.help3 change sort order +pictureviewer.help4 do not scale picture +pictureviewer.help5 diashow mode +pictureviewer.help6 previous image +pictureviewer.help7 next image +pictureviewer.help8 change sort order +pictureviewer.help9 exit +pictureviewer.resize.color_average advanced +pictureviewer.resize.none none +pictureviewer.resize.simple simple +pictureviewer.scaling scaling +pictureviewer.show show +pictureviewer.slide_time slideshow display time +pictureviewer.slideshow slideshow +pictureviewer.sortorder change sort order +pictureviewer.sortorder.date (date) +pictureviewer.sortorder.filename (filename) +ping.ok is reachable (ping) +ping.protocol is unreachable (host or protocol error) +ping.socket is unreachable (socket error) +ping.unreachable is unreachable +pinprotection.head Enter PIN code +pinprotection.wrongcode PIN-Code was wrong! Try again. +plugins.result plugin output +rclock.lockmsg Your box remote control will be locked.\n To unlock it, press \n and on your remote control. +rclock.menueadd Lock RC +rclock.title Lock Remote Control +rclock.unlockmsg Remote control reactivated. +recordingmenu.choose_direct_rec_dir choose dir on imm. recording +recordingmenu.defdir recording directory +recordingmenu.tsdir timeshift directory +recordingmenu.epg_for_filename long filenames (with EPG data) +recordingmenu.file direct (file) +recordingmenu.filesettings direct recording settings +recordingmenu.head Recording Settings +recordingmenu.help Recording devices:\n--------------------------\nserver:\nusing streaming software on a PC\n\n(analog) vcr:\nusing the vcr outlet\n\ndirect (file):\ndirectly into an NFS mounted directory\nor onto an internal hard drive\nTS: use spts mode(dbox2)\nPES: do not use spts mode(dbox2)\n\n\nMax. file size:\n---------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: almost unlimited (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart do not switch to scart mode +recordingmenu.off off +recordingmenu.recording_type recording device +recordingmenu.ringbuffers no. of ringbuffers +recordingmenu.server server +recordingmenu.server_ip recording server IP +recordingmenu.server_mac MAC address +recordingmenu.server_port recording server port +recordingmenu.server_wakeup recording server WOL +recordingmenu.setupnow activate changes +recordingmenu.splitsize Max. file size (MB) +recordingmenu.stopplayback stop playback +recordingmenu.stopsectionsd stop sectionsd +recordingmenu.stream_vtxt_pid record videotext +recordingmenu.use_fdatasync write synchronous (fdatasync) +recordingmenu.use_o_sync write synchronous (O_SYNC) +recordingmenu.vcr vcr +recordtimer.announce Recording starts in a few minutes +repeatblocker.hint_1 Shortest time (in ms) to recognize 2 keystrokes +repeatblocker.hint_2 Enter 0 to switch of the blocker (red is space) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-repeats +satsetup.extended DiSEqC-Settings +satsetup.extended_motor Motor-Settings +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Manual Motor-Setup +satsetup.nodiseqc no DiSEqC +satsetup.satellite Satellite +satsetup.savesettingsnow save settings now +satsetup.smatvremote SMATV Remote Tuning +scants.actcable Cable: +scants.actsatellite Satellite: +scants.bouquet Bouquet +scants.bouquet_create create new +scants.bouquet_erase erase all +scants.bouquet_leave leave current +scants.bouquet_satellite Satellite-Bouquet +scants.bouquet_update update +scants.channel Channel: +scants.failed Transponderscan failed! +scants.finished Transponderscan finished successfully! +scants.freqdata Frequency: +scants.head Scan transponder +scants.numberofdataservices Data +scants.numberofradioservices Radio +scants.numberoftotalservices Total +scants.numberoftvservices TV +scants.provider Provider: +scants.startnow start scan +scants.test Test signal +scants.transponders Transponders: +scants.select_tp Select transponder +screensetup.lowerright green = setup lower right +screensetup.upperleft red = setup upper left +servicemenu.head Service +servicemenu.reload Reload channel lists +servicemenu.reload_hint Reloading channel lists,\nplease be patient. +servicemenu.scants Servicescan +servicemenu.ucodecheck Check ucodes +servicemenu.update Software Update +settings.help Help +settings.missingoptionsconffile The neutrino-settings have been updated.\nNew Options will be set to default. +settings.noconffile No neutrino-settings found.\nUsing defaults. +settings.pos_bottom_left bottom left +settings.pos_bottom_right bottom right +settings.pos_top_left oben top left +settings.pos_top_right oben top right +shutdowntimer.announce Box will shutdown in 1 min.\nCancel Sutdown ? +sleeptimerbox.announce Sleeptimer in 1 min +sleeptimerbox.hint1 Shutdown time in min. (000=off) +sleeptimerbox.hint2 The STB will shutdown after this time. +sleeptimerbox.title Sleeptimer +streamfeatures.head Features +streaminfo.aratio Aspect Ratio +streaminfo.aratio_unknown Aspect Ratio: unknown +streaminfo.audiotype Audiotype +streaminfo.audiotype_unknown Audiotype: unknown +streaminfo.bitrate Bitrate +streaminfo.framerate Framerate +streaminfo.framerate_unknown Framerate: unknown +streaminfo.head Stream-Information +streaminfo.not_available not available +streaminfo.resolution Resolution +streaminfo.signal Receipt signal +streaming.buffer_overflow The recording was aborted,\nsince the data could not be written fast enough. +streaming.busy One or several recording processes are active.\nIf you encounter this message and no recording is active, please restart Neutrino. +streaming.dir_not_writable The recording directory is not writable.\nRecording will not work. +streaming.success The recording has ended successfully. +streaming.write_error The recording was aborted,\nsince an error occured during the writing process. +streaming.write_error_open The recording was aborted,\nbecause the target file could not be opened. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Movieplayer Settings +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Off +streamingmenu.on On +streamingmenu.server_ip Streamingserver IP +streamingmenu.server_port Streamingserver Port +streamingmenu.streaming_audiorate Datarate Audio +streamingmenu.streaming_force_avi_rawaudio Force AC3 for AVI +streamingmenu.streaming_force_transcode_video Transcode MPG/VCD video +streamingmenu.streaming_resolution Resolution +streamingmenu.streaming_server_cddrive DVD Drive +streamingmenu.streaming_server_startdir Directory (VLC) +streamingmenu.streaming_transcode_audio Transcode audio (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec MPEG video codec +streamingmenu.streaming_type Streamingserver +streamingmenu.streaming_videorate Datarate Video +streamingserver.noconnect No connection to streamingserver.\nRecording canceled. +stringinput.caps caps / no caps +stringinput.clear clear all +timer.eventrecord.msg ... TO be DONE, or not to be done +timer.eventrecord.title Schedule Record +timer.eventtimed.msg The event is scheduled.\nThe box will power on and \nswitch to this channel at the given time. +timer.eventtimed.title Schedule Event +timerbar.channelswitch Schedule +timerbar.recordevent Record +timerlist.alarmtime Alarm time +timerlist.apids Audio PIDs +timerlist.bouquetselect choose bouquet +timerlist.channel Channel +timerlist.channelselect choose channel +timerlist.delete Delete +timerlist.menumodify Modify timer +timerlist.menunew New timer +timerlist.message Message +timerlist.moderadio Radio channels +timerlist.modeselect Mode selection +timerlist.modetv TV channels +timerlist.modify Modify +timerlist.name Timer list +timerlist.new New timer +timerlist.plugin Plugin +timerlist.program.unknown Program unknown +timerlist.recording_dir recording directory +timerlist.reload Reload +timerlist.repeat Repeat +timerlist.repeat.biweekly biweekly +timerlist.repeat.byeventdescription see timer +timerlist.repeat.daily daily +timerlist.repeat.fourweekly fourweekly +timerlist.repeat.friday Fr +timerlist.repeat.monday Mo +timerlist.repeat.monthly monthly +timerlist.repeat.once once +timerlist.repeat.saturday Sa +timerlist.repeat.sunday Su +timerlist.repeat.thursday Th +timerlist.repeat.tuesday Tu +timerlist.repeat.unknown unknown +timerlist.repeat.wednesday We +timerlist.repeat.weekdays on weekdays +timerlist.repeat.weekly weekly +timerlist.repeatcount repeats +timerlist.repeatcount.help1 amount of timer repeats +timerlist.repeatcount.help2 0 for unlimited repeats +timerlist.save Save timer +timerlist.standby SB mode +timerlist.standby.off Leave standby +timerlist.standby.on Enter standby +timerlist.stoptime Stop time +timerlist.type Timer typ +timerlist.type.execplugin Execute plugin +timerlist.type.nextprogram Next program +timerlist.type.record Record +timerlist.type.remind Reminder +timerlist.type.shutdown Shutdown +timerlist.type.sleeptimer Sleeptimer +timerlist.type.standby Standby +timerlist.type.unknown Unknown +timerlist.type.zapto Zap to +timerlist.weekdays Days of the week +timerlist.weekdays.hint_1 Mo Tu We Th Fr Sa Su +timerlist.weekdays.hint_2 'X'=timer '-' no timer +timersettings.record_safety_time_after Record stop time correction +timersettings.record_safety_time_after.hint_1 Correction time in min. (00=off). This time +timersettings.record_safety_time_after.hint_2 will added to stop time of every record timer. +timersettings.record_safety_time_before Record start time correction +timersettings.record_safety_time_before.hint_1 Correction time in min. (00=off). This time +timersettings.record_safety_time_before.hint_2 will be deducted of every record timer. +timersettings.separator Timer settings +timing.chanlist Channellist +timing.epg Epg +timing.filebrowser Filebrowser +timing.head OSD Timeouts +timing.hint_1 Time in sec. After this time the +timing.hint_2 infobar will be faded out. +timing.infobar Infobar +timing.menu Menu +timing.numericzap Numeric Zap +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head UCode check +ucodecheck.ucode UCode +ucodes.failure ATTENTION, µCodes could NOT be found!\n\nPlease upload them via FTP (or DBox-BootManager),\nthen restart your box! +videomenu.csync sync correction +videomenu.head Video Settings +videomenu.rgb_centering RGB centering +videomenu.screensetup Screen Setup +videomenu.vcrswitch Switch Scart automatically +videomenu.videoformat Format +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 +videomenu.videoformat_149 14:9 +videomenu.videoformat_autodetect autodetect +videomenu.43mode 4:3 Content mode +videomenu.panscan Pan&Scan +videomenu.panscan2 14:9 Pan&Scan +videomenu.letterbox Letterbox +videomenu.fullscreen Full screen +videomenu.auto Auto +videomenu.analog_mode Analog Video Output +videomenu.analog_sd_rgb_scart RGB on scart (SD) +videomenu.analog_sd_rgb_cinch RGB on cinch (SD) +videomenu.analog_sd_yprpb_scart YPbPr on scart (SD) +videomenu.analog_sd_yprpb_cinch YPbPr on cinch (SD) +videomenu.analog_hd_rgb_scart RGB on scart (HD) +videomenu.analog_hd_rgb_cinch RGB on cinch (HD) +videomenu.analog_hd_yprpb_scart YPbPr on scart (HD) +videomenu.analog_hd_yprpb_cinch YPbPr on cinch (HD) +videomenu.scart Scart +videomenu.cinch Cinch +videomenu.dbdr MPEG2 de-block/de-ring +videomenu.dbdr_none none +videomenu.dbdr_deblock de-block +videomenu.dbdr_both de-block+de-ring +videomenu.enabled_modes VF key enabled modes +zaptotimer.announce Zapto timer in one minute +extra.english English +extra.dboxinfo Box Info +extra.scan_mode Scan mode +extra.start_tostandby Startup to standby +extra.rotor_swap Swap rotor east/west +extra.use_log Log to /tmp/log +extra.spts_mode SPTS mode +extra.hw_sect Hardware Sections +extra.logo Logo number +extra.scan_full Full +extra.scan_fast Fast +hdd_slow Slow +hdd_middle Middle +hdd_fast Fast +hdd_ext3 Ext3fs +hdd_reiser Reiserfs +hdd_1min 1 min. +hdd_5min 5 min. +hdd_10min 10 min. +hdd_20min 20 min. +hdd_30min 30 min. +hdd_60min 60 min. +hdd_sleep Sleep time +hdd_noise Noise +hdd_activate Activate settings +hdd_fs Filesystem +hdd_format Format HDD +hdd_check Check filesystem +hdd_settings HDD Settings +hdd_format_warn Are you sure to format ? You will lost all data ! +hdd_umount_warn HDD unmount failed ! +hdd_check_failed HDD check failed ! +hdd_format_failed HDD format failed ! +hdd_manage Manage +hdd_not_found No HDD found +extra.clear_log Clear Log +extra.zap_cycle Zap cycle +extra.sms_channel sms-mode channel +extra.manual_scan Manual scan +extra.tp_freq Frequency +extra.tp_rate Symbol rate +extra.tp_pol Polarization +extra.tp.pol_v V +extra.tp_pol_h H +extra.tp_fec FEC +extra.fec_1_2 1/2 +extra.fec_2_3 2/3 +extra.fec_3_4 3/4 +extra.fec_5_6 5/6 +extra.fec_7_8 7/8 +extra.timezone Timezone +extra.zapit_menu Zapit options +extra.zapit_make_bouquet Make Remaining Channels list +extra.zapit_save_last_chan Save last channel +extra.zapit_motor_speed Motor moving speed (10 = 1deg/sec) +extra.zapit_fe_timeout Tune timeout +extra.add_to_bouquet Add to bouquet +extra.key_list_start home +extra.key_list_end end +extra.chadded The current channel has been added to selected bouquet....\n +extra.chalreadyinbq The current channel is already in selected bouquet....\n +extra.menu_left_exit "Left" = menu back +extra.zapit_write_names Write channel names +extra.update_dir Directory for updates +extra.zapit_fast_zap fast zap +extra.zapit_sort_names Sort ch. by name +extra.zapit_backup Backup channels to /tmp +extra.zapit_restore Restore channels from /tmp +pictureviewer.decode_server_ip decode server ip +pictureviewer.decode_server_port decode server port +scants.abort_body Should the search really be aborted? +scants.abort_header Abortion of channel scan +recordingmenu.record_in_spts_mode switch to spts mode before recording +servicemenu.getplugins Reload plugins +servicemenu.getplugins_hint Reloading plugins,\nplease be patient. +zapit.scantype scan for services +zapit.scantype.all all services +zapit.scantype.radio only radio +zapit.scantype.tv only tv +zapit.scantype.tvradio tv & radio +colorthememenu.red_theme Simply Red +lcdmenu.dim_brightness Brightness after dim timeout +lcdmenu.dim_time Dim timeout +timerlist.overlapping_timer Timer conflict. Create the timer anyway? +extra.audio_run_player Audio key start player +mpkey.rewind Rewind +mpkey.forward Forward +mpkey.pause Pause +mpkey.stop Stop +mpkey.play Play +mpkey.audio Audio track +mpkey.time Show time +mpkey.bookmark save bookmark +mpkey.plugin Run plugin +extra.key_click Key click +extra.loadcolors Load colors from +extra.savecolors Save colors as +extra.loadkeys Load keys from +extra.savekeys Save keys as +extra.loadconfig Load settings from +extra.saveconfig Save settings as +videomenu.videomode Digital video mode +videomenu.videomode_ntsc NTSC +videomenu.videomode_pal PAL +videomenu.videomode_palm PAL-M +extra.key_timeshift Timeshift +extra.key_plugin One touch plugin +extra.timeshift_pause Timeshift pause +rfmod.rfmod RF modulator +rfmod.carrier Subcarrier Frequency +rfmod.carrier4500 4.5 +rfmod.carrier5500 5.5 +rfmod.carrier6000 6.0 +rfmod.carrier6500 6.5 +rfmod.enable Enable sound +rfmod.channel Channel +rfmod.finetune Fine tune +rfmod.standby Enable modulator +rfmod.test Test pattern +extra.zapit_scanpids Scan/Use pids +extra.zapit_rezap_time Re-Zap on emu switch time +extra.zapit_hvoltage High (13.5/18.5) voltage +extra.key_unlock Unlock key +servicemenu.imageinfo Image info +imageinfo.creator Creator: +imageinfo.date Date: +imageinfo.dokumentation Docs: +imageinfo.forum Forum: +imageinfo.head Image info: +imageinfo.homepage Home page: +imageinfo.image Image: +imageinfo.license License: +imageinfo.version Version: +extra.cache_txt Cache teletext +extra.use_gotoxx Use gotoXX +extra.latitude Latitude +extra.longitude Longitude +extra.ladirection LaDirection +extra.lodirection LoDirection +extra.south South +extra.north North +extra.east East +extra.west West +epgextended.actors Actors +epgextended.director Director +epgextended.guests Guests +epgextended.original_title Original Title +epgextended.presenter Presenter +epgextended.year_of_production Year of Production +recordingmenu.save_in_channeldir Save in channel dir +servicemenu.restart Soft restart +servicemenu.restart_failed Restart failed +servicemenu.restart_hint Restarting, please wait +servicemenu.restart_refused_recording Cant restart, recording in progress +extra.tp_mod Modulation +extra.tp_mod_16 QAM/16 +extra.tp_mod_32 QAM/32 +extra.tp_mod_64 QAM/64 +extra.tp_mod_128 QAM/128 +extra.tp_mod_256 QAM/256 +moviebrowser.book_head Bookmarks +moviebrowser.book_lastmoviestop Last play stop: +moviebrowser.book_movieend Movie end: +moviebrowser.book_moviestart Movie start: +moviebrowser.book_name Name: +moviebrowser.book_new New Bookmark +moviebrowser.book_position Position: +moviebrowser.book_type Jump (<0 back , >0 for): +moviebrowser.book_type_backward Repeat +moviebrowser.book_type_forward jump over +moviebrowser.edit_book Bookmark change +moviebrowser.edit_book_name_info1 Enter new Bookmark name +moviebrowser.edit_book_name_info2 +moviebrowser.edit_book_pos_info1 Enter new Position (s) +moviebrowser.edit_book_pos_info2 +moviebrowser.edit_book_type_info1 Enter new jump length (s) +moviebrowser.edit_book_type_info2 <0 back , >0 for, 0: none +moviebrowser.edit_serie Enter name of serie +moviebrowser.error_no_movies No movies found +moviebrowser.foot_filter Filter: +moviebrowser.foot_play Start movie +moviebrowser.foot_sort Sort: +moviebrowser.head TS MovieBrowser +moviebrowser.head_filter Filter movies by category: +moviebrowser.head_playlist Last played: +moviebrowser.head_recordlist Last recorded: +moviebrowser.hint_jumpbackward Jump back in 5 s\n '0' to cancel +moviebrowser.hint_jumpforward Jump forward in 5 s\n '0' to cancel +moviebrowser.hint_movieend Filmende in 5 s\n '0' zum weitersehen +moviebrowser.hint_newbook_backward New jump back\n 'blue' for endposition +moviebrowser.hint_newbook_forward New jump forward\n 'blue' for endposition +moviebrowser.info_audio Audio +moviebrowser.info_channel Channel +moviebrowser.info_filename Name +moviebrowser.info_genre_major Genre +moviebrowser.info_genre_minor Genre +moviebrowser.info_head Film Informationen +moviebrowser.info_info1 Info 1 +moviebrowser.info_length Length (Min) +moviebrowser.info_parental_lockage Parental Lock age +moviebrowser.info_parental_lockage_0year always +moviebrowser.info_parental_lockage_12year 12 years +moviebrowser.info_parental_lockage_16year 16 years +moviebrowser.info_parental_lockage_18year 18 years +moviebrowser.info_parental_lockage_6year 6 years +moviebrowser.info_parental_lockage_always never +moviebrowser.info_path Path +moviebrowser.info_prevplaydate Last play date +moviebrowser.info_prodcountry Country +moviebrowser.info_prodyear Year +moviebrowser.info_quality Quality +moviebrowser.info_recorddate Record date +moviebrowser.info_serie Serie +moviebrowser.info_size File size (MB) +moviebrowser.info_title Titel +moviebrowser.info_videoformat Picture +moviebrowser.menu_directories_head Paths +moviebrowser.menu_help_head Help +moviebrowser.menu_main_bookmarks Bookmarks +moviebrowser.menu_main_head Settings +moviebrowser.menu_nfs_head NFS settings +moviebrowser.menu_parental_lock_activated activated +moviebrowser.menu_parental_lock_activated_no no +moviebrowser.menu_parental_lock_activated_yes yes +moviebrowser.menu_parental_lock_activated_no_temp no (temporary) +moviebrowser.menu_parental_lock_head Parental Lock +moviebrowser.menu_parental_lock_rate_head Lock movies from +moviebrowser.scan_for_movies Scan for Movies ... +moviebrowser.serie_head Serie +moviebrowser.serie_name Change name +moviebrowser.short_audio Audio +moviebrowser.short_book Book +moviebrowser.short_channel Channel +moviebrowser.short_country Country +moviebrowser.short_filename Name +moviebrowser.short_format Format +moviebrowser.short_genre_major Genre +moviebrowser.short_genre_minor Genre +moviebrowser.short_info1 Info 1 +moviebrowser.short_info2 Info 2 +moviebrowser.short_length Min +moviebrowser.short_parental_lockage Age +moviebrowser.short_path Path +moviebrowser.short_prevplaydate Last +moviebrowser.short_prodyear Year +moviebrowser.short_quality * (quality) +moviebrowser.short_recorddate Date +moviebrowser.short_serie Serie +moviebrowser.short_size MB +moviebrowser.short_title Title +moviebrowser.start_head Start movie from: +moviebrowser.start_record_start Movie start +options.on.without_messages Without msg +extra.zapit_scan_sdt Scan SDT for updates +extra.zapit_sdt_changed Channels changed, reload settings. +miscsettings.epg_head Epg settings +miscsettings.epg_cache EPG-Cache (Days) +miscsettings.epg_cache_hint1 How long will EPG-Data in the future cached? +miscsettings.epg_cache_hint2 Set in days. +miscsettings.epg_dir EPG save path +miscsettings.epg_extendedcache EPG Long Description (hours) +miscsettings.epg_extendedcache_hint1 How long into the future will EPG extended descriptions +miscsettings.epg_extendedcache_hint2 be Cached? (Set in hours) +miscsettings.epg_max_events Max. Events +miscsettings.epg_max_events_hint1 How many events should be stored? +miscsettings.epg_max_events_hint2 normaly 6000, 0 to disable limit +miscsettings.epg_old_events EPG remove after (std.) +miscsettings.epg_old_events_hint1 How long will EPG-Data be stored after they timed out? +miscsettings.epg_old_events_hint2 Set in hours +miscsettings.epg_save Save/Restore epg on reboot +miscsettings.virtual_zap_mode Virtual zap +shutdown.recoding_query You really want to to stop record ? +recordingmenu.apids default audio streams +recordingmenu.apids_ac3 record AC3 streams +recordingmenu.apids_alt record alternative streams +recordingmenu.apids_std record standard stream +recordingmenu.stream_pmt_pid record PMT +recordingmenu.zap_on_announce zap on recording announce +timerlist.apids_dflt record default audio streams +videomenu.osd OSD +videomenu.tv-scart Video +videomenu.vcr-scart VCR Scart +videomenu.vcrsignal VCR Output Signal Type +videomenu.vcrsignal_composite CVBS +videomenu.vcrsignal_svideo S-Video +moviebrowser.option_browser Browser Options +moviebrowser.book_clear_all Clear all +moviebrowser.menu_save Save changes +moviebrowser.menu_save_all Start update of movie info files +moviebrowser.info_head_update Save changes in all movie info files +moviebrowser.update_if_dest_empty_only Copy if destination is empty only +moviebrowser.serie_auto_create Serie auto create +moviebrowser.load_default Load default settings +moviebrowser.browser_row_head Row settings +moviebrowser.browser_row_nr Number of rows +moviebrowser.browser_row_item Row item +moviebrowser.browser_row_width Row width +moviebrowser.reload_at_start Reload movie info at start +moviebrowser.remount_at_start Remount at start +moviebrowser.dir_head Additional paths +moviebrowser.dir Path +moviebrowser.use_dir Use directory +moviebrowser.use_rec_dir Use record directory +moviebrowser.use_movie_dir Use movie directory +moviebrowser.hide_series Hide series +moviebrowser.last_record_max_items Number of lines last record +moviebrowser.last_play_max_items Number of lines last play +moviebrowser.browser_frame_high Browser hight [Pixel] +extra.auto_timeshift Auto-record, sec (0 = disable) +extra.auto_delete Auto-delete +extra.auto_to_record Move timeshift to records +extra.record_time Fast/timeshift record time(hours) +audioplayer.spectrum lcd a-spectrum +extra.temp_timeshift Temporary timeshift +AUDIOSelectMenue.head Audio Selection +infoviewer.languages Audio +mainmenu.clearsectionsd Clear EPG Cache +usermenu.button_blue User menu blue +usermenu.button_green User menu green +usermenu.button_red User menu red +usermenu.button_yellow User menu yellow +usermenu.head User menu +usermenu.item_bar ---- Boarder ---- +usermenu.item_epg_misc EPG functions +usermenu.item_none Nothing +usermenu.item_vtxt Videotext +usermenu.name Name +extra.fec_s2_qpsk_1_2 1/2 s2 qpsk +extra.fec_s2_qpsk_2_3 2/3 s2 qpsk +extra.fec_s2_qpsk_3_4 3/4 s2 qpsk +extra.fec_s2_qpsk_5_6 5/6 s2 qpsk +extra.fec_s2_qpsk_7_8 7/8 s2 qpsk +extra.fec_s2_qpsk_8_9 8/9 s2 qpsk +extra.fec_s2_qpsk_3_5 3/5 s2 qpsk +extra.fec_s2_qpsk_4_5 4/5 s2 qpsk +extra.fec_s2_qpsk_9_10 9/10 s2 qpsk +extra.fec_s2_8psk_1_2 1/2 s2 8psk +extra.fec_s2_8psk_2_3 3/2 s2 8psk +extra.fec_s2_8psk_3_4 3/4 s2 8psk +extra.fec_s2_8psk_5_6 5/6 s2 8psk +extra.fec_s2_8psk_7_8 7/8 s2 8psk +extra.fec_s2_8psk_8_9 8/9 s2 8psk +extra.fec_s2_8psk_3_5 3/5 s2 8psk +extra.fec_s2_8psk_4_5 4/5 s2 8psk +extra.fec_s2_8psk_9_10 9/10 s2 8psk +channellist.edit Edit +channellist.extended Extended channel list +channellist.favs Favorites +channellist.provs Providers +channellist.sats Satellites +channellist.history History +channellist.current_tp Current transponder +channellist.make_hdlist Create list of HD channels +video_mode_ok Is this video mode working ok ? +moviebrowser.edit_book_name_info2 book name info2 +satsetup.sat_setup Setup satellites input / LNB +satsetup.do_scan Include in all scan +satsetup.lofl LNB Low Offset +satsetup.lofh LNB High Offset +satsetup.lofs LNB switch Offset +satsetup.diseqc_input Diseqc input +satsetup.uncomm_input Uncommited input +satsetup.motor_pos Rotor position +satsetup.auto_scan Auto-Scan selected Satellite +satsetup.auto_scan_all Auto-Scan multiple Satellites +satsetup.manual_scan Manual frequency scan +satsetup.use_nit Use NIT +satsetup.diseqc_advanced Advanced +satsetup.diseqc_order Input order +satsetup.diseqc_com_uncom Commited/Uncommited +satsetup.diseqc_uncom_com Uncommited/Commited +satsetup.comm_input Commited input +satsetup.use_usals Use usals +satsetup.usals_repeat USALS command repeat +motorcontrol.user_menu User menu +motorcontrol.install_menu Install menu +motorcontrol.step_west Step/Drive Motor West (b,c) +motorcontrol.step_east Step/Drive Motor East (b,c) +motorcontrol.halt Halt Motor +motorcontrol.west_limit Set West (soft) Limit +motorcontrol.east_limit Set East (soft) Limit +motorcontrol.enable_limit Enable (soft) Limits +motorcontrol.disable_limit Disable (soft) Limits +motorcontrol.ref_position Goto Reference Position +motorcontrol.calc_positions (Re)-Calculate Positions +motorcontrol.pos_increase Increase Motor Position (a) +motorcontrol.pos_decrease Decrease Motor Position (a) +motorcontrol.step_drive Switch Step/Drive Mode (b) +motorcontrol.store Store Motor Position (a) +motorcontrol.step_increase Increase Step Size (c) +motorcontrol.step_decrease Decrease Step Size (c) +motorcontrol.goto Goto Motor Position (a) +motorcontrol.notdef Not used +motorcontrol.motor_pos (a) Motor Position: +motorcontrol.settings Motor Control Settings +motorcontrol.movement (b) Movement: +motorcontrol.step_mode Step Mode +motorcontrol.drive_mode Drive Mode +motorcontrol.drive_mode_auto Drive Mode/auto stop +motorcontrol.timed_mode Timed Step Mode +motorcontrol.step_size (c) Step Size: +motorcontrol.stop_moving stop on good signal(moving) +motorcontrol.stop_stopped stop on good signal(stopped) +motorcontrol.no_mode don't care +motorcontrol.msec milliseconds +motorcontrol.status Status +motorcontrol.sat_pos Satellite Position (Step Mode): +mainsettings.timezone Timezone +scrambled_channel Scrambled channel +neutrino_starting Neutrino starting... +reset_channels Delete all channels +reset_settings Reset settings to defaults +reset_all Factory reset +reset_confirm Are you sure ? +cam.settings CI Cam +cam.empty No CAM in slot +cam.inserted CAM inserted in slot +cam.removed CAM removed from slot +cam.init_ok CAM init complete +cam.waiting Waiting for CI answer +cam.timeout Timeout waiting CI menu ready +subtitles.head Subtitles +subtitles.stop Stop subtitles +favorites.copy Copy bouquet to Favorites +fan_speed CPU Fan speed +audio.srs_iq SRS TruVolume algo +audio.srs_algo Type +audio.srs_algo_light Light +audio.srs_algo_normal Normal +audio.srs_volume Reference volume +audio.srs_nmgr Noise manager +cpu.freq Cpu frequency +cpu.freq_normal Normal frequency +cpu.freq_standby Standby frequency +cpu.freq_default default frequency +audioplayer.add_ic Icecast +audioplayer.add_loc Local radio list +audioplayer.add_sc Shoutcast +audioplayer.load_radio_stations Load internet radios +audioplayer.receiving_list Receiving list, please wait +inetradio.name Internetradio +upnpbrowser.head UPnP Browser +upnpbrowser.noservers No UPnP servers found +upnpbrowser.rescan Scan again +upnpbrowser.scanning Scanning for UPnP servers diff --git a/data/locale/francais.locale b/data/locale/francais.locale new file mode 100644 index 000000000..4e10ecbad --- /dev/null +++ b/data/locale/francais.locale @@ -0,0 +1,807 @@ +EPGMenu.epgplus Visualiasation liste évènements +EPGMenu.eventinfo Détails programme en cours +EPGMenu.eventlist Liste évènements programme en cours +EPGMenu.head EPG - Information du programme +EPGMenu.streaminfo Informations techniques +EPGPlus.actions Actions +EPGPlus.bybouquet_mode Par bouquet +EPGPlus.bypage_mode par Page +EPGPlus.change_font_size Taille caractère +EPGPlus.change_font_style Taille style +EPGPlus.change_size Taille +EPGPlus.channelentry_font caractère chaine +EPGPlus.channelentry_separationlineheight Hauteur ligne de séparation +EPGPlus.channelentry_width Largeur +EPGPlus.channelevententry_font Caractère événement +EPGPlus.edit_fonts edit Caractères +EPGPlus.edit_sizes edit Tailles +EPGPlus.font_style_bold style Gras +EPGPlus.font_style_italic style Italic +EPGPlus.font_style_regular style Régulier +EPGPlus.footer_fontbouquetchannelname Bas de page bouquet +EPGPlus.footer_fontbuttons Bas de page boutons +EPGPlus.footer_fonteventdescription Bas de page évènement +EPGPlus.footer_fonteventshortdescription Bas de page évènement réduit +EPGPlus.head Eventlist Présentation (EPG Plus) +EPGPlus.header_font Caractère Entête +EPGPlus.horgap1_height Hauteur1 +EPGPlus.horgap2_height Hauteur2 +EPGPlus.next_bouquet Bouquet suivant +EPGPlus.options Options +EPGPlus.page_down Page vers le bas +EPGPlus.page_up Page vers le haut +EPGPlus.prev_bouquet Bouquet précedent +EPGPlus.record Enregistrer +EPGPlus.refresh_epg Rafraîchir +EPGPlus.remind Rappel +EPGPlus.reset_settings Reset réglages +EPGPlus.save_settings Sauvegarder Réglages +EPGPlus.scroll_mode Mode défilement +EPGPlus.select_font_name Nom de caractère +EPGPlus.settings Réglages +EPGPlus.slider_width Largeur barette +EPGPlus.stretch_mode Mode déployé +EPGPlus.swap_mode Mode échange +EPGPlus.timeline_fontdate Caractère de Date +EPGPlus.timeline_fonttime Caractère d'heure +EPGPlus.vergap1_width Largeur1 +EPGPlus.vergap2_width Largeur2 +EPGPlus.view_mode Mode visualisation +GENRE.ARTS.0 arts / culture +GENRE.ARTS.1 arts contemporains +GENRE.ARTS.10 arts/culture magazines +GENRE.ARTS.11 mode +GENRE.ARTS.2 arts fins +GENRE.ARTS.3 religions +GENRE.ARTS.4 culture populaire/arts traditionels +GENRE.ARTS.5 littérature +GENRE.ARTS.6 film/cinéma +GENRE.ARTS.7 film expérimental/vidéo +GENRE.ARTS.8 broadcasting/press +GENRE.ARTS.9 nouvelle média +GENRE.CHILDRENs_PROGRAMMES.0 enfants / programme juvénile +GENRE.CHILDRENs_PROGRAMMES.1 programme pré-scolaire +GENRE.CHILDRENs_PROGRAMMES.2 programme de loisirs pour 6 à 14 +GENRE.CHILDRENs_PROGRAMMES.3 programme de loisirs pour 10 à 16 +GENRE.CHILDRENs_PROGRAMMES.4 programme information/éducation/école +GENRE.CHILDRENs_PROGRAMMES.5 déssins animés/marionettes +GENRE.DOCUS_MAGAZINES.0 documentaire / magazine +GENRE.DOCUS_MAGAZINES.1 nature/animaux/environnement +GENRE.DOCUS_MAGAZINES.2 sciences technologie/nature +GENRE.DOCUS_MAGAZINES.3 médecine/physiologie/psychologie +GENRE.DOCUS_MAGAZINES.4 Pays étrangers/expéditions +GENRE.DOCUS_MAGAZINES.5 Sciences sociales/spirituelles +GENRE.DOCUS_MAGAZINES.6 Aurtes éducations +GENRE.DOCUS_MAGAZINES.7 languages +GENRE.MOVIE.0 films/drames +GENRE.MOVIE.1 détective/Policier +GENRE.MOVIE.2 aventure/western/guerre +GENRE.MOVIE.3 science-fiction/fantaisie/horreur +GENRE.MOVIE.4 comédie +GENRE.MOVIE.5 opéra/mélodrame/folklore +GENRE.MOVIE.6 romantique +GENRE.MOVIE.7 serieux/classique/réligieux/film historique/drame +GENRE.MOVIE.8 Film adulte/drame +GENRE.MUSIC_DANCE.0 musique / ballet / dance +GENRE.MUSIC_DANCE.1 rock/pop +GENRE.MUSIC_DANCE.2 musique sérieuse/classique +GENRE.MUSIC_DANCE.3 folk/musique traditionelle +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musique/opéra +GENRE.MUSIC_DANCE.6 ballet +GENRE.NEWS.0 informations +GENRE.NEWS.1 info/météo +GENRE.NEWS.2 magazines d'info +GENRE.NEWS.3 documentaire +GENRE.NEWS.4 discussion/interview/débat +GENRE.SHOW.0 Show / Gameshow +GENRE.SHOW.1 game show/quiz/concours +GENRE.SHOW.2 varieté show +GENRE.SHOW.3 discours show +GENRE.SOCIAL_POLITICAL.0 évènements socials & politiques / affaires +GENRE.SOCIAL_POLITICAL.1 magazines/reportages/documentaires +GENRE.SOCIAL_POLITICAL.2 conseil économique/social +GENRE.SOCIAL_POLITICAL.3 peuple remarquable +GENRE.SPORTS.0 sports +GENRE.SPORTS.1 évenemnts spéciaux (Jeux Olympiques,Coupe du Monde etc.) +GENRE.SPORTS.10 équitation +GENRE.SPORTS.11 sports martiaux +GENRE.SPORTS.2 magazines de sports +GENRE.SPORTS.3 football +GENRE.SPORTS.4 tennis/squash +GENRE.SPORTS.5 sports d'équipe (hors football) +GENRE.SPORTS.6 athlétisme +GENRE.SPORTS.7 sports de moteurs +GENRE.SPORTS.8 sports acquatiques +GENRE.SPORTS.9 sports d'hiver +GENRE.TRAVEL_HOBBIES.0 voyage et détente +GENRE.TRAVEL_HOBBIES.1 tourisme/voyage +GENRE.TRAVEL_HOBBIES.2 artisanet +GENRE.TRAVEL_HOBBIES.3 automobilisme +GENRE.TRAVEL_HOBBIES.4 fitness & santé +GENRE.TRAVEL_HOBBIES.5 cuisine +GENRE.TRAVEL_HOBBIES.6 publicité/shopping +GENRE.TRAVEL_HOBBIES.7 jardinage +GENRE.UNKNOWN inconnu +apids.hint_1 Entrer APIDs à streamer +apids.hint_2 en notation hex séparé par ' ' +apidselector.head Sélectionner language +audiomenu.PCMOffset diminuer le Volume PCM +audiomenu.analogout sortie Analogique +audiomenu.avs avs +audiomenu.avs_control Contrôle de Volume avs/ost +audiomenu.dolbydigital Dolby Digital +audiomenu.head Réglages Audio +audiomenu.lirc lirc +audiomenu.monoleft mono gauche +audiomenu.monoright mono droite +audiomenu.ost ost +audiomenu.stereo stéreo +audioplayer.add Ajouter +audioplayer.artist_title Artiste, Titre +audioplayer.button_select_title_by_id chercher par ID +audioplayer.button_select_title_by_name charcher par nom +audioplayer.defdir dir. de Départ +audioplayer.delete éffacer +audioplayer.deleteall tout éffacer +audioplayer.display_order afficher ordre +audioplayer.fastforward avance rapide. +audioplayer.follow selection autode l'encours +audioplayer.head liste Liste Audio +audioplayer.highprio Pririté de décodage élevé +audioplayer.id3scan étiquette ID3 de Scanning +audioplayer.jump_backwards Saut à l'arrière +audioplayer.jump_dialog_hint1 Entrer cible pour saut SVP +audioplayer.jump_dialog_hint2 (relative, en secondes) +audioplayer.jump_dialog_title Entrer cible pour saut +audioplayer.jump_forwards Saut en avant +audioplayer.keylevel Niveau de clé +audioplayer.name Audioplayer +audioplayer.pause pause +audioplayer.play écouter +audioplayer.playing Piste en cours +audioplayer.playlist_fileerror_msg Fichier non crée: +audioplayer.playlist_fileerror_title Erreur +audioplayer.playlist_fileoverwrite_msg Voulez-vous écraser l'ancien fichier: +audioplayer.playlist_fileoverwrite_title écraser? +audioplayer.playlist_name Nom de fichier de la liste +audioplayer.playlist_name_hint1 Entrer le nom de fichier de la liste SVP +audioplayer.playlist_name_hint2 l'extension .m3u sera ajouté automatiquement +audioplayer.repeat_on Mode répétition activé +audioplayer.rewind rebibiner +audioplayer.save_playlist sauvegarder la liste +audioplayer.screensaver_timeout Ecran de sauvegarde timeout (min, 0=off) +audioplayer.select_title_by_name Chercher titre par nom (SMS) +audioplayer.show_playlist Montrer la liste +audioplayer.shuffle Pas +audioplayer.stop Stop +audioplayer.title_artist Titre, Artiste +audioplayerpicsettings.general Lecteur audio/Visualiseur de Photos +bookmarkmanager.delete Effacer +bookmarkmanager.name Marquer +bookmarkmanager.rename renommer +bookmarkmanager.select sélectionner +bouqueteditor.add Ajouter +bouqueteditor.bouquetname Nom de bouquets +bouqueteditor.delete Effacer +bouqueteditor.discardingchanges Annulation des changement. Patienter SVP... +bouqueteditor.hide Cacher +bouqueteditor.lock Bloquer +bouqueteditor.move Dépalcer +bouqueteditor.name Editeur de bouquet +bouqueteditor.newbouquetname Nouveau nom de bouquets +bouqueteditor.rename Renommer +bouqueteditor.return Prêt +bouqueteditor.savechanges? Voulez-vous sauvegarder les changements? +bouqueteditor.savingchanges Sauvegarde des changements. Pateientez SVP... +bouqueteditor.switch ajout/suppression +bouqueteditor.switchmode TV/Radio +bouquetlist.head Bouquets +cablesetup.provider Fournisseur de service +channellist.head tout les services +channellist.nonefound Aucune chaines trouvée!\néxecuter un scan\n(DBOX-key -> service) +channellist.since depuis %02d:%02d +colorchooser.alpha alpha +colorchooser.blue bleu +colorchooser.green vert +colorchooser.red rouge +colormenu.background Arrière plan +colormenu.background_head Arrière plan +colormenu.fade Fade menus +colormenu.font Font taille +colormenu.gtx_alpha Transparence (GTX) +colormenu.head Color Régalges +colormenu.menucolors Couleur de Menu +colormenu.statusbar Barre d'info +colormenu.textcolor Couleur du texte +colormenu.textcolor_head Couleur de texte +colormenu.themeselect sélectionner le thème +colormenu.timing Temporisation OSD +colormenusetup.head Couleurs du Menu +colormenusetup.menucontent Contenu Fenêtre +colormenusetup.menucontent_inactive Contenue Fenêtre inactive +colormenusetup.menucontent_selected Contenue Fenêtre sélectinnée +colormenusetup.menuhead Menu entête +colorstatusbar.head Barre d'info +colorstatusbar.text Barre d'info +colorthememenu.classic_theme Thème Classique +colorthememenu.dblue_theme Thème bleu foncé +colorthememenu.dvb2k_theme Thème DVB2000 +colorthememenu.head Sélecteur de thème +colorthememenu.neutrino_theme Thème Neutrino +date.Apr Avr +date.Aug Aoû +date.Dec Déc +date.Feb Fév +date.Fri Ven +date.Jan Jan +date.Jul Jul +date.Jun Jui +date.Mar Mar +date.May Mai +date.Mon Lun +date.Nov Nov +date.Oct Oct +date.Sat Sam +date.Sep Sép +date.Sun Dim +date.Thu Jeu +date.Tue Mar +date.Wed Mer +epglist.head Liste Evenement - %s +epglist.noevents Pas d'EPG disponible... +epgviewer.More_Screenings Plus de diffusion sur cette chaine +epgviewer.nodetailed Pas d'informations détaillée disponible +epgviewer.notfound Pas d'EPG trouvé +eventlistbar.channelswitch Agenda +eventlistbar.eventsort Classement +eventlistbar.recordevent Enregistrement +favorites.addchannel La chaine en cours sera ajoutée \nau bouquet "Mes Favories". \n ça prendra quelques secondes... +favorites.bouquetname Mes Favories +favorites.bqcreated Le Bouquet "Mes Favories" est crée...\n +favorites.chadded La chaine en cours est ajoutée à vos favories...\n +favorites.chalreadyinbq La chaine en cours est déja dans vos favories...\n +favorites.finalhint \nUtilise l'éditeur de bouquet pour modifier vos favories.\n +favorites.menueadd Ajouter une chaine aux favories +favorites.nobouquets Les Favories sont disponibles les bouquets activés uniquement. +filebrowser.delete Effacer +filebrowser.denydirectoryleave Répertoire de démarrage réel +filebrowser.dodelete1 Effacer +filebrowser.dodelete2 ? +filebrowser.filter.active Filtre on +filebrowser.filter.inactive Filtre off +filebrowser.head Navigateur de fichiers +filebrowser.mark Marquer +filebrowser.nextpage Page suivante +filebrowser.prevpage Page précedente +filebrowser.scan Balayage de réprtoire +filebrowser.select Selectionner +filebrowser.showrights Montrer les attribues de fichier +filebrowser.sort.date (date) +filebrowser.sort.name (Nom de fichier) +filebrowser.sort.namedirsfirst (Nom de fichier2) +filebrowser.sort.size (Taille) +filebrowser.sort.type (type) +flashupdate.actionreadflash Lecture +flashupdate.cantopenfile Ouverture de fichier impossible +flashupdate.cantopenmtd Ouverture de mtd-device impossible +flashupdate.checkupdate Recherche de nouvelle version +flashupdate.currentreleasecycle Cycle de sortie +flashupdate.currentversion_sep Version courante +flashupdate.currentversiondate Date +flashupdate.currentversionsnapshot Type d'Image +flashupdate.currentversiontime heure +flashupdate.erasefailed Effacement du flash échoué +flashupdate.erasing Effacement flash +flashupdate.experimentalimage L'Image sélectionnée est une version non testée, Ca veut dire \nvotre récepteur ne plus redémarrer après la mise à jour.\n\nvoulez-vous vraiment mettre à jour avec cette version? +flashupdate.expertfunctions Fonctions Expert +flashupdate.fileis0bytes La taille du fichier est 0 Bytes +flashupdate.fileselector Sélecteur de fichier +flashupdate.flashreadyreboot L'Image est flashée avec succès.\nLe récepteur va redémarrer maintenant. +flashupdate.getinfofile Obtention de l'info version +flashupdate.getinfofileerror Impossible d'extraire l'info version +flashupdate.getupdatefile Obtention de la m.à.j (mise à jour) +flashupdate.getupdatefileerror Impossible d'extraire la m.à.j +flashupdate.globalprogress Progression globale: +flashupdate.head m.à.j du Software (Mise à jour du programme) +flashupdate.md5check Vérification de l'Image +flashupdate.md5sumerror L'Image a des erreurs +flashupdate.msgbox La nouvelle image suivante est trouvée:\nDate: %s, %s\nBaseImage: %s\nImageType: %s\n\nVoulez-vous télécharger et installer cette version maintenant? +flashupdate.msgbox_manual La nouvelle image suivante est trouvée:\nDate: %s, %s\nBaseImage: %s\nImageType: %s\n\nVoulez-vous télécharger et installer cette version maintenant? +flashupdate.mtdselector Sélecteur de partition +flashupdate.programmingflash programmation du flash +flashupdate.proxypassword Mot de passe +flashupdate.proxypassword_hint1 entrer le mot de pass du serveur proxy +flashupdate.proxypassword_hint2 Entrée vide veut dire pas de proxy-auth +flashupdate.proxyserver Nom de l'hôte +flashupdate.proxyserver_hint1 entrer le nom du serveur proxy ou bien ip, utiliser hôte:port +flashupdate.proxyserver_hint2 Entrée vide veut dire pas de proxy +flashupdate.proxyserver_sep Serveur Proxy +flashupdate.proxyusername Nom d'utilisateur +flashupdate.proxyusername_hint1 entrer le nom d'utilisateur du serveur proxy +flashupdate.proxyusername_hint2 Entrée vide veut dire pas de proxy-auth +flashupdate.readflash Lire l'image entièrement +flashupdate.readflashmtd Lire une partition +flashupdate.ready Prêt +flashupdate.reallyflashmtd Vous voulez vraiment flasher?\n\nSi une erreur survient ou l'Image est non\nvalide, le récepteur ne redémarrera pas après le flash.\n\nImagename: %s\nTarget: %s +flashupdate.savesuccess L'Image est sauvegardée avec succès \nsous %s. +flashupdate.selectimage Images disponibles +flashupdate.squashfs.noversion La vérification de la version SquashFS version ne sont supportée que lors de la m.à.j via le WEB actuellement.\nVoulez-vous vraiment installer cette Image? +flashupdate.titlereadflash Lecture du Flash +flashupdate.titlewriteflash Ecriture du Flash +flashupdate.updatemode Mode de m.à.j +flashupdate.updatemode_internet internet +flashupdate.updatemode_manual manuel (ftp) +flashupdate.url_file Fichier de configuration +flashupdate.versioncheck Vérification de la version +flashupdate.writeflash Ecrire l'Image entièrement +flashupdate.writeflashmtd Ecrire une partition +flashupdate.wrongbase Votre cycle de sortie est différent, Incapable de mettre à jour\nsans avoir installé la version convenable! +fontmenu.channellist Liste de chaines +fontmenu.epg EPG +fontmenu.eventlist Liste d'évènements +fontmenu.gamelist Liste de jeux +fontmenu.head Réglage taille caractère +fontmenu.infobar Barre d'Info +fontsize.channel_num_zap Sélection directe +fontsize.channellist Liste de chaines +fontsize.channellist_descr Déscription +fontsize.channellist_number Numéro +fontsize.epg_date EPG Date +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Titre +fontsize.eventlist_datetime date / heure +fontsize.eventlist_itemlarge large +fontsize.eventlist_itemsmall petit +fontsize.eventlist_title Titre +fontsize.filebrowser_item Article du navigateur de fichier +fontsize.gamelist_itemlarge large +fontsize.gamelist_itemsmall petit +fontsize.hint Initialisation caractère,\nattendre SVP... +fontsize.infobar_channame Nom de chaine +fontsize.infobar_info info +fontsize.infobar_number Numéro +fontsize.infobar_small petit +fontsize.menu Menu texte +fontsize.menu_info Menu Info +fontsize.menu_title Menu Titre +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.epgnotload EPG non chargé.... +infoviewer.epgwait attente EPG... +infoviewer.eventlist Liste d'évènements +infoviewer.languages Audio +infoviewer.motor_moving positionnement de l'antenne +infoviewer.nocurrent Pas d'info pour le programme en cours +infoviewer.noepg Pas d'EPG disponible +infoviewer.notavailable Chaine non disponible +infoviewer.selecttime Sélection heure +infoviewer.streaminfo Options de caractéristiques +infoviewer.subservice Sous services +infoviewer.waittime Attented d'heure... +ipsetup.hint_1 Utilise 0..9, ou bien haut/bas, +ipsetup.hint_2 OK sauvegader, LAME! annuler +keybindingmenu.RC Touche repeat-blocker +keybindingmenu.addrecord Ajouter horaire d'enregistrement +keybindingmenu.addrecord_head Ajouter horaire d'enregistrement +keybindingmenu.addremind Ajouter horaire de zap vers... +keybindingmenu.addremind_head Ajouter horaire de zap vers... +keybindingmenu.allchannels_on_ok tous-services +keybindingmenu.bouquetchannels_on_ok bouquet en cours +keybindingmenu.bouquetdown bouquet arrière +keybindingmenu.bouquetdown_head Choix touche bouquet arrière +keybindingmenu.bouquethandling Contrôle de Bouquet +keybindingmenu.bouquetlist_on_ok Liste de bouquets +keybindingmenu.bouquetup next bouquet +keybindingmenu.bouquetup_head Choix touche bouquet avant +keybindingmenu.cancel Fermer liste de chaines +keybindingmenu.cancel_head Fermer liste de chaines +keybindingmenu.channeldown chaine bas +keybindingmenu.channeldown_head Choix touche chaine arrière +keybindingmenu.channellist Liste de chaines +keybindingmenu.channelup chaine avant +keybindingmenu.channelup_head Choix touche chaine avant +keybindingmenu.head Réglage des touches +keybindingmenu.lastchannel Zap rapide +keybindingmenu.lastchannel_head Zap rapide +keybindingmenu.modechange Mode changement +keybindingmenu.pagedown page bas +keybindingmenu.pagedown_head Choix touche page bas +keybindingmenu.pageup page haut +keybindingmenu.pageup_head Choix touche page haut +keybindingmenu.quickzap zap rapide +keybindingmenu.repeatblock délai de répétition +keybindingmenu.repeatblockgeneric délai générique +keybindingmenu.sort changer l'ordre de classement +keybindingmenu.sort_head changer l'ordre de classement +keybindingmenu.subchanneldown sous-chaine bas +keybindingmenu.subchanneldown_head touche sous-chaine bas +keybindingmenu.subchannelup sous-chaine haut +keybindingmenu.subchannelup_head touche sous-chaine haut +keybindingmenu.tvradiomode Mode TV/Radio +keybindingmenu.tvradiomode_head Mode TV/Radio +keybindingmenu.zaphistory Zapping Bouquet Historique +keybindingmenu.zaphistory_head Zapping Bouquet historique +keychooser.head Setup nouvelle touche +keychooser.text1 Appuyer sur la nouvelle touche SVP +keychooser.text2 Attendez quelques secondes pour quitter +keychoosermenu.currentkey touche en cours +keychoosermenu.setnew réglage nouvelle touche +keychoosermenu.setnone Pas de touche +languagesetup.head Réglage Langue +languagesetup.select Langue +lcdcontroler.brightness Brillance normale +lcdcontroler.brightnessstandby Brillance de veille +lcdcontroler.contrast Contraste +lcdcontroler.head Réglage LCD +lcdmenu.autodimm Estompage Auto +lcdmenu.head LCD Réglages +lcdmenu.inverse Inverse +lcdmenu.lcdcontroler Contraste / Brillance +lcdmenu.power Alimentation +lcdmenu.statusline Ligne d'état +lcdmenu.statusline.both Volume / temps écoulé +lcdmenu.statusline.playtime Temps écoulé +lcdmenu.statusline.volume Volume +mainmenu.audioplayer Lecteur Audio +mainmenu.games Jeux +mainmenu.head MENU PRINCIPAL +mainmenu.movieplayer Lecteur Vidéo +mainmenu.pausesectionsd Lire EPG +mainmenu.pictureviewer Visionneur de photos +mainmenu.radiomode Mode Radio +mainmenu.recording Enregistrement +mainmenu.recording_start Début +mainmenu.recording_stop stop +mainmenu.scartmode Mode Péritel +mainmenu.service Service +mainmenu.settings Réglages +mainmenu.shutdown Eteindre +mainmenu.sleeptimer Veille +mainmenu.tvmode Mode TV +mainsettings.audio Audio +mainsettings.colors Coleurs / thèmes / Caractères +mainsettings.head Réglages +mainsettings.keybinding Réglage touche +mainsettings.language Langue +mainsettings.lcd Ecran à Cristaux Liquides (LCD) +mainsettings.misc Réglage divers +mainsettings.network Réseau +mainsettings.recording Enregistrement +mainsettings.savesettingsnow Sauvegarder réglage maintenant +mainsettings.savesettingsnow_hint Sauvegarde de réglage,\nPatientez SVP... +mainsettings.streaming Lecteur vidéo +mainsettings.video Vidéo +menu.back Retour +messagebox.back Retour +messagebox.cancel Annuler +messagebox.discard Annuler les changemnts? +messagebox.error Erreur +messagebox.info Information +messagebox.no Non +messagebox.yes Oui +miscsettings.bootinfo Montrer les infos au démarrage +miscsettings.bootmenu Montrer le menu démarrage +miscsettings.driver_boot Options de driver et Démarrage +miscsettings.fb_destination Console de démarrage Expert! +miscsettings.general Général +miscsettings.head Réglages divers +miscsettings.hwsections Utiliser les sections hardware +miscsettings.infobar_sat_display Affichage du satellite dans la barre d'infos +miscsettings.pmtupdate enable m.à.j pmt +miscsettings.shutdown_real Permettre Veille +miscsettings.shutdown_real_rcdelay Arrêt retardé +miscsettings.sptsmode utiliser le mode spts +miscsettings.startbhdriver Charger les drivers du Mode BH +motorcontrol.head Réglage moteur +movieplayer.bookmark Signet +movieplayer.bookmarkname Nom du signet +movieplayer.bookmarkname_hint1 Entrer un nom pour votre nouveau signet +movieplayer.bookmarkname_hint2 +movieplayer.buffering (Tampons)Buffering... +movieplayer.defdir dir. de démarrage +movieplayer.dvdplayback DVD +movieplayer.fileplayback Fichier via VLC +movieplayer.goto Saut vers ... +movieplayer.goto.h1 = -> Saut absolu +movieplayer.goto.h2 +,- -> Saut relatif +movieplayer.head Lecteur vidéo +movieplayer.nostreamingserver Le serveur Streaming n'est pas accessible. +movieplayer.pesplayback Lecture PES (Expérimental) +movieplayer.pleasewait Patienter SVP.\nConnection au serveur streaming... +movieplayer.toomanybookmarks Il y'a plusieurs signets.\nVous avez à éffacer l'un d'eux avant. +movieplayer.tshelp Rouge/LAME(Exit)! Stop\nVERT Sélection piste audio\nJAUNE Pause/Continu\nBLEU Créer signet\nRécepteur montre progression\n1 approx. 1 minute arrière\n3 saut approx. 1 minute\n4 approx. 5 minutes arrière\n6 saut approx. 5 minutes\n7 approx. 10 minutes arrière\n9 skip approx. 10 minutes\nHelp: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tsplayback Lecture TS +movieplayer.vcdplayback (S)VCD +movieplayer.vlchelp Rouge/LAME(Exit)! Stop\nVERT Resync\nJAUNE Pause/Continu\nBLEU Créer signet\nRécepteur montre Progression\n1 approx. 1 minute arrière\n3 saut approx. 1 minute\n4 approx. 5 minutes arrière\n6 saut approx. 5 minutes\n7 approx. 10 minutes arrière\n9 saut approx. 10 minutes\nHelp: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.wrongvlcversion Cette option n'est pas supportée par votre version courante de VLC +networkmenu.broadcast Transmisson +networkmenu.dhcp DHCP +networkmenu.gateway Entrée par défaut +networkmenu.head Réglage réseau +networkmenu.ipaddress Adresse IP +networkmenu.mount NFS/CIFS +networkmenu.nameserver Nom du serveur +networkmenu.netmask Masque du net +networkmenu.setupnow Régler le réseau maintenant +networkmenu.setuponstartup Régler le réseau au démarrage +networkmenu.show montrer le régalge du réseau actif +networkmenu.test tester le réseau maintenant +nfs.alreadymounted repértoire déja monté +nfs.automount monter au démarrage +nfs.dir Répertoire/paratge +nfs.ip IP du sereveur NFS/CIFS +nfs.localdir Répertoire Local de NFS/CIFS +nfs.mount Monter Volume NFS/CIFS +nfs.mount_options Options de montage NFS/CIFS +nfs.mounterror erreur montage NFS/CIFS +nfs.mounterror_notsup Type de système de fichier non supporté pour NFS/CIFS +nfs.mountnow monter maintenant NFS/CIFS +nfs.mounttimeout erreur montage NFS/CIFS: Dépassement du temps alloué +nfs.password Mot de passe CIFS +nfs.remount répertoire de remontage NFS/CIFS +nfs.type type +nfs.type_cifs CIFS +nfs.type_nfs NFS +nfs.umount éffacer volume montage NFS/CIFS(Unmount) +nfs.umounterror erreur éffacement montage volume NFS/CIFS +nfs.username Nom d'utilisateur CIFS +nfsmenu.head Réglages NFS/CIFS +nvod.percentage (%d%% fini) +nvod.starting (démarrage dans %d min) +nvodselector.head Sélectionner heure démarrage +nvodselector.subservice Sélectionner Sous-service +options.default Reset à par défaut +options.fb framebuffer +options.null null +options.off off +options.on on +options.serial série +parentallock.changepin changer PIN code +parentallock.changepin_hint1 Entrer votre code de protection(PIN) ici! +parentallock.changetolocked pour les bouquets bloquer +parentallock.head Entrer code parental (PIN) +parentallock.lockage Bloquer le programme +parentallock.lockage12 pour 12 ans et plus +parentallock.lockage16 pour 16 ans et plus +parentallock.lockage18 pour 18 ans et plus +parentallock.lockedchannel Expéditeur bloqué... +parentallock.lockedprogram Programme bloqué (pour %d ans et plus) +parentallock.never jamais +parentallock.onsignal pour fournisseur bloquer +parentallock.parentallock Protection parentale +parentallock.prompt ponctuellemnt pour PIN +pictureviewer.defdir Répertoire de démarrage. +pictureviewer.head Visualiseur de photos +pictureviewer.resize.color_average avancé +pictureviewer.resize.none aucun +pictureviewer.resize.simple simple +pictureviewer.scaling réajustement +pictureviewer.show montrer +pictureviewer.slide_time temps de défilement +pictureviewer.slideshow défilement +pictureviewer.sortorder changer l'ordre de tri +pictureviewer.sortorder.date (date) +pictureviewer.sortorder.filename (Nom de fichier) +ping.ok est joignable (ping) +ping.protocol est injoignable (erreur hôte ou protocole) +ping.socket est injoignable (erreur socket) +ping.unreachable est injoignable +pinprotection.head Entrer code PIN +pinprotection.wrongcode Le code PIN est faux! Essayer encore. +rclock.lockmsg votre télécommande Récepteur sera bloquée.\n pour débloquer, Appuyer \n et sur la Télécommande. +rclock.menueadd Bloquer Télécommande (RC) +rclock.title Bloquer Télécommande (RC) +rclock.unlockmsg Télécommande réactivée. +recordingmenu.defdir Répertoire d'enregistrement +recordingmenu.file Directe (fichier) +recordingmenu.filesettingsseparator Enregistrement directe +recordingmenu.head Réglages d'enregistrement +recordingmenu.help Dispositifs d'enregistrement:\n--------------------------\nserveur:\nutilisation du programme de streaming sur PC\n\n(analogique) vcr:\nutilisation de la sortie vcr\n\ndirecte (fichier):\ndirectement dans le répertoire NFS mounté\nsur le dique dur interne(HDD)\nTS: utiliser mode spts (dbox2)\nPES: ne pas utiliser le mode spts(dbox2)\n\n\nTaille fichier Max.:\n---------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: Presque illimité (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart Ne pas balancer vers le mode Péritel +recordingmenu.off off +recordingmenu.recording_type Dispositif d'enregistrement +recordingmenu.server serveur +recordingmenu.server_ip IP serveur d'enregistrement +recordingmenu.server_mac Adresse MAC +recordingmenu.server_port PORT serveur d'enregistrement +recordingmenu.server_wakeup WOL serveur d'enregistrement +recordingmenu.setupnow activater les changements +recordingmenu.splitsize Max. Taille fichier (MB) +recordingmenu.stopplayback stop playback +recordingmenu.stopsectionsd stop section sd +recordingmenu.stream_all_audio_pids enregistrer tout les PIDS audio +recordingmenu.stream_vtxt_pid enregistrer le videotext +recordingmenu.use_o_sync écrire synchrone (O_SYNC) +recordingmenu.vcr vcr +recordtimer.announce L'enregistrement démarre dans quelques minutes +repeatblocker.hint_1 Durée test court (in ms) pour reconnaitre 2 keystrokes +repeatblocker.hint_2 Entrer 0 pour éteindre le blocker (rouge est espace) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat Répetitions DiSEqC +satsetup.extended Réglages DiSEqC +satsetup.extended_motor Réglages Moteur +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Réglages Moteur Manuel +satsetup.nodiseqc Pas de DiSEqC +satsetup.satellite Satellite +satsetup.savesettingsnow sauvegarder réglages maintenant +satsetup.smatvremote mise au point SMATV +scants.actcable Cable: +scants.actsatellite Satellite: +scants.bouquet Bouquet +scants.bouquet_create créer nouveau +scants.bouquet_erase Tout éffacer +scants.bouquet_leave Laisser l'actuel +scants.bouquet_satellite Satellite-Bouquet +scants.bouquet_update mettre à jour +scants.channel Chaine: +scants.failed Balayage du Transpondeur échoué! +scants.finished Balayage du Transpondeur réussi! +scants.freqdata Fréquence: +scants.head Balayer le transpondeur +scants.numberofdataservices Data +scants.numberofradioservices Radio +scants.numberoftotalservices Total +scants.numberoftvservices TV +scants.provider Provider(Fournisseur): +scants.startnow commencer le Balayage +scants.transponders Transpondeurs: +screensetup.lowerright Vert = réglage du bas à droite +screensetup.upperleft Rouge = réglage du haut à gauche +servicemenu.head Service +servicemenu.reload Recharger listes de chaines +servicemenu.reload_hint Rechargement listes de chaines,\nPatientez SVP. +servicemenu.scants Balayage du service +servicemenu.ucodecheck Verifier ucodes +servicemenu.update Mise à jour du Software +settings.help Aide +settings.missingoptionsconffile Les réglages NEUTRINO sont mis à jour.\nDes nouvelles Options seront mis par défaut. +settings.noconffile Pas de réglages NEUTRINO trouvés.\nUtilisation de celles par défaut. +shutdowntimer.announce Le récepteur sera arrêté dans 1 min.\nAnnuler arrêt? +sleeptimerbox.announce Veille dans in 1 min +sleeptimerbox.hint1 Arrêt dans in min. (000=off) +sleeptimerbox.hint2 Le récepteur sera arrêté après ce temps. +sleeptimerbox.title Veille +streamfeatures.head Caractéristiques +streaminfo.aratio Aspect de proportion +streaminfo.aratio_unknown Aspect de proportion: inconnu +streaminfo.audiotype Type Audio +streaminfo.audiotype_unknown Type Audio: inconnu +streaminfo.bitrate Bitrate +streaminfo.framerate Framerate +streaminfo.framerate_unknown Framerate: inconnu +streaminfo.head Information Stream +streaminfo.not_available Non disponible +streaminfo.resolution Résolution +streaminfo.signal Receipt signal +streaming.buffer_overflow L'enregistrement est abondonné,\nTant que les données ne peuvent être écrites assez rapidement. +streaming.busy Un ou plusieurs processus d'enregistrement sont actifs.\nSi vous rencontrez ce message et aucun enregistrement n'est actif, Redémarrer NEUTRINO SVP. +streaming.dir_not_writable Le répertoire d'enregistrement n'est pas autorisé en écriture.\nL'enregistrement ne fonctionnera pas. +streaming.success L'enregistrement est effectué avec succès. +streaming.write_error L'enregistrement est abondonné,\nTant qu'une erreur est survenue lors du processus d'écriture. +streaming.write_error_open L'enregistrement est abondonné,\nParceque le fichier cible ne peut être ouvert. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Réglages Lecteur vidéo +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Off +streamingmenu.on On +streamingmenu.server_ip IP Serveur Streaming +streamingmenu.server_port PORT Serveur Streaming +streamingmenu.streaming_audiorate Taux de données Audio +streamingmenu.streaming_force_avi_rawaudio Forcer AC3 pour AVI +streamingmenu.streaming_force_transcode_video Transcoder MPG/VCD vidéo +streamingmenu.streaming_resolution Résolution +streamingmenu.streaming_server_cddrive DVD Drive +streamingmenu.streaming_server_startdir Répertoire (VLC) +streamingmenu.streaming_transcode_audio Transcoder audio (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec MPEG vidéo codec +streamingmenu.streaming_type Serveur Streaming +streamingmenu.streaming_videorate Taux de données Vidéo +streamingserver.noconnect Pas de connection au serveur streaming.\nEnregistrement annulé. +stringinput.caps caps / Pas de caps +stringinput.clear Tout éffacer +timer.eventrecord.msg ... à exécuter, ou bien non +timer.eventrecord.title Programmer enregistrement +timer.eventtimed.msg L'évènement est programmé.\nLe récepteur démarrera et \basculera vers cette chaine à l'heure programmée. +timer.eventtimed.title Programme Evènement +timerbar.channelswitch programmer +timerbar.recordevent Enregistrer +timerlist.alarmtime Réveil +timerlist.apids PIDs Audio +timerlist.bouquetselect Choisir bouquet +timerlist.channel Chaine +timerlist.channelselect choisir chaine +timerlist.delete éffacer +timerlist.menumodify Modifier horaire +timerlist.menunew Nouvel horaire +timerlist.message Message +timerlist.moderadio Chaines Radio +timerlist.modeselect Mode sélection +timerlist.modetv Chaines TV +timerlist.modify Modifier +timerlist.name Liste horaire +timerlist.new nouvel horaire +timerlist.program.unknown Programme inconnu +timerlist.reload Recharger +timerlist.repeat Repéter +timerlist.repeat.biweekly bi-hebdomadaire +timerlist.repeat.byeventdescription Voir Horaire +timerlist.repeat.daily Quotidien +timerlist.repeat.fourweekly Quatre fois/semaine +timerlist.repeat.friday Vendredi +timerlist.repeat.monday Lundi +timerlist.repeat.monthly mensuellement +timerlist.repeat.once une fois +timerlist.repeat.saturday Samedi +timerlist.repeat.sunday Dimanche +timerlist.repeat.thursday Jeudi +timerlist.repeat.tuesday Mardi +timerlist.repeat.unknown inconnu +timerlist.repeat.wednesday Mercredi +timerlist.repeat.weekdays Jours de la semaine +timerlist.repeat.weekly Hebdomadaire +timerlist.save Sauvegarder horaire +timerlist.standby Mode SB +timerlist.standby.off Quitter Veille +timerlist.standby.on Entrer en Veille +timerlist.stoptime heure Arrêt +timerlist.type Type d'horaire +timerlist.type.nextprogram Prochain programme +timerlist.type.record Enregistrer +timerlist.type.remind Rappeler +timerlist.type.shutdown Arrêt +timerlist.type.sleeptimer Veille programmée +timerlist.type.standby Veille +timerlist.type.unknown inconnu +timerlist.type.zapto Zapper vers +timerlist.weekdays Jours de la semaine +timerlist.weekdays.hint_1 Lun Mar Mar Jeu Ven Sam Dim +timerlist.weekdays.hint_2 'X'=Horaire '-' Pas d'horaire +timersettings.record_safety_time_after Correction du temps d'arrêt d'enregistrement +timersettings.record_safety_time_after.hint_1 Temps de Correction en min. (00=off). Ce temps +timersettings.record_safety_time_after.hint_2 sera ajouté à chaque horaire d'enregistrement. +timersettings.record_safety_time_before Correction du temps de démarrage d'enregistrement +timersettings.record_safety_time_before.hint_1 Temps de Correction en min. (00=off). Ce temps +timersettings.record_safety_time_before.hint_2 sera déduit de chaque horaire d'enregistrement. +timersettings.separator Réglages d'horaire +timing.chanlist Liste chaine +timing.epg Epg +timing.filebrowser Navigateur de fichier +timing.head Temps d'éclipse OSD +timing.hint_1 Temps en sec. Après ce temps +timing.hint_2 la barre d'infos disparaîtra . +timing.infobar Barre d'infos +timing.menu Menu +timing.numericzap Zap Numerique +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head vérification UCode +ucodecheck.ucode UCode +ucodes.failure ATTENTION, µCodes ne sont pas trouvés!\n\nTélécharger les via FTP (ou bien Récepteur-BootManager),\nensuite redémarrer votre récepteur! +videomenu.csync Correction sync +videomenu.head Réglages Vidéo +videomenu.rgb_centering Centrage RGB +videomenu.screensetup Réglage écran +videomenu.vcrswitch Balance Péritel automatique +videomenu.videoformat Format +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect Détection automatique +videomenu.videosignal Sortie Vidéo +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Vidéo +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce Zapper vers programmeur dans une minute diff --git a/data/locale/french.locale b/data/locale/french.locale new file mode 100644 index 000000000..3f388b9ed --- /dev/null +++ b/data/locale/french.locale @@ -0,0 +1,1237 @@ +EPGMenu.epgplus Visualiasation liste évènements +EPGMenu.eventinfo Détails programme en cours +EPGMenu.eventlist Liste évènements programme en cours +EPGMenu.head EPG - Information du programme +EPGMenu.streaminfo Informations techniques +EPGPlus.actions Actions +EPGPlus.bybouquet_mode Par bouquet +EPGPlus.bypage_mode par Page +EPGPlus.change_font_size Taille caractère +EPGPlus.change_font_style Taille style +EPGPlus.change_size Taille +EPGPlus.channelentry_font caractère chaine +EPGPlus.channelentry_separationlineheight Hauteur ligne de séparation +EPGPlus.channelentry_width Largeur +EPGPlus.channelevententry_font Caractère événement +EPGPlus.edit_fonts edit Caractères +EPGPlus.edit_sizes edit Tailles +EPGPlus.font_style_bold style Gras +EPGPlus.font_style_italic style Italic +EPGPlus.font_style_regular style Régulier +EPGPlus.footer_fontbouquetchannelname Bas de page bouquet +EPGPlus.footer_fontbuttons Bas de page boutons +EPGPlus.footer_fonteventdescription Bas de page évènement +EPGPlus.footer_fonteventshortdescription Bas de page évènement réduit +EPGPlus.head Eventlist Présentation (EPG Plus) +EPGPlus.header_font Caractère Entête +EPGPlus.horgap1_height Hauteur1 +EPGPlus.horgap2_height Hauteur2 +EPGPlus.next_bouquet Bouquet suivant +EPGPlus.options Options +EPGPlus.page_down Page vers le bas +EPGPlus.page_up Page vers le haut +EPGPlus.prev_bouquet Bouquet précedent +EPGPlus.record Enregistrer +EPGPlus.refresh_epg Rafraîchir +EPGPlus.remind Rappel +EPGPlus.reset_settings Reset réglages +EPGPlus.save_settings Sauvegarder Réglages +EPGPlus.scroll_mode Mode défilement +EPGPlus.select_font_name Nom de caractère +EPGPlus.settings Réglages +EPGPlus.slider_width Largeur barette +EPGPlus.stretch_mode Mode déployé +EPGPlus.swap_mode Mode échange +EPGPlus.timeline_fontdate Caractère de Date +EPGPlus.timeline_fonttime Caractère d'heure +EPGPlus.vergap1_width Largeur1 +EPGPlus.vergap2_width Largeur2 +EPGPlus.view_mode Mode visualisation +GENRE.ARTS.0 arts / culture +GENRE.ARTS.1 arts contemporains +GENRE.ARTS.10 arts/culture magazines +GENRE.ARTS.11 mode +GENRE.ARTS.2 arts fins +GENRE.ARTS.3 religions +GENRE.ARTS.4 culture populaire/arts traditionels +GENRE.ARTS.5 littérature +GENRE.ARTS.6 film/cinéma +GENRE.ARTS.7 film expérimental/vidéo +GENRE.ARTS.8 broadcasting/press +GENRE.ARTS.9 nouvelle média +GENRE.CHILDRENs_PROGRAMMES.0 enfants / programme juvénile +GENRE.CHILDRENs_PROGRAMMES.1 programme pré-scolaire +GENRE.CHILDRENs_PROGRAMMES.2 programme de loisirs pour 6 à 14 +GENRE.CHILDRENs_PROGRAMMES.3 programme de loisirs pour 10 à 16 +GENRE.CHILDRENs_PROGRAMMES.4 programme information/éducation/école +GENRE.CHILDRENs_PROGRAMMES.5 déssins animés/marionettes +GENRE.DOCUS_MAGAZINES.0 documentaire / magazine +GENRE.DOCUS_MAGAZINES.1 nature/animaux/environnement +GENRE.DOCUS_MAGAZINES.2 sciences technologie/nature +GENRE.DOCUS_MAGAZINES.3 médecine/physiologie/psychologie +GENRE.DOCUS_MAGAZINES.4 Pays étrangers/expéditions +GENRE.DOCUS_MAGAZINES.5 Sciences sociales/spirituelles +GENRE.DOCUS_MAGAZINES.6 Aurtes éducations +GENRE.DOCUS_MAGAZINES.7 languages +GENRE.MOVIE.0 films/drames +GENRE.MOVIE.1 détective/Policier +GENRE.MOVIE.2 aventure/western/guerre +GENRE.MOVIE.3 science-fiction/fantaisie/horreur +GENRE.MOVIE.4 comédie +GENRE.MOVIE.5 opéra/mélodrame/folklore +GENRE.MOVIE.6 romantique +GENRE.MOVIE.7 serieux/classique/réligieux/film historique/drame +GENRE.MOVIE.8 Film adulte/drame +GENRE.MUSIC_DANCE.0 musique / ballet / dance +GENRE.MUSIC_DANCE.1 rock/pop +GENRE.MUSIC_DANCE.2 musique sérieuse/classique +GENRE.MUSIC_DANCE.3 folk/musique traditionelle +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musique/opéra +GENRE.MUSIC_DANCE.6 ballet +GENRE.NEWS.0 informations +GENRE.NEWS.1 info/météo +GENRE.NEWS.2 magazines d'info +GENRE.NEWS.3 documentaire +GENRE.NEWS.4 discussion/interview/débat +GENRE.SHOW.0 Show / Gameshow +GENRE.SHOW.1 game show/quiz/concours +GENRE.SHOW.2 varieté show +GENRE.SHOW.3 discours show +GENRE.SOCIAL_POLITICAL.0 évènements socials & politiques / affaires +GENRE.SOCIAL_POLITICAL.1 magazines/reportages/documentaires +GENRE.SOCIAL_POLITICAL.2 conseil économique/social +GENRE.SOCIAL_POLITICAL.3 peuple remarquable +GENRE.SPORTS.0 sports +GENRE.SPORTS.1 évenemnts spéciaux (Jeux Olympiques,Coupe du Monde etc.) +GENRE.SPORTS.10 équitation +GENRE.SPORTS.11 sports martiaux +GENRE.SPORTS.2 magazines de sports +GENRE.SPORTS.3 football +GENRE.SPORTS.4 tennis/squash +GENRE.SPORTS.5 sports d'équipe (hors football) +GENRE.SPORTS.6 athlétisme +GENRE.SPORTS.7 sports de moteurs +GENRE.SPORTS.8 sports acquatiques +GENRE.SPORTS.9 sports d'hiver +GENRE.TRAVEL_HOBBIES.0 voyage et détente +GENRE.TRAVEL_HOBBIES.1 tourisme/voyage +GENRE.TRAVEL_HOBBIES.2 artisanet +GENRE.TRAVEL_HOBBIES.3 automobilisme +GENRE.TRAVEL_HOBBIES.4 fitness & santé +GENRE.TRAVEL_HOBBIES.5 cuisine +GENRE.TRAVEL_HOBBIES.6 publicité/shopping +GENRE.TRAVEL_HOBBIES.7 jardinage +GENRE.UNKNOWN inconnu +apids.hint_1 Entrer APIDs à streamer +apids.hint_2 en notation hex séparé par ' ' +apidselector.head Sélectionner language +audiomenu.PCMOffset diminuer le Volume PCM +audiomenu.analogout sortie Analogique +audiomenu.avs avs +audiomenu.avs_control Contrôle de Volume avs/ost +audiomenu.dolbydigital Dolby Digital +audiomenu.head Réglages Audio +audiomenu.lirc lirc +audiomenu.monoleft mono gauche +audiomenu.monoright mono droite +audiomenu.ost ost +audiomenu.stereo stéreo +audioplayer.add Ajouter +audioplayer.artist_title Artiste, Titre +audioplayer.building_search_index building search index +audioplayer.button_select_title_by_id chercher par ID +audioplayer.button_select_title_by_name charcher par nom +audioplayer.defdir dir. de Départ +audioplayer.delete éffacer +audioplayer.deleteall tout éffacer +audioplayer.display_order afficher ordre +audioplayer.enable_sc_metadata enable shoutcast meta data parsing +audioplayer.fastforward avance rapide. +audioplayer.follow selection autode l'encours +audioplayer.head liste Liste Audio +audioplayer.highprio Pririté de décodage élevé +audioplayer.id3scan étiquette ID3 de Scanning +audioplayer.jump_backwards Saut à l'arrière +audioplayer.jump_dialog_hint1 Entrer cible pour saut SVP +audioplayer.jump_dialog_hint2 (relative, en secondes) +audioplayer.jump_dialog_title Entrer cible pour saut +audioplayer.jump_forwards Saut en avant +audioplayer.keylevel Niveau de clé +audioplayer.name Audioplayer +audioplayer.pause pause +audioplayer.play écouter +audioplayer.playing Piste en cours +audioplayer.playlist_fileerror_msg Fichier non crée: +audioplayer.playlist_fileerror_title Erreur +audioplayer.playlist_fileoverwrite_msg Voulez-vous écraser l'ancien fichier: +audioplayer.playlist_fileoverwrite_title écraser? +audioplayer.playlist_name Nom de fichier de la liste +audioplayer.playlist_name_hint1 Entrer le nom de fichier de la liste SVP +audioplayer.playlist_name_hint2 l'extension .m3u sera ajouté automatiquement +audioplayer.reading_files reading files +audioplayer.repeat_on Mode répétition activé +audioplayer.rewind rebibiner +audioplayer.save_playlist sauvegarder la liste +audioplayer.screensaver_timeout Ecran de sauvegarde timeout (min, 0=off) +audioplayer.select_title_by_name Chercher titre par nom (SMS) +audioplayer.show_playlist Montrer la liste +audioplayer.shuffle Pas +audioplayer.stop Stop +audioplayer.title_artist Titre, Artiste +audioplayerpicsettings.general Lecteur audio/Visualiseur de Photos +bookmarkmanager.delete Effacer +bookmarkmanager.name Marquer +bookmarkmanager.rename renommer +bookmarkmanager.select sélectionner +bouqueteditor.add Ajouter +bouqueteditor.bouquetname Nom de bouquets +bouqueteditor.delete Effacer +bouqueteditor.discardingchanges Annulation des changement. Patienter SVP... +bouqueteditor.hide Cacher +bouqueteditor.lock Bloquer +bouqueteditor.move Dépalcer +bouqueteditor.name Editeur de bouquet +bouqueteditor.newbouquetname Nouveau nom de bouquets +bouqueteditor.rename Renommer +bouqueteditor.return Prêt +bouqueteditor.savechanges? Voulez-vous sauvegarder les changements? +bouqueteditor.savingchanges Sauvegarde des changements. Pateientez SVP... +bouqueteditor.switch ajout/suppression +bouqueteditor.switchmode TV/Radio +bouquetlist.head Bouquets +cablesetup.provider Fournisseur de service +channellist.head tout les services +channellist.nonefound Aucune chaines trouvée!\néxecuter un scan\n(DBOX-key -> service) +channellist.since depuis %02d:%02d +colorchooser.alpha alpha +colorchooser.blue bleu +colorchooser.green vert +colorchooser.red rouge +colormenu.background Arrière plan +colormenu.fade Fade menus +colormenu.font Font taille +colormenu.gtx_alpha Transparence (GTX) +colormenu.head Color Régalges +colormenu.menucolors Couleur de Menu +colormenu.statusbar Barre d'info +colormenu.textcolor Couleur du texte +colormenu.themeselect sélectionner le thème +colormenu.timing Temporisation OSD +colormenusetup.head Couleurs du Menu +colormenusetup.menucontent Contenu Fenêtre +colormenusetup.menucontent_inactive Contenue Fenêtre inactive +colormenusetup.menucontent_selected Contenue Fenêtre sélectinnée +colormenusetup.menuhead Menu entête +colorstatusbar.head Barre d'info +colorstatusbar.text Barre d'info +colorthememenu.classic_theme Thème Classique +colorthememenu.dblue_theme Thème bleu foncé +colorthememenu.dvb2k_theme Thème DVB2000 +colorthememenu.head Sélecteur de thème +colorthememenu.neutrino_theme Thème Neutrino +date.Apr Avr +date.Aug Aoû +date.Dec Déc +date.Feb Fév +date.Fri Ven +date.Jan Jan +date.Jul Jul +date.Jun Jui +date.Mar Mar +date.May Mai +date.Mon Lun +date.Nov Nov +date.Oct Oct +date.Sat Sam +date.Sep Sép +date.Sun Dim +date.Thu Jeu +date.Tue Mar +date.Wed Mer +epglist.head Liste Evenement - %s +epglist.noevents Pas d'EPG disponible... +epgviewer.More_Screenings Plus de diffusion sur cette chaine +epgviewer.nodetailed Pas d'informations détaillée disponible +epgviewer.notfound Pas d'EPG trouvé +eventlistbar.channelswitch Agenda +eventlistbar.eventsort Classement +eventlistbar.recordevent Enregistrement +favorites.addchannel La chaine en cours sera ajoutée \nau bouquet "Mes Favories". \n ça prendra quelques secondes... +favorites.bouquetname Mes Favories +favorites.bqcreated Le Bouquet "Mes Favories" est crée...\n +favorites.chadded La chaine en cours est ajoutée à vos favories...\n +favorites.chalreadyinbq La chaine en cours est déja dans vos favories...\n +favorites.finalhint \nUtilise l'éditeur de bouquet pour modifier vos favories.\n +favorites.menueadd Ajouter une chaine aux favories +favorites.nobouquets Les Favories sont disponibles les bouquets activés uniquement. +filebrowser.delete Effacer +filebrowser.denydirectoryleave Répertoire de démarrage réel +filebrowser.dodelete1 Effacer +filebrowser.dodelete2 ? +filebrowser.filter.active Filtre on +filebrowser.filter.inactive Filtre off +filebrowser.head Navigateur de fichiers +filebrowser.mark Marquer +filebrowser.nextpage Page suivante +filebrowser.prevpage Page précedente +filebrowser.scan Balayage de réprtoire +filebrowser.select Selectionner +filebrowser.showrights Montrer les attribues de fichier +filebrowser.sort.date (date) +filebrowser.sort.name (Nom de fichier) +filebrowser.sort.namedirsfirst (Nom de fichier2) +filebrowser.sort.size (Taille) +filebrowser.sort.type (type) +flashupdate.actionreadflash Lecture +flashupdate.cantopenfile Ouverture de fichier impossible +flashupdate.cantopenmtd Ouverture de mtd-device impossible +flashupdate.checkupdate Recherche de nouvelle version +flashupdate.currentreleasecycle Cycle de sortie +flashupdate.currentversion_sep Version courante +flashupdate.currentversiondate Date +flashupdate.currentversionsnapshot Type d'Image +flashupdate.currentversiontime heure +flashupdate.erasefailed Effacement du flash échoué +flashupdate.erasing Effacement flash +flashupdate.experimentalimage L'Image sélectionnée est une version non testée, Ca veut dire \nvotre récepteur ne plus redémarrer après la mise à jour.\n\nvoulez-vous vraiment mettre à jour avec cette version? +flashupdate.expertfunctions Fonctions Expert +flashupdate.fileis0bytes La taille du fichier est 0 Bytes +flashupdate.fileselector Sélecteur de fichier +flashupdate.flashreadyreboot L'Image est flashée avec succès.\nLe récepteur va redémarrer maintenant. +flashupdate.getinfofile Obtention de l'info version +flashupdate.getinfofileerror Impossible d'extraire l'info version +flashupdate.getupdatefile Obtention de la m.à.j (mise à jour) +flashupdate.getupdatefileerror Impossible d'extraire la m.à.j +flashupdate.globalprogress Progression globale: +flashupdate.head m.à.j du Software (Mise à jour du programme) +flashupdate.md5check Vérification de l'Image +flashupdate.md5sumerror L'Image a des erreurs +flashupdate.msgbox La nouvelle file suivante est trouvée:\nDate: %s, %s\nBaseImage: %s\nType: %s\n\nVoulez-vous télécharger et installer cette version maintenant? +flashupdate.msgbox_manual La nouvelle image suivante est trouvée:\nDate: %s, %s\nBaseImage: %s\nImageType: %s\n\nVoulez-vous télécharger et installer cette version maintenant? +flashupdate.mtdselector Sélecteur de partition +flashupdate.programmingflash programmation du flash +flashupdate.proxypassword Mot de passe +flashupdate.proxypassword_hint1 entrer le mot de pass du serveur proxy +flashupdate.proxypassword_hint2 Entrée vide veut dire pas de proxy-auth +flashupdate.proxyserver Nom de l'hôte +flashupdate.proxyserver_hint1 entrer le nom du serveur proxy ou bien ip, utiliser hôte:port +flashupdate.proxyserver_hint2 Entrée vide veut dire pas de proxy +flashupdate.proxyserver_sep Serveur Proxy +flashupdate.proxyusername Nom d'utilisateur +flashupdate.proxyusername_hint1 entrer le nom d'utilisateur du serveur proxy +flashupdate.proxyusername_hint2 Entrée vide veut dire pas de proxy-auth +flashupdate.readflash Lire l'image entièrement +flashupdate.readflashmtd Lire une partition +flashupdate.ready Prêt +flashupdate.reallyflashmtd Vous voulez vraiment flasher?\n\nSi une erreur survient ou l'Image est non\nvalide, le récepteur ne redémarrera pas après le flash.\n\nImagename: %s\nTarget: %s +flashupdate.savesuccess L'Image est sauvegardée avec succès \nsous %s. +flashupdate.selectimage Images/Files disponibles +flashupdate.squashfs.noversion La vérification de la version SquashFS version ne sont supportée que lors de la m.à.j via le WEB actuellement.\nVoulez-vous vraiment installer cette Image? +flashupdate.titlereadflash Lecture du Flash +flashupdate.titlewriteflash Ecriture du Flash +flashupdate.updatemode Mode de m.à.j +flashupdate.updatemode_internet internet +flashupdate.updatemode_manual manuel (ftp) +flashupdate.url_file Fichier de configuration +flashupdate.versioncheck Vérification de la version +flashupdate.writeflash Ecrire l'Image entièrement +flashupdate.writeflashmtd Ecrire une partition +flashupdate.wrongbase flashupdate.wrongbase Your Release cycle differs.\nTo continue? +fontmenu.channellist Liste de chaines +fontmenu.epg EPG +fontmenu.eventlist Liste d'évènements +fontmenu.gamelist Liste de jeux +fontmenu.head Réglage taille caractère +fontmenu.infobar Barre d'Info +fontsize.channel_num_zap Sélection directe +fontsize.channellist Liste de chaines +fontsize.channellist_descr Déscription +fontsize.channellist_number Numéro +fontsize.epg_date EPG Date +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Titre +fontsize.eventlist_datetime date / heure +fontsize.eventlist_itemlarge large +fontsize.eventlist_itemsmall petit +fontsize.eventlist_title Titre +fontsize.filebrowser_item Article du navigateur de fichier +fontsize.gamelist_itemlarge large +fontsize.gamelist_itemsmall petit +fontsize.hint Initialisation caractère,\nattendre SVP... +fontsize.infobar_channame Nom de chaine +fontsize.infobar_info info +fontsize.infobar_number Numéro +fontsize.infobar_small petit +fontsize.menu Menu texte +fontsize.menu_info Menu Info +fontsize.menu_title Menu Titre +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.epgnotload EPG non chargé.... +infoviewer.epgwait attente EPG... +infoviewer.eventlist Liste d'évènements +infoviewer.languages Audio +infoviewer.motor_moving positionnement de l'antenne +infoviewer.nocurrent Pas d'info pour le programme en cours +infoviewer.noepg Pas d'EPG disponible +infoviewer.notavailable Chaine non disponible +infoviewer.selecttime Sélection heure +infoviewer.streaminfo Options de caractéristiques +infoviewer.subservice Sous services +infoviewer.waittime Attented d'heure... +ipsetup.hint_1 Utilise 0..9, ou bien haut/bas, +ipsetup.hint_2 OK sauvegader, HOME annuler +keybindingmenu.RC Touche repeat-blocker +keybindingmenu.addrecord Ajouter horaire d'enregistrement +keybindingmenu.addremind Ajouter horaire de zap vers... +keybindingmenu.allchannels_on_ok tous-services +keybindingmenu.bouquetchannels_on_ok bouquet en cours +keybindingmenu.bouquetdown bouquet arrière +keybindingmenu.bouquethandling Contrôle de Bouquet +keybindingmenu.bouquetlist_on_ok Liste de bouquets +keybindingmenu.bouquetup next bouquet +keybindingmenu.cancel Fermer liste de chaines +keybindingmenu.channeldown chaine bas +keybindingmenu.channellist Liste de chaines +keybindingmenu.channelup chaine avant +keybindingmenu.head Réglage des touches +keybindingmenu.lastchannel Zap rapide +keybindingmenu.modechange Mode changement +keybindingmenu.pagedown page bas +keybindingmenu.pageup page haut +keybindingmenu.quickzap zap rapide +keybindingmenu.repeatblock délai de répétition +keybindingmenu.repeatblockgeneric délai générique +keybindingmenu.sort changer l'ordre de classement +keybindingmenu.subchanneldown sous-chaine bas +keybindingmenu.subchannelup sous-chaine haut +keybindingmenu.tvradiomode Mode TV/Radio +keybindingmenu.zaphistory Zapping Bouquet Historique +keychooser.head Setup nouvelle touche +keychooser.text1 Appuyer sur la nouvelle touche SVP +keychooser.text2 Attendez quelques secondes pour quitter +keychoosermenu.currentkey touche en cours +keychoosermenu.setnew réglage nouvelle touche +keychoosermenu.setnone Pas de touche +languagesetup.head Réglage Langue +languagesetup.select Langue +lcdcontroler.brightness Brillance normale +lcdcontroler.brightnessstandby Brillance de veille +lcdcontroler.contrast Contraste +lcdcontroler.head Réglage LCD +lcdmenu.autodimm Estompage Auto +lcdmenu.head LCD Réglages +lcdmenu.inverse Inverse +lcdmenu.lcdcontroler Contraste / Brillance +lcdmenu.power Alimentation +lcdmenu.statusline Ligne d'état +lcdmenu.statusline.both Volume / temps écoulé +lcdmenu.statusline.playtime Temps écoulé +lcdmenu.statusline.volume Volume +mainmenu.audioplayer Lecteur Audio +mainmenu.games Jeux +mainmenu.head MENU PRINCIPAL +mainmenu.movieplayer Lecteur Vidéo +mainmenu.pausesectionsd Lire EPG +mainmenu.pictureviewer Visionneur de photos +mainmenu.radiomode Mode Radio +mainmenu.recording Enregistrement +mainmenu.recording_start Début +mainmenu.recording_stop stop +mainmenu.scartmode Mode Péritel +mainmenu.service Service +mainmenu.settings Réglages +mainmenu.shutdown Eteindre +mainmenu.sleeptimer Veille +mainmenu.tvmode Mode TV +mainsettings.audio Audio +mainsettings.colors Coleurs / thèmes / Caractères +mainsettings.head Réglages +mainsettings.keybinding Réglage touche +mainsettings.language Langue +mainsettings.lcd Ecran à Cristaux Liquides (LCD) +mainsettings.misc Réglage divers +mainsettings.network Réseau +mainsettings.recording Enregistrement +mainsettings.savesettingsnow Sauvegarder réglage maintenant +mainsettings.savesettingsnow_hint Sauvegarde de réglage,\nPatientez SVP... +mainsettings.streaming Lecteur vidéo +mainsettings.video Vidéo +menu.back Retour +messagebox.back Retour +messagebox.cancel Annuler +messagebox.discard Annuler les changemnts? +messagebox.error Erreur +messagebox.info Information +messagebox.no Non +messagebox.yes Oui +miscsettings.bootinfo Montrer les infos au démarrage +miscsettings.bootmenu Montrer le menu démarrage +miscsettings.driver_boot Options de driver et Démarrage +miscsettings.fb_destination Console de démarrage Expert! +miscsettings.general Général +miscsettings.head Réglages divers +miscsettings.hwsections Utiliser les sections hardware +miscsettings.infobar_sat_display Affichage du satellite dans la barre d'infos +miscsettings.pmtupdate enable m.à.j pmt +miscsettings.shutdown_real Permettre Veille +miscsettings.shutdown_real_rcdelay Arrêt retardé +miscsettings.sptsmode utiliser le mode spts +miscsettings.startbhdriver Charger les drivers du Mode BH +motorcontrol.head Réglage moteur +movieplayer.bookmark Signet +movieplayer.bookmarkname Nom du signet +movieplayer.bookmarkname_hint1 Entrer un nom pour votre nouveau signet +movieplayer.bookmarkname_hint2 +movieplayer.buffering (Tampons)Buffering... +movieplayer.defdir dir. de démarrage +movieplayer.dvdplayback DVD +movieplayer.fileplayback Fichier via VLC +movieplayer.goto Saut vers ... +movieplayer.goto.h1 = -> Saut absolu +movieplayer.goto.h2 +,- -> Saut relatif +movieplayer.head Lecteur vidéo +movieplayer.nostreamingserver Le serveur Streaming n'est pas accessible. +movieplayer.pesplayback Lecture PES (Expérimental) +movieplayer.pleasewait Patienter SVP.\nConnection au serveur streaming... +movieplayer.toomanybookmarks Il y'a plusieurs signets.\nVous avez à éffacer l'un d'eux avant. +movieplayer.tsplayback Lecture TS +movieplayer.vcdplayback (S)VCD +movieplayer.wrongvlcversion Cette option n'est pas supportée par votre version courante de VLC +networkmenu.broadcast Transmisson +networkmenu.dhcp DHCP +networkmenu.gateway Entrée par défaut +networkmenu.head Réglage réseau +networkmenu.ipaddress Adresse IP +networkmenu.mount NFS/CIFS +networkmenu.nameserver Nom du serveur +networkmenu.netmask Masque du net +networkmenu.setupnow Régler le réseau maintenant +networkmenu.setuponstartup Régler le réseau au démarrage +networkmenu.show montrer le régalge du réseau actif +networkmenu.test tester le réseau maintenant +nfs.alreadymounted repértoire déja monté +nfs.automount monter au démarrage +nfs.dir Répertoire/paratge +nfs.ip IP du sereveur NFS/CIFS +nfs.localdir Répertoire Local de NFS/CIFS +nfs.mount Monter Volume NFS/CIFS +nfs.mount_options Options de montage NFS/CIFS +nfs.mounterror erreur montage NFS/CIFS +nfs.mounterror_notsup Type de système de fichier non supporté pour NFS/CIFS +nfs.mountnow monter maintenant NFS/CIFS +nfs.mounttimeout erreur montage NFS/CIFS: Dépassement du temps alloué +nfs.password Mot de passe CIFS +nfs.remount répertoire de remontage NFS/CIFS +nfs.type type +nfs.type_cifs CIFS +nfs.type_nfs NFS +nfs.umount éffacer volume montage NFS/CIFS(Unmount) +nfs.umounterror erreur éffacement montage volume NFS/CIFS +nfs.username Nom d'utilisateur CIFS +nfsmenu.head Réglages NFS/CIFS +nvod.percentage (%d%% fini) +nvod.starting (démarrage dans %d min) +nvodselector.directormode Direct +nvodselector.head Sélectionner heure démarrage +nvodselector.subservice Sélectionner Sous-service +options.default Reset à par défaut +options.fb framebuffer +options.null null +options.off off +options.on on +options.serial série +parentallock.changepin changer PIN code +parentallock.changepin_hint1 Entrer votre code de protection(PIN) ici! +parentallock.changetolocked pour les bouquets bloquer +parentallock.head Entrer code parental (PIN) +parentallock.lockage Bloquer le programme +parentallock.lockage12 pour 12 ans et plus +parentallock.lockage16 pour 16 ans et plus +parentallock.lockage18 pour 18 ans et plus +parentallock.lockedchannel Expéditeur bloqué... +parentallock.lockedprogram Programme bloqué (pour %d ans et plus) +parentallock.never jamais +parentallock.onsignal pour fournisseur bloquer +parentallock.parentallock Protection parentale +parentallock.prompt ponctuellemnt pour PIN +pictureviewer.defdir Répertoire de démarrage. +pictureviewer.head Visualiseur de photos +pictureviewer.resize.color_average avancé +pictureviewer.resize.none aucun +pictureviewer.resize.simple simple +pictureviewer.scaling réajustement +pictureviewer.show montrer +pictureviewer.slide_time temps de défilement +pictureviewer.slideshow défilement +pictureviewer.sortorder changer l’ordre de tri +pictureviewer.sortorder.date (date) +pictureviewer.sortorder.filename (Nom de fichier) +ping.ok est joignable (ping) +ping.protocol est injoignable (erreur hôte ou protocole) +ping.socket est injoignable (erreur socket) +ping.unreachable est injoignable +pinprotection.head Entrer code PIN +pinprotection.wrongcode Le code PIN est faux! Essayer encore. +rclock.lockmsg votre télécommande Récepteur sera bloquée.\n pour débloquer, Appuyer \n et sur la Télécommande. +rclock.menueadd Bloquer Télécommande (RC) +rclock.title Bloquer Télécommande (RC) +rclock.unlockmsg Télécommande réactivée. +recordingmenu.defdir Répertoire d’enregistrement +recordingmenu.file Directe (fichier) +recordingmenu.head Réglages d’enregistrement +recordingmenu.help Dispositifs d’enregistrement:\n--------------------------\nserveur:\nutilisation du programme de streaming sur PC\n\n(analogique) vcr:\nutilisation de la sortie vcr\n\ndirecte (fichier):\ndirectement dans le répertoire NFS mounté\nsur le dique dur interne(HDD)\nTS: utiliser mode spts (dbox2)\nPES: ne pas utiliser le mode spts(dbox2)\n\n\nTaille fichier Max.:\n---------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: Presque illimité (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart Ne pas balancer vers le mode Péritel +recordingmenu.off off +recordingmenu.recording_type Dispositif d’enregistrement +recordingmenu.server serveur +recordingmenu.server_ip IP serveur d’enregistrement +recordingmenu.server_mac Adresse MAC +recordingmenu.server_port PORT serveur d’enregistrement +recordingmenu.server_wakeup WOL serveur d’enregistrement +recordingmenu.setupnow activater les changements +recordingmenu.splitsize Max. Taille fichier (MB) +recordingmenu.stopplayback stop playback +recordingmenu.stopsectionsd stop section sd +recordingmenu.stream_vtxt_pid enregistrer le videotext +recordingmenu.use_o_sync écrire synchrone (O_SYNC) +recordingmenu.vcr vcr +recordtimer.announce L’enregistrement démarre dans quelques minutes +repeatblocker.hint_1 Durée test court (in ms) pour reconnaitre 2 keystrokes +repeatblocker.hint_2 Entrer 0 pour éteindre le blocker (rouge est espace) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat Répetitions DiSEqC +satsetup.extended Réglages DiSEqC +satsetup.extended_motor Réglages Moteur +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Réglages Moteur Manuel +satsetup.nodiseqc Pas de DiSEqC +satsetup.satellite Satellite +satsetup.savesettingsnow sauvegarder réglages maintenant +satsetup.smatvremote mise au point SMATV +scants.actcable Cable: +scants.actsatellite Satellite: +scants.bouquet Bouquet +scants.bouquet_create créer nouveau +scants.bouquet_erase Tout éffacer +scants.bouquet_leave Laisser l’actuel +scants.bouquet_satellite Satellite-Bouquet +scants.bouquet_update mettre à jour +scants.channel Chaine: +scants.failed Balayage du Transpondeur échoué! +scants.finished Balayage du Transpondeur réussi! +scants.freqdata Fréquence: +scants.head Balayer le transpondeur +scants.numberofdataservices Data +scants.numberofradioservices Radio +scants.numberoftotalservices Total +scants.numberoftvservices TV +scants.provider Provider(Fournisseur): +scants.startnow commencer le Balayage +scants.transponders Transpondeurs: +screensetup.lowerright Vert = réglage du bas à droite +screensetup.upperleft Rouge = réglage du haut à gauche +servicemenu.head Service +servicemenu.reload Recharger listes de chaines +servicemenu.reload_hint Rechargement listes de chaines,\nPatientez SVP. +servicemenu.scants Balayage du service +servicemenu.ucodecheck Verifier ucodes +servicemenu.update Mise à jour du Software +settings.help Aide +settings.missingoptionsconffile Les réglages NEUTRINO sont mis à jour.\nDes nouvelles Options seront mis par défaut. +settings.noconffile Pas de réglages NEUTRINO trouvés.\nUtilisation de celles par défaut. +shutdowntimer.announce Le récepteur sera arrêté dans 1 min.\nAnnuler arrêt? +sleeptimerbox.announce Veille dans in 1 min +sleeptimerbox.hint1 Arrêt dans in min. (000=off) +sleeptimerbox.hint2 Le récepteur sera arrêté après ce temps. +sleeptimerbox.title Veille +streamfeatures.head Caractéristiques +streaminfo.aratio Aspect de proportion +streaminfo.aratio_unknown Aspect de proportion: inconnu +streaminfo.audiotype Type Audio +streaminfo.audiotype_unknown Type Audio: inconnu +streaminfo.bitrate Bitrate +streaminfo.framerate Framerate +streaminfo.framerate_unknown Framerate: inconnu +streaminfo.head Information Stream +streaminfo.not_available Non disponible +streaminfo.resolution Résolution +streaminfo.signal Receipt signal +streaming.buffer_overflow L’enregistrement est abondonné,\nTant que les données ne peuvent être écrites assez rapidement. +streaming.busy Un ou plusieurs processus d’enregistrement sont actifs.\nSi vous rencontrez ce message et aucun enregistrement n’est actif, Redémarrer NEUTRINO SVP. +streaming.dir_not_writable Le répertoire d’enregistrement n’est pas autorisé en écriture.\nL’enregistrement ne fonctionnera pas. +streaming.success L’enregistrement est effectué avec succès. +streaming.write_error L’enregistrement est abondonné,\nTant qu’une erreur est survenue lors du processus d’écriture. +streaming.write_error_open L’enregistrement est abondonné,\nParceque le fichier cible ne peut être ouvert. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Réglages Lecteur vidéo +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Off +streamingmenu.on On +streamingmenu.server_ip IP Serveur Streaming +streamingmenu.server_port PORT Serveur Streaming +streamingmenu.streaming_audiorate Taux de données Audio +streamingmenu.streaming_force_avi_rawaudio Forcer AC3 pour AVI +streamingmenu.streaming_force_transcode_video Transcoder MPG/VCD vidéo +streamingmenu.streaming_resolution Résolution +streamingmenu.streaming_server_cddrive DVD Drive +streamingmenu.streaming_server_startdir Répertoire (VLC) +streamingmenu.streaming_transcode_audio Transcoder audio (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec MPEG vidéo codec +streamingmenu.streaming_type Serveur Streaming +streamingmenu.streaming_videorate Taux de données Vidéo +streamingserver.noconnect Pas de connection au serveur streaming.\nEnregistrement annulé. +stringinput.caps caps / Pas de caps +stringinput.clear Tout éffacer +timer.eventrecord.msg ... à exécuter, ou bien non +timer.eventrecord.title Programmer enregistrement +timer.eventtimed.msg L’évènement est programmé.\nLe récepteur démarrera et \basculera vers cette chaine à l’heure programmée. +timer.eventtimed.title Programme Evènement +timerbar.channelswitch programmer +timerbar.recordevent Enregistrer +timerlist.alarmtime Réveil +timerlist.apids PIDs Audio +timerlist.bouquetselect Choisir bouquet +timerlist.channel Chaine +timerlist.channelselect choisir chaine +timerlist.delete éffacer +timerlist.menumodify Modifier horaire +timerlist.menunew Nouvel horaire +timerlist.message Message +timerlist.moderadio Chaines Radio +timerlist.modeselect Mode sélection +timerlist.modetv Chaines TV +timerlist.modify Modifier +timerlist.name Liste horaire +timerlist.new nouvel horaire +timerlist.program.unknown Programme inconnu +timerlist.reload Recharger +timerlist.repeat Repéter +timerlist.repeat.biweekly bi-hebdomadaire +timerlist.repeat.byeventdescription Voir Horaire +timerlist.repeat.daily Quotidien +timerlist.repeat.fourweekly Quatre fois/semaine +timerlist.repeat.friday Vendredi +timerlist.repeat.monday Lundi +timerlist.repeat.monthly mensuellement +timerlist.repeat.once une fois +timerlist.repeat.saturday Samedi +timerlist.repeat.sunday Dimanche +timerlist.repeat.thursday Jeudi +timerlist.repeat.tuesday Mardi +timerlist.repeat.unknown inconnu +timerlist.repeat.wednesday Mercredi +timerlist.repeat.weekdays Jours de la semaine +timerlist.repeat.weekly Hebdomadaire +timerlist.save Sauvegarder horaire +timerlist.standby Mode SB +timerlist.standby.off Quitter Veille +timerlist.standby.on Entrer en Veille +timerlist.stoptime heure Arrêt +timerlist.type Type d’horaire +timerlist.type.nextprogram Prochain programme +timerlist.type.record Enregistrer +timerlist.type.remind Rappeler +timerlist.type.shutdown Arrêt +timerlist.type.sleeptimer Veille programmée +timerlist.type.standby Veille +timerlist.type.unknown inconnu +timerlist.type.zapto Zapper vers +timerlist.weekdays Jours de la semaine +timerlist.weekdays.hint_1 Lun Mar Mar Jeu Ven Sam Dim +timerlist.weekdays.hint_2 'X'=Horaire '-' Pas d’horaire +timersettings.record_safety_time_after Correction du temps d’arrêt d’enregistrement +timersettings.record_safety_time_after.hint_1 Temps de Correction en min. (00=off). Ce temps +timersettings.record_safety_time_after.hint_2 sera ajouté à chaque horaire d’enregistrement. +timersettings.record_safety_time_before Correction du temps de démarrage d’enregistrement +timersettings.record_safety_time_before.hint_1 Temps de Correction en min. (00=off). Ce temps +timersettings.record_safety_time_before.hint_2 sera déduit de chaque horaire d’enregistrement. +timersettings.separator Réglages d’horaire +timing.chanlist Liste chaine +timing.epg Epg +timing.filebrowser Navigateur de fichier +timing.head Temps d’éclipse OSD +timing.hint_1 Temps en sec. Après ce temps +timing.hint_2 la barre d’infos disparaîtra . +timing.infobar Barre d’infos +timing.menu Menu +timing.numericzap Zap Numerique +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head vérification UCode +ucodecheck.ucode UCode +ucodes.failure ATTENTION, µCodes ne sont pas trouvés!\n\nTélécharger les via FTP (ou bien Récepteur-BootManager),\nensuite redémarrer votre récepteur! +videomenu.csync Correction sync +videomenu.head Réglages Vidéo +videomenu.rgb_centering Centrage RGB +videomenu.screensetup Réglage écran +videomenu.vcrswitch Balance Péritel automatique +videomenu.videoformat Format +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect Détection automatique +videomenu.videosignal Sortie Vidéo +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Vidéo +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce Zapper vers programmeur dans une minute +extra.auto Auto +extra.valid Valider +extra.all tout +extra.new_keys Nouvelles clés(keys) +extra.all_keys Toutes les clés +extra.vartmp /var/tmp +extra.varkeys /var/keys +extra.algo Algo pids +extra.gbox_emu Emu +extra.gbox_softcam Softcam +extra.gbox_net Réseau +extra.gbox_mix Mélange +extra.gbox_info Gbox Info +extra.sep_extra Extras +extra.save_settings Sauvegarder les réglages +extra.extra_menu Addons +extra.ecm_info Ecm Info +extra.pid_info Pid Info +extra.emm_info Nouvelles clés(Keys) +extra.emu_type Type d’Emu +extra.camd Camd +extra.restart_camd Redémarrer camd +extra.mg_settings Réglages Mgcamd +extra.netmode Mode réseau +extra.autoupdate m.à.j Automatique +extra.show_ecm Montrer Ecm +extra.show_emm Montrer Emm +extra.keyupdate m.à.j des clés(keys) +extra.osd OSD(affichage) +extra.keyfolder Répertoire des clés(keys) +extra.hash_pids Hash pids +extra.gbox_settings Réglage Gbox +extra.gbox_mode Mode +extra.newcamd_settings Réglage Newcamd +extra.show_cw Montrer CW +extra.debug_ecm Débguer Ecm +extra.disable_cam Désctiver CAM +extra.show_cat Montrer CAT +extra.show_pmt Montrer PMT +extra.update_pmt m.à.j PMT +extra.report_emm Report wrong EMM sig. +extra.debug_emm Déboguer Emm +extra.show_allca Montrer tout ca sys. +extra.reload_keys Recharger les clés après un Zap +extra.reload_cfg Recharger config après un zap +extra.cw_delay Délai CW par défaut +extra.dvbsnoop DVB Infos Stream +extra.dvbsnoop_pat Montrer PAT +extra.dvbsnoop_cat Montrer CAT +extra.dvbsnoop_tsdt Montrer TSDT +extra.dvbsnoop_nit Montrer NIT +extra.dvbsnoop_sdt Montrer SDT +extra.dvbsnoop_eit Montrer EIT +extra.dvbsnoop_rst Montrer RST +extra.dvbsnoop_tdt Montrer TDT +extra.dvbsnoop_sit Montrer SIT +extra.dvbsnoop_pid Montrer PID manuelle +extra.dvbsnoop_scan Balayage PIDs +extra.dvbsnoop_band Montrer Largeur bande pid +extra.logview Montrer Log +extra.ru ruDREAM +extra.english Anglais +extra.dboxinfo Infos Récepteur +extra.scan_mode Mode Balayage +extra.start_tostandby Démarrage vers veille +extra.rotor_swap Echange Rotor Est/Ouest +extra.use_log Log vers /tmp/log +extra.spts_mode Mode SPTS +extra.hw_sect Section Hardware (matériel) +extra.logo Numéro Logo +extra.scan_full Plein +extra.scan_fast Rapide +extra.hdd_slow Lent +extra.hdd_middle Moyen +extra.hdd_fast Rapide +extra.hdd_ext3 Ext3fs +extra.hdd_reiser Reiserfs +extra.hdd_1min 1 min. +extra.hdd_5min 5 min. +extra.hdd_10min 10 min. +extra.hdd_20min 20 min. +extra.hdd_30min 30 min. +extra.hdd_60min 60 min. +extra.logo1 1 +extra.logo2 2 +extra.logo3 3 +extra.hdd_sleep Temps vers Veille +extra.hdd_noise Bruit +extra.hdd_activate Activater Réglages +extra.hdd_fs Système de fichiers +extra.hdd_format Formater Disque dur(HDD) +extra.hdd_check Vérifier système fichiers +extra.hdd_settings Réglages Disque Dur(HDD) +extra.clear_log Effacer Log +extra.zap_cycle Cycle de Zap +extra.sms_channel Chaine Mode sms +extra.manual_scan Balayage Manuelle +extra.tp_freq Fréquence +extra.tp_rate Taux de Symbole +extra.tp_pol Polarisation +extra.tp.pol_v V +extra.tp_pol_h H +extra.tp_fec FEC +extra.fec_1_2 1/2 +extra.fec_2_3 2/3 +extra.fec_3_4 3/4 +extra.fec_5_6 5/6 +extra.fec_7_8 7/8 +extra.timezone Zone horaire(TimeZone) +extra.zapit_menu Options Zapit +extra.zapit_make_bouquet Construire liste chaines restantes +extra.zapit_save_last_chan Sauvegarder dernière chaine +extra.zapit_motor_speed Vitesse du Moteur (10 = 1deg/sec) +extra.zapit_fe_timeout Régler temps de sortie(timeout) +extra.add_to_bouquet Ajouter au bouquet +extra.key_list_start Retour départ +extra.key_list_end Fin +extra.chadded La chaine actuelle est ajoutée au bouquet selectionné....\n +extra.chalreadyinbq La chaine actuelle existe déja dans le bouquet selectionné....\n +extra.menu_left_exit "Left" = menu back +extra.zapit_write_names Write channel names +extra.update_dir Directory for updates +extra.cache Cache +extra.debug Debug +extra.zapit_backup Backup channels to /tmp +extra.zapit_delete Delete channels +extra.zapit_fast_zap fast zap +extra.zapit_restore Restore channels from /tmp +extra.zapit_sort_names Sort ch. by name +filesystem.is.utf8 file system +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +infoviewer.subchan_disp_pos Subchannel display +mainmenu.scripts Scripts +miscsettings.noaviawatchdog enable AVIA watchdog +miscsettings.noenxwatchdog enable eNX watchdog +movieplayer.defplugin Start-Plugin +movieplayer.tshelp1 Stop +movieplayer.tshelp10 approx. 10 minutes back +movieplayer.tshelp11 skip approx. 10 minutes +movieplayer.tshelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Select audio track +movieplayer.tshelp3 Pause/Continue +movieplayer.tshelp4 Create bookmark +movieplayer.tshelp5 Show progress +movieplayer.tshelp6 approx. 1 minute back +movieplayer.tshelp7 skip approx. 1 minute +movieplayer.tshelp8 approx. 5 minutes back +movieplayer.tshelp9 skip approx. 5 minutes +movieplayer.vlchelp1 Stop +movieplayer.vlchelp10 approx. 10 minutes back +movieplayer.vlchelp11 skip approx. 10 minutes +movieplayer.vlchelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Resync +movieplayer.vlchelp3 Pause/Continue +movieplayer.vlchelp4 Create bookmark +movieplayer.vlchelp5 Show progress +movieplayer.vlchelp6 approx. 1 minute back +movieplayer.vlchelp7 skip approx. 1 minute +movieplayer.vlchelp8 approx. 5 minutes back +movieplayer.vlchelp9 skip approx. 5 minutes +nfs.mountok mount successful +nfs.type_lufs FTPFS +pictureviewer.help1 menu mode +pictureviewer.help10 show mode +pictureviewer.help11 reread image +pictureviewer.help12 previous image +pictureviewer.help13 next image +pictureviewer.help14 Zoom out +pictureviewer.help15 Zoom in +pictureviewer.help16 scroll up +pictureviewer.help17 scroll left +pictureviewer.help18 scroll right +pictureviewer.help19 scroll down +pictureviewer.help2 display image +pictureviewer.help20 change sort order +pictureviewer.help21 reread image (no scaling) +pictureviewer.help22 exit +pictureviewer.help3 change sort order +pictureviewer.help4 do not scale picture +pictureviewer.help5 diashow mode +pictureviewer.help6 previous image +pictureviewer.help7 next image +pictureviewer.help8 change sort order +pictureviewer.help9 exit +plugins.result plugin output +recordingmenu.choose_direct_rec_dir choose dir on imm. recording +recordingmenu.epg_for_filename long filenames (with EPG data) +recordingmenu.filesettings direct recording settings +recordingmenu.ringbuffers no. of ringbuffers +recordingmenu.use_fdatasync write synchronous (fdatasync) +settings.pos_bottom_left bottom left +settings.pos_bottom_right bottom right +settings.pos_top_left oben top left +settings.pos_top_right oben top right +timerlist.plugin Plugin +timerlist.recording_dir recording directory +timerlist.repeatcount repeats +timerlist.repeatcount.help1 amount of timer repeats +timerlist.repeatcount.help2 0 for unlimited repeats +timerlist.type.execplugin Execute plugin +pictureviewer.decode_server_ip decode server ip +pictureviewer.decode_server_port decode server port +scants.abort_body Should the search really be aborted? +scants.abort_header Abondonner le balayage +recordingmenu.record_in_spts_mode switch to spts mode before recording +servicemenu.getplugins Reload plugins +servicemenu.getplugins_hint Reloading plugins,\nplease be patient. +zapit.scantype scan for services +zapit.scantype.all all services +zapit.scantype.radio only radio +zapit.scantype.tv only tv +zapit.scantype.tvradio tv & radio +colorthememenu.red_theme Simply Red +lcdmenu.dim_brightness Brightness after dim timeout +lcdmenu.dim_time Dim timeout +timerlist.overlapping_timer Timer conflict. Create the timer anyway? +extra.audio_run_player Audio key start player +mpkey.rewind Rewind +mpkey.forward Forward +mpkey.pause Pause +mpkey.stop Stop +mpkey.play Play +mpkey.audio Audio track +mpkey.time Show time +mpkey.bookmark save bookmark +mpkey.plugin Run plugin +extra.key_click Key click +extra.loadcolors Load colors from +extra.savecolors Save colors as +extra.loadkeys Load keys from +extra.savekeys Save keys as +extra.loadconfig Load settings from +extra.saveconfig Save settings as +videomenu.videomode Video system +videomenu.videomode_ntsc NTSC +videomenu.videomode_pal PAL +videomenu.videomode_palm PAL-M +extra.key_timeshift Timeshift +extra.key_plugin One touch plugin +extra.timeshift_pause Timeshift pause +rfmod.rfmod RF modulator +rfmod.carrier Subcarrier Frequency +rfmod.carrier4500 4.5 +rfmod.carrier5500 5.5 +rfmod.carrier6000 6.0 +rfmod.carrier6500 6.5 +rfmod.enable Enable sound +rfmod.channel Channel +rfmod.finetune Fine tune +rfmod.standby Enable modulator +rfmod.test Test pattern +extra.zapit_scanpids Scan/Use pids +extra.zapit_rezap_time Re-Zap on emu switch time +extra.zapit_hvoltage High (13.5/18.5) voltage +extra.key_unlock Unlock key +extra.mg_netoptions Network options +extra.mg_ecm_timeout Network ecm timeout +extra.mg_reconnect Shares reconnect +extra.mg_priority Share priority +extra.mg_osd_options Osd options +extra.mg_reread Reread files on zap +servicemenu.imageinfo Image info +imageinfo.creator Creator: +imageinfo.date Date: +imageinfo.dokumentation Docs: +imageinfo.forum Forum: +imageinfo.head Image info: +imageinfo.homepage Home page: +imageinfo.image Image: +imageinfo.license License: +imageinfo.version Version: +extra.cache_txt Cache teletext +extra.use_gotoxx Use gotoXX +extra.latitude Latitude +extra.longitude Longitude +extra.ladirection LaDirection +extra.lodirection LoDirection +extra.south South +extra.north North +extra.east East +extra.west West +epgextended.actors Actors +epgextended.director Director +epgextended.guests Guests +epgextended.original_title Original Title +epgextended.presenter Presenter +epgextended.year_of_production Year of Production +recordingmenu.save_in_channeldir Save in channel dir +servicemenu.restart Soft restart +servicemenu.restart_failed Restart failed +servicemenu.restart_hint Restarting, please wait +servicemenu.restart_refused_recording Cant restart, recording in progress +extra.cs Cardserver +extra.restart_cs Restart cardserver +extra.tp_mod Modulation +extra.tp_mod_16 QAM/16 +extra.tp_mod_32 QAM/32 +extra.tp_mod_64 QAM/64 +extra.tp_mod_128 QAM/128 +extra.tp_mod_256 QAM/256 +moviebrowser.book_head Bookmarks +moviebrowser.book_lastmoviestop Last play stop: +moviebrowser.book_movieend Movie end: +moviebrowser.book_moviestart Movie start: +moviebrowser.book_name Name: +moviebrowser.book_new New Bookmark +moviebrowser.book_position Position: +moviebrowser.book_type Jump (<0 back , >0 for): +moviebrowser.book_type_backward Repeat +moviebrowser.book_type_forward jump over +moviebrowser.edit_book Bookmark change +moviebrowser.edit_book_name_info1 Enter new Bookmark name +moviebrowser.edit_book_name_info2 +moviebrowser.edit_book_pos_info1 Enter new Position (s) +moviebrowser.edit_book_pos_info2 +moviebrowser.edit_book_type_info1 Enter new jump length (s) +moviebrowser.edit_book_type_info2 <0 back , >0 for, 0: none +moviebrowser.edit_serie Enter name of serie +moviebrowser.error_no_movies No movies found +moviebrowser.foot_filter Filter: +moviebrowser.foot_play Start movie +moviebrowser.foot_sort Sort: +moviebrowser.head TS MovieBrowser +moviebrowser.head_filter Filter movies by category: +moviebrowser.head_playlist Last played: +moviebrowser.head_recordlist Last recorded: +moviebrowser.hint_jumpbackward Jump back in 5 s\n '0' to cancel +moviebrowser.hint_jumpforward Jump forward in 5 s\n '0' to cancel +moviebrowser.hint_movieend Filmende in 5 s\n '0' zum weitersehen +moviebrowser.hint_newbook_backward New jump back\n 'blue' for endposition +moviebrowser.hint_newbook_forward New jump forward\n 'blue' for endposition +moviebrowser.info_audio Audio +moviebrowser.info_channel Channel +moviebrowser.info_filename Name +moviebrowser.info_genre_major Genre +moviebrowser.info_genre_minor Genre +moviebrowser.info_head Film Informationen +moviebrowser.info_info1 Info 1 +moviebrowser.info_info2 Info 2 +moviebrowser.info_length Length (Min) +moviebrowser.info_parental_lockage Parental Lock age +moviebrowser.info_parental_lockage_0year always +moviebrowser.info_parental_lockage_12year 12 years +moviebrowser.info_parental_lockage_16year 16 years +moviebrowser.info_parental_lockage_18year 18 years +moviebrowser.info_parental_lockage_6year 6 years +moviebrowser.info_parental_lockage_always never +moviebrowser.info_path Path +moviebrowser.info_prevplaydate Last play date +moviebrowser.info_prodcountry Country +moviebrowser.info_prodyear Year +moviebrowser.info_quality Quality +moviebrowser.info_recorddate Record date +moviebrowser.info_serie Serie +moviebrowser.info_size File size (MB) +moviebrowser.info_title Titel +moviebrowser.info_videoformat Picture +moviebrowser.menu_directories_head Paths +moviebrowser.menu_help_head Help +moviebrowser.menu_main_bookmarks Bookmarks +moviebrowser.menu_main_head Settings +moviebrowser.menu_main_movieinfo Movie info +moviebrowser.menu_main_saveandback save and back +moviebrowser.menu_nfs_head NFS settings +moviebrowser.menu_parental_lock_activated activated +moviebrowser.menu_parental_lock_activated_no no +moviebrowser.menu_parental_lock_activated_yes yes +moviebrowser.menu_parental_lock_activated_no_temp no (temporary) +moviebrowser.menu_parental_lock_head Parental Lock +moviebrowser.menu_parental_lock_rate_head Lock movies from +moviebrowser.scan_for_movies Scan for Movies ... +moviebrowser.serie_existingname Existing series +moviebrowser.serie_head Serie +moviebrowser.serie_name Change name +moviebrowser.short_audio Audio +moviebrowser.short_book Book +moviebrowser.short_channel Channel +moviebrowser.short_country Country +moviebrowser.short_filename Name +moviebrowser.short_format Format +moviebrowser.short_genre_major Genre +moviebrowser.short_genre_minor Genre +moviebrowser.short_info1 Info 1 +moviebrowser.short_info2 Info 2 +moviebrowser.short_length Min +moviebrowser.short_parental_lockage Age +moviebrowser.short_path Path +moviebrowser.short_prevplaydate Last +moviebrowser.short_prodyear Year +moviebrowser.short_quality * (quality) +moviebrowser.short_recorddate Date +moviebrowser.short_serie Serie +moviebrowser.short_size MB +moviebrowser.short_title Title +moviebrowser.start_head Start movie from: +moviebrowser.start_record_start Movie start +options.on.without_messages Without msg +extra.zapit_scan_sdt Scan SDT for updates +extra.zapit_sdt_changed Channels changed, reload settings. +miscsettings.virtual_zap_mode Virtual zap +miscsettings.epg_head Epg settings +miscsettings.epg_cache_days EPG-Cache (days) +miscsettings.epg_old_hours Events old after (hours) +miscsettings.epg_dir Dir for epg cache +miscsettings.epg_save Save/Restore epg on reboot +shutdown.recoding_query Box in record mode, you really want to shutdown ? +recordingmenu.apids default audio streams +recordingmenu.apids_ac3 record AC3 streams +recordingmenu.apids_alt record alternative streams +recordingmenu.apids_std record standard stream +recordingmenu.stream_pmt_pid record PMT +recordingmenu.zap_on_announce zap on recording announce +timerlist.apids_dflt record default audio streams +videomenu.osd OSD +videomenu.tv-scart TV Scart +videomenu.vcr-scart VCR Scart +videomenu.vcrsignal VCR Output Signal Type +videomenu.vcrsignal_composite CVBS +videomenu.vcrsignal_svideo S-Video +moviebrowser.option_browser Browser Options +moviebrowser.book_clear_all Clear all +moviebrowser.menu_save Save changes +moviebrowser.menu_save_all Start update of movie info files +moviebrowser.info_head_update Save changes in all movie info files +moviebrowser.update_if_dest_empty_only Copy if destination is empty only +moviebrowser.serie_auto_create Serie auto create +moviebrowser.load_default Load default settings +moviebrowser.browser_row_head Row settings +moviebrowser.browser_row_nr Number of rows +moviebrowser.browser_row_item Row item +moviebrowser.browser_row_width Row width +moviebrowser.reload_at_start Reload movie info at start +moviebrowser.remount_at_start Remount at start +moviebrowser.dir_head Additional paths +moviebrowser.dir Path +moviebrowser.use_dir Use directory +moviebrowser.use_rec_dir Use record directory +moviebrowser.use_movie_dir Use movie directory +moviebrowser.hide_series Hide series +moviebrowser.last_record_max_items Number of lines last record +moviebrowser.last_play_max_items Number of lines last play +moviebrowser.browser_frame_high Browser hight [Pixel] +extra.auto_timeshift Auto-record, sec (0 = disable) +extra.auto_delete Auto-delete +extra.auto_to_record Move timeshift to records +extra.record_time Fast/timeshift record time(hours) diff --git a/data/locale/hungarian.locale b/data/locale/hungarian.locale new file mode 100644 index 000000000..b49c7cc1c --- /dev/null +++ b/data/locale/hungarian.locale @@ -0,0 +1,1237 @@ +EPGMenu.epgplus Műsorok áttekintése +EPGMenu.eventinfo Műsor leírása +EPGMenu.eventlist Csatorna műsora +EPGMenu.head Elektronikus műsorfüzet +EPGMenu.streaminfo Technikai információk +EPGPlus.actions műveletek +EPGPlus.bybouquet_mode csomag szerint +EPGPlus.bypage_mode oldal szerint +EPGPlus.change_font_size Betűméret +EPGPlus.change_font_style Betűstílus +EPGPlus.change_size Méret +EPGPlus.channelentry_font Csatorna +EPGPlus.channelentry_separationlineheight Elválasztó-vonalmagasság +EPGPlus.channelentry_width Szélesség +EPGPlus.channelevententry_font Műsor +EPGPlus.edit_fonts Betűk szerkesztése +EPGPlus.edit_sizes Méretek szerkesztése +EPGPlus.font_style_bold kövér +EPGPlus.font_style_italic dÅ‘lt +EPGPlus.font_style_regular sima +EPGPlus.footer_fontbouquetchannelname Csomag lábjegyzet +EPGPlus.footer_fontbuttons Csomag gombok +EPGPlus.footer_fonteventdescription Műsor lábjegyzet +EPGPlus.footer_fonteventshortdescription Rövid leírás lábjegyzet +EPGPlus.head Műsorok áttekintése (EPG Plus) +EPGPlus.header_font Fejléc +EPGPlus.horgap1_height Magasság1 +EPGPlus.horgap2_height Magasság2 +EPGPlus.next_bouquet KövetkezÅ‘ csomag +EPGPlus.options opciók +EPGPlus.page_down Oldalt le +EPGPlus.page_up Oldalt fel +EPGPlus.prev_bouquet elÅ‘zÅ‘ csomag +EPGPlus.record felvétel +EPGPlus.refresh_epg Frissítés +EPGPlus.remind IdÅ‘zítés +EPGPlus.reset_settings Alapértelmezés +EPGPlus.save_settings Beállítások mentése +EPGPlus.scroll_mode görgetési mód +EPGPlus.select_font_name Betűtípus +EPGPlus.settings Beállítások +EPGPlus.slider_width Csúszkaszélesség +EPGPlus.stretch_mode nyújtási mód +EPGPlus.swap_mode Mód váltás +EPGPlus.timeline_fontdate Dátum +EPGPlus.timeline_fonttime IdÅ‘ +EPGPlus.vergap1_width Szélesség1 +EPGPlus.vergap2_width Szélesség2 +EPGPlus.view_mode Nézet +GENRE.ARTS.0 mûvészet / kultúra +GENRE.ARTS.1 performing arts +GENRE.ARTS.10 mûvészet/kultúra magazin +GENRE.ARTS.11 divat +GENRE.ARTS.2 szépmûvészet +GENRE.ARTS.3 vallás +GENRE.ARTS.4 popular culture/traditional arts +GENRE.ARTS.5 irodalom +GENRE.ARTS.6 film/mozi +GENRE.ARTS.7 kísérleti film/videó +GENRE.ARTS.8 broadcasting/press +GENRE.ARTS.9 new media +GENRE.CHILDRENs_PROGRAMMES.0 gyermek/ifjúsági mûsor +GENRE.CHILDRENs_PROGRAMMES.1 pre-school children's programmes +GENRE.CHILDRENs_PROGRAMMES.2 entertainment programmes for 6 to 14 +GENRE.CHILDRENs_PROGRAMMES.3 entertainment programmes for 10 to 16 +GENRE.CHILDRENs_PROGRAMMES.4 informational/educational/school programmes +GENRE.CHILDRENs_PROGRAMMES.5 báb/rajzfilm +GENRE.DOCUS_MAGAZINES.0 documentation / magazine +GENRE.DOCUS_MAGAZINES.1 természet/állatok/környezet +GENRE.DOCUS_MAGAZINES.2 technológia/természettudomány +GENRE.DOCUS_MAGAZINES.3 gyógyszer/élettan/lélektan +GENRE.DOCUS_MAGAZINES.4 külföldi országok/expedíció +GENRE.DOCUS_MAGAZINES.5 társadalmi/szellemi tudományok +GENRE.DOCUS_MAGAZINES.6 további oktatás +GENRE.DOCUS_MAGAZINES.7 nyelvek +GENRE.MOVIE.0 film/dráma +GENRE.MOVIE.1 detektív/thriller +GENRE.MOVIE.2 kaland/western/háború +GENRE.MOVIE.3 sci-fi/fantázia/horror +GENRE.MOVIE.4 vígjáték +GENRE.MOVIE.5 szappanopera/melódráma/népi +GENRE.MOVIE.6 romatika +GENRE.MOVIE.7 komoly/klasszikus/vallási/történelmi film/dráma +GENRE.MOVIE.8 felnõtt film/dráma +GENRE.MUSIC_DANCE.0 zene/balett/tánc +GENRE.MUSIC_DANCE.1 rock/pop +GENRE.MUSIC_DANCE.2 komolyzene/kalsszikus +GENRE.MUSIC_DANCE.3 népzene +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musical/opera +GENRE.MUSIC_DANCE.6 balett +GENRE.NEWS.0 hírek +GENRE.NEWS.1 hírek/idõjárásjelentés +GENRE.NEWS.2 hírmûsor +GENRE.NEWS.3 ismeretterjesztõ +GENRE.NEWS.4 megbeszélés/interjú/vita +GENRE.SHOW.0 show/játék +GENRE.SHOW.1 játék/kvíz/verseny +GENRE.SHOW.2 varieté +GENRE.SHOW.3 talk show +GENRE.SOCIAL_POLITICAL.0 social & politic events / business +GENRE.SOCIAL_POLITICAL.1 magazines/reports/documentary +GENRE.SOCIAL_POLITICAL.2 economics/social advisory +GENRE.SOCIAL_POLITICAL.3 remarkable people +GENRE.SPORTS.0 sport +GENRE.SPORTS.1 különleges esemény (Olimpiai Játékok, Világkupa, stb.) +GENRE.SPORTS.10 lovaspóló +GENRE.SPORTS.11 küzdõsportok +GENRE.SPORTS.2 sportmagazin +GENRE.SPORTS.3 labdarúgás +GENRE.SPORTS.4 tenisz/squash +GENRE.SPORTS.5 csapatjáték (kivéve labdarúgás) +GENRE.SPORTS.6 atlétika +GENRE.SPORTS.7 motorsport +GENRE.SPORTS.8 vízisport +GENRE.SPORTS.9 téli sportok +GENRE.TRAVEL_HOBBIES.0 utazás és szórakozás +GENRE.TRAVEL_HOBBIES.1 utazás és turizmus +GENRE.TRAVEL_HOBBIES.2 kézimunka +GENRE.TRAVEL_HOBBIES.3 motoring +GENRE.TRAVEL_HOBBIES.4 fitnessz és egészség +GENRE.TRAVEL_HOBBIES.5 sütés/fõzés +GENRE.TRAVEL_HOBBIES.6 hirdetés/bevásárlás +GENRE.TRAVEL_HOBBIES.7 kertgazdálkodás +GENRE.UNKNOWN ismeretlen +apids.hint_1 Ãœsse be a streamelni kívánt APID-eket, +apids.hint_2 HEX-ben, szóközzel elválasztva! +apidselector.head Nyelvválasztás +audiomenu.PCMOffset PCM hangerÅ‘-csökkentés +audiomenu.analogout Analóg kimenet +audiomenu.avs avs +audiomenu.avs_control HangerÅ‘-szabalyzás (avs/ost) +audiomenu.dolbydigital Dolby Digital +audiomenu.head Hangbeállítások +audiomenu.lirc lirc +audiomenu.monoleft bal monó +audiomenu.monoright jobb monó +audiomenu.ost ost +audiomenu.stereo sztereó +audioplayer.add hozzáadás +audioplayer.artist_title ElÅ‘adó, Cím +audioplayer.building_search_index building search index +audioplayer.button_select_title_by_id search by ID +audioplayer.button_select_title_by_name név szerinti keresés +audioplayer.defdir Kiindulási könyvtár +audioplayer.delete törlés +audioplayer.deleteall összes törlése +audioplayer.display_order kijelzési sorrend +audioplayer.enable_sc_metadata enable shoutcast meta data parsing +audioplayer.fastforward gyors elÅ‘re +audioplayer.follow auto select current +audioplayer.head Audio Lejátszási lista +audioplayer.highprio magas dekódolási prioritás +audioplayer.id3scan ID3 TAG-ek beolvasása +audioplayer.jump_backwards ugrás vissza +audioplayer.jump_dialog_hint1 Kérem adja meg az ugrási célt! +audioplayer.jump_dialog_hint2 (viszonylagos, másodpercben) +audioplayer.jump_dialog_title Adja meg az ugrási célt! +audioplayer.jump_forwards ugrás elÅ‘re +audioplayer.keylevel key level +audioplayer.name Hanglejátszó +audioplayer.pause Pillanatállj +audioplayer.play Lejátszás +audioplayer.playing Current Track +audioplayer.playlist_fileerror_msg A fájlt nem lehet létrehozni: +audioplayer.playlist_fileerror_title Hiba +audioplayer.playlist_fileoverwrite_msg Kívánja felülírni ezt a fájlt? +audioplayer.playlist_fileoverwrite_title Felülírja? +audioplayer.playlist_name lejátszási lista fájlneve +audioplayer.playlist_name_hint1 Kérem adja meg a lejátszási lista fájlnevét! +audioplayer.playlist_name_hint2 Az .m3u kiterjeszés automatikusan hozzáadódik +audioplayer.reading_files reading files +audioplayer.repeat_on ismétlési mód bekapcsolása +audioplayer.rewind visszatekerés +audioplayer.save_playlist lejátszási lista mentése +audioplayer.screensaver_timeout képernyÅ‘védÅ‘ késleltetése (percben, 0=ki) +audioplayer.select_title_by_name cím névszerinti keresése (SMS) +audioplayer.show_playlist lejátszási lista mutatása +audioplayer.shuffle véletlenszerű lejátszás +audioplayer.stop Ãllj +audioplayer.title_artist cím, elÅ‘adó +audioplayerpicsettings.general Hanglejátszó / KépnézegetÅ‘ +bookmarkmanager.delete törlés +bookmarkmanager.name KönyvjelzÅ‘k +bookmarkmanager.rename átnevezés +bookmarkmanager.select kiválasztás +bouqueteditor.add hozzáadás +bouqueteditor.bouquetname Csomagok nevei +bouqueteditor.delete törlés +bouqueteditor.discardingchanges Vátozások elvetése. Kérem várjon! +bouqueteditor.hide rejtés +bouqueteditor.lock zárolás +bouqueteditor.move mozgatás +bouqueteditor.name CsomagszerkesztÅ‘ +bouqueteditor.newbouquetname Új csomag neve +bouqueteditor.rename átnevezés +bouqueteditor.return vissza +bouqueteditor.savechanges? Kívánja menteni a változásokat? +bouqueteditor.savingchanges Változások mentése. Kérem várjon! +bouqueteditor.switch hozzáadás/eltávolítás +bouqueteditor.switchmode TV/Rádió +bouquetlist.head Csomagok +cablesetup.provider Kábelszolgáltató +channellist.head Összes csatorna +channellist.nonefound A cstornalista üres.\nKérem futtasson egy keresést! +channellist.since %02d:%02d óta +colorchooser.alpha alpha +colorchooser.blue kék +colorchooser.green zöld +colorchooser.red piros +colormenu.background Háttér +colormenu.fade Menük úsztatása +colormenu.font Betűméret +colormenu.gtx_alpha ÃttetszÅ‘ség +colormenu.head Színbeállítások +colormenu.menucolors Menüszínek +colormenu.statusbar Infósor +colormenu.textcolor Betűszín +colormenu.themeselect Témaválasztás +colormenu.timing OSD idÅ‘tartam +colormenusetup.head Menüszínek +colormenusetup.menucontent ablaktartalom +colormenusetup.menucontent_inactive inaktív ablaktartalom +colormenusetup.menucontent_selected kijelölt ablaktartalom +colormenusetup.menuhead Menü fejléc +colorstatusbar.head Infósor +colorstatusbar.text infósor +colorthememenu.classic_theme Klasszikus +colorthememenu.dblue_theme DarkBlue +colorthememenu.dvb2k_theme DVB2000 +colorthememenu.head Témaválasztás +colorthememenu.neutrino_theme Neutrino +date.Apr április +date.Aug augusztus +date.Dec december +date.Feb február +date.Fri péntek +date.Jan január +date.Jul július +date.Jun június +date.Mar március +date.May május +date.Mon hétfÅ‘ +date.Nov november +date.Oct október +date.Sat szombat +date.Sep szeptember +date.Sun vasárnap +date.Thu csütörtök +date.Tue kedd +date.Wed szerda +epglist.head Műsorlista - %s +epglist.noevents Információ nem elérhetÅ‘... +epgviewer.More_Screenings További adások ezen a csatornán: +epgviewer.nodetailed Nincs bÅ‘vebb információ +epgviewer.notfound Műsorfüzet nem elérhetÅ‘ +eventlistbar.channelswitch idÅ‘zítés +eventlistbar.eventsort rendezés +eventlistbar.recordevent felvétel +favorites.addchannel A kiválasztott csatorna hozzáadódik a kedvencekhez.\nEz pár másodpercet vesz igénybe. +favorites.bouquetname Kedvencek +favorites.bqcreated A kedvencek csomag létrejött... +favorites.chadded A kiválasztott csatorna hozzáadódott a kedvencekhez... +favorites.chalreadyinbq A kiválasztott csatorna már benne van a kedvencekben... +favorites.finalhint \nKérem használja a csomagszerkesztÅ‘t a kedvencek módosításához!\n +favorites.menueadd csatorna hozzáadása a kedvencekhez +favorites.nobouquets A kedvencek csak az aktív csomagokra érvényesek. +filebrowser.delete törlés +filebrowser.denydirectoryleave Abszolút kiindulási könyvtár +filebrowser.dodelete1 Törlés +filebrowser.dodelete2 ? +filebrowser.filter.active szűrÅ‘ be +filebrowser.filter.inactive szűrÅ‘ ki +filebrowser.head FájlböngészÅ‘ +filebrowser.mark kijelölés +filebrowser.nextpage következÅ‘ oldal +filebrowser.prevpage elÅ‘zÅ‘ oldal +filebrowser.scan Könyvtár beolvasása +filebrowser.select kiválasztás +filebrowser.showrights Fájljogok kijelzése +filebrowser.sort.date (dátum) +filebrowser.sort.name (fájlnév) +filebrowser.sort.namedirsfirst (fájlnév2) +filebrowser.sort.size (méret) +filebrowser.sort.type (típus) +flashupdate.actionreadflash olvasás +flashupdate.cantopenfile a fájl nem nyitható +flashupdate.cantopenmtd az MTD eszköz nem nyitható +flashupdate.checkupdate új verzió keresése +flashupdate.currentreleasecycle kibocsátási ciklus +flashupdate.currentversion_sep aktuális verzió +flashupdate.currentversiondate dátum +flashupdate.currentversionsnapshot image típusa +flashupdate.currentversiontime idÅ‘ +flashupdate.erasefailed flash törlése sikertelen +flashupdate.erasing Flash törlése +flashupdate.experimentalimage A kiválasztott image kipróbálatlan verzió!\nEz azt jelentheti, hogy a készülék nem indul el a frissítés után.\nBiztos, hogy szeretne frissíteni erre a verzióra? +flashupdate.expertfunctions Haladó funkciók +flashupdate.fileis0bytes A fájlméret 0 Byte +flashupdate.fileselector Fájlválasztó +flashupdate.flashreadyreboot A frissítés sikeresen befejezÅ‘dött.\nA beltéri egység most újraindul. +flashupdate.getinfofile verzióinformáció lekérdezése +flashupdate.getinfofileerror verzióinformáció lekérdezése sikertelen +flashupdate.getupdatefile frissítés letöltése +flashupdate.getupdatefileerror frissítés letöltése sikertelen +flashupdate.globalprogress Összesen: +flashupdate.head Szoftverfrissítés +flashupdate.md5check image ellenÅ‘rzése +flashupdate.md5sumerror az image hibás +flashupdate.msgbox A következÅ‘ image elérhetÅ‘:\ndátum: %s, %s\nalap image: %s\nimage típus: %s\n\nKívánja letölteni és installálni ezt a verziót? +flashupdate.msgbox_manual A következÅ‘ image elérhetÅ‘:\ndátum: %s, %s\nalap image: %s\nimage típus: %s\n\nKívánja installálni ezt a verziót? +flashupdate.mtdselector Partícióválasztó +flashupdate.programmingflash Flash írása +flashupdate.proxypassword jelszó +flashupdate.proxypassword_hint1 írja be a proxy jelszavát! +flashupdate.proxypassword_hint2 üres bejegyzés esetén nincs hitelesítés +flashupdate.proxyserver hostnév +flashupdate.proxyserver_hint1 írja be a proxy nevét vagy IP címét és a portot! (host:port) +flashupdate.proxyserver_hint2 üres bejegyzés esetén nincs proxy +flashupdate.proxyserver_sep Proxy szerver +flashupdate.proxyusername felhasználónév +flashupdate.proxyusername_hint1 írja be a proxy felhasználónevet +flashupdate.proxyusername_hint2 üres bejegyzés esetén nincs hitelesítés +flashupdate.readflash Teljes image kiolvasása +flashupdate.readflashmtd Egy partíció kiolvasása +flashupdate.ready Kész +flashupdate.reallyflashmtd Biztos benne, hogy programoz?\n\nHa hiba történik, vagy az image\nnem érvényes, a készülék nem fog elindulni a frissítés után!\n\Image neve: %s\nCél: %s +flashupdate.savesuccess Az image sikeresen el lett mentve\n%s néven. +flashupdate.selectimage ElérhetÅ‘ image-ek +flashupdate.squashfs.noversion SquashFS version checks are currently only supported when updating over the web.\nAre you sure that you wish to install this image? +flashupdate.titlereadflash Flash olvasása +flashupdate.titlewriteflash Flash írása +flashupdate.updatemode Frissítési mód +flashupdate.updatemode_internet Internet +flashupdate.updatemode_manual Kézi (FTP) +flashupdate.url_file Konfigurációs fájl +flashupdate.versioncheck Verzió ellenÅ‘rzése +flashupdate.writeflash Teljes image írása +flashupdate.writeflashmtd Egy partíció írása +flashupdate.wrongbase Your Release cycle differs, unable to update\nwithout having installed the right version! +fontmenu.channellist Csatornalista +fontmenu.epg EPG +fontmenu.eventlist Műsorfüzet +fontmenu.gamelist Játéklista +fontmenu.head Betűméretek beállítása +fontmenu.infobar Infósor +fontsize.channel_num_zap közvetlen kiválasztás +fontsize.channellist Csatornalista +fontsize.channellist_descr Leírás +fontsize.channellist_number Szám +fontsize.epg_date EPG dátum +fontsize.epg_info1 EPG infó 1 +fontsize.epg_info2 EPG infó 2 +fontsize.epg_title EPG cím +fontsize.eventlist_datetime dátum / idÅ‘ +fontsize.eventlist_itemlarge nagy +fontsize.eventlist_itemsmall kicsi +fontsize.eventlist_title cím +fontsize.filebrowser_item fájlböngészÅ‘ elem +fontsize.gamelist_itemlarge nagy +fontsize.gamelist_itemsmall kicsi +fontsize.hint Betűtípus inicializálása,\nkérem várjon! +fontsize.infobar_channame csatorna neve +fontsize.infobar_info infó +fontsize.infobar_number szám +fontsize.infobar_small kicsi +fontsize.menu menüszöveg +fontsize.menu_info menü infó +fontsize.menu_title menü címsor +gtxalpha.alpha1 alpha 1 +gtxalpha.alpha2 alpha 2 +infoviewer.epgnotload EPG nincs betöltve.... +infoviewer.epgwait Várakozás a műsorinformációra... +infoviewer.eventlist műsorlista +infoviewer.languages hang +infoviewer.motor_moving Motor pozícionálása +infoviewer.nocurrent Nincs elérhetÅ‘ információ a műsorról +infoviewer.noepg Műsorinformáció nem elérhetÅ‘ +infoviewer.notavailable Csatorna nem elérhetÅ‘ +infoviewer.selecttime idÅ‘választás +infoviewer.streaminfo extrák +infoviewer.subservice alcsatornák +infoviewer.waittime Várakozás az idÅ‘re... +ipsetup.hint_1 0..9, vagy fel/le, +ipsetup.hint_2 OK: mentés, LAME/EXIT: mégsem +keybindingmenu.RC Gombnyomás isméltésgátló +keybindingmenu.addrecord Felvételi idÅ‘zítÅ‘ hozzáadása +keybindingmenu.addremind Csatornaváltás-idÅ‘zítÅ‘ hozzáadása +keybindingmenu.allchannels_on_ok minden csatorna +keybindingmenu.bouquetchannels_on_ok aktuális csomag +keybindingmenu.bouquetdown Csomagot vissza +keybindingmenu.bouquethandling Csomagkezelés +keybindingmenu.bouquetlist_on_ok Csomaglista +keybindingmenu.bouquetup KövetkezÅ‘ csomag +keybindingmenu.cancel Csatornalista bezárása +keybindingmenu.channeldown Csatonát le +keybindingmenu.channellist Csatornalista +keybindingmenu.channelup Csatornát fel +keybindingmenu.head TávvezérlÅ‘ +keybindingmenu.lastchannel Gyorsváltás +keybindingmenu.modechange Módválasztás +keybindingmenu.pagedown Oldalt le +keybindingmenu.pageup Oldalt fel +keybindingmenu.quickzap Gyorsváltás +keybindingmenu.repeatblock Ismétlési késleltetés +keybindingmenu.repeatblockgeneric Ãltalános késleltetés +keybindingmenu.sort Rendezési sorrend +keybindingmenu.subchanneldown Alcsatornát le +keybindingmenu.subchannelup Alcsatornát fel +keybindingmenu.tvradiomode TV/Radió mód +keybindingmenu.zaphistory ElÅ‘zÅ‘ csatornák +keychooser.head Új gomb beállítása +keychooser.text1 Kérem nyomja meg a kívánt gombot! +keychooser.text2 Várjon, ha mégsem. +keychoosermenu.currentkey Aktuális gomb +keychoosermenu.setnew Új gomb beállítása +keychoosermenu.setnone Nincs gomb +languagesetup.head Nyelv +languagesetup.select Nyelv +lcdcontroler.brightness Normál fényerÅ‘ +lcdcontroler.brightnessstandby Készenléti fényerÅ‘ +lcdcontroler.contrast kontraszt +lcdcontroler.head KijelzÅ‘ +lcdmenu.autodimm automatikus halványítás +lcdmenu.head LCD beállítások +lcdmenu.inverse Inverz +lcdmenu.lcdcontroler Kontraszt / fényerÅ‘ +lcdmenu.power Világítás +lcdmenu.statusline Megjelenítés +lcdmenu.statusline.both hangerÅ‘ / eltelt idÅ‘ +lcdmenu.statusline.playtime eltelt idÅ‘ +lcdmenu.statusline.volume hangerÅ‘ +mainmenu.audioplayer Hanglejátszó +mainmenu.games Játékok +mainmenu.head FÅ‘menü +mainmenu.movieplayer Videólejátszó +mainmenu.pausesectionsd EPG olvasása +mainmenu.pictureviewer KépnézegetÅ‘ +mainmenu.radiomode Rádió mód +mainmenu.recording Felvétel +mainmenu.recording_start start +mainmenu.recording_stop stop +mainmenu.scartmode SCART mód +mainmenu.service Szolgáltatások +mainmenu.settings Beállítások +mainmenu.shutdown Kikapcsolás +mainmenu.sleeptimer Elalváskapcsoló +mainmenu.tvmode TV mód +mainsettings.audio Hangbeállítások +mainsettings.colors Színek / témák / betűtípusok +mainsettings.head Beállítások +mainsettings.keybinding TávvezérlÅ‘ +mainsettings.language Nyelv +mainsettings.lcd KijelzÅ‘ +mainsettings.misc Egyéb beállítások +mainsettings.network Hálózat +mainsettings.recording Felvétel +mainsettings.savesettingsnow Beállítások mentése +mainsettings.savesettingsnow_hint Mentés folyamatban,\nkérem várjon... +mainsettings.streaming Videólejátszó +mainsettings.video Képbeállítások +menu.back Vissza +messagebox.back Vissza +messagebox.cancel mégsem +messagebox.discard Elveti a változásokat? +messagebox.error Hiba +messagebox.info Információ +messagebox.no nem +messagebox.yes igen +miscsettings.bootinfo infók mutatása indításkor +miscsettings.bootmenu indítási menü bekapcsoláskor +miscsettings.driver_boot Meghajtó és indítási beállítások +miscsettings.fb_destination Expert! Boot-Console +miscsettings.general Ãltalános +miscsettings.head Egyéb beállítások +miscsettings.hwsections hardverszekciók használata +miscsettings.infobar_sat_display Műhold neve az infósoron +miscsettings.pmtupdate PMT frissítés engedélyezése +miscsettings.shutdown_real Készenlét engedélyezése +miscsettings.shutdown_real_rcdelay Késleltetett kikapcsolás +miscsettings.sptsmode SPTS mód használata +miscsettings.startbhdriver BH módú meghajtók betöltése +motorcontrol.head Motorbeállítások +movieplayer.bookmark könyvjelzÅ‘k +movieplayer.bookmarkname könyvjelzÅ‘ neve +movieplayer.bookmarkname_hint1 Kérem adjon nevet az új könyvjelzÅ‘nek! +movieplayer.bookmarkname_hint2 +movieplayer.buffering Buffering... +movieplayer.defdir kiindulási könyvtár +movieplayer.dvdplayback DVD +movieplayer.fileplayback Fájl VLC-n keresztül +movieplayer.goto Ugrás... +movieplayer.goto.h1 = -> abszolút ugrás +movieplayer.goto.h2 +,- -> relatív ugrás +movieplayer.head Videólejátszó +movieplayer.nostreamingserver A streamingszerver nem elérhetÅ‘. +movieplayer.pesplayback PES lejátszása (kísérleti) +movieplayer.pleasewait Kérem várjon!\nCsatlakozás a streamingszerverhez... +movieplayer.toomanybookmarks Túl sok könyvjelzÅ‘.\nElÅ‘bb törölni kell egyet. +movieplayer.tsplayback TS lejátszása +movieplayer.vcdplayback (S)VCD +movieplayer.wrongvlcversion Ez a funkció nem elérhetÅ‘ a VLC jelenlegi verziójával. +networkmenu.broadcast Broadcast +networkmenu.dhcp DHCP +networkmenu.gateway Ãtjáró +networkmenu.head Hálózat +networkmenu.ipaddress IP cím +networkmenu.mount NFS/CIFS +networkmenu.nameserver DNS +networkmenu.netmask Netmaszk +networkmenu.setupnow Beállítások aktualizálása +networkmenu.setuponstartup Hálózat inicializálása indításkor +networkmenu.show Jelenlegi beállítások mutatása +networkmenu.test Hálozat tesztelése +nfs.alreadymounted directory already mounted +nfs.automount mount on startup +nfs.dir directory/share +nfs.ip NFS/CIFS Server IP +nfs.localdir local dir +nfs.mount Mount NFS/CIFS volume +nfs.mount_options mount options +nfs.mounterror mount error +nfs.mounterror_notsup filesystem type not supported +nfs.mountnow mount now +nfs.mounttimeout mount error: timeout +nfs.password CIFS password +nfs.remount remount directories +nfs.type type +nfs.type_cifs CIFS +nfs.type_nfs NFS +nfs.umount Unmount NFS/CIFS volume +nfs.umounterror error umounting volume +nfs.username CIFS username +nfsmenu.head NFS/CIFS settings +nvod.percentage (%d%% over) +nvod.starting (kezdés %d pecr múlva) +nvodselector.directormode közvetlen elérési mód +nvodselector.head Kezdési idÅ‘pont kiválasztása +nvodselector.subservice Alcsatorna kiválasztása +options.default Alapértelmezett értékek +options.fb képernyÅ‘ +options.null null +options.off ki +options.on be +options.serial serial +parentallock.changepin PIN megváltoztatása +parentallock.changepin_hint1 Ide üsse be az új PIN kódot! +parentallock.changetolocked on locked bouquets +parentallock.head Ãœsse be a PIN kódot! +parentallock.lockage Program zárolása +parentallock.lockage12 12 évtÅ‘l +parentallock.lockage16 16 évtÅ‘l +parentallock.lockage18 18 évtÅ‘l +parentallock.lockedchannel Zárolt csatorna... +parentallock.lockedprogram Zárolt műsor (%d évtÅ‘l) +parentallock.never soha +parentallock.onsignal műsor szerint +parentallock.parentallock Gyermekzár +parentallock.prompt PIN kód kérése +pictureviewer.defdir kiindulási könyvtár +pictureviewer.head KépnézegetÅ‘ +pictureviewer.resize.color_average fejlett +pictureviewer.resize.none nincs +pictureviewer.resize.simple egyszerű +pictureviewer.scaling méretezés +pictureviewer.show mutatás +pictureviewer.slide_time slideshow display time +pictureviewer.slideshow vetítés +pictureviewer.sortorder rendezési sorrend +pictureviewer.sortorder.date (dátum) +pictureviewer.sortorder.filename (fájlnév) +ping.ok elérhetÅ‘ (ping) +ping.protocol nem elérhetÅ‘ (host vagy protokoll hiba) +ping.socket nem elérhetÅ‘ (socket hiba) +ping.unreachable nem elérhetÅ‘ +pinprotection.head Ãœsse be a PIN kódot +pinprotection.wrongcode A PIN kód hibás! Próbálja újra! +rclock.lockmsg A távvezérlÅ‘ zárolva lesz.\nA nyitáshoz nyomja meg a PIROS gombot,\nmajd a MENU/DBOX gombot! +rclock.menueadd TávvezérlÅ‘-zár +rclock.title TávvezérlÅ‘ zárolása +rclock.unlockmsg TávvezérlÅ‘ aktiválva +recordingmenu.defdir felvételi könyvtár +recordingmenu.file közvetlen (fájl) +recordingmenu.head Felvétel +recordingmenu.help Felvételi eszközök:\n--------------------------\nszerver:\nstreaming szoftver használata a PC-n\n\n(analóg) képmagnó:\nképmagnó használata\n\nközvetlen (fájl):\nközvetlen felvétel NFS könyvtárba,\nvagy beépített merevlemezre\n\n\nMax. fájlméret:\n---------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: elég nagy :) (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart ne kapcsoljon SCART módba +recordingmenu.off ki +recordingmenu.recording_type Felvételi eszköz +recordingmenu.server Szerver +recordingmenu.server_ip Felvételi szerver IP címe +recordingmenu.server_mac MAC cím +recordingmenu.server_port Felvételi szerver portja +recordingmenu.server_wakeup Felvételi szerver WOL +recordingmenu.setupnow Beállítások aktualizálása +recordingmenu.splitsize Max. fájlméret (MB) +recordingmenu.stopplayback Lejátszás megállítása +recordingmenu.stopsectionsd SectionSD megállítása +recordingmenu.stream_vtxt_pid Teletext rögzítése +recordingmenu.use_o_sync Szinkron írás (O_SYNC) +recordingmenu.vcr Képmagnó +recordtimer.announce A felvétel néhány percen belül kezdÅ‘dik +repeatblocker.hint_1 A legrövidebb idÅ‘ (ms-ban) két gombnyomás felismerésére +repeatblocker.hint_2 0 érték kikapcsolja a blokkolót (PIROS gomb: szóköz) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-ismétlések +satsetup.extended DiSEqC beállítások +satsetup.extended_motor Motorbeállítások +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Kézi beállítás +satsetup.nodiseqc nincs DiSEqC +satsetup.satellite Műhold +satsetup.savesettingsnow Beállítások mentése +satsetup.smatvremote SMATV távhangolás +scants.actcable Kábel: +scants.actsatellite Műhold: +scants.bouquet Csomagok kezelése +scants.bouquet_create újak készítése +scants.bouquet_erase összes törlése +scants.bouquet_leave jelenlegiek megtartása +scants.bouquet_satellite műhold-csomagok +scants.bouquet_update frissítés +scants.channel Csatorna: +scants.failed A transzponderkeresés sikertelen! +scants.finished A transponderkeresés sikereresen befejezÅ‘dött! +scants.freqdata Frekvencia: +scants.head Transzponderkeresés +scants.numberofdataservices Adat +scants.numberofradioservices Rádio +scants.numberoftotalservices Összesen +scants.numberoftvservices TV +scants.provider Szolgáltató: +scants.startnow Keresés indítása +scants.transponders Transzponder: +screensetup.lowerright ZÖLD = jobb alsó +screensetup.upperleft PIROS = bal felsÅ‘ +servicemenu.head Szolgáltatások +servicemenu.reload Csatornalista újratöltése +servicemenu.reload_hint Újratöltés. Kérem várjon! +servicemenu.scants Csatornakeresés +servicemenu.ucodecheck Mikrokódok ellenÅ‘rzése +servicemenu.update Szoftverfrissítés +settings.help Segítség +settings.missingoptionsconffile A konfigurációs fájl hiányzik.\nAz összes érték alapértelmezettre lesz állítva. +settings.noconffile A beállítások hiányoznak.\nAlapértékek használata. +shutdowntimer.announce A készülék 1 percen belül kikapcsol.\nMegszakítja a folyamatot? +sleeptimerbox.announce Elalváskapcsoló 1 perc múlva +sleeptimerbox.hint1 Kikapcsolási idÅ‘ percben. (000=ki) +sleeptimerbox.hint2 A készülék ennyi idÅ‘ múlva fog kikapcsolni. +sleeptimerbox.title Elalváskapcsoló +streamfeatures.head Features +streaminfo.aratio képarány +streaminfo.aratio_unknown képarány: ismeretlen +streaminfo.audiotype hangtípus +streaminfo.audiotype_unknown hangtípus: ismeretlen +streaminfo.bitrate bitráta +streaminfo.framerate képkocka-ráta +streaminfo.framerate_unknown képkocka-ráta: ismeretlen +streaminfo.head Adatfolyam-információk +streaminfo.not_available nem elérhetÅ‘ +streaminfo.resolution felbontás +streaminfo.signal Vett jel +streaming.buffer_overflow A felvétel meg lett szakítva,\nmert az adatot nem lehetett eléggé gyorsan írni. +streaming.busy One or several recording processes are active.\nIf you encounter this message and no recording is active, please restart Neutrino. +streaming.dir_not_writable A felvételi könyvtár nem írható.\nA felvétel nem fog működni. +streaming.success A felvétel sikeresen befejezÅ‘dött. +streaming.write_error A felvétel meg lett szakítva,\nmert hiba történt az írásnál. +streaming.write_error_open A felvétel meg lett szakítva,\nmert a célfájlt nem lehet megnyitni. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Videólejátszó +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off ki +streamingmenu.on be +streamingmenu.server_ip streaming szerver IP címe +streamingmenu.server_port streaming szerver portja +streamingmenu.streaming_audiorate hang bitráta +streamingmenu.streaming_force_avi_rawaudio Force AC3 for AVI +streamingmenu.streaming_force_transcode_video MPG/VCD videó áttömörítése +streamingmenu.streaming_resolution Felbontás +streamingmenu.streaming_server_cddrive DVD meghajtó +streamingmenu.streaming_server_startdir könyvtár (VLC) +streamingmenu.streaming_transcode_audio Hang áttömörítése (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec MPEG videókodek +streamingmenu.streaming_type Streaming szerver +streamingmenu.streaming_videorate videó adatráta +streamingserver.noconnect Nincs kapcsolat a streaming szerverrel.\nFelvétel megszakítva. +stringinput.caps nagybetű / kisbetű +stringinput.clear összes törlése +timer.eventrecord.msg ... TO be DONE, or not to be done +timer.eventrecord.title Felvétel idÅ‘zítés +timer.eventtimed.msg A műsor idÅ‘zítve van.\nA készülék be fog kapcsolni és\nát fog kapcsolni a megadott csatornára a megadott idÅ‘ben. +timer.eventtimed.title Műsor idÅ‘zítés +timerbar.channelswitch IdÅ‘zítés +timerbar.recordevent Felvétel +timerlist.alarmtime Művelet idÅ‘pontja +timerlist.apids Hang PID-ek +timerlist.bouquetselect Csomagok +timerlist.channel Csatorna +timerlist.channelselect Csatornák +timerlist.delete törlés +timerlist.menumodify módosítás +timerlist.menunew új idÅ‘zítÅ‘ +timerlist.message üzenet +timerlist.moderadio Rádiócsatornák +timerlist.modeselect Ãœzemmód választás +timerlist.modetv Tévécsatornák +timerlist.modify módosítás +timerlist.name IdÅ‘zítÅ‘lista +timerlist.new új idÅ‘zítÅ‘ +timerlist.program.unknown ismeretlen műsor +timerlist.reload újratöltés +timerlist.repeat ismétlés +timerlist.repeat.biweekly kéthetente +timerlist.repeat.byeventdescription lásd az idÅ‘zítÅ‘t +timerlist.repeat.daily naponta +timerlist.repeat.fourweekly négyhetente +timerlist.repeat.friday P +timerlist.repeat.monday H +timerlist.repeat.monthly havonta +timerlist.repeat.once egyszer +timerlist.repeat.saturday SZ +timerlist.repeat.sunday V +timerlist.repeat.thursday CS +timerlist.repeat.tuesday K +timerlist.repeat.unknown ismeretlen +timerlist.repeat.wednesday SZ +timerlist.repeat.weekdays hét adott napjain +timerlist.repeat.weekly hetente +timerlist.save IdÅ‘zítÅ‘ mentése +timerlist.standby készenléti üzemmód +timerlist.standby.off készenlét elhagyása +timerlist.standby.on készenlétbe menetel +timerlist.stoptime Megállás idÅ‘pontja +timerlist.type IdÅ‘zítÅ‘ típusa +timerlist.type.nextprogram KövetkezÅ‘ műsor +timerlist.type.record felvétel +timerlist.type.remind emlékeztetÅ‘ +timerlist.type.shutdown kikapcsolás +timerlist.type.sleeptimer elalváskapcsoló +timerlist.type.standby készenlét +timerlist.type.unknown ismeretlen +timerlist.type.zapto csatornaváltás +timerlist.weekdays A hét napjai +timerlist.weekdays.hint_1 H K SZ CS P SZ V +timerlist.weekdays.hint_2 igen:X, nem:- +timersettings.record_safety_time_after Megállás idejének korrekciója +timersettings.record_safety_time_after.hint_1 Correction time in min. (00=off). This time +timersettings.record_safety_time_after.hint_2 will added to stop time of every record timer. +timersettings.record_safety_time_before Record start time correction +timersettings.record_safety_time_before.hint_1 Correction time in min. (00=off). This time +timersettings.record_safety_time_before.hint_2 will be deducted of every record timer. +timersettings.separator IdÅ‘zítÅ‘ beállítások +timing.chanlist Csatornalista +timing.epg EPG +timing.filebrowser FájlböngészÅ‘ +timing.head OSD idÅ‘tartam +timing.hint_1 Time in sec. After this time the +timing.hint_2 infobar will be faded out. +timing.infobar Infósor +timing.menu Menü +timing.numericzap Numerikus váltás +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head Mikrokód ellenÅ‘rzés +ucodecheck.ucode Mikrokód +ucodes.failure Figyelem! A mikrokódok hiányoznak!\n\nKérem töltse fel Å‘ket a készülékbe,\nmajd indítson újra! +videomenu.csync Szinkronkorrekció +videomenu.head Képbeállítások +videomenu.rgb_centering RGB középpont +videomenu.screensetup KépernyÅ‘-beállítás +videomenu.vcrswitch SCART automatikus kapcsolása +videomenu.videoformat Formátum +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect automatikus +videomenu.videosignal Videójel +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce Csatornaváltás 1 perc múlva +extra.auto automatikus +extra.valid érvényes +extra.all összes +extra.new_keys új kulcsok +extra.all_keys minden kulcs +extra.vartmp /var/tmp +extra.varkeys /var/keys +extra.algo csak ismerteket +extra.gbox_emu emu +extra.gbox_softcam softcam +extra.gbox_net hálózat +extra.gbox_mix kevert +extra.gbox_info GBOX infó +extra.sep_extra Extrák +extra.save_settings Beállítások mentése +extra.extra_menu Kiegészítések +extra.ecm_info ECM infó +extra.pid_info PID infó +extra.emm_info Új kulcsok +extra.emu_type Emu típusa +extra.camd CAMD +extra.restart_camd CAMD újraindítása +extra.mg_settings Mgcamd beállítások +extra.netmode netmód +extra.autoupdate autoupdate +extra.show_ecm ECM kijelzése +extra.show_emm EMM kijelzése +extra.keyupdate kulcsfrissítés +extra.osd OSD +extra.keyfolder Kulcsok könyvtára +extra.hash_pids PID-ek ellenÅ‘rzése +extra.gbox_settings GBOX Settings +extra.gbox_mode Ãœzemmód +extra.newcamd_settings Newcamd beállítások +extra.show_cw CW kijelzése +extra.debug_ecm ECM debug +extra.disable_cam CAM letiltása +extra.show_cat Show CAT +extra.show_pmt show PMT +extra.update_pmt Update PMT +extra.report_emm Report wrong EMM sig. +extra.debug_emm Debug Emm +extra.show_allca Show all ca sys. +extra.reload_keys Reload keys on zap +extra.reload_cfg Reload config on zap +extra.cw_delay Default CW delay +extra.dvbsnoop DVB Stream Info +extra.dvbsnoop_pat Show PAT +extra.dvbsnoop_cat Show CAT +extra.dvbsnoop_tsdt Show TSDT +extra.dvbsnoop_nit Show NIT +extra.dvbsnoop_sdt Show SDT +extra.dvbsnoop_eit Show EIT +extra.dvbsnoop_rst Show RST +extra.dvbsnoop_tdt Show TDT +extra.dvbsnoop_sit Show SIT +extra.dvbsnoop_pid Show manual PID +extra.dvbsnoop_scan Scan PIDs +extra.dvbsnoop_band Show pid bandwidth +extra.logview View Log +extra.ru ruDREAM +extra.english Automatikus angol nyelv +extra.dboxinfo Készülék infó +extra.scan_mode Keresési mód +extra.start_tostandby Készenlét bekapcsolás után +extra.rotor_swap Kelet/Nyugat felcserélése +extra.use_log Naplózás a /tmp/log -ba +extra.spts_mode SPTS mód +extra.hw_sect Hardwareszekciók +extra.logo Logó száma +extra.scan_full teljes +extra.scan_fast gyors +extra.hdd_slow lassú +extra.hdd_middle közepes +extra.hdd_fast gyors +extra.hdd_ext3 Ext3FS +extra.hdd_reiser ReiserFS +extra.hdd_1min 1 perc +extra.hdd_5min 5 perc +extra.hdd_10min 10 perc +extra.hdd_20min 20 perc +extra.hdd_30min 30 perc +extra.hdd_60min 60 perc +extra.logo1 1 +extra.logo2 2 +extra.logo3 3 +extra.hdd_sleep Elalvási idÅ‘ +extra.hdd_noise Teljesítmény/zaj +extra.hdd_activate Beállítások aktualizálása +extra.hdd_fs Fájlrendszer +extra.hdd_format Merevlemez formázása +extra.hdd_check Fájlrendszer ellenÅ‘rzése +extra.hdd_settings Merevlemez-beállítások +extra.clear_log Napló törlése +extra.zap_cycle Körbejárás +extra.sms_channel SMS csatornaváltás +extra.manual_scan Kézi keresés +extra.tp_freq Frekvencia +extra.tp_rate Symbol Rate +extra.tp_pol Polarizáció +extra.tp.pol_v V +extra.tp_pol_h H +extra.tp_fec FEC +extra.fec_1_2 1/2 +extra.fec_2_3 2/3 +extra.fec_3_4 3/4 +extra.fec_5_6 5/6 +extra.fec_7_8 7/8 +extra.timezone IdÅ‘zóna +extra.zapit_menu Zapit beállítások +extra.zapit_make_bouquet Csomagokon kívüli csatornák +extra.zapit_save_last_chan Utolsó pozíció mentése +extra.zapit_motor_speed Forgató sebessége +extra.zapit_fe_timeout Hanglolásra várakozás +extra.add_to_bouquet másolás csomagba +extra.key_list_start eleje +extra.key_list_end vége +extra.chadded A csatorna hozzá lett adva a kiválasztott csomaghoz...\n +extra.chalreadyinbq A csatorna már benne van a kiválasztott csomagban...\n +extra.menu_left_exit "balra" = visszalépés a menüben +extra.zapit_write_names Csatornanevek mentése +extra.update_dir Könyvtár a frissítésekhezextra.cache Cache +extra.debug Debug +extra.zapit_backup Backup channels to /tmp +extra.zapit_delete Delete channels +extra.zapit_fast_zap fast zap +extra.zapit_restore Restore channels from /tmp +extra.zapit_sort_names Sort ch. by name +filesystem.is.utf8 file system +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +infoviewer.subchan_disp_pos Subchannel display +mainmenu.scripts Scripts +miscsettings.noaviawatchdog enable AVIA watchdog +miscsettings.noenxwatchdog enable eNX watchdog +movieplayer.defplugin Start-Plugin +movieplayer.tshelp1 Stop +movieplayer.tshelp10 approx. 10 minutes back +movieplayer.tshelp11 skip approx. 10 minutes +movieplayer.tshelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Select audio track +movieplayer.tshelp3 Pause/Continue +movieplayer.tshelp4 Create bookmark +movieplayer.tshelp5 Show progress +movieplayer.tshelp6 approx. 1 minute back +movieplayer.tshelp7 skip approx. 1 minute +movieplayer.tshelp8 approx. 5 minutes back +movieplayer.tshelp9 skip approx. 5 minutes +movieplayer.vlchelp1 Stop +movieplayer.vlchelp10 approx. 10 minutes back +movieplayer.vlchelp11 skip approx. 10 minutes +movieplayer.vlchelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Resync +movieplayer.vlchelp3 Pause/Continue +movieplayer.vlchelp4 Create bookmark +movieplayer.vlchelp5 Show progress +movieplayer.vlchelp6 approx. 1 minute back +movieplayer.vlchelp7 skip approx. 1 minute +movieplayer.vlchelp8 approx. 5 minutes back +movieplayer.vlchelp9 skip approx. 5 minutes +nfs.mountok mount successful +nfs.type_lufs FTPFS +pictureviewer.help1 menu mode +pictureviewer.help10 show mode +pictureviewer.help11 reread image +pictureviewer.help12 previous image +pictureviewer.help13 next image +pictureviewer.help14 Zoom out +pictureviewer.help15 Zoom in +pictureviewer.help16 scroll up +pictureviewer.help17 scroll left +pictureviewer.help18 scroll right +pictureviewer.help19 scroll down +pictureviewer.help2 display image +pictureviewer.help20 change sort order +pictureviewer.help21 reread image (no scaling) +pictureviewer.help22 exit +pictureviewer.help3 change sort order +pictureviewer.help4 do not scale picture +pictureviewer.help5 diashow mode +pictureviewer.help6 previous image +pictureviewer.help7 next image +pictureviewer.help8 change sort order +pictureviewer.help9 exit +plugins.result plugin output +recordingmenu.choose_direct_rec_dir choose dir on imm. recording +recordingmenu.epg_for_filename long filenames (with EPG data) +recordingmenu.filesettings direct recording settings +recordingmenu.ringbuffers no. of ringbuffers +recordingmenu.use_fdatasync write synchronous (fdatasync) +settings.pos_bottom_left bottom left +settings.pos_bottom_right bottom right +settings.pos_top_left oben top left +settings.pos_top_right oben top right +timerlist.plugin Plugin +timerlist.recording_dir recording directory +timerlist.repeatcount repeats +timerlist.repeatcount.help1 amount of timer repeats +timerlist.repeatcount.help2 0 for unlimited repeats +timerlist.type.execplugin Execute plugin +extra.cache Cache +pictureviewer.decode_server_ip decode server ip +pictureviewer.decode_server_port decode server port +scants.abort_body Should the search really be aborted? +scants.abort_header Keresés megszakítása +recordingmenu.record_in_spts_mode switch to spts mode before recording +servicemenu.getplugins Reload plugins +servicemenu.getplugins_hint Reloading plugins,\nplease be patient. +zapit.scantype scan for services +zapit.scantype.all all services +zapit.scantype.radio only radio +zapit.scantype.tv only tv +zapit.scantype.tvradio tv & radio +colorthememenu.red_theme Simply Red +lcdmenu.dim_brightness Brightness after dim timeout +lcdmenu.dim_time Dim timeout +timerlist.overlapping_timer Timer conflict. Create the timer anyway? +extra.audio_run_player Audio key start player +mpkey.rewind Rewind +mpkey.forward Forward +mpkey.pause Pause +mpkey.stop Stop +mpkey.play Play +mpkey.audio Audio track +mpkey.time Show time +mpkey.bookmark save bookmark +mpkey.plugin Run plugin +extra.key_click Key click +extra.loadcolors Load colors from +extra.savecolors Save colors as +extra.loadkeys Load keys from +extra.savekeys Save keys as +extra.loadconfig Load settings from +extra.saveconfig Save settings as +videomenu.videomode Video system +videomenu.videomode_ntsc NTSC +videomenu.videomode_pal PAL +videomenu.videomode_palm PAL-M +extra.key_timeshift Timeshift +extra.key_plugin One touch plugin +extra.timeshift_pause Timeshift pause +rfmod.rfmod RF modulator +rfmod.carrier Subcarrier Frequency +rfmod.carrier4500 4.5 +rfmod.carrier5500 5.5 +rfmod.carrier6000 6.0 +rfmod.carrier6500 6.5 +rfmod.enable Enable sound +rfmod.channel Channel +rfmod.finetune Fine tune +rfmod.standby Enable modulator +rfmod.test Test pattern +extra.zapit_scanpids Scan/Use pids +extra.zapit_rezap_time Re-Zap on emu switch time +extra.zapit_hvoltage High (13.5/18.5) voltage +extra.key_unlock Unlock key +extra.mg_netoptions Network options +extra.mg_ecm_timeout Network ecm timeout +extra.mg_reconnect Shares reconnect +extra.mg_priority Share priority +extra.mg_osd_options Osd options +extra.mg_reread Reread files on zap +servicemenu.imageinfo Image info +imageinfo.creator Creator: +imageinfo.date Date: +imageinfo.dokumentation Docs: +imageinfo.forum Forum: +imageinfo.head Image info: +imageinfo.homepage Home page: +imageinfo.image Image: +imageinfo.license License: +imageinfo.version Version: +extra.cache_txt Cache teletext +extra.use_gotoxx Use gotoXX +extra.latitude Latitude +extra.longitude Longitude +extra.ladirection LaDirection +extra.lodirection LoDirection +extra.south South +extra.north North +extra.east East +extra.west West +epgextended.actors Actors +epgextended.director Director +epgextended.guests Guests +epgextended.original_title Original Title +epgextended.presenter Presenter +epgextended.year_of_production Year of Production +recordingmenu.save_in_channeldir Save in channel dir +servicemenu.restart Soft restart +servicemenu.restart_failed Restart failed +servicemenu.restart_hint Restarting, please wait +servicemenu.restart_refused_recording Cant restart, recording in progress +extra.cs Cardserver +extra.restart_cs Restart cardserver +extra.tp_mod Modulation +extra.tp_mod_16 QAM/16 +extra.tp_mod_32 QAM/32 +extra.tp_mod_64 QAM/64 +extra.tp_mod_128 QAM/128 +extra.tp_mod_256 QAM/256 +moviebrowser.book_head Bookmarks +moviebrowser.book_lastmoviestop Last play stop: +moviebrowser.book_movieend Movie end: +moviebrowser.book_moviestart Movie start: +moviebrowser.book_name Name: +moviebrowser.book_new New Bookmark +moviebrowser.book_position Position: +moviebrowser.book_type Jump (<0 back , >0 for): +moviebrowser.book_type_backward Repeat +moviebrowser.book_type_forward jump over +moviebrowser.edit_book Bookmark change +moviebrowser.edit_book_name_info1 Enter new Bookmark name +moviebrowser.edit_book_name_info2 +moviebrowser.edit_book_pos_info1 Enter new Position (s) +moviebrowser.edit_book_pos_info2 +moviebrowser.edit_book_type_info1 Enter new jump length (s) +moviebrowser.edit_book_type_info2 <0 back , >0 for, 0: none +moviebrowser.edit_serie Enter name of serie +moviebrowser.error_no_movies No movies found +moviebrowser.foot_filter Filter: +moviebrowser.foot_play Start movie +moviebrowser.foot_sort Sort: +moviebrowser.head TS MovieBrowser +moviebrowser.head_filter Filter movies by category: +moviebrowser.head_playlist Last played: +moviebrowser.head_recordlist Last recorded: +moviebrowser.hint_jumpbackward Jump back in 5 s\n '0' to cancel +moviebrowser.hint_jumpforward Jump forward in 5 s\n '0' to cancel +moviebrowser.hint_movieend Filmende in 5 s\n '0' zum weitersehen +moviebrowser.hint_newbook_backward New jump back\n 'blue' for endposition +moviebrowser.hint_newbook_forward New jump forward\n 'blue' for endposition +moviebrowser.info_audio Audio +moviebrowser.info_channel Channel +moviebrowser.info_filename Name +moviebrowser.info_genre_major Genre +moviebrowser.info_genre_minor Genre +moviebrowser.info_head Film Informationen +moviebrowser.info_info1 Info 1 +moviebrowser.info_info2 Info 2 +moviebrowser.info_length Length (Min) +moviebrowser.info_parental_lockage Parental Lock age +moviebrowser.info_parental_lockage_0year always +moviebrowser.info_parental_lockage_12year 12 years +moviebrowser.info_parental_lockage_16year 16 years +moviebrowser.info_parental_lockage_18year 18 years +moviebrowser.info_parental_lockage_6year 6 years +moviebrowser.info_parental_lockage_always never +moviebrowser.info_path Path +moviebrowser.info_prevplaydate Last play date +moviebrowser.info_prodcountry Country +moviebrowser.info_prodyear Year +moviebrowser.info_quality Quality +moviebrowser.info_recorddate Record date +moviebrowser.info_serie Serie +moviebrowser.info_size File size (MB) +moviebrowser.info_title Titel +moviebrowser.info_videoformat Picture +moviebrowser.menu_directories_head Paths +moviebrowser.menu_help_head Help +moviebrowser.menu_main_bookmarks Bookmarks +moviebrowser.menu_main_head Settings +moviebrowser.menu_main_movieinfo Movie info +moviebrowser.menu_main_saveandback save and back +moviebrowser.menu_nfs_head NFS settings +moviebrowser.menu_parental_lock_activated activated +moviebrowser.menu_parental_lock_activated_no no +moviebrowser.menu_parental_lock_activated_yes yes +moviebrowser.menu_parental_lock_activated_no_temp no (temporary) +moviebrowser.menu_parental_lock_head Parental Lock +moviebrowser.menu_parental_lock_rate_head Lock movies from +moviebrowser.scan_for_movies Scan for Movies ... +moviebrowser.serie_existingname Existing series +moviebrowser.serie_head Serie +moviebrowser.serie_name Change name +moviebrowser.short_audio Audio +moviebrowser.short_book Book +moviebrowser.short_channel Channel +moviebrowser.short_country Country +moviebrowser.short_filename Name +moviebrowser.short_format Format +moviebrowser.short_genre_major Genre +moviebrowser.short_genre_minor Genre +moviebrowser.short_info1 Info 1 +moviebrowser.short_info2 Info 2 +moviebrowser.short_length Min +moviebrowser.short_parental_lockage Age +moviebrowser.short_path Path +moviebrowser.short_prevplaydate Last +moviebrowser.short_prodyear Year +moviebrowser.short_quality * (quality) +moviebrowser.short_recorddate Date +moviebrowser.short_serie Serie +moviebrowser.short_size MB +moviebrowser.short_title Title +moviebrowser.start_head Start movie from: +moviebrowser.start_record_start Movie start +options.on.without_messages Without msg +extra.zapit_scan_sdt Scan SDT for updates +extra.zapit_sdt_changed Channels changed, reload settings. +miscsettings.virtual_zap_mode Virtual zap +miscsettings.epg_head Epg settings +miscsettings.epg_cache_days EPG-Cache (days) +miscsettings.epg_old_hours Events old after (hours) +miscsettings.epg_dir Dir for epg cache +miscsettings.epg_save Save/Restore epg on reboot +shutdown.recoding_query Box in record mode, you really want to shutdown ? +recordingmenu.apids default audio streams +recordingmenu.apids_ac3 record AC3 streams +recordingmenu.apids_alt record alternative streams +recordingmenu.apids_std record standard stream +recordingmenu.stream_pmt_pid record PMT +recordingmenu.zap_on_announce zap on recording announce +timerlist.apids_dflt record default audio streams +videomenu.osd OSD +videomenu.tv-scart TV Scart +videomenu.vcr-scart VCR Scart +videomenu.vcrsignal VCR Output Signal Type +videomenu.vcrsignal_composite CVBS +videomenu.vcrsignal_svideo S-Video +moviebrowser.option_browser Browser Options +moviebrowser.book_clear_all Clear all +moviebrowser.menu_save Save changes +moviebrowser.menu_save_all Start update of movie info files +moviebrowser.info_head_update Save changes in all movie info files +moviebrowser.update_if_dest_empty_only Copy if destination is empty only +moviebrowser.serie_auto_create Serie auto create +moviebrowser.load_default Load default settings +moviebrowser.browser_row_head Row settings +moviebrowser.browser_row_nr Number of rows +moviebrowser.browser_row_item Row item +moviebrowser.browser_row_width Row width +moviebrowser.reload_at_start Reload movie info at start +moviebrowser.remount_at_start Remount at start +moviebrowser.dir_head Additional paths +moviebrowser.dir Path +moviebrowser.use_dir Use directory +moviebrowser.use_rec_dir Use record directory +moviebrowser.use_movie_dir Use movie directory +moviebrowser.hide_series Hide series +moviebrowser.last_record_max_items Number of lines last record +moviebrowser.last_play_max_items Number of lines last play +moviebrowser.browser_frame_high Browser hight [Pixel] +extra.auto_timeshift Auto-record, sec (0 = disable) +extra.auto_delete Auto-delete +extra.auto_to_record Move timeshift to records +extra.record_time Fast/timeshift record time(hours) diff --git a/data/locale/italiano.locale b/data/locale/italiano.locale new file mode 100644 index 000000000..3bd4a0937 --- /dev/null +++ b/data/locale/italiano.locale @@ -0,0 +1,1237 @@ +EPGMenu.epgplus Lista Programmi +EPGMenu.eventinfo Dettagli programma corrente +EPGMenu.eventlist Lista programmi canale corrente +EPGMenu.head EPG - Informazioni programmi (EPG Plus) +EPGMenu.streaminfo informazioni tecniche +EPGPlus.actions Azioni +EPGPlus.bybouquet_mode per bouquet +EPGPlus.bypage_mode per pagina +EPGPlus.change_font_size dimensioni caratteri +EPGPlus.change_font_style stile caratteri +EPGPlus.change_size dimensioni +EPGPlus.channelentry_font caratteri dei canali +EPGPlus.channelentry_separationlineheight separazione linea superiore +EPGPlus.channelentry_width width +EPGPlus.channelevententry_font event font +EPGPlus.edit_fonts edita caratteri +EPGPlus.edit_sizes edita dimensioni +EPGPlus.font_style_bold style bold +EPGPlus.font_style_italic style italic +EPGPlus.font_style_regular style regular +EPGPlus.footer_fontbouquetchannelname footer bouquet +EPGPlus.footer_fontbuttons footer buttons +EPGPlus.footer_fonteventdescription footer event +EPGPlus.footer_fonteventshortdescription footer event short +EPGPlus.head Informazioni programmi (EPG Plus) +EPGPlus.header_font header dei caratteri +EPGPlus.horgap1_height height1 +EPGPlus.horgap2_height height2 +EPGPlus.next_bouquet bouquet succes. +EPGPlus.options opzioni +EPGPlus.page_down pagina in basso +EPGPlus.page_up pagina in alto +EPGPlus.prev_bouquet bouquet preced. +EPGPlus.record Registrare +EPGPlus.refresh_epg Attualizzare +EPGPlus.remind Ricordare +EPGPlus.reset_settings reset settings +EPGPlus.save_settings salva settings +EPGPlus.scroll_mode Modo Scroll +EPGPlus.select_font_name font name +EPGPlus.settings Impostazioni +EPGPlus.slider_width slider width +EPGPlus.stretch_mode Stretch Mode +EPGPlus.swap_mode selezione +EPGPlus.timeline_fontdate font date +EPGPlus.timeline_fonttime font time +EPGPlus.vergap1_width width1 +EPGPlus.vergap2_width width2 +EPGPlus.view_mode visione +GENRE.ARTS.0 arte / cultura +GENRE.ARTS.1 performing arts +GENRE.ARTS.10 arte/cultura magazines +GENRE.ARTS.11 moda +GENRE.ARTS.2 fine arts +GENRE.ARTS.3 religione +GENRE.ARTS.4 cultura popolare/arti tradizionali +GENRE.ARTS.5 letteratura +GENRE.ARTS.6 film/cinema +GENRE.ARTS.7 cinema sperimentale/video +GENRE.ARTS.8 broadcasting/stampa +GENRE.ARTS.9 new media +GENRE.CHILDRENs_PROGRAMMES.0 ragazzi/ programmi per ragazzi +GENRE.CHILDRENs_PROGRAMMES.1 programmi ragazzi prescolarizzazione +GENRE.CHILDRENs_PROGRAMMES.2 intrattenimento 6 - 14 anni +GENRE.CHILDRENs_PROGRAMMES.3 intrattenimento adolescenti +GENRE.CHILDRENs_PROGRAMMES.4 informazione +GENRE.CHILDRENs_PROGRAMMES.5 cartoni animati +GENRE.DOCUS_MAGAZINES.0 documentari / magazine +GENRE.DOCUS_MAGAZINES.1 natura/animali +GENRE.DOCUS_MAGAZINES.2 scienze +GENRE.DOCUS_MAGAZINES.3 medicina/filosofia/psicologia +GENRE.DOCUS_MAGAZINES.4 viaggi/spedizioni +GENRE.DOCUS_MAGAZINES.5 sciene sociospirituali +GENRE.DOCUS_MAGAZINES.6 educazione +GENRE.DOCUS_MAGAZINES.7 lingue +GENRE.MOVIE.0 film tv/drammi +GENRE.MOVIE.1 thriller +GENRE.MOVIE.2 avventura/western/guerra +GENRE.MOVIE.3 fantascienza +GENRE.MOVIE.4 commedia +GENRE.MOVIE.5 melodrammi +GENRE.MOVIE.6 romantici +GENRE.MOVIE.7 classici +GENRE.MOVIE.8 film per adulti +GENRE.MUSIC_DANCE.0 musica/danza/balletto +GENRE.MUSIC_DANCE.1 rock/pop +GENRE.MUSIC_DANCE.2 classica +GENRE.MUSIC_DANCE.3 musica folcloristica +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musical/opera +GENRE.MUSIC_DANCE.6 balletto +GENRE.NEWS.0 news +GENRE.NEWS.1 news/weather report +GENRE.NEWS.2 news magazine +GENRE.NEWS.3 documentari +GENRE.NEWS.4 discussioni/interviste/dibattiti +GENRE.SHOW.0 Show / Gameshow +GENRE.SHOW.1 game show/quiz/contest +GENRE.SHOW.2 variet +GENRE.SHOW.3 talk show +GENRE.SOCIAL_POLITICAL.0 social & politic events / business +GENRE.SOCIAL_POLITICAL.1 magazines/reports/documentary +GENRE.SOCIAL_POLITICAL.2 economics/social advisory +GENRE.SOCIAL_POLITICAL.3 remarkable people +GENRE.SPORTS.0 sport +GENRE.SPORTS.1 eventi speciali (Giochi olimpici,Campionati del mondo etc.) +GENRE.SPORTS.10 equitazione +GENRE.SPORTS.11 sport combattimento +GENRE.SPORTS.2 sports magazines +GENRE.SPORTS.3 calcio/footeball americano +GENRE.SPORTS.4 tennis/squash +GENRE.SPORTS.5 sport di squadra (eccetto il calcio) +GENRE.SPORTS.6 atletica +GENRE.SPORTS.7 sports motoristici +GENRE.SPORTS.8 sports acquatici +GENRE.SPORTS.9 winter sports +GENRE.TRAVEL_HOBBIES.0 viaggi e ricreazione +GENRE.TRAVEL_HOBBIES.1 turismo/viaggi +GENRE.TRAVEL_HOBBIES.2 handicraft +GENRE.TRAVEL_HOBBIES.3 motoring +GENRE.TRAVEL_HOBBIES.4 fitness & health +GENRE.TRAVEL_HOBBIES.5 cucina +GENRE.TRAVEL_HOBBIES.6 shopping +GENRE.TRAVEL_HOBBIES.7 giardinaggio +GENRE.UNKNOWN sconosciuto +apids.hint_1 Inserisci APIDs +apids.hint_2 in hex notation seperated by ' ' +apidselector.head Seleziona la lingua +audiomenu.PCMOffset Diminuisci il Volume PCM +audiomenu.analogout Uscita Analogica +audiomenu.avs avs +audiomenu.avs_control Volume Control avs/ost +audiomenu.dolbydigital Dolby Digital +audiomenu.head Audio Settings +audiomenu.lirc lirc +audiomenu.monoleft mono sinistro +audiomenu.monoright mono destro +audiomenu.ost ost +audiomenu.stereo stereo +audioplayer.add aggiungi +audioplayer.artist_title Artista, Titolo +audioplayer.building_search_index building search index +audioplayer.button_select_title_by_id search by ID +audioplayer.button_select_title_by_name search by name +audioplayer.defdir Start-Directory. +audioplayer.delete rimuovi +audioplayer.deleteall Cancella tutti +audioplayer.display_order Visore +audioplayer.enable_sc_metadata enable shoutcast meta data parsing +audioplayer.fastforward Avanti svelto +audioplayer.follow Selezionare Track attuale +audioplayer.head Audio Playlist +audioplayer.highprio High decode priority +audioplayer.id3scan leggo ID3-Tags +audioplayer.jump_backwards jump backwards +audioplayer.jump_dialog_hint1 Please enter jump target +audioplayer.jump_dialog_hint2 (relative, in seconds) +audioplayer.jump_dialog_title Enter jump target +audioplayer.jump_forwards jump forwards +audioplayer.keylevel Cambio-Tasti +audioplayer.name Audioplayer +audioplayer.pause Pausa +audioplayer.play play +audioplayer.playing Brano attuale +audioplayer.playlist_fileerror_msg File could not be created: +audioplayer.playlist_fileerror_title Errore +audioplayer.playlist_fileoverwrite_msg Vuoi sovrascrivere questo file: +audioplayer.playlist_fileoverwrite_title Sovrascrivere? +audioplayer.playlist_name filename of the play list +audioplayer.playlist_name_hint1 Please enter the filename of the playlist +audioplayer.playlist_name_hint2 The extension .m3u will be added automatically +audioplayer.reading_files reading files +audioplayer.repeat_on enable repeat mode +audioplayer.rewind Indietro svelto +audioplayer.save_playlist save play list +audioplayer.select_title_by_name search title by name (SMS) +audioplayer.screensaver_timeout Salvaschermo_Timeout +audioplayer.show_playlist Show Playlist +audioplayer.shuffle shuffle +audioplayer.stop stop +audioplayer.title_artist Titolo, Artista +audioplayerpicsettings.general audioplayer / picviewer +bookmarkmanager.delete cancella +bookmarkmanager.name bookmarks +bookmarkmanager.rename cambia nome +bookmarkmanager.select seleziona +bouqueteditor.add Aggiungi +bouqueteditor.bouquetname Nome del bouquets +bouqueteditor.delete Cancella +bouqueteditor.discardingchanges Non salvare i cambiamenti. Attendi .. +bouqueteditor.hide Nascondi +bouqueteditor.lock Blocca +bouqueteditor.move Sposta +bouqueteditor.name gestione bouquets +bouqueteditor.newbouquetname Nuovo nome del bouquets +bouqueteditor.rename Rinomina +bouqueteditor.return terminato +bouqueteditor.savechanges? vuoi salvare le modifiche? +bouqueteditor.savingchanges Salva le modifiche.Attendi ... +bouqueteditor.switch aggiungere/rimuovere +bouqueteditor.switchmode TV/Radio +bouquetlist.head Bouquets +cablesetup.provider providers via cavo +channellist.head Tutti i canali +channellist.nonefound Non ci sono canali!\n\nEseguire una Scansione\n(DBOX-Tasto -> Servizio) +channellist.since since %02d:%02d +colorchooser.alpha alpha +colorchooser.blue blu +colorchooser.green verde +colorchooser.red rosso +colormenu.background Colori di fondo +colormenu.fade Fader +colormenu.font Dimensioni dei caratteri +colormenu.gtx_alpha Transparenza (GTX) +colormenu.head Impostazioni dei colori +colormenu.menucolors Colori Menu +colormenu.statusbar Barra d'informazione +colormenu.textcolor Colori Testo +colormenu.themeselect seleziona tema +colormenu.timing OSD Timing +colormenusetup.head Colori Menu +colormenusetup.menucontent Contenuto Menu +colormenusetup.menucontent_inactive Contenuto Menu disattivato +colormenusetup.menucontent_selected Contenuto Menu attivato +colormenusetup.menuhead Menu Header +colorstatusbar.head Barra d'informazione +colorstatusbar.text Barra d'informazione +colorthememenu.classic_theme Tema Classico +colorthememenu.dblue_theme Tema nerazzurro +colorthememenu.dvb2k_theme DVB2000 Tema +colorthememenu.head Seleziona tema +colorthememenu.neutrino_theme Tema Neutrino +date.Apr Apr +date.Aug Ago +date.Dec Dic +date.Feb Feb +date.Fri Ven +date.Jan Gen +date.Jul Lug +date.Jun Giu +date.Mar Mar +date.May Mag +date.Mon Lun +date.Nov Nov +date.Oct Ott +date.Sat Sab +date.Sep Set +date.Sun Dom +date.Thu Gio +date.Tue Mar +date.Wed Mer +epglist.head Lista programmi - %s +epglist.noevents nessuna informazione EPG... +epgviewer.More_Screenings Programmi successivi su questo canale +epgviewer.nodetailed Nessuna informazione dettagliata +epgviewer.notfound Epg non presente +eventlistbar.channelswitch schedule +eventlistbar.eventsort esci +eventlistbar.recordevent registra +favorites.addchannel Questo canale sara aggiunto al Bouquet \n\n"Miei Favoriti" . \nOperazione necessita di un po di tempo..attendere +favorites.bouquetname Miei Favoriti +favorites.bqcreated Bouquet "Miei Favoriti" e stato creato...\n +favorites.chadded Il Canale attuale e stato aggiunto nei Favoriti...\n +favorites.chalreadyinbq Il Canale attuale e gia fra i Favoriti...\n +favorites.finalhint \nUsa bouqueteditor per modificare i favoriti.\n +favorites.menueadd aggiungi canale nei favoriti +favorites.nobouquets I favoriti sono selezionabili solo fra i bouquets attivi +filebrowser.delete Cancella +filebrowser.denydirectoryleave Absolute start directory +filebrowser.dodelete1 Cancella +filebrowser.dodelete2 ? +filebrowser.filter.active Filtro Attivo +filebrowser.filter.inactive Filtro Disattivo +filebrowser.head Filebrowser +filebrowser.mark seleziona +filebrowser.nextpage Pagina successiva +filebrowser.prevpage Pagina precedente +filebrowser.scan cerca nelle cartelle +filebrowser.select Seleziona +filebrowser.showrights Caratteristiche del file +filebrowser.sort.date (data) +filebrowser.sort.name (nome del file) +filebrowser.sort.namedirsfirst (nome del file2) +filebrowser.sort.size (Grandezza) +filebrowser.sort.type (tipo) +flashupdate.actionreadflash leggo flash +flashupdate.cantopenfile impossibile aprire il file +flashupdate.cantopenmtd impossibile aprire mtd-device +flashupdate.checkupdate ricerca nuove versioni +flashupdate.currentreleasecycle Release cycle +flashupdate.currentversion_sep Versione installata +flashupdate.currentversiondate Data +flashupdate.currentversionsnapshot ImagineTipo +flashupdate.currentversiontime Orario +flashupdate.erasefailed cancellazione flash fallita +flashupdate.erasing cancella flash +flashupdate.experimentalimage hai scelto un firmware sperimentale non testato +flashupdate.expertfunctions funzioni avanzate +flashupdate.fileis0bytes la dimensione del file e 0 Bytes +flashupdate.fileselector Seleziona file +flashupdate.flashreadyreboot immagine installata con successo il ruDbox si riavvia +flashupdate.getinfofile Carica Info Versione +flashupdate.getinfofileerror impossibile caricare info versione +flashupdate.getupdatefile carica aggiornamento +flashupdate.getupdatefileerror impossibile caricare aggiornamento +flashupdate.globalprogress Stato del sistema: +flashupdate.head Aggiornamento Software +flashupdate.md5check controllo immagine +flashupdate.md5sumerror immagine contiene errori +flashupdate.msgbox Sono state trovate queste file:\nDate: %s, %s\nBaseImage: %s\nType: %s\n\nDo you want to download and install this version now? +flashupdate.msgbox_manual Trovata una nuova img:\nDate: %s, %s\nBaseImage: %s\nImageType: %s\n\nDo you want to install this version now? +flashupdate.mtdselector Scelta della partizione +flashupdate.programmingflash programma flash +flashupdate.proxypassword Password +flashupdate.proxypassword_hint1 inserisci la password del server proxy +flashupdate.proxypassword_hint2 a empty entry means no proxy +flashupdate.proxyserver Nome del proxy +flashupdate.proxyserver_hint1 inserisci nome del proxy o IP, usa host:port +flashupdate.proxyserver_hint2 nessun nome inserito no proxy +flashupdate.proxyserver_sep Proxyserver +flashupdate.proxyusername Username +flashupdate.proxyusername_hint1 iserisci proxyserver username +flashupdate.proxyusername_hint2 nessun nome inserito nessuna identificazione +flashupdate.readflash Leggi tutta img su flash +flashupdate.readflashmtd leggi singole parti +flashupdate.ready terminato +flashupdate.reallyflashmtd Vuoi veramente flashare il db?\n\in caso d'errore\nil ruDbox potr non riavviarsi.\n\nImagename: %s\nTarget: %s +flashupdate.savesuccess L'immagine stata salvata con successo con\nquesto nome %s. +flashupdate.selectimage Immagini/Files disponibili +flashupdate.squashfs.noversion SquashFS version checks are currently only supported when updating over the web.\nAre you sure that you wish to install this image? +flashupdate.titlereadflash Leggi Flash +flashupdate.titlewriteflash Scrivi Flash +flashupdate.updatemode Modalita aggiornamento +flashupdate.updatemode_internet internet +flashupdate.updatemode_manual manuale (ftp) +flashupdate.url_file configurazione +flashupdate.versioncheck controlla versione +flashupdate.writeflash Scrivi l immagine completa +flashupdate.writeflashmtd Scrivi singole parti +flashupdate.wrongbase flashupdate.wrongbase Your Release cycle differs.\nTo continue? +fontmenu.channellist Lista Canali +fontmenu.epg Titolo EPG +fontmenu.eventlist Lista programmi +fontmenu.gamelist Lista giochi +fontmenu.head Impostazioni dei caratteri +fontmenu.infobar Barra d informazione +fontsize.channel_num_zap selezione diretta +fontsize.channellist Lista Canali +fontsize.channellist_descr Descrizione +fontsize.channellist_number Numero +fontsize.epg_date EPG Data +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title Titolo EPG +fontsize.eventlist_datetime lista programmi data / ora +fontsize.eventlist_itemlarge larga +fontsize.eventlist_itemsmall stretta +fontsize.eventlist_title Lista eventi +fontsize.filebrowser_item vedi filebrowser +fontsize.gamelist_itemlarge largo +fontsize.gamelist_itemsmall piccolo +fontsize.hint Inizializzazione caratteri,\nattendere... +fontsize.infobar_channame Nome dei canali +fontsize.infobar_info informazioni barra d informazione +fontsize.infobar_number Numeri barra d informazione +fontsize.infobar_small piccolo +fontsize.menu testo menu +fontsize.menu_info Menu Info +fontsize.menu_title Titolo menu +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.epgnotload EPG non caricata.... +infoviewer.epgwait attendi per EPG... +infoviewer.eventlist Lista programmi +infoviewer.languages Audio +infoviewer.motor_moving Posizionamento antenna +infoviewer.nocurrent Non disponibili informazioni su questo programma +infoviewer.noepg EPG non presente +infoviewer.notavailable Canale non presente +infoviewer.selecttime Orario di inizio +infoviewer.streaminfo Informazioni +infoviewer.subservice Sottoservizi +infoviewer.waittime Attendo orario... +ipsetup.hint_1 Usare il 0..9 per Alto/Basso +ipsetup.hint_2 OK salva, HOME indietro +keybindingmenu.RC Telecomando +keybindingmenu.addrecord Aggiungi-Timer di Registrazione +keybindingmenu.addremind Aggiungi-Timer per cambio canale +keybindingmenu.allchannels_on_ok Lista canali +keybindingmenu.bouquetchannels_on_ok Bouquet-Canali +keybindingmenu.bouquetdown bouquet precedente +keybindingmenu.bouquethandling Tasto-OK-per +keybindingmenu.bouquetlist_on_ok Lista Bouquet +keybindingmenu.bouquetup bouquet successivo +keybindingmenu.cancel chiudi lista canali +keybindingmenu.channeldown canale in basso +keybindingmenu.channellist Lista Canali +keybindingmenu.channelup canale in alto +keybindingmenu.head Impostazione Tasti +keybindingmenu.lastchannel Quick Zap +keybindingmenu.modechange Modalita di cambio +keybindingmenu.pagedown pagina in basso +keybindingmenu.pageup pagina in alto +keybindingmenu.quickzap Cambio veloce +keybindingmenu.repeatblock Ritardo ripetizione +keybindingmenu.repeatblockgeneric Ritardo di ripetizione iniziale +keybindingmenu.sort cambia posti +keybindingmenu.subchanneldown sottocanale indietro +keybindingmenu.subchannelup sottocanale avanti +keybindingmenu.tvradiomode Modo TV/Radio +keybindingmenu.zaphistory Zapping History Bouquet +keychooser.head Impostazione nuovo Tasto +keychooser.text1 Premere il tasto +keychooser.text2 per interrompere aspettare +keychoosermenu.currentkey tasto attuale +keychoosermenu.setnew imposta nuovo tasto +keychoosermenu.setnone nessun tasto +languagesetup.head Impostazioni lingua +languagesetup.select Lingua +lcdcontroler.brightness luminosita normale +lcdcontroler.brightnessstandby luminosita Standby +lcdcontroler.contrast Contrasto +lcdcontroler.head Imostazioni LCD +lcdmenu.autodimm Auto dimm +lcdmenu.head LCD Settings +lcdmenu.inverse Inversione +lcdmenu.lcdcontroler Contrasto / Luminosita +lcdmenu.power Power +lcdmenu.statusline linea di stato +lcdmenu.statusline.both volume / tempo trascorso +lcdmenu.statusline.playtime tempo trascorso +lcdmenu.statusline.volume volume +mainmenu.audioplayer Audioplayer +mainmenu.games Giochi +mainmenu.head Menu Principale +mainmenu.movieplayer Movieplayer +mainmenu.pausesectionsd Leggi EPG +mainmenu.pictureviewer Lettore immagini +mainmenu.radiomode Modo-Radio +mainmenu.recording Registrazione +mainmenu.recording_start avvia +mainmenu.recording_stop interrompi +mainmenu.scartmode Entrata Scart +mainmenu.service Menu di servizio +mainmenu.settings Impostazioni +mainmenu.shutdown Spegnere +mainmenu.sleeptimer Timer spegnimento +mainmenu.tvmode Modo-TV +mainsettings.audio Audio +mainsettings.colors Colori / temi /caratteri +mainsettings.head Impostazioni +mainsettings.keybinding Impostazioni tasti +mainsettings.language Lingua +mainsettings.lcd Display LCD +mainsettings.misc Altre Impostazioni +mainsettings.network Network +mainsettings.recording Impostazioni di Registrazione +mainsettings.savesettingsnow Salva impostazioni +mainsettings.savesettingsnow_hint le impostazioni vengono salvate\nattendi... +mainsettings.streaming Movieplayer +mainsettings.video Video +menu.back indietro +messagebox.back Indietro +messagebox.cancel Cancella +messagebox.discard rifiuto i cambiamenti? +messagebox.error Errore +messagebox.info Informazioni +messagebox.no No +messagebox.yes Si +miscsettings.bootinfo Mostra informazioni all avvio +miscsettings.bootmenu Show boot menu +miscsettings.driver_boot driver and boot options +miscsettings.fb_destination Expert! Boot-Console +miscsettings.general Generale +miscsettings.head Altre impostazioni +miscsettings.hwsections use hardware sections +miscsettings.infobar_sat_display Satellite display on infobar +miscsettings.pmtupdate enable pmt update +miscsettings.shutdown_real Modo standby +miscsettings.shutdown_real_rcdelay spegnimento ritardato +miscsettings.sptsmode use spts mode +miscsettings.startbhdriver carica BH-Mode drivers +motorcontrol.head Impostazioni Motore +movieplayer.bookmark Bookmarks +movieplayer.bookmarkname Bookmarkname +movieplayer.bookmarkname_hint1 Inserire nome del nuovo bookmark +movieplayer.bookmarkname_hint2 +movieplayer.buffering Buffering... +movieplayer.defdir start dir. +movieplayer.dvdplayback DVD +movieplayer.fileplayback File via VLC +movieplayer.goto salta a ... +movieplayer.goto.h1 = -> salto assoluto +movieplayer.goto.h2 +,- -> salto relativo +movieplayer.head Movieplayer +movieplayer.nostreamingserver The streaming server could not be reached. +movieplayer.pesplayback Play PES (Experimental) +movieplayer.pleasewait Attendi.\nConnesiione al streaming server... +movieplayer.toomanybookmarks There are too many bookmarks.\nYou need to delete one of them first. +movieplayer.tsplayback Play TS +movieplayer.vcdplayback (S)VCD +movieplayer.wrongvlcversion This feature is not support by your current version of VLC +networkmenu.broadcast Broadcast +networkmenu.dhcp DHCP +networkmenu.gateway gateway predefinito +networkmenu.head Impostazioni Rete +networkmenu.ipaddress indirizzo IP +networkmenu.mount NFS/CIFS +networkmenu.nameserver name server +networkmenu.netmask netmask +networkmenu.setupnow attiva rete +networkmenu.setuponstartup attiva rete all avvio +networkmenu.show mostra impostazioni rete attive +networkmenu.test testa rete +nfs.alreadymounted directory gia caricata +nfs.automount carica all avvio +nfs.dir directory/share +nfs.ip NFS/CIFS Server IP +nfs.localdir cartella locale +nfs.mount Mount NFS/CIFS volume +nfs.mount_options opzioni di caricamento +nfs.mounterror mount error: carica impostazioni predefinite +nfs.mounterror_notsup tipo di filesystem non supportato +nfs.mountnow carica adesso +nfs.mounttimeout mount error: timeout +nfs.password CIFS password +nfs.remount ricarica directories +nfs.type tipo +nfs.type_cifs CIFS +nfs.type_nfs NFS +nfs.umount Umount NFS/CIFS volume +nfs.umounterror error scarica volume +nfs.username CIFS username +nfsmenu.head NFS/CIFS impostazioni +nvod.percentage (%d%% over) +nvod.starting (starting in %d min) +nvodselector.directormode Modo-diretto +nvodselector.head Seleziona orario inizio +nvodselector.subservice Seleziona sottoservizio +options.default Resetta alle impostazioni preimpostate +options.fb framebuffer +options.null null +options.off spento +options.on acceso +options.serial seriale +parentallock.changepin cambia codice parentale +parentallock.changepin_hint1 Inserisci il nuovo codice parentale! +parentallock.changetolocked bouquets bloccati +parentallock.head Inserisci codice parentale PIN code +parentallock.lockage blocca programmma +parentallock.lockage12 da 12 anni in su +parentallock.lockage16 da 16 anni in su +parentallock.lockage18 da 18 anni in su +parentallock.lockedchannel Locked sender... +parentallock.lockedprogram Programma bloccato (da %d anni in su) +parentallock.never mai +parentallock.onsignal blocco al segnale +parentallock.parentallock Blocco parentale +parentallock.prompt inserimento PIN +pictureviewer.defdir start dir. +pictureviewer.head Lettore immagini +pictureviewer.resize.color_average avanzate +pictureviewer.resize.none nessuno +pictureviewer.resize.simple semplice +pictureviewer.scaling ingrandimento +pictureviewer.show vedi +pictureviewer.slide_time durata sul display +pictureviewer.slideshow durata +pictureviewer.sortorder cambia ordine selezione +pictureviewer.sortorder.date (data) +pictureviewer.sortorder.filename (nomefile) +ping.ok irraggiungibile (ping) +ping.protocol irraggiungibile (host o protocollo errore) +ping.socket irraggiungibile (socket errore) +ping.unreachable irraggiungibile +pinprotection.head Inserisci PIN code +pinprotection.wrongcode PIN-Code sbagliato! Prova ancora. +rclock.lockmsg Blocco telecomando ruDbox.\n per sbloccarlo, premi \n e sul telecomando. +rclock.menueadd Blocca telecomando +rclock.title Blocco telecomando +rclock.unlockmsg Telecomando riattivato. +recordingmenu.defdir cartella di registrazione +recordingmenu.file diretta su hdd del db +recordingmenu.head Impostazioni di registrazione +recordingmenu.help Recording devices:\n--------------------------\nserver:\nusing streaming software on a PC\n\n(analog) vcr:\nusing the vcr outlet\n\ndirect (file):\ndirectly into an NFS mounted directory\nor onto an internal hard drive\nTS: use spts mode(dbox2)\nPES: do not use spts mode(dbox2)\n\n\nMax. file size:\n---------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: almost unlimited (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart non passare in modo-scart +recordingmenu.off spento +recordingmenu.recording_type modalita registrazione +recordingmenu.server server +recordingmenu.server_ip IP server di registrazione +recordingmenu.server_mac MAC address +recordingmenu.server_port porta server registrazione +recordingmenu.server_wakeup server registrazione WOL +recordingmenu.setupnow salva cambiamenti +recordingmenu.splitsize dimensione massima file (MB) +recordingmenu.stopplayback stop riproduzione +recordingmenu.stopsectionsd stop sectionsd +recordingmenu.stream_vtxt_pid record videotext +recordingmenu.use_o_sync write synchronous (O_SYNC) +recordingmenu.vcr vcr +recordtimer.announce Registrazione parte fra alcuni minuti +repeatblocker.hint_1 Shortest time (in ms) to recognize 2 keystrokes +repeatblocker.hint_2 Enter 0 to switch of the blocker (red is space) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-ripetizioni +satsetup.extended DiSEqC-Impostazioni +satsetup.extended_motor Motore-Impostazioni +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Impostazione manuale Motore +satsetup.nodiseqc no DiSEqC +satsetup.satellite Satellite +satsetup.savesettingsnow salva impostazioni +satsetup.smatvremote SMATV Tuning remoto +scants.actcable Cavo: +scants.actsatellite Satellite: +scants.bouquet Bouquet +scants.bouquet_create crea nuovi +scants.bouquet_erase cancella tutti +scants.bouquet_leave non modificare +scants.bouquet_satellite bouquets satellite +scants.bouquet_update aggiorna +scants.channel Canali: +scants.failed Scansione transponder fallita! +scants.finished Scansione transponder terminata con successo! +scants.freqdata Frequenza: +scants.head Scansiona transponder +scants.numberofdataservices Dati +scants.numberofradioservices Radio +scants.numberoftotalservices Totali +scants.numberoftvservices TV +scants.provider Provider: +scants.startnow inizia scansione +scants.transponders Transponders: +screensetup.lowerright verde = margine basso destro +screensetup.upperleft rosso = margine alto sinistro +servicemenu.head Menu di servizio +servicemenu.reload Ricarica Lista Canali +servicemenu.reload_hint Ricarica Lista Canali,\nattendi... +servicemenu.scants Scansione canali +servicemenu.ucodecheck Check ucodes +servicemenu.update Aggiornamento Software +settings.help Help +settings.missingoptionsconffile le impostazioni di neutrino sono state aggiornate.\nNuove impostazioni settate come predefinite. +settings.noconffile No neutrino-impostazioni.\nUsing defaults. +shutdowntimer.announce ruDBox will spento in 1 min.\nCancello Spegnimento ? +sleeptimerbox.announce Sleeptimer in 1 min +sleeptimerbox.hint1 Orario di spegnimento in min. (000=off) +sleeptimerbox.hint2 ruDbox si spegne trascorso questo tempo. +sleeptimerbox.title Timer spegnimento +streamfeatures.head Caratteristiche +streaminfo.aratio Formato +streaminfo.aratio_unknown Formato: sconosciuto +streaminfo.audiotype Tipo di audio +streaminfo.audiotype_unknown Tipo di audio: sconosciuto +streaminfo.bitrate Bitrate +streaminfo.framerate Framerate +streaminfo.framerate_unknown Framerate: sconosciuto +streaminfo.head Informazioni Stream +streaminfo.not_available non disponibili +streaminfo.resolution Risoluzione +streaminfo.signal receipt signal +streaming.buffer_overflow The recording was aborted,\nsince the data could not be written fast enough. +streaming.busy One or several recording processes are active.\nIf you encounter this message and no recording is active, please restart Neutrino. +streaming.dir_not_writable The recording directory is not writable.\nRecording will not work. +streaming.success The recording has ended successfully. +streaming.write_error The recording was aborted,\nsince an error occured during the writing process. +streaming.write_error_open The recording was aborted,\nbecause the target file could not be opened. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Movieplayer Settings +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Spento +streamingmenu.on Acceso +streamingmenu.server_ip Streamingserver IP +streamingmenu.server_port Streamingserver Porta +streamingmenu.streaming_audiorate Datarate Audio +streamingmenu.streaming_force_avi_rawaudio Force AC3 for AVI +streamingmenu.streaming_force_transcode_video Transcodifica MPG/VCD video +streamingmenu.streaming_resolution Risoluzione +streamingmenu.streaming_server_cddrive DVD Drive +streamingmenu.streaming_server_startdir Directory (VLC) +streamingmenu.streaming_transcode_audio Transcodifica audio (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec MPEG video codec +streamingmenu.streaming_type Streamingserver +streamingmenu.streaming_videorate Datarate Video +streamingserver.noconnect Nessuna connessione con streamingserver.\nRegistrazione cancellata. +stringinput.caps caps / no caps +stringinput.clear cancella tutto +timer.eventrecord.msg ... TO be DONE, or not to be done +timer.eventrecord.title Schedule Record +timer.eventtimed.msg The event is scheduled.\nThe ruDbox will power on and \nswitch to this channel at the given time. +timer.eventtimed.title Schedule Event +timerbar.channelswitch Schedule +timerbar.recordevent Record +timerlist.alarmtime Alarm time +timerlist.apids Audio PIDs +timerlist.bouquetselect scegli bouquet +timerlist.channel Canale +timerlist.channelselect scegli canale +timerlist.delete Cancella +timerlist.menumodify Modifica timer registrazione +timerlist.menunew Nuovo timer +timerlist.message Messaggi +timerlist.moderadio Canali radio +timerlist.modeselect Modo di selezione +timerlist.modetv Canali TV +timerlist.modify Modifica +timerlist.name lista Timer +timerlist.new Nuovo timer +timerlist.program.unknown Programma sconosciuto +timerlist.reload Riprendi +timerlist.repeat Ripeti +timerlist.repeat.biweekly 2 volte a settimana +timerlist.repeat.byeventdescription vedi timer +timerlist.repeat.daily giornaliera +timerlist.repeat.fourweekly 4 volte a settimana +timerlist.repeat.friday Venerdi +timerlist.repeat.monday Lunedi +timerlist.repeat.monthly Ogni Mese +timerlist.repeat.once una sola volta +timerlist.repeat.saturday Sabato +timerlist.repeat.sunday Domenica +timerlist.repeat.thursday Giovedi +timerlist.repeat.tuesday Maredi +timerlist.repeat.unknown sconoscito +timerlist.repeat.wednesday Mercoledi +timerlist.repeat.weekdays ad inizio Settimana +timerlist.repeat.weekly settimanalmente +timerlist.save Salva +timerlist.standby Standby +timerlist.standby.off Poni db in standby +timerlist.standby.on Riaccendi da standby +timerlist.stoptime Orario per fermarsi +timerlist.type Tipo di Timer +timerlist.type.nextprogram Programma successsivo +timerlist.type.record Registrazione +timerlist.type.remind Ricordami +timerlist.type.shutdown Spegnere +timerlist.type.sleeptimer Sleeptimer +timerlist.type.standby Standby +timerlist.type.unknown Sconosciuto +timerlist.type.zapto Cambia +timerlist.weekdays Giorni della settimana +timerlist.weekdays.hint_1 LU MA ME GI VE SA DO +timerlist.weekdays.hint_2 'X'=timer '-' nessun timer +timersettings.record_safety_time_after Correzione fine registrazione +timersettings.record_safety_time_after.hint_1 Correzione in min. (00=off). This time +timersettings.record_safety_time_after.hint_2 che vengono aggiunti. +timersettings.record_safety_time_before Correzione inizio registrazione +timersettings.record_safety_time_before.hint_1 Correzione in min. (00=off). This time +timersettings.record_safety_time_before.hint_2 Che vengono tolti al Timer. +timersettings.separator Impostazione Timer +timing.chanlist Lista Canali +timing.epg Epg +timing.filebrowser Filebrowser +timing.head OSD Timeouts +timing.hint_1 Tempo in sec in cui OSD appare +timing.hint_2 sullo schermo. +timing.infobar Barra Informazione +timing.menu Menu +timing.numericzap Numeric Zap +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head UCode controllo +ucodecheck.ucode UCode +ucodes.failure ATTENTION, µCodes non trovati!\n\nCaricali via FTP ,\npoi riavvia ruDbox! +videomenu.csync correzione sync. +videomenu.head Impostazioni Video +videomenu.rgb_centering RGB-Posizionamento +videomenu.screensetup Impostazioni Margine Video +videomenu.vcrswitch Entrata-Scart automatica +videomenu.videoformat Formato +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect automatico +videomenu.videosignal Tipo di segnale Video +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce In un Minuto verra cambiato il Canale +extra.auto Auto +extra.valid Validi +extra.all Tutti +extra.new_keys New keys +extra.all_keys All keys +extra.vartmp /var/tmp +extra.varkeys /var/keys +extra.algo Algo pids +extra.gbox_emu Emu +extra.gbox_softcam Softcam +extra.gbox_net Network +extra.gbox_mix Mixed +extra.gbox_info Gbox Info +extra.sep_extra Extras +extra.save_settings Salva +extra.extra_menu Impostazioni Emu +extra.ecm_info Ecm Info +extra.pid_info Pid Info +extra.emm_info New Keys +extra.emu_type Emu Type +extra.camd Camd +extra.restart_camd Restart camd +extra.mg_settings Mgcamd settings +extra.netmode Netmode +extra.autoupdate Autoupdate +extra.show_ecm Show Ecm +extra.show_emm Show Emm +extra.keyupdate Key update +extra.osd OSD +extra.keyfolder Key dir +extra.hash_pids Hash pids +extra.gbox_settings Gbox Settings +extra.gbox_mode Mode +extra.newcamd_settings Newcamd Settings +extra.show_cw Show CW +extra.debug_ecm Debug Ecm +extra.disable_cam Disable CAM +extra.show_cat Show CAT +extra.show_pmt show PMT +extra.update_pmt Update PMT +extra.report_emm Report wrong EMM sig. +extra.debug_emm Debug Emm +extra.show_allca Show all ca sys. +extra.reload_keys Reload keys on zap +extra.reload_cfg Reload config on zap +extra.cw_delay Default CW delay +extra.dvbsnoop DVB Stream Info +extra.dvbsnoop_pat Show PAT +extra.dvbsnoop_cat Show CAT +extra.dvbsnoop_tsdt Show TSDT +extra.dvbsnoop_nit Show NIT +extra.dvbsnoop_sdt Show SDT +extra.dvbsnoop_eit Show EIT +extra.dvbsnoop_rst Show RST +extra.dvbsnoop_tdt Show TDT +extra.dvbsnoop_sit Show SIT +extra.dvbsnoop_pid Show manual PID +extra.dvbsnoop_scan Scan PIDs +extra.dvbsnoop_band Show pid bandwidth +extra.logview View Log +extra.ru ruDREAM +extra.english English +extra.dboxinfo Box Info +extra.scan_mode Scan mode +extra.start_tostandby Startup to standby +extra.rotor_swap Swap rotor east/west +extra.use_log Log to /tmp/log +extra.spts_mode SPTS mode +extra.hw_sect Hardware Sections +extra.logo Logo number +extra.scan_full Full +extra.scan_fast Fast +extra.hdd_slow Slow +extra.hdd_middle Middle +extra.hdd_fast Fast +extra.hdd_ext3 Ext3fs +extra.hdd_reiser Reiserfs +extra.hdd_1min 1 min. +extra.hdd_5min 5 min. +extra.hdd_10min 10 min. +extra.hdd_20min 20 min. +extra.hdd_30min 30 min. +extra.hdd_60min 60 min. +extra.logo1 1 +extra.logo2 2 +extra.logo3 3 +extra.hdd_sleep Sleep time +extra.hdd_noise Noise +extra.hdd_activate Activate settings +extra.hdd_fs Filesystem +extra.hdd_format Format HDD +extra.hdd_check Check filesystem +extra.hdd_settings HDD Settings +extra.clear_log Clear Log +extra.zap_cycle Zap cycle +extra.sms_channel sms-mode channel +extra.manual_scan Manual scan +extra.tp_freq Frequency +extra.tp_rate Symbol rate +extra.tp_pol Polarization +extra.tp.pol_v V +extra.tp_pol_h H +extra.tp_fec FEC +extra.fec_1_2 1/2 +extra.fec_2_3 2/3 +extra.fec_3_4 3/4 +extra.fec_5_6 5/6 +extra.fec_7_8 7/8 +extra.timezone Timezone +extra.zapit_menu Zapit options +extra.zapit_make_bouquet Make Remaining Channels list +extra.zapit_save_last_chan Save last channel +extra.zapit_motor_speed Motor moving speed (10 = 1deg/sec) +extra.zapit_fe_timeout Tune timeout +extra.add_to_bouquet Add to bouquet +extra.key_list_start home +extra.key_list_end end +extra.chadded The current channel has been added to selected bouquet....\n +extra.chalreadyinbq The current channel is already in selected bouquet....\n +extra.menu_left_exit "Left" = menu back +extra.zapit_write_names Write channel names +extra.update_dir Directory for updates +extra.cache Cache +extra.debug Debug +extra.zapit_backup Backup channels to /tmp +extra.zapit_delete Delete channels +extra.zapit_fast_zap fast zap +extra.zapit_restore Restore channels from /tmp +extra.zapit_sort_names Sort ch. by name +filesystem.is.utf8 file system +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +infoviewer.subchan_disp_pos Subchannel display +mainmenu.scripts Scripts +miscsettings.noaviawatchdog enable AVIA watchdog +miscsettings.noenxwatchdog enable eNX watchdog +movieplayer.defplugin Start-Plugin +movieplayer.tshelp1 Stop +movieplayer.tshelp10 approx. 10 minutes back +movieplayer.tshelp11 skip approx. 10 minutes +movieplayer.tshelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Select audio track +movieplayer.tshelp3 Pause/Continue +movieplayer.tshelp4 Create bookmark +movieplayer.tshelp5 Show progress +movieplayer.tshelp6 approx. 1 minute back +movieplayer.tshelp7 skip approx. 1 minute +movieplayer.tshelp8 approx. 5 minutes back +movieplayer.tshelp9 skip approx. 5 minutes +movieplayer.vlchelp1 Stop +movieplayer.vlchelp10 approx. 10 minutes back +movieplayer.vlchelp11 skip approx. 10 minutes +movieplayer.vlchelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Resync +movieplayer.vlchelp3 Pause/Continue +movieplayer.vlchelp4 Create bookmark +movieplayer.vlchelp5 Show progress +movieplayer.vlchelp6 approx. 1 minute back +movieplayer.vlchelp7 skip approx. 1 minute +movieplayer.vlchelp8 approx. 5 minutes back +movieplayer.vlchelp9 skip approx. 5 minutes +nfs.mountok mount successful +nfs.type_lufs FTPFS +pictureviewer.help1 menu mode +pictureviewer.help10 show mode +pictureviewer.help11 reread image +pictureviewer.help12 previous image +pictureviewer.help13 next image +pictureviewer.help14 Zoom out +pictureviewer.help15 Zoom in +pictureviewer.help16 scroll up +pictureviewer.help17 scroll left +pictureviewer.help18 scroll right +pictureviewer.help19 scroll down +pictureviewer.help2 display image +pictureviewer.help20 change sort order +pictureviewer.help21 reread image (no scaling) +pictureviewer.help22 exit +pictureviewer.help3 change sort order +pictureviewer.help4 do not scale picture +pictureviewer.help5 diashow mode +pictureviewer.help6 previous image +pictureviewer.help7 next image +pictureviewer.help8 change sort order +pictureviewer.help9 exit +plugins.result plugin output +recordingmenu.choose_direct_rec_dir choose dir on imm. recording +recordingmenu.epg_for_filename long filenames (with EPG data) +recordingmenu.filesettings direct recording settings +recordingmenu.ringbuffers no. of ringbuffers +recordingmenu.use_fdatasync write synchronous (fdatasync) +settings.pos_bottom_left bottom left +settings.pos_bottom_right bottom right +settings.pos_top_left oben top left +settings.pos_top_right oben top right +timerlist.plugin Plugin +timerlist.recording_dir recording directory +timerlist.repeatcount repeats +timerlist.repeatcount.help1 amount of timer repeats +timerlist.repeatcount.help2 0 for unlimited repeats +timerlist.type.execplugin Execute plugin +pictureviewer.decode_server_ip decode server ip +pictureviewer.decode_server_port decode server port +scants.abort_body Should the search really be aborted? +scants.abort_header Abortion of channel scan +recordingmenu.record_in_spts_mode switch to spts mode before recording +servicemenu.getplugins Reload plugins +servicemenu.getplugins_hint Reloading plugins,\nplease be patient. +zapit.scantype scan for services +zapit.scantype.all all services +zapit.scantype.radio only radio +zapit.scantype.tv only tv +zapit.scantype.tvradio tv & radio +colorthememenu.red_theme Simply Red +lcdmenu.dim_brightness Brightness after dim timeout +lcdmenu.dim_time Dim timeout +timerlist.overlapping_timer Timer conflict. Create the timer anyway? +extra.audio_run_player Audio key start player +mpkey.rewind Rewind +mpkey.forward Forward +mpkey.pause Pause +mpkey.stop Stop +mpkey.play Play +mpkey.audio Audio track +mpkey.time Show time +mpkey.bookmark save bookmark +mpkey.plugin Run plugin +extra.key_click Key click +extra.loadcolors Load colors from +extra.savecolors Save colors as +extra.loadkeys Load keys from +extra.savekeys Save keys as +extra.loadconfig Load settings from +extra.saveconfig Save settings as +videomenu.videomode Video system +videomenu.videomode_ntsc NTSC +videomenu.videomode_pal PAL +videomenu.videomode_palm PAL-M +extra.key_timeshift Timeshift +extra.key_plugin One touch plugin +extra.timeshift_pause Timeshift pause +rfmod.rfmod RF modulator +rfmod.carrier Subcarrier Frequency +rfmod.carrier4500 4.5 +rfmod.carrier5500 5.5 +rfmod.carrier6000 6.0 +rfmod.carrier6500 6.5 +rfmod.enable Enable sound +rfmod.channel Channel +rfmod.finetune Fine tune +rfmod.standby Enable modulator +rfmod.test Test pattern +extra.zapit_scanpids Scan/Use pids +extra.zapit_rezap_time Re-Zap on emu switch time +extra.zapit_hvoltage High (13.5/18.5) voltage +extra.key_unlock Unlock key +extra.mg_netoptions Network options +extra.mg_ecm_timeout Network ecm timeout +extra.mg_reconnect Shares reconnect +extra.mg_priority Share priority +extra.mg_osd_options Osd options +extra.mg_reread Reread files on zap +servicemenu.imageinfo Image info +imageinfo.creator Creator: +imageinfo.date Date: +imageinfo.dokumentation Docs: +imageinfo.forum Forum: +imageinfo.head Image info: +imageinfo.homepage Home page: +imageinfo.image Image: +imageinfo.license License: +imageinfo.version Version: +extra.cache_txt Cache teletext +extra.use_gotoxx Use gotoXX +extra.latitude Latitude +extra.longitude Longitude +extra.ladirection LaDirection +extra.lodirection LoDirection +extra.south South +extra.north North +extra.east East +extra.west West +epgextended.actors Actors +epgextended.director Director +epgextended.guests Guests +epgextended.original_title Original Title +epgextended.presenter Presenter +epgextended.year_of_production Year of Production +recordingmenu.save_in_channeldir Save in channel dir +servicemenu.restart Soft restart +servicemenu.restart_failed Restart failed +servicemenu.restart_hint Restarting, please wait +servicemenu.restart_refused_recording Cant restart, recording in progress +extra.cs Cardserver +extra.restart_cs Restart cardserver +extra.tp_mod Modulation +extra.tp_mod_16 QAM/16 +extra.tp_mod_32 QAM/32 +extra.tp_mod_64 QAM/64 +extra.tp_mod_128 QAM/128 +extra.tp_mod_256 QAM/256 +moviebrowser.book_head Bookmarks +moviebrowser.book_lastmoviestop Last play stop: +moviebrowser.book_movieend Movie end: +moviebrowser.book_moviestart Movie start: +moviebrowser.book_name Name: +moviebrowser.book_new New Bookmark +moviebrowser.book_position Position: +moviebrowser.book_type Jump (<0 back , >0 for): +moviebrowser.book_type_backward Repeat +moviebrowser.book_type_forward jump over +moviebrowser.edit_book Bookmark change +moviebrowser.edit_book_name_info1 Enter new Bookmark name +moviebrowser.edit_book_name_info2 +moviebrowser.edit_book_pos_info1 Enter new Position (s) +moviebrowser.edit_book_pos_info2 +moviebrowser.edit_book_type_info1 Enter new jump length (s) +moviebrowser.edit_book_type_info2 <0 back , >0 for, 0: none +moviebrowser.edit_serie Enter name of serie +moviebrowser.error_no_movies No movies found +moviebrowser.foot_filter Filter: +moviebrowser.foot_play Start movie +moviebrowser.foot_sort Sort: +moviebrowser.head TS MovieBrowser +moviebrowser.head_filter Filter movies by category: +moviebrowser.head_playlist Last played: +moviebrowser.head_recordlist Last recorded: +moviebrowser.hint_jumpbackward Jump back in 5 s\n '0' to cancel +moviebrowser.hint_jumpforward Jump forward in 5 s\n '0' to cancel +moviebrowser.hint_movieend Filmende in 5 s\n '0' zum weitersehen +moviebrowser.hint_newbook_backward New jump back\n 'blue' for endposition +moviebrowser.hint_newbook_forward New jump forward\n 'blue' for endposition +moviebrowser.info_audio Audio +moviebrowser.info_channel Channel +moviebrowser.info_filename Name +moviebrowser.info_genre_major Genre +moviebrowser.info_genre_minor Genre +moviebrowser.info_head Film Informationen +moviebrowser.info_info1 Info 1 +moviebrowser.info_info2 Info 2 +moviebrowser.info_length Length (Min) +moviebrowser.info_parental_lockage Parental Lock age +moviebrowser.info_parental_lockage_0year always +moviebrowser.info_parental_lockage_12year 12 years +moviebrowser.info_parental_lockage_16year 16 years +moviebrowser.info_parental_lockage_18year 18 years +moviebrowser.info_parental_lockage_6year 6 years +moviebrowser.info_parental_lockage_always never +moviebrowser.info_path Path +moviebrowser.info_prevplaydate Last play date +moviebrowser.info_prodcountry Country +moviebrowser.info_prodyear Year +moviebrowser.info_quality Quality +moviebrowser.info_recorddate Record date +moviebrowser.info_serie Serie +moviebrowser.info_size File size (MB) +moviebrowser.info_title Titel +moviebrowser.info_videoformat Picture +moviebrowser.menu_directories_head Paths +moviebrowser.menu_help_head Help +moviebrowser.menu_main_bookmarks Bookmarks +moviebrowser.menu_main_head Settings +moviebrowser.menu_main_movieinfo Movie info +moviebrowser.menu_main_saveandback save and back +moviebrowser.menu_nfs_head NFS settings +moviebrowser.menu_parental_lock_activated activated +moviebrowser.menu_parental_lock_activated_no no +moviebrowser.menu_parental_lock_activated_yes yes +moviebrowser.menu_parental_lock_activated_no_temp no (temporary) +moviebrowser.menu_parental_lock_head Parental Lock +moviebrowser.menu_parental_lock_rate_head Lock movies from +moviebrowser.scan_for_movies Scan for Movies ... +moviebrowser.serie_existingname Existing series +moviebrowser.serie_head Serie +moviebrowser.serie_name Change name +moviebrowser.short_audio Audio +moviebrowser.short_book Book +moviebrowser.short_channel Channel +moviebrowser.short_country Country +moviebrowser.short_filename Name +moviebrowser.short_format Format +moviebrowser.short_genre_major Genre +moviebrowser.short_genre_minor Genre +moviebrowser.short_info1 Info 1 +moviebrowser.short_info2 Info 2 +moviebrowser.short_length Min +moviebrowser.short_parental_lockage Age +moviebrowser.short_path Path +moviebrowser.short_prevplaydate Last +moviebrowser.short_prodyear Year +moviebrowser.short_quality * (quality) +moviebrowser.short_recorddate Date +moviebrowser.short_serie Serie +moviebrowser.short_size MB +moviebrowser.short_title Title +moviebrowser.start_head Start movie from: +moviebrowser.start_record_start Movie start +options.on.without_messages Without msg +extra.zapit_scan_sdt Scan SDT for updates +extra.zapit_sdt_changed Channels changed, reload settings. +miscsettings.virtual_zap_mode Virtual zap +miscsettings.epg_head Epg settings +miscsettings.epg_cache_days EPG-Cache (days) +miscsettings.epg_old_hours Events old after (hours) +miscsettings.epg_dir Dir for epg cache +miscsettings.epg_save Save/Restore epg on reboot +shutdown.recoding_query Box in record mode, you really want to shutdown ? +recordingmenu.apids default audio streams +recordingmenu.apids_ac3 record AC3 streams +recordingmenu.apids_alt record alternative streams +recordingmenu.apids_std record standard stream +recordingmenu.stream_pmt_pid record PMT +recordingmenu.zap_on_announce zap on recording announce +timerlist.apids_dflt record default audio streams +videomenu.osd OSD +videomenu.tv-scart TV Scart +videomenu.vcr-scart VCR Scart +videomenu.vcrsignal VCR Output Signal Type +videomenu.vcrsignal_composite CVBS +videomenu.vcrsignal_svideo S-Video +moviebrowser.option_browser Browser Options +moviebrowser.book_clear_all Clear all +moviebrowser.menu_save Save changes +moviebrowser.menu_save_all Start update of movie info files +moviebrowser.info_head_update Save changes in all movie info files +moviebrowser.update_if_dest_empty_only Copy if destination is empty only +moviebrowser.serie_auto_create Serie auto create +moviebrowser.load_default Load default settings +moviebrowser.browser_row_head Row settings +moviebrowser.browser_row_nr Number of rows +moviebrowser.browser_row_item Row item +moviebrowser.browser_row_width Row width +moviebrowser.reload_at_start Reload movie info at start +moviebrowser.remount_at_start Remount at start +moviebrowser.dir_head Additional paths +moviebrowser.dir Path +moviebrowser.use_dir Use directory +moviebrowser.use_rec_dir Use record directory +moviebrowser.use_movie_dir Use movie directory +moviebrowser.hide_series Hide series +moviebrowser.last_record_max_items Number of lines last record +moviebrowser.last_play_max_items Number of lines last play +moviebrowser.browser_frame_high Browser hight [Pixel] +extra.auto_timeshift Auto-record, sec (0 = disable) +extra.auto_delete Auto-delete +extra.auto_to_record Move timeshift to records +extra.record_time Fast/timeshift record time(hours) diff --git a/data/locale/nederlands.locale b/data/locale/nederlands.locale new file mode 100644 index 000000000..b19d04ee0 --- /dev/null +++ b/data/locale/nederlands.locale @@ -0,0 +1,771 @@ +EPGMenu.epgplus Preview overzicht +EPGMenu.eventinfo Info over uitzending +EPGMenu.eventlist Preview programma +EPGMenu.head EPG - Programma Informatie +EPGMenu.streaminfo technische Informatie +EPGPlus.actions Aktie's +EPGPlus.change_font_size Fonttype veranderen +EPGPlus.change_font_style Fontstijl veranderen +EPGPlus.change_size Grootte veranderen +EPGPlus.channelentry_font Kanaal +EPGPlus.channelentry_separationlineheight Hoogteverschil tussen 2 kanaalnamen +EPGPlus.channelentry_width Breedte van de kanaallnamen +EPGPlus.channelevententry_font Uitzendingen +EPGPlus.edit_fonts Fonts instellen +EPGPlus.edit_sizes Grootte instellen +EPGPlus.font_style_bold Vet +EPGPlus.font_style_italic Cursief +EPGPlus.font_style_regular Normaal +EPGPlus.footer_fontbouquetchannelname Kies Boeket- of Kanaalnaam +EPGPlus.footer_fontbuttons Knoppen +EPGPlus.footer_fonteventdescription Titel 1 kies uitzending +EPGPlus.footer_fonteventshortdescription Titel 2 kies uitzending +EPGPlus.head Preview (EPG Plus) +EPGPlus.header_font Menu +EPGPlus.next_bouquet Volgend Boeket +EPGPlus.options Optie's +EPGPlus.page_down Vorige pagina. +EPGPlus.page_up Volgende pagina. +EPGPlus.prev_bouquet Vorig Boeket. +EPGPlus.record Opname +EPGPlus.refresh_epg Aktualiseren +EPGPlus.remind Herinneren +EPGPlus.reset_settings Resetten van instellingen. +EPGPlus.save_settings Instellingen bewaren +EPGPlus.scroll_mode Scroll Mode +EPGPlus.select_font_name Lettertype kiezen +EPGPlus.settings Instellingen +EPGPlus.slider_width Breedte van de sliders +EPGPlus.stretch_mode Stretch Mode +EPGPlus.swap_mode Bladeren +EPGPlus.timeline_fontdate Tijdschaal datum +EPGPlus.timeline_fonttime Tijdschaal Tijd +EPGPlus.view_mode Mode +GENRE.ARTS.0 Kunst/ cultuur +GENRE.ARTS.1 Beeldende kunst +GENRE.ARTS.10 kunst/culturele magazines +GENRE.ARTS.11 mode +GENRE.ARTS.2 fijne kunst +GENRE.ARTS.3 religie +GENRE.ARTS.4 populair cultuur/traditionele kunst +GENRE.ARTS.5 literatuur +GENRE.ARTS.6 film/cinema +GENRE.ARTS.7 experimentele film/video +GENRE.ARTS.8 uitzendingen/pers +GENRE.ARTS.9 nieuwe media +GENRE.CHILDRENs_PROGRAMMES.0 Kinderprogramma/ animatie +GENRE.CHILDRENs_PROGRAMMES.1 Kleuterprogramma +GENRE.CHILDRENs_PROGRAMMES.2 Ontspanningsprogramma (leeftijd: 6 tot 14) +GENRE.CHILDRENs_PROGRAMMES.3 Ontspanningsprogramma (leeftijd: 10 tot 16) +GENRE.CHILDRENs_PROGRAMMES.4 informationeel/educationeel/schoolprogramma +GENRE.CHILDRENs_PROGRAMMES.5 tekenfilms/animatie +GENRE.DOCUS_MAGAZINES.0 documentatie/magazine +GENRE.DOCUS_MAGAZINES.1 natuur/dieren/omgeving +GENRE.DOCUS_MAGAZINES.2 technologie/natuurkunde +GENRE.DOCUS_MAGAZINES.3 Geneeskunde/psychologie/ +GENRE.DOCUS_MAGAZINES.4 Vreemde landen/expeditie's +GENRE.DOCUS_MAGAZINES.5 sociale- en spirituele wetenschappen +GENRE.DOCUS_MAGAZINES.6 andere opvoedingen +GENRE.DOCUS_MAGAZINES.7 Talen +GENRE.MOVIE.0 film/drama +GENRE.MOVIE.1 detectieve/thriller +GENRE.MOVIE.2 aventuren/western/oorlog +GENRE.MOVIE.3 science-fiction/fantasy/horror +GENRE.MOVIE.4 comedy +GENRE.MOVIE.5 soap/melodrama/folkloristisch +GENRE.MOVIE.6 romantiek +GENRE.MOVIE.7 ernstig/klassiek/religieus/historische film/drama +GENRE.MOVIE.8 +18 / drama +GENRE.MUSIC_DANCE.0 muziek / ballet / dance +GENRE.MUSIC_DANCE.1 rock/pop +GENRE.MUSIC_DANCE.2 klassieke music +GENRE.MUSIC_DANCE.3 folk/traditionele muziek +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musical/opera +GENRE.MUSIC_DANCE.6 ballet +GENRE.NEWS.0 nieuws +GENRE.NEWS.1 nieuws/weerbulletin +GENRE.NEWS.2 nieuwsmagazine +GENRE.NEWS.3 documentaire +GENRE.NEWS.4 discussie/interview/debat +GENRE.SHOW.0 Show / Spelshow +GENRE.SHOW.1 game show/quiz/contest +GENRE.SHOW.2 varieteit show +GENRE.SHOW.3 talk show +GENRE.SOCIAL_POLITICAL.0 sociale en politieke evenementen/zaken +GENRE.SOCIAL_POLITICAL.1 magazines/verslagen/documentaire +GENRE.SOCIAL_POLITICAL.2 economische /sociale adviezen +GENRE.SOCIAL_POLITICAL.3 Opmerkzame personen +GENRE.SPORTS.0 sport +GENRE.SPORTS.1 speciale evenementen (Olympische spelen,Wereldbeker, etc.) +GENRE.SPORTS.10 paardensport +GENRE.SPORTS.11 gevechtsporten +GENRE.SPORTS.2 sportmagazine +GENRE.SPORTS.3 Voetbal +GENRE.SPORTS.4 tennis/squash +GENRE.SPORTS.5 teamsporten +GENRE.SPORTS.6 atletiek +GENRE.SPORTS.7 motorsport +GENRE.SPORTS.8 watersport +GENRE.SPORTS.9 wintersport +GENRE.TRAVEL_HOBBIES.0 reizen en ontspanning +GENRE.TRAVEL_HOBBIES.1 tourisme/reizen +GENRE.TRAVEL_HOBBIES.2 werk +GENRE.TRAVEL_HOBBIES.3 autotoerisme +GENRE.TRAVEL_HOBBIES.4 fitness & gezondheid +GENRE.TRAVEL_HOBBIES.5 koken +GENRE.TRAVEL_HOBBIES.6 adverteren/shopping +GENRE.TRAVEL_HOBBIES.7 tuinieren +GENRE.UNKNOWN Onbekend +apids.hint_1 Geef de te streamen APIDs in +apids.hint_2 in hex-weergave scheiden met ' ' +apidselector.head Kies taal +audiomenu.PCMOffset Volume Decrease PCM +audiomenu.analogout Analoge uitgang +audiomenu.avs avs +audiomenu.avs_control Volume Control avs/ost +audiomenu.dolbydigital Dolby Digital +audiomenu.head Geluidsinstellingen +audiomenu.lirc lirc +audiomenu.monoleft mono links +audiomenu.monoright mono rechts +audiomenu.ost ost +audiomenu.stereo stereo +audioplayer.add Voeg toe +audioplayer.artist_title Artiest, Titel +audioplayer.defdir Startdirectory +audioplayer.delete Wis +audioplayer.deleteall Wis alles +audioplayer.display_order display order +audioplayer.fastforward Vooruitspoelen +audioplayer.follow auto Kies huidig +audioplayer.head Audio Speellijst +audioplayer.highprio Hoge decoderingsprioriteit +audioplayer.id3scan Scannen van ID3 tags +audioplayer.keylevel key level +audioplayer.name Audioplayer +audioplayer.pause pauze +audioplayer.play Play +audioplayer.playing Huidig nummer +audioplayer.rewind terugspoelen +audioplayer.screensaver_timeout screensaver timeout (min, 0=uit) +audioplayer.shuffle shuffle +audioplayer.stop Stop +audioplayer.title_artist Titel, Artiest +audioplayerpicsettings.general Audioplayer/ beeldviewer +bookmarkmanager.delete Verwijderen +bookmarkmanager.name Favorieten +bookmarkmanager.rename Hernoemen +bookmarkmanager.select Kiezen +bouqueteditor.add Voeg toe +bouqueteditor.bouquetname Naam van het boeket +bouqueteditor.delete Wis +bouqueteditor.discardingchanges Wegzetten van de wijzigingen, even geduld a.u.b... +bouqueteditor.hide Verberg +bouqueteditor.lock Slot +bouqueteditor.move Verzet +bouqueteditor.name Boeket-editor +bouqueteditor.newbouquetname Nieuwe naam van het boeket +bouqueteditor.rename Hernoem +bouqueteditor.return Klaar +bouqueteditor.savechanges? Wilt u de wijzigingen bewaren? +bouqueteditor.savingchanges Bewaren van wijzigingen, even geduld... +bouqueteditor.switch Toevoegen/verwijderen +bouqueteditor.switchmode TV/Radio +bouquetlist.head Boeket +cablesetup.provider Kabelprovider +channellist.head Alle Services +channellist.nonefound Geen kanalen gevonden!\nVoer aub een scan uit\n(dbox-toets -> service) +channellist.since sinds %02d:%02d +colorchooser.alpha alpha +colorchooser.blue blauw +colorchooser.green groen +colorchooser.red rood +colormenu.background Achtergrond +colormenu.background_head Achtergrond +colormenu.fade Fade menu's +colormenu.font lettergrootte +colormenu.gtx_alpha Transparantheid (GTX) +colormenu.head Kleur Settings +colormenu.menucolors Menu kleuren +colormenu.statusbar Infobar +colormenu.textcolor Tekstkleur +colormenu.textcolor_head Tekstkleur +colormenu.themeselect selecteer onderwerp +colormenu.timing OSD Tijd +colormenusetup.head Menu Kleuren +colormenusetup.menucontent Vensterinhoud +colormenusetup.menucontent_inactive Vensterinhoud niet actief +colormenusetup.menucontent_selected Vensterinhoud geactiveerd +colormenusetup.menuhead Menu bovenkant +colorstatusbar.head Infobar +colorstatusbar.text Infobar +colorthememenu.classic_theme Classic thema +colorthememenu.dblue_theme Donkerblauw thema +colorthememenu.dvb2k_theme DVB2000 thema +colorthememenu.head Themakeuze +colorthememenu.neutrino_theme Neutrino thema +date.Apr April +date.Aug Augustus +date.Dec December +date.Feb Februari +date.Fri vrijdag +date.Jan Januari +date.Jul Juli +date.Jun Juni +date.Mar Maart +date.May Mei +date.Mon maandag +date.Nov November +date.Oct Oktober +date.Sat zaterdag +date.Sep September +date.Sun zondag +date.Thu donderdag +date.Tue dinsdag +date.Wed woensdag +epglist.head Event-list - %s +epglist.noevents EPG is niet beschikbaar +epgviewer.More_Screenings Meerdere Screenings op dit kanaal +epgviewer.nodetailed Geen details beschikbaar +epgviewer.notfound Geen EPG gevonden +eventlistbar.channelswitch Planning +eventlistbar.eventsort Sorteren +eventlistbar.recordevent Opnemen +favorites.addchannel Huidig kanaal zal toegevoegd worden\naan het boeket "mijn favorieten".\nDit zal enkele seconden durens... +favorites.bouquetname Mijn favorieten +favorites.bqcreated Bouquet "Mijn favorieten" is gemaakt...\n +favorites.chadded Huidig kanaal is aan de favorieten toegevoegd...\n +favorites.chalreadyinbq Huidig kanaal staat reeds bij de favorieten...\n +favorites.finalhint \nGebruik de boeketeditor om de favorieten aan te passen.\n +favorites.menueadd Voeg kanaal aan favorieten toe. +favorites.nobouquets Favorieten zijn alleen beschikbaar met geactiveerde boeketten. +filebrowser.delete Verwijderen +filebrowser.dodelete1 Moet +filebrowser.dodelete2 gewist worden? +filebrowser.filter.active Filter aan +filebrowser.filter.inactive Filter uit +filebrowser.head Browser +filebrowser.mark Markeer +filebrowser.nextpage Volgende pagina +filebrowser.prevpage Vorige pagina +filebrowser.scan Folders doorzoeken +filebrowser.select Kies +filebrowser.showrights Toon rechten +filebrowser.sort.date (datum) +filebrowser.sort.name (bestandsname) +filebrowser.sort.namedirsfirst (Dateiname2) +filebrowser.sort.size (Grootte) +filebrowser.sort.type (Type) +flashupdate.actionreadflash lezen +flashupdate.cantopenfile Kan bestand niet openen +flashupdate.cantopenmtd Kan het mtd-device niet openen +flashupdate.checkupdate Zoek nieuwe versie +flashupdate.currentreleasecycle Release cycle +flashupdate.currentversion_sep Huidige versie +flashupdate.currentversiondate Datum +flashupdate.currentversionsnapshot Type Image +flashupdate.currentversiontime Tijd +flashupdate.erasefailed Wissen van de flash mislukt +flashupdate.erasing Wissen van de flash +flashupdate.experimentalimage De gekozen image is nog niet getest.D.w.z.dat\nuw ontvanger misschien niet opstart na de update.\n\nWilt u echt deze versie updaten? +flashupdate.expertfunctions Expert-functie's +flashupdate.fileis0bytes De grootte van het bestand is 0 Byte +flashupdate.fileselector File kiezen +flashupdate.flashreadyreboot De image is succesvol geflashed.\nDe DBox zal nu herstarten. +flashupdate.getinfofile Haalt info versie op +flashupdate.getinfofileerror Geen info van de versie gevonden +flashupdate.getupdatefile Krijgt een update +flashupdate.getupdatefileerror Krijgt geen update +flashupdate.globalprogress Globale vooruitgang: +flashupdate.head Software Update +flashupdate.md5check controleer image +flashupdate.md5sumerror Image heeft fouten +flashupdate.msgbox De volgende nieuwe image is gevonden:\nDatum: %s, %s\nBaseImage: %s\nImageType: %s\n\nWilt u de nieuwe image nu downloaden en installeren? +flashupdate.msgbox_manual De volgende nieuwe image is gevonden:\nDatum: %s, %s\nBaseImage: %s\nImageType: %s\n\nWilt u deze versie nu installeren? +flashupdate.mtdselector Partitie kiezen +flashupdate.programmingflash Programmeren van de flash +flashupdate.proxypassword Paswoord +flashupdate.proxypassword_hint1 Geef het paswoord voor de proxyserver +flashupdate.proxypassword_hint2 Leeg betekent geen proxy +flashupdate.proxyserver Hostnaam +flashupdate.proxyserver_hint1 Geef naam of IP proxyserver, Gebruik host: poort +flashupdate.proxyserver_hint2 Geen invoer = geen proxy +flashupdate.proxyserver_sep Proxyserver +flashupdate.proxyusername Gebruikersnaam +flashupdate.proxyusername_hint1 Geef de gebruikersnaam van de proxyserver +flashupdate.proxyusername_hint2 Geen invoer= geen proxy-auth +flashupdate.readflash Lees de hele image +flashupdate.readflashmtd Lees een partitie +flashupdate.ready Klaar +flashupdate.reallyflashmtd Wilt u echt flashen?\n\nAls er een fout optreed is de image niet\ngeldig, De Dbox zal niet starten na het flashen.\n\nImagename: %s\nTarget: %s +flashupdate.savesuccess De image is succesvol bewaard \nonder %s. +flashupdate.selectimage Beschikbare Images +flashupdate.squashfs.noversion Versiecontrole van SquashFS gaat momenteel enkel via webupdating +flashupdate.titlereadflash Lezen Flash +flashupdate.titlewriteflash Writing Flash +flashupdate.updatemode Updatemode +flashupdate.updatemode_internet Internet +flashupdate.updatemode_manual Manueel (ftp) +flashupdate.url_file config file +flashupdate.versioncheck Controleer versie +flashupdate.writeflash Schrijf de hele image +flashupdate.writeflashmtd Schrijf een partitie +flashupdate.wrongbase Your Release cycle differs, unable to update\nwithout having installed the right version! +fontmenu.channellist kanalenlijst +fontmenu.epg EPG +fontmenu.eventlist Eventlist +fontmenu.gamelist Spellijst +fontmenu.head Settings lettergrootte +fontmenu.infobar Infobar +fontsize.channel_num_zap Directe selectie +fontsize.channellist Kanalenlijst +fontsize.channellist_descr Omschrijving +fontsize.channellist_number Nummer +fontsize.epg_date EPG datum +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Titel +fontsize.eventlist_datetime datum/tijd +fontsize.eventlist_itemlarge groot +fontsize.eventlist_itemsmall klein +fontsize.eventlist_title Titel +fontsize.filebrowser_item filebrowser item +fontsize.gamelist_itemlarge groot +fontsize.gamelist_itemsmall klein +fontsize.hint lettertype instellen,\ngeduld aub... +fontsize.infobar_channame Kanaalnaam +fontsize.infobar_info info +fontsize.infobar_number Nummer +fontsize.infobar_small klein +fontsize.menu Menutekst +fontsize.menu_info Menu Info +fontsize.menu_title Menu Titel +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.epgnotload EPG niet geladen.... +infoviewer.epgwait wachten op EPG... +infoviewer.eventlist Event-Lijst +infoviewer.languages Geluid +infoviewer.motor_moving Positionering van de antenne +infoviewer.nocurrent Geen info beschikbaar voor dit programma +infoviewer.noepg EPG is niet beschikbaar +infoviewer.notavailable Kanaal is niet beschikbaar +infoviewer.selecttime Tijdskeuze +infoviewer.streaminfo Kenmerken +infoviewer.subservice Subservices +infoviewer.waittime Wacht op de tijd... +ipsetup.hint_1 Gebruik 0 tot 9, of Use 0..9, of gebruik Up/Down, +ipsetup.hint_2 OK bewaar, Home afbreken +keybindingmenu.RC Key herhaal-blocker +keybindingmenu.addrecord Voeg record timer toe +keybindingmenu.addrecord_head Voeg record timer toe +keybindingmenu.addremind add zapto timer +keybindingmenu.addremind_head add zapto timer +keybindingmenu.allchannels_on_ok Alle services +keybindingmenu.bouquetchannels_on_ok Huidig boeket +keybindingmenu.bouquetdown vorig boeket +keybindingmenu.bouquetdown_head keysetup vorig boeket back +keybindingmenu.bouquethandling Boeket-control +keybindingmenu.bouquetlist_on_ok Boeketlijst +keybindingmenu.bouquetup Volgend boeket +keybindingmenu.bouquetup_head keysetup Volgend boeket +keybindingmenu.cancel Sluit kanalenlijst +keybindingmenu.cancel_head Kanalenlijst gesloten +keybindingmenu.channeldown Kanaal omlaag +keybindingmenu.channeldown_head Keysetup channel down +keybindingmenu.channellist Kanaallijst +keybindingmenu.channelup kanaal omhoog +keybindingmenu.channelup_head Keysetup channel up +keybindingmenu.head Keybinding Setup +keybindingmenu.modechange Modechange +keybindingmenu.pagedown Volgende pagina +keybindingmenu.pagedown_head Keysetup page down +keybindingmenu.pageup Vorige pagina +keybindingmenu.pageup_head Keysetup page up +keybindingmenu.quickzap Quickzap +keybindingmenu.repeatblock Herhaal delay +keybindingmenu.repeatblockgeneric generic delay +keybindingmenu.sort Verander sorteervolgorde +keybindingmenu.sort_head Verander sorteervolgorde +keybindingmenu.subchanneldown subchannel omlaag +keybindingmenu.subchanneldown_head key subkanaal omlaag +keybindingmenu.subchannelup subkanaal omhoog +keybindingmenu.subchannelup_head key subkanaal omhoog +keybindingmenu.tvradiomode TV/Radio-mode +keybindingmenu.tvradiomode_head TV/Radio-mode +keychooser.head Setup nieuwe Key +keychooser.text1 Geef de nieuwe key in +keychooser.text2 Wacht enkele sec. om af te breken +keychoosermenu.currentkey Huidige key +keychoosermenu.setnew setup nieuwe key +keychoosermenu.setnone Geen key +languagesetup.head Setup Taal +languagesetup.select Taalkeuze +lcdcontroler.brightness normale helderheid +lcdcontroler.brightnessstandby Standby helderheid +lcdcontroler.contrast Contrast +lcdcontroler.head Display-instellingen +lcdmenu.autodimm Auto dimm +lcdmenu.head LCD Settings +lcdmenu.inverse Invert +lcdmenu.lcdcontroler Contrast / Helderheid +lcdmenu.power Voeding +lcdmenu.statusline status lijn +lcdmenu.statusline.both Volume/Speelduur +lcdmenu.statusline.playtime Speelduur +lcdmenu.statusline.volume Volume +mainmenu.audioplayer Audioplayer +mainmenu.games Spelletjes +mainmenu.head Hoofdmenu +mainmenu.movieplayer Filmspeler +mainmenu.pausesectionsd Lees EPG +mainmenu.pictureviewer Weergeven van afbeeldingen +mainmenu.radiomode Radio-Mode +mainmenu.recording Opnemen +mainmenu.recording_start Start opname +mainmenu.recording_stop Stop opname +mainmenu.scartmode Scart-Mode +mainmenu.service Service +mainmenu.settings Instellingen +mainmenu.shutdown Uitschakelen +mainmenu.sleeptimer SleepTimer +mainmenu.tvmode TV-Mode +mainsettings.audio Geluid +mainsettings.colors Kleuren/lettertype +mainsettings.head Settings +mainsettings.keybinding Key Setup +mainsettings.language Taal +mainsettings.lcd LCD-display +mainsettings.misc Overige settings +mainsettings.network Netwerk +mainsettings.recording Opnemen +mainsettings.savesettingsnow Bewaar de settings nu +mainsettings.savesettingsnow_hint Even geduld, settings worden bewaard +mainsettings.streaming Filmspeler +mainsettings.video Beeld +menu.back Terug +messagebox.back terug +messagebox.cancel Annuleren +messagebox.discard Bewaren van de wijzigingen? +messagebox.error Fout +messagebox.info Informatie +messagebox.no Neen +messagebox.yes Ja +miscsettings.bootinfo Toon info bij starten +miscsettings.bootmenu Info tonen bij opstarten +miscsettings.driver_boot Bootoptie's +miscsettings.fb_destination Expert! Boot-Console +miscsettings.general Algemeen +miscsettings.head Overige settings +miscsettings.hwsections Gebruik hardware secties +miscsettings.infobar_sat_display Satelliet display in infobar +miscsettings.shutdown_real standby +miscsettings.shutdown_real_rcdelay vertraagde shutdown +miscsettings.sptsmode Gebruik spts-mode +miscsettings.startbhdriver load BH-Mode drivers +motorcontrol.head Motor-Setup +movieplayer.bookmark Favorieten +movieplayer.bookmarkname Bookmark Naam +movieplayer.bookmarkname_hint1 Geef de naam voor de +movieplayer.bookmarkname_hint2 nieuwe favoriet in +movieplayer.buffering Bufferen... +movieplayer.defdir startdirectory +movieplayer.dvdplayback DVD +movieplayer.fileplayback Bestand via VLC +movieplayer.goto Ga naar... +movieplayer.goto.h1 = -> absolute sprong +movieplayer.goto.h2 +,- -> relatieve sprong +movieplayer.head Filmplayer +movieplayer.nostreamingserver De streamserver kon niet gevonden worden +movieplayer.pesplayback PES Afspelen (Experiment) +movieplayer.pleasewait Even geduld aub.\nBezig met verbinden met streamserver... +movieplayer.toomanybookmarks U heeft te veel favorieten.\nEr moet een andere favoriet gewist worden. +movieplayer.tshelp Rood/Home Stop\nGROEN Kies audio track\nGEEL Pause/Continue\nBLUE Create bookmark\nd-box Show progress\n1 approx. 1 minute back\n3 skip approx. 1 minute\n4 approx. 5 minuten terug\n6 sla over ongeveer 5 minuten\n7 ongeveer 10 minuten terug\n9 sla ongeveer 10 minutes\nHelp: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tsplayback Speel TS +movieplayer.vcdplayback (S)VCD +movieplayer.vlchelp ROOD/Home Stop\nGROEN Resync\nGEEL Pause/verder\nBLAUW Favoriet instellen\n1 ca. 1 Minuut terug\n3 ca. 1 Minuut vooruit\n4 ca. 5 Minuten terug\n6 ca. 5 Minuten vooruit\n7 ca. 10 Minuten terug\n9 ca. 10 Minuten vooruit\nHelp: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.wrongvlcversion Functie is niet mogelijk met de gebruikte VLC-versie +networkmenu.broadcast Broadcast +networkmenu.dhcp DHCP +networkmenu.gateway Standaard Gateway +networkmenu.head Netwerkinstellingen +networkmenu.ipaddress IP-Addres +networkmenu.mount NFS/CIFS +networkmenu.nameserver Nameserver +networkmenu.netmask Netmasker +networkmenu.setupnow Netwerk nu activeren +networkmenu.setuponstartup Netwerk activeren bij opstarten +networkmenu.show Toon actieve netwerksettings +networkmenu.test Test nu het netwerk +nfs.alreadymounted directory reeds gemount +nfs.automount mount bij starten +nfs.dir directory/share +nfs.ip NFS/CIFS Server IP +nfs.localdir plaatselijke directory +nfs.mount Mount NFS/CIFS volume +nfs.mount_options mountoptie's +nfs.mounterror mountfout +nfs.mounterror_notsup Type filesysteem niet ondersteund +nfs.mountnow direct mounten +nfs.mounttimeout mountfout: timeout +nfs.password paswoord Common Internet File System (CIFS) +nfs.remount Lijst opnieuw mounten +nfs.type type +nfs.type_cifs Common Internet File System (CIFS) +nfs.type_nfs Network File System (NFS) +nfs.umount Umount NFS/CIFS volume +nfs.umounterror umountingfout: volume +nfs.username Gebruikersnaam Common Internet File System (CIFS) +nfsmenu.head NFS/CIFS instellingen +nvod.percentage (%d%% over) +nvod.starting (start binnen %d minuten) +nvodselector.directormode Direct-Mode +nvodselector.head Kies starttijd +nvodselector.subservice Kies Subservice +options.default Reset naar standaard +options.fb Framebuffer +options.null Null +options.off Uit +options.on Aan +options.serial Serieel +parentallock.changepin verander PIN code +parentallock.changepin_hint1 Geef hier de nieuwe PIN-code in! +parentallock.changetolocked on locked bouquets +parentallock.head Voer PIN-code v.h. kinderslot in +parentallock.lockage Programma op slot +parentallock.lockage12 Voor jonger dan 12j +parentallock.lockage16 Voor jonger dan 16j +parentallock.lockage18 Voor jonger dan 18j +parentallock.lockedprogram Gesloten programma (vanaf %d jaar en hoger) +parentallock.never nooit +parentallock.onsignal Bij uitzenden op slot +parentallock.parentallock Kinderslot +parentallock.prompt prompt voor PIN +pictureviewer.defdir startdirectory +pictureviewer.head Weergave van afbeeldingen +pictureviewer.resize.color_average Geavanceerd +pictureviewer.resize.none Geen +pictureviewer.resize.simple Eenvoudig +pictureviewer.scaling schaal +pictureviewer.show Toon +pictureviewer.slide_time toon tijd van slideshow +pictureviewer.slideshow slideshow +pictureviewer.sortorder verander volgorde +pictureviewer.sortorder.date (datum) +pictureviewer.sortorder.filename (bestandsnaam) +ping.ok Bereikbaar door Ping +ping.protocol Niet bereikbaar (fout bij host of protocol) +ping.socket Niet bereikbaar (socketfout) +ping.unreachable Onbereikbaar door Ping +pinprotection.head Voer PIN-code in +pinprotection.wrongcode Foute PIN-Code! Probeer opnieuw +rclock.lockmsg Uw afstandsbediening van de DBox2 zal vergrendeld worden.\nOm de DBox2 vrij te geven druk op \nen op uw afstandsbediening. +rclock.menueadd Vergrendelen afstandsbediening +rclock.title Vergrendel afstandsbediening +rclock.unlockmsg Afstandsbediening in werking. +recordingmenu.defdir Opnamefolder +recordingmenu.file Direct (file) +recordingmenu.filesettingsseparator Direct opnemen +recordingmenu.head Opnameinstellingen +recordingmenu.no_scart Verander niet naar Scart-mode +recordingmenu.off Uit +recordingmenu.recording_type Opname type +recordingmenu.server server +recordingmenu.server_ip Opname server IP +recordingmenu.server_mac MAC adres +recordingmenu.server_port Opname server port +recordingmenu.server_wakeup recording server WOL +recordingmenu.setupnow Activeer veranderingen +recordingmenu.splitsize Max. grootte (MB) +recordingmenu.stopplayback stop playback +recordingmenu.stopsectionsd stop sectionsd +recordingmenu.stream_all_audio_pids Alle audiopids opnemen +recordingmenu.vcr vcr +recordtimer.announce Opname start in enkele minuten +repeatblocker.hint_1 Kortste tijd (in ms) tussen 2 drukken op de knop +repeatblocker.hint_2 Druk op 0 om de blocker uit te zetten (rood is spatie) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-herhaling +satsetup.extended DiSEqC-Settings +satsetup.extended_motor Motorsettings +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Manuele Setup van de motor +satsetup.nodiseqc Geen DiSEqC +satsetup.satellite Satelliet +satsetup.savesettingsnow Sla de settings op +satsetup.smatvremote SMATV Remote Tuning +scants.actcable Kabel: +scants.actsatellite Satelliet: +scants.bouquet Boeket +scants.bouquet_create Maak een nieuw +scants.bouquet_erase Wis alles +scants.bouquet_leave Verlaat huidig +scants.bouquet_satellite Satellietboeket +scants.bouquet_update update +scants.channel Kanaal: +scants.failed Faling transponderscan! +scants.finished Transponderscan succesvol! +scants.freqdata Frequentie +scants.head Scan transponder +scants.numberofdataservices Data: +scants.numberofradioservices Radio: +scants.numberoftotalservices Totaal: +scants.numberoftvservices TV: +scants.provider Provider: +scants.startnow Start scan +scants.transponders Transponders: +screensetup.lowerright groen = setup lower right +screensetup.upperleft rood = setup upper left +servicemenu.head Service +servicemenu.reload Herlaad Kanalenlijst +servicemenu.reload_hint Even geduld, herladen van kanalenlijst +servicemenu.scants Service scan +servicemenu.ucodecheck Controle ucodes +servicemenu.update Software Update +settings.missingoptionsconffile De neutrino-settings zijn geupdate.\nNew Opties worden standaard gezet. +settings.noconffile Geen neutrino-settings gevonden.\nStandaart in gebruik. +shutdowntimer.announce Box zal uitschakelen in 1 min.\nUitschakelen aflassen? +sleeptimerbox.announce Sleeptimer in 1 min +sleeptimerbox.hint1 Schakel uit in ...minuten. (000=uit) +sleeptimerbox.hint2 dbox2 zal uitgaan na deze tijd. +sleeptimerbox.title Sleeptimer +streamfeatures.head Features +streaminfo.aratio Aspect Ratio +streaminfo.aratio_unknown Aspect Ratio: onbekend +streaminfo.audiotype Audiotype +streaminfo.audiotype_unknown Audiotype: onbekend +streaminfo.bitrate Bitrate +streaminfo.framerate Framerate +streaminfo.framerate_unknown Framerate: onbekend +streaminfo.head Stream-Informatie +streaminfo.not_available Niet beschikbaar +streaminfo.resolution Resolutie +streaming.buffer_overflow De opname is afgebroken \nomdat doelmap niet kon geopend worden. +streaming.busy Een of meerdere opnames zijn bezig.\nAls U deze oodschap krijgt en er is geen opname\nbezig herstart dan Neutrino. +streaming.dir_not_writable De opnamefolder is niet bereikbaar.\nOpnemen zal niet gaan. +streaming.success De opname is met succes beëindigd +streaming.write_error De opname is afgebroken \nomdat er een schrijffout opgetreden is. +streaming.write_error_open De opname is afgebroken \nomdat de doelmap niet kon geopend worden. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Instellingen filmspeler +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Uit +streamingmenu.on Aan +streamingmenu.server_ip Streamingserver IP +streamingmenu.server_port Streamingserver Poort +streamingmenu.streaming_audiorate Datarate Geluid +streamingmenu.streaming_force_avi_rawaudio AC3 met avi +streamingmenu.streaming_force_transcode_video Transcod. ook mpg/vcd Video +streamingmenu.streaming_resolution Resolutie +streamingmenu.streaming_server_cddrive DVD Drive +streamingmenu.streaming_server_startdir Directory (VLC) +streamingmenu.streaming_transcode_audio Transcod. Audio (dvd/vcd/mpg) +streamingmenu.streaming_transcode_video_codec MPEG Video Codec +streamingmenu.streaming_type Streamingserver +streamingmenu.streaming_videorate Datarate Beeld +streamingserver.noconnect Geen verbinding met de streamserver.\nOpname afgelast. +stringinput.caps caps/geen caps +stringinput.clear Wis alles +timer.eventrecord.msg OK, niet OK +timer.eventrecord.title Opname plannen +timer.eventtimed.msg Dit programma is opgeslagen.\ndbox2 zal opstarten en \nschakelt naar dit programma op het gegeven tijdstip. +timer.eventtimed.title Programmeren +timerbar.channelswitch Overzicht +timerbar.recordevent Opnemen +timerlist.alarmtime Alarm time +timerlist.apids Audio PIDs +timerlist.bouquetselect Kies boeket +timerlist.channel Kanaal +timerlist.channelselect Kies kanaal +timerlist.delete Wis +timerlist.menumodify Pas timer aan +timerlist.menunew nieuwe timer +timerlist.message Boodschap +timerlist.moderadio Radio-kanalen +timerlist.modeselect Mode selection +timerlist.modetv TV-kanalen +timerlist.modify Modify +timerlist.name Timer list +timerlist.new Nieuwe timer +timerlist.program.unknown Programma onbekend +timerlist.reload Herlaad +timerlist.repeat Herhaal +timerlist.repeat.biweekly Tweewekelijks +timerlist.repeat.byeventdescription Bekijk programmatie +timerlist.repeat.daily Dagelijks +timerlist.repeat.fourweekly Vierweekelijks +timerlist.repeat.friday Vr +timerlist.repeat.monday Ma +timerlist.repeat.monthly Maandelijks +timerlist.repeat.once Eenmalig +timerlist.repeat.saturday Za +timerlist.repeat.sunday Zo +timerlist.repeat.thursday Do +timerlist.repeat.tuesday Di +timerlist.repeat.unknown Onbekend +timerlist.repeat.wednesday Woe +timerlist.repeat.weekdays Op weekdagen +timerlist.repeat.weekly weekelijks +timerlist.save Bewaar timer +timerlist.standby SB mode +timerlist.standby.off Standby laten +timerlist.standby.on Enter standby +timerlist.stoptime Stop time +timerlist.type Timer typ +timerlist.type.nextprogram Volgend programma +timerlist.type.record Opnemen +timerlist.type.remind Herinnering +timerlist.type.shutdown Uitschakelen +timerlist.type.sleeptimer Sleeptimer +timerlist.type.standby Standby +timerlist.type.unknown Onbekend +timerlist.type.zapto Zap naar +timerlist.weekdays Weekdagen +timerlist.weekdays.hint_1 Ma Di Wo Do Vr Za Zo +timerlist.weekdays.hint_2 'X'=timer '-' geen timer +timersettings.record_safety_time_after Stop opname tijdscorrectie +timersettings.record_safety_time_after.hint_1 Correctie van tijd in min. (00=uit). Deze tijd +timersettings.record_safety_time_after.hint_2 wordt toegevoegd aan iedere stoptijd van de timer. +timersettings.record_safety_time_before Start opname tijdscorrectie +timersettings.record_safety_time_before.hint_1 Correctie van tijd in min. (00=uit). Deze tijd +timersettings.record_safety_time_before.hint_2 will be deducted of every record timer. +timersettings.separator Timer instellingen +timing.chanlist Kanalenlijst +timing.epg Epg +timing.filebrowser Browser voor bestanden +timing.head OSD Timeouts +timing.hint_1 Tijd in sec. Na deze tijd zal de +timing.hint_2 infobar verdwijnen. +timing.infobar Infobar +timing.menu Menu +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Alpha-Cam +ucodecheck.head Controle UCode +ucodecheck.ucode UCode +ucodes.failure Opgelet, µCodes konden niet gevonden worden!\n\nLoad ze up via FTP (of via de DBox-BootManager),\nnadien de DBox herstarten! +videomenu.csync Sync.-correctie +videomenu.head Videoinstellingen +videomenu.rgb_centering RGB-centering +videomenu.screensetup Scherm Setup +videomenu.vcrswitch Switch Scart automatisch +videomenu.videoformat Formaat +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect autodetect +videomenu.videosignal Video uit +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce Zapto timer in 1 minuut. diff --git a/data/locale/polski.locale b/data/locale/polski.locale new file mode 100644 index 000000000..c3fb6eb3d --- /dev/null +++ b/data/locale/polski.locale @@ -0,0 +1,1237 @@ +EPGMenu.epgplus EPG Plus +EPGMenu.eventinfo Opis programu +EPGMenu.eventlist Lista programów +EPGMenu.head EPG +EPGMenu.streaminfo Informacje o strumieniu +EPGPlus.actions akcje +EPGPlus.bybouquet_mode bukietami +EPGPlus.bypage_mode stronami +EPGPlus.change_font_size Rozmiar +EPGPlus.change_font_style Styl +EPGPlus.change_size Podaj wielkość +EPGPlus.channelentry_font Nazwa kanaÅ‚u +EPGPlus.channelentry_separationlineheight Wysokość separatorów +EPGPlus.channelentry_width Szerokość kolumny z kanaÅ‚ami +EPGPlus.channelevententry_font TytuÅ‚ programu +EPGPlus.edit_fonts Edycja czcionek +EPGPlus.edit_sizes Edycja rozmiarów +EPGPlus.font_style_bold pogrubiony +EPGPlus.font_style_italic kursywa +EPGPlus.font_style_regular normalny +EPGPlus.footer_fontbouquetchannelname Pasek: Bukiet +EPGPlus.footer_fontbuttons Pasek: Funkcje +EPGPlus.footer_fonteventdescription Pasek: TytuÅ‚ programu +EPGPlus.footer_fonteventshortdescription Pasek: Opis programu +EPGPlus.head EPG Plus +EPGPlus.header_font Nagłówek +EPGPlus.horgap1_height Wysokość górnego odstÄ™pu +EPGPlus.horgap2_height Wysokość dolnego odstÄ™pu +EPGPlus.next_bouquet nast.bukiet +EPGPlus.options opcje +EPGPlus.page_down poprz.strona +EPGPlus.page_up nast.strona +EPGPlus.prev_bouquet poprz.bukiet +EPGPlus.record nagraj +EPGPlus.refresh_epg odÅ›wież +EPGPlus.remind zapamiÄ™taj +EPGPlus.reset_settings Przywróć ustawienia domyÅ›lne +EPGPlus.save_settings Zapisz ustawienia +EPGPlus.scroll_mode przewijanie +EPGPlus.select_font_name Wybór czcionki +EPGPlus.settings Ustawienia +EPGPlus.slider_width Szerokość suwaka +EPGPlus.stretch_mode rozciÄ…ganie +EPGPlus.swap_mode Rodzaj przewijania +EPGPlus.timeline_fontdate Data +EPGPlus.timeline_fonttime Czas +EPGPlus.vergap1_width Szerokość lewego odstÄ™pu +EPGPlus.vergap2_width Szerokość prawego odstÄ™pu +EPGPlus.view_mode Tryb wyÅ›wietlania +GENRE.ARTS.0 sztuka/kultura +GENRE.ARTS.1 sztuki plastyczne +GENRE.ARTS.10 magazyn artystyczny/kulturalny +GENRE.ARTS.11 moda +GENRE.ARTS.2 sztuki piÄ™kne +GENRE.ARTS.3 religia +GENRE.ARTS.4 sztuka ludowa +GENRE.ARTS.5 literatura +GENRE.ARTS.6 film/kino +GENRE.ARTS.7 film eksperymentalny +GENRE.ARTS.8 radio/prasa +GENRE.ARTS.9 nowe media +GENRE.CHILDRENs_PROGRAMMES.0 program dla dzieci / mÅ‚odzieży +GENRE.CHILDRENs_PROGRAMMES.1 program dla dzieci w wieku przedszkolnym +GENRE.CHILDRENs_PROGRAMMES.2 program rozrywkowy dla osób w wieku 6 – 14 lat +GENRE.CHILDRENs_PROGRAMMES.3 program rozrywkowy dla osób w wieku 10 – 16 lat +GENRE.CHILDRENs_PROGRAMMES.4 program informacyjny i edukacyjny +GENRE.CHILDRENs_PROGRAMMES.5 film rysunkowy +GENRE.DOCUS_MAGAZINES.0 dokument/magazyn +GENRE.DOCUS_MAGAZINES.1 przyroda/zwierzÄ™ta/Å›rodowisko +GENRE.DOCUS_MAGAZINES.2 nauki przyrodnicze i technika +GENRE.DOCUS_MAGAZINES.3 medycyna/fizjologia/psychologia +GENRE.DOCUS_MAGAZINES.4 zagranica/wyprawy +GENRE.DOCUS_MAGAZINES.5 nauki spoÅ‚eczne i humanistyczne +GENRE.DOCUS_MAGAZINES.6 edukacja +GENRE.DOCUS_MAGAZINES.7 jÄ™zyki +GENRE.MOVIE.0 film fabularny/dramat +GENRE.MOVIE.1 film kryminalny/dreszczowiec +GENRE.MOVIE.2 film przygodowy/western/film wojenny +GENRE.MOVIE.3 fantastyka naukowa/fantasy/horror +GENRE.MOVIE.4 komedia +GENRE.MOVIE.5 opera mydlana/melodramat/folklor +GENRE.MOVIE.6 film romantyczny +GENRE.MOVIE.7 film/dramat poważny/klasyczny/religijny/historyczny +GENRE.MOVIE.8 film/dramat dla dorosÅ‚ych +GENRE.MUSIC_DANCE.0 muzyka/balet/taniec +GENRE.MUSIC_DANCE.1 rock/pop +GENRE.MUSIC_DANCE.2 muzyka poważna/klasyczna +GENRE.MUSIC_DANCE.3 muzyka ludowa +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musical/opera +GENRE.MUSIC_DANCE.6 balet +GENRE.NEWS.0 wiadomoÅ›ci +GENRE.NEWS.1 wiadomoÅ›ci/pogoda +GENRE.NEWS.2 magazyn informacyjny +GENRE.NEWS.3 dokument +GENRE.NEWS.4 dyskusja/wywiad/debata +GENRE.SHOW.0 widowisko / teleturniej +GENRE.SHOW.1 teleturniej/kwiz +GENRE.SHOW.2 rewia +GENRE.SHOW.3 talk-show +GENRE.SOCIAL_POLITICAL.0 wydarzenia spoÅ‚eczne i polityczne / gospodarka +GENRE.SOCIAL_POLITICAL.1 magazyn / reportaż / dokumentacja +GENRE.SOCIAL_POLITICAL.2 gospodarka i sprawy spoÅ‚eczne +GENRE.SOCIAL_POLITICAL.3 wyjÄ…tkowi ludzie +GENRE.SPORTS.0 sport +GENRE.SPORTS.1 wydarzenia specjalne (olimpiady, mistrzostwa Å›wiata itp.) +GENRE.SPORTS.10 jazda konna +GENRE.SPORTS.11 sztuki walki +GENRE.SPORTS.2 programy sportowe +GENRE.SPORTS.3 piÅ‚ka nożna +GENRE.SPORTS.4 tenis +GENRE.SPORTS.5 sporty drużynowe +GENRE.SPORTS.6 lekka atletyka +GENRE.SPORTS.7 sporty motorowe +GENRE.SPORTS.8 sporty wodne +GENRE.SPORTS.9 sporty zimowe +GENRE.TRAVEL_HOBBIES.0 podróże & rekreacja +GENRE.TRAVEL_HOBBIES.1 podróże & turystyka +GENRE.TRAVEL_HOBBIES.2 rzemiosÅ‚o +GENRE.TRAVEL_HOBBIES.3 motocykle +GENRE.TRAVEL_HOBBIES.4 kondycja fizyczna i zdrowie +GENRE.TRAVEL_HOBBIES.5 gotowanie +GENRE.TRAVEL_HOBBIES.6 zakupy +GENRE.TRAVEL_HOBBIES.7 ogród +GENRE.UNKNOWN nieznana kategoria +apids.hint_1 Wpisz APIDy, które majÄ… byç strumieniowane, +apids.hint_2 oddzielone znakiem ' ' w formie szesnastkowej +apidselector.head Wybór jÄ™zyka +audiomenu.PCMOffset Zmniejszenie gÅ‚oÅ›noÅ›ci PCM +audiomenu.analogout WyjÅ›cie analogowe +audiomenu.avs avs +audiomenu.avs_control Tryb sterowania gÅ‚oÅ›noÅ›ciÄ… +audiomenu.dolbydigital Dolby Digital +audiomenu.head Ustawienia dźwiÄ™ku +audiomenu.lirc lirc +audiomenu.monoleft mono lewy kanaÅ‚ +audiomenu.monoright mono prawy kanaÅ‚ +audiomenu.ost ost +audiomenu.stereo stereo +audioplayer.add dodaj +audioplayer.artist_title wykonawca, tytuÅ‚ +audioplayer.building_search_index building search index +audioplayer.button_select_title_by_id wybór wg ID +audioplayer.button_select_title_by_name wybór wg nazwy +audioplayer.defdir Katalog startowy +audioplayer.delete usuÅ„ +audioplayer.deleteall usuÅ„ wszystko +audioplayer.display_order Kolejność +audioplayer.enable_sc_metadata enable shoutcast meta data parsing +audioplayer.fastforward do przodu +audioplayer.follow Wybór bieżącego utworu +audioplayer.head Lista odtwarzania Mp3 +audioplayer.highprio Wysoki priorytet dekodowania +audioplayer.id3scan wczytaj informacje ID3 +audioplayer.jump_backwards skocz do tyÅ‚u +audioplayer.jump_dialog_hint1 wzglÄ™dnie, +audioplayer.jump_dialog_hint2 w sekundach. +audioplayer.jump_dialog_title Podaj wartość +audioplayer.jump_forwards skocz do przodu +audioplayer.keylevel zmieÅ„ funkcje klawiszy +audioplayer.name Odtwarzacz MP3 +audioplayer.pause pauza +audioplayer.play odtwarzaj +audioplayer.playing bieżący utwór +audioplayer.playlist_fileerror_msg File could not be created: +audioplayer.playlist_fileerror_title Error +audioplayer.playlist_fileoverwrite_msg Do you want to overwrite this file: +audioplayer.playlist_fileoverwrite_title Overwrite? +audioplayer.playlist_name filename of the play list +audioplayer.playlist_name_hint1 Please enter the filename of the playlist +audioplayer.playlist_name_hint2 The extension .m3u will be added automatically +audioplayer.reading_files reading files +audioplayer.repeat_on enable repeat mode +audioplayer.rewind do tyÅ‚u +audioplayer.save_playlist zapisz listÄ™ +audioplayer.screensaver_timeout Wygaszacz ekranu (min, 0=wyÅ‚) +audioplayer.select_title_by_name search title by name (SMS) +audioplayer.show_playlist Show Playlist +audioplayer.shuffle odtw. losowo +audioplayer.stop zatrzymaj +audioplayer.title_artist tytuÅ‚, wykonawca +audioplayerpicsettings.general Odtw. MP3 / przeglÄ…darka obr. +bookmarkmanager.delete usuÅ„ +bookmarkmanager.name ZakÅ‚adki +bookmarkmanager.rename zmieÅ„ +bookmarkmanager.select wybierz +bouqueteditor.add dodaj +bouqueteditor.bouquetname Nazwa bukietu +bouqueteditor.delete usuÅ„ +bouqueteditor.discardingchanges Zmiany zostanÄ… odrzucone. ProszÄ™ czekaç ... +bouqueteditor.hide ukryj +bouqueteditor.lock blokuj +bouqueteditor.move przenieÅ› +bouqueteditor.name ZarzÄ…dzanie bukietami +bouqueteditor.newbouquetname Nowa nazwa bukietu +bouqueteditor.rename zmieÅ„ nazwÄ™ +bouqueteditor.return Gotowe +bouqueteditor.savechanges? Czy chcesz zapisaç zmiany? +bouqueteditor.savingchanges Trwa zapisywanie zmian. ProszÄ™ czekaç ... +bouqueteditor.switch dodaj/usuÅ„ kanaÅ‚ +bouqueteditor.switchmode TV/radio +bouquetlist.head Bukiety +cablesetup.provider Dostawca telewizji kablowej +channellist.head Wszystkie kanaÅ‚y +channellist.nonefound Brak listy kanałów!\nUruchom wyszukiwanie kanałów\n(DBOX -> UsÅ‚ugi) +channellist.since od %02d:%02d +colorchooser.alpha ALPHA +colorchooser.blue BLUE +colorchooser.green GREEN +colorchooser.red RED +colormenu.background Kolor tÅ‚a +colormenu.fade Zanikanie menu +colormenu.font Wielkość czcionki +colormenu.gtx_alpha Przezroczystość (GTX) +colormenu.head Ustawienia kolorów +colormenu.menucolors Kolory menu +colormenu.statusbar Pasek stanu +colormenu.textcolor Kolor tekstu +colormenu.themeselect Wybór tematów +colormenu.timing Czasy wyÅ›wietlania OSD +colormenusetup.head Kolory menu +colormenusetup.menucontent Zawartość okna +colormenusetup.menucontent_inactive Nieaktywna zawartość okna +colormenusetup.menucontent_selected Wybrana zawartość okna +colormenusetup.menuhead Pasek tytuÅ‚u +colorstatusbar.head Kolory paska stanu +colorstatusbar.text Pasek stanu +colorthememenu.classic_theme klasyczna +colorthememenu.dblue_theme DarkBlue +colorthememenu.dvb2k_theme DVB2000 +colorthememenu.head Wybór tematów +colorthememenu.neutrino_theme Neutrino +date.Apr Kwi +date.Aug Sie +date.Dec Gru +date.Feb Lut +date.Fri Pt +date.Jan Sty +date.Jul Lip +date.Jun Cze +date.Mar Mar +date.May Maj +date.Mon Pn +date.Nov Lis +date.Oct Paz +date.Sat So +date.Sep Wrz +date.Sun Ni +date.Thu Cz +date.Tue Wt +date.Wed Sr +epglist.head Lista programów - %s +epglist.noevents Informacje EPG sÄ… niedostÄ™pne +epgviewer.More_Screenings Kolejne emisje na tym kanale +epgviewer.nodetailed Brak szczegółowych informacji +epgviewer.notfound Nie znaleziono informacji programowych (EPG) +eventlistbar.channelswitch przeÅ‚Ä…cz +eventlistbar.eventsort sortuj +eventlistbar.recordevent nagraj +favorites.addchannel Bieżący kanaÅ‚ zostanie dodany do bukietu \n"Ulubione". \nProszÄ™ czekaç... +favorites.bouquetname Ulubione +favorites.bqcreated Utworzono kanaÅ‚y ulubione...\n +favorites.chadded Bieżący kanaÅ‚ zostaÅ‚ dodany do ulubionych...\n +favorites.chalreadyinbq Bieżący kanaÅ‚ znajduje siÄ™ już w ulubionych...\n +favorites.finalhint \nUżyj edytora bukietów, aby dokonaç\nzmian w ulubionych.\n +favorites.menueadd Dodaj kanaÅ‚ do ulubionych +favorites.nobouquets Funkcja jest dostÄ™pna wyÅ‚Ä…cznie przy wÅ‚Ä…czonych bukietach. +filebrowser.delete usuÅ„ +filebrowser.denydirectoryleave Montuj jako główny katalog +filebrowser.dodelete1 usuÅ„ +filebrowser.dodelete2 ? +filebrowser.filter.active wÅ‚Ä…cz filtr +filebrowser.filter.inactive wyÅ‚Ä…cz filtr +filebrowser.head PrzeglÄ…darka plików +filebrowser.mark zaznacz +filebrowser.nextpage nast.strona +filebrowser.prevpage poprz.strona +filebrowser.scan Trwa wyszukiwanie... +filebrowser.select wybierz +filebrowser.showrights Pokaż uprawnienia plików +filebrowser.sort.date (data) +filebrowser.sort.name (pliki) +filebrowser.sort.namedirsfirst (kat,pliki) +filebrowser.sort.size (rozmiar) +filebrowser.sort.type (typ) +flashupdate.actionreadflash reading +flashupdate.cantopenfile Nie można otworzyç pliku +flashupdate.cantopenmtd Nie można otworzyç urzÄ…dzenia MTD +flashupdate.checkupdate Szukaj nowej wersji +flashupdate.currentreleasecycle Cykl wersji +flashupdate.currentversion_sep Zainstalowana wersja +flashupdate.currentversiondate Data +flashupdate.currentversionsnapshot Typ obrazu +flashupdate.currentversiontime Godzina +flashupdate.erasefailed Kasowanie pamiÄ™ci nie powiodÅ‚o siÄ™ +flashupdate.erasing Kasuj pamięç flash +flashupdate.experimentalimage Wybrano obraz stanu. Należy wziąç pod uwagÄ™, że wersja ta nie\nzostaÅ‚a sprawdzona, a tuner może nie dziaÅ‚aç po wykonaniu\naktualizacji.\n\nCzy na pewno chcesz zainstalowaç tÄ™ wersjÄ™? +flashupdate.expertfunctions Funkcje zaawansowane +flashupdate.fileis0bytes Wielkość pliku wynosi 0 bajtów +flashupdate.fileselector Wybór pliku +flashupdate.flashreadyreboot Programowanie obrazu powiodÅ‚o siÄ™.\nBox zostanie uruchomiony ponownie. +flashupdate.getinfofile Trwa sprawdzanie wersji +flashupdate.getinfofileerror Nie można sprawdziç wersji +flashupdate.getupdatefile ZaÅ‚aduj aktualizacjÄ™ +flashupdate.getupdatefileerror Nie można zaÅ‚adowaç aktualizacji +flashupdate.globalprogress PostÄ™p caÅ‚kowity: +flashupdate.head Aktualizacja +flashupdate.md5check Kontrola obrazu +flashupdate.md5sumerror NieprawidÅ‚owy obraz +flashupdate.msgbox Znaleziono nowy file:\nData: %s, %s\nObraz podstawowy: %s\nTyp: %s\n\nCzy chcesz teraz pobraç i zainstalowaç\nten obraz? +flashupdate.msgbox_manual Znaleziono nowy obrazu:\nData: %s, %s\nObraz podstawowy: %s\nTyp obrazu: %s\n\nCzy chcesz teraz zainstalowaç\nten obraz? +flashupdate.mtdselector Wybór partycji +flashupdate.programmingflash Programowanie pamiÄ™ci flash +flashupdate.proxypassword HasÅ‚o +flashupdate.proxypassword_hint1 Wpisz hasÅ‚o serwera proxy +flashupdate.proxypassword_hint2 Pusty wpis oznacza brak hasÅ‚a +flashupdate.proxyserver Nazwa serwera proxy +flashupdate.proxyserver_hint1 Wpisz nazwÄ™ serwera proxy lub IP (host:port) +flashupdate.proxyserver_hint2 Pusty wpis oznacza brak serwera proxy +flashupdate.proxyserver_sep Serwer proxy +flashupdate.proxyusername Nazwa użytkownika +flashupdate.proxyusername_hint1 Wpisz nazwÄ™ użytkownika serwera proxy +flashupdate.proxyusername_hint2 Pusty wpis oznacza brak autoryzacji +flashupdate.readflash odczytaj caÅ‚y obraz z pamiÄ™ci flash +flashupdate.readflashmtd odczytaj pojedynczÄ… partycjÄ™ +flashupdate.ready Gotowe. +flashupdate.reallyflashmtd Czy na pewno chcesz wykonaç programowanie?\n\nW przypadku wystÄ…pienia bÅ‚Ä™du lub nieprawidÅ‚owego obrazu\n box nie wystartuje.\n\nNazwa obrazu: %s\nCel: %s +flashupdate.savesuccess Obraz zostaÅ‚ zapisany pomyÅ›lnie\npod nazwÄ… %s. +flashupdate.selectimage DostÄ™pne obrazy/files +flashupdate.squashfs.noversion SquashFS version checks are currently only supported when updating over the web.\nAre you sure that you wish to install this image? +flashupdate.titlereadflash Odczyt pamiÄ™ci flash +flashupdate.titlewriteflash Zapis pamiÄ™ci flash +flashupdate.updatemode Tryb aktualizacji +flashupdate.updatemode_internet Internet +flashupdate.updatemode_manual rÄ™czny (ftp) +flashupdate.url_file Plik konfiguracyjny +flashupdate.versioncheck Kontrola wersji +flashupdate.writeflash wgraj caÅ‚y obraz do pamiÄ™ci flash +flashupdate.writeflashmtd wgraj pojedynczÄ… partycjÄ™ +flashupdate.wrongbase flashupdate.wrongbase Your Release cycle differs.\nTo continue? +fontmenu.channellist Lista kanałów +fontmenu.epg EPG +fontmenu.eventlist Lista programów +fontmenu.gamelist Lista gier +fontmenu.head Ustawienia wielkoÅ›ci czcionki +fontmenu.infobar Pasek informacyjny +fontsize.channel_num_zap Bez funkcji +fontsize.channellist Lista kanałów +fontsize.channellist_descr Opis +fontsize.channellist_number Numer +fontsize.epg_date Data EPG +fontsize.epg_info1 Informacja EPG 1 +fontsize.epg_info2 Informacja EPG 2 +fontsize.epg_title TytuÅ‚ EPG +fontsize.eventlist_datetime Data / godzina listy programów +fontsize.eventlist_itemlarge Duża lista programów +fontsize.eventlist_itemsmall MaÅ‚a lista programów +fontsize.eventlist_title TytuÅ‚ listy programów +fontsize.filebrowser_item Wpis przeglÄ…darki plików +fontsize.gamelist_itemlarge duża +fontsize.gamelist_itemsmall maÅ‚a +fontsize.hint Trwa inicjalizowanie czcionki,\nproszÄ™ czekaç... +fontsize.infobar_channame Nazwa kanaÅ‚u +fontsize.infobar_info Informacja na pasku +fontsize.infobar_number KanaÅ‚ na pasku informacyjnym +fontsize.infobar_small MaÅ‚y pasek informacyjny +fontsize.menu Tekst menu +fontsize.menu_info Menu informacyjne +fontsize.menu_title TytuÅ‚ menu +gtxalpha.alpha1 1 +gtxalpha.alpha2 2 +infoviewer.epgnotload Informacje nie zostaÅ‚y jeszcze odczytane... +infoviewer.epgwait Trwa odczytywanie informacji EPG... +infoviewer.eventlist prog +infoviewer.languages jÄ™zyk +infoviewer.motor_moving Ustawienie anteny +infoviewer.nocurrent Brak informacji o bieżącym programie +infoviewer.noepg Informacje EPG sÄ… niedostÄ™pne +infoviewer.notavailable KanaÅ‚ (obecnie) niedostÄ™pny. +infoviewer.selecttime Czasy rozpoczÄ™cia +infoviewer.streaminfo funkcje +infoviewer.subservice PodusÅ‚ugi +infoviewer.waittime Trwa odczytywanie godziny... +ipsetup.hint_1 Wpisz 0...9 lub naciÅ›nij klawisz góra/dół +ipsetup.hint_2 OK = zapis, HOME = anuluj +keybindingmenu.RC Ustawienia pilota +keybindingmenu.addrecord Dodaj nagrywanie +keybindingmenu.addremind Dodaj zmianÄ™ kanaÅ‚u +keybindingmenu.allchannels_on_ok lista kanałów +keybindingmenu.bouquetchannels_on_ok bieżący bukiet +keybindingmenu.bouquetdown Poprzedni bukiet +keybindingmenu.bouquethandling Klawisz OK +keybindingmenu.bouquetlist_on_ok lista bukietów +keybindingmenu.bouquetup NastÄ™pny bukiet +keybindingmenu.cancel Zamknij listÄ™ kanałów +keybindingmenu.channeldown NastÄ™pny kanaÅ‚ +keybindingmenu.channellist Lista kanałów +keybindingmenu.channelup Poprzedni kanaÅ‚ +keybindingmenu.head Konfiguracja klawiszy +keybindingmenu.lastchannel Quick Zap +keybindingmenu.modechange Zmiana trybu +keybindingmenu.pagedown NastÄ™pna strona +keybindingmenu.pageup Poprzednia strona +keybindingmenu.quickzap Szybkie przeÅ‚Ä…czanie kanałów +keybindingmenu.repeatblock Opóźnienie powtarzania +keybindingmenu.repeatblockgeneric Opóźnienie poczÄ…tkowe +keybindingmenu.sort ZmieÅ„ kolejność sortowania +keybindingmenu.subchanneldown Poprzedni podkanaÅ‚ +keybindingmenu.subchannelup NastÄ™pny podkanaÅ‚ +keybindingmenu.tvradiomode TV / Radio +keybindingmenu.zaphistory Zapping History Bouquet +keychooser.head Ustaw nowy klawisz +keychooser.text1 NaciÅ›nij klawisz +keychooser.text2 Czekaj, aby anulowaç... +keychoosermenu.currentkey bieżący klawisz +keychoosermenu.setnew ustaw nowy klawisz +keychoosermenu.setnone brak klawisza +languagesetup.head Ustawienia jÄ™zykowe +languagesetup.select JÄ™zyk +lcdcontroler.brightness Jasność +lcdcontroler.brightnessstandby Tryb gotowoÅ›ci +lcdcontroler.contrast Kontrast +lcdcontroler.head Ustawienia LCD +lcdmenu.autodimm Automatyczne przyciemnianie +lcdmenu.head Ustawienia LCD +lcdmenu.inverse Inwersja +lcdmenu.lcdcontroler Kontrast / Jasność +lcdmenu.power Zasilanie +lcdmenu.statusline Pasek stanu +lcdmenu.statusline.both gÅ‚oÅ›ność / czas +lcdmenu.statusline.playtime czas +lcdmenu.statusline.volume gÅ‚oÅ›ność +mainmenu.audioplayer Odtwarzacz MP3 +mainmenu.games Gry +mainmenu.head Menu główne +mainmenu.movieplayer Odtwarzacz filmów +mainmenu.pausesectionsd Czytaj informacje EPG +mainmenu.pictureviewer PrzeglÄ…darka obrazów +mainmenu.radiomode Radio +mainmenu.recording Nagrywanie +mainmenu.recording_start START +mainmenu.recording_stop STOP +mainmenu.scartmode EurozÅ‚Ä…cze +mainmenu.service UsÅ‚ugi +mainmenu.settings Konfiguracja +mainmenu.shutdown WyÅ‚Ä…cz +mainmenu.sleeptimer WyÅ‚Ä…cznik czasowy +mainmenu.tvmode TV +mainsettings.audio DźwiÄ™k +mainsettings.colors Kolory / tematy / czcionki +mainsettings.head Konfiguracja +mainsettings.keybinding Konfiguracja klawiszy +mainsettings.language JÄ™zyk +mainsettings.lcd WyÅ›wietlacz LCD +mainsettings.misc Inne ustawienia +mainsettings.network Sieç +mainsettings.recording Nagrywanie +mainsettings.savesettingsnow zapisz ustawienia +mainsettings.savesettingsnow_hint Trwa zapisywanie ustawieÅ„,\nproszÄ™ czekaç... +mainsettings.streaming Odtwarzacz filmów +mainsettings.video Obraz +menu.back wstecz +messagebox.back Wróç +messagebox.cancel Anuluj +messagebox.discard Czy chcesz odrzuciç zmiany? +messagebox.error BÅ‚Ä…d +messagebox.info Informacja +messagebox.no NIE +messagebox.yes TAK +miscsettings.bootinfo Informacje przy starcie +miscsettings.bootmenu Show boot menu +miscsettings.driver_boot Ustawienia zaawansowane +miscsettings.fb_destination Konsola startowa +miscsettings.general Ustawienia ogólne +miscsettings.head Inne ustawienia +miscsettings.hwsections użyj hardware sections +miscsettings.infobar_sat_display WyÅ›wietlanie nazwy satelity +miscsettings.pmtupdate enable pmt update +miscsettings.shutdown_real Tryb gotowoÅ›ci +miscsettings.shutdown_real_rcdelay Opóźnione wyÅ‚Ä…czenie +miscsettings.sptsmode użyj trybu SPTS +miscsettings.startbhdriver zaÅ‚aduj sterowniki BH +motorcontrol.head Konfiguracja siÅ‚ownika +movieplayer.bookmark ZakÅ‚adki +movieplayer.bookmarkname Nazwa zakÅ‚adki +movieplayer.bookmarkname_hint1 Podaj nazwÄ™ nowej zakÅ‚adki +movieplayer.bookmarkname_hint2 +movieplayer.buffering Trwa buforowanie... +movieplayer.defdir Katalog startowy +movieplayer.dvdplayback DVD +movieplayer.fileplayback Plik przez VLC +movieplayer.goto Skocz do ... +movieplayer.goto.h1 = -> skok bezwzglÄ™dny +movieplayer.goto.h2 +,- -> skok wzglÄ™dny +movieplayer.head Odtwarzacz filmów +movieplayer.nostreamingserver NawiÄ…zanie poÅ‚Ä…czenia z serwerem\nstrumieniowania nie powiodÅ‚o siÄ™. +movieplayer.pesplayback Odtwarzaj PES (experimental) +movieplayer.pleasewait ProszÄ™ czekaç. Trwa nawiÄ…zywanie\npoÅ‚Ä…czenia z serwerem strumieniowania. +movieplayer.toomanybookmarks Za dużo zakÅ‚adek.\nAby dodaç kolejnÄ… musisz jednÄ… usunąç. +movieplayer.tsplayback Odtwarzaj TS +movieplayer.vcdplayback (S)VCD +movieplayer.wrongvlcversion Ta opcja nie jest wspierana przez twojÄ… wersjÄ™ VLC +networkmenu.broadcast RozgÅ‚aszanie +networkmenu.dhcp Pobierz z DHCP +networkmenu.gateway Brama domyÅ›lna +networkmenu.head Konfiguracja sieci +networkmenu.ipaddress Adres IP +networkmenu.mount Zasoby sieciowe +networkmenu.nameserver Serwer nazw +networkmenu.netmask Maska podsieci +networkmenu.setupnow Zastosuj ustawienia +networkmenu.setuponstartup Zastosuj podczas uruchamiania +networkmenu.show Pokaż bieżące ustawienia +networkmenu.test Testuj ustawienia sieci +nfs.alreadymounted Katalog jest już podÅ‚Ä…czony. +nfs.automount PodÅ‚Ä…cz przy uruchamianiu +nfs.dir Katalog/zasób współużytkowany +nfs.ip IP serwera NFS/CIFS +nfs.localdir Patalog lokalny +nfs.mount PodÅ‚Ä…cz katalog +nfs.mount_options Parametry +nfs.mounterror BÅ‚Ä…d podÅ‚Ä…czenia +nfs.mounterror_notsup NieobsÅ‚ugiwany system plików. +nfs.mountnow PodÅ‚Ä…cz teraz +nfs.mounttimeout BÅ‚Ä…d podÅ‚Ä…czenia: upÅ‚ynÄ…Å‚ limit czasu +nfs.password HasÅ‚o CIFS +nfs.remount OdÅ›wież +nfs.type Typ +nfs.type_cifs CIFS +nfs.type_nfs NFS +nfs.umount OdÅ‚Ä…cz katalog +nfs.umounterror BÅ‚Ä…d przy odÅ‚Ä…czaniu +nfs.username Nazwa użytkownika CIFS +nfsmenu.head Ustawienia NFS/CIFS +nvod.percentage (minęło: %d%% min) +nvod.starting (rozpoczÄ™cie za %d min) +nvodselector.directormode Widok +nvodselector.head Wybierz czas rozpoczÄ™cia +nvodselector.subservice Perspektywy +options.default przywróç wartoÅ›ci domyÅ›lne +options.fb ekran +options.null brak +options.off NIE +options.on TAK +options.serial serial +parentallock.changepin Zmiana kodu PIN +parentallock.changepin_hint1 Wpisz nowy kod PIN! +parentallock.changetolocked zablokowane bukiety +parentallock.head Blokada rodzicielska +parentallock.lockage Blokuj programy +parentallock.lockage12 od 12-tu lat +parentallock.lockage16 od 16-tu lat +parentallock.lockage18 od 18-tu lat +parentallock.lockedchannel KanaÑ– zablokowany... +parentallock.lockedprogram Program zablokowany (od lat %d) +parentallock.never nigdy +parentallock.onsignal po wysÅ‚aniu blokady +parentallock.parentallock Blokada rodzicielska +parentallock.prompt żądanie kodu PIN +pictureviewer.defdir Katalog startowy +pictureviewer.head PrzeglÄ…darka obrazów +pictureviewer.resize.color_average zaawansowane +pictureviewer.resize.none brak +pictureviewer.resize.simple proste +pictureviewer.scaling Rodzaj skalowania +pictureviewer.show WyÅ›wietl +pictureviewer.slide_time Czas wyÅ›wietlania pokazu slajdów +pictureviewer.slideshow Pokaz slajdów +pictureviewer.sortorder ZmieÅ„ kolejność sortowania +pictureviewer.sortorder.date (data) +pictureviewer.sortorder.filename (nazwa pliku) +ping.ok jest dostÄ™pny (ping) +ping.protocol jest niedostÄ™pny (bÅ‚Ä…d hosta lub protokoÅ‚u) +ping.socket jest niedostÄ™pny (bÅ‚Ä…d gniazda) +ping.unreachable jest niedostÄ™pny +pinprotection.head Wpisz kod PIN +pinprotection.wrongcode Wpisz ponownie kod PIN! +rclock.lockmsg sterowanie boxem zostanie zablokowane\n\naby je przywróciç naciÅ›nij [RED], a nastÄ™pnie [DBOX] +rclock.menueadd Blokada sterowania +rclock.title Blokada sterowania +rclock.unlockmsg sterowanie zostaÅ‚o przywrócone +recordingmenu.defdir Nagrywaj do katalogu +recordingmenu.file dysk +recordingmenu.head Ustawienia nagrywania +recordingmenu.help UrzÄ…dzenia nagrywajÄ…ce:\n--------------------------------------\nserwer:\nwykorzystuje serwer strumieniowania\n\nmagnetowid:\nwykorzystuje gniazdo magnetowidu (drugi scart)\n\ndysk:\nwykorzystuje zasób sieciowy (NFS)\nlub wewnÄ™trzny dysk twardy\nTS: używaj trybu SPTS(Dbox2)\nPES: nie używaj trybu SPTS(Dbox2)\n\n\nMaksymalny rozmiar pliku:\n---------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: bez ograniczeÅ„ (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB)\n\nDla NFS (UDP) zaleca siÄ™ zapis synchroniczny +recordingmenu.no_scart Nie przeÅ‚Ä…czaj w tryb SCART +recordingmenu.off wyÅ‚Ä…czone +recordingmenu.recording_type UrzÄ…dzenie nagrywajÄ…ce +recordingmenu.server serwer +recordingmenu.server_ip Adres IP serwera +recordingmenu.server_mac Adres Mac serwera (WoL) +recordingmenu.server_port Port serwera +recordingmenu.server_wakeup Budzenie serwera (WoL) +recordingmenu.setupnow Zastosuj ustawienia +recordingmenu.splitsize Dziel plik na części (MB) +recordingmenu.stopplayback Zatrzymaj playback +recordingmenu.stopsectionsd Zatrzymaj sectionsd +recordingmenu.stream_vtxt_pid Nagrywaj teletext +recordingmenu.use_o_sync Zapis synchroniczny (O_SYNC) +recordingmenu.vcr magnetowid +recordtimer.announce Za kilka minut rozpocznie siÄ™ nagrywanie. +repeatblocker.hint_1 Czas opóźnienia miÄ™dzy 2 naciÅ›niÄ™ciami klawiszy +repeatblocker.hint_2 0 = wyÅ‚Ä…czenie blokady (przycisk czerwony) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat Liczba powtórzeÅ„ DiSEqC +satsetup.extended Konfiguracja DiSEqC +satsetup.extended_motor Konfiguracja siÅ‚ownika +satsetup.minidiseqc mini-DiSEqC +satsetup.motorcontrol RÄ™czna konfiguracja siÅ‚ownika +satsetup.nodiseqc brak DiSEqC +satsetup.satellite Satelita +satsetup.savesettingsnow zapisz ustawienia +satsetup.smatvremote strojenie zdalne SMATV +scants.actcable Kabel: +scants.actsatellite Satelita: +scants.bouquet Bukiety +scants.bouquet_create utwórz nowe +scants.bouquet_erase usuÅ„ +scants.bouquet_leave bez zmian +scants.bouquet_satellite bukiet pozycji sat. +scants.bouquet_update aktualizuj +scants.channel KanaÅ‚: +scants.failed Wyszukiwanie kanałów nie powiodÅ‚o siÄ™! +scants.finished Wyszukiwanie kanałów powiodÅ‚o siÄ™! +scants.freqdata CzÄ™stotliwość: +scants.head Wyszukiwanie kanałów +scants.numberofdataservices Dane +scants.numberofradioservices Radio +scants.numberoftotalservices Ogółem +scants.numberoftvservices TV +scants.provider Dostawca: +scants.startnow Uruchom wyszukiwanie +scants.transponders Transponder: +screensetup.lowerright zielony = dolna, prawa kraw. +screensetup.upperleft czerwony = górna, lewa kraw. +servicemenu.head UsÅ‚ugi +servicemenu.reload PrzeÅ‚aduj listy kanałów +servicemenu.reload_hint Trwa przeÅ‚adowywanie list kanałów, \nproszÄ™ czekaç... +servicemenu.scants Wyszukaj kanaÅ‚y +servicemenu.ucodecheck Sprawdź wersje uCodes +servicemenu.update Aktualizuj oprogramowanie +settings.help Pomoc +settings.missingoptionsconffile Ustawienia Neutrino zostaÅ‚y rozszerzone.\nDla nowych opcji zostanÄ… okreÅ›lone wartoÅ›ci domyÅ›lne. +settings.noconffile Nie można odnaleźç ustawieÅ„ Neutrino.\nZostanÄ… użyte wartoÅ›ci domyÅ›lne. +shutdowntimer.announce Tuner zostanie wyÅ‚Ä…czony za minutÄ™.\nCzy chcesz anulowaç proces? +sleeptimerbox.announce Tuner zostanie wyÅ‚Ä…czony za minutÄ™ +sleeptimerbox.hint1 Czas do wyÅ‚Ä…czenia w min. (000=wyÅ‚) +sleeptimerbox.hint2 Po upÅ‚ywie tego czasu, tuner zostanie wyÅ‚Ä…czony +sleeptimerbox.title WyÅ‚Ä…cznik czasowy +streamfeatures.head Funkcje +streaminfo.aratio Format obrazu +streaminfo.aratio_unknown Format obrazu: nieznany +streaminfo.audiotype Format dźwiÄ™ku +streaminfo.audiotype_unknown Audiotype: unknown +streaminfo.bitrate Szybkość transmisji +streaminfo.framerate Szybkość klatek +streaminfo.framerate_unknown Szybkość klatek: nieznana +streaminfo.head Stream-Information +streaminfo.not_available niedostÄ™pny +streaminfo.resolution test +streaminfo.signal Parametry sygnaÅ‚u +streaming.buffer_overflow Nagrywanie zostaÅ‚o przerwane\nz powodu zbyt dużych opóźnieÅ„ w zapisie. +streaming.busy Proces nagrywania wciąż trwa.\nJeÅ›li komunikat ten siÄ™ powtarza i nie jesteÅ› w trakcie nagrywania,\nzrestartuj Neutrino. +streaming.dir_not_writable Brak możliwoÅ›ci zapisu do katalogu nagrywania.\nNagrywanie nie bÄ™dzie dziaÅ‚aç. +streaming.success Nagrywanie zakoÅ„czone sukcesem. +streaming.write_error Nagrywanie zostaÅ‚o przerwane\nz powodu bÅ‚Ä™du w trakcie zapisu. +streaming.write_error_open Nagrywanie zostaÅ‚o przerwane\nz powodu bÅ‚Ä™du otwarcia pliku do zapisu. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Ustawienia odtwarzacza filmów +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off wyÅ‚Ä…czony +streamingmenu.on wÅ‚Ä…czony +streamingmenu.server_ip IP serwera strumieniowania +streamingmenu.server_port Port serwera strumieniowania +streamingmenu.streaming_audiorate Szybkość transmisji dźwiÄ™ku +streamingmenu.streaming_force_avi_rawaudio WymuÅ› AC3 dla AVI +streamingmenu.streaming_force_transcode_video Transkoduj obraz (MPG/VCD) +streamingmenu.streaming_resolution Rozdzielczość +streamingmenu.streaming_server_cddrive NapÄ™d DVD +streamingmenu.streaming_server_startdir Katalog (VLC) +streamingmenu.streaming_transcode_audio Transkoduj dźwiÄ™k (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec Kodowanie obrazu +streamingmenu.streaming_type Serwer strumieniowania +streamingmenu.streaming_videorate Szybkość transmisji obrazu +streamingserver.noconnect Brak poÅ‚Ä…czenia z serwerem strumieniowym.\nNagrywanie zostanie przerwane. +stringinput.caps wielkie/maÅ‚e litery +stringinput.clear usuÅ„ wszystko +timer.eventrecord.msg Program zostanie nagrany. +timer.eventrecord.title zapamiÄ™taj nagrywanie +timer.eventtimed.msg Program zostaÅ‚ zapamiÄ™tany. +timer.eventtimed.title zapamiÄ™taj program +timerbar.channelswitch przeÅ‚Ä…cz +timerbar.recordevent nagraj +timerlist.alarmtime Godzina alarmu +timerlist.apids PIDy audio +timerlist.bouquetselect wybierz bukiet +timerlist.channel kanaÅ‚ +timerlist.channelselect wybierz kanaÅ‚ +timerlist.delete usuÅ„ +timerlist.menumodify edytuj zegar +timerlist.menunew nowy zegar +timerlist.message Wiadomość +timerlist.moderadio KanaÅ‚y radiowe +timerlist.modeselect wybierz tryb +timerlist.modetv KanaÅ‚y TV +timerlist.modify edytuj +timerlist.name Lista zegarów +timerlist.new nowy zegar +timerlist.program.unknown Nieznany program +timerlist.reload aktualizuj +timerlist.repeat Powtórzenie +timerlist.repeat.biweekly dwa razy w tygodniu +timerlist.repeat.byeventdescription patrz zegar +timerlist.repeat.daily codziennie +timerlist.repeat.fourweekly cztery razy w tygodniu +timerlist.repeat.friday Pt +timerlist.repeat.monday Po +timerlist.repeat.monthly raz w miesiÄ…cu +timerlist.repeat.once jednorazowo +timerlist.repeat.saturday So +timerlist.repeat.sunday Nd +timerlist.repeat.thursday Cz +timerlist.repeat.tuesday Wt +timerlist.repeat.unknown nieznane +timerlist.repeat.wednesday Sr +timerlist.repeat.weekdays w dni powszednie +timerlist.repeat.weekly dni tygodnia +timerlist.save zapisz zegar +timerlist.standby Tryb stanu +timerlist.standby.off ze stanu gotowoÅ›ci +timerlist.standby.on w stan gotowoÅ›ci +timerlist.stoptime godzina zatrzymania +timerlist.type Typ zegara +timerlist.type.nextprogram Kolejny program +timerlist.type.record nagrywanie +timerlist.type.remind przypomnienie +timerlist.type.shutdown zamkniÄ™cie systemu +timerlist.type.sleeptimer wyÅ‚Ä…cznik czasowy +timerlist.type.standby tryb gotowoÅ›ci +timerlist.type.unknown nieznane +timerlist.type.zapto przeÅ‚Ä…cz +timerlist.weekdays w dni powszednie +timerlist.weekdays.hint_1 Pn Wt Sr Cz Pt So Ni +timerlist.weekdays.hint_2 'X'=zegar '-' brak zegara +timersettings.record_safety_time_after Korekta koÅ„ca nagrywania +timersettings.record_safety_time_after.hint_1 Czas w min. (00=wyÅ‚), który zostanie dodany +timersettings.record_safety_time_after.hint_2 po zakoÅ„czeniu danego zegara +timersettings.record_safety_time_before Korekta poczÄ…tku nagrywania +timersettings.record_safety_time_before.hint_1 Czas w min. (00=wyÅ‚), który zostanie odjÄ™ty +timersettings.record_safety_time_before.hint_2 przy uruchamianiu danego zegara +timersettings.separator Ustawienia zegara +timing.chanlist Lista kanałów +timing.epg Epg +timing.filebrowser PrzeglÄ…darka plików +timing.head Czasy wyÅ›wietlania OSD +timing.hint_1 Czas wyÅ›wietlania OSD +timing.hint_2 na ekranie TV (w sekundach) +timing.infobar Pasek informacyjny +timing.menu Menu +timing.numericzap Numeric Zap +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head Wersje uCodes +ucodecheck.ucode uCode +ucodes.failure Uwaga, uCodes NIE zostaÅ‚y znalezione!\n\nWyÅ›lij pliki przez FTP (lub za pomocÄ…\nprogramu DBox-BootManager) i uruchom ponownie tuner box! +videomenu.csync korekcja synchronizacji +videomenu.head Ustawienia obrazu +videomenu.rgb_centering wyÅ›rodkowanie RGB +videomenu.screensetup Ustaw widocznÄ… część obrazu +videomenu.vcrswitch PrzeÅ‚Ä…czanie EurozÅ‚Ä…cza +videomenu.videoformat Format obrazu +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect automatyczny +videomenu.videosignal SygnaÅ‚ wideo +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce Za minutÄ™ zostanie zmieniony kanaÅ‚. +extra.auto automatycznie +extra.valid wÅ‚aÅ›ciwe +extra.all wszystkie +extra.new_keys tylko nowe klucze +extra.all_keys wszystkie klucze +extra.vartmp /var/tmp +extra.varkeys /var/keys +extra.algo znanych algorytmów +extra.gbox_emu emulator +extra.gbox_softcam softcam +extra.gbox_net klient sieciowy +extra.gbox_mix emu+softcam+klient +extra.gbox_info Informacje gbox +extra.sep_extra Inne +extra.save_settings zapisz ustawienia +extra.extra_menu Dodatki +extra.ecm_info Pokaż ECM +extra.pid_info Pokaż PID +extra.emm_info Pokaż EMM +extra.emu_type Emulacja +extra.camd Typ emulatora +extra.restart_camd Uruchom ponownie emulator +extra.mg_settings Ustawienia mgcamd +extra.netmode Typ klienta sieciowego +extra.autoupdate Aktualizuj klucze +extra.show_ecm Pokazuj ECM +extra.show_emm Pokazuj EMM +extra.keyupdate Tryb aktualizacji +extra.osd Informacje ekranowe +extra.keyfolder Katalog z kluczami +extra.hash_pids Przetwarzaj PIDy +extra.gbox_settings Ustawienia gbox +extra.gbox_mode Tryb +extra.newcamd_settings Ustawienia newcamd +extra.show_cw Pokazuj CW +extra.debug_ecm Analizuj ECM +extra.disable_cam WyÅ‚Ä…cz CAM +extra.show_cat Pokazuj CAT +extra.show_pmt Pokazuj PMT +extra.update_pmt OdÅ›wieżaj PMT +extra.report_emm Raportuj zÅ‚e sygnatury EMM +extra.debug_emm Analizuj Emm +extra.show_allca Pokazuj wszystkie CA +extra.reload_keys PrzeÅ‚aduj klucze przy zm.kanaÅ‚u +extra.reload_cfg PrzeÅ‚aduj konfiguracje przy zm.kanaÅ‚u +extra.cw_delay Standardowe opóznienie zapisu CW +extra.dvbsnoop Informacje o strumieniu DVB +extra.dvbsnoop_pat Pokaż PAT +extra.dvbsnoop_cat Pokaż CAT +extra.dvbsnoop_tsdt Pokaż TSDT +extra.dvbsnoop_nit Pokaż NIT +extra.dvbsnoop_sdt Pokaż SDT +extra.dvbsnoop_eit Pokaż EIT +extra.dvbsnoop_rst Pokaż RST +extra.dvbsnoop_tdt Pokaż TDT +extra.dvbsnoop_sit Pokaż SIT +extra.dvbsnoop_pid Wybierz PID +extra.dvbsnoop_scan Skanuj PIDy +extra.dvbsnoop_band Pokaż szybkość przesyÅ‚u danych +extra.logview Pokaż /tmp/log +extra.ru ruDREAM +extra.english Wybieranie angielskiej Å›cieżki +extra.dboxinfo Informacje o systemie +extra.scan_mode Tryb wyszukiwania +extra.start_tostandby Uruchom w trybie czuwania +extra.rotor_swap ZamieÅ„ kierunki obrotnicy +extra.use_log Loguj do /tmp/log +extra.spts_mode Tryb SPTS +extra.hw_sect SprzÄ™towe przetwarzanie sekcji +extra.logo Logo startowe +extra.scan_full peÅ‚ne +extra.scan_fast szybkie +extra.hdd_slow Slow +extra.hdd_middle Middle +extra.hdd_fast Fast +extra.hdd_ext3 Ext3fs +extra.hdd_reiser Reiserfs +extra.hdd_1min 1 min. +extra.hdd_5min 5 min. +extra.hdd_10min 10 min. +extra.hdd_20min 20 min. +extra.hdd_30min 30 min. +extra.hdd_60min 60 min. +extra.logo1 1 +extra.logo2 2 +extra.logo3 3 +extra.hdd_sleep Sleep time +extra.hdd_noise Noise +extra.hdd_activate Activate settings +extra.hdd_fs Filesystem +extra.hdd_format Format HDD +extra.hdd_check Check filesystem +extra.hdd_settings HDD Settings +extra.clear_log Clear Log +extra.zap_cycle WyÅ‚Ä…cz historiÄ™ programów +extra.sms_channel sms-mode channel +extra.manual_scan Manual scan +extra.tp_freq Frequency +extra.tp_rate Symbol rate +extra.tp_pol Polarization +extra.tp.pol_v V +extra.tp_pol_h H +extra.tp_fec FEC +extra.fec_1_2 1/2 +extra.fec_2_3 2/3 +extra.fec_3_4 3/4 +extra.fec_5_6 5/6 +extra.fec_7_8 7/8 +extra.timezone Timezone +extra.zapit_menu Zapit options +extra.zapit_make_bouquet Make Remaining Channels list +extra.zapit_save_last_chan Save last channel +extra.zapit_motor_speed Motor moving speed (10 = 1deg/sec) +extra.zapit_fe_timeout Tune timeout +extra.add_to_bouquet Add to bouquet +extra.key_list_start home +extra.key_list_end end +extra.chadded The current channel has been added to selected bouquet....\n +extra.chalreadyinbq The current channel is already in selected bouquet....\n +extra.menu_left_exit "Left" = menu back +extra.zapit_write_names Write channel names +extra.update_dir Directory for updates +extra.cache Cache +extra.debug Debug +extra.zapit_backup Backup channels to /tmp +extra.zapit_delete Delete channels +extra.zapit_fast_zap fast zap +extra.zapit_restore Restore channels from /tmp +extra.zapit_sort_names Sort ch. by name +filesystem.is.utf8 file system +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +infoviewer.subchan_disp_pos Subchannel display +mainmenu.scripts Scripts +miscsettings.noaviawatchdog enable AVIA watchdog +miscsettings.noenxwatchdog enable eNX watchdog +movieplayer.defplugin Start-Plugin +movieplayer.tshelp1 Stop +movieplayer.tshelp10 approx. 10 minutes back +movieplayer.tshelp11 skip approx. 10 minutes +movieplayer.tshelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Select audio track +movieplayer.tshelp3 Pause/Continue +movieplayer.tshelp4 Create bookmark +movieplayer.tshelp5 Show progress +movieplayer.tshelp6 approx. 1 minute back +movieplayer.tshelp7 skip approx. 1 minute +movieplayer.tshelp8 approx. 5 minutes back +movieplayer.tshelp9 skip approx. 5 minutes +movieplayer.vlchelp1 Stop +movieplayer.vlchelp10 approx. 10 minutes back +movieplayer.vlchelp11 skip approx. 10 minutes +movieplayer.vlchelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Resync +movieplayer.vlchelp3 Pause/Continue +movieplayer.vlchelp4 Create bookmark +movieplayer.vlchelp5 Show progress +movieplayer.vlchelp6 approx. 1 minute back +movieplayer.vlchelp7 skip approx. 1 minute +movieplayer.vlchelp8 approx. 5 minutes back +movieplayer.vlchelp9 skip approx. 5 minutes +nfs.mountok mount successful +nfs.type_lufs FTPFS +pictureviewer.help1 menu mode +pictureviewer.help10 show mode +pictureviewer.help11 reread image +pictureviewer.help12 previous image +pictureviewer.help13 next image +pictureviewer.help14 Zoom out +pictureviewer.help15 Zoom in +pictureviewer.help16 scroll up +pictureviewer.help17 scroll left +pictureviewer.help18 scroll right +pictureviewer.help19 scroll down +pictureviewer.help2 display image +pictureviewer.help20 change sort order +pictureviewer.help21 reread image (no scaling) +pictureviewer.help22 exit +pictureviewer.help3 change sort order +pictureviewer.help4 do not scale picture +pictureviewer.help5 diashow mode +pictureviewer.help6 previous image +pictureviewer.help7 next image +pictureviewer.help8 change sort order +pictureviewer.help9 exit +plugins.result plugin output +recordingmenu.choose_direct_rec_dir choose dir on imm. recording +recordingmenu.epg_for_filename long filenames (with EPG data) +recordingmenu.filesettings direct recording settings +recordingmenu.ringbuffers no. of ringbuffers +recordingmenu.use_fdatasync write synchronous (fdatasync) +settings.pos_bottom_left bottom left +settings.pos_bottom_right bottom right +settings.pos_top_left oben top left +settings.pos_top_right oben top right +timerlist.plugin Plugin +timerlist.recording_dir recording directory +timerlist.repeatcount repeats +timerlist.repeatcount.help1 amount of timer repeats +timerlist.repeatcount.help2 0 for unlimited repeats +timerlist.type.execplugin Execute plugin +pictureviewer.decode_server_ip decode server ip +pictureviewer.decode_server_port decode server port +scants.abort_body Should the search really be aborted? +scants.abort_header Abortion of channel scan +recordingmenu.record_in_spts_mode switch to spts mode before recording +servicemenu.getplugins Reload plugins +servicemenu.getplugins_hint Reloading plugins,\nplease be patient. +zapit.scantype scan for services +zapit.scantype.all all services +zapit.scantype.radio only radio +zapit.scantype.tv only tv +zapit.scantype.tvradio tv & radio +colorthememenu.red_theme Simply Red +lcdmenu.dim_brightness Brightness after dim timeout +lcdmenu.dim_time Dim timeout +timerlist.overlapping_timer Timer conflict. Create the timer anyway? +extra.audio_run_player Audio key start player +mpkey.rewind Rewind +mpkey.forward Forward +mpkey.pause Pause +mpkey.stop Stop +mpkey.play Play +mpkey.audio Audio track +mpkey.time Show time +mpkey.bookmark save bookmark +mpkey.plugin Run plugin +extra.key_click Key click +extra.loadcolors Load colors from +extra.savecolors Save colors as +extra.loadkeys Load keys from +extra.savekeys Save keys as +extra.loadconfig Load settings from +extra.saveconfig Save settings as +videomenu.videomode Video system +videomenu.videomode_ntsc NTSC +videomenu.videomode_pal PAL +videomenu.videomode_palm PAL-M +extra.key_timeshift Timeshift +extra.key_plugin One touch plugin +extra.timeshift_pause Timeshift pause +rfmod.rfmod RF modulator +rfmod.carrier Subcarrier Frequency +rfmod.carrier4500 4.5 +rfmod.carrier5500 5.5 +rfmod.carrier6000 6.0 +rfmod.carrier6500 6.5 +rfmod.enable Enable sound +rfmod.channel Channel +rfmod.finetune Fine tune +rfmod.standby Enable modulator +rfmod.test Test pattern +extra.zapit_scanpids Scan/Use pids +extra.zapit_rezap_time Re-Zap on emu switch time +extra.zapit_hvoltage High (13.5/18.5) voltage +extra.key_unlock Unlock key +extra.mg_netoptions Network options +extra.mg_ecm_timeout Network ecm timeout +extra.mg_reconnect Shares reconnect +extra.mg_priority Share priority +extra.mg_osd_options Osd options +extra.mg_reread Reread files on zap +servicemenu.imageinfo Image info +imageinfo.creator Creator: +imageinfo.date Date: +imageinfo.dokumentation Docs: +imageinfo.forum Forum: +imageinfo.head Image info: +imageinfo.homepage Home page: +imageinfo.image Image: +imageinfo.license License: +imageinfo.version Version: +extra.cache_txt Cache teletext +extra.use_gotoxx Use gotoXX +extra.latitude Latitude +extra.longitude Longitude +extra.ladirection LaDirection +extra.lodirection LoDirection +extra.south South +extra.north North +extra.east East +extra.west West +epgextended.actors Actors +epgextended.director Director +epgextended.guests Guests +epgextended.original_title Original Title +epgextended.presenter Presenter +epgextended.year_of_production Year of Production +recordingmenu.save_in_channeldir Save in channel dir +servicemenu.restart Soft restart +servicemenu.restart_failed Restart failed +servicemenu.restart_hint Restarting, please wait +servicemenu.restart_refused_recording Cant restart, recording in progress +extra.cs Cardserver +extra.restart_cs Restart cardserver +extra.tp_mod Modulation +extra.tp_mod_16 QAM/16 +extra.tp_mod_32 QAM/32 +extra.tp_mod_64 QAM/64 +extra.tp_mod_128 QAM/128 +extra.tp_mod_256 QAM/256 +moviebrowser.book_head Bookmarks +moviebrowser.book_lastmoviestop Last play stop: +moviebrowser.book_movieend Movie end: +moviebrowser.book_moviestart Movie start: +moviebrowser.book_name Name: +moviebrowser.book_new New Bookmark +moviebrowser.book_position Position: +moviebrowser.book_type Jump (<0 back , >0 for): +moviebrowser.book_type_backward Repeat +moviebrowser.book_type_forward jump over +moviebrowser.edit_book Bookmark change +moviebrowser.edit_book_name_info1 Enter new Bookmark name +moviebrowser.edit_book_name_info2 +moviebrowser.edit_book_pos_info1 Enter new Position (s) +moviebrowser.edit_book_pos_info2 +moviebrowser.edit_book_type_info1 Enter new jump length (s) +moviebrowser.edit_book_type_info2 <0 back , >0 for, 0: none +moviebrowser.edit_serie Enter name of serie +moviebrowser.error_no_movies No movies found +moviebrowser.foot_filter Filter: +moviebrowser.foot_play Start movie +moviebrowser.foot_sort Sort: +moviebrowser.head TS MovieBrowser +moviebrowser.head_filter Filter movies by category: +moviebrowser.head_playlist Last played: +moviebrowser.head_recordlist Last recorded: +moviebrowser.hint_jumpbackward Jump back in 5 s\n '0' to cancel +moviebrowser.hint_jumpforward Jump forward in 5 s\n '0' to cancel +moviebrowser.hint_movieend Filmende in 5 s\n '0' zum weitersehen +moviebrowser.hint_newbook_backward New jump back\n 'blue' for endposition +moviebrowser.hint_newbook_forward New jump forward\n 'blue' for endposition +moviebrowser.info_audio Audio +moviebrowser.info_channel Channel +moviebrowser.info_filename Name +moviebrowser.info_genre_major Genre +moviebrowser.info_genre_minor Genre +moviebrowser.info_head Film Informationen +moviebrowser.info_info1 Info 1 +moviebrowser.info_info2 Info 2 +moviebrowser.info_length Length (Min) +moviebrowser.info_parental_lockage Parental Lock age +moviebrowser.info_parental_lockage_0year always +moviebrowser.info_parental_lockage_12year 12 years +moviebrowser.info_parental_lockage_16year 16 years +moviebrowser.info_parental_lockage_18year 18 years +moviebrowser.info_parental_lockage_6year 6 years +moviebrowser.info_parental_lockage_always never +moviebrowser.info_path Path +moviebrowser.info_prevplaydate Last play date +moviebrowser.info_prodcountry Country +moviebrowser.info_prodyear Year +moviebrowser.info_quality Quality +moviebrowser.info_recorddate Record date +moviebrowser.info_serie Serie +moviebrowser.info_size File size (MB) +moviebrowser.info_title Titel +moviebrowser.info_videoformat Picture +moviebrowser.menu_directories_head Paths +moviebrowser.menu_help_head Help +moviebrowser.menu_main_bookmarks Bookmarks +moviebrowser.menu_main_head Settings +moviebrowser.menu_main_movieinfo Movie info +moviebrowser.menu_main_saveandback save and back +moviebrowser.menu_nfs_head NFS settings +moviebrowser.menu_parental_lock_activated activated +moviebrowser.menu_parental_lock_activated_no no +moviebrowser.menu_parental_lock_activated_yes yes +moviebrowser.menu_parental_lock_activated_no_temp no (temporary) +moviebrowser.menu_parental_lock_head Parental Lock +moviebrowser.menu_parental_lock_rate_head Lock movies from +moviebrowser.scan_for_movies Scan for Movies ... +moviebrowser.serie_existingname Existing series +moviebrowser.serie_head Serie +moviebrowser.serie_name Change name +moviebrowser.short_audio Audio +moviebrowser.short_book Book +moviebrowser.short_channel Channel +moviebrowser.short_country Country +moviebrowser.short_filename Name +moviebrowser.short_format Format +moviebrowser.short_genre_major Genre +moviebrowser.short_genre_minor Genre +moviebrowser.short_info1 Info 1 +moviebrowser.short_info2 Info 2 +moviebrowser.short_length Min +moviebrowser.short_parental_lockage Age +moviebrowser.short_path Path +moviebrowser.short_prevplaydate Last +moviebrowser.short_prodyear Year +moviebrowser.short_quality * (quality) +moviebrowser.short_recorddate Date +moviebrowser.short_serie Serie +moviebrowser.short_size MB +moviebrowser.short_title Title +moviebrowser.start_head Start movie from: +moviebrowser.start_record_start Movie start +options.on.without_messages Without msg +extra.zapit_scan_sdt Scan SDT for updates +extra.zapit_sdt_changed Channels changed, reload settings. +miscsettings.virtual_zap_mode Virtual zap +miscsettings.epg_head Epg settings +miscsettings.epg_cache_days EPG-Cache (days) +miscsettings.epg_old_hours Events old after (hours) +miscsettings.epg_dir Dir for epg cache +miscsettings.epg_save Save/Restore epg on reboot +shutdown.recoding_query Box in record mode, you really want to shutdown ? +recordingmenu.apids default audio streams +recordingmenu.apids_ac3 record AC3 streams +recordingmenu.apids_alt record alternative streams +recordingmenu.apids_std record standard stream +recordingmenu.stream_pmt_pid record PMT +recordingmenu.zap_on_announce zap on recording announce +timerlist.apids_dflt record default audio streams +videomenu.osd OSD +videomenu.tv-scart TV Scart +videomenu.vcr-scart VCR Scart +videomenu.vcrsignal VCR Output Signal Type +videomenu.vcrsignal_composite CVBS +videomenu.vcrsignal_svideo S-Video +moviebrowser.option_browser Browser Options +moviebrowser.book_clear_all Clear all +moviebrowser.menu_save Save changes +moviebrowser.menu_save_all Start update of movie info files +moviebrowser.info_head_update Save changes in all movie info files +moviebrowser.update_if_dest_empty_only Copy if destination is empty only +moviebrowser.serie_auto_create Serie auto create +moviebrowser.load_default Load default settings +moviebrowser.browser_row_head Row settings +moviebrowser.browser_row_nr Number of rows +moviebrowser.browser_row_item Row item +moviebrowser.browser_row_width Row width +moviebrowser.reload_at_start Reload movie info at start +moviebrowser.remount_at_start Remount at start +moviebrowser.dir_head Additional paths +moviebrowser.dir Path +moviebrowser.use_dir Use directory +moviebrowser.use_rec_dir Use record directory +moviebrowser.use_movie_dir Use movie directory +moviebrowser.hide_series Hide series +moviebrowser.last_record_max_items Number of lines last record +moviebrowser.last_play_max_items Number of lines last play +moviebrowser.browser_frame_high Browser hight [Pixel] +extra.auto_timeshift Auto-record, sec (0 = disable) +extra.auto_delete Auto-delete +extra.auto_to_record Move timeshift to records +extra.record_time Fast/timeshift record time(hours) diff --git a/data/locale/portugues.locale b/data/locale/portugues.locale new file mode 100644 index 000000000..84b177252 --- /dev/null +++ b/data/locale/portugues.locale @@ -0,0 +1,1237 @@ +EPGMenu.epgplus Ver EPG global +EPGMenu.eventinfo EPG actual +EPGMenu.eventlist EPG do canal actual +EPGMenu.head EPG - Guia de Programação +EPGMenu.streaminfo Informação +EPGPlus.actions Acções +EPGPlus.bybouquet_mode por bouquet +EPGPlus.bypage_mode tudo (ordem numérica) +EPGPlus.change_font_size tamanho da letra +EPGPlus.change_font_style estilo da letra +EPGPlus.change_size tamanho +EPGPlus.channelentry_font letera do canal +EPGPlus.channelentry_separationlineheight linha de separação em cima +EPGPlus.channelentry_width largura +EPGPlus.channelevententry_font letra do evento +EPGPlus.edit_fonts editar letra +EPGPlus.edit_sizes editar os tamanhos +EPGPlus.font_style_bold tipo bold +EPGPlus.font_style_italic tipo itálico +EPGPlus.font_style_regular tipo regular +EPGPlus.footer_fontbouquetchannelname bouquet de fundo +EPGPlus.footer_fontbuttons butões de fundo +EPGPlus.footer_fonteventdescription eventos de fundo +EPGPlus.footer_fonteventshortdescription pequena descrição de eventos de fundo +EPGPlus.head EPG Plus +EPGPlus.header_font letra do cabeçalho +EPGPlus.horgap1_height altura1 +EPGPlus.horgap2_height altura2 +EPGPlus.next_bouquet próximo bouquet +EPGPlus.options Opções +EPGPlus.page_down Para baixo +EPGPlus.page_up Para cima +EPGPlus.prev_bouquet bouquet anterior +EPGPlus.record Gravar +EPGPlus.refresh_epg Actualizar +EPGPlus.remind Programar gravação +EPGPlus.reset_settings repor as definições de origem +EPGPlus.save_settings guardar as alterações +EPGPlus.scroll_mode Modo rolante +EPGPlus.select_font_name nome da letra +EPGPlus.settings configurações +EPGPlus.slider_width largura de slider de EPG +EPGPlus.stretch_mode Modo expandido +EPGPlus.swap_mode mostra +EPGPlus.timeline_fontdate letra da data +EPGPlus.timeline_fonttime letra do tempo +EPGPlus.vergap1_width largura1 +EPGPlus.vergap2_width largura2 +EPGPlus.view_mode modo ver +GENRE.ARTS.0 arte / cultura +GENRE.ARTS.1 performing arts +GENRE.ARTS.10 arte/revistas de cultura +GENRE.ARTS.11 moda +GENRE.ARTS.2 fine arts +GENRE.ARTS.3 religião +GENRE.ARTS.4 cultura popular/artes tradicionais +GENRE.ARTS.5 literatura +GENRE.ARTS.6 cinema +GENRE.ARTS.7 experimental filmes/vídeo +GENRE.ARTS.8 notícias/imprensa +GENRE.ARTS.9 novos media +GENRE.CHILDRENs_PROGRAMMES.0 crianças / programas juvenis +GENRE.CHILDRENs_PROGRAMMES.1 programas pré-escolares +GENRE.CHILDRENs_PROGRAMMES.2 programas de entretenimento para os 6 aos 14 +GENRE.CHILDRENs_PROGRAMMES.3 programas de entretenimento para os 10 aos 16 +GENRE.CHILDRENs_PROGRAMMES.4 informação/educação/programas escolares +GENRE.CHILDRENs_PROGRAMMES.5 desenhos animados +GENRE.DOCUS_MAGAZINES.0 documentários +GENRE.DOCUS_MAGAZINES.1 natureza/animais/meio ambiente +GENRE.DOCUS_MAGAZINES.2 tecnologia/ciências naturaias +GENRE.DOCUS_MAGAZINES.3 medicina/psicologia +GENRE.DOCUS_MAGAZINES.4 países estrangeiros/expedições +GENRE.DOCUS_MAGAZINES.5 sociais/ciências espirituais +GENRE.DOCUS_MAGAZINES.6 educação +GENRE.DOCUS_MAGAZINES.7 linguagens +GENRE.MOVIE.0 filmes/drama +GENRE.MOVIE.1 detectives/thriller +GENRE.MOVIE.2 aventura/western/guerra +GENRE.MOVIE.3 ficção cientifica/fantasia/terror +GENRE.MOVIE.4 comedia +GENRE.MOVIE.5 soap/melodrama/folkloric +GENRE.MOVIE.6 romantico +GENRE.MOVIE.7 séries/clássico/religioso/filmes históricos/drama +GENRE.MOVIE.8 filmes xx's/drama +GENRE.MUSIC_DANCE.0 musica / ballet / dança +GENRE.MUSIC_DANCE.1 rock/pop +GENRE.MUSIC_DANCE.2 serious music/musica clássica +GENRE.MUSIC_DANCE.3 folclore/musica tradicional +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musicais/opera +GENRE.MUSIC_DANCE.6 ballet +GENRE.NEWS.0 notícias +GENRE.NEWS.1 notícias/notícias do tempo +GENRE.NEWS.2 telejornal +GENRE.NEWS.3 documentário +GENRE.NEWS.4 debate/entrevista/debate +GENRE.SHOW.0 espectáculos / Jogos de TV +GENRE.SHOW.1 jogos tv/questionários/respostas +GENRE.SHOW.2 espectáculos variados +GENRE.SHOW.3 talk show +GENRE.SOCIAL_POLITICAL.0 eventos políticos e sociais / negócios +GENRE.SOCIAL_POLITICAL.1 revista/reportagens/documentários +GENRE.SOCIAL_POLITICAL.2 economia/conselhos sociais +GENRE.SOCIAL_POLITICAL.3 pessoas de nome +GENRE.SPORTS.0 desporto +GENRE.SPORTS.1 desportos especiais (Jogos Olímpicos, Supertaça Cândido Oliveira, etc...) +GENRE.SPORTS.10 equestre +GENRE.SPORTS.11 desportos marciais +GENRE.SPORTS.2 revistas desportivas +GENRE.SPORTS.3 futebol +GENRE.SPORTS.4 ténis/squash +GENRE.SPORTS.5 desportos colectivos (excluindo o futebol) +GENRE.SPORTS.6 atletismo +GENRE.SPORTS.7 desportos motorizados +GENRE.SPORTS.8 desportos aquáticos +GENRE.SPORTS.9 desportos de Inverno +GENRE.TRAVEL_HOBBIES.0 viagens e recreio +GENRE.TRAVEL_HOBBIES.1 turismo/viagens +GENRE.TRAVEL_HOBBIES.2 handicraft +GENRE.TRAVEL_HOBBIES.3 motores +GENRE.TRAVEL_HOBBIES.4 desporto e saúde +GENRE.TRAVEL_HOBBIES.5 cozinha +GENRE.TRAVEL_HOBBIES.6 shopping +GENRE.TRAVEL_HOBBIES.7 jardinagem +GENRE.UNKNOWN desconhecido +apids.hint_1 Adicionar APIDs para serem "streamed" +apids.hint_2 em notação haxadecimal separada por ' ' +apidselector.head Seleccionar língua +audiomenu.PCMOffset Descer o volume usando PCM +audiomenu.analogout Saída Analógica +audiomenu.avs avs +audiomenu.avs_control Volume Controlo avs/ost +audiomenu.dolbydigital Dolby Digital +audiomenu.head Audio Configurações +audiomenu.lirc lirc +audiomenu.monoleft mono esquerdo +audiomenu.monoright mono direito +audiomenu.ost ost +audiomenu.stereo stereo +audioplayer.add Adicionar +audioplayer.artist_title Artista, titulo +audioplayer.building_search_index building search index +audioplayer.button_select_title_by_id procurar por ID +audioplayer.button_select_title_by_name procurar por nome +audioplayer.defdir directório de início +audioplayer.delete Apagar +audioplayer.deleteall Apagar todos +audioplayer.display_order ordem de exibição +audioplayer.enable_sc_metadata enable shoutcast meta data parsing +audioplayer.fastforward avanço rápido +audioplayer.follow auto seleccionar a actual +audioplayer.head Lista de Ãudio +audioplayer.highprio alta prioridade na descodificação +audioplayer.id3scan Procurando etiquetas ID3 +audioplayer.jump_backwards Salto para trás +audioplayer.jump_dialog_hint1 Insira destino do salto +audioplayer.jump_dialog_hint2 Em Segundos +audioplayer.jump_dialog_title Destino do salto +audioplayer.jump_forwards Salto para frente +audioplayer.keylevel key level +audioplayer.name Reprodutor de Ãudio +audioplayer.pause pausa +audioplayer.play Reproduzir +audioplayer.playing Faixa em execução +audioplayer.playlist_fileerror_msg Ficheiro não pode ser criado: +audioplayer.playlist_fileerror_title Erro +audioplayer.playlist_fileoverwrite_msg Deseja sobrepor este ficheiro? +audioplayer.playlist_fileoverwrite_title Sobrepor? +audioplayer.playlist_name nome da lista +audioplayer.playlist_name_hint1 Por favor introduzir o nome da lista +audioplayer.playlist_name_hint2 A extensão .m3u será automaticamente adicionada +audioplayer.reading_files reading files +audioplayer.repeat_on activar modo repetição +audioplayer.rewind Modo continuo +audioplayer.save_playlist guardar lista em execução +audioplayer.screensaver_timeout definir tempo para a protecção de ecrã (min, 0=off) +audioplayer.select_title_by_name procurar titúlo por nome (SMS) +audioplayer.show_playlist mostar lista +audioplayer.shuffle Modo aleatório +audioplayer.stop Parar +audioplayer.title_artist Titulo, Artista +audioplayerpicsettings.general Reprodutor de áudio / Visualizar fotografias +bookmarkmanager.delete apagar +bookmarkmanager.name nome favoritos +bookmarkmanager.rename renomear +bookmarkmanager.select seleccionar +bouqueteditor.add Adicionar +bouqueteditor.bouquetname Nome do bouquet +bouqueteditor.delete Apagar +bouqueteditor.discardingchanges A ignorar alterações. Por favor aguardar… +bouqueteditor.hide Esconder +bouqueteditor.lock Bloquear +bouqueteditor.move Mover +bouqueteditor.name Editor de Bouquets +bouqueteditor.newbouquetname Novo nome do bouquet +bouqueteditor.rename Renomear +bouqueteditor.return pronto +bouqueteditor.savechanges? deseja guardar as alterações? +bouqueteditor.savingchanges A guardar alterações. Por favor aguardar... +bouqueteditor.switch adicionar/remover +bouqueteditor.switchmode TV/Rádio +bouquetlist.head Bouquets +cablesetup.provider operador de cabo +channellist.head Todos os serviços +channellist.nonefound Não foram encontrados canais!\nPor favor realize uma busca\n(tecla-DBOX -> serviços) +channellist.since desde %02d:%02d +colorchooser.alpha alpha +colorchooser.blue azul +colorchooser.green verde +colorchooser.red vermelho +colormenu.background Fundo +colormenu.fade Menus escondidos +colormenu.font Tamanho da letra +colormenu.gtx_alpha Transparência (GTX) +colormenu.head Configurar cor +colormenu.menucolors Menu cor +colormenu.statusbar Barra de Informação +colormenu.textcolor Cor do Texto +colormenu.themeselect Seleccionar tema +colormenu.timing Tempo de OSD +colormenusetup.head Menu Cores +colormenusetup.menucontent Janela actual +colormenusetup.menucontent_inactive Janela inactiva +colormenusetup.menucontent_selected Janela seleccionada +colormenusetup.menuhead Título do Menu +colorstatusbar.head Barra de Informação +colorstatusbar.text Barra de Informação +colorthememenu.classic_theme Tema Classico +colorthememenu.dblue_theme Tema AzulEscuro +colorthememenu.dvb2k_theme Tema DVB2000 +colorthememenu.head Selecionar Tema +colorthememenu.neutrino_theme Tema Neutrino +date.Apr Abr +date.Aug Ago +date.Dec Dez +date.Feb Feb +date.Fri Sex +date.Jan Jan +date.Jul Jul +date.Jun Jun +date.Mar Mar +date.May Mai +date.Mon Seg +date.Nov Nov +date.Oct Out +date.Sat Sab +date.Sep Sep +date.Sun Dom +date.Thu Qui +date.Tue Ter +date.Wed Qua +epglist.head Lista de eventos - %s +epglist.noevents EPG não disponível... +epgviewer.More_Screenings Repetições neste canal +epgviewer.nodetailed Informação detalhada não disponível +epgviewer.notfound epg não encontrada +eventlistbar.channelswitch Programar gravação +eventlistbar.eventsort dispor +eventlistbar.recordevent gravar +favorites.addchannel O actual canal será adicionado \npara o bouquet "Os meus favoritos". \n Irá demorar alguns segundos... +favorites.bouquetname Meus favoritos +favorites.bqcreated Bouquet "Meus favoritos" criado com sucesso...\n +favorites.chadded O actual canal foi adicionado aos seus favoritos...\n +favorites.chalreadyinbq O actual canal já pertencia aos seus favoritos...\n +favorites.finalhint \nUse o bouqueteditor para modificar os seus favoritos.\n +favorites.menueadd Adicionar canal aos favoritos +favorites.nobouquets Favorites are available with activated Bouquets only. +filebrowser.delete Apagar +filebrowser.denydirectoryleave Usar apenas directório seleccionado +filebrowser.dodelete1 Apagar +filebrowser.dodelete2 ? +filebrowser.filter.active Activar filtro +filebrowser.filter.inactive Mostrar todos +filebrowser.head Modo Ficheiro +filebrowser.mark Marca +filebrowser.nextpage Página seguinte +filebrowser.prevpage Página anterior +filebrowser.scan Procurar ficheiro +filebrowser.select Seleccionar +filebrowser.showrights Mostrar atributos do ficheiro +filebrowser.sort.date (data) +filebrowser.sort.name (nome) +filebrowser.sort.namedirsfirst (nome2) +filebrowser.sort.size (tamanho) +filebrowser.sort.type (tipo) +flashupdate.actionreadflash a ler +flashupdate.cantopenfile não é possível abrir o ficheiro +flashupdate.cantopenmtd não é possível abrir a mtd-device +flashupdate.checkupdate procura de uma nova versão +flashupdate.currentreleasecycle Release cycle +flashupdate.currentversion_sep Versão actual +flashupdate.currentversiondate Data +flashupdate.currentversionsnapshot Tipo de imagem +flashupdate.currentversiontime Hora +flashupdate.erasefailed a apagar a flash falhou +flashupdate.erasing a apagar a flash +flashupdate.experimentalimage A imagem que seleccionou é uma versão não testada, isso significa que\no seu receptor pode não funcionar correctamente depois de a instalar.\n\ndeseja realmente actualizar para esta versão? +flashupdate.expertfunctions Menu esperto +flashupdate.fileis0bytes o tamanho do ficheiro é de 0 Bytes +flashupdate.fileselector File-Selector +flashupdate.flashreadyreboot A imagem foi escrita com sucesso.\nO receptor reiniciará de imediato. +flashupdate.getinfofile recolhendo informação sobre a versão +flashupdate.getinfofileerror não é possível verificar informação sobre a versão +flashupdate.getupdatefile recebendo a actualização +flashupdate.getupdatefileerror não é possível realizar a actualização +flashupdate.globalprogress Progresso: +flashupdate.head Actualização de Software +flashupdate.md5check verificando a integridade da imagem +flashupdate.md5sumerror imagem contem erros! +flashupdate.msgbox Encontrada a seguinte nova file:\nData: %s, %s\nBaseada na imagem: %s\nTipo: %s\n\nDeseja realizar download e instalar esta versão agora? +flashupdate.msgbox_manual Encontrada a seguinte nova imagem:\nData: %s, %s\nImagem de base: %s\nTipo de imagem: %s\n\nDeseja instalar esta versão agora? +flashupdate.mtdselector Partition-Selector +flashupdate.programmingflash a programar a flash +flashupdate.proxypassword Password +flashupdate.proxypassword_hint1 enter the proxyserver password +flashupdate.proxypassword_hint2 uma entrada vazia significa não haver proxy-auth +flashupdate.proxyserver Hostname +flashupdate.proxyserver_hint1 enter proxyserver name or ip, use host:port +flashupdate.proxyserver_hint2 uma entrada vazia significa não haver proxy +flashupdate.proxyserver_sep Proxyserver +flashupdate.proxyusername Username +flashupdate.proxyusername_hint1 introduza o proxyserver username +flashupdate.proxyusername_hint2 uma entrada vazia significa não haver proxy-auth +flashupdate.readflash Ler a imagem toda +flashupdate.readflashmtd Ler uma partição +flashupdate.ready pronto +flashupdate.reallyflashmtd Tem a certeza que deseja fazer gravar a imagem?\n\nSe ocorre algum erro ou a imagem não é\nválida, o receptor pode não reiniciar após o processo.\n\nNome da Imagem: %s\nLocalização: %s +flashupdate.savesuccess Imagem guardada com sucesso \nsobre %s. +flashupdate.selectimage Imagens/Files Disponíveis +flashupdate.squashfs.noversion A versão de SquashFS presente é actualmente apenas suportada quando actualizada via web.\nTem a certeza que deseja instalar esta imagem? +flashupdate.titlereadflash A ler Flash +flashupdate.titlewriteflash A escrever a Flash +flashupdate.updatemode Modo Update +flashupdate.updatemode_internet internet +flashupdate.updatemode_manual manual (ftp) +flashupdate.url_file localização da imagem +flashupdate.versioncheck verificar versão +flashupdate.writeflash Escrever a imagem toda +flashupdate.writeflashmtd Escrever uma partição +flashupdate.wrongbase flashupdate.wrongbase Your Release cycle differs.\nTo continue? +fontmenu.channellist Lista de canais +fontmenu.epg EPG +fontmenu.eventlist Lista de Eventos +fontmenu.gamelist Lista de Jogos +fontmenu.head Configurações do Tamanho da fonte +fontmenu.infobar Barra de informação +fontsize.channel_num_zap selecção directa +fontsize.channellist Lista de canais +fontsize.channellist_descr Descrição +fontsize.channellist_number Número +fontsize.epg_date EPG Data +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Titulo +fontsize.eventlist_datetime data / tempo +fontsize.eventlist_itemlarge largo +fontsize.eventlist_itemsmall pequeno +fontsize.eventlist_title Titúlo +fontsize.filebrowser_item Item de modo ficheiro +fontsize.gamelist_itemlarge larga +fontsize.gamelist_itemsmall pequena +fontsize.hint A Iniciar letra,\npor favor aguarde... +fontsize.infobar_channame Nome do canal +fontsize.infobar_info info +fontsize.infobar_number Numero +fontsize.infobar_small pequeno +fontsize.menu Menu texto +fontsize.menu_info Menu Informações +fontsize.menu_title Menu Titulo +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.epgnotload EPG não carregada.... +infoviewer.epgwait À espera do EPG... +infoviewer.eventlist EPG actual +infoviewer.languages Audio +infoviewer.motor_moving Movendo a antena +infoviewer.nocurrent Sem informação disponível para o seguinte programa +infoviewer.noepg EPG não disponível +infoviewer.notavailable Canal não disponível +infoviewer.selecttime Timeselection +infoviewer.streaminfo Características +infoviewer.subservice Sub serviços +infoviewer.waittime Esperando pela hora... +ipsetup.hint_1 Use 0..9, ou use Cima/Baixo, +ipsetup.hint_2 OK guardar, HOME cancelar +keybindingmenu.RC Intervalo de repetição para a mesma tecla +keybindingmenu.addrecord adicionar programação de gravação +keybindingmenu.addremind adicionar programação de evento +keybindingmenu.allchannels_on_ok todos os serviços +keybindingmenu.bouquetchannels_on_ok bouquet actual +keybindingmenu.bouquetdown bouquet anterior +keybindingmenu.bouquethandling Bouquet-control +keybindingmenu.bouquetlist_on_ok lista de bouquets +keybindingmenu.bouquetup bouquet seguinte +keybindingmenu.cancel fechar lista de canais +keybindingmenu.channeldown canal anterior +keybindingmenu.channellist Lista de canais +keybindingmenu.channelup canal seguinte +keybindingmenu.head Configurar teclas +keybindingmenu.lastchannel Zapping Rápido +keybindingmenu.modechange Modo edição +keybindingmenu.pagedown página anterior +keybindingmenu.pageup página seguinte +keybindingmenu.quickzap Zapping rápido +keybindingmenu.repeatblock Intervalo da repetição de tecla +keybindingmenu.repeatblockgeneric Intervalo entre teclas +keybindingmenu.sort alterar ordem de exposição +keybindingmenu.subchanneldown canal anterior +keybindingmenu.subchannelup canal seguinte +keybindingmenu.tvradiomode Modo TV/Rádio +keybindingmenu.zaphistory Zapping Bouquet - Histórico +keychooser.head Configurar nova tecla +keychooser.text1 por favor premir a nova tecla +keychooser.text2 esperar alguns segundos para abortar +keychoosermenu.currentkey tecla actual +keychoosermenu.setnew Configurar nova tecla +keychoosermenu.setnone sem tecla definida +languagesetup.head Configurar língua +languagesetup.select Língua +lcdcontroler.brightness Brilho normal +lcdcontroler.brightnessstandby Brilho em Standby +lcdcontroler.contrast Contraste +lcdcontroler.head LCD Configurações +lcdmenu.autodimm Auto dimm +lcdmenu.head LCD Configurações +lcdmenu.inverse Inverter +lcdmenu.lcdcontroler Contraste / Brilho +lcdmenu.power Lidado +lcdmenu.statusline Linha de estado +lcdmenu.statusline.both volume / tempo decorrido +lcdmenu.statusline.playtime tempo decorrido +lcdmenu.statusline.volume volume +mainmenu.audioplayer Reprodutor de Aúdio +mainmenu.games Jogos +mainmenu.head Menu +mainmenu.movieplayer Reprodutor de Vídeo +mainmenu.pausesectionsd Ler EPG +mainmenu.pictureviewer Ver Fotos +mainmenu.radiomode Modo Rádio +mainmenu.recording Gravação +mainmenu.recording_start Iniciar +mainmenu.recording_stop Parar +mainmenu.scartmode Modo Scart +mainmenu.service Serviços +mainmenu.settings Configurações +mainmenu.shutdown Desligar +mainmenu.sleeptimer Desligar por temporizador +mainmenu.tvmode Modo TV +mainsettings.audio Aúdio +mainsettings.colors Cores / temas / letra +mainsettings.head Configurações +mainsettings.keybinding Configurar teclas +mainsettings.language Língua +mainsettings.lcd LC-Display +mainsettings.misc Outras configurações +mainsettings.network Rede +mainsettings.recording Gravação +mainsettings.savesettingsnow Guardar alterações agora +mainsettings.savesettingsnow_hint A guardar alterações,\npor favor aguarde... +mainsettings.streaming Reprodutor de Vídeo +mainsettings.video Video +menu.back Voltar +messagebox.back Atrás +messagebox.cancel Cancelar +messagebox.discard Ignorar alterações? +messagebox.error Erro +messagebox.info Informação +messagebox.no Não +messagebox.yes Sim +miscsettings.bootinfo Mostrar informação ao arrancar +miscsettings.bootmenu Mostrar boot +miscsettings.driver_boot Driver e boot - opções +miscsettings.fb_destination Expertos! Boot-Console +miscsettings.general Geral +miscsettings.head Outras configurações +miscsettings.hwsections Secções de hardware usado +miscsettings.infobar_sat_display Mostrar satélite na barra de informações +miscsettings.pmtupdate activar actualização do pmt +miscsettings.shutdown_real Activar standby +miscsettings.shutdown_real_rcdelay Desligar com telecomando +miscsettings.sptsmode use spts mode +miscsettings.startbhdriver carregar BH-Mode drivers +motorcontrol.head Definições do Motor +movieplayer.bookmark Favoritos +movieplayer.bookmarkname Nome da lista +movieplayer.bookmarkname_hint1 Introduzir um nome para a nova lista +movieplayer.bookmarkname_hint2 +movieplayer.buffering Buffering... +movieplayer.defdir directório de início +movieplayer.dvdplayback DVD +movieplayer.fileplayback Ficheiro via VLC +movieplayer.goto Saltar para ... +movieplayer.goto.h1 = -> salto absoluto +movieplayer.goto.h2 +,- -> salto relativo +movieplayer.head Movieplayer +movieplayer.nostreamingserver The streaming server não pode ser encontrado. +movieplayer.pesplayback Play PES (Experimental) +movieplayer.pleasewait Por favor aguarde.\nA ligar ao streaming server... +movieplayer.toomanybookmarks Tem demasiadas lista de favoritos.\nNecessita primeiro apagar alguma(s) dela(s). +movieplayer.tsplayback Play TS +movieplayer.vcdplayback (S)VCD +movieplayer.wrongvlcversion esta característica não é suportada pela corrente versão de VLC +networkmenu.broadcast Transmissor +networkmenu.dhcp DHCP +networkmenu.gateway Gateway +networkmenu.head Definições de Rede +networkmenu.ipaddress Endereço IP +networkmenu.mount NFS/CIFS +networkmenu.nameserver Name server +networkmenu.netmask Netmask +networkmenu.setupnow configurar a rede +networkmenu.setuponstartup ligar a rede no arranque +networkmenu.show mostrar as definições das ligações activas +networkmenu.test testar ligação agora +nfs.alreadymounted directório já montado +nfs.automount montar no arranque +nfs.dir directório/partilha +nfs.ip NFS/CIFS Server IP +nfs.localdir directório local +nfs.mount Montar unidade de NFS/CIFS +nfs.mount_options opções de montagem +nfs.mounterror erro ao montar +nfs.mounterror_notsup sitema de ficheiros não suportado +nfs.mountnow montar agora +nfs.mounttimeout erro ao montar: timeout +nfs.password CIFS password +nfs.remount Remontar directórios +nfs.type tipo +nfs.type_cifs CIFS +nfs.type_nfs NFS +nfs.umount Desmontar unidade NFS/CIFS +nfs.umounterror erro ao "desmontar" unidade +nfs.username CIFS username +nfsmenu.head NFS/CIFS configurações +nvod.percentage (%d%% para) +nvod.starting (a começar em %d min) +nvodselector.directormode Modo directo +nvodselector.head Seleccionar hora de início +nvodselector.subservice Seleccionar Sub serviço +options.default Restaurar configurações +options.fb framebuffer +options.null nulo +options.off off +options.on on +options.serial serie +parentallock.changepin Alterar código PIN +parentallock.changepin_hint1 Introduza aqui o seu novo código pin! +parentallock.changetolocked nos bouquets bloqueados +parentallock.head Enter Código PIN de protecção +parentallock.lockage Bloquear programa +parentallock.lockage12 de 12 anos para cima +parentallock.lockage16 de 16 anos para cima +parentallock.lockage18 de 18 anos para cima +parentallock.lockedchannel Bloquear emissor... +parentallock.lockedprogram Bloquear programa (de %d anos para cima) +parentallock.never nunca +parentallock.onsignal bloquear ao entrar no canal +parentallock.parentallock Acesso condicional +parentallock.prompt Janela para introduzir PIN +pictureviewer.defdir directório de início +pictureviewer.head Visualizar fotos +pictureviewer.resize.color_average avançado +pictureviewer.resize.none nada +pictureviewer.resize.simple simples +pictureviewer.scaling dimensionamento +pictureviewer.show mostar +pictureviewer.slide_time intervalo entre fotos +pictureviewer.slideshow Slideshow +pictureviewer.sortorder alterar ordem de disposição +pictureviewer.sortorder.date (data) +pictureviewer.sortorder.filename (Nome do ficheiro) +ping.ok localizavél (ping) +ping.protocol não localizável! (host ou protocol error) +ping.socket não localizável! (socket error) +ping.unreachable não localizável! +pinprotection.head Introduzir código PIN +pinprotection.wrongcode Código PIN errado! Tende de novo. +rclock.lockmsg O comando da sua box será bloqueado.\n Para desbloquear a sua box, prima \n e no seu telecomando. +rclock.menueadd Bloquear RC +rclock.title Bloquear Telecomando +rclock.unlockmsg Comando da box reactivado. +recordingmenu.defdir Directório a Gravar +recordingmenu.file directo (ficheiro) +recordingmenu.head Configurações de gravação +recordingmenu.help Modo de Gravação:\nserver: usando software de transmissão de dados num PC\nVcr: usando vcr \ndirect (ficheiro): directamente num directório de NFS montado \nou num Dísco Rígido Interno\n\nMax. Tamanho do Ficheiro:\nNFS V2: 2 GB (2048 MB)\nNFS V3: Não limitado (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart Não alternar para scart mode +recordingmenu.off off +recordingmenu.recording_type recording device +recordingmenu.server server +recordingmenu.server_ip recording server IP +recordingmenu.server_mac MAC address +recordingmenu.server_port recording server port +recordingmenu.server_wakeup recording server WOL +recordingmenu.setupnow Activar alterações +recordingmenu.splitsize Max. Tamanho do ficheiro (MB) +recordingmenu.stopplayback parar playback +recordingmenu.stopsectionsd parar sectionsd +recordingmenu.stream_vtxt_pid Gravar teletextp +recordingmenu.use_o_sync Escrever synchronous (O_SYNC) +recordingmenu.vcr vcr +recordtimer.announce Recording starts in a few minutes +repeatblocker.hint_1 O mais curto espaço de tempo (in ms) para reconhecer 2 "keystrokes" +repeatblocker.hint_2 Introduzir 0 para desligar o blocker (vermelho é espaço) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-repetições +satsetup.extended DiSEqC-Configurações +satsetup.extended_motor Motor-Configurações +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Configuração Manual Motor +satsetup.nodiseqc sem DiSEqC +satsetup.satellite Satelite +satsetup.savesettingsnow Guardar agora configurações +satsetup.smatvremote SMATV Remote Tuning +scants.actcable Cabo: +scants.actsatellite Satelite: +scants.bouquet Bouquet +scants.bouquet_create criar novo +scants.bouquet_erase apagar tudo +scants.bouquet_leave deixar os bouquets actuais +scants.bouquet_satellite Satelite-Bouquet +scants.bouquet_update actualização +scants.channel Channel: +scants.failed Busca de Transpondedor Falhou! +scants.finished Busca de Transpondedor concluiu com sucesso! +scants.freqdata Frequencia: +scants.head Busca transpondedor +scants.numberofdataservices Data +scants.numberofradioservices Rádio +scants.numberoftotalservices Total +scants.numberoftvservices TV +scants.provider Operador: +scants.startnow Começar Busca +scants.transponders Transpondedor: +screensetup.lowerright verde = configurar baixo direita +screensetup.upperleft vermelho = configurar cima esquerda +servicemenu.head Canais +servicemenu.reload Actualizar lista de canais +servicemenu.reload_hint A actualizar Lista de canais,\npor favor esperar... +servicemenu.scants Busca de Canais +servicemenu.ucodecheck Verificar ucodes +servicemenu.update Actualização de Software +settings.help Ajuda +settings.missingoptionsconffile As configurações de neutrino foram actualizadas.\nNovas opções estão agora seleccionadas. +settings.noconffile Não foram encontradas as configurações anteriores de neutrino.\nA usar as predefinidas. +shutdowntimer.announce A box irá desligar em 1 min.\nCancelar Desligar ? +sleeptimerbox.announce A desligar em 1 min +sleeptimerbox.hint1 Desligar em min. (000=off) +sleeptimerbox.hint2 O receptor vai desligar após este tempo. +sleeptimerbox.title Desligar por temporizador +streamfeatures.head Extra Menu +streaminfo.aratio Formato de ecrã +streaminfo.aratio_unknown Formato desconhecido +streaminfo.audiotype Formato Ãudio +streaminfo.audiotype_unknown Formato áudio desconhecido +streaminfo.bitrate Bitrate +streaminfo.framerate Framerate +streaminfo.framerate_unknown Framerate: desconhecido +streaminfo.head Stream-Information +streaminfo.not_available Não disponivél +streaminfo.resolution Resolutução +streaminfo.signal Sinal recebido +streaming.buffer_overflow A gravação abortou,\napós a informação não poder ser escrita de forma tão rápida. +streaming.busy Um processo de gravação está activo.\nSe visualizar esta mensagem e não tiver nenhuma gravação activa, por favor reiniciar a gravação. +streaming.dir_not_writable Não tem permissões para gravar nesse directório.\nA gravação não irá funcionar. +streaming.success Gravação concluída com sucesso. +streaming.write_error A gravação abortou,\napós ocorrer um erro no processo de escrita. +streaming.write_error_open A gravação abortou,\nporque o ficheiro de destino não pode ser aberto. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Configuração do Reprodutor de Vídeo +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Desligar +streamingmenu.on Ligar +streamingmenu.server_ip Streamingserver IP +streamingmenu.server_port Streamingserver Porta +streamingmenu.streaming_audiorate Datarate Audio +streamingmenu.streaming_force_avi_rawaudio Forçar AC3 para filmes AVI +streamingmenu.streaming_force_transcode_video Transcode MPG/VCD vídeo +streamingmenu.streaming_resolution Resolução +streamingmenu.streaming_server_cddrive DVD Drive +streamingmenu.streaming_server_startdir Directório (VLC) +streamingmenu.streaming_transcode_audio Transcode áudio (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec MPEG vídeo codec +streamingmenu.streaming_type Streamingserver +streamingmenu.streaming_videorate Datarate Video +streamingserver.noconnect Não há ligação ao streamingserver.\nGravação Parada. +stringinput.caps maiúsculas / minúsculas +stringinput.clear limpar tudo +timer.eventrecord.msg ... Realizar ou não??? +timer.eventrecord.title Lista de Gravações +timer.eventtimed.msg O evento está programado.\nA box será ligada e \npermanecerá no canal durante a gravação. +timer.eventtimed.title Eventos programados +timerbar.channelswitch Programar gravação +timerbar.recordevent Gravar +timerlist.alarmtime Alarme +timerlist.apids Audio PIDs +timerlist.bouquetselect seleccionar bouquet +timerlist.channel Canal +timerlist.channelselect seleccionar canal +timerlist.delete Apagar +timerlist.menumodify Alterar Temporizador +timerlist.menunew Nova Programação +timerlist.message Mensagem +timerlist.moderadio Canais de Rádio +timerlist.modeselect Modo selecção +timerlist.modetv Canais de TV +timerlist.modify Modificar +timerlist.name Temporizador - Programar acontecimentos +timerlist.new Nova programação +timerlist.program.unknown Programa Desconhecido +timerlist.reload Recarregar +timerlist.repeat Repetir +timerlist.repeat.biweekly Bissemanal +timerlist.repeat.byeventdescription Ver descrição da gravação +timerlist.repeat.daily Diário +timerlist.repeat.fourweekly 4 em 4 semanas +timerlist.repeat.friday Sex +timerlist.repeat.monday Seg +timerlist.repeat.monthly Mensal +timerlist.repeat.once Apenas 1 vez +timerlist.repeat.saturday Sab +timerlist.repeat.sunday Dom +timerlist.repeat.thursday Qui +timerlist.repeat.tuesday Ter +timerlist.repeat.unknown desconhecido +timerlist.repeat.wednesday Qua +timerlist.repeat.weekdays nos dias de semana +timerlist.repeat.weekly Semanal +timerlist.save Guardar programação +timerlist.standby Modo a deixar o receptor +timerlist.standby.off Deixar standby +timerlist.standby.on Activar standby +timerlist.stoptime Parar Tempo +timerlist.type Tipo de função +timerlist.type.nextprogram Próximo programa +timerlist.type.record Gravar +timerlist.type.remind Lembrar +timerlist.type.shutdown Desligar +timerlist.type.sleeptimer desligar +timerlist.type.standby Ir para Standby +timerlist.type.unknown Desconhecido +timerlist.type.zapto Ir para +timerlist.weekdays Dias da Semana +timerlist.weekdays.hint_1 Seg Ter Qua Qui Sex Sáb Dom +timerlist.weekdays.hint_2 'X'=tempo '-' no timer +timersettings.record_safety_time_after Correcção da hora para final de gravação +timersettings.record_safety_time_after.hint_1 Correcção da duração em min. (00=off). Este tempo +timersettings.record_safety_time_after.hint_2 será adicionado ao tempo de parar gravação para todas as programações. +timersettings.record_safety_time_before Correcção da hora de início de gravação +timersettings.record_safety_time_before.hint_1 Correcção da hora de início de gravação em min. (00=off). Este tempo +timersettings.record_safety_time_before.hint_2 será incrementado ao início de todas as gravações programadas. +timersettings.separator Ajustamentos da programação de gravações +timing.chanlist Lista de Canais +timing.epg Epg +timing.filebrowser Modo Ficheiros +timing.head Duração de OSD +timing.hint_1 Time in sec. Após +timing.hint_2 a barra de informação irá desaparecer +timing.infobar Barra de informação +timing.menu Menu +timing.numericzap Numeric Zap +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head Procurar UCode +ucodecheck.ucode UCode +ucodes.failure ATENÇÃO, µCodes NÃO PODE SER ENCONTRADO!\n\nPor favor fazer upload via FTP,\ne depois reiniciar a vossa box! +videomenu.csync Correcção sincronismo +videomenu.head Configurações Vídeo +videomenu.rgb_centering Centrar RGB +videomenu.screensetup Configurar o ecrã +videomenu.vcrswitch Alternar automáticamente com saída Scart +videomenu.videoformat Formato +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect Auto-detectar +videomenu.videosignal Saída de Vídeo +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce Ir para temporizador em um minuto +extra.auto Auto +extra.valid Validas +extra.all Todas +extra.new_keys Novas Chaves +extra.all_keys Todas as Chaves +extra.vartmp /var/tmp +extra.varkeys /var/keys +extra.algo Algo pids +extra.gbox_emu Emu +extra.gbox_softcam Softcam +extra.gbox_net Rede +extra.gbox_mix Misto +extra.gbox_info Gbox Info +extra.sep_extra Extras +extra.save_settings Guardar Configurações +extra.extra_menu EMU Menu +extra.ecm_info Ecm Info +extra.pid_info Pid Info +extra.emm_info Novas chaves +extra.emu_type Tipo de Emu +extra.camd Camd +extra.restart_camd Reiniciar Emulador +extra.mg_settings Mgcamd settings +extra.netmode Netmode +extra.autoupdate Autoupdate +extra.show_ecm Mostrar Ecm +extra.show_emm Mostrar Emm +extra.keyupdate Key update +extra.osd OSD +extra.keyfolder Key dir +extra.hash_pids Hash pids +extra.gbox_settings Gbox Configurações +extra.gbox_mode Modo +extra.newcamd_settings Newcamd Configurações +extra.show_cw Mostrar CW +extra.debug_ecm Debug Ecm +extra.disable_cam Não utilizar CAM +extra.show_cat Mostar CAT +extra.show_pmt Mostar PMT +extra.update_pmt Update PMT +extra.report_emm Report wrong EMM sig. +extra.debug_emm Debug Emm +extra.show_allca Mostrar todos ca sys. +extra.reload_keys Recordar keys no zapping +extra.reload_cfg Recordar configurações no zapping +extra.cw_delay Repor CW delay de origem +extra.dvbsnoop DVB Stream Info +extra.dvbsnoop_pat Mostrar PAT +extra.dvbsnoop_cat Mostrar CAT +extra.dvbsnoop_tsdt Mostrar TSDT +extra.dvbsnoop_nit Mostrar NIT +extra.dvbsnoop_sdt Mostrar SDT +extra.dvbsnoop_eit Mostrar EIT +extra.dvbsnoop_rst Mostrar RST +extra.dvbsnoop_tdt Mostrar TDT +extra.dvbsnoop_sit Mostrar SIT +extra.dvbsnoop_pid Mostrar PID manual +extra.dvbsnoop_scan Scanear PIDs +extra.dvbsnoop_band Mostar PID de Largura de Banda +extra.logview Ver Log +extra.ru ruDREAM +extra.english Inglês +extra.dboxinfo Dbox Informações +extra.scan_mode Busca de Canais +extra.start_tostandby Arrancar para standby +extra.rotor_swap Mover motor este/oeste +extra.use_log Loggear para /tmp/log +extra.spts_mode Modo SPTS +extra.hw_sect Hardware Secções de Hardware +extra.logo Número do logo +extra.scan_full Exaustivo +extra.scan_fast Rápido +extra.hdd_slow Lento +extra.hdd_middle Intermédio +extra.hdd_fast Rápido +extra.hdd_ext3 Ext3fs +extra.hdd_reiser Reiserfs +extra.hdd_1min 1 min. +extra.hdd_5min 5 min. +extra.hdd_10min 10 min. +extra.hdd_20min 20 min. +extra.hdd_30min 30 min. +extra.hdd_60min 60 min. +extra.logo1 1 +extra.logo2 2 +extra.logo3 3 +extra.hdd_sleep Desligar HDD em +extra.hdd_noise Ruído +extra.hdd_activate Activar configurações +extra.hdd_fs Sistema de Ficheiros +extra.hdd_format Formatar HDD +extra.hdd_check Verificar Sistema de Ficheiros +extra.hdd_settings HDD Configurações +extra.clear_log Limpar Log +extra.zap_cycle Zapping na lista de canais +extra.sms_channel sms-mode channel +extra.manual_scan Manual scan +extra.tp_freq Frequencia +extra.tp_rate Symbol rate +extra.tp_pol Polarização +extra.tp.pol_v V +extra.tp_pol_h H +extra.tp_fec FEC +extra.fec_1_2 1/2 +extra.fec_2_3 2/3 +extra.fec_3_4 3/4 +extra.fec_5_6 5/6 +extra.fec_7_8 7/8 +extra.timezone Zona horária +extra.zapit_menu Zapit options +extra.zapit_make_bouquet Realizar lista com canais restantes +extra.zapit_save_last_chan Guardar o ultimo canal +extra.zapit_motor_speed Velocidade do movimento do motor (10 = 1deg/sec) +extra.zapit_fe_timeout Tune timeout +extra.add_to_bouquet Adicionar ao Bouquet +extra.key_list_start início +extra.key_list_end final +extra.chadded O canal actual foi adicionado ao bouquet selecionado....\n +extra.chalreadyinbq O canal actual já estava no bouquet selecionado....\n +extra.menu_left_exit "Left" = menu anterior +extra.zapit_write_names Escrever nome do canal +extra.update_dir Directory for updates +extra.cache Cache +extra.debug Debug +extra.zapit_backup Backup channels to /tmp +extra.zapit_delete Delete channels +extra.zapit_fast_zap fast zap +extra.zapit_restore Restore channels from /tmp +extra.zapit_sort_names Sort ch. by name +filesystem.is.utf8 file system +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +infoviewer.subchan_disp_pos Subchannel display +mainmenu.scripts Scripts +miscsettings.noaviawatchdog enable AVIA watchdog +miscsettings.noenxwatchdog enable eNX watchdog +movieplayer.defplugin Start-Plugin +movieplayer.tshelp1 Stop +movieplayer.tshelp10 approx. 10 minutes back +movieplayer.tshelp11 skip approx. 10 minutes +movieplayer.tshelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Select audio track +movieplayer.tshelp3 Pause/Continue +movieplayer.tshelp4 Create bookmark +movieplayer.tshelp5 Show progress +movieplayer.tshelp6 approx. 1 minute back +movieplayer.tshelp7 skip approx. 1 minute +movieplayer.tshelp8 approx. 5 minutes back +movieplayer.tshelp9 skip approx. 5 minutes +movieplayer.vlchelp1 Stop +movieplayer.vlchelp10 approx. 10 minutes back +movieplayer.vlchelp11 skip approx. 10 minutes +movieplayer.vlchelp12 Help: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Resync +movieplayer.vlchelp3 Pause/Continue +movieplayer.vlchelp4 Create bookmark +movieplayer.vlchelp5 Show progress +movieplayer.vlchelp6 approx. 1 minute back +movieplayer.vlchelp7 skip approx. 1 minute +movieplayer.vlchelp8 approx. 5 minutes back +movieplayer.vlchelp9 skip approx. 5 minutes +nfs.mountok mount successful +nfs.type_lufs FTPFS +pictureviewer.help1 menu mode +pictureviewer.help10 show mode +pictureviewer.help11 reread image +pictureviewer.help12 previous image +pictureviewer.help13 next image +pictureviewer.help14 Zoom out +pictureviewer.help15 Zoom in +pictureviewer.help16 scroll up +pictureviewer.help17 scroll left +pictureviewer.help18 scroll right +pictureviewer.help19 scroll down +pictureviewer.help2 display image +pictureviewer.help20 change sort order +pictureviewer.help21 reread image (no scaling) +pictureviewer.help22 exit +pictureviewer.help3 change sort order +pictureviewer.help4 do not scale picture +pictureviewer.help5 diashow mode +pictureviewer.help6 previous image +pictureviewer.help7 next image +pictureviewer.help8 change sort order +pictureviewer.help9 exit +plugins.result plugin output +recordingmenu.choose_direct_rec_dir choose dir on imm. recording +recordingmenu.epg_for_filename long filenames (with EPG data) +recordingmenu.filesettings direct recording settings +recordingmenu.ringbuffers no. of ringbuffers +recordingmenu.use_fdatasync write synchronous (fdatasync) +settings.pos_bottom_left bottom left +settings.pos_bottom_right bottom right +settings.pos_top_left oben top left +settings.pos_top_right oben top right +timerlist.plugin Plugin +timerlist.recording_dir recording directory +timerlist.repeatcount repeats +timerlist.repeatcount.help1 amount of timer repeats +timerlist.repeatcount.help2 0 for unlimited repeats +timerlist.type.execplugin Execute plugin +pictureviewer.decode_server_ip decode server ip +pictureviewer.decode_server_port decode server port +scants.abort_body Should the search really be aborted? +scants.abort_header Cancelar Busca +recordingmenu.record_in_spts_mode switch to spts mode before recording +servicemenu.getplugins Reload plugins +servicemenu.getplugins_hint Reloading plugins,\nplease be patient. +zapit.scantype scan for services +zapit.scantype.all all services +zapit.scantype.radio only radio +zapit.scantype.tv only tv +zapit.scantype.tvradio tv & radio +colorthememenu.red_theme Simply Red +lcdmenu.dim_brightness Brightness after dim timeout +lcdmenu.dim_time Dim timeout +timerlist.overlapping_timer Timer conflict. Create the timer anyway? +extra.audio_run_player Audio key start player +mpkey.rewind Rewind +mpkey.forward Forward +mpkey.pause Pause +mpkey.stop Stop +mpkey.play Play +mpkey.audio Audio track +mpkey.time Show time +mpkey.bookmark save bookmark +mpkey.plugin Run plugin +extra.key_click Key click +extra.loadcolors Load colors from +extra.savecolors Save colors as +extra.loadkeys Load keys from +extra.savekeys Save keys as +extra.loadconfig Load settings from +extra.saveconfig Save settings as +videomenu.videomode Video system +videomenu.videomode_ntsc NTSC +videomenu.videomode_pal PAL +videomenu.videomode_palm PAL-M +extra.key_timeshift Timeshift +extra.key_plugin One touch plugin +extra.timeshift_pause Timeshift pause +rfmod.rfmod RF modulator +rfmod.carrier Subcarrier Frequency +rfmod.carrier4500 4.5 +rfmod.carrier5500 5.5 +rfmod.carrier6000 6.0 +rfmod.carrier6500 6.5 +rfmod.enable Enable sound +rfmod.channel Channel +rfmod.finetune Fine tune +rfmod.standby Enable modulator +rfmod.test Test pattern +extra.zapit_scanpids Scan/Use pids +extra.zapit_rezap_time Re-Zap on emu switch time +extra.zapit_hvoltage High (13.5/18.5) voltage +extra.key_unlock Unlock key +extra.mg_netoptions Network options +extra.mg_ecm_timeout Network ecm timeout +extra.mg_reconnect Shares reconnect +extra.mg_priority Share priority +extra.mg_osd_options Osd options +extra.mg_reread Reread files on zap +servicemenu.imageinfo Image info +imageinfo.creator Creator: +imageinfo.date Date: +imageinfo.dokumentation Docs: +imageinfo.forum Forum: +imageinfo.head Image info: +imageinfo.homepage Home page: +imageinfo.image Image: +imageinfo.license License: +imageinfo.version Version: +extra.cache_txt Cache teletext +extra.use_gotoxx Use gotoXX +extra.latitude Latitude +extra.longitude Longitude +extra.ladirection LaDirection +extra.lodirection LoDirection +extra.south South +extra.north North +extra.east East +extra.west West +epgextended.actors Actors +epgextended.director Director +epgextended.guests Guests +epgextended.original_title Original Title +epgextended.presenter Presenter +epgextended.year_of_production Year of Production +recordingmenu.save_in_channeldir Save in channel dir +servicemenu.restart Soft restart +servicemenu.restart_failed Restart failed +servicemenu.restart_hint Restarting, please wait +servicemenu.restart_refused_recording Cant restart, recording in progress +extra.cs Cardserver +extra.restart_cs Restart cardserver +extra.tp_mod Modulation +extra.tp_mod_16 QAM/16 +extra.tp_mod_32 QAM/32 +extra.tp_mod_64 QAM/64 +extra.tp_mod_128 QAM/128 +extra.tp_mod_256 QAM/256 +moviebrowser.book_head Bookmarks +moviebrowser.book_lastmoviestop Last play stop: +moviebrowser.book_movieend Movie end: +moviebrowser.book_moviestart Movie start: +moviebrowser.book_name Name: +moviebrowser.book_new New Bookmark +moviebrowser.book_position Position: +moviebrowser.book_type Jump (<0 back , >0 for): +moviebrowser.book_type_backward Repeat +moviebrowser.book_type_forward jump over +moviebrowser.edit_book Bookmark change +moviebrowser.edit_book_name_info1 Enter new Bookmark name +moviebrowser.edit_book_name_info2 +moviebrowser.edit_book_pos_info1 Enter new Position (s) +moviebrowser.edit_book_pos_info2 +moviebrowser.edit_book_type_info1 Enter new jump length (s) +moviebrowser.edit_book_type_info2 <0 back , >0 for, 0: none +moviebrowser.edit_serie Enter name of serie +moviebrowser.error_no_movies No movies found +moviebrowser.foot_filter Filter: +moviebrowser.foot_play Start movie +moviebrowser.foot_sort Sort: +moviebrowser.head TS MovieBrowser +moviebrowser.head_filter Filter movies by category: +moviebrowser.head_playlist Last played: +moviebrowser.head_recordlist Last recorded: +moviebrowser.hint_jumpbackward Jump back in 5 s\n '0' to cancel +moviebrowser.hint_jumpforward Jump forward in 5 s\n '0' to cancel +moviebrowser.hint_movieend Filmende in 5 s\n '0' zum weitersehen +moviebrowser.hint_newbook_backward New jump back\n 'blue' for endposition +moviebrowser.hint_newbook_forward New jump forward\n 'blue' for endposition +moviebrowser.info_audio Audio +moviebrowser.info_channel Channel +moviebrowser.info_filename Name +moviebrowser.info_genre_major Genre +moviebrowser.info_genre_minor Genre +moviebrowser.info_head Film Informationen +moviebrowser.info_info1 Info 1 +moviebrowser.info_info2 Info 2 +moviebrowser.info_length Length (Min) +moviebrowser.info_parental_lockage Parental Lock age +moviebrowser.info_parental_lockage_0year always +moviebrowser.info_parental_lockage_12year 12 years +moviebrowser.info_parental_lockage_16year 16 years +moviebrowser.info_parental_lockage_18year 18 years +moviebrowser.info_parental_lockage_6year 6 years +moviebrowser.info_parental_lockage_always never +moviebrowser.info_path Path +moviebrowser.info_prevplaydate Last play date +moviebrowser.info_prodcountry Country +moviebrowser.info_prodyear Year +moviebrowser.info_quality Quality +moviebrowser.info_recorddate Record date +moviebrowser.info_serie Serie +moviebrowser.info_size File size (MB) +moviebrowser.info_title Titel +moviebrowser.info_videoformat Picture +moviebrowser.menu_directories_head Paths +moviebrowser.menu_help_head Help +moviebrowser.menu_main_bookmarks Bookmarks +moviebrowser.menu_main_head Settings +moviebrowser.menu_main_movieinfo Movie info +moviebrowser.menu_main_saveandback save and back +moviebrowser.menu_nfs_head NFS settings +moviebrowser.menu_parental_lock_activated activated +moviebrowser.menu_parental_lock_activated_no no +moviebrowser.menu_parental_lock_activated_yes yes +moviebrowser.menu_parental_lock_activated_no_temp no (temporary) +moviebrowser.menu_parental_lock_head Parental Lock +moviebrowser.menu_parental_lock_rate_head Lock movies from +moviebrowser.scan_for_movies Scan for Movies ... +moviebrowser.serie_existingname Existing series +moviebrowser.serie_head Serie +moviebrowser.serie_name Change name +moviebrowser.short_audio Audio +moviebrowser.short_book Book +moviebrowser.short_channel Channel +moviebrowser.short_country Country +moviebrowser.short_filename Name +moviebrowser.short_format Format +moviebrowser.short_genre_major Genre +moviebrowser.short_genre_minor Genre +moviebrowser.short_info1 Info 1 +moviebrowser.short_info2 Info 2 +moviebrowser.short_length Min +moviebrowser.short_parental_lockage Age +moviebrowser.short_path Path +moviebrowser.short_prevplaydate Last +moviebrowser.short_prodyear Year +moviebrowser.short_quality * (quality) +moviebrowser.short_recorddate Date +moviebrowser.short_serie Serie +moviebrowser.short_size MB +moviebrowser.short_title Title +moviebrowser.start_head Start movie from: +moviebrowser.start_record_start Movie start +options.on.without_messages Without msg +extra.zapit_scan_sdt Scan SDT for updates +extra.zapit_sdt_changed Channels changed, reload settings. +miscsettings.virtual_zap_mode Virtual zap +miscsettings.epg_head Epg settings +miscsettings.epg_cache_days EPG-Cache (days) +miscsettings.epg_old_hours Events old after (hours) +miscsettings.epg_dir Dir for epg cache +miscsettings.epg_save Save/Restore epg on reboot +shutdown.recoding_query Box in record mode, you really want to shutdown ? +recordingmenu.apids default audio streams +recordingmenu.apids_ac3 record AC3 streams +recordingmenu.apids_alt record alternative streams +recordingmenu.apids_std record standard stream +recordingmenu.stream_pmt_pid record PMT +recordingmenu.zap_on_announce zap on recording announce +timerlist.apids_dflt record default audio streams +videomenu.osd OSD +videomenu.tv-scart TV Scart +videomenu.vcr-scart VCR Scart +videomenu.vcrsignal VCR Output Signal Type +videomenu.vcrsignal_composite CVBS +videomenu.vcrsignal_svideo S-Video +moviebrowser.option_browser Browser Options +moviebrowser.book_clear_all Clear all +moviebrowser.menu_save Save changes +moviebrowser.menu_save_all Start update of movie info files +moviebrowser.info_head_update Save changes in all movie info files +moviebrowser.update_if_dest_empty_only Copy if destination is empty only +moviebrowser.serie_auto_create Serie auto create +moviebrowser.load_default Load default settings +moviebrowser.browser_row_head Row settings +moviebrowser.browser_row_nr Number of rows +moviebrowser.browser_row_item Row item +moviebrowser.browser_row_width Row width +moviebrowser.reload_at_start Reload movie info at start +moviebrowser.remount_at_start Remount at start +moviebrowser.dir_head Additional paths +moviebrowser.dir Path +moviebrowser.use_dir Use directory +moviebrowser.use_rec_dir Use record directory +moviebrowser.use_movie_dir Use movie directory +moviebrowser.hide_series Hide series +moviebrowser.last_record_max_items Number of lines last record +moviebrowser.last_play_max_items Number of lines last play +moviebrowser.browser_frame_high Browser hight [Pixel] +extra.auto_timeshift Auto-record, sec (0 = disable) +extra.auto_delete Auto-delete +extra.auto_to_record Move timeshift to records +extra.record_time Fast/timeshift record time(hours) diff --git a/data/locale/russkij.locale b/data/locale/russkij.locale new file mode 100644 index 000000000..b8cffdc68 --- /dev/null +++ b/data/locale/russkij.locale @@ -0,0 +1,1186 @@ +EPGMenu.epgplus Телегид по вÑем каналам +EPGMenu.eventinfo Передачи канала подробно +EPGMenu.eventlist Телегид канала +EPGMenu.head Телегид-Информ +EPGMenu.streaminfo техничеÑÐºÐ°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ ÐºÐ°Ð½Ð°Ð»Ð° +EPGPlus.actions ДейÑÑ‚Ð²Ð¸Ñ +EPGPlus.bybouquet_mode по пакетам +EPGPlus.bypage_mode по Ñтраницам +EPGPlus.change_font_size Размер шрифта +EPGPlus.change_font_style Вид шрифта +EPGPlus.change_size Изменить размер +EPGPlus.channelentry_font Шрифт Ð´Ð»Ñ ÐšÐ°Ð½Ð°Ð»Ð° +EPGPlus.channelentry_separationlineheight Ð’Ñ‹Ñота Ñтрок +EPGPlus.channelentry_width Ширина Ñчейки канала +EPGPlus.channelevententry_font Шрифт Ð´Ð»Ñ ÐŸÐµÑ€ÐµÐ´Ð°Ñ‡Ð¸ +EPGPlus.edit_fonts УÑтановка шрифтов +EPGPlus.edit_sizes УÑтановка размеров +EPGPlus.font_style_bold Жирный +EPGPlus.font_style_italic КурÑив +EPGPlus.font_style_regular Обычный +EPGPlus.footer_fontbouquetchannelname Шрифт инф.канала в ÑноÑке +EPGPlus.footer_fontbuttons Шрифт подпиÑей кнопок +EPGPlus.footer_fonteventdescription Шрифт Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ð¸ в ÑноÑке +EPGPlus.footer_fonteventshortdescription Шрифт инф.передачи в ÑноÑке +EPGPlus.head Телегид по вÑем каналам (проÑмотр/обзор) +EPGPlus.header_font Шрифт Заголовка +EPGPlus.horgap1_height Ð’Ñ‹Ñота верх.Ð¿Ð¾Ð»Ñ Ñ€Ð°Ð·Ð´ÐµÐ»Ð° +EPGPlus.horgap2_height Ð’Ñ‹Ñота ниж.Ð¿Ð¾Ð»Ñ Ñ€Ð°Ð·Ð´ÐµÐ»Ð° +EPGPlus.next_bouquet Пакет вперед +EPGPlus.options Опции +EPGPlus.page_down вниз Ñтраница +EPGPlus.page_up вверх Ñтраница +EPGPlus.prev_bouquet Пакет обратно +EPGPlus.record запиÑÑŒ +EPGPlus.refresh_epg обновить +EPGPlus.remind запомнить +EPGPlus.reset_settings ÐаÑтройки по умолчанию +EPGPlus.save_settings Сохранить наÑтройки +EPGPlus.scroll_mode Scroll Mode +EPGPlus.select_font_name Выбор шрифта +EPGPlus.settings ÐаÑтройки +EPGPlus.slider_width Ширина Ð¿Ð¾Ð»Ñ Ð²Ñех программ +EPGPlus.stretch_mode Stretch Mode +EPGPlus.swap_mode режим обмена +EPGPlus.timeline_fontdate Шрифт даты +EPGPlus.timeline_fonttime Шрифт времени +EPGPlus.vergap1_width Ширина прав.Ð¿Ð¾Ð»Ñ Ñ€Ð°Ð·Ð´ÐµÐ»Ð° +EPGPlus.vergap2_width Ширина лев.Ð¿Ð¾Ð»Ñ Ñ€Ð°Ð·Ð´ÐµÐ»Ð° +EPGPlus.view_mode режим проÑмотра +GENRE.ARTS.0 иÑкуÑÑтво / культура +GENRE.ARTS.1 иÑполнительное иÑкуÑÑтво (танец, пьеÑа Ñ‚.д.) +GENRE.ARTS.10 иÑкуÑÑтво/журнал культуры +GENRE.ARTS.11 мода +GENRE.ARTS.2 изобразительное иÑкуÑÑтво +GENRE.ARTS.3 Ñ€ÐµÐ»Ð¸Ð³Ð¸Ñ +GENRE.ARTS.4 популÑÑ€Ð½Ð°Ñ ÐºÑƒÐ»ÑŒÑ‚ÑƒÑ€Ð°/традиционные иÑкуÑÑтва +GENRE.ARTS.5 литература +GENRE.ARTS.6 кино/фильм +GENRE.ARTS.7 ÑкÑпериментальное кино/видео +GENRE.ARTS.8 транÑлÑции/преÑÑа +GENRE.ARTS.9 новые Ñ‚ÐµÑ‡ÐµÐ½Ð¸Ñ +GENRE.CHILDRENs_PROGRAMMES.0 дети/передачи Ð´Ð»Ñ Ð´ÐµÑ‚ÐµÐ¹ +GENRE.CHILDRENs_PROGRAMMES.1 программа Ð´Ð»Ñ Ð´Ð¾ÑˆÐºÐ¾Ð»ÑŒÐ½Ð¸ÐºÐ¾Ð² +GENRE.CHILDRENs_PROGRAMMES.2 Ñ€Ð°Ð·Ð²Ð»ÐµÐºÐ°Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð° от 6 до 14 +GENRE.CHILDRENs_PROGRAMMES.3 Ñ€Ð°Ð·Ð²Ð»ÐµÐºÐ°Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð° от 10 до 16 +GENRE.CHILDRENs_PROGRAMMES.4 информационные/образовательные/школьные программы +GENRE.CHILDRENs_PROGRAMMES.5 мультфильмы/кукольные фильмы +GENRE.DOCUS_MAGAZINES.0 документальное кино / тележурналы +GENRE.DOCUS_MAGAZINES.1 природа/животные/Ð¾ÐºÑ€ÑƒÐ¶Ð°ÑŽÑ‰Ð°Ñ Ñреда +GENRE.DOCUS_MAGAZINES.2 технологии/еÑтеÑтвенные науки +GENRE.DOCUS_MAGAZINES.3 медицина/пÑихологиÑ/Ñ„Ð¸Ð·Ð¸Ð¾Ð»Ð¾Ð³Ð¸Ñ +GENRE.DOCUS_MAGAZINES.4 зарубежные Ñтраны/ÑкÑпедиции +GENRE.DOCUS_MAGAZINES.5 общеÑтво/духовные науки +GENRE.DOCUS_MAGAZINES.6 дополнительное образование +GENRE.DOCUS_MAGAZINES.7 Ñзыки +GENRE.MOVIE.0 кино/драма +GENRE.MOVIE.1 детектив/триллер +GENRE.MOVIE.2 приключениÑ/веÑтерн/война +GENRE.MOVIE.3 Ð½Ð°ÑƒÑ‡Ð½Ð°Ñ Ñ„Ð°Ð½Ñ‚Ð°Ñтика/Ñ„Ñнтези/ÑƒÐ¶Ð°Ñ +GENRE.MOVIE.4 комедии +GENRE.MOVIE.5 мыло/мелодрама/фольклор +GENRE.MOVIE.6 романтика +GENRE.MOVIE.7 Ñерьезный/клаÑÑичеÑкий/религиозный/иÑторичеÑкий фильм/драма +GENRE.MOVIE.8 кино Ð´Ð»Ñ Ð²Ð·Ñ€Ð¾Ñлых/драма +GENRE.MUSIC_DANCE.0 музыка / балет / танцы +GENRE.MUSIC_DANCE.1 рок/поп +GENRE.MUSIC_DANCE.2 ÑÐµÑ€ÑŒÐµÐ·Ð½Ð°Ñ Ð¼ÑƒÐ·Ñ‹ÐºÐ° /клаÑÑичеÑÐºÐ°Ñ Ð¼ÑƒÐ·Ñ‹ÐºÐ° +GENRE.MUSIC_DANCE.3 фолк/Ñ‚Ñ€Ð°Ð´Ð¸Ñ†Ð¸Ð¾Ð½Ð½Ð°Ñ Ð¼ÑƒÐ·Ñ‹ÐºÐ° +GENRE.MUSIC_DANCE.4 джаз +GENRE.MUSIC_DANCE.5 музыка/опера +GENRE.MUSIC_DANCE.6 балет +GENRE.NEWS.0 новоÑти +GENRE.NEWS.1 новоÑти/погода +GENRE.NEWS.2 лента новоÑтей +GENRE.NEWS.3 документальные +GENRE.NEWS.4 диÑкуÑÑии/интервью/дебаты +GENRE.SHOW.0 Шоу / Игровое шоу +GENRE.SHOW.1 игровое шоу/викторина/ÐºÐ¾Ð½ÐºÑƒÑ€Ñ +GENRE.SHOW.2 варьете +GENRE.SHOW.3 разговорное шоу +GENRE.SOCIAL_POLITICAL.0 Ñоциальные & политичеÑкие ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ / Ð±Ð¸Ð·Ð½ÐµÑ +GENRE.SOCIAL_POLITICAL.1 журналы/отчеты/документалиÑтика +GENRE.SOCIAL_POLITICAL.2 Ñкономика/общеÑтвенные конÑультации +GENRE.SOCIAL_POLITICAL.3 замечательные люди +GENRE.SPORTS.0 Ñпорт +GENRE.SPORTS.1 Ñпециальные (ОлимпийÑкие игры, Мировые чемпионаты и Ñ‚.д.) +GENRE.SPORTS.10 конный Ñпорт +GENRE.SPORTS.11 военный Ñпорт +GENRE.SPORTS.2 Ñпортивные журналы +GENRE.SPORTS.3 футбол +GENRE.SPORTS.4 тенниÑ/Ñквош +GENRE.SPORTS.5 командный Ñпорт (иÑÐºÐ»ÑŽÑ‡Ð°Ñ Ñ„ÑƒÑ‚Ð±Ð¾Ð») +GENRE.SPORTS.6 атлетика +GENRE.SPORTS.7 мотоÑпорт +GENRE.SPORTS.8 водный Ñпорт +GENRE.SPORTS.9 зимний Ñпорт +GENRE.TRAVEL_HOBBIES.0 путешеÑÑ‚Ð²Ð¸Ñ Ð¸ отдых +GENRE.TRAVEL_HOBBIES.1 туризм/путешеÑÑ‚Ð²Ð¸Ñ +GENRE.TRAVEL_HOBBIES.2 ремеÑло +GENRE.TRAVEL_HOBBIES.3 автомобильный Ñпорт +GENRE.TRAVEL_HOBBIES.4 здоровье +GENRE.TRAVEL_HOBBIES.5 ÐºÑƒÑ…Ð½Ñ +GENRE.TRAVEL_HOBBIES.6 реклама/покупки +GENRE.TRAVEL_HOBBIES.7 ÑадоводÑтво +GENRE.UNKNOWN определить Ð½ÐµÐ»ÑŒÐ·Ñ +apids.hint_1 Введите APIDs потока +apids.hint_2 в hex, разделÑйте ' ' +apidselector.head Выбор Ñзыка +audiomenu.PCMOffset Уменьшение громкоÑти PCM +audiomenu.analogout Ðналоговый выход +audiomenu.avs avs +audiomenu.avs_control Управление громкоÑтью avs/ost +audiomenu.dolbydigital Dolby Digital +audiomenu.head Ðудио ÐаÑтройки +audiomenu.lirc lirc +audiomenu.monoleft левое моно +audiomenu.monoright правое моно +audiomenu.ost ost +audiomenu.stereo Ñтерео +audioplayer.add Добавить +audioplayer.artist_title ÐртиÑÑ‚, Ðазвание +audioplayer.building_search_index поÑтроение индекÑа поиÑка +audioplayer.button_select_title_by_id ПоиÑк по ID +audioplayer.button_select_title_by_name ПоиÑк по имени +audioplayer.defdir Каталог по умолчанию +audioplayer.delete Удалить +audioplayer.deleteall Удалить вÑе +audioplayer.display_order ПорÑдок Ñортировки +audioplayer.enable_sc_metadata enable shoutcast meta data parsing +audioplayer.fastforward Вперед +audioplayer.follow Выбор текущей +audioplayer.head Ðудио-плейлиÑÑ‚ +audioplayer.highprio Задать выÑокий приоритет +audioplayer.id3scan Сканировать ID3-теги +audioplayer.jump_backwards Шаг назад +audioplayer.jump_dialog_hint1 Выбор направление отката +audioplayer.jump_dialog_hint2 (в Ñекундах) +audioplayer.jump_dialog_title Выбор направление отката +audioplayer.jump_forwards Шаг вперёд +audioplayer.keylevel Другие кнопки ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ +audioplayer.name Ðудиоплеер +audioplayer.pause Пауза +audioplayer.play Играть +audioplayer.playing Выбранный трек +audioplayer.playlist_fileerror_msg Файл Ñоздать не удалоÑÑŒ: +audioplayer.playlist_fileerror_title Ошибочка +audioplayer.playlist_fileoverwrite_msg Этот файл будет перезапиÑан: +audioplayer.playlist_fileoverwrite_title ПерезапиÑать? +audioplayer.playlist_name Ð˜Ð¼Ñ Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° Ñ Ð¿Ð»ÐµÐ¹-лиÑтом +audioplayer.playlist_name_hint1 Введите Ð¸Ð¼Ñ Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° плей-лиÑта +audioplayer.playlist_name_hint2 РаÑширение .m3u добавитÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки +audioplayer.reading_files чтение файлов +audioplayer.repeat_on Разрешить повтор +audioplayer.rewind Обратно +audioplayer.save_playlist Сохранить лиÑÑ‚ +audioplayer.screensaver_timeout Включить Screensaver (мин, 0=откл.) +audioplayer.select_title_by_name ПоиÑк Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾ имени (SMS) +audioplayer.show_playlist Показать Плей-лиÑÑ‚ +audioplayer.shuffle Смена порÑдка +audioplayer.stop ОÑтановить +audioplayer.title_artist Ðазвание, ÐртиÑÑ‚ +audioplayerpicsettings.general Ðудиоплеер и Картинки +bookmarkmanager.delete Удалить +bookmarkmanager.name Закладки +bookmarkmanager.rename Переименовать +bookmarkmanager.select Выбрать +bouqueteditor.add Добавить +bouqueteditor.bouquetname Ð˜Ð¼Ñ Ð¿Ð°ÐºÐµÑ‚Ð° +bouqueteditor.delete Удалить +bouqueteditor.discardingchanges Отмена изменений. /nподождите пожалуйÑта... +bouqueteditor.hide СпрÑтать +bouqueteditor.lock Блокировать +bouqueteditor.move ПеремеÑтить +bouqueteditor.name Редактор пакетов +bouqueteditor.newbouquetname Ðовое Ð¸Ð¼Ñ Ð¿Ð°ÐºÐµÑ‚Ð° +bouqueteditor.rename Переименовать +bouqueteditor.return готов +bouqueteditor.savechanges? Сохранить изменениÑ? +bouqueteditor.savingchanges Сохранение изменений. /nподождите пожалуйÑта... +bouqueteditor.switch добавить/удалить +bouqueteditor.switchmode ТВ/Радио +bouquetlist.head Пакеты +cablesetup.provider кабельный провайдер +channellist.head Ð’Ñе ÑервиÑÑ‹ +channellist.nonefound Ðет ни одного канала! \nПожалуйÑта выполните Ñканирование\n(кнопка DREAM -> СервиÑÑ‹) +channellist.since начало в %02d:%02d +colorchooser.alpha alpha +colorchooser.blue Ñиний +colorchooser.green зеленый +colorchooser.red краÑный +colormenu.background Фон +colormenu.fade Fade-режим Ð´Ð»Ñ Ð¼ÐµÐ½ÑŽ +colormenu.font Размер шрифта +colormenu.gtx_alpha ПрозрачноÑÑ‚ÑŒ (GTX) +colormenu.head ÐаÑтройки цвета +colormenu.menucolors Выбор цветов в меню +colormenu.statusbar Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð°Ñ Ð¿Ð°Ð½ÐµÐ»ÑŒ +colormenu.textcolor Цвет текÑта +colormenu.themeselect Выбор темы +colormenu.timing Ð’Ñ€ÐµÐ¼Ñ Ð¿Ð¾ÐºÐ°Ð·Ð° OSD +colormenusetup.head Выбор цветов в меню +colormenusetup.menucontent Содержимое окна +colormenusetup.menucontent_inactive Содержимое окна неактивное +colormenusetup.menucontent_selected Содержимое окна выбранное +colormenusetup.menuhead Заголовок меню +colorstatusbar.head Инфопанель +colorstatusbar.text Инфопанель +colorthememenu.classic_theme Classic +colorthememenu.dblue_theme DarkBlue +colorthememenu.dvb2k_theme DVB2000 +colorthememenu.head Выбор темы +colorthememenu.neutrino_theme Neutrino +date.Apr Ðпр +date.Aug Ðвг +date.Dec Дек +date.Feb Фев +date.Fri Птн +date.Jan Янв +date.Jul Июл +date.Jun Июн +date.Mar Мар +date.May Май +date.Mon Пнд +date.Nov ÐÐ¾Ñ +date.Oct Окт +date.Sat Сбт +date.Sep Сен +date.Sun Ð’Ñк +date.Thu Чтв +date.Tue Ð’Ñ‚Ñ€ +date.Wed Срд +epglist.head Телегид - %s +epglist.noevents Программа передач отÑутÑтвует... +epgviewer.More_Screenings Дата/Ð²Ñ€ÐµÐ¼Ñ Ð¿Ð¾ÐºÐ°Ð·Ð° и повтора на Ñтом канале +epgviewer.nodetailed ÐŸÐ¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ñ‚ÑутÑтвует +epgviewer.notfound Ðет доÑтупа к программе передач +eventlistbar.channelswitch вид Ñортировки +eventlistbar.eventsort Ñортировать +eventlistbar.recordevent запиÑать +favorites.addchannel Этот канал будет добавлен \nв пакет каналов "Избранное". \n Это займет неÑколько Ñекунд... +favorites.bouquetname Избранное +favorites.bqcreated Пакет каналов "Избранное" Ñоздан...\n +favorites.chadded Этот канал добавлен в ÑпиÑок избранных...\n +favorites.chalreadyinbq Этот канал уже еÑÑ‚ÑŒ в ÑпиÑке избранных...\n +favorites.finalhint \nВоÑпользуйтеÑÑŒ редактором пакетов\n Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑпиÑка ваших избранных каналов.\n +favorites.menueadd Добавить канал в избранное +favorites.nobouquets Избранное доÑтупно только из активных пакетов. +filebrowser.delete удалить +filebrowser.denydirectoryleave Absolute start directory +filebrowser.dodelete1 удалÑем раз +filebrowser.dodelete2 удалÑем два +filebrowser.filter.active фильтр вкл +filebrowser.filter.inactive фильтр выкл +filebrowser.head Проводник по каталогам +filebrowser.mark Пометить +filebrowser.nextpage След. Ñтраница +filebrowser.prevpage Пред. Ñтраница +filebrowser.scan Сканирование каталога +filebrowser.select Выбор +filebrowser.showrights Показывать права файлов +filebrowser.sort.date Сорт.(дата) +filebrowser.sort.name Сорт.(имÑ) +filebrowser.sort.namedirsfirst Сорт.(иначе) +filebrowser.sort.size Сорт.(размер) +filebrowser.sort.type Сорт.(тип) +filesystem.is.utf8 file system +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +flashupdate.actionreadflash чтение +flashupdate.cantopenfile не могу открыть файл +flashupdate.cantopenmtd не могу открыть уÑтройÑтво mtd +flashupdate.checkupdate поиÑк новой верÑии +flashupdate.currentreleasecycle ВерÑÐ¸Ñ Ñ€ÐµÐ»Ð¸Ð·Ð° +flashupdate.currentversion_sep Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ +flashupdate.currentversiondate Дата +flashupdate.currentversionsnapshot Тип прошивки +flashupdate.currentversiontime Ð’Ñ€ÐµÐ¼Ñ +flashupdate.erasefailed не могу Ñтереть флешь +flashupdate.erasing Ñтирание флешь +flashupdate.experimentalimage Ð’Ñ‹Ð±Ñ€Ð°Ð½Ð½Ð°Ñ Ð¿Ñ€Ð¾ÑˆÐ¸Ð²ÐºÐ° не проверена и ваш\nтюнер возможно не загрузитÑÑ Ð¿Ð¾Ñле обновлениÑ.\n\nÐ’Ñ‹ дейÑтвительно хотите обновить Ñтой верÑией? +flashupdate.expertfunctions ЭкÑпертные функции +flashupdate.fileis0bytes размер файла 0 байт +flashupdate.fileselector Выбор файла +flashupdate.flashreadyreboot Прошивка уÑпешно запиÑана.\nТюнер ÑÐµÐ¹Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ³Ñ€ÑƒÐ·Ð¸Ñ‚ÑÑ. +flashupdate.getinfofile Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð²ÐµÑ€Ñии +flashupdate.getinfofileerror не могу определить верÑию +flashupdate.getupdatefile обновление +flashupdate.getupdatefileerror не могу обновить +flashupdate.globalprogress Общий прогреÑÑ: +flashupdate.head Обновление Ñофта +flashupdate.md5check проверка прошивки +flashupdate.md5sumerror прошивка без ошибок +flashupdate.msgbox Ðайдена ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ð½Ð¾Ð²Ð°Ñ Ð¿Ñ€Ð¾ÑˆÐ¸Ð²ÐºÐ°:\nДата: %s, %s\nбазовый имидж: %s\nтип имиджа: %s\n\nХотите загрузить и уÑтановить Ñту верÑию ÑейчаÑ? +flashupdate.msgbox_manual Ðайден новый файл:\nДата: %s, %s\nБазовый имидж: %s\nТип: %s\n\n Хотите загрузить и уÑтановить Ñту верÑию ÑейчаÑ? +flashupdate.mtdselector Выбор раздела +flashupdate.programmingflash программирование флешь +flashupdate.proxypassword Пароль +flashupdate.proxypassword_hint1 введите пароль прокÑи-Ñервера +flashupdate.proxypassword_hint2 пуÑтое поле означает, что Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð½ÐµÑ‚ +flashupdate.proxyserver ХоÑÑ‚ +flashupdate.proxyserver_hint1 введите прокÑи-Ñервер или IP-Ð°Ð´Ñ€ÐµÑ Ð² виде host:port +flashupdate.proxyserver_hint2 пуÑтое поле означает, что нет прокÑи-Ñервера +flashupdate.proxyserver_sep ПрокÑи-Ñервер +flashupdate.proxyusername Ð˜Ð¼Ñ +flashupdate.proxyusername_hint1 введите Ð¸Ð¼Ñ Ð¿Ñ€Ð¾ÐºÑи-Ñервера +flashupdate.proxyusername_hint2 пуÑтое поле означает, что нет авт.прокÑи +flashupdate.readflash Сохранить прошивку полноÑтью +flashupdate.readflashmtd Сохранить один из разделов +flashupdate.ready готов +flashupdate.reallyflashmtd Уверены что хотите запиÑать?\n\nЕÑли произойдет ошибка или прошивка не\nÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ Ñ‚ÑŽÐ½ÐµÑ€ не перегрузитÑÑ.\n\nÐ¸Ð¼Ñ Ð¸Ð¼Ð¸Ð´Ð¶Ð°: %s\nЦель: %s +flashupdate.savesuccess Прошивка уÑпешно Ñохранена\nв %s. +flashupdate.selectimage ДоÑтупные прошивки и файлы +flashupdate.squashfs.noversion Проверка обновлений Ð´Ð»Ñ SquashFS-верÑии возможна только по интернету.\n Ð’Ñ‹ уверены в Ñвоем желании уÑтановить Ñту прошивку? +flashupdate.titlereadflash Чтение флешь +flashupdate.titlewriteflash ЗапиÑываю флешь +flashupdate.updatemode Режим Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ +flashupdate.updatemode_internet интернет +flashupdate.updatemode_manual вручную (ftp) +flashupdate.url_file файл конфигурации +flashupdate.versioncheck проверка верÑии +flashupdate.writeflash ЗапиÑать прошивку полноÑтью +flashupdate.writeflashmtd ЗапиÑать один из разделов +flashupdate.wrongbase Ваша верÑÐ¸Ñ Ð¿Ñ€Ð¾ÑˆÐ¸Ð²ÐºÐ¸ отличаетÑÑ Ð¾Ñ‚ выбранной Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸.\nЗагрузить в любом Ñлучае? +fontmenu.channellist СпиÑок каналов +fontmenu.epg EPG +fontmenu.eventlist СпиÑок Ñобытий +fontmenu.gamelist СпиÑок игр +fontmenu.head ÐаÑтройки размера шрифтов +fontmenu.infobar Инфопанель +fontsize.channel_num_zap прÑмой выбор +fontsize.channellist СпиÑок каналов +fontsize.channellist_descr ОпиÑание +fontsize.channellist_number Ðомер +fontsize.epg_date EPG дата +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG заголовок +fontsize.eventlist_datetime Дата / Ð’Ñ€ÐµÐ¼Ñ +fontsize.eventlist_itemlarge Большой +fontsize.eventlist_itemsmall Маленький +fontsize.eventlist_title Заголовок +fontsize.filebrowser_item Содержимое проводника +fontsize.gamelist_itemlarge Большой +fontsize.gamelist_itemsmall Маленький +fontsize.hint Фонт инициализации, \nждем... +fontsize.infobar_channame Ð˜Ð¼Ñ ÐºÐ°Ð½Ð°Ð»Ð° +fontsize.infobar_info Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ +fontsize.infobar_number Ðомер +fontsize.infobar_small Маленький +fontsize.menu ТекÑÑ‚ меню +fontsize.menu_info Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ ÐœÐµÐ½ÑŽ +fontsize.menu_title Заголовок меню +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +infoviewer.epgnotload EPG не загружено.... +infoviewer.epgwait попытка получить программу передач... +infoviewer.eventlist Телегид +infoviewer.languages Ðудио +infoviewer.motor_moving позиционирование антенны +infoviewer.nocurrent Ðет информации о текущей передаче +infoviewer.noepg Ðет доÑтупа к программе передач +infoviewer.notavailable Канал не доÑтупен +infoviewer.selecttime Ð’Ñ€ÐµÐ¼Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° +infoviewer.streaminfo ХарактериÑтики +infoviewer.subchan_disp_pos Subchannel display +infoviewer.subservice Ð”Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ +infoviewer.waittime Попытка получить текущее времÑ... +ipsetup.hint_1 ИÑпользуйте 0..9, или Up/Down, +ipsetup.hint_2 OK - Ñохранено, LAME! - Отмена +keybindingmenu.RC Ð”Ð»Ñ ÐšÐ½Ð¾Ð¿Ð¾Ðº: повтор-блокирование +keybindingmenu.addrecord Добавить таймер запиÑи +keybindingmenu.addremind Добавить таймер Ð¿ÐµÑ€ÐµÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ +keybindingmenu.allchannels_on_ok Ð’Ñе ÑервиÑÑ‹ +keybindingmenu.bouquetchannels_on_ok Текущий пакет +keybindingmenu.bouquetdown Предыдущий пакет +keybindingmenu.bouquethandling Пакет-контроль +keybindingmenu.bouquetlist_on_ok СпиÑок пакетов +keybindingmenu.bouquetup Следующий пакет +keybindingmenu.cancel Закрыть ÑпиÑок каналов +keybindingmenu.channeldown Канал вниз +keybindingmenu.channellist СпиÑок каналов +keybindingmenu.channelup Канал вверх +keybindingmenu.head ÐаÑтройка кнопок +keybindingmenu.lastchannel ВернутьÑÑ Ð½Ð° канал +keybindingmenu.modechange Изменение режима +keybindingmenu.pagedown Страница вниз +keybindingmenu.pageup Страница вверх +keybindingmenu.quickzap Quickzap +keybindingmenu.repeatblock Задержка повтора +keybindingmenu.repeatblockgeneric ÐžÐ±Ñ‰Ð°Ñ Ð·Ð°Ð´ÐµÑ€Ð¶ÐºÐ° +keybindingmenu.sort Изменить порÑдок Ñортировки +keybindingmenu.subchanneldown Подканалы вниз +keybindingmenu.subchannelup Подканалы вверх +keybindingmenu.tvradiomode ТВ/Радио-режим +keybindingmenu.zaphistory СпиÑок переключений +keychooser.head ÐаÑтроить новые кнопки +keychooser.text1 Ðажмите новую кнопку +keychooser.text2 подождете неÑколько Ñекунд Ð´Ð»Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð° +keychoosermenu.currentkey Ñ‚ÐµÐºÑƒÑ‰Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÐ° +keychoosermenu.setnew наÑтроить новые кнопки +keychoosermenu.setnone нет кнопки +languagesetup.head ÐаÑтройка Ñзыка +languagesetup.select Язык +lcdcontroler.brightness ЯркоÑÑ‚ÑŒ +lcdcontroler.brightnessstandby ЯркоÑÑ‚ÑŒ деж.режима +lcdcontroler.contrast КонтраÑтноÑÑ‚ÑŒ +lcdcontroler.head ЖК ÐаÑтройки +lcdmenu.autodimm Ðвто dimm +lcdmenu.head ЖК ÐаÑтройки +lcdmenu.inverse Инвертировать изображение +lcdmenu.lcdcontroler КонтраÑтноÑÑ‚ÑŒ / ЯркоÑÑ‚ÑŒ +lcdmenu.power Питание +lcdmenu.statusline Ð’ Ñтроке ÑтатуÑа +lcdmenu.statusline.both громкоÑÑ‚ÑŒ / Ð²Ñ€ÐµÐ¼Ñ +lcdmenu.statusline.playtime Ð²Ñ€ÐµÐ¼Ñ +lcdmenu.statusline.volume громкоÑÑ‚ÑŒ +mainmenu.audioplayer Ðудиоплеер +mainmenu.games Игры +mainmenu.head Меню ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ +mainmenu.movieplayer Видеоплеер +mainmenu.pausesectionsd Чтение EPG +mainmenu.pictureviewer ПроÑмотр картинок +mainmenu.radiomode Радио-каналы +mainmenu.recording ЗапиÑÑŒ +mainmenu.recording_start Ñтарт +mainmenu.recording_stop Ñтоп +mainmenu.scartmode Scart-режим +mainmenu.scripts Скрипты +mainmenu.service СервиÑÑ‹ +mainmenu.settings ÐаÑтройки +mainmenu.shutdown Выключить +mainmenu.sleeptimer Таймер дежурного режима +mainmenu.tvmode ТВ-каналы +mainsettings.audio Ðудио +mainsettings.colors Цвета / Темы / Шрифты +mainsettings.head ÐаÑтройки +mainsettings.keybinding ÐаÑтройки пульта ДУ +mainsettings.language Языки +mainsettings.lcd ЖК-диÑплей +mainsettings.misc Прочие наÑтройки +mainsettings.network Сеть +mainsettings.recording ЗапиÑÑŒ +mainsettings.savesettingsnow Ñохранить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ +mainsettings.savesettingsnow_hint Сохранение Ñделанных изменений.\nвыполнÑетÑÑ... +mainsettings.streaming Видеоплеер +mainsettings.video Видео +menu.back назад +messagebox.back Ðазад +messagebox.cancel Отменить +messagebox.discard Отменить изменениÑ? +messagebox.error Ошибка +messagebox.info Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ +messagebox.no Ðет +messagebox.yes Да +miscsettings.bootinfo Показывать информацию при Ñтарте +miscsettings.bootmenu Показывать меню загрузки +miscsettings.driver_boot Загрузка ÑиÑтемы +miscsettings.fb_destination Expert! Boot-Console +miscsettings.general ОÑновное +miscsettings.head Прочие наÑтройки +miscsettings.hwsections HW-Sections иÑпользовать +miscsettings.infobar_sat_display Ðазвание Ñпутника на инфопанели +miscsettings.noaviawatchdog enable AVIA watchdog +miscsettings.noenxwatchdog enable eNX watchdog +miscsettings.pmtupdate enable pmt update +miscsettings.shutdown_real Включить дежурный режим +miscsettings.shutdown_real_rcdelay Задержка Ð²Ñ‹ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ +miscsettings.sptsmode SPTS-Mode иÑпользовать +miscsettings.startbhdriver загрузить драйвера BH-Режима +motorcontrol.head ÐаÑтройки мотора +movieplayer.bookmark Закладки +movieplayer.bookmarkname Ðазвание закладки +movieplayer.bookmarkname_hint1 Введите название +movieplayer.bookmarkname_hint2 Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð¹ закладки +movieplayer.buffering БуферизациÑ... +movieplayer.defdir Каталог по умолчанию +movieplayer.defplugin Старт плагина +movieplayer.dvdplayback ПроÑмотр DVD (VLC) +movieplayer.fileplayback ПроÑмотр файлов (VLC) +movieplayer.goto Прыгнуть в ... +movieplayer.goto.h1 = -> абÑолютный прыжок +movieplayer.goto.h2 +,- -> отноÑительный прыжок +movieplayer.head Видеоплеер +movieplayer.nostreamingserver Стрим-Ñервер недоÑтупен. +movieplayer.pesplayback ПроÑмотр PES-файлов +movieplayer.pleasewait Подождите пожалуйÑта.\nСоединение Ñо Ñтрим-Ñервером... +movieplayer.toomanybookmarks Слишком много закладок.\n Удалите одну из уже ÑущеÑтвующих. +movieplayer.tshelp1 Ñтоп +movieplayer.tshelp10 назад на 10 мин. +movieplayer.tshelp11 вперед на 10 мин. +movieplayer.tshelp12 подробнее Ñмотри на http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 выбор звук.дорожки +movieplayer.tshelp3 пауза/продолжить +movieplayer.tshelp4 добавить закладку +movieplayer.tshelp5 общее Ð²Ñ€ÐµÐ¼Ñ +movieplayer.tshelp6 назад на 1 мин. +movieplayer.tshelp7 вперед на 1 мин. +movieplayer.tshelp8 назад на 5 мин. +movieplayer.tshelp9 вперед на 5 мин. +movieplayer.tsplayback ПроÑмотр TS-файлов +movieplayer.vcdplayback ПроÑмотр (S)VCD (VLC) +movieplayer.vlchelp1 Ñтоп +movieplayer.vlchelp10 назад на 10 мин. +movieplayer.vlchelp11 вперед на 10 мин. +movieplayer.vlchelp12 подробнее Ñмотри на: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 реÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ð·Ð¸Ñ +movieplayer.vlchelp3 пауза/продолжить +movieplayer.vlchelp4 добавить закладку +movieplayer.vlchelp5 общее Ð²Ñ€ÐµÐ¼Ñ +movieplayer.vlchelp6 назад на 1 мин. +movieplayer.vlchelp7 вперед на 1 мин. +movieplayer.vlchelp8 назад на 5 мин. +movieplayer.vlchelp9 вперед на 5 мин. +movieplayer.wrongvlcversion Эта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð½Ðµ поддерживаетÑÑ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ верÑией VLC +networkmenu.broadcast Broadcast +networkmenu.dhcp DHCP +networkmenu.gateway ОÑновной шлюз +networkmenu.head ÐаÑтройки Ñети +networkmenu.ipaddress IP-Ð°Ð´Ñ€ÐµÑ +networkmenu.mount NFS/CIFS/FTPFS +networkmenu.nameserver DNS-Ñервер +networkmenu.netmask МаÑка подÑети +networkmenu.setupnow применить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ +networkmenu.setuponstartup ÐаÑтроить Ñеть при Ñтарте +networkmenu.show ИÑпользуемые наÑтройки +networkmenu.test ТеÑÑ‚ Ñетевого ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ +nfs.alreadymounted Уже подключали +nfs.automount Подключать при включении +nfs.dir каталог/обший +nfs.ip IP-Ð°Ð´Ñ€ÐµÑ Ñервера +nfs.localdir Локальный каталог +nfs.mount Подключить Ñетевой раздел +nfs.mount_options Параметры Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ +nfs.mountok подключение ÑоÑтоÑлоÑÑŒ +nfs.mounterror Ошибка при подключении +nfs.mounterror_notsup Тип файловой ÑиÑтемы не поддерживаетÑÑ +nfs.mountnow Подключить ÑÐµÐ¹Ñ‡Ð°Ñ +nfs.mounttimeout Ошибка процеÑÑа подключениÑ: таймаут +nfs.password пароль +nfs.remount Повторить подключение +nfs.type тип +nfs.type_cifs CIFS +nfs.type_lufs FTPFS +nfs.type_nfs NFS +nfs.umount Отключить Ñетевой раздел +nfs.umounterror Ошибка Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð´ÐµÐ»Ð° +nfs.username Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ +nfsmenu.head NFS/CIFS/FTPFS наÑтройки +nvod.percentage (%d%% над) +nvod.starting (Старт через %d минут) +nvodselector.directormode Директ режим +nvodselector.head Выбор времени Ñтарта +nvodselector.subservice Выбор доп.ÑервиÑа +options.default ÐаÑтройки по умолчанию +options.fb framebuffer +options.null null +options.off выкл. +options.on вкл. +options.serial serial +parentallock.changepin Изменить PIN-код +parentallock.changepin_hint1 Введите новый PIN-код. +parentallock.changetolocked на пакет +parentallock.head Введите PIN-код +parentallock.lockage Передачи +parentallock.lockage12 до 12 лет +parentallock.lockage16 до 16 лет +parentallock.lockage18 до 18 лет +parentallock.lockedchannel УÑтановлена защита на проÑмотр... +parentallock.lockedprogram УÑтановлена зашита на проÑмотр (Ñ %d лет по) +parentallock.never не иÑпользовать +parentallock.onsignal на вÑе +parentallock.parentallock ВозраÑÑ‚Ð½Ð°Ñ Ð·Ð°Ñ‰Ð¸Ñ‚Ð° +parentallock.prompt Зашита PIN-кодом +pictureviewer.defdir Каталог по умолчанию +pictureviewer.head ПроÑмотр картинок +pictureviewer.help1 Режим меню +pictureviewer.help10 режим проÑмотра +pictureviewer.help11 перезагрузить картинку +pictureviewer.help12 Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° +pictureviewer.help13 ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° +pictureviewer.help14 уменьшить +pictureviewer.help15 увеличить +pictureviewer.help16 прокрутка вверх +pictureviewer.help17 прокрутка влево +pictureviewer.help18 прокрутка вправо +pictureviewer.help19 прокрутка вниз +pictureviewer.help2 показ картинки +pictureviewer.help20 Ñмена порÑдка Ñортировки +pictureviewer.help21 в оригнальный размер +pictureviewer.help22 выход +pictureviewer.help3 Ñмена порÑдка Ñортировки +pictureviewer.help4 не менÑÑ‚ÑŒ размеры +pictureviewer.help5 режим Ñлайдов +pictureviewer.help6 Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° +pictureviewer.help7 ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð¸Ð½ÐºÐ° +pictureviewer.help8 Ñмена порÑдка Ñортировки +pictureviewer.help9 выход +pictureviewer.resize.color_average раÑширенное +pictureviewer.resize.none не иÑпользовать +pictureviewer.resize.simple проÑтое +pictureviewer.scaling МаÑштабирование +pictureviewer.show Показать +pictureviewer.slide_time Задержка в режиме Ñлайдов +pictureviewer.slideshow Режим Ñлайдов +pictureviewer.sortorder ПорÑдок Ñортировки +pictureviewer.sortorder.date (дата) +pictureviewer.sortorder.filename (Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°) +ping.ok доÑтупен (ping) +ping.protocol недоÑтупен (ошибка Ñервера или протокола) +ping.socket недоÑтупен (ошибка Ñокета) +ping.unreachable недоÑтупен +pinprotection.head Введите PIN-код +pinprotection.wrongcode Ðеверный PIN-код! Повторите ввод. +plugins.result вывод плагина +rclock.lockmsg Ваш пульт ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²Ð°Ð½.\n Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ, нажмите <КРÐСÐУЮ> \n и на вашем пульте управлениÑ. +rclock.menueadd Заблокировать Пульт ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ +rclock.title Заблокировать Пульт ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ +rclock.unlockmsg Пульт ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð°ÐºÑ‚Ð¸Ð²Ð¸Ñ€Ð¾Ð²Ð°Ð½. +recordingmenu.choose_direct_rec_dir куда веÑти запиÑÑŒ +recordingmenu.defdir Каталог Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи +recordingmenu.epg_for_filename Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ñ Ð´Ð°Ð½Ð½Ñ‹Ð¼Ð¸ о программе +recordingmenu.file direkt (в файл) +recordingmenu.filesettings наÑтройки direkt(в файл) +recordingmenu.head ÐаÑтройки запиÑи +recordingmenu.help Режимы запиÑи:\n--------------------------\nÑервер:\nиÑпользуетÑÑ Ñофт уÑтановленный на ПК\n\n(analog) vcr:\nиÑпользуетÑÑ Ð²Ñ‹Ñ…Ð¾Ð´ Ð´Ð»Ñ Ð²Ð¸Ð´ÐµÐ¾Ð¼Ð°Ð³Ð½Ð¸Ñ‚Ð¾Ñ„Ð¾Ð½Ð°\n\ndirect (в файл):\nзапиÑÑŒ в предварительно монтированный NFS-каталог\nили в каталоги внутреннего жеÑткого диÑка\nTS: иÑпользует spts-режим (Ð´Ð»Ñ Dbox2)\nPES: spts-режим должен быть выключен (Ð´Ð»Ñ Dbox2)\n\n\nМакÑ.размер файла:\n---------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: без ограничений (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart не переключатьÑÑ Ð½Ð° SCART +recordingmenu.off отключить +recordingmenu.recording_type Режим запиÑи +recordingmenu.ringbuffers значение Ð´Ð»Ñ ringbuffers +recordingmenu.server Ñервер +recordingmenu.server_ip IP-Ð°Ð´Ñ€ÐµÑ Ñервера запиÑи +recordingmenu.server_mac MAC-Ð°Ð´Ñ€ÐµÑ +recordingmenu.server_port Порт Ñервера запиÑи +recordingmenu.server_wakeup WOL Ñервера запиÑи +recordingmenu.setupnow применить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ +recordingmenu.splitsize МакÑ.размер файла (MB) +recordingmenu.stopplayback ОÑтановить воÑпроизведение +recordingmenu.stopsectionsd ОÑтановить sectionsd +recordingmenu.stream_vtxt_pid ВидеотекÑÑ‚ +recordingmenu.use_fdatasync write synchronous (fdatasync) +recordingmenu.use_o_sync Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ (O_SYNC) +recordingmenu.vcr vcr +recordtimer.announce ЗапиÑÑŒ начинаетÑÑ Ñ‡ÐµÑ€ÐµÐ· неÑколько минут +repeatblocker.hint_1 Ð’Ñ€ÐµÐ¼Ñ Ð² ms Ð´Ð»Ñ Ñ€Ð°ÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ 2-го Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ ÐºÐ½Ð¾Ð¿ÐºÐ¸ +repeatblocker.hint_2 Ðажмите 0 Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ (краÑÐ½Ð°Ñ - пробел) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-повторы +satsetup.extended ÐаÑтройки DiSEqC +satsetup.extended_motor ÐаÑтройки мотора +satsetup.minidiseqc мини-DiSEqC +satsetup.motorcontrol Ð ÑƒÑ‡Ð½Ð°Ñ Ð½Ð°Ñтройка мотора +satsetup.nodiseqc без DiSEqC +satsetup.satellite Спутники +satsetup.savesettingsnow Ñохранить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ +satsetup.smatvremote SMATV Remote Tuning +scants.actcable Кабельные: +scants.actsatellite Спутники: +scants.bouquet Пакеты +scants.bouquet_create Ñоздать новый +scants.bouquet_erase Ñтереть вÑе +scants.bouquet_leave иÑпользовать текущий +scants.bouquet_satellite пакет Ñпутника +scants.bouquet_update обновить +scants.channel Каналы: +scants.failed Ðеудачное Ñканирование транÑпондера! +scants.finished Сканирование транÑпондеров завершено! +scants.freqdata ЧаÑтота: +scants.head Сканирование транÑпондеров +scants.numberofdataservices Данные +scants.numberofradioservices Радио +scants.numberoftotalservices Ð’Ñего +scants.numberoftvservices ТВ +scants.provider Провайдеры: +scants.startnow Ðачать Ñканирование +scants.transponders ТранÑпондеры: +screensetup.lowerright green = наÑтроить Ñнизу Ñправа +screensetup.upperleft red = наÑтроить Ñверху Ñлева +servicemenu.head СервиÑÑ‹ +servicemenu.reload Перегрузить ÑпиÑок каналов +servicemenu.reload_hint Перезагрузка ÑпиÑка каналов,\nвыполнÑетÑÑ... +servicemenu.scants ПоиÑк каналов +servicemenu.ucodecheck Check ucodes +servicemenu.update Обновление прошивки +settings.help ПодÑказка +settings.missingoptionsconffile ÐаÑтройки ÑиÑтемы обновлены.\nÐовые уÑтановки заменÑÑ‚ наÑтройки по умолчанию. +settings.noconffile ÐаÑтройки ÑиÑтемы отÑутÑтвуют.\nИÑпользуютÑÑ Ð½Ð°Ñтройки по умолчанию. +settings.pos_bottom_left низ лево +settings.pos_bottom_right низ право +settings.pos_top_left верх лево +settings.pos_top_right верх право +shutdowntimer.announce Dbox будет выключен через 1 минуту.\nОтменить выключение? +sleeptimerbox.announce Отключение через 1 минуту +sleeptimerbox.hint1 Ð’Ñ€ÐµÐ¼Ñ Ð´Ð¾ Ð²Ñ‹ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð² минутах. (000=откл) +sleeptimerbox.hint2 Ваш Dbox будет выключен через указанное времÑ. +sleeptimerbox.title Таймер перехода в дежурный режим +streamfeatures.head Меню дополнений +streaminfo.aratio Aspect Ratio +streaminfo.aratio_unknown Aspect Ratio: неизвеÑтный +streaminfo.audiotype Audiotype +streaminfo.audiotype_unknown Audiotype: неизвеÑтный +streaminfo.bitrate Bitrate +streaminfo.framerate Framerate +streaminfo.framerate_unknown Framerate: неизвеÑтный +streaminfo.head Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ потоке +streaminfo.not_available не предÑтавлен +streaminfo.resolution Resolution +streaminfo.signal Ñигнал +streaming.buffer_overflow ЗапиÑÑŒ прервана,\n ÑкороÑÑ‚ÑŒ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… низкаÑ. +streaming.busy Идет запиÑÑŒ!\n ЕÑли запиÑÑŒ не включена, а Ð’Ñ‹ получили Ñто Ñообщение, то пожалуйÑта перегрузите Neutrino. +streaming.dir_not_writable Ðет доÑтупа в папку Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи.\nЗапиÑÑŒ не возможна. +streaming.success ЗапиÑÑŒ прошла уÑпешно. +streaming.write_error ЗапиÑÑŒ прервана,\n ошибка в процеÑÑе Ñамой запиÑи. +streaming.write_error_open ЗапиÑÑŒ прервана,\n файл Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи не может быть открыт. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head ÐаÑтройки видеоплеера +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off отключен +streamingmenu.on включен +streamingmenu.server_ip IP-Ð°Ð´Ñ€ÐµÑ Ñтрим-Ñервера +streamingmenu.server_port Порт Ñтрим-Ñервера +streamingmenu.streaming_audiorate Ðудио-поток (kbs) +streamingmenu.streaming_force_avi_rawaudio AC3 Ð´Ð»Ñ AVI +streamingmenu.streaming_force_transcode_video ТранÑкод видео (MPG/VCD) +streamingmenu.streaming_resolution Размер кадра +streamingmenu.streaming_server_cddrive DVD-привод +streamingmenu.streaming_server_startdir Каталог (VLC) +streamingmenu.streaming_transcode_audio ТранÑкод аудио (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec Видео-кодек MPEG +streamingmenu.streaming_type Стрим-Ñервер +streamingmenu.streaming_videorate Видео-поток (kbs) +streamingserver.noconnect Ðет ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñо Ñтрим-Ñервером.\nПринÑтие данных оÑтановлено. +stringinput.caps большие / маленькие +stringinput.clear очиÑтить вÑе +timer.eventrecord.msg ... Быть или не быть? ;-) +timer.eventrecord.title РаÑпиÑание запиÑи +timer.eventtimed.msg Событие запланировано.\nВаш Dbox будет включен и \nпереключитÑÑ Ð½Ð° Ñтот канал в заданное времÑ. +timer.eventtimed.title РаÑпиÑание Ñобытий +timerbar.channelswitch РаÑпиÑание +timerbar.recordevent ЗапиÑÑŒ +timerlist.alarmtime Ð’Ñ€ÐµÐ¼Ñ ALARM +timerlist.apids Ðудио PIDs +timerlist.bouquetselect Выбор пакета +timerlist.channel Каналы +timerlist.channelselect Выбор канала +timerlist.delete Удалить +timerlist.menumodify Изменить таймер +timerlist.menunew Ðовый таймер +timerlist.message Сообщение +timerlist.moderadio Радио каналы +timerlist.modeselect Тип канала +timerlist.modetv ТВ каналы +timerlist.modify Изменить +timerlist.name СпиÑок таймеров +timerlist.new Ðовый таймер +timerlist.plugin Плагин +timerlist.program.unknown ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð° +timerlist.recording_dir каталог Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи +timerlist.reload Перегрузить +timerlist.repeat Повторение +timerlist.repeat.biweekly раз в 2 недели +timerlist.repeat.byeventdescription see timer +timerlist.repeat.daily ежедневно +timerlist.repeat.fourweekly раз в 4 недели +timerlist.repeat.friday Птн +timerlist.repeat.monday Пон +timerlist.repeat.monthly ежемеÑÑчно +timerlist.repeat.once одноразово +timerlist.repeat.saturday Сбт +timerlist.repeat.sunday Ð’Ñкр +timerlist.repeat.thursday Чтв +timerlist.repeat.tuesday Ð’Ñ‚Ñ€ +timerlist.repeat.unknown Хрен знает что +timerlist.repeat.wednesday Срд +timerlist.repeat.weekdays по днÑм недели +timerlist.repeat.weekly еженедельно +timerlist.repeatcount повторы +timerlist.repeatcount.help1 чиÑло повторов +timerlist.repeatcount.help2 0 - повтор навÑегда +timerlist.save Сохранить таймер +timerlist.standby Тип Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ +timerlist.standby.off oÑтавить в дежур.режиме +timerlist.standby.on вывеÑти из дежур.режима +timerlist.stoptime Ð’Ñ€ÐµÐ¼Ñ Ð¾Ñтановки +timerlist.type Режим таймера +timerlist.type.execplugin ЗапуÑтить плагин +timerlist.type.nextprogram Ð¡Ð»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð° +timerlist.type.record запиÑÑŒ +timerlist.type.remind напоминание +timerlist.type.shutdown полное выкл. +timerlist.type.sleeptimer выкл. в дежур.режим +timerlist.type.standby вкл. из дежур.режима +timerlist.type.unknown определить Ð½ÐµÐ»ÑŒÐ·Ñ +timerlist.type.zapto включить на канал +timerlist.weekdays дни недели +timerlist.weekdays.hint_1 Пон Ð’Ñ‚Ñ€ Срд Чтв Птн Сбт Ð’Ñкр +timerlist.weekdays.hint_2 'X'=таймер '-' нет таймера +timersettings.record_safety_time_after ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð¾Ñтановки запиÑи +timersettings.record_safety_time_after.hint_1 ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ в минутах. (00=выкл). Это Ð²Ñ€ÐµÐ¼Ñ +timersettings.record_safety_time_after.hint_2 будет добавлÑетÑÑ Ðº каждому таймеру запиÑи. +timersettings.record_safety_time_before ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ñтарта запиÑи +timersettings.record_safety_time_before.hint_1 ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ в минутах. (00=выкл). Это Ð²Ñ€ÐµÐ¼Ñ +timersettings.record_safety_time_before.hint_2 будет отниматьÑÑ Ð¾Ñ‚ каждого таймера запиÑи. +timersettings.separator ÐаÑтройки таймера +timing.chanlist СпиÑок каналов +timing.epg Epg +timing.filebrowser Проводник по каталогам +timing.head Ð’Ñ€ÐµÐ¼Ñ Ð¿Ð¾ÐºÐ°Ð·Ð° OSD +timing.hint_1 Ð’Ñ€ÐµÐ¼Ñ Ð² Ñекундах. ПоÑле Ñтого +timing.hint_2 инфопанель будет прозрачной. +timing.infobar Инфопанель +timing.menu Меню +timing.numericzap При наборе цифрами Ñ Ð¿ÑƒÐ»ÑŒÑ‚Ð° +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head проверка UCode +ucodecheck.ucode UCode +ucodes.failure Ð’ÐИМÐÐИЕ, , mCodes нет в наличии!\nПожалуйÑта загрузите их через FTP(или Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ DBox-BootManager),\nзатем перегрузите Ваш Dbox! +videomenu.csync ÐºÐ¾Ñ€ÐµÐºÑ†Ð¸Ñ Ñинхронизации +videomenu.head ÐаÑтройки видео-Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ +videomenu.rgb_centering Центровка RGB +videomenu.screensetup ÐаÑтройки Ñкрана +videomenu.vcrswitch Ðвто-включение на SCART +videomenu.videoformat Формат +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect авто-формат +videomenu.videosignal Видео-выход +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zaptotimer.announce Таймер Ð¿ÐµÑ€ÐµÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ ÐºÐ°Ð½Ð°Ð»Ð° Ñработает через 1 минуту +extra.dvbsnoop DVB Stream Info +extra.dvbsnoop_pat Show PAT +extra.dvbsnoop_cat Show CAT +extra.dvbsnoop_tsdt Show TSDT +extra.dvbsnoop_nit Show NIT +extra.dvbsnoop_sdt Show SDT +extra.dvbsnoop_eit Show EIT +extra.dvbsnoop_rst Show RST +extra.dvbsnoop_tdt Show TDT +extra.dvbsnoop_sit Show SIT +extra.dvbsnoop_pid Show manual PID +extra.dvbsnoop_scan Scan PIDs +extra.dvbsnoop_band Show pid bandwidth +extra.logview View Log +extra.english English +extra.dboxinfo Box Info +extra.scan_mode Scan mode +extra.start_tostandby Startup to standby +extra.rotor_swap Swap rotor east/west +extra.use_log Log to /tmp/log +extra.spts_mode SPTS mode +extra.hw_sect Hardware Sections +extra.logo Logo number +extra.scan_full Full +extra.scan_fast Fast +extra.hdd_slow Slow +extra.hdd_middle Middle +extra.hdd_fast Fast +extra.hdd_ext3 Ext3fs +extra.hdd_reiser Reiserfs +extra.hdd_1min 1 min. +extra.hdd_5min 5 min. +extra.hdd_10min 10 min. +extra.hdd_20min 20 min. +extra.hdd_30min 30 min. +extra.hdd_60min 60 min. +extra.logo1 1 +extra.logo2 2 +extra.logo3 3 +extra.hdd_sleep Sleep time +extra.hdd_noise Noise +extra.hdd_activate Activate settings +extra.hdd_fs Filesystem +extra.hdd_format Format HDD +extra.hdd_check Check filesystem +extra.hdd_settings HDD Settings +extra.clear_log Clear Log +extra.zap_cycle Zap cycle +extra.sms_channel sms-mode channel +extra.manual_scan Manual scan +extra.tp_freq Frequency +extra.tp_rate Symbol rate +extra.tp_pol Polarization +extra.tp.pol_v V +extra.tp_pol_h H +extra.tp_fec FEC +extra.fec_1_2 1/2 +extra.fec_2_3 2/3 +extra.fec_3_4 3/4 +extra.fec_5_6 5/6 +extra.fec_7_8 7/8 +extra.timezone Timezone +extra.zapit_menu Параметры Zapit +extra.zapit_make_bouquet Make Remaining Channels list +extra.zapit_save_last_chan Save last channel +extra.zapit_motor_speed Motor moving speed (10 = 1deg/sec) +extra.zapit_fe_timeout Tune timeout +extra.add_to_bouquet Канал в пакет +extra.chadded Канал добавлен в выбранный пакет....\n +extra.chalreadyinbq Канал уже ÑущеÑтвует в выбранном пакете....\n +extra.menu_left_exit Left = выход из меню +extra.zapit_write_names Имена каналов в bouquets.xml +extra.update_dir Каталог Ð´Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ð¹ +extra.zapit_fast_zap fast zap +extra.cache Cache +extra.debug Debug +extra.zapit_sort_names Sort ch. by name +extra.zapit_delete Delete channels +extra.zapit_backup Backup channels to /tmp +extra.zapit_restore Restore channels from /tmp +pictureviewer.decode_server_ip decode server ip +pictureviewer.decode_server_port decode server port +scants.abort_body Should the search really be aborted? +scants.abort_header Abortion of channel scan +recordingmenu.record_in_spts_mode switch to spts mode before recording +servicemenu.getplugins Reload plugins +servicemenu.getplugins_hint Reloading plugins,\nplease be patient. +zapit.scantype scan for services +zapit.scantype.all all services +zapit.scantype.radio only radio +zapit.scantype.tv only tv +zapit.scantype.tvradio tv & radio +colorthememenu.red_theme Simply Red +lcdmenu.dim_brightness Brightness after dim timeout +lcdmenu.dim_time Dim timeout +timerlist.overlapping_timer Timer conflict. Create the timer anyway? +extra.audio_run_player Audio key start player +mpkey.rewind Rewind +mpkey.forward Forward +mpkey.pause Pause +mpkey.stop Stop +mpkey.play Play +mpkey.audio Audio track +mpkey.time Show time +mpkey.bookmark save bookmark +mpkey.plugin Run plugin +extra.key_click Key click +extra.loadcolors Load colors from +extra.savecolors Save colors as +extra.loadkeys Load keys from +extra.savekeys Save keys as +extra.loadconfig Load settings from +extra.saveconfig Save settings as +videomenu.videomode Video system +videomenu.videomode_ntsc NTSC +videomenu.videomode_pal PAL +videomenu.videomode_palm PAL-M +extra.key_timeshift Timeshift +extra.key_plugin One touch plugin +extra.timeshift_pause Timeshift pause +rfmod.rfmod RF modulator +rfmod.carrier Subcarrier Frequency +rfmod.carrier4500 4.5 +rfmod.carrier5500 5.5 +rfmod.carrier6000 6.0 +rfmod.carrier6500 6.5 +rfmod.enable Enable sound +rfmod.channel Channel +rfmod.finetune Fine tune +rfmod.standby Enable modulator +rfmod.test Test pattern +extra.zapit_scanpids Scan/Use pids +extra.zapit_rezap_time Re-Zap on emu switch time +extra.zapit_hvoltage High (13.5/18.5) voltage +extra.key_unlock Unlock key +extra.mg_netoptions Network options +extra.mg_ecm_timeout Network ecm timeout +extra.mg_reconnect Shares reconnect +extra.mg_priority Share priority +extra.mg_osd_options Osd options +extra.mg_reread Reread files on zap +servicemenu.imageinfo Image info +imageinfo.creator Creator: +imageinfo.date Date: +imageinfo.dokumentation Docs: +imageinfo.forum Forum: +imageinfo.head Image info: +imageinfo.homepage Home page: +imageinfo.image Image: +imageinfo.license License: +imageinfo.version Version: +extra.cache_txt Cache teletext +extra.use_gotoxx Use gotoXX +extra.latitude Latitude +extra.longitude Longitude +extra.ladirection LaDirection +extra.lodirection LoDirection +extra.south South +extra.north North +extra.east East +extra.west West +epgextended.actors Actors +epgextended.director Director +epgextended.guests Guests +epgextended.original_title Original Title +epgextended.presenter Presenter +epgextended.year_of_production Year of Production +recordingmenu.save_in_channeldir Save in channel dir +servicemenu.restart Soft restart +servicemenu.restart_failed Restart failed +servicemenu.restart_hint Restarting, please wait +servicemenu.restart_refused_recording Cant restart, recording in progress +extra.tp_mod Modulation +extra.tp_mod_16 QAM/16 +extra.tp_mod_32 QAM/32 +extra.tp_mod_64 QAM/64 +extra.tp_mod_128 QAM/128 +extra.tp_mod_256 QAM/256 +moviebrowser.book_head Bookmarks +moviebrowser.book_lastmoviestop Last play stop: +moviebrowser.book_movieend Movie end: +moviebrowser.book_moviestart Movie start: +moviebrowser.book_name Name: +moviebrowser.book_new New Bookmark +moviebrowser.book_position Position: +moviebrowser.book_type Jump (<0 back , >0 for): +moviebrowser.book_type_backward Repeat +moviebrowser.book_type_forward jump over +moviebrowser.edit_book Bookmark change +moviebrowser.edit_book_name_info1 Enter new Bookmark name +moviebrowser.edit_book_name_info2 +moviebrowser.edit_book_pos_info1 Enter new Position (s) +moviebrowser.edit_book_pos_info2 +moviebrowser.edit_book_type_info1 Enter new jump length (s) +moviebrowser.edit_book_type_info2 <0 back , >0 for, 0: none +moviebrowser.edit_serie Enter name of serie +moviebrowser.error_no_movies No movies found +moviebrowser.foot_filter Filter: +moviebrowser.foot_play Start movie +moviebrowser.foot_sort Sort: +moviebrowser.head TS MovieBrowser +moviebrowser.head_filter Filter movies by category: +moviebrowser.head_playlist Last played: +moviebrowser.head_recordlist Last recorded: +moviebrowser.hint_jumpbackward Jump back in 5 s\n '0' to cancel +moviebrowser.hint_jumpforward Jump forward in 5 s\n '0' to cancel +moviebrowser.hint_movieend Filmende in 5 s\n '0' zum weitersehen +moviebrowser.hint_newbook_backward New jump back\n 'blue' for endposition +moviebrowser.hint_newbook_forward New jump forward\n 'blue' for endposition +moviebrowser.info_audio Audio +moviebrowser.info_channel Channel +moviebrowser.info_filename Name +moviebrowser.info_genre_major Genre +moviebrowser.info_genre_minor Genre +moviebrowser.info_head Film Informationen +moviebrowser.info_info1 Info 1 +moviebrowser.info_info2 Info 2 +moviebrowser.info_length Length (Min) +moviebrowser.info_parental_lockage Parental Lock age +moviebrowser.info_parental_lockage_0year always +moviebrowser.info_parental_lockage_12year 12 years +moviebrowser.info_parental_lockage_16year 16 years +moviebrowser.info_parental_lockage_18year 18 years +moviebrowser.info_parental_lockage_6year 6 years +moviebrowser.info_parental_lockage_always never +moviebrowser.info_path Path +moviebrowser.info_prevplaydate Last play date +moviebrowser.info_prodcountry Country +moviebrowser.info_prodyear Year +moviebrowser.info_quality Quality +moviebrowser.info_recorddate Record date +moviebrowser.info_serie Serie +moviebrowser.info_size File size (MB) +moviebrowser.info_title Titel +moviebrowser.info_videoformat Picture +moviebrowser.menu_directories_head Paths +moviebrowser.menu_help_head Help +moviebrowser.menu_main_bookmarks Bookmarks +moviebrowser.menu_main_head Settings +moviebrowser.menu_main_movieinfo Movie info +moviebrowser.menu_main_saveandback save and back +moviebrowser.menu_nfs_head NFS settings +moviebrowser.menu_parental_lock_activated activated +moviebrowser.menu_parental_lock_activated_no no +moviebrowser.menu_parental_lock_activated_yes yes +moviebrowser.menu_parental_lock_activated_no_temp no (temporary) +moviebrowser.menu_parental_lock_head Parental Lock +moviebrowser.menu_parental_lock_rate_head Lock movies from +moviebrowser.scan_for_movies Scan for Movies ... +moviebrowser.serie_existingname Existing series +moviebrowser.serie_head Serie +moviebrowser.serie_name Change name +moviebrowser.short_audio Audio +moviebrowser.short_book Book +moviebrowser.short_channel Channel +moviebrowser.short_country Country +moviebrowser.short_filename Name +moviebrowser.short_format Format +moviebrowser.short_genre_major Genre +moviebrowser.short_genre_minor Genre +moviebrowser.short_info1 Info 1 +moviebrowser.short_info2 Info 2 +moviebrowser.short_length Min +moviebrowser.short_parental_lockage Age +moviebrowser.short_path Path +moviebrowser.short_prevplaydate Last +moviebrowser.short_prodyear Year +moviebrowser.short_quality * (quality) +moviebrowser.short_recorddate Date +moviebrowser.short_serie Serie +moviebrowser.short_size MB +moviebrowser.short_title Title +moviebrowser.start_head Start movie from: +moviebrowser.start_record_start Movie start +options.on.without_messages Without msg +extra.zapit_scan_sdt Scan SDT for updates +extra.zapit_sdt_changed Channels changed, reload settings. +miscsettings.virtual_zap_mode Virtual zap +miscsettings.epg_head Epg settings +miscsettings.epg_cache_days EPG-Cache (days) +miscsettings.epg_old_hours Events old after (hours) +miscsettings.epg_dir Dir for epg cache +miscsettings.epg_save Save/Restore epg on reboot +shutdown.recoding_query Box in record mode, you really want to shutdown ? +recordingmenu.apids default audio streams +recordingmenu.apids_ac3 record AC3 streams +recordingmenu.apids_alt record alternative streams +recordingmenu.apids_std record standard stream +recordingmenu.stream_pmt_pid record PMT +recordingmenu.zap_on_announce zap on recording announce +timerlist.apids_dflt record default audio streams +videomenu.osd OSD +videomenu.tv-scart TV Scart +videomenu.vcr-scart VCR Scart +videomenu.vcrsignal VCR Output Signal Type +videomenu.vcrsignal_composite CVBS +videomenu.vcrsignal_svideo S-Video +moviebrowser.option_browser Browser Options +moviebrowser.book_clear_all Clear all +moviebrowser.menu_save Save changes +moviebrowser.menu_save_all Start update of movie info files +moviebrowser.info_head_update Save changes in all movie info files +moviebrowser.update_if_dest_empty_only Copy if destination is empty only +moviebrowser.serie_auto_create Serie auto create +moviebrowser.load_default Load default settings +moviebrowser.browser_row_head Row settings +moviebrowser.browser_row_nr Number of rows +moviebrowser.browser_row_item Row item +moviebrowser.browser_row_width Row width +moviebrowser.reload_at_start Reload movie info at start +moviebrowser.remount_at_start Remount at start +moviebrowser.dir_head Additional paths +moviebrowser.dir Path +moviebrowser.use_dir Use directory +moviebrowser.use_rec_dir Use record directory +moviebrowser.use_movie_dir Use movie directory +moviebrowser.hide_series Hide series +moviebrowser.last_record_max_items Number of lines last record +moviebrowser.last_play_max_items Number of lines last play +moviebrowser.browser_frame_high Browser hight [Pixel] +extra.auto_timeshift Auto-record, sec (0 = disable) +extra.auto_delete Auto-delete +extra.auto_to_record Move timeshift to records +extra.record_time Fast/timeshift record time(hours) diff --git a/data/locale/suomi.locale b/data/locale/suomi.locale new file mode 100644 index 000000000..39a797918 --- /dev/null +++ b/data/locale/suomi.locale @@ -0,0 +1,1049 @@ +AUDIOSelectMenue.head Kielivalinta +EPGMenu.epgplus EPG ohjelmaopas +EPGMenu.eventinfo Ohjelman kuvaus +EPGMenu.eventlist Kanavan ohjelmat +EPGMenu.head Ohjelmatiedot +EPGMenu.streaminfo Teknistä tietoa +EPGPlus.actions Toiminnot +EPGPlus.bybouquet_mode Kanavaniputtain +EPGPlus.bypage_mode Sivu kerrallaan +EPGPlus.change_font_size Muuta kirjasimen kokoa +EPGPlus.change_font_style Muuta kirjasinta +EPGPlus.change_size Muuta kokoa +EPGPlus.channelentry_font Kanavat +EPGPlus.channelentry_separationlineheight riviväli +EPGPlus.channelentry_width Kanavanimien leveys +EPGPlus.channelevententry_font Ohjelma +EPGPlus.edit_fonts Muokkaa kirjasinta +EPGPlus.edit_sizes Muokkaa kokoa +EPGPlus.font_style_bold lihavointi +EPGPlus.font_style_italic kursivointi +EPGPlus.font_style_regular normaali +EPGPlus.footer_fontbouquetchannelname Valitse kanavanipun/kanavan nimi +EPGPlus.footer_fontbuttons Näppäimet +EPGPlus.footer_fonteventdescription Ohjelman kuvaus +EPGPlus.footer_fonteventshortdescription Ohjelman kuvaus lyhyesti +EPGPlus.head EPG ohjelmaopas +EPGPlus.header_font Header +EPGPlus.horgap1_height height hor. gap 1 +EPGPlus.horgap2_height height hor. gap 2 +EPGPlus.next_bouquet Seuraava nippu +EPGPlus.options Asetukset +EPGPlus.page_down Sivu ylös +EPGPlus.page_up Sivu alas +EPGPlus.prev_bouquet Edellinen nippu +EPGPlus.record Ajasta tallennus +EPGPlus.refresh_epg Päivitä EPG-tiedot +EPGPlus.remind Ajasta kanavanvaihto +EPGPlus.reset_settings Palauta asetukset +EPGPlus.save_settings Tallenna asetukset +EPGPlus.scroll_mode Vieritys +EPGPlus.select_font_name Kirjasimen valinta +EPGPlus.settings Asetukset +EPGPlus.slider_width slider width +EPGPlus.stretch_mode Venytetty +EPGPlus.swap_mode Vaihtotila +EPGPlus.timeline_fontdate Pvm kirjasin +EPGPlus.timeline_fonttime Aika Kirjasin +EPGPlus.vergap1_width width ver. gap 1 +EPGPlus.vergap2_width width ver. gap 2 +EPGPlus.view_mode Näyttötila +GENRE.ARTS.0 taide / kulttuuri +GENRE.ARTS.1 esittävä taide +GENRE.ARTS.10 kulttuurimakasiini +GENRE.ARTS.11 muoti +GENRE.ARTS.2 korkeakulttuuri +GENRE.ARTS.3 uskonto +GENRE.ARTS.4 populaarikulttuuri +GENRE.ARTS.5 kirjallisuus +GENRE.ARTS.6 elokuva +GENRE.ARTS.7 kokeellinen elokuva +GENRE.ARTS.8 uutiset / lehdistö +GENRE.ARTS.9 uusmedia +GENRE.CHILDRENs_PROGRAMMES.0 lasten ja nuorten ohjelmaa +GENRE.CHILDRENs_PROGRAMMES.1 esikouluikäisten ohjelmaa +GENRE.CHILDRENs_PROGRAMMES.2 viihdettä 6 - 14 vuotiaille +GENRE.CHILDRENs_PROGRAMMES.3 viihdettä 10 - 16 vuotiaille +GENRE.CHILDRENs_PROGRAMMES.4 opetusohjelmaa +GENRE.CHILDRENs_PROGRAMMES.5 piirros- / nukkeanimaatio +GENRE.DOCUS_MAGAZINES.0 dokumentti ja makasiini +GENRE.DOCUS_MAGAZINES.1 luonto +GENRE.DOCUS_MAGAZINES.2 teknologia / luonnontiede +GENRE.DOCUS_MAGAZINES.3 lääketiede / fysiologia / psykologia +GENRE.DOCUS_MAGAZINES.4 vieraat kulttuurit/tutkimusmatkailu +GENRE.DOCUS_MAGAZINES.5 yhteiskunta ja hengellinen +GENRE.DOCUS_MAGAZINES.6 koulutus +GENRE.DOCUS_MAGAZINES.7 kielet +GENRE.MOVIE.0 draama +GENRE.MOVIE.1 dekkari/trilleri +GENRE.MOVIE.2 seikkailu/lännenelokuva/sota +GENRE.MOVIE.3 tieteis/fantasia/kauhu +GENRE.MOVIE.4 komedia +GENRE.MOVIE.5 sarjat/melodraama +GENRE.MOVIE.6 romantiikka +GENRE.MOVIE.7 historiallinen elokuva/draama +GENRE.MOVIE.8 aikuisviihde/draama +GENRE.MUSIC_DANCE.0 musiikki / tanssi +GENRE.MUSIC_DANCE.1 rock / pop +GENRE.MUSIC_DANCE.2 klassinen musiikki +GENRE.MUSIC_DANCE.3 kansanmusiikki +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musikaali / ooppera +GENRE.MUSIC_DANCE.6 baletti +GENRE.NEWS.0 uutiset +GENRE.NEWS.1 uutiset / sääennuste +GENRE.NEWS.2 ajankohtaisohjelma +GENRE.NEWS.3 dokumentti +GENRE.NEWS.4 keskustelu / haastattelu +GENRE.SHOW.0 viihde / visailu +GENRE.SHOW.1 visailu +GENRE.SHOW.2 viihdeohjelma +GENRE.SHOW.3 keskusteluohjelma +GENRE.SOCIAL_POLITICAL.0 yhteiskunta, politiikka ja talous +GENRE.SOCIAL_POLITICAL.1 raportit ja makasiinit +GENRE.SOCIAL_POLITICAL.2 talousneuvontaa +GENRE.SOCIAL_POLITICAL.3 merkkihenkilöitä +GENRE.SPORTS.0 urheilu +GENRE.SPORTS.1 erikoistapahtumat +GENRE.SPORTS.10 hevosurheilu +GENRE.SPORTS.11 kamppailulajit +GENRE.SPORTS.2 urheilumakasiini +GENRE.SPORTS.3 jalkapallo +GENRE.SPORTS.4 tennis/squash +GENRE.SPORTS.5 joukkuelajit +GENRE.SPORTS.6 yleisurheilu +GENRE.SPORTS.7 moottoriurheilu +GENRE.SPORTS.8 vesiurheilu +GENRE.SPORTS.9 talviurheilu +GENRE.TRAVEL_HOBBIES.0 harrasteet, viihde ja virkistys +GENRE.TRAVEL_HOBBIES.1 matkailu ja turismi +GENRE.TRAVEL_HOBBIES.2 käsityöt +GENRE.TRAVEL_HOBBIES.3 autoilu +GENRE.TRAVEL_HOBBIES.4 kuntoilu ja terveys +GENRE.TRAVEL_HOBBIES.5 ruoka +GENRE.TRAVEL_HOBBIES.6 ostos-tv +GENRE.TRAVEL_HOBBIES.7 puutarha +GENRE.UNKNOWN tuntematon +apids.hint_1 Syötä streamattavat audio PIDit +apids.hint_2 heksalukuina välilyönneillä erotettuna +apidselector.head Valitse kieli +audiomenu.PCMOffset PCM äänen vaimennus +audiomenu.analogout Analoginen lähtö +audiomenu.audio_left_right_selectable Stereo/mono-valinta +audiomenu.audiochannel_up_down_enable Valitse ääniraita nuolilla +audiomenu.avs avs +audiomenu.avs_control Äänenvoimakkuuden säätö +audiomenu.dolbydigital Suosi AC3/DD-ääniraitaa +audiomenu.head Ääniasetukset +audiomenu.lirc lirc +audiomenu.monoleft mono vasen +audiomenu.monoright mono oikea +audiomenu.ost ost +audiomenu.stereo stereo +audioplayer.add Lisää +audioplayer.artist_title Artisti, Kappale +audioplayer.building_search_index Luon hakutietokantaa +audioplayer.button_select_title_by_id etsi ID:llä +audioplayer.button_select_title_by_name etsi nimellä +audioplayer.defdir Aloitus hakemisto/suunta +audioplayer.delete poista kaikki +audioplayer.deleteall poista kaikki +audioplayer.display_order järjestys +audioplayer.enable_sc_metadata Näytä shoutcastin metadata +audioplayer.fastforward kelaus eteenpäin +audioplayer.follow valitse automaattisesti nykyinen +audioplayer.head Soittolista +audioplayer.highprio Korkea purun prioriteetti +audioplayer.id3scan ID3 tietojen haku +audioplayer.jump_backwards hyppää taaksepäin +audioplayer.jump_dialog_hint1 Syötä hyppykohta +audioplayer.jump_dialog_hint2 (suhteellinen, sekunneissa) +audioplayer.jump_dialog_title Syötä hyppykohta +audioplayer.jump_forwards Hyppy eteenpäin +audioplayer.keylevel näppäin taso +audioplayer.name Musiikkisoitin +audioplayer.pause Tauko +audioplayer.play Pääte .m3u lisätään automaattisesti +audioplayer.playing Current Track +audioplayer.playlist_fileerror_msg Tiedoston luonti epäonnistui: +audioplayer.playlist_fileerror_title Virhe +audioplayer.playlist_fileoverwrite_msg Haluatko ylikirjoittaa tiedoston: +audioplayer.playlist_fileoverwrite_title Ylikirjoita? +audioplayer.playlist_name Pääte .m3u lisätään automaattisesti +audioplayer.playlist_name_hint1 Syötä soittolistan nimi +audioplayer.playlist_name_hint2 Pääte .m3u lisätään automaattisesti +audioplayer.reading_files Luetaan metadataa +audioplayer.repeat_on Toisto päälle +audioplayer.rewind kelaus taaksep. +audioplayer.save_playlist tallenna soittolista +audioplayer.screensaver_timeout ruudunsäästäjän viive (min, 0=pois) +audioplayer.select_title_by_name Etsi nimellä (SMS) +audioplayer.show_playlist Näytä soittolista +audioplayer.shuffle satunnaissoitto +audioplayer.stop Pysäytä +audioplayer.title_artist Kappale, Artisti +audioplayerpicsettings.general mp3-soitin / kuvankatselu +bookmarkmanager.delete poista +bookmarkmanager.name kirjanmerkit +bookmarkmanager.rename uudelleen nimeä +bookmarkmanager.select valitse +bouqueteditor.add Lisää +bouqueteditor.bouquetname Kanavanippujen nimet +bouqueteditor.delete Poista +bouqueteditor.discardingchanges Kumotaan muutokset. Odota hetki. +bouqueteditor.hide Piilota +bouqueteditor.lock Lukitse +bouqueteditor.move Siirrä +bouqueteditor.name Kanavaniput +bouqueteditor.newbouquetname Uusi nimi kanavanipulle +bouqueteditor.rename Nimeä +bouqueteditor.return Valmis +bouqueteditor.savechanges? Tallennetaanko muutokset? +bouqueteditor.savingchanges Tallennetaan muutoksia. Odota hetki. +bouqueteditor.switch TV/Radio +bouqueteditor.switchmode TV/Radio +bouquetlist.head Kanavaniput +cablesetup.provider Verkko +channellist.head Kaikki palvelut +channellist.nonefound Kanavia ei löytynyt!\nTee kanavahaku\n(dbox-näppäin -> asetukset) +channellist.since alkaen %02d:%02d +colorchooser.alpha alpha +colorchooser.blue sininen +colorchooser.green vihreä +colorchooser.red punainen +colormenu.background Tausta +colormenu.background_head Tausta +colormenu.fade Fade valikot +colormenu.font Kirjasinkoot +colormenu.gtx_alpha Läpinäkyvyys +colormenu.head Käyttöliittymän ulkoasu +colormenu.menucolors Valikon värit +colormenu.statusbar Infopalkin värit +colormenu.textcolor Tekstin väri +colormenu.textcolor_head Tekstin väri +colormenu.themeselect Teeman valinta +colormenu.timing OSD-ajoitukset +colormenusetup.head Valikon värit +colormenusetup.menucontent Valitun ikkunan sisältö +colormenusetup.menucontent_inactive Passiivisen ikkunan sisältö +colormenusetup.menucontent_selected Valitun ikkunan sisältö +colormenusetup.menuhead Valikon otsikko +colorstatusbar.head Infopalkki +colorstatusbar.text Infopalkki +colorthememenu.classic_theme Perinteinen +colorthememenu.dblue_theme DarkBlue +colorthememenu.dvb2k_theme DVB2000 +colorthememenu.head Teeman valinta +colorthememenu.neutrino_theme Neutrino +date.Apr Huhti +date.Aug Elo +date.Dec Joulu +date.Feb Helmi +date.Fri Pe +date.Jan Tammi +date.Jul Heinä +date.Jun Kesä +date.Mar Maalis +date.May Touko +date.Mon Ma +date.Nov Marras +date.Oct Loka +date.Sat La +date.Sep Syys +date.Sun Su +date.Thu To +date.Tue Ti +date.Wed Ke +epgextended.actors Näyttelijät +epgextended.director Ohjaaja +epgextended.guests Vieraat +epgextended.original_title Alkuperäinen nimi +epgextended.presenter Esittäjä +epgextended.year_of_production Tuotantovuosi +epglist.head Ohjelmalista - %s +epglist.noevents EPG ei ole saatavilla... +epgviewer.More_Screenings Muita näytöksiä tällä kanavalla +epgviewer.nodetailed Lisäkuvausta ei ole saatavilla +epgviewer.notfound EPG:tä ei löytynyt +eventlistbar.channelswitch Ajasta kanavan vaihto +eventlistbar.eventsort Lajittele +eventlistbar.recordevent Tallenna +experimentalsettings Kokeiluasetuksia +experimentalsettings.head Kokeiluasetuksia +favorites.addchannel Nykyinen kanava lisätään "Suosikit" kanavanippuun.\nOdota hetki... +favorites.bouquetname Suosikit +favorites.bqcreated Kanavanippu "Suosikit" luotu...\n +favorites.chadded Kanava lisätty suosikkeihisi...\n +favorites.chalreadyinbq Kanava on jo suosikeissasi...\n +favorites.finalhint \nKäytä kanavanippueditoria suosikkiesi muokkaamiseen.\n +favorites.menueadd Lisää kanava suosikkeihin +favorites.nobouquets Suosikit ovat käytettävissä vain aktiivisista kanavanipuista. +filebrowser.delete Poista +filebrowser.denydirectoryleave Rajaa aloitushakemistoon +filebrowser.dodelete1 Poista +filebrowser.dodelete2 ? +filebrowser.filter.active Suodatus päälle +filebrowser.filter.inactive Suodatus pois +filebrowser.head Tiedostoselain +filebrowser.mark Merkitse +filebrowser.nextpage Seur. sivu +filebrowser.prevpage Edell. sivu +filebrowser.scan Selaan kansiota +filebrowser.select Valitse +filebrowser.showrights Näytä tiedosto-oikeudet +filebrowser.sort.date (pvm) +filebrowser.sort.name (nimi) +filebrowser.sort.namedirsfirst (hak/tied) +filebrowser.sort.size (koko) +filebrowser.sort.type (tyyppi) +filesystem.is.utf8 Tiedostonimien merkistö +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +flashupdate.actionreadflash Luetaan +flashupdate.cantopenfile Tiedostoa ei voida avata +flashupdate.cantopenmtd MTD-laitetta ei voida käyttää +flashupdate.checkupdate Etsi uutta versiota +flashupdate.currentreleasecycle Versio +flashupdate.currentversion_sep Nykyinen versio +flashupdate.currentversiondate Päiväys +flashupdate.currentversionsnapshot Tyyppi +flashupdate.currentversiontime Aika +flashupdate.erasefailed Flashin tyhjennys epäonnistui +flashupdate.erasing Flash-muistin tyhjennys +flashupdate.experimentalimage Ohjelmisto jonka valitsit on testaamaton. Tämä tarkoittaa\n, että laitteesi ei ehkä käynnisty päivityksen jälkeen.\n\nOletko varma, että haluat päivittää tähän versioon? +flashupdate.expertfunctions Erikoistoiminnot +flashupdate.fileis0bytes Tiedosto on tyhjä (0 tavua) +flashupdate.fileselector Valitse tiedosto +flashupdate.flashreadyreboot Ohjelmistopäivitys onnistui.\nDBox täytyy käynnistää uudelleen. +flashupdate.getinfofile Versiotiedot +flashupdate.getinfofileerror Versiotietoja ei voitu lukea +flashupdate.getupdatefile Päivityksen haku +flashupdate.getupdatefileerror Päivityksen hakeminen epäonnistui +flashupdate.globalprogress Kokonaiskesto: +flashupdate.head Ohjelmistopäivitys +flashupdate.md5check Ohjelmiston tarkastus +flashupdate.md5sumerror Virheellinen ohjelmisto +flashupdate.msgbox Uusi ohjelmistoversio löydetty:\nPvm: %s, %s\nOhjelmistopohja: %s\nTyyppi: %s\n\nHaluatko asentaa tämän ohjelmistoversion? +flashupdate.msgbox_manual Uusi ohjelmistoversio löydetty:\nPvm: %s, %s\nOhjelmistopohja: %s\nTyyppi: %s\n\nHaluatko asentaa tämän ohjelmistoversion? +flashupdate.mtdselector Valitse osio +flashupdate.programmingflash Flash-muistin kirjoitus +flashupdate.proxypassword Salasana +flashupdate.proxypassword_hint1 Anna välityspalvelimen salasana. +flashupdate.proxypassword_hint2 Jätä tyhjäksi, jos salasanaa ei tarvita. +flashupdate.proxyserver Osoite ja portti +flashupdate.proxyserver_hint1 Anna palvelimen nimi tai IP-osoite, muodossa palvelin:portti +flashupdate.proxyserver_hint2 Jätä tyhjäksi mikäli välityspalvelinta ei käytetä. +flashupdate.proxyserver_sep Välityspalvelin (proxy) +flashupdate.proxyusername Käyttäjätunnus +flashupdate.proxyusername_hint1 Anna välityspalvelimen käyttäjätunnus. +flashupdate.proxyusername_hint2 Jätä tyhjäksi mikäli käyttätunnusta ei tarvita. +flashupdate.readflash Lue koko flash-muisti +flashupdate.readflashmtd Lue yksi osio +flashupdate.ready Valmis +flashupdate.reallyflashmtd Haluatko varmasti päivittää?\n\nMikäli päivitys epäonnistuu tai ohjelmisto\non viallinen, laite ei enää käynnisty uudelleen.\n\nOhjelmisto: %s\nKohde: %s +flashupdate.savesuccess Ohjelmisto tallennettu polkuun %s. +flashupdate.selectimage Saatavilla olevat ohjelmistot +flashupdate.squashfs.noversion SquashFS-versiotarkastus toimii vain\nwebin kautta päivitettäessä.\n\nHaluatko jatkaa tarkastamatta versiota? +flashupdate.titlereadflash Flash-muistin luku +flashupdate.titlewriteflash Flash-muistin kirjoitus +flashupdate.updatemode Päivitystapa +flashupdate.updatemode_internet Internet +flashupdate.updatemode_manual Manuaalinen +flashupdate.url_file Päivitysasetukset +flashupdate.versioncheck Version tarkastus +flashupdate.writeflash Kirjoita koko flash-muisti +flashupdate.writeflashmtd Kirjoita yksi osio +flashupdate.wrongbase Ohjelmistosi perusversio eroaa uudesta. Päivitys ei\nole mahdollista ilman koko ohjelmiston vaihtoa. +fontmenu.channellist Kanavalista +fontmenu.epg EPG +fontmenu.eventlist Ohjelmalista +fontmenu.gamelist Pelit +fontmenu.head Kirjasinkoot +fontmenu.infobar Infopalkki +fontsize.channel_num_zap Kanavan suoravalinta +fontsize.channellist Kanavalista +fontsize.channellist_descr Kuvaus +fontsize.channellist_number Numero +fontsize.epg_date EPG päiväys +fontsize.epg_info1 EPG info 1 +fontsize.epg_info2 EPG info 2 +fontsize.epg_title EPG otsikko +fontsize.eventlist_datetime Päiväys / aika +fontsize.eventlist_itemlarge Suuri +fontsize.eventlist_itemsmall Pieni +fontsize.eventlist_title Otsikko +fontsize.filebrowser_item Tiedostoselain +fontsize.gamelist_itemlarge Suuri +fontsize.gamelist_itemsmall Pieni +fontsize.hint Alustan kirjasinta,\nodota hetki... +fontsize.imageinfo_info Ohjelmistotiedot +fontsize.imageinfo_small Ohjelmiston lisenssitiedot +fontsize.infobar_channame Kanavan nimi +fontsize.infobar_info Info +fontsize.infobar_number Numero +fontsize.infobar_small Pieni +fontsize.menu Valikkoteksti +fontsize.menu_info Valikkotiedot +fontsize.menu_title Valikko-otsikko +gtxalpha.alpha1 Otsikko +gtxalpha.alpha2 Valikko +imageinfo.creator Koonnut: +imageinfo.date Päiväys: +imageinfo.dokumentation Ohjeet: +imageinfo.forum Keskustelu: +imageinfo.head Ohjelmiston tiedot +imageinfo.homepage Kotisivu: +imageinfo.image Nimi: +imageinfo.license Lisenssi: +imageinfo.version Versio: +infoviewer.epgnotload EPG ei vielä valmis... +infoviewer.epgwait odotetaan EPG:tä... +infoviewer.eventlist Ohjelmaopas +infoviewer.languages Ääni +infoviewer.motor_moving Moottori kääntyy.. +infoviewer.nocurrent Ohjelmasta ei ole tietoja saatavilla +infoviewer.noepg EPG ei ole käytettävissä +infoviewer.notavailable Kanava ei ole käytettävissä +infoviewer.selecttime Aikavalinta +infoviewer.streaminfo Lisätoim. +infoviewer.subchan_disp_pos Alikanavan näyttö +infoviewer.subservice Subservices +infoviewer.waittime Waiting for time... +ipsetup.hint_1 Käytä 0..9, tai Nuoli ylös/alas, +ipsetup.hint_2 OK tallentaa, Home keskeyttää +keybindingmenu.RC Kaukosäätimen näppäintoisto +keybindingmenu.addrecord - Ajastintallennus +keybindingmenu.addrecord_head Ajastintallennuksen näppäin +keybindingmenu.addremind - Kanavanvaihtoajastus +keybindingmenu.addremind_head Kanavanvaihtoajastimen näppäin +keybindingmenu.allchannels_on_ok Kaikki palvelut +keybindingmenu.bouquetchannels_on_ok Kanavanipuittain +keybindingmenu.bouquetdown - Edellinen kanavanippu +keybindingmenu.bouquetdown_head Edellisen kanavanipun näppäin +keybindingmenu.bouquethandling Kanavaselaus +keybindingmenu.bouquetlist_on_ok Kanavanippu-lista +keybindingmenu.bouquetup - Seuraava kanavanippu +keybindingmenu.bouquetup_head Seuraavan kanavanipun näppäin +keybindingmenu.cancel - Paluunäppäin +keybindingmenu.cancel_head Paluunäppäin +keybindingmenu.channeldown - Edellinen kanava +keybindingmenu.channeldown_head Edellisen kanavan näppäin +keybindingmenu.channellist Kanavalista +keybindingmenu.channelup - Seuraava kanava +keybindingmenu.channelup_head Seuraavan kanavan näppäin +keybindingmenu.head Näppäinasetukset +keybindingmenu.lastchannel - Paluu aiemmalle kanavalle +keybindingmenu.lastchannel_head Paluu Aiemmalle kanavalle +keybindingmenu.modechange Tilanvaihto +keybindingmenu.pagedown - Seuraava sivu +keybindingmenu.pagedown_head Seuraavan sivun näppäin +keybindingmenu.pageup - Edellinen sivu +keybindingmenu.pageup_head Edellisen sivun näppäin +keybindingmenu.quickzap Pikavaihto +keybindingmenu.repeatblock Toistoviive +keybindingmenu.repeatblockgeneric Yleisviive +keybindingmenu.sort - Lajittelujärjestys +keybindingmenu.sort_head Lajittelujärjestyksen näppän +keybindingmenu.subchanneldown - Edellinen alikanava +keybindingmenu.subchanneldown_head Edellisen alikanavan näppäin +keybindingmenu.subchannelup - Seuraava alikanava +keybindingmenu.subchannelup_head Seuraavan alikanavan näppäin +keybindingmenu.tvradiomode - TV/Radio +keybindingmenu.tvradiomode_head TV/Radio valintanäppäin +keybindingmenu.zaphistory - Kanavahistoria +keybindingmenu.zaphistory_head Kanavahistorian näppäin +keychooser.head Valitse uusi näppäin +keychooser.text1 Paina näppäintä +keychooser.text2 Odota hetki keskeyttääksesi +keychoosermenu.currentkey Nykyinen näppäin +keychoosermenu.setnew Aseta uusi näppäin +keychoosermenu.setnone Ei näppäintä +languagesetup.head Kielivalikko +languagesetup.select Kieli +lcdcontroler.brightness Kirkkaus +lcdcontroler.brightnessstandby - valmiustilassa +lcdcontroler.contrast Kontrasti +lcdcontroler.head LCD asetukset +lcdmenu.autodimm Automaattinen himmennys +lcdmenu.dim_brightness Himmennetty kirkkaus +lcdmenu.dim_time Viive ennen himmennystä +lcdmenu.head LCD-näytön asetukset +lcdmenu.inverse Käänteinen +lcdmenu.lcdcontroler Kontrasti / Kirkkaus +lcdmenu.power Näyttö +lcdmenu.statusline Näytä +lcdmenu.statusline.both äänenvoim. / aikajana +lcdmenu.statusline.playtime aikajana +lcdmenu.statusline.volume äänenvoimakkuus +mainmenu.audioplayer Musiikkisoitin +mainmenu.games Pelit +mainmenu.head Päävalikko +mainmenu.movieplayer Mediasoitin +mainmenu.pausesectionsd Lue EPG +mainmenu.pictureviewer Kuvankatselu +mainmenu.radiomode Radio +mainmenu.reboot Käynnistä uudelleen +mainmenu.recording Tallennus +mainmenu.recording_start Käynnistä +mainmenu.recording_stop Pysäytä +mainmenu.scartmode Scart +mainmenu.scripts Lisäkomennot +mainmenu.service Huoltovalikko +mainmenu.settings Asetukset +mainmenu.shutdown Sammuta +mainmenu.sleeptimer Uniajastin +mainmenu.tvmode TV +mainsettings.audio Ääni +mainsettings.colors Käyttöliittymän ulkoasu +mainsettings.head Asetukset +mainsettings.keybinding Näppäinasetukset +mainsettings.language Kieli +mainsettings.lcd LCD-näyttö +mainsettings.misc Lisäasetukset +mainsettings.network Verkko +mainsettings.recording Tallennus +mainsettings.savesettingsnow Tallenna asetukset +mainsettings.savesettingsnow_hint Asetuksien tallennus,\nodota hetki... +mainsettings.streaming Mediasoitin +mainsettings.video Kuva +menu.back Palaa +messagebox.back Palaa +messagebox.cancel Peruuta +messagebox.discard Peruuta muutokset? +messagebox.error Virhe +messagebox.info Info +messagebox.no Ei +messagebox.yes Kyllä +miscsettings.bootinfo Näytä tiedot käynnistyksessä +miscsettings.bootmenu Näytä käynnistysvalikko +miscsettings.cabledriver Lataa Nokian kaapeliajuri +miscsettings.driver_boot Ajurit ja käynnistys +miscsettings.fb_destination Konsoli +miscsettings.general Yleiset +miscsettings.head Sekalaiset asetukset +miscsettings.hwsections Käytä hwsections:ia +miscsettings.infobar_sat_display Näytä satelliitin nimi +miscsettings.noaviawatchdog Käytä AVIA valvontaa +miscsettings.noenxwatchdog Käytä eNX valvontaa +miscsettings.pmtupdate Käytä PMT päivitystä +miscsettings.shutdown_count Automaattinen sammutus +miscsettings.shutdown_count_hint1 Aika minuutteina jonka jälkeen laite sammuu +miscsettings.shutdown_count_hint2 automaattisesti valmiustilasta (0 = pois). +miscsettings.shutdown_real Käytä valmiustilaa +miscsettings.shutdown_real_rcdelay Sammutusviive +miscsettings.sptsmode Käytä spts-tilaa +miscsettings.startbhdriver Lataa BH-tilan ajurit +miscsettings.tuxtxt_cache Teksti-tv:n välimuisti +motorcontrol.head Kääntömoottorin asetukset +moviebrowser.book_head Bookmarks +moviebrowser.book_lastmoviestop Last play stop: +moviebrowser.book_movieend Movie end: +moviebrowser.book_moviestart Movie start: +moviebrowser.book_name Name: +moviebrowser.book_new New Bookmark +moviebrowser.book_position Position: +moviebrowser.book_type Jump (<0 back , >0 for): +moviebrowser.book_type_backward Repeat +moviebrowser.book_type_forward jump over +moviebrowser.edit_book Bookmark change +moviebrowser.edit_book_name_info1 Enter new Bookmark name +moviebrowser.edit_book_name_info2 +moviebrowser.edit_book_pos_info1 Enter new Position (s) +moviebrowser.edit_book_pos_info2 +moviebrowser.edit_book_type_info1 Enter new jump length (s) +moviebrowser.edit_book_type_info2 <0 back , >0 for, 0: none +moviebrowser.edit_serie Enter name of serie +moviebrowser.error_no_movies No movies found +moviebrowser.foot_filter Filter: +moviebrowser.foot_play Start movie +moviebrowser.foot_sort Sort: +moviebrowser.head TS MovieBrowser +moviebrowser.head_filter Filter movies by category: +moviebrowser.head_playlist Last played: +moviebrowser.head_recordlist Last recorded: +moviebrowser.hint_jumpbackward Jump back in 5 s\n '0' to cancel +moviebrowser.hint_jumpforward Jump forward in 5 s\n '0' to cancel +moviebrowser.hint_movieend Filmende in 5 s\n '0' zum weitersehen +moviebrowser.hint_newbook_backward New jump back\n 'blue' for endposition +moviebrowser.hint_newbook_forward New jump forward\n 'blue' for endposition +moviebrowser.info_audio Audio +moviebrowser.info_channel Channel +moviebrowser.info_filename Name +moviebrowser.info_genre_major Genre +moviebrowser.info_genre_minor Genre +moviebrowser.info_head Film Informationen +moviebrowser.info_info1 Info 1 +moviebrowser.info_info2 Info 2 +moviebrowser.info_length Length (Min) +moviebrowser.info_parental_lockage Parental Lock age +moviebrowser.info_parental_lockage_0year always +moviebrowser.info_parental_lockage_12year 12 years +moviebrowser.info_parental_lockage_16year 16 years +moviebrowser.info_parental_lockage_18year 18 years +moviebrowser.info_parental_lockage_6year 6 years +moviebrowser.info_parental_lockage_always never +moviebrowser.info_path Path +moviebrowser.info_prevplaydate Last play date +moviebrowser.info_prodcountry Country +moviebrowser.info_prodyear Year +moviebrowser.info_quality Quality +moviebrowser.info_recorddate Record date +moviebrowser.info_serie Serie +moviebrowser.info_size File size (MB) +moviebrowser.info_title Titel +moviebrowser.info_videoformat Picture +moviebrowser.menu_directories_head Paths +moviebrowser.menu_help_head Help +moviebrowser.menu_main_bookmarks Bookmarks +moviebrowser.menu_main_head Settings +moviebrowser.menu_main_movieinfo Movie info +moviebrowser.menu_main_saveandback save and back +moviebrowser.menu_nfs_head NFS settings +moviebrowser.menu_parental_lock_activated activated +moviebrowser.menu_parental_lock_activated_no no +moviebrowser.menu_parental_lock_activated_yes yes +moviebrowser.menu_parental_lock_activated_yes_temp yes (temporary) +moviebrowser.menu_parental_lock_head Parental Lock +moviebrowser.menu_parental_lock_rate_head Lock movies from +moviebrowser.scan_for_movies Scan for Movies ... +moviebrowser.serie_existingname Existing series +moviebrowser.serie_head Serie +moviebrowser.serie_name Change name +moviebrowser.short_audio Audio +moviebrowser.short_book Book +moviebrowser.short_channel Channel +moviebrowser.short_country Country +moviebrowser.short_filename Name +moviebrowser.short_format Format +moviebrowser.short_genre_major Genre +moviebrowser.short_genre_minor Genre +moviebrowser.short_info1 Info 1 +moviebrowser.short_info2 Info 2 +moviebrowser.short_length Min +moviebrowser.short_parental_lockage Age +moviebrowser.short_path Path +moviebrowser.short_prevplaydate Last +moviebrowser.short_prodyear Year +moviebrowser.short_quality * (quality) +moviebrowser.short_recorddate Date +moviebrowser.short_serie Serie +moviebrowser.short_size MB +moviebrowser.short_title Title +moviebrowser.start_head Start movie from: +moviebrowser.start_record_start Movie start +movieplayer.bookmark Kirjanmerkit +movieplayer.bookmarkname Kirjanmerkki +movieplayer.bookmarkname_hint1 Syötä nimi uudelle kirjanmerkille +movieplayer.bookmarkname_hint2 +movieplayer.buffering Puskuroin... +movieplayer.defdir Oletushakemisto +movieplayer.defplugin Oletuslaajennos +movieplayer.dvdplayback DVD +movieplayer.fileplayback Toisto VLC:n kautta +movieplayer.goto +,- -> suhteellinen hyppy +movieplayer.goto.h1 = -> absoluuttinen hyppy +movieplayer.goto.h2 +,- -> suhteellinen hyppy +movieplayer.head Mediasoitin +movieplayer.nostreamingserver Videon lähettäjäpalvelimeen ei saatu yhteyttä. +movieplayer.pleasewait Odota hetki.\nYhdistän videopalvelimeen... +movieplayer.toomanybookmarks Liian monta kirjanmerkkiä.\nPoista vähintään yksi ensin. +movieplayer.tshelp1 Ohjeet: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp10 n. 10 minuuttia taaksepäin +movieplayer.tshelp11 n. 10 minuuttia eteenpäin +movieplayer.tshelp12 Ohjeet: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Valitse ääniraita +movieplayer.tshelp3 Tauko/Jatka +movieplayer.tshelp4 Luo kirjanmerkki +movieplayer.tshelp5 Näytä eteneminen +movieplayer.tshelp6 n. minuutti taaksepäin +movieplayer.tshelp7 n. minuutti eteenpäin +movieplayer.tshelp8 n. 5 minuuttia taaksepäin +movieplayer.tshelp9 n. 5 minuuttia eteenpäin +movieplayer.tsplayback Toista tiedosto +movieplayer.tsplayback_pc Toista tiedosto (PIN-koodattu) +movieplayer.vcdplayback (S)VCD +movieplayer.vlchelp1 Ohjeet: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp10 n. 10 minuuttia taaksepäin +movieplayer.vlchelp11 n. 10 minuuttia eteenpäin +movieplayer.vlchelp12 Ohjeet: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Tahdista +movieplayer.vlchelp3 Tauko/Jatka +movieplayer.vlchelp4 Luo kirjanmerkki +movieplayer.vlchelp5 Näytä eteneminen +movieplayer.vlchelp6 n. minuutti taaksepäin +movieplayer.vlchelp7 n. minuutti eteenpäin +movieplayer.vlchelp8 n. 5 minuuttia taaksepäin +movieplayer.vlchelp9 n. 5 minuuttia eteenpäin +movieplayer.wrongvlcversion Tämä toiminto ei ole käytössä tässä VLC versiossa +networkmenu.broadcast Broadcast-osoite +networkmenu.dhcp DHCP +networkmenu.gateway Yhdyskäytävä +networkmenu.head Verkkoasetukset +networkmenu.ipaddress IP-osoite +networkmenu.mount Verkkolevyt +networkmenu.nameserver Nimipalvelin +networkmenu.netmask Aliverkon peite +networkmenu.setupnow Ota asetukset käyttöön +networkmenu.setuponstartup Verkko käynnistyksessä +networkmenu.show Näytä nykyiset asetukset +networkmenu.test Testaa verkkoasetukset +nfs.alreadymounted Hakemisto on jo liitetty +nfs.automount Liitä käynnistyksessä +nfs.dir Palvelimen hakemisto +nfs.ip Palvelimen IP-osoite +nfs.localdir Paikallinen hakemisto +nfs.mount Verkkolevyjen asetukset +nfs.mount_options Liitosasetukset +nfs.mounterror Tuntematon tiedostojärjestelmä +nfs.mounterror_notsup Tuntematon tiedostojärjestelmä +nfs.mountnow Liitä nyt +nfs.mountok Liitos onnistui +nfs.mounttimeout Liitos epäonnistui: aikakatkaisu +nfs.password Salasana +nfs.remount Liitä verkkolevyt uudelleen +nfs.type Verkkolevyn tyyppi +nfs.type_cifs CIFS +nfs.type_lufs FTPFS +nfs.type_nfs NFS +nfs.umount Vapauta verkkolevy +nfs.umounterror Virhe vapauttaessa verkkolevyä +nfs.username Käyttäjätunnus +nfsmenu.head Verkkolevyjen asetukset +nvod.percentage (%d%% jäljellä) +nvod.starting (Käynnistys %d minuutin kuluttua) +nvodselector.directormode Suora-Tila +nvodselector.head Valitse aloitusajankohta +nvodselector.subservice Valitse palvelu +options.default Palauta oletukset +options.fb Framebuffer +options.null (null) +options.off Pois +options.on Päällä +options.on.without_messages Hiljaisesti +options.serial Sarjaportti +parentallock.changepin PIN-koodin vaihto +parentallock.changepin_hint1 Syötä lapsilukon uusi PIN-koodi. +parentallock.changetolocked lukituille kanavanipuille +parentallock.head Syötä lapsilukon PIN-koodi +parentallock.lockage Lukitse +parentallock.lockage12 alle 12 vuotiailta +parentallock.lockage16 alle 16 vuotiailta +parentallock.lockage18 alle 18 vuotiailta +parentallock.lockedchannel Lukittu kanava... +parentallock.lockedprogram Lukittu ohjelma (alle %d vuotiailta) +parentallock.never ei koskaan +parentallock.onsignal lähetyksen mukaan +parentallock.parentallock Lapsilukko +parentallock.prompt PIN-koodin kysely +pictureviewer.decode_server_ip palvelimen IP-osoite +pictureviewer.decode_server_port palvelimen portti +pictureviewer.defdir Aloitushakemisto +pictureviewer.head Kuvankatselu +pictureviewer.help1 siirry alas +pictureviewer.help10 Katselu tila +pictureviewer.help11 lue uudelleen kuva +pictureviewer.help12 edellinen kuva +pictureviewer.help13 seuraava kuva +pictureviewer.help14 loitonna +pictureviewer.help15 lähennä +pictureviewer.help16 siirry ylös +pictureviewer.help17 siirry vasemmalle +pictureviewer.help18 siirry oikealle +pictureviewer.help19 siirry alas +pictureviewer.help2 poistu +pictureviewer.help20 vaihda järjestystä +pictureviewer.help21 lue kuva uudelleen (ei skaalausta) +pictureviewer.help22 poistu +pictureviewer.help3 muuta järjestystä +pictureviewer.help4 älä muuta kuvan kokoa +pictureviewer.help5 diaesitys +pictureviewer.help6 edellinen kuva +pictureviewer.help7 seuraava kuva +pictureviewer.help8 muuta järjestystä +pictureviewer.help9 poistu +pictureviewer.resize.color_average advanced +pictureviewer.resize.none ei mitään +pictureviewer.resize.simple yksinkertainen +pictureviewer.scaling skaalaus +pictureviewer.show näytä +pictureviewer.slide_time diaesityksessä kuvan näyttöaika +pictureviewer.slideshow diaesitys +pictureviewer.sortorder (tiedostonimi) +pictureviewer.sortorder.date (pvm) +pictureviewer.sortorder.filename (tiedostonimi) +ping.ok tavoitettavissa (ping) +ping.protocol ei tavoitettavissa (host or protocol error) +ping.socket ei tavoitettavissa (socket error) +ping.unreachable ei tavoitettavissa +pinprotection.head Syötä PIN-koodi +pinprotection.wrongcode Virheellinen PIN-koodi. Yritä uudelleen. +plugins.result Info +rclock.lockmsg Kaukosäädin on lukittu.\nAvaa painamalla ensin punaista- ja sitten DBox-näppäintä. +rclock.menueadd Lukitse kaukosäädin +rclock.title Kaukosäätimen lukitus +rclock.unlockmsg Lukitus avattu. +recordingmenu.apids Tallennuksen äänet +recordingmenu.apids_ac3 Tallenna AC3 ääni +recordingmenu.apids_alt Tallenna muut äänet +recordingmenu.apids_std Tallenna oletusääni +recordingmenu.choose_direct_rec_dir Hakemiston valinta välittömässä tall. +recordingmenu.defdir Tallennushakemisto +recordingmenu.dir_permissions Hakemisto-oikeudet +recordingmenu.dir_permissions_hint Hakemiston oikeudet unix-tyyliin. Yleensä 755. +recordingmenu.epg_for_filename Pitkät tiedostonimet (sis. EPG-tiedot) +recordingmenu.file Tiedosto +recordingmenu.filename_template Tiedostojen nimeäminen +recordingmenu.filename_template_hint %c=kanava, %i=ohjelman nimi,%d=päiväys, %t=aika +recordingmenu.filesettings Tiedostotallennuksen asetukset +recordingmenu.head Tallennusasetukset +recordingmenu.help Tallennustavat:\n- Palvelin:\n-- Tallennus käyttäen PC:ssä olevaa erillistä ohjelmistoa\n- Videonauhuri:\n-- Tallennus VCR-scart:iin kytketylle videonauhurille\n\n- Tiedosto:\n-- Tallennus suoraan tiedostoon\n -- verkkolevylle tai sisäiselle kiintolevylle\nTallennus spts-tilassa:\n- Päällä = TS\n- Pois = PES\n\nTiedostojärjestelmien suurimmat tiedostokoot:\n- NFS V2: 2 GB (2048 MB)\n- NFS V3: lähes rajoittamaton (0 MB)\n- FAT: 2 GB (2048 MB)\n- FAT32: 4 GB (4096 MB) +recordingmenu.no_scart Älä vaihda scart-tilaan +recordingmenu.off Pois +recordingmenu.record_in_spts_mode Tallennus spts-tilassa +recordingmenu.recording_type Tallennustapa +recordingmenu.ringbuffers Rengaspuskureiden määrä +recordingmenu.server Palvelin (stream) +recordingmenu.server_ip Palvelimen IP-osoite +recordingmenu.server_mac Palvelimen MAC +recordingmenu.server_port Palvelimen portti +recordingmenu.server_wakeup Palvelimen Wake-On-Lan +recordingmenu.setupnow Ota asetukset käyttöön +recordingmenu.splitsize Suurin tiedostokoko (MB) +recordingmenu.stopplayback Pysäytä toisto +recordingmenu.stopsectionsd Pysäytä sectionsd +recordingmenu.stream_pmt_pid Tallenna PMT +recordingmenu.stream_vtxt_pid Tallenna teksti-tv +recordingmenu.use_fdatasync Tallenna synkronisesti (fdatasync) +recordingmenu.use_o_sync Tallenna asynkronisesti (O_SYNC) +recordingmenu.vcr Videonauhuri +recordingmenu.zap_on_announce Kanavanvaihtoennakko +recordtimer.announce Tallennus alkaa muutaman minuutin kuluttua +repeatblocker.hint_1 Pienin aikaväli (ms) 2 näppäinpainalluksen tunnistamiseen +repeatblocker.hint_2 Syötä 0 vaihtaaksesi kursori (punainen = välilyönti) +satsetup.diseqc DiSEqC-toisto +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-toisto +satsetup.extended Moottorin asetukset +satsetup.extended_motor Moottorin asetukset +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Manaalinen moottorin asennus +satsetup.nodiseqc no DiSEqC +satsetup.satellite Satelliitti +satsetup.savesettingsnow Tallenna asetukset +satsetup.smatvremote SMATV Remote Tuning +scantp.fec Virheenkorjaus +scantp.fec_1_2 1/2 +scantp.fec_2_3 2/3 +scantp.fec_3_4 3/4 +scantp.fec_5_6 5/6 +scantp.fec_7_8 7/8 +scantp.freq Taajuus +scantp.pol Polariteetti +scantp.pol_h Vaaka +scantp.pol_v Pysty +scantp.rate Symbolinopeus +scantp.scan Manuaalinen haku +scantp.scanmode Nopea haku +scants.abort_body Keskeytetäänkö haku? +scants.abort_header Kanavien haku keskeytetty +scants.actcable Kaapeli: +scants.actsatellite Sateliitti: +scants.bouquet Kanavaniput +scants.bouquet_create luo uudet +scants.bouquet_erase poista kaikki +scants.bouquet_leave jätä nykyiset +scants.bouquet_satellite satelliittinippu +scants.bouquet_update päivitä +scants.channel Kanava: +scants.failed Lähetinhaku epäonnistui! +scants.finished Lähetinhaku valmis! +scants.freqdata Taajuus: +scants.head Skannaa lähetin +scants.numberofdataservices Data +scants.numberofradioservices Radio +scants.numberoftotalservices Yhteensä +scants.numberoftvservices TV +scants.provider Palveluntarjoaja: +scants.startnow Aloita haku +scants.transponders lähettimet: +screensetup.lowerright vihreä = säädä alakulmaa +screensetup.upperleft punainen = säädä yläkulmaa +sectionsd.scanmode Autom. kanavapäivitys +servicemenu.getplugins Lue laajennoslista uudelleen +servicemenu.getplugins_hint Ladataan laajennoksia,\nodota hetki. +servicemenu.head Huoltovalikko +servicemenu.imageinfo Ohjelmiston tiedot +servicemenu.reload Lue kanavalista uudelleen +servicemenu.reload_hint Ladataan kanavalistoja,\nodota hetki. +servicemenu.restart Käynnistä Neutrino uudelleen +servicemenu.restart_failed Neutrinon uudelleenkäynnistys epäonnistui. +servicemenu.restart_hint Uudelleenkäynnistetään Neutrino... +servicemenu.restart_refused_recording Tallennus käynnissä. Uudelleenkäynnistys estetty. +servicemenu.scants Kanavahaku +servicemenu.ucodecheck µCodejen tiedot +servicemenu.update Ohjelmistopäivitys +settings.help Ohje +settings.missingoptionsconffile Neutrinon asetukset päivitetty.\nUudet asetukset on alustettu oletusarvoihin. +settings.noconffile Neutrinon asetuksia ei löytynyt.\nKaikki asetukset on alustettu oletusarvoihin. +settings.pos_bottom_left vasen ala +settings.pos_bottom_right oikea ala +settings.pos_top_left vasen ylä +settings.pos_top_right oikea ylä +shutdown.recoding_query Tallennus käynnissä. Haluatko varmasti sammuttaa? +shutdowntimer.announce Sammutus minuutin kuluttua.\nPeru sammutus? +sleeptimerbox.announce Uniajastimessa minuutti jäljellä. +sleeptimerbox.hint1 Sammutusaika minuutteina (000=ei sammutusta). +sleeptimerbox.hint2 Laite sammuu itsestään asetetun ajan kuluttua. +sleeptimerbox.title Uniajastin +streamfeatures.head Lisätoiminnot +streaminfo.aratio Kuvasuhde +streaminfo.aratio_unknown Tuntematon kuvasuhde +streaminfo.audiotype Ääniraita +streaminfo.audiotype_unknown Tuntematon ääniraita +streaminfo.bitrate Bittinopeus +streaminfo.framerate Kuvataajuus +streaminfo.framerate_unknown Tuntematon kuvataajuus +streaminfo.head Lähetteen tiedot +streaminfo.not_available ei saatavilla +streaminfo.resolution Resoluutio +streaminfo.signal Signaalitasot +streaming.buffer_overflow Tallennus keskeytyi,\nkoska videota ei pystytty tallentamaan tarpeeksi nopeasti. +streaming.busy Yksi tai useampi tallennus käynnissä.\nMikäli olet varma, että tallennusta ei ole, käynnistä laite uudelleen. +streaming.dir_not_writable Tallennushakemistoon ei voida kirjoittaa\nTallennus ei toimi. +streaming.success Tallennus onnistui. +streaming.write_error Tallennus keskeytyi,\nkoska tallennustiedostoa ei voitu luoda. +streaming.write_error_open Tallennus keskeytyi,\nkoska tallennustiedostoa ei voitu luoda. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Mediasoittimen asetukset +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Pois +streamingmenu.on Päällä +streamingmenu.server_ip Palvelimen IP-osoite +streamingmenu.server_port Palvelimen portti +streamingmenu.streaming_audiorate Äänen datanopeus +streamingmenu.streaming_force_avi_rawaudio Pakota AC3 AVI:lle +streamingmenu.streaming_force_transcode_video Muunna video (MPG/VCD) +streamingmenu.streaming_resolution Resoluutio +streamingmenu.streaming_server_cddrive DVD-aseman polku +streamingmenu.streaming_server_startdir Aloituspolku +streamingmenu.streaming_transcode_audio Muunna audio (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec MPEG video +streamingmenu.streaming_type Palvelin (stream) +streamingmenu.streaming_videorate Kuvan datanopeus +streamingserver.noconnect Tallennuspalvelimelle ei saatu yhteyttä.\nTallennus keskeytetty. +stringinput.caps ABC / abc +stringinput.clear Tyhjennä kaikki +timer.eventrecord.msg Oletko varma? +timer.eventrecord.title Ajasta tallennus +timer.eventtimed.msg Tapahtuma ajastettu.\nLaite käynnistyy ja vaihtaa\nkanavalle tähän aikaan. +timer.eventtimed.title Ajasta tapahtuma +timerbar.channelswitch Ajasta +timerbar.recordevent Tallenna +timerlist.alarmtime Alkuaika +timerlist.apids Audio PIDit +timerlist.bouquetselect Valitse kanavanippu +timerlist.channel Valitse kanava +timerlist.channelselect Valitse kanava +timerlist.delete Poista +timerlist.menumodify Muokkaa ajastusta +timerlist.menunew Uusi ajastus +timerlist.message Viesti +timerlist.moderadio Radiokanavat +timerlist.modeselect Tilan valinta +timerlist.modetv TV-kanavat +timerlist.modify Muokkaa +timerlist.name Ajastukset +timerlist.new Uusi ajastus +timerlist.overlapping_timer Päällekkäisyys ajastuksissa. Jatketaanko? +timerlist.plugin Laajennos +timerlist.program.unknown Tuntematon ohjelma +timerlist.recording_dir Tallennushakemisto +timerlist.reload Lataa uudelleen +timerlist.repeat Toisto +timerlist.repeat.biweekly joka toinen viikko +timerlist.repeat.byeventdescription kuvaksen mukaan +timerlist.repeat.daily päivittäin +timerlist.repeat.fourweekly 4 viikon välein +timerlist.repeat.friday Pe +timerlist.repeat.monday Ma +timerlist.repeat.monthly kuukausittain +timerlist.repeat.once kerran +timerlist.repeat.saturday La +timerlist.repeat.sunday Su +timerlist.repeat.thursday To +timerlist.repeat.tuesday Ti +timerlist.repeat.unknown ei tiedossa +timerlist.repeat.wednesday Ke +timerlist.repeat.weekdays arkisin +timerlist.repeat.weekly viikoittain +timerlist.repeatcount Toistokerrat +timerlist.repeatcount.help1 Toistokertojen lukumäärä. +timerlist.repeatcount.help2 0 = rajoittamattomasti. +timerlist.save Tallenna ajastus +timerlist.standby Tila +timerlist.standby.off Poistu valmiustilasta +timerlist.standby.on Siirry valmiustilaan +timerlist.stoptime Päättymisaika +timerlist.type Toiminne +timerlist.type.execplugin Suorita laajennos +timerlist.type.nextprogram Seuraava ohjelma +timerlist.type.record Tallennus +timerlist.type.remind Muistutus +timerlist.type.shutdown Sammutus +timerlist.type.sleeptimer Uniajastin +timerlist.type.standby Valmiustila +timerlist.type.unknown Tuntematon +timerlist.type.zapto Kanavanvaihto +timerlist.weekdays 'X'=ajastus '-' ei ajastusta +timerlist.weekdays.hint_1 Ma Ti Ke To Pe La Su +timerlist.weekdays.hint_2 'X'=ajastus '-' ei ajastusta +timersettings.record_safety_time_after Ajastuksen pidennys +timersettings.record_safety_time_after.hint_1 Pidennysaika minuutteina (00=pois). Jokaista +timersettings.record_safety_time_after.hint_2 tallennusta jatketaan tämän verran yliajalle. +timersettings.record_safety_time_before Ajastuksen ennakko +timersettings.record_safety_time_before.hint_1 Ennakkoaika minuutteina (00=pois). Jokainen +timersettings.record_safety_time_before.hint_2 tallennus aloitetaan tämän verran etuajassa. +timersettings.separator Ajastusasetukset +timing.chanlist Kanavalista +timing.epg EPG ohjelmaopas +timing.filebrowser Tiedostoselain +timing.head OSD-ajoitukset +timing.hint_1 Aika sekunteina. Infopalkkia/valikkoa +timing.hint_2 näytetään tämä aika. +timing.infobar Infopalkki +timing.menu Valikko +timing.numericzap Kanavan valinta numerolla +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head µCodejen tiedot +ucodecheck.ucode µCode +ucodes.failure VAROITUS: µCodeja ei löytynyt!\n\nOle hyvä ja siirrä ne FTP:llä (tai DBox-BootManagerilla) laitteeseen,\nja käynnistä se uudelleen! +videomenu.csync Tahdistuskorjaus +videomenu.head Kuva-asetukset +videomenu.rgb_centering RGB keskitys +videomenu.screensetup OSD-näytön kohdistus +videomenu.vcrswitch SCART:in automaattiohjaus +videomenu.videoformat Kuvasuhde +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect automaattinen +videomenu.videosignal Videolähtö +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zapit.scantype Haettavat palvelut +zapit.scantype.all kaikki palvelut +zapit.scantype.radio vain radiokanavat +zapit.scantype.tv vain TV-kanavat +zapit.scantype.tvradio TV- ja radiokanavat +zaptotimer.announce Kanava vaihtuu ajastetulle kanavalle minuutin kuluttua diff --git a/data/locale/svenska.locale b/data/locale/svenska.locale new file mode 100644 index 000000000..99883ea33 --- /dev/null +++ b/data/locale/svenska.locale @@ -0,0 +1,954 @@ +AUDIOSelectMenue.head Ljudval +EPGMenu.epgplus Händelsevy +EPGMenu.eventinfo Detaljer om nuvarande program +EPGMenu.eventlist Händelsevy nuvarande program +EPGMenu.head EPG - Program Information +EPGMenu.streaminfo Teknisk information +EPGPlus.actions Ã…tgärder +EPGPlus.bybouquet_mode av bouquet +EPGPlus.bypage_mode av sida +EPGPlus.change_font_size Byt textstorlek +EPGPlus.change_font_style Byt textutseende +EPGPlus.change_size Byt storlek +EPGPlus.channelentry_font Kanaler +EPGPlus.channelentry_separationlineheight höjden av linje mellan poster +EPGPlus.channelentry_width längd av kanalnamn +EPGPlus.channelevententry_font Program +EPGPlus.edit_fonts Edit text +EPGPlus.edit_sizes Edit storlekar +EPGPlus.font_style_bold fet +EPGPlus.font_style_italic kursiv +EPGPlus.font_style_regular vanlig +EPGPlus.footer_fontbouquetchannelname Valt bouquet-/kanalnamn +EPGPlus.footer_fontbuttons Knappar +EPGPlus.footer_fonteventdescription Title 1 valt Prog. +EPGPlus.footer_fonteventshortdescription Title 2 valt Prog. +EPGPlus.head Händelselistvy (EPG Plus) +EPGPlus.header_font Huvud +EPGPlus.horgap1_height höjd hor. gap 1 +EPGPlus.horgap2_height höjd hor. gap 2 +EPGPlus.next_bouquet Nästa bouquet +EPGPlus.options Optioner +EPGPlus.page_down Sida ner +EPGPlus.page_up Sida upp +EPGPlus.prev_bouquet FöregÃ¥ende bouquet +EPGPlus.record Spela in +EPGPlus.refresh_epg Uppdatera +EPGPlus.remind Schema +EPGPlus.reset_settings Ã…terställ inställningar +EPGPlus.save_settings Spara inställningar +EPGPlus.scroll_mode Scroll läge +EPGPlus.select_font_name Textval +EPGPlus.settings Inställningar +EPGPlus.slider_width rullist bredd +EPGPlus.stretch_mode Utdragningsläge +EPGPlus.swap_mode hoppa-över läge +EPGPlus.timeline_fontdate Tidsskala Datum +EPGPlus.timeline_fonttime Tidsskala Tid +EPGPlus.vergap1_width längd ver. gap 1 +EPGPlus.vergap2_width längd ver. gap 2 +EPGPlus.view_mode Läge +GENRE.ARTS.0 konst / kultur +GENRE.ARTS.1 konstnärlig uppvisning +GENRE.ARTS.10 konst/kultur magasin +GENRE.ARTS.11 mode +GENRE.ARTS.2 fin konst +GENRE.ARTS.3 religion +GENRE.ARTS.4 populär kultur/traditionell konst +GENRE.ARTS.5 litteratur +GENRE.ARTS.6 film/bio +GENRE.ARTS.7 experimentell film/video +GENRE.ARTS.8 broadcasting/press +GENRE.ARTS.9 ny media +GENRE.CHILDRENs_PROGRAMMES.0 barn / ungdomsprogram +GENRE.CHILDRENs_PROGRAMMES.1 förskola barnprogram +GENRE.CHILDRENs_PROGRAMMES.2 nöjesprogram frÃ¥n 6 till 14 +GENRE.CHILDRENs_PROGRAMMES.3 nöjesprogram för 10 till 16 +GENRE.CHILDRENs_PROGRAMMES.4 information/utbildning/skolprogram +GENRE.CHILDRENs_PROGRAMMES.5 tecknad film/dockteater +GENRE.DOCUS_MAGAZINES.0 dokumentär / magasin +GENRE.DOCUS_MAGAZINES.1 natur/djur/miljö +GENRE.DOCUS_MAGAZINES.2 teknologi/naturkunskap +GENRE.DOCUS_MAGAZINES.3 medicin/psykologi +GENRE.DOCUS_MAGAZINES.4 utrikes/expeditioner +GENRE.DOCUS_MAGAZINES.5 social/andlig +GENRE.DOCUS_MAGAZINES.6 vidareutbildning +GENRE.DOCUS_MAGAZINES.7 sprÃ¥k +GENRE.MOVIE.0 film/drama +GENRE.MOVIE.1 detektiv/thriller +GENRE.MOVIE.2 äventyr/western/krig +GENRE.MOVIE.3 science fiction/fantasi/skräck +GENRE.MOVIE.4 komedi +GENRE.MOVIE.5 sÃ¥pa/melodrama/folkhistoria +GENRE.MOVIE.6 romans +GENRE.MOVIE.7 seriöst/klassisk/religiös/historisk film/drama +GENRE.MOVIE.8 vuxen film/drama +GENRE.MUSIC_DANCE.0 musik / balett / dans +GENRE.MUSIC_DANCE.1 rock/pop +GENRE.MUSIC_DANCE.2 seriös music/klassisk musik +GENRE.MUSIC_DANCE.3 folk/traditionell musik +GENRE.MUSIC_DANCE.4 jazz +GENRE.MUSIC_DANCE.5 musikal/opera +GENRE.MUSIC_DANCE.6 balett +GENRE.NEWS.0 nyheter +GENRE.NEWS.1 nyheter/väderrapport +GENRE.NEWS.2 nyhetsmagasin +GENRE.NEWS.3 dokumentär +GENRE.NEWS.4 diskussion/intervju/debatt +GENRE.SHOW.0 Show / Gameshow +GENRE.SHOW.1 game show/frÃ¥gesport/tävling +GENRE.SHOW.2 variteshow +GENRE.SHOW.3 pratshow +GENRE.SOCIAL_POLITICAL.0 social & politiska händelser / affärer +GENRE.SOCIAL_POLITICAL.1 magasin/rapporter/dokumentärer +GENRE.SOCIAL_POLITICAL.2 ekonomi/sociala frÃ¥gor +GENRE.SOCIAL_POLITICAL.3 enastÃ¥ende människor +GENRE.SPORTS.0 sport +GENRE.SPORTS.1 special evenemang (Olympiska Spelen, Världsmästerskap etc.) +GENRE.SPORTS.10 hästsport +GENRE.SPORTS.11 kampsport +GENRE.SPORTS.2 sport magasin +GENRE.SPORTS.3 football/fotboll +GENRE.SPORTS.4 tennis/squash +GENRE.SPORTS.5 lagsporter (exklusive fotboll) +GENRE.SPORTS.6 friidrott +GENRE.SPORTS.7 motorsport +GENRE.SPORTS.8 vattensport +GENRE.SPORTS.9 vintersport +GENRE.TRAVEL_HOBBIES.0 resor & rekreation +GENRE.TRAVEL_HOBBIES.1 turism/resor +GENRE.TRAVEL_HOBBIES.2 hantverk +GENRE.TRAVEL_HOBBIES.3 motorer +GENRE.TRAVEL_HOBBIES.4 fitness & hälsa +GENRE.TRAVEL_HOBBIES.5 matlagning +GENRE.TRAVEL_HOBBIES.6 reklam/shopping +GENRE.TRAVEL_HOBBIES.7 trädgÃ¥rd +GENRE.UNKNOWN unknown +apids.hint_1 Ange APIDs som ska streamas +apids.hint_2 i hexadec separerade med ' ' +apidselector.head Välj sprÃ¥k +audiomenu.PCMOffset Sänk volymen (PCM) +audiomenu.analogout Analog utgÃ¥ng +audiomenu.audio_left_right_selectable väljbar i Ljudmenu +audiomenu.audiochannel_up_down_enable Ljudval med höger/vänster +audiomenu.avs avs +audiomenu.avs_control Volymkontroll +audiomenu.dolbydigital Dolby Digital som default +audiomenu.head Ljudinställningar +audiomenu.lirc lirc +audiomenu.monoleft mono vänster +audiomenu.monoright mono höger +audiomenu.ost ost +audiomenu.stereo stereo +audioplayer.add Lägg till +audioplayer.artist_title Artist, Titel +audioplayer.building_search_index bygger sökindex +audioplayer.button_select_title_by_id sök efter ID +audioplayer.button_select_title_by_name sök efter namn +audioplayer.defdir start mapp +audioplayer.delete Radera +audioplayer.deleteall radera alla +audioplayer.display_order visa efter +audioplayer.enable_sc_metadata aktivera shoutcast meta data läsning +audioplayer.fastforward snabbt framÃ¥t +audioplayer.follow auto välj nuvarande +audioplayer.head Ljud spellista +audioplayer.highprio Hög dekodningsprioritet +audioplayer.id3scan Söker ID3 taggar +audioplayer.jump_backwards hoppa bakÃ¥t +audioplayer.jump_dialog_hint1 Ange destinationsmÃ¥l +audioplayer.jump_dialog_hint2 (relativt, i sekunder) +audioplayer.jump_dialog_title Ange destinationsmÃ¥l +audioplayer.jump_forwards hoppa framÃ¥t +audioplayer.keylevel nyckelnivÃ¥ +audioplayer.name Ljudspelare +audioplayer.pause pause +audioplayer.play Spela +audioplayer.playing Nuvarande spÃ¥r +audioplayer.playlist_fileerror_msg Filen kunde inte skapas: +audioplayer.playlist_fileerror_title Fel +audioplayer.playlist_fileoverwrite_msg Vill du skriva över denna fil: +audioplayer.playlist_fileoverwrite_title Skriv över? +audioplayer.playlist_name filnamn pÃ¥ spellistan +audioplayer.playlist_name_hint1 Ange filnamnet pÃ¥ spellistan +audioplayer.playlist_name_hint2 Suffixet .m3u kommer att sättas automatiskt +audioplayer.reading_files läser meta data +audioplayer.repeat_on aktivera upprepningsläge +audioplayer.rewind spela bakÃ¥t +audioplayer.save_playlist spara spellistan +audioplayer.screensaver_timeout timeout skärmsparare (min, 0=av) +audioplayer.select_title_by_name sök titel via namn (SMS) +audioplayer.show_playlist Visa spellistan +audioplayer.shuffle kasta om +audioplayer.stop Stopp +audioplayer.title_artist Titel, Artist +audioplayerpicsettings.general musikspelare / bildvisare +bookmarkmanager.delete radera +bookmarkmanager.name bokmärken +bookmarkmanager.rename byt namn +bookmarkmanager.select välj +bouqueteditor.add Lägg till +bouqueteditor.bouquetname Namn pÃ¥ bouquets +bouqueteditor.delete Radera +bouqueteditor.discardingchanges Glömmer ändringarna. Var god vänta. +bouqueteditor.hide Göm +bouqueteditor.lock LÃ¥s +bouqueteditor.move Flytta +bouqueteditor.name ändra bouquet +bouqueteditor.newbouquetname Nytt namn pÃ¥ bouquets +bouqueteditor.rename Byt namn +bouqueteditor.return klar +bouqueteditor.savechanges? Vill du spara ändringarna? +bouqueteditor.savingchanges Sparar ändringar. Vänta ... +bouqueteditor.switch lägg till/ta bort +bouqueteditor.switchmode TV/Radio +bouquetlist.head Bouquets +cablesetup.provider kabel operatör +channellist.head Alla tjänster +channellist.nonefound Inga kanaler hittades!\nVänligen gör en sökning\n(dbox-knapp -> tjänster) +channellist.since sedan %02d:%02d +colorchooser.alpha alpha +colorchooser.blue blÃ¥ +colorchooser.green grön +colorchooser.red röd +colormenu.background Bakgrund +colormenu.background_head Bakgrund +colormenu.fade Tona ner menyer +colormenu.font Font storlek +colormenu.gtx_alpha Genomskinlighet (GTX) +colormenu.head Färginställningar +colormenu.menucolors Menyfärger +colormenu.statusbar Infobalk +colormenu.textcolor Textfärg +colormenu.textcolor_head Textfärg +colormenu.themeselect välj tema +colormenu.timing OSD Tajming +colormenusetup.head Menyfärger +colormenusetup.menucontent FönsterinnehÃ¥ll +colormenusetup.menucontent_inactive FönsterinnehÃ¥ll inaktivt +colormenusetup.menucontent_selected FönsterinnehÃ¥ll vald +colormenusetup.menuhead Menytopp +colorstatusbar.head Infobalk +colorstatusbar.text Infobalk +colorthememenu.classic_theme Klassiskt tema +colorthememenu.dblue_theme DarkBlue tema +colorthememenu.dvb2k_theme DVB2000 tema +colorthememenu.head Temaväljaren +colorthememenu.neutrino_theme Neutrino tema +date.Apr Apr +date.Aug Aug +date.Dec Dec +date.Feb Feb +date.Fri Fre +date.Jan Jan +date.Jul Jul +date.Jun Jun +date.Mar Mar +date.May Maj +date.Mon MÃ¥n +date.Nov Nov +date.Oct Okt +date.Sat Lör +date.Sep Sep +date.Sun Sön +date.Thu Tor +date.Tue Tis +date.Wed Ons +epgextended.actors SkÃ¥despelare +epgextended.director Regisör +epgextended.guests Gäster +epgextended.original_title Originaltitel +epgextended.presenter Presentatör +epgextended.year_of_production Producerad Ã¥r +epglist.head Händelselista - %s +epglist.noevents EPG är inte tillgänglig... +epgviewer.More_Screenings Fler visningar pÃ¥ denna kanal +epgviewer.nodetailed Ingen detaljerad information tillgänglig +epgviewer.notfound ingen EPG hittades +eventlistbar.channelswitch schema +eventlistbar.eventsort sortering +eventlistbar.recordevent spela in +experimentalsettings Experimentella inställningar +experimentalsettings.head Experimentella inställningar +favorites.addchannel Nuvarande kanal kommer att läggas\ntill i bouqueten "Mina favoriter".\nDetta tar nÃ¥gra sekunder... +favorites.bouquetname Mina favoriter +favorites.bqcreated Bouquet "Mina favoriter" har skapats...\n +favorites.chadded Nuvarande kanal har lagt till i dina favoriter...\n +favorites.chalreadyinbq Nuvarande kanal är redan i dina favoriter...\n +favorites.finalhint \nAnvänd bouqueteditorn för att ändra dina favoriter.\n +favorites.menueadd lägg till kanal till favoriterna +favorites.nobouquets Favoriter är endast tillgängliga med aktiverade Bouquets. +filebrowser.delete Radera +filebrowser.denydirectoryleave Absoluta startmappen +filebrowser.dodelete1 Radera +filebrowser.dodelete2 ? +filebrowser.filter.active Filter pÃ¥ +filebrowser.filter.inactive Filter av +filebrowser.head Filöversikt +filebrowser.mark Markera +filebrowser.nextpage Nästa sida +filebrowser.prevpage Före. sida +filebrowser.scan Söker mapp.. +filebrowser.select Välj +filebrowser.showrights Visa filrättigheter +filebrowser.sort.date (datum) +filebrowser.sort.name (filnamn) +filebrowser.sort.namedirsfirst (filnamn2) +filebrowser.sort.size (Storlek) +filebrowser.sort.type (typ) +filesystem.is.utf8 filsystem +filesystem.is.utf8.option.iso8859.1 ISO-8859-1 +filesystem.is.utf8.option.utf8 UTF-8 +flashupdate.actionreadflash läser +flashupdate.cantopenfile kan inte öppna fil +flashupdate.cantopenmtd kan inte öppna mtd-enhet +flashupdate.checkupdate söker efter ny version +flashupdate.currentreleasecycle Lanseringscykel +flashupdate.currentversion_sep Nuvarande version +flashupdate.currentversiondate Datum +flashupdate.currentversionsnapshot Bildtyp +flashupdate.currentversiontime Tid +flashupdate.erasefailed radering av flash misslyckades +flashupdate.erasing raderar flash +flashupdate.experimentalimage Den image du valt är en otestad version, detta betyder\natt din box kanske inte startar efter uppdateringen.\n\nVill du verkligen uppdatera till denna version? +flashupdate.expertfunctions Expertfunktioner +flashupdate.fileis0bytes filstorlek är 0 Bytes +flashupdate.fileselector Filväljare +flashupdate.flashreadyreboot Flashning av image lyckades.\nDin DBox kommer att startas om nu. +flashupdate.getinfofile hämtar versionsinfo +flashupdate.getinfofileerror kan inte hämta versionsinfo +flashupdate.getupdatefile hämtar uppdatering +flashupdate.getupdatefileerror kan inte hämta uppdatering +flashupdate.globalprogress Global progress: +flashupdate.head Uppdatering av mjukvara +flashupdate.md5check undersöker image +flashupdate.md5sumerror image innehÃ¥ller fel +flashupdate.msgbox Hittade följande ny image:\nDatum: %s, %s\nBasimage: %s\nImagetyp: %s\n\nVill du hämta och installera denna version nu? +flashupdate.msgbox_manual Hittade följande ny image:\nDatum: %s, %s\nBasimage: %s\nImagetyp: %s\n\nVill du installera denna version nu? +flashupdate.mtdselector Partitionsväljare +flashupdate.programmingflash programmerar flash +flashupdate.proxypassword Lösenord +flashupdate.proxypassword_hint1 ange lösenord för proxyserver +flashupdate.proxypassword_hint2 +flashupdate.proxyserver Server +flashupdate.proxyserver_hint1 ange proxyservers namn och IP, använd namn:port +flashupdate.proxyserver_hint2 lämna raden tom om du inte har en proxy +flashupdate.proxyserver_sep Proxyserver +flashupdate.proxyusername Användarnamn +flashupdate.proxyusername_hint1 ange användarnamn för proxyserver +flashupdate.proxyusername_hint2 lämna raden tom om du inte använder proxy-auth +flashupdate.readflash Läs hela imagen +flashupdate.readflashmtd Läs en partition +flashupdate.ready klar +flashupdate.reallyflashmtd Vill du verkligen flasha?\n\nOm ett fel inträffar eller om imagen är invalid\n kan boxen inte startas efter flashning.\n\Imagenamn: %s\nMÃ¥l: %s +flashupdate.savesuccess Imagen sparades under\n%s. +flashupdate.selectimage Tillgängliga images +flashupdate.squashfs.noversion Kontroll av SquashFS version är endast möjlig när uppdateringen görs via webben.\nÄr du säker att du vill installera denna image? +flashupdate.titlereadflash Läser Flash +flashupdate.titlewriteflash Skriver Flash +flashupdate.updatemode Uppdateringsläge +flashupdate.updatemode_internet Internet +flashupdate.updatemode_manual manuell (ftp) +flashupdate.url_file konfigfil +flashupdate.versioncheck undersöker version +flashupdate.writeflash Skriv hela imagen +flashupdate.writeflashmtd Skriv en partition +flashupdate.wrongbase Din lanseringscykel skiljer sig, kan inte uppdatera\nutan att ha den rätta versionen installerad! +fontmenu.channellist Kanallista +fontmenu.epg EPG +fontmenu.eventlist Händelslista +fontmenu.gamelist Spellista +fontmenu.head Inställning för fontstorlek +fontmenu.infobar Infobalk +fontsize.channel_num_zap direktval +fontsize.channellist Kanallista +fontsize.channellist_descr Beskrivning +fontsize.channellist_number Nummer +fontsize.epg_date EPG Datum +fontsize.epg_info1 EPG Info 1 +fontsize.epg_info2 EPG Info 2 +fontsize.epg_title EPG Titel +fontsize.eventlist_datetime datum / tid +fontsize.eventlist_itemlarge stor +fontsize.eventlist_itemsmall liten +fontsize.eventlist_title Titel +fontsize.filebrowser_item filväljare post +fontsize.gamelist_itemlarge stor +fontsize.gamelist_itemsmall liten +fontsize.hint Initialiserar font,\nvar god vänta... +fontsize.imageinfo_info bildinformation +fontsize.imageinfo_small bildinformation licens +fontsize.infobar_channame Kanalnamn +fontsize.infobar_info info +fontsize.infobar_number Nummer +fontsize.infobar_small liten +fontsize.menu Menytext +fontsize.menu_info Meny Info +fontsize.menu_title Meny Titel +gtxalpha.alpha1 Alpha 1 +gtxalpha.alpha2 Alpha 2 +imageinfo.creator Skapare: +imageinfo.date Datum: +imageinfo.dokumentation Dokumentation: +imageinfo.forum Forum: +imageinfo.head Bildinformation +imageinfo.homepage Hemsida: +imageinfo.image Bild: +imageinfo.license Licens: +imageinfo.version Version: +infoviewer.epgnotload EPG inte laddad.... +infoviewer.epgwait vänta pÃ¥ EPG... +infoviewer.eventlist Händelselista +infoviewer.languages Ljud +infoviewer.motor_moving Antennposition +infoviewer.nocurrent Ingen info för nuvarande program tillgänglig +infoviewer.noepg EPG inte tillgänglig +infoviewer.notavailable Kanal inte tillgänglig +infoviewer.selecttime Tidsval +infoviewer.streaminfo InnehÃ¥ller +infoviewer.subchan_disp_pos Underkanal visning +infoviewer.subservice Underkanaler +infoviewer.waittime Väntar pÃ¥ tid... +ipsetup.hint_1 Använd 0..9, eller använd Up/Ned, +ipsetup.hint_2 OK sparar, Home avbryter +keybindingmenu.RC Blockera knapprepetering +keybindingmenu.addrecord lägg till inspelningstimer +keybindingmenu.addrecord_head lägg till inspelningstimer +keybindingmenu.addremind lägg till zaptotimer +keybindingmenu.addremind_head lägg till zaptotimer +keybindingmenu.allchannels_on_ok alla-kanaler +keybindingmenu.bouquetchannels_on_ok nuvarande bouquet +keybindingmenu.bouquetdown bouquet tillbaka +keybindingmenu.bouquetdown_head knappkonfig bouquet tillbaka +keybindingmenu.bouquethandling Bouquetkontroll +keybindingmenu.bouquetlist_on_ok bouquetlista +keybindingmenu.bouquetup next bouquet +keybindingmenu.bouquetup_head knappkonfig bouquet framÃ¥t +keybindingmenu.cancel stäng kanallista +keybindingmenu.cancel_head stäng kanallista +keybindingmenu.channeldown kanal ned +keybindingmenu.channeldown_head Knappkonfig kanal ned +keybindingmenu.channellist Kanallista +keybindingmenu.channelup kanal upp +keybindingmenu.channelup_head Knappkonfig kanal upp +keybindingmenu.head Knappkonfiguration +keybindingmenu.lastchannel Snabbzap +keybindingmenu.lastchannel_head Snabbzap +keybindingmenu.modechange Ändra läge +keybindingmenu.pagedown sida ned +keybindingmenu.pagedown_head Knappkonfig sida ned +keybindingmenu.pageup sida upp +keybindingmenu.pageup_head Knappkonfig sida upp +keybindingmenu.quickzap Snabbzap +keybindingmenu.repeatblock upprepningsfördröjning +keybindingmenu.repeatblockgeneric allmän fördröjning +keybindingmenu.sort ändra sortering +keybindingmenu.sort_head ändra sortering +keybindingmenu.subchanneldown underkanal ned +keybindingmenu.subchanneldown_head knapp underkanal ned +keybindingmenu.subchannelup underkanal upp +keybindingmenu.subchannelup_head knapp underkanal upp +keybindingmenu.tvradiomode TV/Radio-läge +keybindingmenu.tvradiomode_head TV/Radio-läge +keybindingmenu.zaphistory Zappningshistoria Bouquet +keybindingmenu.zaphistory_head Zappningshistoria Bouquet +keychooser.head Ange ny nyckel +keychooser.text1 Vänligen tryck den nya knappen +keychooser.text2 vänta ett par sekunder för avbryt +keychoosermenu.currentkey nuvarande knapp +keychoosermenu.setnew ange ny knapp +keychoosermenu.setnone ingen knapp +languagesetup.head SprÃ¥kinställningar +languagesetup.select SprÃ¥k +lcdcontroler.brightness normal ljusstyrka +lcdcontroler.brightnessstandby Ljusstyrka viloläge +lcdcontroler.contrast Kontrast +lcdcontroler.head LCD Inställning +lcdmenu.autodimm Auto dim +lcdmenu.dim_brightness Ljusstyrka efter dim timeout +lcdmenu.dim_time Dim timeout +lcdmenu.head LCD Inställning +lcdmenu.inverse Invertera +lcdmenu.lcdcontroler Kontrast / Ljusstyrka +lcdmenu.power Ström +lcdmenu.statusline statuslinje +lcdmenu.statusline.both volym / speltid +lcdmenu.statusline.playtime speltid +lcdmenu.statusline.volume volym +mainmenu.audioplayer Ljudspelare +mainmenu.games Spel +mainmenu.head Huvudmeny +mainmenu.movieplayer Filmspelare +mainmenu.pausesectionsd Läs EPG +mainmenu.pictureviewer Bildvisare +mainmenu.radiomode Radioläge +mainmenu.reboot Nystart +mainmenu.recording Inspelning +mainmenu.recording_start start +mainmenu.recording_stop stopp +mainmenu.scartmode Scart-läge +mainmenu.scripts Skript +mainmenu.service Service +mainmenu.settings Inställningar +mainmenu.shutdown Avstängning +mainmenu.sleeptimer Sovtimer +mainmenu.tvmode TV-läge +mainsettings.audio Ljud +mainsettings.colors Färger / teman / font +mainsettings.head Inställningar +mainsettings.keybinding Knappkonfiguration +mainsettings.language SprÃ¥k +mainsettings.lcd LCD-skärm +mainsettings.misc Extra inställningar +mainsettings.network Nätverk +mainsettings.recording Inspelning +mainsettings.savesettingsnow spara inställningar nu +mainsettings.savesettingsnow_hint Sparar inställningar,\nvänta... +mainsettings.streaming Filmspelare +mainsettings.video Video +menu.back tillbaka +messagebox.back tillbaka +messagebox.cancel Avbryt +messagebox.discard Kasta ändringar? +messagebox.error Fel +messagebox.info Information +messagebox.no Nej +messagebox.yes Ja +miscsettings.bootinfo Visa info vid start +miscsettings.bootmenu Visa bootmeny +miscsettings.driver_boot drivare och boot optioner +miscsettings.fb_destination Expert! Bootkonsol +miscsettings.general Generellt +miscsettings.head Extra inställningar +miscsettings.hwsections använd hÃ¥rdvarusektioner +miscsettings.infobar_sat_display Satellitinfo pÃ¥ Infobalken +miscsettings.noaviawatchdog aktivera AVIA watchdog +miscsettings.noenxwatchdog aktivera eNX watchdog +miscsettings.pmtupdate aktivera pmt uppdatering +miscsettings.shutdown_count stäng av efter +miscsettings.shutdown_count_hint1 tid (i minuter) för att växla frÃ¥n viloläge +miscsettings.shutdown_count_hint2 till djupt viloläge (0 = av). +miscsettings.shutdown_real Aktivera vilovälge +miscsettings.shutdown_real_rcdelay Fördröjd avstängning +miscsettings.sptsmode använd spts läge +miscsettings.startbhdriver ladda BH-Mode drivare +miscsettings.tuxtxt_cache mellanlagring av TextTV-sidor +motorcontrol.head Motorinstallation +movieplayer.bookmark Bokmärken +movieplayer.bookmarkname Bokmärkesnamn +movieplayer.bookmarkname_hint1 Ange ett namn för ditt nya bokmärke +movieplayer.bookmarkname_hint2 +movieplayer.buffering Buffrar... +movieplayer.defdir start mapp +movieplayer.defplugin Startplugin +movieplayer.dvdplayback DVD +movieplayer.fileplayback Fil via VLC +movieplayer.goto Hoppa till ... +movieplayer.goto.h1 = -> absolut hopp +movieplayer.goto.h2 +,- -> relativt hopp +movieplayer.head Filmspelare +movieplayer.nostreamingserver Streamingservern kan inte nÃ¥s. +movieplayer.pleasewait Var god vänta.\nKopplar upp mot streamingservern... +movieplayer.toomanybookmarks Det finns för mÃ¥nga bokmärken.\nDu mÃ¥ste ta bort en av dom först. +movieplayer.tshelp1 Stopp +movieplayer.tshelp10 ungefär 10 min tillbaks +movieplayer.tshelp11 hoppa ungefär 10 min +movieplayer.tshelp12 Hjälp: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.tshelp2 Välj ljudspÃ¥r +movieplayer.tshelp3 Pause/Fortsätt +movieplayer.tshelp4 Skapa bokmärke +movieplayer.tshelp5 Visa progress +movieplayer.tshelp6 ungefär 1 min tillbaks +movieplayer.tshelp7 hoppa ungefär 1 min +movieplayer.tshelp8 ungefär 5 min tillbaks +movieplayer.tshelp9 hoppa ungefär 5 min +movieplayer.tsplayback Spela TS +movieplayer.tsplayback_pc Spela TS med PIN-lÃ¥s +movieplayer.vcdplayback (S)VCD +movieplayer.vlchelp1 Stopp +movieplayer.vlchelp10 ungefär 10 min tillbaks +movieplayer.vlchelp11 hoppa ungefär 10 min +movieplayer.vlchelp12 Hjälp: http://www.giggo.de/dbox2/movieplayer.html\n +movieplayer.vlchelp2 Resync +movieplayer.vlchelp3 Pause/Fortsätt +movieplayer.vlchelp4 Skapa bokmärke +movieplayer.vlchelp5 Visa progress +movieplayer.vlchelp6 ungefär 1 min tillbaks +movieplayer.vlchelp7 hoppa ungefär 1 min +movieplayer.vlchelp8 ungefär 5 min tillbaks +movieplayer.vlchelp9 hoppa ungefär 5 min +movieplayer.wrongvlcversion Denna funktion finns inte i den nuvarande versionen av VLC +networkmenu.broadcast Broadcast +networkmenu.dhcp DHCP +networkmenu.gateway Default Gateway +networkmenu.head Nätverksinställningar +networkmenu.ipaddress IP-address +networkmenu.mount NFS/CIFS/FTPFS +networkmenu.nameserver DNS server +networkmenu.netmask Subnetmask +networkmenu.setupnow Start/Ã…terstarta nätverk nu +networkmenu.setuponstartup Starta nätverk vid uppstart +networkmenu.show Visa aktiva nätverksinställningar +networkmenu.test Testa nätverket nu +nfs.alreadymounted Mapp redan monterad +nfs.automount Montera vid uppstart +nfs.dir Mapp/Utdelning +nfs.ip Server IP +nfs.localdir Lokal mapp +nfs.mount Montera nätverksvolym +nfs.mount_options Monteringsoptioner +nfs.mounterror Monteringsfel +nfs.mounterror_notsup Filsystemstypen stöds inte +nfs.mountnow Montera nu +nfs.mountok Montering lyckades +nfs.mounttimeout Monteringsfel: timeout +nfs.password Lösenord +nfs.remount Ã…termontera mappar +nfs.type Typ +nfs.type_cifs CIFS +nfs.type_lufs FTPFS +nfs.type_nfs NFS +nfs.umount Avmontera nätverksvolym +nfs.umounterror Fel vid avmontering +nfs.username Användare +nfsmenu.head NFS/CIFS/FTPFS inställning +nvod.percentage (%d%% över) +nvod.starting (startar om %d min) +nvodselector.directormode Direktläge +nvodselector.head Välj starttid +nvodselector.subservice Välj underprogram +options.default Ã…terställ inställningar +options.fb framebuffer +options.null noll +options.off av +options.on pÃ¥ +options.on.without_messages (tyst) pÃ¥ +options.serial seriell +parentallock.changepin ändra PIN-kod +parentallock.changepin_hint1 Ange PIN-kod för förädralÃ¥set! +parentallock.changetolocked är lÃ¥sta bouquets +parentallock.head Ange PIN-kod för förädralÃ¥s +parentallock.lockage lÃ¥s kanal +parentallock.lockage12 frÃ¥n 12 Ã¥r uppÃ¥t +parentallock.lockage16 frÃ¥n 16 Ã¥r uppÃ¥t +parentallock.lockage18 frÃ¥n 18 Ã¥r uppÃ¥t +parentallock.lockedchannel LÃ¥st sändare... +parentallock.lockedprogram LÃ¥st program (frÃ¥n %d Ã¥r och uppÃ¥t) +parentallock.never aldrig +parentallock.onsignal pÃ¥ broadcastat lÃ¥s +parentallock.parentallock FöräldralÃ¥s +parentallock.prompt frÃ¥ga efter PIN-kod +pictureviewer.decode_server_ip dekoda server ip +pictureviewer.decode_server_port dekoda server port +pictureviewer.defdir start mapp +pictureviewer.head Bildvisare +pictureviewer.help1 menyläge +pictureviewer.help10 visningsläge +pictureviewer.help11 läs in bild igen +pictureviewer.help12 föregÃ¥ende bild +pictureviewer.help13 nästa bild +pictureviewer.help14 Zoom ut +pictureviewer.help15 Zoom in +pictureviewer.help16 skrolla upp +pictureviewer.help17 skrolla vänster +pictureviewer.help18 skrolla höger +pictureviewer.help19 skrolla ned +pictureviewer.help2 visa bild +pictureviewer.help20 ändra sortering +pictureviewer.help21 läs in bild igen (ingen skalning) +pictureviewer.help22 avsluta +pictureviewer.help3 ändra sortering +pictureviewer.help4 skala inte bild +pictureviewer.help5 diavisningläge +pictureviewer.help6 föregÃ¥ende bild +pictureviewer.help7 nästa bild +pictureviewer.help8 ändra sortering +pictureviewer.help9 avsluta +pictureviewer.resize.color_average avancerad +pictureviewer.resize.none ingen +pictureviewer.resize.simple enkel +pictureviewer.scaling skalning +pictureviewer.show visa +pictureviewer.slide_time slideshow visningstid +pictureviewer.slideshow slideshow +pictureviewer.sortorder ändra sortering +pictureviewer.sortorder.date (datum) +pictureviewer.sortorder.filename (filnamn) +ping.ok är nÃ¥bar (ping) +ping.protocol är inte nÃ¥bar (host eller protokollfel) +ping.socket är inte nÃ¥bar (socketfel) +ping.unreachable är inte nÃ¥bar +pinprotection.head Ange PIN-kod +pinprotection.wrongcode Felaktig PIN-kod! Försök igen. +plugins.result plugin utskrift +rclock.lockmsg Din DBOX2 fjärrkontroll kommer att lÃ¥sas.\nFör att lÃ¥sa upp den, tryck \noch pÃ¥ din fjärrkontroll. +rclock.menueadd LÃ¥s FK +rclock.title LÃ¥s fjärrkontroll +rclock.unlockmsg Fjärrkontroll aktiverad. +recordingmenu.apids Förinställning för tonspÃ¥r +recordingmenu.apids_ac3 Spela in AC3 tonspÃ¥r +recordingmenu.apids_alt Spela in alternativt tonspÃ¥r +recordingmenu.apids_std Spela in standard tonspÃ¥r +recordingmenu.choose_direct_rec_dir välj mapp vid direkt inspel. +recordingmenu.defdir inspelningsmapp +recordingmenu.dir_permissions Mapprättigheter +recordingmenu.dir_permissions_hint Rättigheter i 'chmod'-stil +recordingmenu.epg_for_filename lÃ¥nga filnamn (med EPG data) +recordingmenu.file direkt (fil) +recordingmenu.filename_template Schablon för filnamn +recordingmenu.filename_template_hint %c=Kanal, %i=Titel, %d=Datum, %t=Tid +recordingmenu.filesettings direktinspelning inställning +recordingmenu.head Inspelningsinställningar +recordingmenu.help Inspelningsenheter:\n--------------------------\nserver:\nmed en streaming programvara pÃ¥ en PC\n\n(analog) vcr:\nmed ett VCR uttag\n\ndirekt (fil):\ndirekt till en NFS-monterad mapp\neller till en intern hÃ¥rddisk\nTS: använd spts-läge\nPES: använd inte spts-läget\n\n\nMax. filstorlek:\n---------------------\nNFS V2: 2 GB (2048 MB)\nNFS V3: sÃ¥ stor hÃ¥rddisken är (0 MB)\nFAT: 2 GB (2048 MB)\nFAT32: 4 GB (4096 MB) +recordingmenu.no_scart växla inte till SCART-läge +recordingmenu.off av +recordingmenu.record_in_spts_mode växla till spts-läge före inspelning +recordingmenu.recording_type inspelningsenhet +recordingmenu.ringbuffers antal ringbuffrar +recordingmenu.server server +recordingmenu.server_ip inspelningsserver IP +recordingmenu.server_mac MAC address +recordingmenu.server_port inspelningsserver port +recordingmenu.server_wakeup inspelningsserver WoL +recordingmenu.setupnow aktivera ändringar +recordingmenu.splitsize Max. filstorlek (MB) +recordingmenu.stopplayback stoppa avspelning +recordingmenu.stopsectionsd stoppa sectionsd +recordingmenu.stream_pmt_pid spela in PMT +recordingmenu.stream_vtxt_pid spela in TextTV +recordingmenu.use_fdatasync skriv synkront (fdatasync) +recordingmenu.use_o_sync skriv synkront (O_SYNC) +recordingmenu.vcr vcr +recordingmenu.zap_on_announce Slä om vid meddelande +recordtimer.announce Inspelning startar om nÃ¥gra minuter +repeatblocker.hint_1 Kortast tid (i ms) att registrera 2 knapptryck +repeatblocker.hint_2 Tryck 0 för att stänga av blockeraren (röd är mellanslag) +satsetup.diseqc DiSEqC +satsetup.diseqc10 DiSEqC 1.0 +satsetup.diseqc11 DiSEqC 1.1 +satsetup.diseqc12 DiSEqC 1.2 +satsetup.diseqcrepeat DiSEqC-upprepningar +satsetup.extended DiSEqC-inställningar +satsetup.extended_motor Motorinställningar +satsetup.minidiseqc Mini-DiSEqC +satsetup.motorcontrol Manuell Motorinställning +satsetup.nodiseqc ingen DiSEqC +satsetup.satellite Satellit +satsetup.savesettingsnow spara inställningar nu +satsetup.smatvremote SMATV Fjärrtuning +scantp.fec FEC +scantp.fec_1_2 1/2 +scantp.fec_2_3 2/3 +scantp.fec_3_4 3/4 +scantp.fec_5_6 5/6 +scantp.fec_7_8 7/8 +scantp.freq Frekvens +scantp.pol Polarisation +scantp.pol_h H +scantp.pol_v V +scantp.rate Symbolhastighet +scantp.scan Manuell sökning +scantp.scanmode Snabbsökning +scants.abort_body Ska sökningen verkligen avbrytas? +scants.abort_header Avbrytning av kanalsök +scants.actcable Kabel: +scants.actsatellite Satellit: +scants.bouquet Bouquet +scants.bouquet_create skapa ny +scants.bouquet_erase radera alla +scants.bouquet_leave lämna nuvarande +scants.bouquet_satellite Satellit-Bouquet +scants.bouquet_update uppdatera +scants.channel Kanal: +scants.failed Transpondersökning misslyckades! +scants.finished Transpondersökning genomförd! +scants.freqdata Frekvens: +scants.head Sök transponder +scants.numberofdataservices Data +scants.numberofradioservices Radio +scants.numberoftotalservices Total +scants.numberoftvservices TV +scants.provider Operatör: +scants.startnow starta sökning +scants.transponders Transpondrar: +screensetup.lowerright grön = inställning nedre höger +screensetup.upperleft röd = inställning övre vänster +sectionsd.scanmode sektionsscan +servicemenu.getplugins Läs in plugins +servicemenu.getplugins_hint Läser in plugins,\nvar god vänta. +servicemenu.head Service +servicemenu.imageinfo Bildinformation +servicemenu.reload Läs in kanallistor +servicemenu.reload_hint Läser in kanallistor,\nvar god vänta. +servicemenu.restart Starta om Neutrino +servicemenu.restart_failed Fel vid omstart av Neutrino. +servicemenu.restart_hint Startar om Neutrino... +servicemenu.restart_refused_recording Inspelning görs. Omstart inte möjlig. +servicemenu.scants Programsökning +servicemenu.ucodecheck Kontrollera ucodes +servicemenu.update Mjukvaruuppdatering +settings.help Hjälp +settings.missingoptionsconffile Neutrinoinställningarna har uppdaterats.\nNya inställningar kommer att sättas till default. +settings.noconffile Inga Neutrino-inställningar hittades.\nAnvänder default. +settings.pos_bottom_left vänster botten +settings.pos_bottom_right höger botten +settings.pos_top_left vänster topp +settings.pos_top_right höger topp +shutdown.recoding_query dBox spelar in just nu. Verkligen stänga av? +shutdowntimer.announce Box kommer att stängas av om 1 min.\nAvbryt avstängning? +sleeptimerbox.announce Sovtimer om 1 min +sleeptimerbox.hint1 Avstängningstid i min. (000=av) +sleeptimerbox.hint2 Din dbox2 kommer att stängas av efter denna tid. +sleeptimerbox.title Sovtimer +streamfeatures.head Funktioner: +streaminfo.aratio TV-format +streaminfo.aratio_unknown TV-format: okänt +streaminfo.audiotype Ljudtyp +streaminfo.audiotype_unknown Ljudtyp: okänt +streaminfo.bitrate Bitrate +streaminfo.framerate Framerate +streaminfo.framerate_unknown Framerate: okänt +streaminfo.head Stream-Information +streaminfo.not_available inte tillgänglig +streaminfo.resolution Upplösning +streaminfo.signal mottagningssignal +streaming.buffer_overflow Inspelning avbröts eftersom\ndata inte kunde skrivas tillräckligt snabbt. +streaming.busy En eller flera inspelningsprocesser är aktiva.\nOm du ser detta meddelande och inga inspelningar är aktiva, starta om Neutrino. +streaming.dir_not_writable Inspelningsmappen är inte skrivbar.\nInspelningar kommer inte att fungera. +streaming.success Inspelningen gick bra. +streaming.write_error Inspelningen avbröts,\neftersom ett fel inträffade under skrivning. +streaming.write_error_open Inspelningen avbröts,\nför att mÃ¥lfilen inte kunde öppnas. +streamingmenu.352x288 352x288 +streamingmenu.352x576 352x576 +streamingmenu.480x576 480x576 +streamingmenu.704x576 704x576 +streamingmenu.head Filmspelare inställningar +streamingmenu.mpeg1 MPEG1 +streamingmenu.mpeg2 MPEG2 +streamingmenu.off Av +streamingmenu.on PÃ¥ +streamingmenu.server_ip Streamingserver IP +streamingmenu.server_port Streamingserver Port +streamingmenu.streaming_audiorate Datarate Ljud +streamingmenu.streaming_force_avi_rawaudio Tvinga AC3 för AVI +streamingmenu.streaming_force_transcode_video Transcode MPG/VCD video +streamingmenu.streaming_resolution Upplösning +streamingmenu.streaming_server_cddrive DVD-enhet +streamingmenu.streaming_server_startdir Mapp (VLC) +streamingmenu.streaming_transcode_audio Transcode audio (DVD/VCD/MPG) +streamingmenu.streaming_transcode_video_codec MPEG video codec +streamingmenu.streaming_type Streamingserver +streamingmenu.streaming_videorate Datarate Video +streamingserver.noconnect Ingen anslutning till streamingserver.\nInspelning avbruten. +stringinput.caps caps / inga caps +stringinput.clear rensa alla +timer.eventrecord.msg ... FÖR att GÖRAS, eller inte göras +timer.eventrecord.title Schemalägg inspelning +timer.eventtimed.msg Händelsen är schemalagd.\nDin dbox2 kommer att startas och\nbyta till denna kanal pÃ¥ angiven tid. +timer.eventtimed.title Schemalägg händelse +timerbar.channelswitch Schema +timerbar.recordevent Spela in +timerlist.alarmtime Alarmtid +timerlist.apids Ljud PIDs +timerlist.apids_dflt spela in förinstÖllt tonspÃ¥r +timerlist.bouquetselect välj bouquet +timerlist.channel Kanal +timerlist.channelselect välj kanal +timerlist.delete Radera +timerlist.menumodify Ändra timer +timerlist.menunew Ny timer +timerlist.message Meddelande +timerlist.moderadio Radiokanaler +timerlist.modeselect Lägesval +timerlist.modetv TV kanaler +timerlist.modify Modifiera +timerlist.name Timerlista +timerlist.new Ny timer +timerlist.overlapping_timer Timer konflikt. Skapa timern ändÃ¥? +timerlist.plugin Plugin +timerlist.program.unknown Program okänt +timerlist.recording_dir inspelningsmapp +timerlist.reload Läs om +timerlist.repeat Upprepa +timerlist.repeat.biweekly veckomässigt +timerlist.repeat.byeventdescription se timer +timerlist.repeat.daily dagligen +timerlist.repeat.fourweekly var fjärde vecka +timerlist.repeat.friday Fr +timerlist.repeat.monday MÃ¥ +timerlist.repeat.monthly mÃ¥ntlig +timerlist.repeat.once en gÃ¥ng +timerlist.repeat.saturday Lö +timerlist.repeat.sunday Sö +timerlist.repeat.thursday To +timerlist.repeat.tuesday Ti +timerlist.repeat.unknown okänd +timerlist.repeat.wednesday On +timerlist.repeat.weekdays pÃ¥ vardagar +timerlist.repeat.weekly veckomässigt +timerlist.repeatcount upprepningar +timerlist.repeatcount.help1 antal timerupprepningar +timerlist.repeatcount.help2 0 för oändliga upprepningar +timerlist.save Spara timer +timerlist.standby SB läge +timerlist.standby.off Lämna viloläge +timerlist.standby.on GÃ¥ in i viloläge +timerlist.stoptime Stopptid +timerlist.type Timertyp +timerlist.type.execplugin Starta plugin +timerlist.type.nextprogram Nästa program +timerlist.type.record Spela in +timerlist.type.remind PÃ¥minnelse +timerlist.type.shutdown Stäng av +timerlist.type.sleeptimer Sovtimer +timerlist.type.standby Viloläge +timerlist.type.unknown Okänt +timerlist.type.zapto Zappa till +timerlist.weekdays Dagar i veckan +timerlist.weekdays.hint_1 MÃ¥ Ti On To Fr Lö Sö +timerlist.weekdays.hint_2 'X'=timer '-' ingen timer +timersettings.record_safety_time_after Justera stopptid för inspelning +timersettings.record_safety_time_after.hint_1 Justeringstid i min. (00=av). Denna tid +timersettings.record_safety_time_after.hint_2 kommer att läggas pÃ¥ stopptiden för varje inspelningstimer. +timersettings.record_safety_time_before Justering av starttid för inspelning +timersettings.record_safety_time_before.hint_1 Justeringstid i min. (00=av). Denna tid +timersettings.record_safety_time_before.hint_2 kommer att dras av för varje inspelningstimer. +timersettings.separator Timerinställningar +timing.chanlist Kanallista +timing.epg Epg +timing.filebrowser Filväljaren +timing.head OSD Timeouter +timing.hint_1 Tid i sek. Efter denna tid kommer +timing.hint_2 Infobalken att försvinna sakta. +timing.infobar Infobalk +timing.infobar_radio Infobalk/Radio +timing.menu Meny +timing.numericzap Numerisk Zap +ucodecheck.avia500 Avia 500 +ucodecheck.avia600 Avia 600 +ucodecheck.cam-alpha Cam-Alpha +ucodecheck.head UCode kontroll +ucodecheck.ucode UCode +ucodes.failure VARNING, µkoder kunde INTE hittas!\n\nVänligen ladda upp dom via FTP (eller Dbox-BootManager),\nstarta sedan om din DBox! +videomenu.csync sync justering +videomenu.head Videoinställningar +videomenu.rgb_centering RGB centrering +videomenu.screensetup Skärminställning +videomenu.vcrswitch Växla SCART automatiskt +videomenu.videoformat Format +videomenu.videoformat_169 16:9 +videomenu.videoformat_43 4:3 (LB) +videomenu.videoformat_431 4:3 (PS) +videomenu.videoformat_autodetect autodetektera +videomenu.videosignal VideoutgÃ¥ng +videomenu.videosignal_composite CVBS +videomenu.videosignal_rgb RGB + CVBS +videomenu.videosignal_svideo S-Video +videomenu.videosignal_yuv_c YUV + CVBS +videomenu.videosignal_yuv_v YUV + VBS +zapit.scantype sök efter program +zapit.scantype.all alla program +zapit.scantype.radio bara radio +zapit.scantype.tv bara tv +zapit.scantype.tvradio tv & radio +zaptotimer.announce Zaptotimer om en minut diff --git a/doc/ir.html b/doc/ir.html new file mode 100644 index 000000000..bf986f3e2 --- /dev/null +++ b/doc/ir.html @@ -0,0 +1,74 @@ + + + + Neutrino Timer Doku + + + +
+

Neutrino LIRC Unterstützung

+
+Konfiguration des lirc siehe + +http://www.dbox2.info/doku/lirc/lirc_doku.html

+Syntax der Lirc-Kommando Dateien:
+Es können in einer Kommando-Datei beliebig viele Befehle der Form
+

<device> <command> (<duration>)
+vorkommen.

+<device> = Name der Fernbedienung in der lirc.conf Datei
+<command> = Name der Taste einer Fernbedienung in lirc.conf
+<duration> = Dauer, die das Signal gesendet werden soll, in ms (optional). +Wenn nicht angegeben wird das Signal genau ein mal gesendet. +Werte zwischen 50ms und 500ms sind ein guter Anfang
+

+Folgende Neutrino-Aktionen können zusätzlich zum VCR Support mit IR-Signalen +versehen werden:
+(ist die entsprechende Kommando-Datei vorhanden, werden die Kommandos gesendet, +existiert die Datei nicht, passiert nichts.) +

+Sleeptimer:
+Wenn der Sleeptimer die Box in den Standby bzw. Deep-Standby schickt, +werden die Lirc-Kommandos in der Datei sleep.lirc ausgeführt. +Dies dient zur Abschaltung des TVs / Verstärkers/...
+Bsp. /var/tuxbox/config/lirc/sleep.lirc: +

+tv power 500
+amplifier power 500
+
+Standby on/off:
+Wir die Box in den standby geschickt (egal, ob per Fernbedienung, timer, +web,...) so wird die Kommando-Datei sbon.lirc ausgeführt. Wacht sie +aus dem Standby auf wird die Kommando-Datei sboff.lirc ausgeführt.
+Achtung , bei Deep-Standby funktioniert nur sbon.lirc !
+Bsp. /var/tuxbox/config/lirc/sbon.lirc: +
+tv power 500
+amplifier power 500
+
+Bsp. /var/tuxbox/config/lirc/sboff.lirc: +
+tv 1 250
+tv av 250
+amplifier power 500
+
+Volume +/-:
+Bei erhöhen der Lautstärke wird die Kommando-Datei volplus.lirc bei +erniedrigen der Lautstärke volminus ausgeführt. Dies ist für Leute +interessant, die Audio nicht über den Fernseher, sondern digital über einen +Verstärker abspielen. Hier kann jetzt auch über die DBox-Fernbedienung die +Lautstärke verändert werden.
+Dabei ist zu beachten, dass die Dauer, die die Kommados gesendet werden, +relativ kurz sein sollte, da sonst der Neutrino-Programmablauf sehr +unflüssig wirkt. Ich arbeite hier mit Werten zwischen 50 und 100 ms.
+Bsp. /var/tuxbox/config/lirc/volplus.lirc: +
+amplifier vol_inc 60
+
+Bsp. /var/tuxbox/config/lirc/volminus.lirc: +
+amplifier vol_dec 60
+
+ + + diff --git a/doc/picviewer.html b/doc/picviewer.html new file mode 100644 index 000000000..0e5767b3a --- /dev/null +++ b/doc/picviewer.html @@ -0,0 +1,39 @@ + + + + Neutrino Pictureviewer Doku + + + +
+

Neutrino Pictureviewer

+
+Tasten im Menü-Modus:
+siehe Beschriftung...
+OK-Taste zeigt ein Bild an.
+0: Bild in voller Grösse unskaliert einlesen (kann lange dauern...)
+

+Tasten im Diashow-Modus:
+Pfeil links : Bild zurück
+Pfeil rechts : Bild weiter
+Home: Diashow-Modus verlassen(kann etwas dauern...)
+

+Tasten im Anzeige-Modus:
+Pfeil links : Bild zurück
+Pfeil rechts : Bild weiter
+Home: Anzeige-Modus verlassen
+1: Zoom out
+3: Zoom in
+2,4,6,8: Scroll hoch,links,rechts,runter
+0: Bild in voller Grösse unskaliert einlesen (kann lange dauern...)
+OK: Bild neu einlesen +

+Anmerkung zum Zoomen:
+Beim Zoomen von Bildern stösst die Dbox sehr schnell an ihre Speichergrenzen, +da unkomprimierte Bilder sehr viel Speicher benötigen, die Dbox aber nicht +gerade üppig mit selbigem ausgestattet ist. Sollte im Anzeigemodus +nicht mehr gescrollt oder gezoomt werden können, so ist der Speicher voll. +In diesem Falle entweder zum nächsten Bild schalten (Pfeil rechts) oder den +Anzeigemodus beenden (home). + diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 000000000..a0fc874fb --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,13 @@ +SUBDIRS = \ + connection \ + libeventserver \ + controldclient \ + sectionsdclient \ + timerdclient \ + libconfigfile \ + libmd5sum \ + libnet \ + xmltree \ + libtuxtxt \ + libdvbsub \ + libupnpclient diff --git a/lib/connection/Makefile.am b/lib/connection/Makefile.am new file mode 100644 index 000000000..cd4b786d6 --- /dev/null +++ b/lib/connection/Makefile.am @@ -0,0 +1,5 @@ +noinst_LIBRARIES = libtuxbox-connection.a + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +libtuxbox_connection_a_SOURCES = basicclient.cpp basicserver.cpp basicsocket.cpp messagetools.cpp diff --git a/lib/connection/basicclient.cpp b/lib/connection/basicclient.cpp new file mode 100644 index 000000000..cbccbff84 --- /dev/null +++ b/lib/connection/basicclient.cpp @@ -0,0 +1,164 @@ +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libconnection/basicclient.cpp,v 1.17 2004/04/08 07:19:00 thegoodguy Exp $ + * + * Basic Client Class - The Tuxbox Project + * + * (C) 2002-2003 by thegoodguy + * + * License: GPL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "basicclient.h" +#include "basicmessage.h" +#include "basicsocket.h" + +#include +#include +#include +#include +#include + +#define TIMEOUT_SEC 60 +#define TIMEOUT_USEC 0 +#define MAX_TIMEOUT_SEC 300 +#define MAX_TIMEOUT_USEC 0 + +CBasicClient::CBasicClient() +{ + sock_fd = -1; +} + +bool CBasicClient::open_connection() +{ + close_connection(); + + struct sockaddr_un servaddr; + int clilen; + + memset(&servaddr, 0, sizeof(struct sockaddr_un)); + servaddr.sun_family = AF_UNIX; + strcpy(servaddr.sun_path, getSocketName()); // no length check !!! + clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path); + + if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + printf("[CBasicClient] socket failed.\n"); + perror(getSocketName()); + sock_fd = -1; + return false; + } + + if (connect(sock_fd, (struct sockaddr*) &servaddr, clilen) < 0) + { + printf("[CBasicClient] connect failed.\n"); + perror(getSocketName()); + close_connection(); + return false; + } + return true; +} + +void CBasicClient::close_connection() +{ + if (sock_fd != -1) + { + close(sock_fd); + sock_fd = -1; + } +} + +bool CBasicClient::send_data(const char* data, const size_t size) +{ + timeval timeout; + + if (sock_fd == -1) + return false; + + timeout.tv_sec = TIMEOUT_SEC; + timeout.tv_usec = TIMEOUT_USEC; + + if (::send_data(sock_fd, data, size, timeout) == false) + { + printf("[CBasicClient] send failed: %s\n", getSocketName()); + close_connection(); + return false; + } + return true; +} + +bool CBasicClient::send_string(const char* data) +{ + uint8_t send_length; + size_t length = strlen(data); + if (length > 255) + { + printf("[CBasicClient] string too long - sending only first 255 characters: %s\n", data); + send_length = 255; + } + else + { + send_length = length; + } + return (send_data((char *)&send_length, sizeof(send_length)) && + send_data(data, send_length)); +} + +bool CBasicClient::receive_data(char* data, const size_t size, bool use_max_timeout) +{ + timeval timeout; + + if (sock_fd == -1) + return false; + + if (use_max_timeout) + { + timeout.tv_sec = MAX_TIMEOUT_SEC; + timeout.tv_usec = MAX_TIMEOUT_USEC; + } + else + { + timeout.tv_sec = TIMEOUT_SEC; + timeout.tv_usec = TIMEOUT_USEC; + } + + if (::receive_data(sock_fd, data, size, timeout) == false) + { + printf("[CBasicClient] receive failed: %s\n", getSocketName()); + close_connection(); + return false; + } + return true; +} + +bool CBasicClient::send(const unsigned char command, const char* data, const unsigned int size) +{ + CBasicMessage::Header msgHead; + msgHead.version = getVersion(); + msgHead.cmd = command; + + open_connection(); // if the return value is false, the next send_data call will return false, too + + if (!send_data((char*)&msgHead, sizeof(msgHead))) + return false; + + if (size != 0) + return send_data(data, size); + + return true; +} + diff --git a/lib/connection/basicclient.h b/lib/connection/basicclient.h new file mode 100644 index 000000000..7b82de108 --- /dev/null +++ b/lib/connection/basicclient.h @@ -0,0 +1,51 @@ +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libconnection/basicclient.h,v 1.7 2004/04/08 07:19:00 thegoodguy Exp $ + * + * Basic Client Class - The Tuxbox Project + * + * (C) 2002-2003 by thegoodguy + * + * License: GPL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __basicclient__ +#define __basicclient__ + +#include +#include + +class CBasicClient +{ + private: + int sock_fd; + + protected: + virtual const unsigned char getVersion () const = 0; + virtual const char * getSocketName() const = 0; + + bool open_connection(); + bool send_data(const char * data, const size_t size); + bool send_string(const char * data); + bool receive_data(char* data, const size_t size, bool use_max_timeout = false); + bool send(const unsigned char command, const char* data = NULL, const unsigned int size = 0); + void close_connection(); + + CBasicClient(); +}; + +#endif diff --git a/lib/connection/basicmessage.h b/lib/connection/basicmessage.h new file mode 100644 index 000000000..ab3228731 --- /dev/null +++ b/lib/connection/basicmessage.h @@ -0,0 +1,43 @@ +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libconnection/basicmessage.h,v 1.2 2002/10/18 11:56:56 thegoodguy Exp $ + * + * types used for clientlib <-> daemon communication - d-box2 linux project + * + * (C) 2002 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __basicmessage_h__ +#define __basicmessage_h__ + + +class CBasicMessage +{ + public: + + typedef unsigned char t_version; + typedef unsigned char t_cmd; + + struct Header + { + t_version version; + t_cmd cmd; + }; +}; + + +#endif /* __basicmessage_h__ */ diff --git a/lib/connection/basicserver.cpp b/lib/connection/basicserver.cpp new file mode 100644 index 000000000..9156c1514 --- /dev/null +++ b/lib/connection/basicserver.cpp @@ -0,0 +1,172 @@ +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libconnection/basicserver.cpp,v 1.11 2004/04/08 08:00:55 thegoodguy Exp $ + * + * Basic Server Class Class - The Tuxbox Project + * + * (C) 2002 - 2003 by thegoodguy + * + * License: GPL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "basicserver.h" +#include "basicsocket.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define RECEIVE_TIMEOUT_IN_SECONDS 60 +#define SEND_TIMEOUT_IN_SECONDS 60 + +bool CBasicServer::receive_data(int fd, void * data, const size_t size) +{ + timeval timeout; + timeout.tv_sec = RECEIVE_TIMEOUT_IN_SECONDS; + timeout.tv_usec = 0; + return ::receive_data(fd, data, size, timeout); +} + +bool CBasicServer::send_data(int fd, const void * data, const size_t size) +{ + timeval timeout; + timeout.tv_sec = SEND_TIMEOUT_IN_SECONDS; + timeout.tv_usec = 0; + return ::send_data(fd, data, size, timeout); +} + +void CBasicServer::delete_string(char * data) +{ + free((void *)data); +} + +char * CBasicServer::receive_string(int fd) +{ + uint8_t length; + + if (receive_data(fd, &length, sizeof(length))) + { + char * data = (char *)malloc(((size_t)length) + 1); + if (receive_data(fd, data, length)) + { + data[length] = 0; /* add terminating 0 */ + return data; + } + else + { + delete_string(data); + return NULL; + } + } + return NULL; +} + +bool CBasicServer::prepare(const char* socketname) +{ + struct sockaddr_un servaddr; + int clilen; + + memset(&servaddr, 0, sizeof(struct sockaddr_un)); + servaddr.sun_family = AF_UNIX; + strcpy(servaddr.sun_path, socketname); + clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path); + + unlink(socketname); + + if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + printf("[CBasicServer] socket failed.\n"); + perror(socketname); + return false; + } + if (bind(sock_fd, (struct sockaddr*) &servaddr, clilen) < 0) + { + printf("[CBasicServer] bind failed.\n"); + perror(socketname); + return false; + } + +#define N_connection_requests_queued 5 + + if (listen(sock_fd, N_connection_requests_queued) != 0) + { + printf("[CBasicServer] listen failed.\n"); + perror(socketname); + return false; + } + + name = socketname; + + return true; +} + +bool CBasicServer::parse(bool (parse_command)(CBasicMessage::Header &rmsg, int connfd), const CBasicMessage::t_version version) +{ + int conn_fd; + struct sockaddr_un servaddr; + int clilen = sizeof(servaddr); + bool parse_another_command = true; + + CBasicMessage::Header rmsg; + conn_fd = accept(sock_fd, (struct sockaddr*) &servaddr, (socklen_t*) &clilen); + memset(&rmsg, 0, sizeof(rmsg)); + read(conn_fd, &rmsg, sizeof(rmsg)); + + if (rmsg.version == version) + parse_another_command = parse_command(rmsg, conn_fd); + else + printf("[%s] Command ignored: cmd version %d received - server cmd version is %d\n", name.c_str(), rmsg.version, version); + + close(conn_fd); + + return parse_another_command; +} + +bool CBasicServer::run(bool (parse_command)(CBasicMessage::Header &rmsg, int connfd), const CBasicMessage::t_version version, bool non_blocking) +{ + if (non_blocking) { + struct pollfd pfd; + + pfd.fd = sock_fd; + pfd.events = (POLLIN | POLLPRI); + + if (poll(&pfd, 1, 0) > 0) + return parse(parse_command, version); + else + return true; + } + else { + while(parse(parse_command, version)); + + stop(); + + return false; + } +} + +void CBasicServer::stop(void) +{ + close(sock_fd); + unlink(name.c_str()); +} + diff --git a/lib/connection/basicserver.h b/lib/connection/basicserver.h new file mode 100644 index 000000000..848ab9857 --- /dev/null +++ b/lib/connection/basicserver.h @@ -0,0 +1,60 @@ +#ifndef __basicserver__ +#define __basicserver__ + +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libconnection/basicserver.h,v 1.7 2004/04/08 07:19:00 thegoodguy Exp $ + * + * Basic Server Class Class - The Tuxbox Project + * + * (C) 2002 - 2003 by thegoodguy + * + * License: GPL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +#include "basicmessage.h" + +class CBasicServer +{ + private: + int sock_fd; + std::string name; + + // used by run + bool parse(bool (parse_command)(CBasicMessage::Header &rmsg, int connfd), const CBasicMessage::t_version version); + + public: + static bool receive_data (int fd, void * data, const size_t size); + static bool send_data (int fd, const void * data, const size_t size); + static char * receive_string(int fd); + static void delete_string (char * data); + + bool prepare(const char* socketname); + + // run the server socket + // if set to non-blocking, it will leave the socket open but + // will return immediately without parsing a command if no data + // is sent by a client + bool run(bool (parse_command)(CBasicMessage::Header &rmsg, int connfd), const CBasicMessage::t_version version, bool non_blocking = false); + + // manual stop, can and should only be used in non-blocking mode + void stop(void); +}; + +#endif diff --git a/lib/connection/basicsocket.cpp b/lib/connection/basicsocket.cpp new file mode 100644 index 000000000..3ae8fd889 --- /dev/null +++ b/lib/connection/basicsocket.cpp @@ -0,0 +1,140 @@ +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libconnection/basicsocket.cpp,v 1.2 2003/02/24 21:14:15 thegoodguy Exp $ + * + * Basic Socket Class - The Tuxbox Project + * + * (C) 2003 by thegoodguy + * + * License: GPL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "basicsocket.h" + +#include +#include +#include +#include +#include + +bool send_data(int fd, const void * data, const size_t size, const timeval timeout) +{ + fd_set writefds; + timeval tv; + const void * buffer; + size_t n; + int rc; + + n = size; + + while (n > 0) + { + buffer = (void *)((char *)data + (size - n)); + rc = ::send(fd, buffer, n, MSG_DONTWAIT | MSG_NOSIGNAL); + + if (rc == -1) + { + perror("[basicsocket] send_data"); +char * buf = (char *) data; +printf("send_data: errno %d data %X\n", errno, buf[0]); + //if (errno == EPIPE) + if (errno == EPIPE || errno == ESPIPE) + return false; + + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + + tv = timeout; + + rc = select(fd + 1, NULL, &writefds, NULL, &tv); + + if (rc == 0) + { + printf("[basicsocket] send timed out.\n"); + return false; + } + if (rc == -1) + { + perror("[basicsocket] send_data select"); + return false; + } + } + else + n -= rc; + } + return true; +} + + +bool receive_data(int fd, void * data, const size_t size, const timeval timeout) +{ + fd_set readfds; + timeval tv; + void * buffer; + size_t n; + int rc; + + n = size; + + while (n > 0) + { + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + tv = timeout; + + rc = select(fd + 1, &readfds, NULL, NULL, &tv); + + if (rc == 0) + { + printf("[basicsocket] receive timed out.\n"); + return false; + } + if (rc == -1) + { + perror("[basicsocket] receive_data select"); + return false; + } + buffer = (void *)((char *)data + (size - n)); + rc = ::recv(fd, buffer, n, MSG_DONTWAIT | MSG_NOSIGNAL); + + if ((rc == 0) || (rc == -1)) + { + if (rc == -1) + { + perror("[basicsocket] receive_data"); + + //if (errno == EPIPE) + if (errno == EPIPE || errno == ESPIPE) + return false; + } + else + { + /* + * silently return false + * + * printf("[basicsocket] no more data\n"); + */ + return false; + } + + } + else + n -= rc; + } + return true; +} diff --git a/lib/connection/basicsocket.h b/lib/connection/basicsocket.h new file mode 100644 index 000000000..f236d3d71 --- /dev/null +++ b/lib/connection/basicsocket.h @@ -0,0 +1,35 @@ +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libconnection/basicsocket.h,v 1.2 2003/02/24 21:14:15 thegoodguy Exp $ + * + * Basic Socket Class - The Tuxbox Project + * + * (C) 2003 by thegoodguy + * + * License: GPL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __basicsocket__ +#define __basicsocket__ + +#include +#include + +bool send_data(int fd, const void * data, const size_t size, const timeval timeout); +bool receive_data(int fd, void * data, const size_t size, const timeval timeout); + +#endif diff --git a/lib/connection/messagetools.cpp b/lib/connection/messagetools.cpp new file mode 100644 index 000000000..cf140aa71 --- /dev/null +++ b/lib/connection/messagetools.cpp @@ -0,0 +1,96 @@ +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libconnection/messagetools.cpp,v 1.1 2002/12/07 13:37:06 thegoodguy Exp $ + * + * tools used in clientlib <-> daemon communication - d-box2 linux project + * + * (C) 2002 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "messagetools.h" + +size_t write_length_field (unsigned char * buffer, unsigned int length) +{ + if (length < 128) + { + buffer[0] = length; + return 1; + } + else + { + unsigned int pos = 0; + unsigned int shiftby = 8; + unsigned char length_field_size = 1; + + while ((length >> shiftby) != 0) + { + length_field_size++; + shiftby += 8; + } + + buffer[pos++] = ((1 << 7) | length_field_size); + + while (shiftby != 0) + { + shiftby -= 8; + buffer[pos++] = length >> shiftby; + } + return pos; + } + +} + +unsigned int parse_length_field (const unsigned char * buffer) +{ + unsigned char size_indicator = (buffer[0] >> 7) & 0x01; + unsigned int length_value = 0; + + if (size_indicator == 0) + { + length_value = buffer[0] & 0x7F; + } + + else if (size_indicator == 1) + { + unsigned char length_field_size = buffer[0] & 0x7F; + unsigned int i; + + for (i = 0; i < length_field_size; i++) + { + length_value = (length_value << 8) | buffer[i + 1]; + } + } + + return length_value; +} + +size_t get_length_field_size (const unsigned int length) +{ + if (length < 0x80) + return 0x01; + + if (length < 0x100) + return 0x02; + + if (length < 0x10000) + return 0x03; + + if (length < 0x1000000) + return 0x04; + + return 0x05; +} diff --git a/lib/connection/messagetools.h b/lib/connection/messagetools.h new file mode 100644 index 000000000..09241138d --- /dev/null +++ b/lib/connection/messagetools.h @@ -0,0 +1,34 @@ +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libconnection/messagetools.h,v 1.1 2002/12/07 13:37:06 thegoodguy Exp $ + * + * tools used in clientlib <-> daemon communication - d-box2 linux project + * + * (C) 2002 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __messagetools_h__ +#define __messagetools_h__ + +#include + +size_t write_length_field (unsigned char * buffer, const unsigned int length); +size_t get_length_field_size (const unsigned int length); +unsigned int parse_length_field (const unsigned char * buffer); + + +#endif /* __messagetools_h__ */ diff --git a/lib/controldclient/Makefile.am b/lib/controldclient/Makefile.am new file mode 100644 index 000000000..56165105b --- /dev/null +++ b/lib/controldclient/Makefile.am @@ -0,0 +1,10 @@ +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/connection \ + -I$(top_srcdir)/lib/libeventserver + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +lib_LTLIBRARIES = libcontroldclient.la + +libcontroldclient_la_SOURCES = controldclient.cpp diff --git a/lib/controldclient/controldMsg.h b/lib/controldclient/controldMsg.h new file mode 100644 index 000000000..e68d6f112 --- /dev/null +++ b/lib/controldclient/controldMsg.h @@ -0,0 +1,172 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __controldMsg__ +#define __controldMsg__ + +#include +#include + +#define CONTROLD_UDS_NAME "/tmp/controld.sock" + + +class CControldMsg : public CBasicMessage +{ + + public: + + static const CBasicMessage::t_version ACTVERSION = 2; + + enum commands + { + CMD_SHUTDOWN = 1, + CMD_SAVECONFIG, + + CMD_SETVOLUME, + CMD_GETVOLUME, + + CMD_SETVOLUME_AVS, + CMD_GETVOLUME_AVS, + + CMD_SETMUTE, + CMD_GETMUTESTATUS, + + CMD_SETVIDEOFORMAT, + CMD_GETVIDEOFORMAT, + + CMD_SETVIDEOOUTPUT, + CMD_GETVIDEOOUTPUT, + + CMD_SETVCROUTPUT, + CMD_GETVCROUTPUT, + + CMD_SETBOXTYPE, + CMD_GETBOXTYPE, + + CMD_SETSCARTMODE, + CMD_GETSCARTMODE, + + CMD_GETASPECTRATIO, + + CMD_SETVIDEOPOWERDOWN, + CMD_GETVIDEOPOWERDOWN, + + CMD_REGISTEREVENT, + CMD_UNREGISTEREVENT, + + CMD_EVENT, + + CMD_SETCSYNC, + CMD_GETCSYNC, + CMD_SETVIDEOMODE, + CMD_GETVIDEOMODE + + }; + + struct commandVolume + { + unsigned char volume; + CControld::volume_type type; + }; + + struct commandMute + { + bool mute; + CControld::volume_type type; + }; + + struct commandVideoFormat + { + unsigned char format; + }; + + struct commandVideoOutput + { + unsigned char output; + }; + + struct commandVCROutput + { + unsigned char vcr_output; + }; + + struct commandBoxType + { + CControld::tuxbox_maker_t boxtype; + }; + + struct commandScartMode + { + unsigned char mode; + }; + + struct commandVideoPowerSave + { + bool powerdown; + }; + + //response structures + + struct responseVideoFormat + { + unsigned char format; + }; + + struct responseAspectRatio + { + unsigned char aspectRatio; + }; + + struct responseVideoOutput + { + unsigned char output; + }; + + struct responseVCROutput + { + unsigned char vcr_output; + }; + + struct responseBoxType + { + CControld::tuxbox_maker_t boxtype; + }; + + struct responseScartMode + { + unsigned char mode; + }; + + struct commandCsync + { + unsigned char csync; + }; + + struct responseVideoPowerSave + { + bool videoPowerSave; + }; + +}; + +#endif diff --git a/lib/controldclient/controldclient.cpp b/lib/controldclient/controldclient.cpp new file mode 100644 index 000000000..89bdfd9ca --- /dev/null +++ b/lib/controldclient/controldclient.cpp @@ -0,0 +1,316 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +#include +#include + + +const unsigned char CControldClient::getVersion () const +{ + return CControldMsg::ACTVERSION; +} + +const char * CControldClient::getSocketName() const +{ + return CONTROLD_UDS_NAME; +} + +void CControldClient::shutdown() +{ + send(CControldMsg::CMD_SHUTDOWN); + close_connection(); +} + +void CControldClient::setBoxType(CControld::tuxbox_maker_t type) +{ + CControldMsg::commandBoxType msg2; + + msg2.boxtype = type; + + send(CControldMsg::CMD_SETBOXTYPE, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} + +CControld::tuxbox_maker_t CControldClient::getBoxType() +{ + CControldMsg::responseBoxType rmsg; + + send(CControldMsg::CMD_GETBOXTYPE); + + if (!receive_data((char*)&rmsg, sizeof(rmsg))) + rmsg.boxtype = CControld::TUXBOX_MAKER_UNKNOWN; + + close_connection(); + + return rmsg.boxtype; +} + +void CControldClient::setScartMode(bool mode) +{ + CControldMsg::commandScartMode msg2; + + msg2.mode = mode; + + send(CControldMsg::CMD_SETSCARTMODE, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} + +char CControldClient::getScartMode() +{ + CControldMsg::responseScartMode rmsg; + send(CControldMsg::CMD_GETSCARTMODE); + receive_data((char*)&rmsg, sizeof(rmsg)); + close_connection(); + + return rmsg.mode; +} + +void CControldClient::setVolume(const char volume, const CControld::volume_type volume_type) +{ + CControldMsg::commandVolume msg2; + msg2.type = volume_type; + msg2.volume = volume; + send(CControldMsg::CMD_SETVOLUME, (char*)&msg2, sizeof(msg2)); + close_connection(); +} + +char CControldClient::getVolume(const CControld::volume_type volume_type) +{ + CControldMsg::commandVolume rmsg; + rmsg.type = volume_type; + send(CControldMsg::CMD_GETVOLUME, (char*)&rmsg, sizeof(rmsg)); + receive_data((char*)&rmsg, sizeof(rmsg)); + close_connection(); + + return rmsg.volume; +} + +void CControldClient::setVideoFormat(char format) +{ + CControldMsg::commandVideoFormat msg2; + + msg2.format = format; + + send(CControldMsg::CMD_SETVIDEOFORMAT, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} + +char CControldClient::getAspectRatio() +{ + CControldMsg::responseAspectRatio rmsg; + + send(CControldMsg::CMD_GETASPECTRATIO); + + receive_data((char*)&rmsg, sizeof(rmsg)); + + close_connection(); + + return rmsg.aspectRatio; +} + +char CControldClient::getVideoFormat() +{ + CControldMsg::responseVideoFormat rmsg; + + send(CControldMsg::CMD_GETVIDEOFORMAT); + + bool success = receive_data((char*)&rmsg, sizeof(rmsg)); + + close_connection(); + + return success ? rmsg.format : 2; /* default value is 2 (cf. controld.cpp) */ +} + +void CControldClient::setVideoOutput(char output) +{ + CControldMsg::commandVideoOutput msg2; + + msg2.output = output; + + send(CControldMsg::CMD_SETVIDEOOUTPUT, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} + +void CControldClient::setVCROutput(char output) +{ + CControldMsg::commandVCROutput msg2; + + msg2.vcr_output = output; + + send(CControldMsg::CMD_SETVCROUTPUT, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} + +char CControldClient::getVideoOutput() +{ + CControldMsg::responseVideoOutput rmsg; + + send(CControldMsg::CMD_GETVIDEOOUTPUT); + + bool success = receive_data((char*)&rmsg, sizeof(rmsg)); + + close_connection(); + + return success ? rmsg.output : 1; /* default value is 1 (cf. controld.cpp) */ +} + +char CControldClient::getVCROutput() +{ + CControldMsg::responseVCROutput rmsg; + + send(CControldMsg::CMD_GETVCROUTPUT); + + bool success = receive_data((char*)&rmsg, sizeof(rmsg)); + + close_connection(); + + return success ? rmsg.vcr_output : 1; /* default value is 1 (cf. controld.cpp) */ +} + +void CControldClient::Mute(const CControld::volume_type volume_type) +{ + setMute(true,volume_type); +} + +void CControldClient::UnMute(const CControld::volume_type volume_type) +{ + setMute(false,volume_type); +} + +void CControldClient::setMute(const bool mute, const CControld::volume_type volume_type) +{ + CControldMsg::commandMute msg; + msg.mute = mute; + msg.type = volume_type; + send(CControldMsg::CMD_SETMUTE, (char*)&msg, sizeof(msg)); + close_connection(); +} + +bool CControldClient::getMute(const CControld::volume_type volume_type) +{ + CControldMsg::commandMute rmsg; + rmsg.type = volume_type; + send(CControldMsg::CMD_GETMUTESTATUS, (char*)&rmsg, sizeof(rmsg)); + receive_data((char*)&rmsg, sizeof(rmsg)); + close_connection(); + return rmsg.mute; +} + +void CControldClient::registerEvent(unsigned int eventID, unsigned int clientID, const char * const udsName) +{ + CEventServer::commandRegisterEvent msg2; + + msg2.eventID = eventID; + msg2.clientID = clientID; + strcpy(msg2.udsName, udsName); + + send(CControldMsg::CMD_REGISTEREVENT, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} + +void CControldClient::unRegisterEvent(unsigned int eventID, unsigned int clientID) +{ + CEventServer::commandUnRegisterEvent msg2; + + msg2.eventID = eventID; + msg2.clientID = clientID; + + send(CControldMsg::CMD_UNREGISTEREVENT, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} + +void CControldClient::videoPowerDown(bool powerdown) +{ + CControldMsg::commandVideoPowerSave msg2; + + msg2.powerdown = powerdown; + + send(CControldMsg::CMD_SETVIDEOPOWERDOWN, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} + +bool CControldClient::getVideoPowerDown() +{ + CControldMsg::responseVideoPowerSave msg; + send(CControldMsg::CMD_GETVIDEOPOWERDOWN); + receive_data((char*) &msg, sizeof(msg)); + close_connection(); + return msg.videoPowerSave; +} + +void CControldClient::saveSettings() +{ + send(CControldMsg::CMD_SAVECONFIG); + close_connection(); +} + +void CControldClient::setRGBCsync(char val) +{ + CControldMsg::commandCsync msg; + msg.csync = val; + send(CControldMsg::CMD_SETCSYNC, (char*) &msg, sizeof(msg)); + close_connection(); +} + +char CControldClient::getRGBCsync() +{ + CControldMsg::commandCsync msg; + send(CControldMsg::CMD_GETCSYNC); + receive_data((char*) &msg, sizeof(msg)); + close_connection(); + return msg.csync; +} +char CControldClient::getVideoMode() +{ + CControldMsg::responseVideoFormat rmsg; + send(CControldMsg::CMD_GETVIDEOMODE); + bool success = receive_data((char*)&rmsg, sizeof(rmsg)); + close_connection(); + return success ? rmsg.format : 1; /* default value is 2 (cf. controld.cpp) */ +} +void CControldClient::setVideoMode(char format) +{ + CControldMsg::commandVideoFormat msg2; + msg2.format = format; + send(CControldMsg::CMD_SETVIDEOMODE, (char*)&msg2, sizeof(msg2)); + close_connection(); +} + diff --git a/lib/controldclient/controldclient.h b/lib/controldclient/controldclient.h new file mode 100644 index 000000000..8df78261a --- /dev/null +++ b/lib/controldclient/controldclient.h @@ -0,0 +1,196 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __controldclient__ +#define __controldclient__ + +#include +#include + + +#define VCR_STATUS_OFF 0 +#define VCR_STATUS_ON 1 +#define VCR_STATUS_16_9 2 + +class CControldClient:private CBasicClient +{ + private: + virtual const unsigned char getVersion () const; + virtual const char * getSocketName() const; + + public: + + enum events + { + EVT_VOLUMECHANGED, + EVT_MUTECHANGED, + EVT_MODECHANGED, + EVT_VCRCHANGED + }; + + //VideoFormat + static const char VIDEOFORMAT_AUTO = 0; + static const char VIDEOFORMAT_16_9 = 1; + static const char VIDEOFORMAT_4_3 = 2; + static const char VIDEOFORMAT_4_3_PS = 3; + + //VideoOutput + static const char VIDEOOUTPUT_COMPOSITE = 0; + static const char VIDEOOUTPUT_RGB = 1; + static const char VIDEOOUTPUT_SVIDEO = 2; + static const char VIDEOOUTPUT_YUV_VBS = 3; + static const char VIDEOOUTPUT_YUV_CVBS = 4; + + //mute + static const bool VOLUME_MUTE = true; + static const bool VOLUME_UNMUTE = false; + + //scartmode + static const char SCARTMODE_ON = 1; + static const char SCARTMODE_OFF = 0; + + /* + setVolume(volume_type) : Setzten der Lautstärke + Parameter: 0..100 - 0=leise 100=laut + volume_type : device AVS/OST/UNKOWN(=last used) + */ + void setVolume(const char volume, const CControld::volume_type volume_type = CControld::TYPE_UNKNOWN); + char getVolume(const CControld::volume_type volume_type = CControld::TYPE_UNKNOWN); + + /* + setMute(bool, volume_type) : setzen von Mute + Parameter: mute == true : ton aus + mute == false : ton an + volume_type : device AVS/OST/UNKOWN(=last used) + */ + void setMute(const bool mute, const CControld::volume_type volume_type = CControld::TYPE_UNKNOWN); + bool getMute(const CControld::volume_type volume_type = CControld::TYPE_UNKNOWN); + + /* + Mute(volume_type) : Ton ausschalten + Parameter: volume_type : device AVS/OST/UNKOWN(=last used) + */ + void Mute(const CControld::volume_type volume_type = CControld::TYPE_UNKNOWN); + + /* + UnMute(bool) : Ton wieder einschalten + Parameter: volume_type : device AVS/OST/UNKOWN(=last used) + + */ + void UnMute(const CControld::volume_type volume_type = CControld::TYPE_UNKNOWN); + + + /* + setVideoFormat(char) : Setzten des Bildformates ( 4:3 / 16:9 ) + Parameter: VIDEOFORMAT_AUTO = auto + VIDEOFORMAT_4_3 = 4:3 + VIDEOFORMAT_16_9 = 16:9 + */ + void setVideoFormat(char); + char getVideoFormat(); + /* + getAspectRatio : Aktueller Wert aus dem Bitstream + 2: 4:3 + 3: 16:9 + 4: 2:2.1 + */ + char getAspectRatio(); + + /* + setVideoOutput(char) : Setzten des Videooutputs ( composite (= cvbs) / svideo / rgb+cvbs / yuv+vbs / yuv+cvbs ) + Parameter: VIDEOOUTPUT_COMPOSITE = cvbs (composite) video + VIDEOOUTPUT_SVIDEO = svideo + VIDEOOUTPUT_RGB = rgb+cvbs + VIDEOOUTPUT_YUV_VBS = yuv+vbs + VIDEOOUTPUT_YUV_CVBS = yuv+cvbs + */ + void setVideoOutput(char); + char getVideoOutput(); + + /* + setVCROutput(char) : Setzten des Videooutputs für VCR ( composite / svideo ) + Parameter: VIDEOOUTPUT_COMPOSITE = cvbs + VIDEOOUTPUT_SVIDEO = svideo + */ + void setVCROutput(char); + char getVCROutput(); + + /* + setBoxType(CControldClient::tuxbox_vendor_t) : Setzten des Boxentyps ( nokia / sagem / philips ) + */ + void setBoxType(const CControld::tuxbox_maker_t); + CControld::tuxbox_maker_t getBoxType(); + + /* + setScartMode(char) : Scartmode ( an / aus ) + Parameter: SCARTMODE_ON = auf scartinput schalten + SCARTMODE_OFF = wieder dvb anzeigen + + + */ + void setScartMode(bool); + char getScartMode(); + + + /* + die dBox in standby bringen + */ + void videoPowerDown(bool); + + /* + standby abfragen + */ + bool getVideoPowerDown(); + + /* + die Dbox herunterfahren + */ + void shutdown(); + + + /* + ein beliebiges Event anmelden + */ + void registerEvent(unsigned int eventID, unsigned int clientID, const char * const udsName); + + /* + ein beliebiges Event abmelden + */ + void unRegisterEvent(unsigned int eventID, unsigned int clientID); + + void saveSettings(); + + /* + setzen der sync correction im RGB mode des saa7126 (csync) 0=aus, 31=max + */ + + void setRGBCsync(char csync); + /* + lesen der sync correction im RGB mode des saa7126 (csync) 0=aus, 31=max + */ + char getRGBCsync(); + void setVideoMode(char); + char getVideoMode(); +}; + +#endif diff --git a/lib/controldclient/controldtypes.h b/lib/controldclient/controldtypes.h new file mode 100644 index 000000000..1025b0494 --- /dev/null +++ b/lib/controldclient/controldtypes.h @@ -0,0 +1,62 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __controldtypes__ +#define __controldtypes__ + +class CControld +{ +public: + + //BoxType /* cf. driver/include/tuxbox/tuxbox_info.h */ + typedef enum tuxbox_maker + { + TUXBOX_MAKER_UNKNOWN = 0, + TUXBOX_MAKER_NOKIA = 1, + TUXBOX_MAKER_PHILIPS = 2, + TUXBOX_MAKER_SAGEM = 3, + TUXBOX_MAKER_DREAM_MM = 4, + TUXBOX_MAKER_TECHNOTREND = 5 + } tuxbox_maker_t; + + enum volume_type + { + TYPE_OST=0, + TYPE_AVS=1, + TYPE_LIRC=2, + TYPE_UNKNOWN + }; + + const static int no_video_formats = 5; + + typedef enum video_format + { + FORMAT_CVBS = 0, + FORMAT_RGB = 1, + FORMAT_SVIDEO = 2, + FORMAT_YUV_VBS = 3, + FORMAT_YUV_CVBS = 4 + } t_video_format; + +}; +#endif diff --git a/lib/libconfigfile/Makefile.am b/lib/libconfigfile/Makefile.am new file mode 100644 index 000000000..201efcd63 --- /dev/null +++ b/lib/libconfigfile/Makefile.am @@ -0,0 +1,5 @@ +noinst_LIBRARIES = libtuxbox-configfile.a + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +libtuxbox_configfile_a_SOURCES = configfile.cpp diff --git a/lib/libconfigfile/configfile.cpp b/lib/libconfigfile/configfile.cpp new file mode 100644 index 000000000..0b28f9f40 --- /dev/null +++ b/lib/libconfigfile/configfile.cpp @@ -0,0 +1,415 @@ +/* + * $Id: configfile.cpp,v 1.19 2003/11/23 19:16:03 obi Exp $ + * + * configuration object for the d-box 2 linux project + * + * Copyright (C) 2001, 2002 Andreas Oberritter , + * thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "configfile.h" + +#include +#include +#include +#include +#include + +#include +#include + +CConfigFile::CConfigFile(const char p_delimiter, const bool p_saveDefaults) +{ + modifiedFlag = false; + unknownKeyQueryedFlag = false; + delimiter = p_delimiter; + saveDefaults = p_saveDefaults; +} + +void CConfigFile::clear() +{ + configData.clear(); +} + +// +// public file operation methods +// +const bool CConfigFile::loadConfig(const char * const filename) +{ + std::ifstream configFile(filename); + + if (configFile != NULL) + { + std::string s; + clear(); + modifiedFlag = false; + + for (int linenr = 1; ; linenr++) + { + getline(configFile, s); + if (configFile.fail()) + break; + + std::string::size_type i = s.find('='); + if (i != std::string::npos) + { + std::string::size_type j = s.find('#'); + if (j == std::string::npos) + j = s.length(); + configData[s.substr(0, i)] = s.substr(i + 1, j - (i + 1)); + } + } + configFile.close(); + return true; + } + else + { + std::cerr << "[ConfigFile] Unable to open file " << filename << " for reading." << std::endl; + return false; + } +} + +const bool CConfigFile::loadConfig(const std::string & filename) +{ + return loadConfig(filename.c_str()); +} + +const bool CConfigFile::saveConfig(const char * const filename) +{ + std::ofstream configFile(filename); + + if (configFile != NULL) + { + for (ConfigDataMap::const_iterator it = configData.begin(); it != configData.end(); it++) + { + configFile << it->first << "=" << it->second << std::endl; + } + + configFile.close(); + sync(); + + chmod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + return true; + } + else + { + std::cerr << "[ConfigFile] Unable to open file " << filename << " for writing." << std::endl; + return false; + } +} + +const bool CConfigFile::saveConfig(const std::string & filename) +{ + return saveConfig(filename.c_str()); +} + + + +// +// private "store" methods +// +void CConfigFile::storeBool(const std::string & key, const bool val) +{ + if (val == true) + configData[key] = std::string("true"); + else + configData[key] = std::string("false"); +} + +void CConfigFile::storeInt32(const std::string & key, const int32_t val) +{ + std::stringstream s; + s << val; + s >> configData[key]; +} + +void CConfigFile::storeInt64(const std::string & key, const int64_t val) +{ + std::stringstream s; + s << val; + s >> configData[key]; +} + +void CConfigFile::storeString(const std::string & key, const std::string & val) +{ + configData[key] = val; +} + + + +// +// public "get" methods +// +bool CConfigFile::getBool(const char * const key, const bool defaultVal) +{ + return getBool(std::string(key), defaultVal); +} + +bool CConfigFile::getBool(const std::string & key, const bool defaultVal) +{ + if (configData.find(key) == configData.end()) + { + if (saveDefaults) { + unknownKeyQueryedFlag = true; + storeBool(key, defaultVal); + } + else { + return defaultVal; + } + } + + return !((configData[key] == "false") || (configData[key] == "0")); +} + +int32_t CConfigFile::getInt32(const char * const key, const int32_t defaultVal) +{ + return getInt32(std::string(key), defaultVal); +} + +int32_t CConfigFile::getInt32(const std::string & key, const int32_t defaultVal) +{ + if (configData.find(key) == configData.end()) + { + if (saveDefaults) { + unknownKeyQueryedFlag = true; + storeInt32(key, defaultVal); + } + else { + return defaultVal; + } + } + + return atoi(configData[key].c_str()); +} + +int64_t CConfigFile::getInt64(const char * const key, const int64_t defaultVal) +{ + return getInt64(std::string(key), defaultVal); +} + +int64_t CConfigFile::getInt64(const std::string & key, const int64_t defaultVal) +{ + if (configData.find(key) == configData.end()) + { + if (saveDefaults) { + unknownKeyQueryedFlag = true; + storeInt64(key, defaultVal); + } + else { + return defaultVal; + } + } + + return atoll(configData[key].c_str()); +} + +std::string CConfigFile::getString(const char * const key, const std::string & defaultVal) +{ + return getString(std::string(key), defaultVal); +} + +std::string CConfigFile::getString(const std::string & key, const std::string & defaultVal) +{ + if (configData.find(key) == configData.end()) + { + if (saveDefaults) { + unknownKeyQueryedFlag = true; + storeString(key, defaultVal); + } + else { + return defaultVal; + } + } + + return configData[key]; +} + +std::vector CConfigFile::getInt32Vector(const std::string & key) +{ + std::string val = configData[key]; + std::vector vec; + uint16_t length = 0; + uint16_t pos = 0; + uint16_t i; + + for (i = 0; i < val.length(); i++) + { + if (val[i] == delimiter) + { + vec.push_back(atoi(val.substr(pos, length).c_str())); + pos = i + 1; + length = 0; + } + else + { + length++; + } + } + + if (length == 0) + unknownKeyQueryedFlag = true; + else + vec.push_back(atoi(val.substr(pos, length).c_str())); + + return vec; +} + +std::vector CConfigFile::getStringVector(const std::string & key) +{ + std::string val = configData[key]; + std::vector vec; + uint16_t length = 0; + uint16_t pos = 0; + uint16_t i; + + for (i = 0; i < val.length(); i++) + { + if (val[i] == delimiter) + { + vec.push_back(val.substr(pos, length)); + pos = i + 1; + length = 0; + } + else + { + length++; + } + } + + if (length == 0) + unknownKeyQueryedFlag = true; + else + vec.push_back(val.substr(pos, length)); + + return vec; +} + + + +// +// public "set" methods +// +void CConfigFile::setBool(const char * const key, const bool val) +{ + setBool(std::string(key), val); +} + +void CConfigFile::setBool(const std::string & key, const bool val) +{ + bool tmpUnknownKeyQueryedFlag = unknownKeyQueryedFlag; + unknownKeyQueryedFlag = false; + bool oldVal = getBool(key); + + if ((oldVal != val) || (unknownKeyQueryedFlag)) + { + modifiedFlag = true; + storeBool(key, val); + } + + unknownKeyQueryedFlag = tmpUnknownKeyQueryedFlag; +} + +void CConfigFile::setInt32(const char * const key, int32_t val) +{ + setInt32(std::string(key), val); +} + +void CConfigFile::setInt32(const std::string & key, int32_t val) +{ + bool tmpUnknownKeyQueryedFlag = unknownKeyQueryedFlag; + unknownKeyQueryedFlag = false; + int32_t oldVal = getInt32(key); + + if ((oldVal != val) || (unknownKeyQueryedFlag)) + { + modifiedFlag = true; + storeInt32(key, val); + } + + unknownKeyQueryedFlag = tmpUnknownKeyQueryedFlag; +} + +void CConfigFile::setInt64(const char * const key, const int64_t val) +{ + setInt64(std::string(key), val); +} + +void CConfigFile::setInt64(const std::string & key, const int64_t val) +{ + bool tmpUnknownKeyQueryedFlag = unknownKeyQueryedFlag; + unknownKeyQueryedFlag = false; + int64_t oldVal = getInt64(key); + + if ((oldVal != val) || (unknownKeyQueryedFlag)) + { + modifiedFlag = true; + storeInt64(key, val); + } + + unknownKeyQueryedFlag = tmpUnknownKeyQueryedFlag; +} + +void CConfigFile::setString(const char * const key, const std::string & val) +{ + setString(std::string(key), val); +} + +void CConfigFile::setString(const std::string & key, const std::string & val) +{ + bool tmpUnknownKeyQueryedFlag = unknownKeyQueryedFlag; + unknownKeyQueryedFlag = false; + std::string oldVal = getString(key); + + if ((oldVal != val) || (unknownKeyQueryedFlag)) + { + modifiedFlag = true; + storeString(key, val); + } + + unknownKeyQueryedFlag = tmpUnknownKeyQueryedFlag; +} + +void CConfigFile::setInt32Vector(const std::string & key, const std::vector vec) +{ + std::stringstream s; + + for (std::vector::const_iterator it = vec.begin(); ; ) + { + s << (*it); + it++; + if (it == vec.end()) + break; + s << delimiter; + } + s >> configData[key]; +} + +void CConfigFile::setStringVector(const std::string & key, const std::vector vec) +{ + configData[key] = ""; + + for (std::vector::const_iterator it = vec.begin(); ; ) + { + configData[key] += *it; + it++; + if (it == vec.end()) + break; + configData[key] += delimiter; + } +} diff --git a/lib/libconfigfile/configfile.h b/lib/libconfigfile/configfile.h new file mode 100644 index 000000000..0142d4544 --- /dev/null +++ b/lib/libconfigfile/configfile.h @@ -0,0 +1,111 @@ +/* + * $Id: configfile.h,v 1.11 2003/09/25 18:52:27 thegoodguy Exp $ + * + * Copyright (C) 2001, 2002 Andreas Oberritter , + * thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __configfile_h__ +#define __configfile_h__ + + +#include + +#include +#include +#include + + +class CConfigFile +{ + private: + + typedef std::map ConfigDataMap; + + ConfigDataMap configData; + char delimiter; + bool saveDefaults; + bool modifiedFlag; + bool unknownKeyQueryedFlag; + + void storeBool(const std::string & key, const bool val); + void storeInt32(const std::string & key, const int32_t val); + void storeInt64(const std::string & key, const int64_t val); + void storeString(const std::string & key, const std::string & val); + + public: + CConfigFile(const char p_delimiter, const bool p_saveDefaults = true); + + const bool loadConfig(const char * const filename); + const bool loadConfig(const std::string & filename); + + const bool saveConfig(const char * const filename); + const bool saveConfig(const std::string & filename); + + void clear(); + + // + // strings + // + std::string getString(const char * const key, const std::string & defaultVal = ""); + std::string getString(const std::string & key, const std::string & defaultVal = ""); + void setString(const char * const key, const std::string & val); + void setString(const std::string & key, const std::string & val); + + // + // 32, 64 bit int + // + int32_t getInt32(const char * const key, const int32_t defaultVal = 0); + int32_t getInt32(const std::string & key, const int32_t defaultVal = 0); + void setInt32(const char * const key, const int32_t val); + void setInt32(const std::string & key, const int32_t val); + + int64_t getInt64(const char * const key, const int64_t defaultVal = 0); + int64_t getInt64(const std::string & key, const int64_t defaultVal = 0); + void setInt64(const char * const key, const int64_t val); + void setInt64(const std::string & key, const int64_t val); + + // + // boolean + // + bool getBool(const char * const key, const bool defaultVal = false); + bool getBool(const std::string & key, const bool defaultVal = false); + void setBool(const char * const key, const bool val); + void setBool(const std::string & key, const bool val); + + // + // vectors + // + std::vector getStringVector(const std::string & key); + void setStringVector(const std::string & key, const std::vector vec); + + std::vector getInt32Vector(const std::string & key); + void setInt32Vector(const std::string & key, const std::vector vec); + + // + // flags + // + const bool getModifiedFlag() const { return modifiedFlag; } + void setModifiedFlag(const bool val) { modifiedFlag = val; } + + const bool getUnknownKeyQueryedFlag() const { return unknownKeyQueryedFlag; } + void setUnknownKeyQueryedFlag(const bool val) { unknownKeyQueryedFlag = val; } + +}; + +#endif /* __configfile_h__ */ diff --git a/lib/libcoolstream/.svnignore b/lib/libcoolstream/.svnignore new file mode 100644 index 000000000..3694ff0e6 --- /dev/null +++ b/lib/libcoolstream/.svnignore @@ -0,0 +1,5 @@ +Makefile.in +.libs +.deps +*.la +*.lo diff --git a/lib/libcoolstream/audio_cs.h b/lib/libcoolstream/audio_cs.h new file mode 100644 index 000000000..b2dea13e7 --- /dev/null +++ b/lib/libcoolstream/audio_cs.h @@ -0,0 +1,115 @@ +/* public header file */ + +#ifndef _AUDIO_CS_H_ +#define _AUDIO_CS_H_ + +typedef enum +{ + AUDIO_SYNC_WITH_PTS, + AUDIO_NO_SYNC, + AUDIO_SYNC_AUDIO_MASTER +} AUDIO_SYNC_MODE; + +typedef enum +{ + AUDIO_FMT_AUTO = 0, + AUDIO_FMT_MPEG, + AUDIO_FMT_MP3, + AUDIO_FMT_DOLBY_DIGITAL, + AUDIO_FMT_BASIC = AUDIO_FMT_DOLBY_DIGITAL, + AUDIO_FMT_AAC, + AUDIO_FMT_AAC_PLUS, + AUDIO_FMT_DD_PLUS, + AUDIO_FMT_DTS, + AUDIO_FMT_AVS, + AUDIO_FMT_MLP, + AUDIO_FMT_WMA, + AUDIO_FMT_ADVANCED = AUDIO_FMT_MLP +} AUDIO_FORMAT; + +#ifndef CS_AUDIO_PDATA +#define CS_AUDIO_PDATA void +#endif + +#include "cs_types.h" + +class cAudio +{ + private: + CS_AUDIO_PDATA * privateData; + unsigned int cEncodedDataOnSPDIF, cEncodedDataOnHDMI; + bool Muted; + + AUDIO_FORMAT StreamType; + AUDIO_SYNC_MODE SyncMode; + bool started; + unsigned int uAudioPTSDelay; + unsigned int uAudioDolbyPTSDelay, uAudioMpegPTSDelay; + bool receivedDelay; + + /* internal methods */ + int setBypassMode(int disable); + int LipsyncAdjust(void); + int atten; + int volume; + + bool clip_started; + bool hdmiDD; + bool spdifDD; + bool hasMuteScheduled; + public: + /* construct & destruct */ + cAudio(void * hBuffer, void * encHD, void * encSD); + ~cAudio(void); + + void * GetHandle(); + void * GetDSP(); + void HandleAudioMessage(int Event, void *pData); + void HandlePcmMessage(int Event, void *pData); + /* shut up */ + int mute(void); + int unmute(void); + int SetMute(int enable); + + /* bypass audio to external decoder */ + int enableBypass(void); + int disableBypass(void); + + /* volume, min = 0, max = 255 */ + int setVolume(unsigned int left, unsigned int right); + int getVolume(void) { return volume;} + + /* start and stop audio */ + int Start(void); + int Stop(void); + bool Pause(bool Pcm = true); + bool Resume(bool Pcm = true); + void SetStreamType(AUDIO_FORMAT type) { StreamType = type; }; + AUDIO_FORMAT GetStreamType(void) { return StreamType; } + bool ReceivedAudioDelay(void) { return receivedDelay; } + void SetReceivedAudioDelay(bool set = false) { receivedDelay = set; } + unsigned int GetAudioDelay(void) { return (StreamType == AUDIO_FMT_DOLBY_DIGITAL) ? uAudioDolbyPTSDelay : uAudioMpegPTSDelay; } + void SetSyncMode(AVSYNC_TYPE Mode); + + /* stream source */ + int getSource(void); + int setSource(int source); + int Flush(void); + + /* select channels */ + int setChannel(int channel); + int getChannel(void); + int PrepareClipPlay(int uNoOfChannels, int uSampleRate, int uBitsPerSample, int bLittleEndian); + int WriteClip(unsigned char * buffer, int size); + int StopClip(); + void getAudioInfo(int &type, int &layer, int& freq, int &bitrate, int &mode); + void SetSRS(int iq_enable, int nmgr_enable, int iq_mode, int iq_level); + bool IsHdmiDDSupported(); + void SetHdmiDD(bool enable); + void SetSpdifDD(bool enable); + void ScheduleMute(bool On); + +}; + +#endif + diff --git a/lib/libcoolstream/cs_types.h b/lib/libcoolstream/cs_types.h new file mode 100644 index 000000000..da046341e --- /dev/null +++ b/lib/libcoolstream/cs_types.h @@ -0,0 +1,11 @@ +#ifndef __CS_TYPES +#define __CS_TYPES + +typedef enum +{ + AVSYNC_DISABLED, + AVSYNC_ENABLED, + AVSYNC_AUDIO_IS_MASTER, +} AVSYNC_TYPE; + +#endif diff --git a/lib/libcoolstream/dmx_cs.h b/lib/libcoolstream/dmx_cs.h new file mode 100644 index 000000000..35108ca29 --- /dev/null +++ b/lib/libcoolstream/dmx_cs.h @@ -0,0 +1,78 @@ +/*******************************************************************************/ +/* */ +/* libcoolstream/cszapper/demux.h */ +/* ZAP interface for neutrino frontend */ +/* */ +/* (C) 2008 CoolStream International */ +/* */ +/*******************************************************************************/ +#ifndef __DEMUX_CS_H +#define __DEMUX_CS_H + +#include + +#define DEMUX_POLL_TIMEOUT 0 // timeout in ms +#define MAX_FILTER_LENGTH 16 // maximum number of filters +#ifndef DMX_FILTER_SIZE +#define DMX_FILTER_SIZE MAX_FILTER_LENGTH +#endif +#define MAX_DMX_UNITS 4 //DMX_NUM_TSS_INPUTS_REVB + +#ifndef CS_DMX_PDATA +#define CS_DMX_PDATA void +#endif + +#include "cs_types.h" + +typedef enum +{ + DMX_VIDEO_CHANNEL = 1, + DMX_AUDIO_CHANNEL, + DMX_PES_CHANNEL, + DMX_PSI_CHANNEL, + DMX_PIP_CHANNEL, + DMX_TP_CHANNEL, + DMX_PCR_ONLY_CHANNEL, +} DMX_CHANNEL_TYPE; + +class cDemux +{ + private: + int timeout; + unsigned short pid; + unsigned char tid[MAX_FILTER_LENGTH], mask[MAX_FILTER_LENGTH]; + bool nb; // non block + pthread_cond_t read_cond; + pthread_mutex_t mutex; + AVSYNC_TYPE SyncMode; + int uLength; + bool enabled; + int unit; + + DMX_CHANNEL_TYPE type; + CS_DMX_PDATA * privateData; + public: + + bool Open(DMX_CHANNEL_TYPE pes_type, void * hVideoBuffer = NULL, int uBufferSize = 8192); + void Close(void); + bool Start(void); + bool Stop(void); + int Read(unsigned char *buff, int len, int Timeout = 0); + void SignalRead(int len); + unsigned short GetPID(void) { return pid; } + const unsigned char *GetFilterTID(void) { return tid; } + const unsigned char *GetFilterMask(void) { return mask; } + bool sectionFilter(unsigned short Pid, const unsigned char * const Tid, const unsigned char * const Mask, int len, int Timeout = DEMUX_POLL_TIMEOUT, const unsigned char * const nMask = NULL); + bool pesFilter(const unsigned short Pid); + void SetSyncMode(AVSYNC_TYPE mode); + void * getBuffer(); + void * getChannel(); + const DMX_CHANNEL_TYPE getChannelType(void); + void addPid(unsigned short Pid); + void getSTC(int64_t * STC); + // + cDemux(int num = 0); + ~cDemux(); +}; + +#endif //__DEMUX_H diff --git a/lib/libcoolstream/dvb-ci.h b/lib/libcoolstream/dvb-ci.h new file mode 100644 index 000000000..483ae2c4a --- /dev/null +++ b/lib/libcoolstream/dvb-ci.h @@ -0,0 +1,62 @@ +#ifndef __DVBCI_H +#define __DVBCI_H + +#ifdef __cplusplus +extern "C" { +#endif +void CI_MenuAnswer(unsigned char bSlotIndex,unsigned char choice); +void CI_Answer(unsigned char bSlotIndex,unsigned char *pBuffer,unsigned char nLength); +void CI_CloseMMI(unsigned char bSlotIndex); +void CI_EnterMenu(unsigned char bSlotIndex); +#ifdef __cplusplus +} +#endif + +#define MAX_MMI_ITEMS 20 +#define MAX_MMI_TEXT_LEN 255 +#define MAX_MMI_CHOICE_TEXT_LEN 255 + +typedef struct +{ + int slot; + int choice_nb; + char title[MAX_MMI_TEXT_LEN]; + char subtitle[MAX_MMI_TEXT_LEN]; + char bottom[MAX_MMI_TEXT_LEN]; + char choice_item[MAX_MMI_ITEMS][MAX_MMI_CHOICE_TEXT_LEN]; +} MMI_MENU_LIST_INFO; + +typedef struct +{ + int slot; + int blind; + int answerlen; + char enguiryText[MAX_MMI_TEXT_LEN]; + +} MMI_ENGUIRY_INFO; + +typedef void (*SEND_MSG_HOOK) (unsigned int msg, unsigned int data); + +class cDvbCi { + private: + int slots; + bool init; + int pmtlen; + unsigned char * pmtbuf; + void SendPMT(); + pthread_mutex_t ciMutex; + public: + bool Init(void); + bool SendPMT(unsigned char *data, int len); + bool SendDateTime(void); + // + cDvbCi(int Slots); + ~cDvbCi(); + static cDvbCi * getInstance(); + SEND_MSG_HOOK SendMessage; + void SetHook(SEND_MSG_HOOK _SendMessage) { SendMessage = _SendMessage; }; + bool CamPresent(int slot); + bool GetName(int slot, char * name); +}; + +#endif //__DVBCI_H diff --git a/lib/libcoolstream/init_cs.h b/lib/libcoolstream/init_cs.h new file mode 100644 index 000000000..17412fd69 --- /dev/null +++ b/lib/libcoolstream/init_cs.h @@ -0,0 +1,5 @@ +#ifndef __INIT_CS_H +#define __INIT_CS_H +void init_cs_api(); +void shutdown_cs_api(); +#endif diff --git a/lib/libcoolstream/playback_cs.h b/lib/libcoolstream/playback_cs.h new file mode 100644 index 000000000..71bad086c --- /dev/null +++ b/lib/libcoolstream/playback_cs.h @@ -0,0 +1,68 @@ +/*******************************************************************************/ +/* */ +/* libcoolstream/cszapper/demux.h */ +/* ZAP interface for neutrino frontend */ +/* */ +/* (C) 2008 CoolStream International */ +/* */ +/*******************************************************************************/ +#ifndef __PLAYBACK_CS_H +#define __PLAYBACK_CS_H + +#include + +#ifndef CS_PLAYBACK_PDATA +#define CS_PLAYBACK_PDATA void +#endif + +typedef enum { + PLAYMODE_TS = 0, + PLAYMODE_FILE, +} playmode_t; + +class cPlayback +{ + private: + int timeout; + pthread_cond_t read_cond; + pthread_mutex_t mutex; + CS_PLAYBACK_PDATA * privateData; + bool enabled; + bool paused; + bool playing; + int unit; + int nPlaybackFD; + int video_type; + int nPlaybackSpeed; + int mSpeed; + playmode_t playMode; + // + void Attach(void); + void Detach(void); + bool SetAVDemuxChannel(bool On, bool Video = true, bool Audio = true); + public: + void PlaybackNotify (int Event, void *pData, void *pTag); + void DMNotify(int Event, void *pTsBuf, void *Tag); + bool Open(playmode_t PlayMode); + void Close(void); + bool Start(char * filename, unsigned short vpid, int vtype, unsigned short apid, bool ac3); + bool Stop(void); + bool SetAPid(unsigned short pid, bool ac3); + bool SetSpeed(int speed); + bool GetSpeed(int &speed) const; + bool GetPosition(int &position, int &duration); + bool GetOffset(off64_t &offset); + bool SetPosition(int position, bool absolute = false); + bool IsPlaying(void) const { return playing; } + bool IsEnabled(void) const { return enabled; } + void * GetHandle(void); + void * GetDmHandle(void); + int GetCurrPlaybackSpeed(void) const { return nPlaybackSpeed; } + void FindAllPids(uint16_t *apids, unsigned short *ac3flags, uint16_t *numpida, std::string *language); + // + cPlayback(int num = 0); + ~cPlayback(); + +}; + +#endif diff --git a/lib/libcoolstream/pwrmngr.h b/lib/libcoolstream/pwrmngr.h new file mode 100644 index 000000000..0adbb267d --- /dev/null +++ b/lib/libcoolstream/pwrmngr.h @@ -0,0 +1,53 @@ +#ifndef __PWRMNGR_H__ +#define __PWRMNGR_H__ + +// -- cCpuFreqManager ---------------------------------------------------------- + +class cCpuFreqManager { +private: + unsigned long startCpuFreq; + unsigned long delta; +public: + void Up(void); + void Down(void); + void Reset(void); + // + bool SetCpuFreq(unsigned long CpuFreq); + bool SetDelta(unsigned long Delta); + unsigned long GetCpuFreq(void); + unsigned long GetDelta(void); + // + cCpuFreqManager(void); + +}; + +// -- cPowerManageger ---------------------------------------------------------- + +typedef enum +{ + PWR_INIT = 1, + PWR_FULL_ACTIVE, /* all devices/clocks up */ + PWR_ACTIVE_STANDBY, + PWR_PASSIVE_STANDBY, + PWR_INVALID +} PWR_STATE; + +class cPowerManager { +private: + bool init; + bool opened; + PWR_STATE powerState; + // + static void ApplicationCallback(void *hHandle, void *pUserData, signed long eEvent, void *pEventData, void *pTag) {} + bool SetState(PWR_STATE PowerState); +public: + bool Open(void); + void Close(void); + // + bool SetStandby(bool Active, bool Passive); + // + cPowerManager(void); + virtual ~cPowerManager(); +}; + +#endif // __PWRMNGR_H__ diff --git a/lib/libcoolstream/record_cs.h b/lib/libcoolstream/record_cs.h new file mode 100644 index 000000000..72b5c66f2 --- /dev/null +++ b/lib/libcoolstream/record_cs.h @@ -0,0 +1,38 @@ +/*******************************************************************************/ +/* */ +/* libcoolstream/cszapper/demux.h */ +/* ZAP interface for neutrino frontend */ +/* */ +/* (C) 2008 CoolStream International */ +/* */ +/*******************************************************************************/ +#ifndef __RECORD_CS_H +#define __RECORD_CS_H + +#include + +#ifndef CS_RECORD_PDATA +#define CS_RECORD_PDATA void +#endif + +class cRecord +{ + private: + CS_RECORD_PDATA * privateData; + bool enabled; + int num_apids; + int unit; + int nRecordFD; + + public: + cRecord(int num = 0); + ~cRecord(); + + bool Open(int numpids); + void Close(void); + bool Start(int fd, unsigned short vpid, unsigned short * apids, int numpids); + bool Stop(void); + void RecordNotify(int Event, void *pData); +}; + +#endif diff --git a/lib/libcoolstream/video_cs.h b/lib/libcoolstream/video_cs.h new file mode 100644 index 000000000..a667ac1c4 --- /dev/null +++ b/lib/libcoolstream/video_cs.h @@ -0,0 +1,203 @@ +#ifndef _VIDEO_CS_H +#define _VIDEO_CS_H + +#include +#include + +#include "cs_types.h" + +typedef enum { + ANALOG_SD_RGB_CINCH = 0x00, + ANALOG_SD_YPRPB_CINCH, + ANALOG_HD_RGB_CINCH, + ANALOG_HD_YPRPB_CINCH, + ANALOG_SD_RGB_SCART = 0x10, + ANALOG_SD_YPRPB_SCART, + ANALOG_HD_RGB_SCART, + ANALOG_HD_YPRPB_SCART, + ANALOG_SCART_MASK = 0x10, +} analog_mode_t; + +typedef enum { + VIDEO_FORMAT_MPEG2 = 0, + VIDEO_FORMAT_MPEG4, + VIDEO_FORMAT_VC1, + VIDEO_FORMAT_JPEG, + VIDEO_FORMAT_GIF, + VIDEO_FORMAT_PNG +} VIDEO_FORMAT; + +typedef enum { + VIDEO_SD = 0, + VIDEO_HD, + VIDEO_120x60i, + VIDEO_320x240i, + VIDEO_1440x800i, + VIDEO_360x288i +} VIDEO_DEFINITION; + +typedef enum { + VIDEO_FRAME_RATE_23_976 = 0, + VIDEO_FRAME_RATE_24, + VIDEO_FRAME_RATE_25, + VIDEO_FRAME_RATE_29_97, + VIDEO_FRAME_RATE_30, + VIDEO_FRAME_RATE_50, + VIDEO_FRAME_RATE_59_94, + VIDEO_FRAME_RATE_60 +} VIDEO_FRAME_RATE; + +typedef enum { + DISPLAY_AR_1_1, + DISPLAY_AR_4_3, + DISPLAY_AR_14_9, + DISPLAY_AR_16_9, + DISPLAY_AR_20_9, + DISPLAY_AR_RAW, +} DISPLAY_AR; + +typedef enum { + DISPLAY_AR_MODE_PANSCAN = 0, + DISPLAY_AR_MODE_LETTERBOX, + DISPLAY_AR_MODE_NONE, + DISPLAY_AR_MODE_PANSCAN2 +} DISPLAY_AR_MODE; + +typedef enum { + VIDEO_DB_DR_NEITHER = 0, + VIDEO_DB_ON, + VIDEO_DB_DR_BOTH +} VIDEO_DB_DR; + +typedef enum { + VIDEO_PLAY_STILL = 0, + VIDEO_PLAY_CLIP, + VIDEO_PLAY_TRICK, + VIDEO_PLAY_MOTION, + VIDEO_PLAY_MOTION_NO_SYNC +} VIDEO_PLAY_MODE; + +typedef enum { + VIDEO_STD_NTSC, + VIDEO_STD_SECAM, + VIDEO_STD_PAL, + VIDEO_STD_480P, + VIDEO_STD_576P, + VIDEO_STD_720P60, + VIDEO_STD_1080I60, + VIDEO_STD_720P50, + VIDEO_STD_1080I50, + VIDEO_STD_1080P30, + VIDEO_STD_1080P24, + VIDEO_STD_1080P25, + VIDEO_STD_AUTO +} VIDEO_STD; + +#ifndef CS_VIDEO_PDATA +#define CS_VIDEO_PDATA void +#endif + +class cVideo +{ + private: + CS_VIDEO_PDATA * privateData; + VIDEO_FORMAT StreamType; + VIDEO_DEFINITION VideoDefinition; + DISPLAY_AR DisplayAR; + VIDEO_PLAY_MODE SyncMode; + DISPLAY_AR_MODE ARMode; + VIDEO_DB_DR eDbDr; + DISPLAY_AR PictureAR; + VIDEO_FRAME_RATE FrameRate; + bool interlaced; + + unsigned int uDRMDisplayDelay; + unsigned int uVideoPTSDelay; + int StcPts; + bool started; + unsigned int bStandby; + bool blank; + bool playing; + bool auto_format; + int uFormatIndex; + int pic_width, pic_height; + int jpeg_width, jpeg_height; + int video_width, video_height; + + bool receivedDRMDelay; + bool receivedVideoDelay; + int cfd; // control driver fd + analog_mode_t analog_mode_cinch; + analog_mode_t analog_mode_scart; + + vfd_icon mode_icon; + int SelectAutoFormat(); + void ScalePic(); + public: + /* constructor & destructor */ + cVideo(int mode, void * hChannel, void * hBuffer); + ~cVideo(void); + + void * GetDRM(void); + void * GetTVEnc(); + void * GetTVEncSD(); + void * GetHandle(); + + void SetAudioHandle(void * handle); + /* aspect ratio */ + int getAspectRatio(void); + void getPictureInfo(int &width, int &height, int &rate); + int setAspectRatio(int aspect, int mode); + + /* cropping mode */ + int getCroppingMode(void); + int setCroppingMode(void); + + /* stream source */ + int getSource(void); + int setSource(void); + int GetStreamType(void) { return StreamType; }; + + /* blank on freeze */ + int getBlank(void); + int setBlank(int enable); + + /* get play state */ + int getPlayState(void); + void SetDRMDelay(unsigned int delay) { uDRMDisplayDelay = delay;}; + void SetVideoDelay(unsigned int delay) { uVideoPTSDelay = delay;}; + void HandleDRMMessage(int Event, void *pData); + void HandleVideoMessage(void * hHandle, int Event, void *pData); + VIDEO_DEFINITION GetVideoDef(void) { return VideoDefinition; } + + /* change video play state */ + int Start(void * PcrChannel, unsigned short PcrPid, unsigned short VideoPid, void * hChannel = NULL); + int Stop(bool blank = true); + bool Pause(void); + bool Resume(void); + int LipsyncAdjust(); + int64_t GetPTS(void); + + int Flush(void); + + /* set video_system */ + int SetVideoSystem(int video_system, bool remember = true); + int SetStreamType(VIDEO_FORMAT type); + void SetSyncMode(AVSYNC_TYPE mode); + void ShowPicture(const char * fname); + void StopPicture(); + void Standby(unsigned int bOn); + void Pig(int x, int y, int w, int h, int osd_w = 1064, int osd_h = 600); + void setContrast(int val); + bool ReceivedDRMDelay(void) { return receivedDRMDelay; } + bool ReceivedVideoDelay(void) { return receivedVideoDelay; } + void SetReceivedDRMDelay(bool Received) { receivedDRMDelay = Received; } + void SetReceivedVideoDelay(bool Received) { receivedVideoDelay = Received; } + void SetFastBlank(bool onoff); + void SetTVAV(bool onoff); + void SetWideScreen(bool onoff); + void SetVideoMode(analog_mode_t mode); + void SetDBDR(int dbdr); +}; + +#endif diff --git a/lib/libdvbsub/Debug.cpp b/lib/libdvbsub/Debug.cpp new file mode 100644 index 000000000..f2df3b672 --- /dev/null +++ b/lib/libdvbsub/Debug.cpp @@ -0,0 +1,41 @@ +#include +#include +#include "Debug.hpp" + +Debug::Debug() : + file_(""), level_(0), fp_(stdout) +{ +} + +Debug::~Debug() +{ + if (fp_ && fp_ != stdout) { + fclose(fp_); + } +} + +void Debug::set_level(int level) +{ + level_ = level; +} + +FILE* Debug::set_file(char* file) +{ + FILE* fp = fopen(file, "a"); + if (!fp) { + return NULL; + } + fp_ = fp; + return fp_; +} + +void Debug::print(int level, const char *fmt, ...) +{ + va_list argp; + va_start(argp, fmt); + // if (level < level_) { + vfprintf(fp_, fmt, argp); + // } + va_end(argp); +} + diff --git a/lib/libdvbsub/Debug.hpp b/lib/libdvbsub/Debug.hpp new file mode 100644 index 000000000..01a446101 --- /dev/null +++ b/lib/libdvbsub/Debug.hpp @@ -0,0 +1,28 @@ +#ifndef DEBUG_HPP_ +#define DEBUG_HPP_ + +#include + +class Debug { +public: + Debug(); + ~Debug(); + + void set_level(int level); + FILE* set_file(char* file); + void print(int level, const char *fmt, ...); + + static const int ERROR = 0; + static const int INFO = 1; + static const int VERBOSE = 2; + +private: + char* file_; + int level_; + FILE* fp_; + +}; + +extern Debug sub_debug; + +#endif diff --git a/lib/libdvbsub/Makefile.am b/lib/libdvbsub/Makefile.am new file mode 100644 index 000000000..8b19a9925 --- /dev/null +++ b/lib/libdvbsub/Makefile.am @@ -0,0 +1,11 @@ +INCLUDES = \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/lib/libcoolstream + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +noinst_LIBRARIES = libdvbsub.a + +libdvbsub_a_SOURCES = dvbsub.cpp dvbsubtitle.cpp \ + tools.cpp osd.cpp PacketQueue.cpp helpers.cpp Debug.cpp diff --git a/lib/libdvbsub/PacketQueue.cpp b/lib/libdvbsub/PacketQueue.cpp new file mode 100644 index 000000000..8fc6a8455 --- /dev/null +++ b/lib/libdvbsub/PacketQueue.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include "Debug.hpp" +#include "PacketQueue.hpp" + +PacketQueue::PacketQueue() +{ + pthread_mutex_init(&mutex, NULL); +} + +PacketQueue::~PacketQueue() +{ + while (queue.begin() != queue.end()) { + delete[] queue.front(); + queue.pop_front(); + } +} + +void PacketQueue::push(uint8_t* data) +{ + pthread_mutex_lock(&mutex); + + queue.push_back(data); + + pthread_mutex_unlock(&mutex); +} + +uint8_t* PacketQueue::pop() +{ + uint8_t* retval; + + pthread_mutex_lock(&mutex); + + retval = queue.front(); + queue.pop_front(); + + pthread_mutex_unlock(&mutex); + + return retval; +} + +size_t PacketQueue::size() +{ + return queue.size(); +} + diff --git a/lib/libdvbsub/PacketQueue.hpp b/lib/libdvbsub/PacketQueue.hpp new file mode 100644 index 000000000..f948ecdb2 --- /dev/null +++ b/lib/libdvbsub/PacketQueue.hpp @@ -0,0 +1,20 @@ +#ifndef PACKET_QUEUE_H_ +#define PACKET_QUEUE_H_ +#include +#include +#include + +class PacketQueue { +public: + PacketQueue(); + ~PacketQueue(); + void push(uint8_t* data); + uint8_t* pop(); + size_t size(); + +private: + std::list queue; + pthread_mutex_t mutex; +}; + +#endif diff --git a/lib/libdvbsub/dvbsub.cpp b/lib/libdvbsub/dvbsub.cpp new file mode 100644 index 000000000..0e57b7f0e --- /dev/null +++ b/lib/libdvbsub/dvbsub.cpp @@ -0,0 +1,369 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "Debug.hpp" +#include "PacketQueue.hpp" +#include "semaphore.h" +#include "reader_thread.hpp" +#include "dvbsub_thread.hpp" +#include "helpers.hpp" +#include "dvbsubtitle.h" + +#define Log2File printf +#define RECVBUFFER_STEPSIZE 1024 + +enum {NOERROR, NETWORK, DENIED, NOSERVICE, BOXTYPE, THREAD, ABOUT}; +enum {GET_VOLUME, SET_VOLUME, SET_MUTE, SET_CHANNEL}; + +Debug sub_debug; +static PacketQueue packet_queue; +//sem_t event_semaphore; + +static pthread_t threadReader; +static pthread_t threadDvbsub; + +static pthread_cond_t readerCond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t readerMutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t packetCond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t packetMutex = PTHREAD_MUTEX_INITIALIZER; + +static int reader_running; +static int dvbsub_running; +static int dvbsub_paused = true; +static int dvbsub_pid; +static int dvbsub_stopped; + +cDvbSubtitleConverter *dvbSubtitleConverter; + +int dvbsub_init() { + int trc; + + sub_debug.set_level(42); + + reader_running = true; + // reader-Thread starten + trc = pthread_create(&threadReader, 0, reader_thread, (void *) NULL); + if (trc) { + fprintf(stderr, "[dvb-sub] failed to create reader-thread (rc=%d)\n", trc); + reader_running = false; + return -1; + } + + dvbsub_running = true; + // subtitle decoder-Thread starten + trc = pthread_create(&threadDvbsub, 0, dvbsub_thread, NULL); + if (trc) { + fprintf(stderr, "[dvb-sub] failed to create dvbsub-thread (rc=%d)\n", trc); + dvbsub_running = false; + return -1; + } + + return(0); +} + +int dvbsub_pause() +{ + if(reader_running) { + if(dvbSubtitleConverter) { + dvbSubtitleConverter->Pause(true); + } + dvbsub_paused = true; + printf("[dvb-sub] paused\n"); + } + + return 0; +} + +int dvbsub_start(int pid) +{ + if(!dvbsub_paused && (pid == 0)) { + return 0; + } + + + if(pid) { + if(pid != dvbsub_pid) + dvbsub_pause(); + dvbsub_pid = pid; + } + + while(!dvbsub_stopped) + usleep(10); + + if(dvbsub_pid > 0) { + dvbsub_paused = false; + dvbSubtitleConverter->Pause(false); + pthread_mutex_lock(&readerMutex); + pthread_cond_broadcast(&readerCond); + pthread_mutex_unlock(&readerMutex); + printf("[dvb-sub] started with pid 0x%x\n", pid); + } + + return 0; +} + +int dvbsub_stop() +{ + dvbsub_pid = 0; + if(reader_running) { + dvbsub_pause(); + } + + return 0; +} + +int dvbsub_getpid() +{ + return dvbsub_pid; +} + +int dvbsub_close() +{ + if(threadReader) { + dvbsub_pause(); + reader_running = false; + pthread_mutex_lock(&readerMutex); + pthread_cond_broadcast(&readerCond); + pthread_mutex_unlock(&readerMutex); + pthread_join(threadReader, NULL); + threadReader = NULL; + } + if(threadDvbsub) { + dvbsub_running = false; + pthread_join(threadDvbsub, NULL); + threadDvbsub = NULL; + } + printf("[dvb-sub] stopped\n"); + + return 0; +} + +static cDemux * dmx; + +void* reader_thread(void *arg) +{ + uint8_t tmp[16]; /* actually 6 should be enough */ + int count; + int len; + uint16_t packlen; + uint8_t* buf; + + dmx = new cDemux(0); + dmx->Open(DMX_PES_CHANNEL, NULL, 64*1024); + + while (reader_running) { + if(dvbsub_paused) { + sub_debug.print(Debug::VERBOSE, "%s stopped\n", __FUNCTION__); + dmx->Stop(); + dvbsub_stopped = 1; + pthread_mutex_lock(&readerMutex ); + int ret = pthread_cond_wait(&readerCond, &readerMutex); + pthread_mutex_unlock(&readerMutex); + if (ret) { + sub_debug.print(Debug::VERBOSE, "pthread_cond_timedwait fails with %d\n", ret); + } + if(reader_running) { + dmx->pesFilter(dvbsub_pid); + dmx->Start(); + sub_debug.print(Debug::VERBOSE, "%s started: pid 0x%x\n", __FUNCTION__, dvbsub_pid); + dvbsub_stopped = 0; + } else + break; + } + + /* Wait for pes sync */ + len = 0; + count = 0; + int tosync = 0; + + while (!dvbsub_paused) { + //len = read(fd, &tmp[count], 3-count); + len = dmx->Read(&tmp[count], 3-count, 1000); + //printf("reader: fd = %d, len = %d\n", fd, len); + if(len <= 0) + continue; + else if (len == (3-count)) { + if ( (tmp[0] == 0x00) && + (tmp[1] == 0x00) && + (tmp[2] == 0x01)) { + count = 3; + break; + } + tosync += len; + } else { + count += len; + tosync += len; + continue; + } + tmp[0] = tmp[1]; + tmp[1] = tmp[2]; + count = 2; + } // while (!dvbsub_paused) + if(tosync) + printf("[subtitles] sync after %d bytes\n", tosync); + /* read stream id & length */ + while ((count < 6) && !dvbsub_paused) { + //printf("try to read 6-count = %d\n", 6-count); + //len = read(fd, &tmp[count], 6-count); + len = dmx->Read(&tmp[count], 6-count, 1000); + if (len < 0) { + continue; + } else { + count += len; + } + } + + packlen = getbits(tmp, 4*8, 16) + 6; + + buf = new uint8_t[packlen]; + + /* TODO: Throws an exception on out of memory */ + + /* copy tmp[0..5] => buf[0..5] */ + *(uint32_t*)buf = *(uint32_t*)tmp; + ((uint16_t*)buf)[2] = ((uint16_t*)tmp)[2]; + + /* read rest of the packet */ + while((count < packlen) && !dvbsub_paused) { + //len = read(fd, buf+count, packlen-count); + len = dmx->Read(buf+count, packlen-count, 1000); + if (len < 0) { + continue; + } else { + count += len; + } + } + if(!dvbsub_paused) { + printf("[subtitles] adding packet, len %d\n", count); + /* Packet now in memory */ + packet_queue.push(buf); + /* TODO: allocation exception */ + // wake up dvb thread + pthread_mutex_lock(&packetMutex); + pthread_cond_broadcast(&packetCond); + pthread_mutex_unlock(&packetMutex); + } else { + delete[] buf; + buf=NULL; + } + } + + dmx->Stop(); + delete dmx; + dmx = NULL; + + sub_debug.print(Debug::VERBOSE, "%s shutdown\n", __FUNCTION__); + pthread_exit(NULL); +} + +void* dvbsub_thread(void* arg) +{ + struct timespec restartWait; + struct timeval now; + + sub_debug.print(Debug::VERBOSE, "%s started\n", __FUNCTION__); + if (!dvbSubtitleConverter) + dvbSubtitleConverter = new cDvbSubtitleConverter; + + while(dvbsub_running) { + uint8_t* packet; + int64_t pts; + int pts_dts_flag; + int dataoffset; + int packlen; + + gettimeofday(&now, NULL); + TIMEVAL_TO_TIMESPEC(&now, &restartWait); + restartWait.tv_sec += 1; + + int ret = 0; + if(packet_queue.size() == 0) { + pthread_mutex_lock( &packetMutex ); + ret = pthread_cond_timedwait( &packetCond, &packetMutex, &restartWait ); + pthread_mutex_unlock( &packetMutex ); + } + if (ret == ETIMEDOUT) + { + dvbSubtitleConverter->Action(); + continue; + } + else if (ret == EINTR) + { + sub_debug.print(Debug::VERBOSE, "pthread_cond_timedwait fails with %s\n", strerror(errno)); + } + sub_debug.print(Debug::VERBOSE, "\nPES: Wakeup, queue size %d\n", packet_queue.size()); + if(dvbsub_paused) { + do { + packet = packet_queue.pop(); + if(packet) + delete[] packet; + } while(packet); + continue; + } + packet = packet_queue.pop(); + if (!packet) { + sub_debug.print(Debug::VERBOSE, "Error no packet found\n"); + continue; + } + packlen = (packet[4] << 8 | packet[5]) + 6; + + /* Get PTS */ + pts_dts_flag = getbits(packet, 7*8, 2); + if ((pts_dts_flag == 2) || (pts_dts_flag == 3)) { + pts = (uint64_t)getbits(packet, 9*8+4, 3) << 30; /* PTS[32..30] */ + pts |= getbits(packet, 10*8, 15) << 15; /* PTS[29..15] */ + pts |= getbits(packet, 12*8, 15); /* PTS[14..0] */ + } else { + pts = 0; + } + + dataoffset = packet[8] + 8 + 1; + if (packet[dataoffset] != 0x20) { + sub_debug.print(Debug::VERBOSE, "Not a dvb subtitle packet, discard it (len %d)\n", packlen); + for(int i = 0; i < packlen; i++) + printf("%02X ", packet[i]); + printf("\n"); + goto next_round; + } + + sub_debug.print(Debug::VERBOSE, "PES packet: len %d PTS=%Ld (%02d:%02d:%02d.%d)\n", + packlen, pts, (int)(pts/324000000), (int)((pts/5400000)%60), + (int)((pts/90000)%60), (int)(pts%90000)); + + if (packlen <= dataoffset + 3) { + sub_debug.print(Debug::INFO, "Packet too short, discard\n"); + goto next_round; + } + + if (packet[dataoffset + 2] == 0x0f) { + dvbSubtitleConverter->Convert(&packet[dataoffset + 2], + packlen - (dataoffset + 2), pts); + } else { + sub_debug.print(Debug::INFO, "End_of_PES is missing\n"); + } + dvbSubtitleConverter->Action(); + +next_round: + delete[] packet; + } + + delete dvbSubtitleConverter; + + sub_debug.print(Debug::VERBOSE, "%s shutdown\n", __FUNCTION__); + pthread_exit(NULL); +} + +void dvbsub_get_stc(int64_t * STC) +{ + if(dmx) + dmx->getSTC(STC); +} diff --git a/lib/libdvbsub/dvbsub_thread.hpp b/lib/libdvbsub/dvbsub_thread.hpp new file mode 100644 index 000000000..f4d240ab1 --- /dev/null +++ b/lib/libdvbsub/dvbsub_thread.hpp @@ -0,0 +1,8 @@ +#ifndef DVBSUB_THREAD_HPP_ +#define DVBSUB_THREAD_HPP_ + +#include + +void* dvbsub_thread(void* arg); + +#endif diff --git a/lib/libdvbsub/dvbsubtitle.cpp b/lib/libdvbsub/dvbsubtitle.cpp new file mode 100644 index 000000000..09c18b127 --- /dev/null +++ b/lib/libdvbsub/dvbsubtitle.cpp @@ -0,0 +1,1200 @@ +/* + * dvbsubtitle.c: DVB subtitles + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * Original author: Marco Schlüßler + * With some input from the "subtitle plugin" by Pekka Virtanen + * + * $Id: dvbsubtitle.cpp,v 1.1 2009/02/23 19:46:44 rhabarber1848 Exp $ + * dvbsubtitle for HD1 ported by Coolstream LTD + */ + +#include "dvbsubtitle.h" + +extern "C" { +#include +#include +#include +#include +} +#include "driver/framebuffer.h" + +#define FB "/dev/fb/0" +extern int fb_fd; +//struct fb_fix_screeninfo fix_screeninfo; +//struct fb_var_screeninfo var_screeninfo; + +#define PAGE_COMPOSITION_SEGMENT 0x10 +#define REGION_COMPOSITION_SEGMENT 0x11 +#define CLUT_DEFINITION_SEGMENT 0x12 +#define OBJECT_DATA_SEGMENT 0x13 +#define END_OF_DISPLAY_SET_SEGMENT 0x80 + +// Set these to 'true' for debug output: +#if 1 +static bool DebugConverter = true; +static bool DebugSegments = false; +static bool DebugPages = false; +static bool DebugRegions = false; +static bool DebugObjects = false; +static bool DebugCluts = false; +#else +static bool DebugConverter = true; +static bool DebugSegments = true; +static bool DebugPages = true; +static bool DebugRegions = true; +static bool DebugObjects = true; +static bool DebugCluts = true; +#endif + +#define dbgconverter(a...) if (DebugConverter) fprintf(stderr, a) +#define dbgsegments(a...) if (DebugSegments) fprintf(stderr, a) +#define dbgpages(a...) if (DebugPages) fprintf(stderr, a) +#define dbgregions(a...) if (DebugRegions) fprintf(stderr, a) +#define dbgobjects(a...) if (DebugObjects) fprintf(stderr, a) +#define dbgcluts(a...) if (DebugCluts) fprintf(stderr, a) + +int SubtitleFgTransparency = 0; +int SubtitleBgTransparency = 0; + +// --- cSubtitleClut --------------------------------------------------------- + +class cSubtitleClut : public cListObject { +private: + int clutId; + int version; + cPalette palette2; + cPalette palette4; + cPalette palette8; +public: + cSubtitleClut(int ClutId); + int ClutId(void) { return clutId; } + int Version(void) { return version; } + void SetVersion(int Version) { version = Version; } + void SetColor(int Bpp, int Index, tColor Color); + const cPalette *GetPalette(int Bpp); + }; + +cSubtitleClut::cSubtitleClut(int ClutId) +:palette2(2) +,palette4(4) +,palette8(8) +{ + clutId = ClutId; + version = -1; +} + +void cSubtitleClut::SetColor(int Bpp, int Index, tColor Color) +{ + switch (Bpp) { + case 2: palette2.SetColor(Index, Color); break; + case 4: palette4.SetColor(Index, Color); break; + case 8: palette8.SetColor(Index, Color); break; + default: esyslog("ERROR: wrong Bpp in cSubtitleClut::SetColor(%d, %d, %08X)", Bpp, Index, Color); + } +} + +const cPalette *cSubtitleClut::GetPalette(int Bpp) +{ + switch (Bpp) { + case 2: return &palette2; + case 4: return &palette4; + case 8: return &palette8; + default: esyslog("ERROR: wrong Bpp in cSubtitleClut::GetPalette(%d)", Bpp); + } + return &palette8; +} + +// --- cSubtitleObject ------------------------------------------------------- + +class cSubtitleObject : public cListObject { +private: + int objectId; + int version; + int codingMethod; + bool nonModifyingColorFlag; + int nibblePos; + uchar backgroundColor; + uchar foregroundColor; + int providerFlag; + int px; + int py; + cBitmap *bitmap; + void DrawLine(int x, int y, tIndex Index, int Length); + uchar Get2Bits(const uchar *Data, int &Index); + uchar Get4Bits(const uchar *Data, int &Index); + bool Decode2BppCodeString(const uchar *Data, int &Index, int&x, int y); + bool Decode4BppCodeString(const uchar *Data, int &Index, int&x, int y); + bool Decode8BppCodeString(const uchar *Data, int &Index, int&x, int y); +public: + cSubtitleObject(int ObjectId, cBitmap *Bitmap); + int ObjectId(void) { return objectId; } + int Version(void) { return version; } + int CodingMethod(void) { return codingMethod; } + bool NonModifyingColorFlag(void) { return nonModifyingColorFlag; } + void DecodeSubBlock(const uchar *Data, int Length, bool Even); + void SetVersion(int Version) { version = Version; } + void SetBackgroundColor(uchar BackgroundColor) { backgroundColor = BackgroundColor; } + void SetForegroundColor(uchar ForegroundColor) { foregroundColor = ForegroundColor; } + void SetNonModifyingColorFlag(bool NonModifyingColorFlag) { nonModifyingColorFlag = NonModifyingColorFlag; } + void SetCodingMethod(int CodingMethod) { codingMethod = CodingMethod; } + void SetPosition(int x, int y) { px = x; py = y; } + void SetProviderFlag(int ProviderFlag) { providerFlag = ProviderFlag; } + }; + +cSubtitleObject::cSubtitleObject(int ObjectId, cBitmap *Bitmap) +{ + objectId = ObjectId; + version = -1; + codingMethod = -1; + nonModifyingColorFlag = false; + nibblePos = 0; + backgroundColor = 0; + foregroundColor = 0; + providerFlag = -1; + px = py = 0; + bitmap = Bitmap; +} + +void cSubtitleObject::DecodeSubBlock(const uchar *Data, int Length, bool Even) +{ + int x = 0; + int y = Even ? 0 : 1; + for (int index = 0; index < Length; ) { + switch (Data[index++]) { + case 0x10: { + nibblePos = 8; + while (Decode2BppCodeString(Data, index, x, y) && index < Length) + ; + if (!nibblePos) + index++; + break; + } + case 0x11: { + nibblePos = 4; + while (Decode4BppCodeString(Data, index, x, y) && index < Length) + ; + if (!nibblePos) + index++; + break; + } + case 0x12: + while (Decode8BppCodeString(Data, index, x, y) && index < Length) + ; + break; + case 0x20: //TODO + dbgobjects("sub block 2 to 4 map"); + index += 4; + break; + case 0x21: //TODO + dbgobjects("sub block 2 to 8 map"); + index += 4; + break; + case 0x22: //TODO + dbgobjects("sub block 4 to 8 map"); + index += 16; + break; + case 0xF0: + x = 0; + y += 2; + break; + } + } +} + +void cSubtitleObject::DrawLine(int x, int y, tIndex Index, int Length) +{ + if (nonModifyingColorFlag && Index == 1) + return; + x += px; + y += py; + for (int pos = x; pos < x + Length; pos++) + bitmap->SetIndex(pos, y, Index); +} + +uchar cSubtitleObject::Get2Bits(const uchar *Data, int &Index) +{ + uchar result = Data[Index]; + if (!nibblePos) { + Index++; + nibblePos = 8; + } + nibblePos -= 2; + return (result >> nibblePos) & 0x03; +} + +uchar cSubtitleObject::Get4Bits(const uchar *Data, int &Index) +{ + uchar result = Data[Index]; + if (!nibblePos) { + Index++; + nibblePos = 4; + } + else { + result >>= 4; + nibblePos -= 4; + } + return result & 0x0F; +} + +bool cSubtitleObject::Decode2BppCodeString(const uchar *Data, int &Index, int &x, int y) +{ + int rl = 0; + int color = 0; + uchar code = Get2Bits(Data, Index); + if (code) { + color = code; + rl = 1; + } + else { + code = Get2Bits(Data, Index); + if (code & 2) { // switch_1 + rl = ((code & 1) << 2) + Get2Bits(Data, Index) + 3; + color = Get2Bits(Data, Index); + } + else if (code & 1) + rl = 1; //color 0 + else { + code = Get2Bits(Data, Index); + switch (code & 0x3) { //switch_3 + case 0: + return false; + case 1: + rl = 2; //color 0 + break; + case 2: + rl = (Get2Bits(Data, Index) << 2) + Get2Bits(Data, Index) + 12; + color = Get2Bits(Data, Index); + break; + case 3: + rl = (Get2Bits(Data, Index) << 6) + (Get2Bits(Data, Index) << 4) + (Get2Bits(Data, Index) << 2) + Get2Bits(Data, Index) + 29; + color = Get2Bits(Data, Index); + break; + } + } + } + DrawLine(x, y, color, rl); + x += rl; + return true; +} + +bool cSubtitleObject::Decode4BppCodeString(const uchar *Data, int &Index, int &x, int y) +{ + int rl = 0; + int color = 0; + uchar code = Get4Bits(Data, Index); + if (code) { + color = code; + rl = 1; + } + else { + code = Get4Bits(Data, Index); + if (code & 8) { // switch_1 + if (code & 4) { //switch_2 + switch (code & 3) { //switch_3 + case 0: // color 0 + rl = 1; + break; + case 1: // color 0 + rl = 2; + break; + case 2: + rl = Get4Bits(Data, Index) + 9; + color = Get4Bits(Data, Index); + break; + case 3: + rl = (Get4Bits(Data, Index) << 4) + Get4Bits(Data, Index) + 25; + color = Get4Bits(Data, Index); + break; + } + } + else { + rl = (code & 3) + 4; + color = Get4Bits(Data, Index); + } + } + else { // color 0 + if (!code) + return false; + rl = code + 2; + } + } + DrawLine(x, y, color, rl); + x += rl; + return true; +} + +bool cSubtitleObject::Decode8BppCodeString(const uchar *Data, int &Index, int &x, int y) +{ + int rl = 0; + int color = 0; + uchar code = Data[Index++]; + if (code) { + color = code; + rl = 1; + } + else { + code = Data[Index++]; + rl = code & 0x63; + if (code & 0x80) + color = Data[Index++]; + else if (!rl) + return false; //else color 0 + } + DrawLine(x, y, color, rl); + x += rl; + return true; +} + +// --- cSubtitleRegion ------------------------------------------------------- + +class cSubtitleRegion : public cListObject, public cBitmap { +private: + int regionId; + int version; + int clutId; + int horizontalAddress; + int verticalAddress; + int level; + cList objects; +public: + cSubtitleRegion(int RegionId); + int RegionId(void) { return regionId; } + int Version(void) { return version; } + int ClutId(void) { return clutId; } + int Level(void) { return level; } + int Depth(void) { return Bpp(); } + void FillRegion(tIndex Index); + cSubtitleObject *GetObjectById(int ObjectId, bool New = false); + int HorizontalAddress(void) { return horizontalAddress; } + int VerticalAddress(void) { return verticalAddress; } + void SetVersion(int Version) { version = Version; } + void SetClutId(int ClutId) { clutId = ClutId; } + void SetLevel(int Level); + void SetDepth(int Depth); + void SetHorizontalAddress(int HorizontalAddress) { horizontalAddress = HorizontalAddress; } + void SetVerticalAddress(int VerticalAddress) { verticalAddress = VerticalAddress; } + }; + +cSubtitleRegion::cSubtitleRegion(int RegionId) +:cBitmap(1, 1, 4) +{ + regionId = RegionId; + version = -1; + clutId = -1; + horizontalAddress = 0; + verticalAddress = 0; + level = 0; +} + +void cSubtitleRegion::FillRegion(tIndex Index) +{ + dbgregions("FillRegion %d\n", Index); + for (int y = 0; y < Height(); y++) { + for (int x = 0; x < Width(); x++) + SetIndex(x, y, Index); + } +} + +cSubtitleObject *cSubtitleRegion::GetObjectById(int ObjectId, bool New) +{ + cSubtitleObject *result = NULL; + for (cSubtitleObject *so = objects.First(); so; so = objects.Next(so)) { + if (so->ObjectId() == ObjectId) + result = so; + } + if (!result && New) { + result = new cSubtitleObject(ObjectId, this); + objects.Add(result); + } + return result; +} + +void cSubtitleRegion::SetLevel(int Level) +{ + if (Level > 0 && Level < 4) + level = 1 << Level; +} + +void cSubtitleRegion::SetDepth(int Depth) +{ + if (Depth > 0 && Depth < 4) + SetBpp(1 << Depth); +} + +// --- cDvbSubtitlePage ------------------------------------------------------ + +class cDvbSubtitlePage : public cListObject { +private: + int pageId; + int version; + int state; + int64_t pts; + int timeout; + cList cluts; +public: + cList regions; + cDvbSubtitlePage(int PageId); + virtual ~cDvbSubtitlePage(); + int PageId(void) { return pageId; } + int Version(void) { return version; } + int State(void) { return state; } + tArea *GetAreas(void); + cSubtitleClut *GetClutById(int ClutId, bool New = false); + cSubtitleObject *GetObjectById(int ObjectId); + cSubtitleRegion *GetRegionById(int RegionId, bool New = false); + int64_t Pts(void) const { return pts; } + int Timeout(void) { return timeout; } + void SetVersion(int Version) { version = Version; } + void SetPts(int64_t Pts) { pts = Pts; } + void SetState(int State); + void SetTimeout(int Timeout) { timeout = Timeout; } + void UpdateRegionPalette(cSubtitleClut *Clut); +}; + +cDvbSubtitlePage::cDvbSubtitlePage(int PageId) +{ + pageId = PageId; + version = -1; + state = -1; + pts = 0; + timeout = 0; +} + +cDvbSubtitlePage::~cDvbSubtitlePage() +{ +} + +tArea *cDvbSubtitlePage::GetAreas(void) +{ + if (regions.Count() > 0) { + tArea *Areas = new tArea[regions.Count()]; + tArea *a = Areas; + for (cSubtitleRegion *sr = regions.First(); sr; sr = regions.Next(sr)) { + a->x1 = sr->HorizontalAddress(); + a->y1 = sr->VerticalAddress(); + a->x2 = sr->HorizontalAddress() + sr->Width() - 1; + a->y2 = sr->VerticalAddress() + sr->Height() - 1; + a->bpp = sr->Bpp(); + while ((a->Width() & 3) != 0) + a->x2++; // aligns width to a multiple of 4, so 2, 4 and 8 bpp will work + a++; + } + return Areas; + } + return NULL; +} + +cSubtitleClut *cDvbSubtitlePage::GetClutById(int ClutId, bool New) +{ + cSubtitleClut *result = NULL; + for (cSubtitleClut *sc = cluts.First(); sc; sc = cluts.Next(sc)) { + if (sc->ClutId() == ClutId) + result = sc; + } + if (!result && New) { + result = new cSubtitleClut(ClutId); + cluts.Add(result); + } + return result; +} + +cSubtitleRegion *cDvbSubtitlePage::GetRegionById(int RegionId, bool New) +{ + cSubtitleRegion *result = NULL; + for (cSubtitleRegion *sr = regions.First(); sr; sr = regions.Next(sr)) { + if (sr->RegionId() == RegionId) + result = sr; + } + if (!result && New) { + result = new cSubtitleRegion(RegionId); + regions.Add(result); + } + return result; +} + +cSubtitleObject *cDvbSubtitlePage::GetObjectById(int ObjectId) +{ + cSubtitleObject *result = NULL; + for (cSubtitleRegion *sr = regions.First(); sr && !result; sr = regions.Next(sr)) + result = sr->GetObjectById(ObjectId); + return result; +} + +void cDvbSubtitlePage::SetState(int State) +{ + state = State; + switch (state) { + case 0: // normal case - page update + dbgpages("page update\n"); + break; + case 1: // aquisition point - page refresh + dbgpages("page refresh\n"); + regions.Clear(); + break; + case 2: // mode change - new page + dbgpages("new Page\n"); + regions.Clear(); + cluts.Clear(); + break; + case 3: // reserved + break; + } +} + +void cDvbSubtitlePage::UpdateRegionPalette(cSubtitleClut *Clut) +{ + for (cSubtitleRegion *sr = regions.First(); sr; sr = regions.Next(sr)) { + if (sr->ClutId() == Clut->ClutId()) + sr->Replace(*Clut->GetPalette(sr->Bpp())); + } +} + +// --- cDvbSubtitleAssembler ------------------------------------------------- + +class cDvbSubtitleAssembler { +private: + uchar *data; + int length; + int pos; + int size; + bool Realloc(int Size); +public: + cDvbSubtitleAssembler(void); + virtual ~cDvbSubtitleAssembler(); + void Reset(void); + unsigned char *Get(int &Length); + void Put(const uchar *Data, int Length); + }; + +cDvbSubtitleAssembler::cDvbSubtitleAssembler(void) +{ + data = NULL; + size = 0; + Reset(); +} + +cDvbSubtitleAssembler::~cDvbSubtitleAssembler() +{ + free(data); +} + +void cDvbSubtitleAssembler::Reset(void) +{ + length = 0; + pos = 0; +} + +bool cDvbSubtitleAssembler::Realloc(int Size) +{ + if (Size > size) { + size = max(Size, 2048); + data = (uchar *)realloc(data, size); + if (!data) { + esyslog("ERROR: can't allocate memory for subtitle assembler"); + length = 0; + size = 0; + return false; + } + } + return true; +} + +unsigned char *cDvbSubtitleAssembler::Get(int &Length) +{ + if (length > pos + 5) { + Length = (data[pos + 4] << 8) + data[pos + 5] + 6; + if (length >= pos + Length) { + unsigned char *result = data + pos; + pos += Length; + return result; + } + } + return NULL; +} + +void cDvbSubtitleAssembler::Put(const uchar *Data, int Length) +{ + if (Length && Realloc(length + Length)) { + memcpy(data + length, Data, Length); + length += Length; + } +} + +// --- cDvbSubtitleBitmaps --------------------------------------------------- + +class cDvbSubtitleBitmaps : public cListObject { +private: + int64_t pts; + int timeout; + tArea *areas; + int numAreas; + cVector bitmaps; +// int min_x, min_y, max_x, max_y; +public: + cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas); + ~cDvbSubtitleBitmaps(); + int64_t Pts(void) { return pts; } + int Timeout(void) { return timeout; } + void AddBitmap(cBitmap *Bitmap); + void Draw(); + void Clear(void); + }; + +cDvbSubtitleBitmaps::cDvbSubtitleBitmaps(int64_t Pts, int Timeout, tArea *Areas, int NumAreas) +{ + pts = Pts; + timeout = Timeout; + areas = Areas; + numAreas = NumAreas; +// max_x = max_y = 0; +// min_x = min_y = 0xFFFF; + //dbgconverter("cDvbSubtitleBitmaps::new: PTS: %lld\n", pts); +} + +cDvbSubtitleBitmaps::~cDvbSubtitleBitmaps() +{ + //dbgconverter("cDvbSubtitleBitmaps::delete: PTS: %lld\n", pts); + delete[] areas; + for (int i = 0; i < bitmaps.Size(); i++) + delete bitmaps[i]; +} + +void cDvbSubtitleBitmaps::AddBitmap(cBitmap *Bitmap) +{ + bitmaps.Append(Bitmap); + //dbgconverter("cDvbSubtitleBitmaps::AddBitmap size %d PTS: %lld\n", bitmaps.Size(), pts); +} + +static int min_x = 0xFFFF, min_y = 0xFFFF; +static int max_x = 0, max_y = 0; + +void cDvbSubtitleBitmaps::Clear() +{ + dbgconverter("cDvbSubtitleBitmaps::Draw: clear x=% d y= %d, w= %d, h= %d\n", min_x, min_y, max_x-min_x, max_y-min_y); + if(max_x && max_y) { + CFrameBuffer::getInstance()->paintBackgroundBoxRel (min_x, min_y, max_x-min_x, max_y-min_y); + max_x = max_y = 0; + } +} + +void cDvbSubtitleBitmaps::Draw() +{ + static tColor save_colors[MAXNUMCOLORS]; + + int stride = CFrameBuffer::getInstance()->getScreenWidth(true); + int wd = CFrameBuffer::getInstance()->getScreenWidth(); + int xs = CFrameBuffer::getInstance()->getScreenX(); + int yend = CFrameBuffer::getInstance()->getScreenY() + CFrameBuffer::getInstance()->getScreenHeight(); + uint32_t *sublfb = CFrameBuffer::getInstance()->getFrameBufferPointer(); + + dbgconverter("cDvbSubtitleBitmaps::Draw: %d bitmaps, x= %d, width= %d end=%d stride %d\n", bitmaps.Size(), xs, wd, yend, stride); + + if(bitmaps.Size()) + Clear(); //FIXME should we clear for new bitmaps set ? + + for (int i = 0; i < bitmaps.Size(); i++) { + + int NumColors; + const tColor *Colors = bitmaps[i]->Colors(NumColors); + if (Colors) { + memcpy(save_colors, Colors, sizeof(tColor)*NumColors); + } + /* center on screen */ + int xoff = xs + (wd - bitmaps[i]->Width())/2; + /* move to screen bottom */ + int yoff = (yend - (576-bitmaps[i]->Y0()))*stride; + int ys = yend - (576-bitmaps[i]->Y0()); + + dbgconverter("cDvbSubtitleBitmaps::Draw %d colors= %d at %d,%d (x=%d y=%d) size %dx%d\n", + i, NumColors, bitmaps[i]->X0(), bitmaps[i]->Y0(), xoff, ys, bitmaps[i]->Width(), bitmaps[i]->Height()); + + for (int y2 = 0; y2 < bitmaps[i]->Height(); y2++) { + int y = y2*stride + yoff; + for (int x2 = 0; x2 < bitmaps[i]->Width(); x2++) + { + int idx = *(bitmaps[i]->Data(x2, y2)); + *(sublfb + xoff + x2 + y) = save_colors[idx]; + } + } + if(min_x > xoff) + min_x = xoff; + if(min_y > ys) + min_y = ys; + if(max_x < (xoff + bitmaps[i]->Width())) + max_x = xoff + bitmaps[i]->Width(); + if(max_y < (ys+bitmaps[i]->Height())) + max_y = ys+bitmaps[i]->Height(); + } + if(bitmaps.Size()) + dbgconverter("cDvbSubtitleBitmaps::Draw: finish, min/max screen: x=% d y= %d, w= %d, h= %d\n", min_x, min_y, max_x-min_x, max_y-min_y); +} + +// --- cDvbSubtitleConverter ------------------------------------------------- + +int cDvbSubtitleConverter::setupLevel = 0; + +cDvbSubtitleConverter::cDvbSubtitleConverter(void) +//:cThread("subtitleConverter") +{ + dvbSubtitleAssembler = new cDvbSubtitleAssembler; + pages = new cList; + bitmaps = new cList; + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); + pthread_mutex_init(&mutex, &attr); + running = false; +// Start(); +} + +cDvbSubtitleConverter::~cDvbSubtitleConverter() +{ +// Cancel(3); + delete dvbSubtitleAssembler; + delete bitmaps; + delete pages; +} + +void cDvbSubtitleConverter::Lock(void) +{ + pthread_mutex_lock(&mutex); +} + +void cDvbSubtitleConverter::Unlock(void) +{ + pthread_mutex_unlock(&mutex); +} + +void cDvbSubtitleConverter::Pause(bool pause) +{ + dbgconverter("cDvbSubtitleConverter::Pause: %s\n", pause ? "pause" : "resume"); + if(pause) { + if(!running) + return; + Lock(); + running = false; + Clear(); + Unlock(); + Reset(); + } else { + running = true; + } +} + +void cDvbSubtitleConverter::Clear(void) +{ + if(max_x && max_y) { + dbgconverter("cDvbSubtitleConverter::Draw: clear x=% d y= %d, w= %d, h= %d\n", min_x, min_y, max_x-min_x, max_y-min_y); + CFrameBuffer::getInstance()->paintBackgroundBoxRel (min_x, min_y, max_x-min_x, max_y-min_y); + max_x = max_y = 0; + } +} + +void cDvbSubtitleConverter::SetupChanged(void) +{ + setupLevel++; +} + +void cDvbSubtitleConverter::Reset(void) +{ + dbgconverter("Converter reset -----------------------\n"); + dvbSubtitleAssembler->Reset(); + Lock(); + pages->Clear(); + bitmaps->Clear(); + Unlock(); +} + +int cDvbSubtitleConverter::ConvertFragments(const uchar *Data, int Length, int64_t pts) +{ + if (Data && Length > 8) { + int PayloadOffset = 0;//PesPayloadOffset(Data); + int SubstreamHeaderLength = 4; + bool ResetSubtitleAssembler = Data[PayloadOffset + 3] == 0x00; + + // Compatibility mode for old subtitles plugin: +#if 0 + if ((Data[7] & 0x01) && (Data[PayloadOffset - 3] & 0x81) == 0x01 && Data[PayloadOffset - 2] == 0x81) { + PayloadOffset--; + SubstreamHeaderLength = 1; + ResetSubtitleAssembler = Data[8] >= 5; + } +#endif + + if (Length > PayloadOffset + SubstreamHeaderLength) { +// int64_t pts = 0;//PesGetPts(Data); + //if (pts) + // dbgconverter("Converter PTS: %lld\n", pts); + const uchar *data = Data + PayloadOffset + SubstreamHeaderLength; // skip substream header + int length = Length - PayloadOffset - SubstreamHeaderLength; // skip substream header + if (ResetSubtitleAssembler) + dvbSubtitleAssembler->Reset(); + + if (length > 3) { + if (data[0] == 0x20 && data[1] == 0x00 && data[2] == 0x0F) + dvbSubtitleAssembler->Put(data + 2, length - 2); + else + dvbSubtitleAssembler->Put(data, length); + + int Count; + while (true) { + unsigned char *b = dvbSubtitleAssembler->Get(Count); + if (b && b[0] == 0x0F) { + if (ExtractSegment(b, Count, pts) == -1) + break; + } + else { + break; + } + } + } + } + return Length; + } + return 0; +} + +int cDvbSubtitleConverter::Convert(const uchar *Data, int Length, int64_t pts) +{ + if (Data && Length > 8) { + int PayloadOffset = 0;//PesPayloadOffset(Data); + if (Length > PayloadOffset) { +// int64_t pts = 0;//PesGetPts(Data); + //if (pts) + // dbgconverter("Converter PTS: %lld\n", pts); + const uchar *data = Data + PayloadOffset; + int length = Length - PayloadOffset; + if (length > 3) { + if (data[0] == 0x20 && data[1] == 0x00 && data[2] == 0x0F) { + data += 2; + length -= 2; + } + const uchar *b = data; + while (length > 0) { + if (b[0] == 0x0F) { + int n = ExtractSegment(b, length, pts); + if (n < 0) + break; + b += n; + length -= n; + } + else + break; + } + } + } + return Length; + } + return 0; +} + +#define LimitTo32Bit(n) (n & 0x00000000FFFFFFFFL) +#define MAXDELTA 40000 // max. reasonable PTS/STC delta in ms + +void dvbsub_get_stc(int64_t * STC); + +void cDvbSubtitleConverter::Action(void) +{ + static cTimeMs Timeout(0xFFFF*1000); + int WaitMs = 100; + + if(!running) + return; + + Lock(); + if (cDvbSubtitleBitmaps *sb = bitmaps->First()) { + int64_t STC; + dvbsub_get_stc(&STC); + int64_t Delta = 0; + + Delta = sb->Pts() - STC; + Delta /= 90; // STC and PTS are in 1/90000s + dbgconverter("cDvbSubtitleConverter::Action: PTS: %lld STC: %lld (%lld) timeout: %d\n", sb->Pts(), STC, Delta, sb->Timeout()); + + if(Delta > 1800) { + Unlock(); + usleep((Delta-500)*1000); + Lock(); + if(!running) { + Unlock(); + return; + } +#if 1 // debug + dvbsub_get_stc(&STC); + Delta = sb->Pts() - STC; + dbgconverter("cDvbSubtitleConverter::Action: PTS: %lld STC: %lld (%lld) timeout: %d after sleep\n", sb->Pts(), STC, Delta/90, sb->Timeout()); +#endif + } + Delta = 0; + if (Delta <= MAXDELTA) { + if (Delta <= 0) { + dbgconverter("cDvbSubtitleConverter::Action: Got %d bitmaps, showing #%d\n", bitmaps->Count(), sb->Index() + 1); + if (running) { + sb->Draw(); + Timeout.Set(sb->Timeout() * 100);//max: was 1000 and timeout seems in 1/10 of sec ?? + } + bitmaps->Del(sb, true); + } + else if (Delta < WaitMs) + WaitMs = Delta; + } + else + bitmaps->Del(sb, true); + } else { + //printf("cDvbSubtitleConverter::Action: timeout elapsed %lld\n", Timeout.Elapsed()); + if (Timeout.TimedOut()) { + //printf("************************************ cDvbSubtitleConverter::Action: we timed out\n"); + Timeout.Set(0xFFFF*1000); + Clear(); + } + } + Unlock(); +} + +tColor cDvbSubtitleConverter::yuv2rgb(int Y, int Cb, int Cr) +{ + int Ey, Epb, Epr; + int Eg, Eb, Er; + + Ey = (Y - 16); + Epb = (Cb - 128); + Epr = (Cr - 128); + /* ITU-R 709 */ + Er = max(min(((298 * Ey + 460 * Epr) / 256), 255), 0); + Eg = max(min(((298 * Ey - 55 * Epb - 137 * Epr) / 256), 255), 0); + Eb = max(min(((298 * Ey + 543 * Epb ) / 256), 255), 0); + + return (Er << 16) | (Eg << 8) | Eb; +} + +bool cDvbSubtitleConverter::AssertOsd(void) +{ + return 1;//osd || (osd = cOsdProvider::NewOsd(0, Setup.SubtitleOffset, OSD_LEVEL_SUBTITLES)); +} + +int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t Pts) +{ + if (Length > 5 && Data[0] == 0x0F) { + int segmentLength = (Data[4] << 8) + Data[5] + 6; + if (segmentLength > Length) + return -1; + int segmentType = Data[1]; + int pageId = (Data[2] << 8) + Data[3]; + cDvbSubtitlePage *page = NULL; +// LOCK_THREAD; + for (cDvbSubtitlePage *sp = pages->First(); sp; sp = pages->Next(sp)) { + if (sp->PageId() == pageId) { + page = sp; + break; + } + } + if (!page) { + page = new cDvbSubtitlePage(pageId); + pages->Add(page); + dbgpages("Create SubtitlePage %d (total pages = %d)\n", pageId, pages->Count()); + } + if (Pts) + page->SetPts(Pts); + switch (segmentType) { + case PAGE_COMPOSITION_SEGMENT: { + dbgsegments("PAGE_COMPOSITION_SEGMENT\n"); + int pageVersion = (Data[6 + 1] & 0xF0) >> 4; + if (pageVersion == page->Version()) + break; // no update + page->SetVersion(pageVersion); + page->SetTimeout(Data[6]); + page->SetState((Data[6 + 1] & 0x0C) >> 2); + page->regions.Clear(); + dbgpages("Update page id %d version %d pts %lld timeout %d state %d\n", pageId, page->Version(), page->Pts(), page->Timeout(), page->State()); + for (int i = 6 + 2; i < segmentLength; i += 6) { + cSubtitleRegion *region = page->GetRegionById(Data[i], true); + region->SetHorizontalAddress((Data[i + 2] << 8) + Data[i + 3]); + region->SetVerticalAddress((Data[i + 4] << 8) + Data[i + 5]); + } + break; + } + case REGION_COMPOSITION_SEGMENT: { + dbgsegments("REGION_COMPOSITION_SEGMENT\n"); + cSubtitleRegion *region = page->GetRegionById(Data[6]); + if (!region) + break; + int regionVersion = (Data[6 + 1] & 0xF0) >> 4; + if (regionVersion == region->Version()) + break; // no update + region->SetVersion(regionVersion); + bool regionFillFlag = (Data[6 + 1] & 0x08) >> 3; + int regionWidth = (Data[6 + 2] << 8) | Data[6 + 3]; + int regionHeight = (Data[6 + 4] << 8) | Data[6 + 5]; + region->SetSize(regionWidth, regionHeight); + region->SetLevel((Data[6 + 6] & 0xE0) >> 5); + region->SetDepth((Data[6 + 6] & 0x1C) >> 2); + region->SetClutId(Data[6 + 7]); + dbgregions("Region pageId %d id %d version %d fill %d width %d height %d level %d depth %d clutId %d\n", pageId, region->RegionId(), region->Version(), regionFillFlag, regionWidth, regionHeight, region->Level(), region->Depth(), region->ClutId()); + if (regionFillFlag) { + switch (region->Bpp()) { + case 2: region->FillRegion((Data[6 + 9] & 0x0C) >> 2); break; + case 4: region->FillRegion((Data[6 + 9] & 0xF0) >> 4); break; + case 8: region->FillRegion(Data[6 + 8]); break; + } + } + for (int i = 6 + 10; i < segmentLength; i += 6) { + cSubtitleObject *object = region->GetObjectById((Data[i] << 8) | Data[i + 1], true); + int objectType = (Data[i + 2] & 0xC0) >> 6; + object->SetCodingMethod(objectType); + object->SetProviderFlag((Data[i + 2] & 0x30) >> 4); + int objectHorizontalPosition = ((Data[i + 2] & 0x0F) << 8) | Data[i + 3]; + int objectVerticalPosition = ((Data[i + 4] & 0x0F) << 8) | Data[i + 5]; + object->SetPosition(objectHorizontalPosition, objectVerticalPosition); + if (objectType == 0x01 || objectType == 0x02) { + object->SetForegroundColor(Data[i + 6]); + object->SetBackgroundColor(Data[i + 7]); + i += 2; + } + } + break; + } + case CLUT_DEFINITION_SEGMENT: { + dbgsegments("CLUT_DEFINITION_SEGMENT\n"); + cSubtitleClut *clut = page->GetClutById(Data[6], true); + int clutVersion = (Data[6 + 1] & 0xF0) >> 4; + if (clutVersion == clut->Version()) + break; // no update + clut->SetVersion(clutVersion); + dbgcluts("Clut pageId %d id %d version %d\n", pageId, clut->ClutId(), clut->Version()); + for (int i = 6 + 2; i < segmentLength; i += 2) { + uchar clutEntryId = Data[i]; + bool fullRangeFlag = Data[i + 1] & 1; + uchar yval; + uchar crval; + uchar cbval; + uchar tval; + if (fullRangeFlag) { + yval = Data[i + 2]; + crval = Data[i + 3]; + cbval = Data[i + 4]; + tval = Data[i + 5]; + } + else { + yval = Data[i + 2] & 0xFC; + crval = (Data[i + 2] & 0x03) << 6; + crval |= (Data[i + 3] & 0xC0) >> 2; + cbval = (Data[i + 3] & 0x3C) << 2; + tval = (Data[i + 3] & 0x03) << 6; + } + tColor value = 0; + if (yval) { + value = yuv2rgb(yval, cbval, crval); + value |= ((10 - (clutEntryId ? SubtitleFgTransparency : SubtitleBgTransparency)) * (255 - tval) / 10) << 24; + } + int EntryFlags = Data[i + 1]; + dbgcluts("%2d %d %d %d %08X\n", clutEntryId, (EntryFlags & 0x80) ? 2 : 0, (EntryFlags & 0x40) ? 4 : 0, (EntryFlags & 0x20) ? 8 : 0, value); + if ((EntryFlags & 0x80) != 0) + clut->SetColor(2, clutEntryId, value); + if ((EntryFlags & 0x40) != 0) + clut->SetColor(4, clutEntryId, value); + if ((EntryFlags & 0x20) != 0) + clut->SetColor(8, clutEntryId, value); + i += fullRangeFlag ? 4 : 2; + } + dbgcluts("\n"); + page->UpdateRegionPalette(clut); + break; + } + case OBJECT_DATA_SEGMENT: { + dbgsegments("OBJECT_DATA_SEGMENT\n"); + cSubtitleObject *object = page->GetObjectById((Data[6] << 8) | Data[6 + 1]); + if (!object) + break; + int objectVersion = (Data[6 + 2] & 0xF0) >> 4; + if (objectVersion == object->Version()) + break; // no update + object->SetVersion(objectVersion); + int codingMethod = (Data[6 + 2] & 0x0C) >> 2; + object->SetNonModifyingColorFlag(Data[6 + 2] & 0x01); + dbgobjects("Object pageId %d id %d version %d method %d modify %d\n", pageId, object->ObjectId(), object->Version(), object->CodingMethod(), object->NonModifyingColorFlag()); + if (codingMethod == 0) { // coding of pixels + int i = 6 + 3; + int topFieldLength = (Data[i] << 8) | Data[i + 1]; + int bottomFieldLength = (Data[i + 2] << 8) | Data[i + 3]; + object->DecodeSubBlock(Data + i + 4, topFieldLength, true); + if (bottomFieldLength) + object->DecodeSubBlock(Data + i + 4 + topFieldLength, bottomFieldLength, false); + else + object->DecodeSubBlock(Data + i + 4, topFieldLength, false); + } + else if (codingMethod == 1) { // coded as a string of characters + //TODO implement textual subtitles + } + break; + } + case END_OF_DISPLAY_SET_SEGMENT: { + dbgsegments("END_OF_DISPLAY_SET_SEGMENT\n"); + FinishPage(page); + } + break; + default: + dbgsegments("*** unknown segment type: %02X\n", segmentType); + } + return segmentLength; + } + return -1; +} + +void cDvbSubtitleConverter::FinishPage(cDvbSubtitlePage *Page) +{ + if (!AssertOsd()) + return; + tArea *Areas = Page->GetAreas(); + int NumAreas = Page->regions.Count(); +#if 0 + int Bpp = 8; + bool Reduced = false; + + while (osd->CanHandleAreas(Areas, NumAreas) != oeOk) { + int HalfBpp = Bpp / 2; + if (HalfBpp >= 2) { + for (int i = 0; i < NumAreas; i++) { + if (Areas[i].bpp >= Bpp) { + Areas[i].bpp = HalfBpp; + Reduced = true; + } + } + Bpp = HalfBpp; + } + else + return; // unable to draw bitmaps + } + + if (Reduced) { + for (int i = 0; i < NumAreas; i++) { + cSubtitleRegion *sr = Page->regions.Get(i); + if (sr->Bpp() != Areas[i].bpp) { + if (sr->Level() <= Areas[i].bpp) { + //TODO this is untested - didn't have any such subtitle stream + cSubtitleClut *Clut = Page->GetClutById(sr->ClutId()); + if (Clut) { + dbgregions("reduce region %d bpp %d level %d area bpp %d\n", sr->RegionId(), sr->Bpp(), sr->Level(), Areas[i].bpp); + sr->ReduceBpp(*Clut->GetPalette(sr->Bpp())); + } + } + else { + dbgregions("condense region %d bpp %d level %d area bpp %d\n", sr->RegionId(), sr->Bpp(), sr->Level(), Areas[i].bpp); + sr->ShrinkBpp(Areas[i].bpp); + } + } + } + } +#endif + cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->Pts(), Page->Timeout(), Areas, NumAreas); + bitmaps->Add(Bitmaps); + for (cSubtitleRegion *sr = Page->regions.First(); sr; sr = Page->regions.Next(sr)) { + int posX = sr->HorizontalAddress(); + int posY = sr->VerticalAddress(); + cBitmap *bm = new cBitmap(sr->Width(), sr->Height(), sr->Bpp(), posX, posY); + bm->DrawBitmap(posX, posY, *sr); + Bitmaps->AddBitmap(bm); + } +} diff --git a/lib/libdvbsub/dvbsubtitle.h b/lib/libdvbsub/dvbsubtitle.h new file mode 100644 index 000000000..c6672492a --- /dev/null +++ b/lib/libdvbsub/dvbsubtitle.h @@ -0,0 +1,51 @@ +/* + * dvbsubtitle.h: DVB subtitles + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * Original author: Marco Schlüßler + * + * $Id: dvbsubtitle.h,v 1.1 2009/02/23 19:46:44 rhabarber1848 Exp $ + */ + +#ifndef __DVBSUBTITLE_H +#define __DVBSUBTITLE_H + +#include "osd.h" +#include "tools.h" + +class cDvbSubtitlePage; +class cDvbSubtitleAssembler; // for legacy PES recordings +class cDvbSubtitleBitmaps; + +class cDvbSubtitleConverter /*: public cThread */{ +private: + static int setupLevel; + cDvbSubtitleAssembler *dvbSubtitleAssembler; +// cOsd *osd; + cList *pages; + cList *bitmaps; + tColor yuv2rgb(int Y, int Cb, int Cr); + bool AssertOsd(void); + int ExtractSegment(const uchar *Data, int Length, int64_t Pts); + void FinishPage(cDvbSubtitlePage *Page); + bool running; + pthread_mutex_t mutex; +public: + cDvbSubtitleConverter(void); + virtual ~cDvbSubtitleConverter(); + void Action(void); + void Reset(void); + void Clear(void); + void Pause(bool pause); + void Lock(); + void Unlock(); + int ConvertFragments(const uchar *Data, int Length, int64_t pts); // for legacy PES recordings + int Convert(const uchar *Data, int Length, int64_t pts); + static void SetupChanged(void); + bool Running() { return running; }; +}; + + +#endif //__DVBSUBTITLE_H diff --git a/lib/libdvbsub/helpers.cpp b/lib/libdvbsub/helpers.cpp new file mode 100644 index 000000000..bed1d1a86 --- /dev/null +++ b/lib/libdvbsub/helpers.cpp @@ -0,0 +1,50 @@ +#include + +#include "helpers.hpp" + +/* Max 24 bit */ +uint32_t getbits(const uint8_t* buf, uint32_t offset, uint8_t len) +{ + const uint8_t* a = buf + (offset / 8); + uint32_t retval = 0; + uint32_t mask = 1; + + retval = ((*(a)<<8) | *(a+1)); + mask <<= len; + + if (len > 8) { + retval <<= 8; + retval |= *(a+2); + len -= 8; + } + if (len > 8) { + retval <<= 8; + retval |= *(a+3); + len -= 8; + } + if (len > 8) { + unsigned long long tmp = retval << 8; + tmp |= *(a+4); + tmp >>= ((8-(offset%8)) + (8-(len))); + return tmp & (mask -1); + } + + retval >>= ((8-(offset%8)) + (8-len)); + return retval & (mask -1); +} + +#if 0 +void hexdump(uint8_t* buf) +{ + int i; + for (i = 0 ; i < 16 ; i++) { + debug.print(Debug::DEBUG, "%02x ", buf[i]); + } + debug.print(Debug::DEBUG, "\n"); + for (i = 16 ; i < 32 ; i++) { + debug.print(Debug::DEBUG, "%02x ", buf[i]); + } + debug.print(Debug::DEBUG, "\n"); +} + +#endif diff --git a/lib/libdvbsub/helpers.hpp b/lib/libdvbsub/helpers.hpp new file mode 100644 index 000000000..3ad8e134a --- /dev/null +++ b/lib/libdvbsub/helpers.hpp @@ -0,0 +1,14 @@ +#ifndef HELPERS_H_ +#define HELPERS_H_ + +#include + +uint32_t getbits(const uint8_t* buf, uint32_t offset, uint8_t len); +void hexdump(uint8_t* buf); + +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +#endif diff --git a/lib/libdvbsub/osd.cpp b/lib/libdvbsub/osd.cpp new file mode 100644 index 000000000..3607e6901 --- /dev/null +++ b/lib/libdvbsub/osd.cpp @@ -0,0 +1,287 @@ +/* + * osd.c: Abstract On Screen Display layer + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: osd.cpp,v 1.1 2009/02/23 19:46:44 rhabarber1848 Exp $ + */ + +#include "dvbsubtitle.h" +//#include "device.h" + +#define PAGE_COMPOSITION_SEGMENT 0x10 +#define REGION_COMPOSITION_SEGMENT 0x11 +#define CLUT_DEFINITION_SEGMENT 0x12 +#define OBJECT_DATA_SEGMENT 0x13 +#define END_OF_DISPLAY_SET_SEGMENT 0x80 + +// --- cPalette -------------------------------------------------------------- + +cPalette::cPalette(int Bpp) +{ + SetBpp(Bpp); + SetAntiAliasGranularity(10, 10); +} + +void cPalette::SetAntiAliasGranularity(uint FixedColors, uint BlendColors) +{ + if (FixedColors >= MAXNUMCOLORS || BlendColors == 0) + antiAliasGranularity = MAXNUMCOLORS - 1; + else { + int ColorsForBlending = MAXNUMCOLORS - FixedColors; + int ColorsPerBlend = ColorsForBlending / BlendColors + 2; // +2 = the full foreground and background colors, which are amoung the fixed colors + antiAliasGranularity = double(MAXNUMCOLORS - 1) / (ColorsPerBlend - 1); + } +} + +void cPalette::Reset(void) +{ + numColors = 0; + modified = false; +} + +int cPalette::Index(tColor Color) +{ + // Check if color is already defined: + for (int i = 0; i < numColors; i++) { + if (color[i] == Color) + return i; + } + // No exact color, try a close one: + int i = ClosestColor(Color, 4); + if (i >= 0) + return i; + // No close one, try to define a new one: + if (numColors < maxColors) { + color[numColors++] = Color; + modified = true; + return numColors - 1; + } + // Out of colors, so any close color must do: + return ClosestColor(Color); +} + +void cPalette::SetBpp(int Bpp) +{ + bpp = Bpp; + maxColors = 1 << bpp; + Reset(); +} + +void cPalette::SetColor(int Index, tColor Color) +{ + if (Index < maxColors) { + if (numColors <= Index) { + numColors = Index + 1; + modified = true; + } + else + modified |= color[Index] != Color; + color[Index] = Color; + } +} + +const tColor *cPalette::Colors(int &NumColors) const +{ + NumColors = numColors; + return numColors ? color : NULL; +} + +void cPalette::Take(const cPalette &Palette, tIndexes *Indexes, tColor ColorFg, tColor ColorBg) +{ + for (int i = 0; i < Palette.numColors; i++) { + tColor Color = Palette.color[i]; + if (ColorFg || ColorBg) { + switch (i) { + case 0: Color = ColorBg; break; + case 1: Color = ColorFg; break; + } + } + int n = Index(Color); + if (Indexes) + (*Indexes)[i] = n; + } +} + +void cPalette::Replace(const cPalette &Palette) +{ + for (int i = 0; i < Palette.numColors; i++) + SetColor(i, Palette.color[i]); + numColors = Palette.numColors; + antiAliasGranularity = Palette.antiAliasGranularity; +} + +tColor cPalette::Blend(tColor ColorFg, tColor ColorBg, uint8_t Level) const +{ + if (antiAliasGranularity > 0) + Level = uint8_t(int(Level / antiAliasGranularity + 0.5) * antiAliasGranularity); + int Af = (ColorFg & 0xFF000000) >> 24; + int Rf = (ColorFg & 0x00FF0000) >> 16; + int Gf = (ColorFg & 0x0000FF00) >> 8; + int Bf = (ColorFg & 0x000000FF); + int Ab = (ColorBg & 0xFF000000) >> 24; + int Rb = (ColorBg & 0x00FF0000) >> 16; + int Gb = (ColorBg & 0x0000FF00) >> 8; + int Bb = (ColorBg & 0x000000FF); + int A = (Ab + (Af - Ab) * Level / 0xFF) & 0xFF; + int R = (Rb + (Rf - Rb) * Level / 0xFF) & 0xFF; + int G = (Gb + (Gf - Gb) * Level / 0xFF) & 0xFF; + int B = (Bb + (Bf - Bb) * Level / 0xFF) & 0xFF; + return (A << 24) | (R << 16) | (G << 8) | B; +} + +int cPalette::ClosestColor(tColor Color, int MaxDiff) const +{ + int n = 0; + int d = INT_MAX; + int A1 = (Color & 0xFF000000) >> 24; + int R1 = (Color & 0x00FF0000) >> 16; + int G1 = (Color & 0x0000FF00) >> 8; + int B1 = (Color & 0x000000FF); + for (int i = 0; i < numColors; i++) { + int A2 = (color[i] & 0xFF000000) >> 24; + int R2 = (color[i] & 0x00FF0000) >> 16; + int G2 = (color[i] & 0x0000FF00) >> 8; + int B2 = (color[i] & 0x000000FF); + int diff = (abs(A1 - A2) << 1) + (abs(R1 - R2) << 1) + (abs(G1 - G2) << 1) + (abs(B1 - B2) << 1); + if (diff < d) { + d = diff; + n = i; + } + } + return d <= MaxDiff ? n : -1; +} + +cBitmap::cBitmap(int Width, int Height, int Bpp, int X0, int Y0) +:cPalette(Bpp) +{ + bitmap = NULL; + x0 = X0; + y0 = Y0; + SetSize(Width, Height); +} + +cBitmap::~cBitmap() +{ + free(bitmap); +} + +void cBitmap::SetIndex(int x, int y, tIndex Index) +{ + if (bitmap) { + if (0 <= x && x < width && 0 <= y && y < height) { + if (bitmap[width * y + x] != Index) { + bitmap[width * y + x] = Index; + if (dirtyX1 > x) dirtyX1 = x; + if (dirtyY1 > y) dirtyY1 = y; + if (dirtyX2 < x) dirtyX2 = x; + if (dirtyY2 < y) dirtyY2 = y; + } + } + } +} + +void cBitmap::SetSize(int Width, int Height) +{ + if (bitmap && Width == width && Height == height) + return; + width = Width; + height = Height; + free(bitmap); + bitmap = NULL; + dirtyX1 = 0; + dirtyY1 = 0; + dirtyX2 = width - 1; + dirtyY2 = height - 1; + if (width > 0 && height > 0) { + bitmap = MALLOC(tIndex, width * height); + if (bitmap) + memset(bitmap, 0x00, width * height); + else + esyslog("ERROR: can't allocate bitmap!"); + } + else + esyslog("ERROR: invalid bitmap parameters (%d, %d)!", width, height); +} + +void cBitmap::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay) +{ + if (bitmap && Bitmap.bitmap && Intersects(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) { + if (Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) + Reset(); + x -= x0; + y -= y0; + if (ReplacePalette && Covers(x + x0, y + y0, x + x0 + Bitmap.Width() - 1, y + y0 + Bitmap.Height() - 1)) { + Replace(Bitmap); + for (int ix = 0; ix < Bitmap.width; ix++) { + for (int iy = 0; iy < Bitmap.height; iy++) { + if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0) + SetIndex(x + ix, y + iy, Bitmap.bitmap[Bitmap.width * iy + ix]); + } + } + } + else { + tIndexes Indexes; + Take(Bitmap, &Indexes, ColorFg, ColorBg); + for (int ix = 0; ix < Bitmap.width; ix++) { + for (int iy = 0; iy < Bitmap.height; iy++) { + if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0) + SetIndex(x + ix, y + iy, Indexes[int(Bitmap.bitmap[Bitmap.width * iy + ix])]); + } + } + } + } +} + + +bool cBitmap::Contains(int x, int y) const +{ + x -= x0; + y -= y0; + return 0 <= x && x < width && 0 <= y && y < height; +} + +bool cBitmap::Covers(int x1, int y1, int x2, int y2) const +{ + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + return x1 <= 0 && y1 <= 0 && x2 >= width - 1 && y2 >= height - 1; +} + +bool cBitmap::Intersects(int x1, int y1, int x2, int y2) const +{ + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + return !(x2 < 0 || x1 >= width || y2 < 0 || y1 >= height); +} + +bool cBitmap::Dirty(int &x1, int &y1, int &x2, int &y2) +{ + if (dirtyX2 >= 0) { + x1 = dirtyX1; + y1 = dirtyY1; + x2 = dirtyX2; + y2 = dirtyY2; + return true; + } + return false; +} + +void cBitmap::Clean(void) +{ + dirtyX1 = width; + dirtyY1 = height; + dirtyX2 = -1; + dirtyY2 = -1; +} + +const tIndex *cBitmap::Data(int x, int y) +{ + return &bitmap[y * width + x]; +} + diff --git a/lib/libdvbsub/osd.h b/lib/libdvbsub/osd.h new file mode 100644 index 000000000..9ac555e05 --- /dev/null +++ b/lib/libdvbsub/osd.h @@ -0,0 +1,147 @@ +/* + * osd.h: Abstract On Screen Display layer + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * Original author: Marco Schlüßler + * + * $Id: osd.h,v 1.1 2009/02/23 19:46:44 rhabarber1848 Exp $ + */ + +#ifndef __OSD_H +#define __OSD_H + +#include "tools.h" +#include + +#define MAXNUMCOLORS 256 + +typedef uint32_t tColor; +typedef unsigned char tIndex; + +class cPalette { +private: + tColor color[MAXNUMCOLORS]; + int bpp; + int maxColors, numColors; + bool modified; + double antiAliasGranularity; +protected: + typedef tIndex tIndexes[MAXNUMCOLORS]; +public: + cPalette(int Bpp = 8); + ///< Initializes the palette with the given color depth. + void SetAntiAliasGranularity(uint FixedColors, uint BlendColors); + ///< Allows the system to optimize utilization of the limited color + ///< palette entries when generating blended colors for anti-aliasing. + ///< FixedColors is the maximum number of colors used, and BlendColors + ///< is the maximum number of foreground/background color combinations + ///< used with anti-aliasing. If this function is not called with + ///< useful values, the palette may be filled up with many shades of + ///< a single color combination, and may not be able to serve all + ///< requested colors. By default the palette assumes there will be + ///< 10 fixed colors and 10 color combinations. + int Bpp(void) const { return bpp; } + void Reset(void); + ///< Resets the palette, making it contain no colors. + int Index(tColor Color); + ///< Returns the index of the given Color (the first color has index 0). + ///< If Color is not yet contained in this palette, it will be added if + ///< there is a free slot. If the color can't be added to this palette, + ///< the closest existing color will be returned. + tColor Color(int Index) const { return Index < maxColors ? color[Index] : 0; } + ///< Returns the color at the given Index. If Index is outside the valid + ///< range, 0 will be returned. + void SetBpp(int Bpp); + ///< Sets the color depth of this palette to the given value. + ///< The palette contents will be reset, so that it contains no colors. + void SetColor(int Index, tColor Color); + ///< Sets the palette entry at Index to Color. If Index is larger than + ///< the number of currently used entries in this palette, the entries + ///< in between will have undefined values. + const tColor *Colors(int &NumColors) const; + ///< Returns a pointer to the complete color table and stores the + ///< number of valid entries in NumColors. If no colors have been + ///< stored yet, NumColors will be set to 0 and the function will + ///< return NULL. + void Take(const cPalette &Palette, tIndexes *Indexes = NULL, tColor ColorFg = 0, tColor ColorBg = 0); + ///< Takes the colors from the given Palette and adds them to this palette, + ///< using existing entries if possible. If Indexes is given, it will be + ///< filled with the index values that each color of Palette has in this + ///< palette. If either of ColorFg or ColorBg is not zero, the first color + ///< in Palette will be taken as ColorBg, and the second color will become + ///< ColorFg. + void Replace(const cPalette &Palette); + ///< Replaces the colors of this palette with the colors from the given + ///< palette. + tColor Blend(tColor ColorFg, tColor ColorBg, uint8_t Level) const; + ///< Determines a color that consists of a linear blend between ColorFg + ///< and ColorBg. If Level is 0, the result is ColorBg, if it is 255, + ///< the result is ColorFg. If SetAntiAliasGranularity() has been called previously, + ///< Level will be mapped to a limited range of levels that allow to make best + ///< use of the palette entries. + int ClosestColor(tColor Color, int MaxDiff = INT_MAX) const; + ///< Returns the index of a color in this palette that is closest to the given + ///< Color. MaxDiff can be used to control the maximum allowed color difference. + ///< If no color with a maximum difference of MaxDiff can be found, -1 will + ///< be returned. With the default value of INT_MAX, there will always be + ///< a valid color index returned, but the color may be completely different. +}; + +class cBitmap : public cPalette { +private: + tIndex *bitmap; + int x0, y0; + int width, height; + int dirtyX1, dirtyY1, dirtyX2, dirtyY2; +public: + cBitmap(int Width, int Height, int Bpp, int X0 = 0, int Y0 = 0); + ///< Creates a bitmap with the given Width, Height and color depth (Bpp). + ///< X0 and Y0 define the offset at which this bitmap will be located on the OSD. + ///< All coordinates given in the other functions will be relative to + ///< this offset (unless specified otherwise). + cBitmap(const char *FileName); + ///< Creates a bitmap and loads an XPM image from the given file. + virtual ~cBitmap(); + int X0(void) const { return x0; } + int Y0(void) const { return y0; } + int Width(void) const { return width; } + int Height(void) const { return height; } + void SetSize(int Width, int Height); + ///< Sets the size of this bitmap to the given values. Any previous + ///< contents of the bitmap will be lost. If Width and Height are the same + ///< as the current values, nothing will happen and the bitmap remains + ///< unchanged. + void SetIndex(int x, int y, tIndex Index); + ///< Sets the index at the given coordinates to Index. + ///< Coordinates are relative to the bitmap's origin. + void DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool ReplacePalette = false, bool Overlay = false); + ///< Sets the pixels in this bitmap with the data from the given + ///< Bitmap, putting the upper left corner of the Bitmap at (x, y). + ///< If ColorFg or ColorBg is given, the first palette entry of the Bitmap + ///< will be mapped to ColorBg and the second palette entry will be mapped to + ///< ColorFg (palette indexes are defined so that 0 is the background and + ///< 1 is the foreground color). ReplacePalette controls whether the target + ///< area shall have its palette replaced with the one from Bitmap. + ///< If Overlay is true, any pixel in Bitmap that has color index 0 will + ///< not overwrite the corresponding pixel in the target area. + const tIndex *Data(int x, int y); + ///< Returns the address of the index byte at the given coordinates. + + bool Contains(int x, int y) const; + bool Covers(int x1, int y1, int x2, int y2) const; + bool Intersects(int x1, int y1, int x2, int y2) const; + bool Dirty(int &x1, int &y1, int &x2, int &y2); + void Clean(void); +}; + +struct tArea { + int x1, y1, x2, y2; + int bpp; + int Width(void) const { return x2 - x1 + 1; } + int Height(void) const { return y2 - y1 + 1; } + bool Intersects(const tArea &Area) const { return !(x2 < Area.x1 || x1 > Area.x2 || y2 < Area.y1 || y1 > Area.y2); } +}; + +#endif //__OSD_H diff --git a/lib/libdvbsub/reader_thread.hpp b/lib/libdvbsub/reader_thread.hpp new file mode 100644 index 000000000..15c1b9f5b --- /dev/null +++ b/lib/libdvbsub/reader_thread.hpp @@ -0,0 +1,6 @@ +#ifndef READER_THREAD_HPP_ +#define READER_THREAD_HPP_ + +void* reader_thread(void *arg); + +#endif diff --git a/lib/libdvbsub/tools.cpp b/lib/libdvbsub/tools.cpp new file mode 100644 index 000000000..bd432bd16 --- /dev/null +++ b/lib/libdvbsub/tools.cpp @@ -0,0 +1,267 @@ +/* + * tools.c: Various tools + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * vdr: Id: tools.c 2.0 2008/03/05 17:23:47 kls Exp + */ + +#include "tools.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int SysLogLevel = 3; + +#define MAXSYSLOGBUF 256 + +// --- cTimeMs --------------------------------------------------------------- + +cTimeMs::cTimeMs(int Ms) +{ + Set(Ms); +} + +uint64_t cTimeMs::Now(void) +{ +#if 0 && _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) +#define MIN_RESOLUTION 5 // ms + static bool initialized = false; + static bool monotonic = false; + struct timespec tp; + if (!initialized) { + // check if monotonic timer is available and provides enough accurate resolution: + if (clock_getres(CLOCK_MONOTONIC, &tp) == 0) { + long Resolution = tp.tv_nsec; + // require a minimum resolution: + if (tp.tv_sec == 0 && tp.tv_nsec <= MIN_RESOLUTION * 1000000) { + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) { + dsyslog("cTimeMs: using monotonic clock (resolution is %ld ns)", Resolution); + monotonic = true; + } + else + esyslog("cTimeMs: clock_gettime(CLOCK_MONOTONIC) failed"); + } + else + dsyslog("cTimeMs: not using monotonic clock - resolution is too bad (%ld s %ld ns)", tp.tv_sec, tp.tv_nsec); + } + else + esyslog("cTimeMs: clock_getres(CLOCK_MONOTONIC) failed"); + initialized = true; + } + if (monotonic) { + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) + return (uint64_t(tp.tv_sec)) * 1000 + tp.tv_nsec / 1000000; + esyslog("cTimeMs: clock_gettime(CLOCK_MONOTONIC) failed"); + monotonic = false; + // fall back to gettimeofday() + } +#else +# warning Posix monotonic clock not available +#endif + struct timeval t; + if (gettimeofday(&t, NULL) == 0) + return (uint64_t(t.tv_sec)) * 1000 + t.tv_usec / 1000; + return 0; +} + +void cTimeMs::Set(int Ms) +{ + begin = Now() + Ms; +} + +bool cTimeMs::TimedOut(void) +{ + return Now() >= begin; +} + +uint64_t cTimeMs::Elapsed(void) +{ + return Now() - begin; +} + +// --- cListObject ----------------------------------------------------------- + +cListObject::cListObject(void) +{ + prev = next = NULL; +} + +cListObject::~cListObject() +{ +} + +void cListObject::Append(cListObject *Object) +{ + next = Object; + Object->prev = this; +} + +void cListObject::Insert(cListObject *Object) +{ + prev = Object; + Object->next = this; +} + +void cListObject::Unlink(void) +{ + if (next) + next->prev = prev; + if (prev) + prev->next = next; + next = prev = NULL; +} + +int cListObject::Index(void) const +{ + cListObject *p = prev; + int i = 0; + + while (p) { + i++; + p = p->prev; + } + return i; +} + +// --- cListBase ------------------------------------------------------------- + +cListBase::cListBase(void) +{ + objects = lastObject = NULL; + count = 0; +} + +cListBase::~cListBase() +{ + Clear(); +} + +void cListBase::Add(cListObject *Object, cListObject *After) +{ + if (After && After != lastObject) { + After->Next()->Insert(Object); + After->Append(Object); + } + else { + if (lastObject) + lastObject->Append(Object); + else + objects = Object; + lastObject = Object; + } + count++; +} + +void cListBase::Ins(cListObject *Object, cListObject *Before) +{ + if (Before && Before != objects) { + Before->Prev()->Append(Object); + Before->Insert(Object); + } + else { + if (objects) + objects->Insert(Object); + else + lastObject = Object; + objects = Object; + } + count++; +} + +void cListBase::Del(cListObject *Object, bool DeleteObject) +{ + if (Object == objects) + objects = Object->Next(); + if (Object == lastObject) + lastObject = Object->Prev(); + Object->Unlink(); + if (DeleteObject) { + delete Object; + count--; + } +} + +void cListBase::Move(int From, int To) +{ + Move(Get(From), Get(To)); +} + +void cListBase::Move(cListObject *From, cListObject *To) +{ + if (From && To) { + if (From->Index() < To->Index()) + To = To->Next(); + if (From == objects) + objects = From->Next(); + if (From == lastObject) + lastObject = From->Prev(); + From->Unlink(); + if (To) { + if (To->Prev()) + To->Prev()->Append(From); + From->Append(To); + } + else { + lastObject->Append(From); + lastObject = From; + } + if (!From->Prev()) + objects = From; + } +} + +void cListBase::Clear(void) +{ + while (objects) { + cListObject *object = objects->Next(); + delete objects; + objects = object; + } + objects = lastObject = NULL; + count = 0; +} + +cListObject *cListBase::Get(int Index) const +{ + if (Index < 0) + return NULL; + cListObject *object = objects; + while (object && Index-- > 0) + object = object->Next(); + return object; +} + +static int CompareListObjects(const void *a, const void *b) +{ + const cListObject *la = *(const cListObject **)a; + const cListObject *lb = *(const cListObject **)b; + return la->Compare(*lb); +} + +void cListBase::Sort(void) +{ + int n = Count(); + cListObject *a[n]; + cListObject *object = objects; + int i = 0; + while (object && i < n) { + a[i++] = object; + object = object->Next(); + } + qsort(a, n, sizeof(cListObject *), CompareListObjects); + objects = lastObject = NULL; + for (i = 0; i < n; i++) { + a[i]->Unlink(); + count--; + Add(a[i]); + } +} diff --git a/lib/libdvbsub/tools.h b/lib/libdvbsub/tools.h new file mode 100644 index 000000000..0e509790a --- /dev/null +++ b/lib/libdvbsub/tools.h @@ -0,0 +1,193 @@ +/* + * tools.h: Various tools + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: tools.h,v 1.1 2009/02/23 19:46:44 rhabarber1848 Exp $ + */ + +#ifndef __TOOLS_H +#define __TOOLS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned char uchar; + +extern int SysLogLevel; + +#if 0 +#define esyslog(a...) void( (SysLogLevel > 0) ? syslog_with_tid(LOG_ERR, a) : void() ) +#define isyslog(a...) void( (SysLogLevel > 1) ? syslog_with_tid(LOG_ERR, a) : void() ) +#define dsyslog(a...) void( (SysLogLevel > 2) ? syslog_with_tid(LOG_ERR, a) : void() ) +#else +#define esyslog printf +#define isyslog printf +#define dsyslog printf +#endif + +#define LOG_ERROR esyslog("ERROR (%s,%d): %m", __FILE__, __LINE__) +#define LOG_ERROR_STR(s) esyslog("ERROR: %s: %m", s) + +#define SECSINDAY 86400 + +#define KILOBYTE(n) ((n) * 1024) +#define MEGABYTE(n) ((n) * 1024 * 1024) + +#define MALLOC(type, size) (type *)malloc(sizeof(type) * (size)) + +#define DELETENULL(p) (delete (p), p = NULL) + +#define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls +#define FATALERRNO (errno && errno != EAGAIN && errno != EINTR) + +#ifndef __STL_CONFIG_H // in case some plugin needs to use the STL +template inline T min(T a, T b) { return a <= b ? a : b; } +template inline T max(T a, T b) { return a >= b ? a : b; } +template inline int sgn(T a) { return a < 0 ? -1 : a > 0 ? 1 : 0; } +template inline void swap(T &a, T &b) { T t = a; a = b; b = t; } +#endif + +class cTimeMs { +private: + uint64_t begin; +public: + cTimeMs(int Ms = 0); + ///< Creates a timer with ms resolution and an initial timeout of Ms. + static uint64_t Now(void); + void Set(int Ms = 0); + bool TimedOut(void); + uint64_t Elapsed(void); + }; + +class cListObject { +private: + cListObject *prev, *next; +public: + cListObject(void); + virtual ~cListObject(); + virtual int Compare(const cListObject &ListObject) const { return 0; } + ///< Must return 0 if this object is equal to ListObject, a positive value + ///< if it is "greater", and a negative value if it is "smaller". + void Append(cListObject *Object); + void Insert(cListObject *Object); + void Unlink(void); + int Index(void) const; + cListObject *Prev(void) const { return prev; } + cListObject *Next(void) const { return next; } + }; + +class cListBase { +protected: + cListObject *objects, *lastObject; + cListBase(void); + int count; +public: + virtual ~cListBase(); + void Add(cListObject *Object, cListObject *After = NULL); + void Ins(cListObject *Object, cListObject *Before = NULL); + void Del(cListObject *Object, bool DeleteObject = true); + virtual void Move(int From, int To); + void Move(cListObject *From, cListObject *To); + virtual void Clear(void); + cListObject *Get(int Index) const; + int Count(void) const { return count; } + void Sort(void); + }; + +template class cList : public cListBase { +public: + T *Get(int Index) const { return (T *)cListBase::Get(Index); } + T *First(void) const { return (T *)objects; } + T *Last(void) const { return (T *)lastObject; } + T *Prev(const T *object) const { return (T *)object->cListObject::Prev(); } // need to call cListObject's members to + T *Next(const T *object) const { return (T *)object->cListObject::Next(); } // avoid ambiguities in case of a "list of lists" + }; + +template class cVector { +private: + mutable int allocated; + mutable int size; + mutable T *data; + cVector(const cVector &Vector) {} // don't copy... + cVector &operator=(const cVector &Vector) { return *this; } // ...or assign this! + void Realloc(int Index) const + { + if (++Index > allocated) { + data = (T *)realloc(data, Index * sizeof(T)); + for (int i = allocated; i < Index; i++) + data[i] = T(0); + allocated = Index; + } + } +public: + cVector(int Allocated = 10) + { + allocated = 0; + size = 0; + data = NULL; + Realloc(Allocated); + } + virtual ~cVector() { free(data); } + T& At(int Index) const + { + Realloc(Index); + if (Index >= size) + size = Index + 1; + return data[Index]; + } + const T& operator[](int Index) const + { + return At(Index); + } + T& operator[](int Index) + { + return At(Index); + } + int Size(void) const { return size; } + virtual void Insert(T Data, int Before = 0) + { + if (Before < size) { + Realloc(size); + memmove(&data[Before + 1], &data[Before], (size - Before) * sizeof(T)); + size++; + data[Before] = Data; + } + else + Append(Data); + } + virtual void Append(T Data) + { + if (size >= allocated) + Realloc(allocated * 4 / 2); // increase size by 50% + data[size++] = Data; + } + virtual void Remove(int Index) + { + if (Index < size - 1) + memmove(&data[Index], &data[Index + 1], (size - Index) * sizeof(T)); + size--; + } + virtual void Clear(void) + { + size = 0; + } + void Sort(__compar_fn_t Compare) + { + qsort(data, size, sizeof(T), Compare); + } + }; + +#endif //__TOOLS_H diff --git a/lib/libeventserver/Makefile.am b/lib/libeventserver/Makefile.am new file mode 100644 index 000000000..d7ae11165 --- /dev/null +++ b/lib/libeventserver/Makefile.am @@ -0,0 +1,5 @@ +noinst_LIBRARIES = libtuxbox-eventserver.a + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +libtuxbox_eventserver_a_SOURCES = eventserver.cpp diff --git a/lib/libeventserver/eventserver.cpp b/lib/libeventserver/eventserver.cpp new file mode 100644 index 000000000..0ce98e244 --- /dev/null +++ b/lib/libeventserver/eventserver.cpp @@ -0,0 +1,115 @@ +/* + + $Header: /cvs/tuxbox/apps/misc/libs/libeventserver/eventserver.cpp,v 1.12 2003/03/14 06:25:49 obi Exp $ + + Event-Server - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include + +#include "eventserver.h" + +void CEventServer::registerEvent2(const unsigned int eventID, const unsigned int ClientID, const std::string udsName) +{ + strcpy(eventData[eventID][ClientID].udsName, udsName.c_str()); +} + +void CEventServer::registerEvent(const int fd) +{ + commandRegisterEvent msg; + + int readresult= read(fd, &msg, sizeof(msg)); + if ( readresult<= 0 ) + perror("[eventserver]: read"); +// printf("[eventserver]: read from %d %x bytes %d/%d\n", fd, errno, readresult, sizeof(msg)); +// printf("[eventserver]: registered event (%d) to: %d - %s\n", msg.eventID, msg.clientID, msg.udsName); + registerEvent2(msg.eventID, msg.clientID, msg.udsName); +} + +void CEventServer::unRegisterEvent2(const unsigned int eventID, const unsigned int ClientID) +{ + eventData[eventID].erase( ClientID ); +} + +void CEventServer::unRegisterEvent(const int fd) +{ + commandUnRegisterEvent msg; + read(fd, &msg, sizeof(msg)); + unRegisterEvent2(msg.eventID, msg.clientID); +} + +void CEventServer::sendEvent(const unsigned int eventID, const initiators initiatorID, const void* eventbody, const unsigned int eventbodysize) +{ + eventClientMap notifyClients = eventData[eventID]; + + for(eventClientMap::iterator pos = notifyClients.begin(); pos != notifyClients.end(); pos++) + { + //allen clients ein event schicken + eventClient client = pos->second; + sendEvent2Client(eventID, initiatorID, &client, eventbody, eventbodysize); + } +} + + +bool CEventServer::sendEvent2Client(const unsigned int eventID, const initiators initiatorID, const eventClient* ClientData, const void* eventbody, const unsigned int eventbodysize) +{ + struct sockaddr_un servaddr; + int clilen, sock_fd; + + memset(&servaddr, 0, sizeof(struct sockaddr_un)); + servaddr.sun_family = AF_UNIX; + strcpy(servaddr.sun_path, ClientData->udsName); + clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path); + + if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + perror("[eventserver]: socket"); + return false; + } + + if(connect(sock_fd, (struct sockaddr*) &servaddr, clilen) <0 ) + { + char errmsg[128]; + snprintf(errmsg, 128, "[eventserver]: connect (%s)", ClientData->udsName); + perror(errmsg); + close(sock_fd); + return false; + } + + eventHead head; + head.eventID = eventID; + head.initiatorID = initiatorID; + head.dataSize = eventbodysize; + int written = write(sock_fd, &head, sizeof(head)); +// printf ("[eventserver]: sent 0x%x - following eventbody= %d\n", written, eventbodysize ); + + if(eventbodysize!=0) + { + written = write(sock_fd, eventbody, eventbodysize); +// printf ("[eventserver]: eventbody sent 0x%x - peventbody= %x eventbody= %x\n", written, (unsigned)eventbody, *(unsigned*)eventbody ); + } + close(sock_fd); + return true; +} diff --git a/lib/libeventserver/eventserver.h b/lib/libeventserver/eventserver.h new file mode 100644 index 000000000..f68233fe9 --- /dev/null +++ b/lib/libeventserver/eventserver.h @@ -0,0 +1,95 @@ +/* + + $Header: /cvs/tuxbox/apps/misc/libs/libeventserver/eventserver.h,v 1.14 2004/05/06 15:06:30 thegoodguy Exp $ + + Event-Server - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __libevent__ +#define __libevent__ + +#include +#include + + +class CEventServer +{ + public: + + enum initiators + { + INITID_CONTROLD, + INITID_SECTIONSD, + INITID_ZAPIT, + INITID_TIMERD, + INITID_HTTPD, + INITID_NEUTRINO, + INITID_GENERIC_INPUT_EVENT_PROVIDER + }; + + + struct commandRegisterEvent + { + unsigned int eventID; + unsigned int clientID; + char udsName[50]; + }; + + struct commandUnRegisterEvent + { + unsigned int eventID; + unsigned int clientID; + }; + + struct eventHead + { + unsigned int eventID; + unsigned int initiatorID; + unsigned int dataSize; + }; + + void registerEvent2(const unsigned int eventID, const unsigned int ClientID, const std::string udsName); + void registerEvent(const int fd); + void unRegisterEvent2(const unsigned int eventID, const unsigned int ClientID); + void unRegisterEvent(const int fd); + void sendEvent(const unsigned int eventID, const initiators initiatorID, const void* eventbody = NULL, const unsigned int eventbodysize = 0); + + protected: + + struct eventClient + { + char udsName[50]; + }; + + //key: ClientID // Map is a Sorted Associative Container + typedef std::map eventClientMap; // -> clients with lower ClientID receive events first + + //key: eventID + std::map eventData; + + bool sendEvent2Client(const unsigned int eventID, const initiators initiatorID, const eventClient* ClientData, const void* eventbody = NULL, const unsigned int eventbodysize = 0); + +}; + + +#endif diff --git a/lib/libmd5sum/Makefile.am b/lib/libmd5sum/Makefile.am new file mode 100644 index 000000000..632a9debe --- /dev/null +++ b/lib/libmd5sum/Makefile.am @@ -0,0 +1,5 @@ +noinst_LIBRARIES = libtuxbox-md5sum.a + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +libtuxbox_md5sum_a_SOURCES = libmd5sum.c md5.c diff --git a/lib/libmd5sum/getline.h b/lib/libmd5sum/getline.h new file mode 100644 index 000000000..991184c75 --- /dev/null +++ b/lib/libmd5sum/getline.h @@ -0,0 +1,38 @@ +/* Copyright (C) 1995, 1997, 1999 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef GETLINE_H_ +# define GETLINE_H_ 1 + +# include + +# ifndef PARAMS +# if defined PROTOTYPES || (defined __STDC__ && __STDC__) +# define PARAMS(Args) Args +# else +# define PARAMS(Args) () +# endif +# endif + +# if __GLIBC__ < 2 +int +getline PARAMS ((char **_lineptr, size_t *_n, FILE *_stream)); + +int +getdelim PARAMS ((char **_lineptr, size_t *_n, int _delimiter, FILE *_stream)); +# endif + +#endif /* not GETLINE_H_ */ diff --git a/lib/libmd5sum/libmd5sum.c b/lib/libmd5sum/libmd5sum.c new file mode 100644 index 000000000..85878045a --- /dev/null +++ b/lib/libmd5sum/libmd5sum.c @@ -0,0 +1,87 @@ +#include "libmd5sum.h" +#include + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "md5.h" +#include "getline.h" +#include +#include "error.h" +#include + +#define STREQ(a, b) (strcmp ((a), (b)) == 0) + +static int have_read_stdin; + +#if O_BINARY +# define OPENOPTS(BINARY) ((BINARY) != 0 ? TEXT1TO1 : TEXTCNVT) +# define TEXT1TO1 "rb" +# define TEXTCNVT "r" +#else +# if defined VMS +# define OPENOPTS(BINARY) ((BINARY) != 0 ? TEXT1TO1 : TEXTCNVT) +# define TEXT1TO1 "rb", "ctx=stm" +# define TEXTCNVT "r", "ctx=stm" +# else +# if UNIX || __UNIX__ || unix || __unix__ || _POSIX_VERSION +# define OPENOPTS(BINARY) "r" +# else + /* The following line is intended to evoke an error. + Using #error is not portable enough. */ + "Cannot determine system type." +# endif +# endif +#endif + +int md5_file (const char *filename, int binary, unsigned char *md5_result) +{ + FILE *fp; + int err; + + (void)binary; + + if (STREQ (filename, "-")) + { + have_read_stdin = 1; + fp = stdin; +#if O_BINARY + /* If we need binary reads from a pipe or redirected stdin, we need + to switch it to BINARY mode here, since stdin is already open. */ + if (binary) + SET_BINARY (fileno (stdin)); +#endif + } + else + { + /* OPENOPTS is a macro. It varies with the system. + Some systems distinguish between internal and + external text representations. */ + + fp = fopen (filename, OPENOPTS (binary)); + if (fp == NULL) + { + error (0, errno, "%s", filename); + return 1; + } + } + + err = md5_stream (fp, md5_result); + if (err) + { + error (0, errno, "%s", filename); + if (fp != stdin) + fclose (fp); + return 1; + } + + if (fp != stdin && fclose (fp) == EOF) + { + error (0, errno, "%s", filename); + return 1; + } + + return 0; +} diff --git a/lib/libmd5sum/libmd5sum.h b/lib/libmd5sum/libmd5sum.h new file mode 100644 index 000000000..6a604903d --- /dev/null +++ b/lib/libmd5sum/libmd5sum.h @@ -0,0 +1,45 @@ +/* + md5sum lib - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + MD5-functions Written by Ulrich Drepper . +*/ + +#ifndef __libmd5sum__ +#define __libmd5sum__ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +int md5_file (const char *filename, int binary, unsigned char *md5_result); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libmd5sum/md5.c b/lib/libmd5sum/md5.c new file mode 100644 index 000000000..f69e22685 --- /dev/null +++ b/lib/libmd5sum/md5.c @@ -0,0 +1,413 @@ +/* md5.c - Functions to compute MD5 message digest of files or memory blocks + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + NOTE: The canonical source of this file is maintained with the GNU C + Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Ulrich Drepper , 1995. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include +#include + +#include "md5.h" + +#ifdef HAVE_ENDIAN_H +# include +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +# endif +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (ctx) + struct md5_ctx *ctx; +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_read_ctx (ctx, resbuf) + const struct md5_ctx *ctx; + void *resbuf; +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +md5_finish_ctx (ctx, resbuf) + struct md5_ctx *ctx; + void *resbuf; +{ + /* Take yet unprocessed bytes into account. */ + md5_uint32 bytes = ctx->buflen; + size_t pad; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy (&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); + *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) | + (ctx->total[0] >> 29)); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, bytes + pad + 8, ctx); + + return md5_read_ctx (ctx, resbuf); +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (stream, resblock) + FILE *stream; + void *resblock; +{ + /* Important: BLOCKSIZE must be a multiple of 64. */ +#define BLOCKSIZE 4096 + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + do + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + } + while (sum < BLOCKSIZE && n != 0); + if (n == 0 && ferror (stream)) + return 1; + + /* If end of file is reached, end the loop. */ + if (n == 0) + break; + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + + /* Add the last bytes if necessary. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (buffer, len, resblock) + const char *buffer; + size_t len; + void *resblock; +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} + + +void +md5_process_bytes (buffer, len, ctx) + const void *buffer; + size_t len; + struct md5_ctx *ctx; +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (left_over + add > 64) + { + md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx); + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + (left_over + add) & 63); + ctx->buflen = (left_over + add) & 63; + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len > 64) + { + md5_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + memcpy (ctx->buffer, buffer, len); + ctx->buflen = len; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (buffer, len, ctx) + const void *buffer; + size_t len; + struct md5_ctx *ctx; +{ + md5_uint32 correct_words[16]; + const md5_uint32 *words = buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 A = ctx->A; + md5_uint32 B = ctx->B; + md5_uint32 C = ctx->C; + md5_uint32 D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + md5_uint32 *cwp = correct_words; + md5_uint32 A_save = A; + md5_uint32 B_save = B; + md5_uint32 C_save = C; + md5_uint32 D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} diff --git a/lib/libmd5sum/md5.h b/lib/libmd5sum/md5.h new file mode 100644 index 000000000..ad97efc32 --- /dev/null +++ b/lib/libmd5sum/md5.h @@ -0,0 +1,146 @@ +/* md5.h - Declaration of functions and data types used for MD5 sum + computing library functions. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + NOTE: The canonical source of this file is maintained with the GNU C + Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _MD5_H +#define _MD5_H 1 + +#include + +#if defined HAVE_LIMITS_H || _LIBC +# include +#endif + +/* The following contortions are an attempt to use the C preprocessor + to determine an unsigned integral type that is 32 bits wide. An + alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but + doing that would require that the configure script compile and *run* + the resulting executable. Locally running cross-compiled executables + is usually not possible. */ + +#ifdef _LIBC +# include +typedef u_int32_t md5_uint32; +#else +# if defined __STDC__ && __STDC__ +# define UINT_MAX_32_BITS 4294967295U +# else +# define UINT_MAX_32_BITS 0xFFFFFFFF +# endif + +/* If UINT_MAX isn't defined, assume it's a 32-bit type. + This should be valid for all systems GNU cares about because + that doesn't include 16-bit systems, and only modern systems + (that certainly have ) have 64+-bit integral types. */ + +# ifndef UINT_MAX +# define UINT_MAX UINT_MAX_32_BITS +# endif + +# if UINT_MAX == UINT_MAX_32_BITS + typedef unsigned int md5_uint32; +# else +# if USHRT_MAX == UINT_MAX_32_BITS + typedef unsigned short md5_uint32; +# else +# if ULONG_MAX == UINT_MAX_32_BITS + typedef unsigned long md5_uint32; +# else + /* The following line is intended to evoke an error. + Using #error is not portable enough. */ + "Cannot determine unsigned 32-bit data type." +# endif +# endif +# endif +#endif + +#undef __P +#if defined (__STDC__) && __STDC__ +#define __P(x) x +#else +#define __P(x) () +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + md5_uint32 A; + md5_uint32 B; + md5_uint32 C; + md5_uint32 D; + + md5_uint32 total[2]; + md5_uint32 buflen; + char buffer[128]; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +extern void md5_init_ctx __P ((struct md5_ctx *ctx)); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void md5_process_block __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void md5_process_bytes __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf)); + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int md5_stream __P ((FILE *stream, void *resblock)); + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock)); + +#endif diff --git a/lib/libmd5sum/sys2.h b/lib/libmd5sum/sys2.h new file mode 100644 index 000000000..13201bb16 --- /dev/null +++ b/lib/libmd5sum/sys2.h @@ -0,0 +1,347 @@ +/* WARNING -- this file is temporary. It is shared between the + sh-utils, fileutils, and textutils packages. Once I find a little + more time, I'll merge the remaining things in system.h and everything + in this file will go back there. */ + +#ifndef RETSIGTYPE +# define RETSIGTYPE void +#endif + +#ifndef __GNUC__ +# ifdef HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + # pragma alloca +# else +# ifdef _WIN32 +# include +# include +# else +# ifndef alloca +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +#ifdef __DJGPP__ + /* We need the declaration of setmode. */ +# include + /* We need the declaration of __djgpp_set_ctrl_c. */ +# include +#endif + +#include + +/* Jim Meyering writes: + + "... Some ctype macros are valid only for character codes that + isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when + using /bin/cc or gcc but without giving an ansi option). So, all + ctype uses should be through macros like ISPRINT... If + STDC_HEADERS is defined, then autoconf has verified that the ctype + macros don't need to be guarded with references to isascii. ... + Defining isascii to 1 should let any compiler worth its salt + eliminate the && through constant folding." + + Bruno Haible adds: + + "... Furthermore, isupper(c) etc. have an undefined result if c is + outside the range -1 <= c <= 255. One is tempted to write isupper(c) + with c being of type `char', but this is wrong if c is an 8-bit + character >= 128 which gets sign-extended to a negative value. + The macro ISUPPER protects against this as well." */ + +#if STDC_HEADERS || (!defined (isascii) && !HAVE_ISASCII) +# define IN_CTYPE_DOMAIN(c) 1 +#else +# define IN_CTYPE_DOMAIN(c) isascii(c) +#endif + +#ifdef isblank +# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c)) +#else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c)) +#else +# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c)) +#endif + +#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c)) +#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c)) +#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) +#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c)) +#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) +#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct (c)) +#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) +#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c)) +#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c)) +#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) + +#if STDC_HEADERS +# define TOLOWER(Ch) tolower (Ch) +# define TOUPPER(Ch) toupper (Ch) +#else +# define TOLOWER(Ch) (ISUPPER (Ch) ? tolower (Ch) : (Ch)) +# define TOUPPER(Ch) (ISLOWER (Ch) ? toupper (Ch) : (Ch)) +#endif + +/* ISDIGIT differs from ISDIGIT_LOCALE, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char. + - It's guaranteed to evaluate its argument exactly once. + - It's typically faster. + Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that + only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless + it's important to use the locale's definition of `digit' even when the + host does not conform to Posix. */ +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) + +#ifndef PARAMS +# if PROTOTYPES +# define PARAMS(Args) Args +# else +# define PARAMS(Args) () +# endif +#endif + +/* Take care of NLS matters. */ + +#if HAVE_LOCALE_H +# include +#endif +#if !HAVE_SETLOCALE +# define setlocale(Category, Locale) /* empty */ +#endif + +#if ENABLE_NLS +# include +# define _(Text) gettext (Text) +#else +# undef bindtextdomain +# define bindtextdomain(Domain, Directory) /* empty */ +# undef textdomain +# define textdomain(Domain) /* empty */ +# define _(Text) Text +#endif +#define N_(Text) Text + +#define STREQ(a, b) (strcmp ((a), (b)) == 0) + +#ifndef HAVE_DECL_FREE +void free (); +#endif + +//#ifndef HAVE_DECL_MALLOC +//char *malloc (); +//#endif + +//#ifndef HAVE_DECL_MEMCHR +//char *memchr (); +//#endif + +#ifndef HAVE_DECL_REALLOC +char *realloc (); +#endif + +#ifndef HAVE_DECL_STPCPY +# ifndef stpcpy +char *stpcpy (); +# endif +#endif + +#ifndef HAVE_DECL_STRSTR +char *strstr (); +#endif + +#ifndef HAVE_DECL_GETENV +char *getenv (); +#endif + +#ifndef HAVE_DECL_LSEEK +off_t lseek (); +#endif + +#if ! defined HAVE_MEMPCPY && ! defined mempcpy +/* Be CAREFUL that there are no side effects in N. */ +# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N))) +#endif + +/* These are wrappers for functions/macros from GNU libc. + The standard I/O functions are thread-safe. These *_unlocked ones + are more efficient but not thread-safe. That they're not thread-safe + is fine since all these applications are single threaded. */ + +#ifdef HAVE_CLEARERR_UNLOCKED +# undef clearerr +# define clearerr(S) clearerr_unlocked (S) +#endif + +#ifdef HAVE_FEOF_UNLOCKED +# undef feof +# define feof(S) feof_unlocked (S) +#endif + +#ifdef HAVE_FERROR_UNLOCKED +# undef ferror +# define ferror(S) ferror_unlocked (S) +#endif + +#ifdef HAVE_FFLUSH_UNLOCKED +# undef fflush +# define fflush(S) fflush_unlocked (S) +#endif + +#ifdef HAVE_FPUTC_UNLOCKED +# undef fputc +# define fputc(C, S) fputc_unlocked (C, S) +#endif + +#ifdef HAVE_FREAD_UNLOCKED +# undef fread +# define fread(P, Z, N, S) fread_unlocked (P, Z, N, S) +#endif + +#ifdef HAVE_FWRITE_UNLOCKED +# undef fwrite +# define fwrite(P, Z, N, S) fwrite_unlocked (P, Z, N, S) +#endif + +#ifdef HAVE_GETC_UNLOCKED +# undef getc +# define getc(S) getc_unlocked (S) +#endif + +#ifdef HAVE_GETCHAR_UNLOCKED +# undef getchar +# define getchar(S) getchar_unlocked (S) +#endif + +#ifdef HAVE_PUTC_UNLOCKED +# undef putc +# define putc(C, S) putc_unlocked (C, S) +#endif + +#ifdef HAVE_PUTCHAR_UNLOCKED +# undef putchar +# define putchar(C) putchar_unlocked (C) +#endif + +#define SAME_INODE(Stat_buf_1, Stat_buf_2) \ + ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \ + && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev) + +#define DOT_OR_DOTDOT(Basename) \ + (Basename[0] == '.' && (Basename[1] == '\0' \ + || (Basename[1] == '.' && Basename[2] == '\0'))) + +#if SETVBUF_REVERSED +# define SETVBUF(Stream, Buffer, Type, Size) \ + setvbuf (Stream, Type, Buffer, Size) +#else +# define SETVBUF(Stream, Buffer, Type, Size) \ + setvbuf (Stream, Buffer, Type, Size) +#endif + +char *base_name PARAMS ((char const *)); + +/* Factor out some of the common --help and --version processing code. */ + +#define GETOPT_HELP_CHAR 250 +#define GETOPT_VERSION_CHAR 251 + +#define GETOPT_HELP_OPTION_DECL \ + "help", no_argument, 0, GETOPT_HELP_CHAR +#define GETOPT_VERSION_OPTION_DECL \ + "version", no_argument, 0, GETOPT_VERSION_CHAR + +#define case_GETOPT_HELP_CHAR \ + case GETOPT_HELP_CHAR: \ + usage (EXIT_SUCCESS); \ + break; + +#define case_GETOPT_VERSION_CHAR(Program_name, Authors) \ + case GETOPT_VERSION_CHAR: \ + version_etc (stdout, Program_name, GNU_PACKAGE, VERSION, Authors); \ + close_stdout (); \ + exit (EXIT_SUCCESS); \ + break; + +#ifndef MAX +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* The extra casts work around common compiler bugs. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. + It is necessary at least when t == time_t. */ +#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ + ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) +#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) + +#ifndef CHAR_MIN +# define CHAR_MIN TYPE_MINIMUM (char) +#endif + +#ifndef CHAR_MAX +# define CHAR_MAX TYPE_MAXIMUM (char) +#endif + +#ifndef SCHAR_MIN +# define SCHAR_MIN (-1 - SCHAR_MAX) +#endif + +#ifndef SCHAR_MAX +# define SCHAR_MAX (CHAR_MAX == UCHAR_MAX ? CHAR_MAX / 2 : CHAR_MAX) +#endif + +#ifndef UCHAR_MAX +# define UCHAR_MAX TYPE_MAXIMUM (unsigned char) +#endif + +#ifndef SHRT_MIN +# define SHRT_MIN TYPE_MINIMUM (short int) +#endif + +#ifndef SHRT_MAX +# define SHRT_MAX TYPE_MAXIMUM (short int) +#endif + +#ifndef INT_MAX +# define INT_MAX TYPE_MAXIMUM (int) +#endif + +#ifndef UINT_MAX +# define UINT_MAX TYPE_MAXIMUM (unsigned int) +#endif + +#ifndef LONG_MAX +# define LONG_MAX TYPE_MAXIMUM (long) +#endif + +#ifndef ULONG_MAX +# define ULONG_MAX TYPE_MAXIMUM (unsigned long) +#endif + +#ifndef UID_T_MAX +# define UID_T_MAX TYPE_MAXIMUM (uid_t) +#endif + +#ifndef GID_T_MAX +# define GID_T_MAX TYPE_MAXIMUM (gid_t) +#endif + +#ifndef PID_T_MAX +# define PID_T_MAX TYPE_MAXIMUM (pid_t) +#endif diff --git a/lib/libmd5sum/system.h b/lib/libmd5sum/system.h new file mode 100644 index 000000000..5082e6a62 --- /dev/null +++ b/lib/libmd5sum/system.h @@ -0,0 +1,245 @@ +/* system-dependent definitions for fileutils, textutils, and sh-utils packages. + Copyright (C) 89, 1991-1998, 1999 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Include sys/types.h before this file. */ + +#include + +#ifdef STAT_MACROS_BROKEN +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISLNK +# undef S_ISMPB +# undef S_ISMPC +# undef S_ISNWK +# undef S_ISREG +# undef S_ISSOCK +#endif /* STAT_MACROS_BROKEN. */ + +#ifndef S_IFMT +# define S_IFMT 0170000 +#endif +#if !defined(S_ISBLK) && defined(S_IFBLK) +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#endif +#if !defined(S_ISCHR) && defined(S_IFCHR) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISDIR) && defined(S_IFDIR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) && defined(S_IFREG) +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISFIFO) && defined(S_IFIFO) +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISLNK) && defined(S_IFLNK) +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */ +# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) +# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) +#endif +#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */ +# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +#endif + +#ifndef S_IEXEC +# define S_IEXEC S_IXUSR +#endif + +#ifndef S_IXUSR +# define S_IXUSR S_IEXEC +#endif +#ifndef S_IXGRP +# define S_IXGRP (S_IEXEC >> 3) +#endif +#ifndef S_IXOTH +# define S_IXOTH (S_IEXEC >> 6) +#endif +#ifndef S_IXUGO +# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) +#endif + +#if !defined(HAVE_MKFIFO) +# define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0)) +#endif + +#ifdef HAVE_SYS_PARAM_H +# include +#endif + +/* should be included before any preprocessor test + of _POSIX_VERSION. */ +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + + +#if HAVE_LIMITS_H +/* limits.h must come before pathmax.h because limits.h on some systems + undefs PATH_MAX, whereas pathmax.h sets PATH_MAX. */ +# include +#endif + +/* Don't use bcopy! Use memmove if source and destination may overlap, + memcpy otherwise. */ + +#ifdef HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#else +# include +#endif + +#include +#ifndef errno +extern int errno; +#endif + +#if HAVE_STDLIB_H +# define getopt system_getopt +# include +# undef getopt +#endif + +/* The following test is to work around the gross typo in + systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE + is defined to 0, not 1. */ +#if !EXIT_FAILURE +# undef EXIT_FAILURE +# define EXIT_FAILURE 1 +#endif + +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +#endif + +#ifdef HAVE_FCNTL_H +# include +#else +# include +#endif + +#if !defined (SEEK_SET) +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif +#ifndef F_OK +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + +/* For systems that distinguish between text and binary I/O. + O_BINARY is usually declared in fcntl.h */ +#if !defined O_BINARY && defined _O_BINARY + /* For MSC-compatible compilers. */ +# define O_BINARY _O_BINARY +# define O_TEXT _O_TEXT +#endif +#if O_BINARY +# ifndef __DJGPP__ +# define setmode _setmode +# define fileno(_fp) _fileno (_fp) +# endif /* not DJGPP */ +# define SET_BINARY(_f) do {if (!isatty(_f)) setmode (_f, O_BINARY);} while (0) +# define SET_BINARY2(_f1, _f2) \ + do { \ + if (!isatty (_f1)) \ + { \ + setmode (_f1, O_BINARY); \ + if (!isatty (_f2)) \ + setmode (_f2, O_BINARY); \ + } \ + } while(0) +#else +# define SET_BINARY(f) (void)0 +# define SET_BINARY2(f1,f2) (void)0 +# define O_BINARY 0 +# define O_TEXT 0 +#endif /* O_BINARY */ + +#ifdef HAVE_DIRENT_H +# include +# define NLENGTH(direct) (strlen((direct)->d_name)) +#else /* not HAVE_DIRENT_H */ +# define dirent direct +# define NLENGTH(direct) ((direct)->d_namlen) +# ifdef HAVE_SYS_NDIR_H +# include +# endif /* HAVE_SYS_NDIR_H */ +# ifdef HAVE_SYS_DIR_H +# include +# endif /* HAVE_SYS_DIR_H */ +# ifdef HAVE_NDIR_H +# include +# endif /* HAVE_NDIR_H */ +#endif /* HAVE_DIRENT_H */ + +#ifdef CLOSEDIR_VOID +/* Fake a return value. */ +# define CLOSEDIR(d) (closedir (d), 0) +#else +# define CLOSEDIR(d) closedir (d) +#endif + +/* Get or fake the disk device blocksize. + Usually defined by sys/param.h (if at all). */ +#if !defined(DEV_BSIZE) && defined(BSIZE) +# define DEV_BSIZE BSIZE +#endif +#if !defined(DEV_BSIZE) && defined(BBSIZE) /* SGI */ +# define DEV_BSIZE BBSIZE +#endif +#ifndef DEV_BSIZE +# define DEV_BSIZE 4096 +#endif + +/* Extract or fake data from a `struct stat'. + ST_BLKSIZE: Optimal I/O blocksize for the file, in bytes. */ +#ifndef HAVE_ST_BLKSIZE +# define ST_BLKSIZE(statbuf) DEV_BSIZE +#else /* HAVE_ST_BLKSIZE */ +/* Some systems, like Sequents, return st_blksize of 0 on pipes. */ +# define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \ + ? (statbuf).st_blksize : DEV_BSIZE) +#endif /* HAVE_ST_BLKSIZE */ + +#include "sys2.h" diff --git a/lib/libnet/Makefile.am b/lib/libnet/Makefile.am new file mode 100644 index 000000000..33472a037 --- /dev/null +++ b/lib/libnet/Makefile.am @@ -0,0 +1,5 @@ +noinst_LIBRARIES = libtuxbox-net.a + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +libtuxbox_net_a_SOURCES = libnet.c network_interfaces.cpp diff --git a/lib/libnet/libnet.c b/lib/libnet/libnet.c new file mode 100644 index 000000000..6db6baf67 --- /dev/null +++ b/lib/libnet/libnet.c @@ -0,0 +1,260 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void scanip( char *str, unsigned char *to ) +{ + int val; + int c; + char *sp; + int b=4; + + for( sp=str; b; b-- ) + { + val=0; + for(; (*sp != 0) && (*sp != '.'); sp++) + { + c = *sp - '0'; + if (( c < 0 ) || ( c>=10)) + break; + val=(val*10)+c; + } + *to=val; + to++; + if ( !*sp ) + break; + sp++; + } +} + +int netSetIP( char *dev, char *ip, char *mask, char *brdcast ) +{ + int fd; + struct ifreq req; + int rc=-1; + unsigned char adr_ip[4]; + unsigned char adr_mask[4]; + unsigned char adr_brdcast[4]; + struct sockaddr_in addr; + + fd=socket(AF_INET,SOCK_DGRAM,0); + if ( !fd ) + return -1; + + scanip( ip, adr_ip ); + scanip( mask, adr_mask ); + scanip( brdcast, adr_brdcast ); + + /* init structures */ + bzero(&req,sizeof(req)); + strcpy(req.ifr_name,dev); + + bzero(&addr,sizeof(addr)); + addr.sin_family = AF_INET; + + addr.sin_addr.s_addr = *((unsigned long *) adr_ip); + memcpy(&req.ifr_addr,&addr,sizeof(addr)); + if( ioctl(fd,SIOCSIFADDR,&req) < 0 ) + goto abbruch; + + addr.sin_addr.s_addr = *((unsigned long *) adr_mask); + memcpy(&req.ifr_addr,&addr,sizeof(addr)); + if( ioctl(fd,SIOCSIFNETMASK,&req) < 0 ) + goto abbruch; + + addr.sin_addr.s_addr = *((unsigned long *) adr_brdcast); + memcpy(&req.ifr_addr,&addr,sizeof(addr)); + if( ioctl(fd,SIOCSIFBRDADDR,&req) < 0 ) + goto abbruch; + + rc = 0; +abbruch: + close(fd); + + return rc; +} + +void netGetIP( char *dev, char *ip, char *mask, char *brdcast ) +{ + int fd; + struct ifreq req; + struct sockaddr_in *saddr; + unsigned char *addr; + + *ip=0; + *mask=0; + *brdcast=0; + + fd=socket(AF_INET,SOCK_DGRAM,0); + if ( !fd ) + return; + + + bzero(&req,sizeof(req)); + strcpy(req.ifr_name,dev); + saddr = (struct sockaddr_in *) &req.ifr_addr; + addr= (unsigned char*) &saddr->sin_addr.s_addr; + + if( ioctl(fd,SIOCGIFADDR,&req) == 0 ) + sprintf(ip,"%d.%d.%d.%d",addr[0],addr[1],addr[2],addr[3]); + + if( ioctl(fd,SIOCGIFNETMASK,&req) == 0 ) + sprintf(mask,"%d.%d.%d.%d",addr[0],addr[1],addr[2],addr[3]); + + if( ioctl(fd,SIOCGIFBRDADDR,&req) == 0 ) + sprintf(brdcast,"%d.%d.%d.%d",addr[0],addr[1],addr[2],addr[3]); + + close(fd); + return; +} + +void netSetDefaultRoute( char *gw ) +{ + struct rtentry re; + struct sockaddr_in *in_addr; + unsigned char *addr; + int fd; + unsigned char adr_gw[4]; + + scanip( gw, adr_gw ); + + memset(&re,0,sizeof(struct rtentry)); + + in_addr = (struct sockaddr_in *)&re.rt_dst; + in_addr->sin_family = AF_INET; + + in_addr = (struct sockaddr_in *)&re.rt_gateway; + in_addr->sin_family = AF_INET; + addr=(unsigned char*)&in_addr->sin_addr.s_addr; + + in_addr = (struct sockaddr_in *)&re.rt_genmask; + in_addr->sin_family = AF_INET; + + fd=socket(AF_INET,SOCK_DGRAM,0); + if ( fd < 0 ) + return; + + re.rt_flags = RTF_GATEWAY | RTF_UP; + memcpy(addr,adr_gw,4); + + ioctl(fd,SIOCADDRT,&re); + + close(fd); + return; +} + +void netGetDefaultRoute( char *ip ) +{ + FILE *fp; + char interface[9]; + unsigned char destination[4]; + unsigned char gateway[4]; + char zeile[256]; + + *ip = 0 ; + fp = fopen("/proc/net/route","r"); + if (fp == NULL) + return; + fgets(zeile,sizeof(zeile),fp); + while(fgets(zeile,sizeof(zeile),fp)) + { + sscanf(zeile,"%8s %x %x",interface,(unsigned *) destination,(unsigned *) gateway); + if (*(unsigned *)destination == 0) + { + sprintf(ip,"%d.%d.%d.%d",gateway[0],gateway[1],gateway[2],gateway[3]); + break; + } + } + fclose(fp); +} + +static char dombuf[256]; +static char hostbuf[256]; +static char domis=0; +static char hostis=0; + +char *netGetDomainname( void ) +{ + if (!domis) + getdomainname( dombuf, 256 ); + domis=1; + return dombuf; +} + +void netSetDomainname( char *dom ) +{ + strcpy(dombuf,dom); + domis=1; + setdomainname(dombuf,strlen(dombuf)+1); +} + +char *netGetHostname( void ) +{ + if (!hostis) + gethostname( hostbuf, 256 ); + hostis=1; + return hostbuf; +} + +void netSetHostname( char *host ) +{ + strcpy(hostbuf,host); + hostis=1; + sethostname(hostbuf,strlen(hostbuf)+1); +} + +void netSetNameserver(const char * const ip) +{ + FILE *fp; + + fp = fopen("/etc/resolv.conf","w"); + if (!fp) + return; + +#if 0 + char *dom; + dom=netGetDomainname(); + if (dom && strlen(dom)>2) + fprintf(fp,"search %s\n",dom); +#endif + fprintf(fp, "# generated by neutrino\n"); + if ((ip != NULL) && (strlen(ip) > 0)) + fprintf(fp,"nameserver %s\n",ip); + fclose(fp); +} + +void netGetNameserver( char *ip ) +{ + FILE *fp; + char zeile[256]; + char *index; + unsigned zaehler; + + *ip = 0; + fp = fopen("/etc/resolv.conf","r"); + if (!fp) + return; + + while (fgets(zeile,sizeof(zeile),fp)) + { + if (!strncasecmp(zeile,"nameserver",10)) + { + index = zeile + 10; + while ( (*index == ' ') || (*index == '\t') ) + index++; + zaehler = 0; + while ( (zaehler < 15) && ( ((*index >= '0') && (*index <= '9')) || (*index == '.'))) + ip[zaehler++] = *(index++); + ip[zaehler] = 0; + break; + } + } + fclose(fp); +} diff --git a/lib/libnet/libnet.h b/lib/libnet/libnet.h new file mode 100644 index 000000000..a1ddad998 --- /dev/null +++ b/lib/libnet/libnet.h @@ -0,0 +1,27 @@ +#ifndef __libnet__ +#define __libnet__ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +extern int netSetIP( char *dev, char *ip, char *mask, char *brdcast ); +extern void netGetIP( char *dev, char *ip, char *mask, char *brdcast ); +extern void netSetDefaultRoute( char *gw ); +extern void netGetDefaultRoute( char *ip ); +extern char *netGetDomainname( void ); +extern void netSetDomainname( char *dom ); +extern char *netGetHostname( void ); +extern void netSetHostname( char *host ); +extern void netSetNameserver(const char *ip); +extern void netGetNameserver( char *ip ); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/lib/libnet/network_interfaces.cpp b/lib/libnet/network_interfaces.cpp new file mode 100644 index 000000000..e3f57c0e3 --- /dev/null +++ b/lib/libnet/network_interfaces.cpp @@ -0,0 +1,373 @@ +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libnet/network_interfaces.cpp,v 1.6 2003/03/20 15:32:52 thegoodguy Exp $ + * + * (C) 2003 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +/* + * Known bugs: + * ----------- + * + * - extension of lines across multiple lines using \ is not supported + * + */ + +bool read_file(const std::string filename, std::list &line) +{ + std::string s; + std::ifstream in(filename.c_str()); + + line.clear(); + + if (!in.is_open()) + return false; + + while (getline(in, s)) + line.push_back(s); + + return true; +} + +bool write_file(const std::string filename, const std::list line) +{ + std::ofstream out(filename.c_str()); + + if (!out.is_open()) + return false; + + for (std::list::const_iterator it = line.begin(); it != line.end(); it++) + out << (*it) << std::endl; + + return true; +} + +std::list::iterator add_attributes(const std::map attribute, std::list &line, std::list::iterator here) +{ + for (std::map::const_iterator it = attribute.begin(); it != attribute.end(); it++) + { + std::ostringstream out; + out << '\t' << (it -> first) << ' ' << (it -> second); + line.insert(here, out.str()); + } + return here; +} + +std::string remove_interface_from_line(const std::string interface, const std::string line) +{ + std::string s; + std::istringstream in(line.c_str()); + std::ostringstream out; + bool contains_at_least_one_interface = false; + + if (in >> s) + { + out << s; /* auto */ + + while (in >> s) + { + if (s != interface) + { + out << ' ' << s; + contains_at_least_one_interface = true; + } + } + } + + return (contains_at_least_one_interface ? out.str() : ""); +} + +bool write_interface(const std::string filename, const std::string name, const bool automatic_start, const std::string family, const std::string method, const std::map attribute) +{ + std::string s; + std::list line; + bool found = false; + + read_file(filename, line); /* ignore return value */ + + for (std::list::iterator it = line.begin(); it != line.end(); ) + { + { + std::istringstream in((*it).c_str()); + + if (!(in >> s)) + { + it++; + continue; + } + + if (s != std::string("iface")) + { + if (s == std::string("auto")) + { + bool advance = true; + while (in >> s) + { + if (s == std::string(name)) + { + *it = remove_interface_from_line(name, *it); + if ((*it).empty()) + { + it = line.erase(it); /* erase advances it */ + advance = false; + } + break; + } + } + if (advance) + it++; + } + else + it++; + continue; + } + + if (!(in >> s)) + { + it++; + continue; + } + + if (s != std::string(name)) + { + it++; + continue; + } + } + + found = true; + + /* replace line */ + std::ostringstream out; + out << "iface " << name << ' ' << family << ' ' << method; + (*it) = out.str(); + + if (automatic_start) + line.insert(it, "auto " + name); + + /* add attributes */ + it++; + it = add_attributes(attribute, line, it); + + /* remove current attributes */ + while (it != line.end()) + { + std::istringstream in((*it).c_str()); + + if (!(in >> s)) /* retain empty lines */ + { + it++; + continue; + } + + if (s[0] == '#') /* retain comments */ + { + it++; + continue; + } + + if (s == std::string("iface")) + break; + + if (s == std::string("auto")) + break; + + if (s == std::string("mapping")) + break; + + it = line.erase(it); + } + } + + if (!found) + { + std::ostringstream out; + + if (automatic_start) + line.push_back("auto " + name); + + out << "iface " << name << ' ' << family << ' ' << method; + line.push_back(out.str()); + add_attributes(attribute, line, line.end()); + } + + return write_file(filename, line); +} + +bool read_interface(const std::string filename, const std::string name, bool &automatic_start, std::string &family, std::string &method, std::map &attribute) +{ + std::string s; + std::string t; + std::ifstream in(filename.c_str()); + bool advance = true; + + automatic_start = false; + attribute.clear(); + + if (!in.is_open()) + return false; + + while (true) + { + if (advance) + { + if (!getline(in, s)) + break; + } + else + advance = true; + + { + std::istringstream in(s.c_str()); + + if (!(in >> s)) + continue; + + if (s != std::string("iface")) + { + if (s == std::string("auto")) + { + while (in >> s) + { + if (s == std::string(name)) + { + automatic_start = true; + break; + } + } + } + continue; + } + + if (!(in >> s)) + continue; + + if (s != std::string(name)) + continue; + + if (!(in >> s)) + continue; + + if (!(in >> t)) + continue; + + family = s; + method = t; + } + + while (true) + { + if (!getline(in, s)) + return true; + + std::istringstream in(s.c_str()); + + if (!(in >> t)) /* ignore empty lines */ + continue; + + if (t[0] == '#') /* ignore comments */ + continue; + + if (t == std::string("iface")) + break; + + if (t == std::string("auto")) + break; + + if (t == std::string("mapping")) + break; + + if (!(in >> s)) + continue; + + attribute[t] = s; + } + advance = false; + } + + return true; +} + +bool getInetAttributes(const std::string name, bool &automatic_start, std::string &address, std::string &netmask, std::string &broadcast, std::string &gateway) +{ + std::string family; + std::string method; + std::map attribute; + + if (!read_interface("/etc/network/interfaces", name, automatic_start, family, method, attribute)) + return false; + + if (family != "inet") + return false; + + if (method != "static") + return false; + + address = ""; + netmask = ""; + broadcast = ""; + gateway = ""; + + for (std::map::const_iterator it = attribute.begin(); it != attribute.end(); it++) + { + if ((*it).first == "address") + address = (*it).second; + if ((*it).first == "netmask") + netmask = (*it).second; + if ((*it).first == "broadcast") + broadcast = (*it).second; + if ((*it).first == "gateway") + gateway = (*it).second; + } + return true; +} + +bool addLoopbackDevice(const std::string name, const bool automatic_start) +{ + std::map attribute; + + return write_interface("/etc/network/interfaces", name, automatic_start, "inet", "loopback", attribute); +} + +bool setStaticAttributes(const std::string name, const bool automatic_start, const std::string address, const std::string netmask, const std::string broadcast, const std::string gateway) +{ + std::map attribute; + + attribute["address"] = address; + attribute["netmask"] = netmask; + + if (!broadcast.empty()) + attribute["broadcast"] = broadcast; + + if (!gateway.empty()) + attribute["gateway"] = gateway; + + return write_interface("/etc/network/interfaces", name, automatic_start, "inet", "static", attribute); +} + +bool setDhcpAttributes(const std::string name, const bool automatic_start) +{ + std::map attribute; + + return write_interface("/etc/network/interfaces", name, automatic_start, "inet", "dhcp", attribute); +} diff --git a/lib/libnet/network_interfaces.h b/lib/libnet/network_interfaces.h new file mode 100644 index 000000000..56bbe43a3 --- /dev/null +++ b/lib/libnet/network_interfaces.h @@ -0,0 +1,35 @@ +#ifndef __network_interfaces_h__ +#define __network_interfaces_h__ + +/* + * $Header: /cvs/tuxbox/apps/misc/libs/libnet/network_interfaces.h,v 1.4 2003/03/20 14:07:32 thegoodguy Exp $ + * + * (C) 2003 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +bool getInetAttributes(const std::string name, bool &automatic_start, std::string &address, std::string &netmask, std::string &broadcast, std::string &gateway); + +bool addLoopbackDevice(const std::string name, const bool automatic_start); + +bool setStaticAttributes(const std::string name, const bool automatic_start, const std::string address, const std::string netmask, const std::string broadcast, const std::string gateway); + +bool setDhcpAttributes(const std::string name, const bool automatic_start); + +#endif /* __network_interfaces_h__ */ diff --git a/lib/libtuxtxt/Makefile.am b/lib/libtuxtxt/Makefile.am new file mode 100644 index 000000000..c4d95e4ef --- /dev/null +++ b/lib/libtuxtxt/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/libcoolstream + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +noinst_LIBRARIES = libtuxtxt.a + +libtuxtxt_a_SOURCES = libtuxtxt.cpp tuxtxt.cpp diff --git a/lib/libtuxtxt/libtuxtxt.cpp b/lib/libtuxtxt/libtuxtxt.cpp new file mode 100644 index 000000000..14b5b4758 --- /dev/null +++ b/lib/libtuxtxt/libtuxtxt.cpp @@ -0,0 +1,95 @@ +/****************************************************************************** + * <<< TuxTxt - Teletext Plugin >>> * + * * + * (c) Thomas "LazyT" Loewe 2002-2003 (LazyT@gmx.net) * + * * + * TOP-Text Support 2004 by Roland Meier * + * Info entnommen aus videotext-0.6.19991029, * + * Copyright (c) 1994-96 Martin Buck * + * * + ******************************************************************************/ + +#define TUXTXT_DEBUG 0 + +#include +#include + +#include "tuxtxt_def.h" +#include "tuxtxt_common.h" + +/****************************************************************************** + * Initialize * + ******************************************************************************/ + +static int tuxtxt_initialized=0; + +int tuxtxt_init() +{ + if ( tuxtxt_initialized ) + return 0; + + tuxtxt_initialized=1; + + /* init data */ + memset(&tuxtxt_cache.astCachetable, 0, sizeof(tuxtxt_cache.astCachetable)); + memset(&tuxtxt_cache.astP29, 0, sizeof(tuxtxt_cache.astP29)); + + tuxtxt_clear_cache(); + tuxtxt_cache.receiving = 0; + tuxtxt_cache.thread_starting = 0; + tuxtxt_cache.vtxtpid = -1; + tuxtxt_cache.thread_id = 0; + tuxtxt_cache.dmx = -1; + return 1;//tuxtxt_init_demuxer(); +} + +/****************************************************************************** + * Interface to caller * + ******************************************************************************/ + +int tuxtxt_stop() +{ + if (!tuxtxt_cache.receiving) return 1; + tuxtxt_cache.receiving = 0; + + return tuxtxt_stop_thread(); +} + +void tuxtxt_start(int tpid) +{ + if (tuxtxt_cache.vtxtpid != tpid) + { + tuxtxt_stop(); + tuxtxt_clear_cache(); + tuxtxt_cache.page = 0x100; + tuxtxt_cache.vtxtpid = tpid; + tuxtxt_start_thread(); + } + else if (!tuxtxt_cache.thread_starting && !tuxtxt_cache.receiving) + { + tuxtxt_start_thread(); + } +} + +void tuxtxt_close() +{ +#if TUXTXT_DEBUG + printf ("libtuxtxt: cleaning up\n"); +#endif + tuxtxt_stop(); +#if 0 + if (tuxtxt_cache.dmx != -1) + close(tuxtxt_cache.dmx); +#endif + tuxtxt_cache.dmx = -1; + tuxtxt_clear_cache(); + tuxtxt_initialized=0; +} + +/* Local Variables: */ +/* indent-tabs-mode:t */ +/* tab-width:3 */ +/* c-basic-offset:3 */ +/* comment-column:0 */ +/* fill-column:120 */ +/* End: */ diff --git a/lib/libtuxtxt/tuxtxt.cpp b/lib/libtuxtxt/tuxtxt.cpp new file mode 100644 index 000000000..1a309dadf --- /dev/null +++ b/lib/libtuxtxt/tuxtxt.cpp @@ -0,0 +1,6176 @@ +/****************************************************************************** + * <<< TuxTxt - Teletext Plugin >>> * + * * + * (c) Thomas "LazyT" Loewe 2002-2003 (LazyT@gmx.net) * + * * + * continued 2004-2005 by Roland Meier * + * and DBLuelle * + * * + * ported 2006 to Dreambox 7025 / 32Bit framebuffer * + * by Seddi * + * * + * ported 2009 to HD1 by Coolstream LTD * + * * + ******************************************************************************/ + +#include "tuxtxt.h" +#include + +void FillRect(int x, int y, int w, int h, int color) +{ + unsigned char *p = lfb + x*4 + y * fix_screeninfo.line_length; +#if 1 + unsigned int col = bgra[color][3] << 24 | bgra[color][2] << 16 | bgra[color][1] << 8 | bgra[color][0]; + + if (w > 0) + for (int count = 0; count < h; count++) { + unsigned int * dest0 = (unsigned int *)p; + for (int i = 0; i < w; i++) + *(dest0++) = col; + p += fix_screeninfo.line_length; + } +#else + int xtmp; + if (w > 0) + for ( ; h > 0 ; h--) + { + for (xtmp=0; xtmp<=w; xtmp++) + { + memcpy(p+xtmp*4,bgra[color],4); + } + p += fix_screeninfo.line_length; + } +#endif +} + +void FillBorder(int color) +{ + int ys = (var_screeninfo.yres-var_screeninfo.yoffset); + FillRect(0 , ys ,StartX ,var_screeninfo.yres ,color); + FillRect(StartX, ys ,displaywidth,StartY ,color); + FillRect(StartX, ys+StartY+25*fontheight,displaywidth,var_screeninfo.yres-(StartY+25*fontheight),color); + + if (screenmode == 0 ) + FillRect(StartX+displaywidth, ys,var_screeninfo.xres-(StartX+displaywidth),var_screeninfo.yres ,color); +} + +int getIndexOfPageInHotlist() +{ + int i; + for (i = 0; i <= maxhotlist; i++) + { + if (tuxtxt_cache.page == hotlist[i]) + return i; + } + return -1; +} + +void gethotlist() +{ + FILE *hl; + char line[100]; + + hotlistchanged = 0; + maxhotlist = -1; + sprintf(line, CONFIGDIR "/tuxtxt/hotlist%d.conf", tuxtxt_cache.vtxtpid); +#if TUXTXT_DEBUG + printf("TuxTxt = 0x100 && hotlist[maxhotlist+1] <= 0x899) + { +#if TUXTXT_DEBUG + printf(" %03x", hotlist[maxhotlist+1]); +#endif + maxhotlist++; + continue; + } + } +#if TUXTXT_DEBUG + else + printf(" ?%s?", line); +#endif + } while (maxhotlist < (int) (sizeof(hotlist)/sizeof(hotlist[0])-1)); + fclose(hl); + } +#if TUXTXT_DEBUG + printf(">\n"); +#endif + if (maxhotlist < 0) /* hotlist incorrect or not found */ + { + hotlist[0] = 0x100; /* create one */ + hotlist[1] = 0x303; + maxhotlist = 1; + } +} + +void savehotlist() +{ + FILE *hl; + char line[100]; + int i; + + hotlistchanged = 0; + sprintf(line, CONFIGDIR "/tuxtxt/hotlist%d.conf", tuxtxt_cache.vtxtpid); +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif +} + +#define number2char(c) ((c) + (((c) <= 9) ? '0' : ('A' - 10))) +/* print hex-number into string, s points to last digit, caller has to provide enough space, no termination */ +void hex2str(char *s, unsigned int n) +{ + do { + char c = (n & 0xF); + *s-- = number2char(c); + n >>= 4; + } while (n); +} + + +int toptext_getnext(int startpage, int up, int findgroup) +{ + int current, nextgrp, nextblk; + + int stoppage = (tuxtxt_is_dec(startpage) ? startpage : startpage & 0xF00); // avoid endless loop in hexmode + nextgrp = nextblk = 0; + current = startpage; + + do { + if (up) + tuxtxt_next_dec(¤t); + else + tuxtxt_prev_dec(¤t); + + if (!tuxtxt_cache.bttok || tuxtxt_cache.basictop[current]) /* only if existent */ + { + if (findgroup) + { + if (tuxtxt_cache.basictop[current] >= 6 && tuxtxt_cache.basictop[current] <= 7) + return current; + if (!nextgrp && (current&0x00F) == 0) + nextgrp = current; + } + if (tuxtxt_cache.basictop[current] >= 2 && tuxtxt_cache.basictop[current] <= 5) /* always find block */ + return current; + + if (!nextblk && (current&0x0FF) == 0) + nextblk = current; + } + } while (current != stoppage); + + if (nextgrp) + return nextgrp; + else if (nextblk) + return nextblk; + else + return startpage; +} + +void RenderClearMenuLineBB(char *p, tstPageAttr *attrcol, tstPageAttr *attr) +{ + int col; + + PosX = TOPMENUSTARTX; + RenderCharBB(' ', attrcol); /* indicator for navigation keys */ +#if 0 + RenderCharBB(' ', attr); /* separator */ +#endif + for(col = 0; col < TOPMENUCHARS; col++) + { + RenderCharBB(*p++, attr); + } + PosY += fontheight; + memset(p-TOPMENUCHARS, ' ', TOPMENUCHARS); /* init with spaces */ +} + +void ClearBB(int color) +{ + FillRect(0,(var_screeninfo.yres-var_screeninfo.yoffset),fix_screeninfo.line_length,var_screeninfo.yres, color); +} + +void ClearFB(int color) +{ + memset(lfb,0, var_screeninfo.yres*fix_screeninfo.line_length); + //FillRect(0,var_screeninfo.yoffset,fix_screeninfo.line_length,var_screeninfo.yres,color); +} + +void ClearB(int color) +{ + FillRect(0,0,fix_screeninfo.line_length,var_screeninfo.yres*2,color); +} + + +int GetCurFontWidth() +{ + int mx = (displaywidth)%(40-nofirst); // # of unused pixels + int abx = (mx == 0 ? displaywidth+1 : (displaywidth)/(mx+1));// distance between 'inserted' pixels + int nx= abx+1-((PosX-sx) % (abx+1)); // # of pixels to next insert + return fontwidth+(((PosX+fontwidth+1-sx) <= displaywidth && nx <= fontwidth+1) ? 1 : 0); +} + +void SetPosX(int column) +{ + PosX = StartX; + int i; + for (i = 0; i < column-nofirst; i++) + PosX += GetCurFontWidth(); +} + +void setfontwidth(int newwidth) +{ + if (fontwidth != newwidth) + { + int i; + fontwidth = newwidth; + if (usettf) + typettf.width = (FT_UShort) fontwidth * TTFWidthFactor16 / 16; + else + { + if (newwidth < 11) + newwidth = 21; + else if (newwidth < 14) + newwidth = 22; + else + newwidth = 23; + typettf.width = typettf.height = (FT_UShort) newwidth; + } + for (i = 0; i <= 12; i++) + axdrcs[i] = (fontwidth * i + 6) / 12; + } +} + + +void setcolors(unsigned short *pcolormap, int offset, int number) +{ + int i,trans_tmp; + int j = offset; /* index in global color table */ + + trans_tmp=25-trans_mode; + + bgra[transp2][3]=((trans_tmp+7)<<11 | 0x7FF)>>8; + + for (i = 0; i < number; i++) + { + int r = (pcolormap[i] << 12 & 0xF000) >> 8; + int g = (pcolormap[i] << 8 & 0xF000) >> 8; + int b = (pcolormap[i] << 4 & 0xF000) >> 8; + + r = (r * (0x3f+(color_mode<<3))) >> 8; + g = (g * (0x3f+(color_mode<<3))) >> 8; + b = (b * (0x3f+(color_mode<<3))) >> 8; + + bgra[j][2]=r; + bgra[j][1]=g; + bgra[j][0]=b; + + j++; + } +} + + +/* hexdump of page contents to stdout for debugging */ +void dump_page() +{ + int r, c; + char *p; + unsigned char pagedata[23*40]; + + if (!tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage]) + return; + tuxtxt_decompress_page(tuxtxt_cache.page,tuxtxt_cache.subpage,pagedata); + for (r=1; r < 24; r++) + { + p = (char *) pagedata+40*(r-1); + for (c=0; c < 40; c++) + printf(" %02x", *p++); + printf("\n"); + p = (char *) page_char + 40*r; + for (c=0; c < 40; c++) + printf(" %c", *p++); + printf("\n"); + } +} + + +/* get object data */ +/* in: absolute triplet number (0..506, start at packet 3 byte 1) */ +/* in: pointer to cache struct of page data */ +/* out: 18 bit triplet data, <0 if invalid number, not cached, or hamming error */ +int iTripletNumber2Data(int iONr, tstCachedPage *pstCachedPage, unsigned char* pagedata) +{ + if (iONr > 506 || 0 == pstCachedPage) + return -1; + + unsigned char *p; + int packet = (iONr / 13) + 3; + int packetoffset = 3 * (iONr % 13); + + if (packet <= 23) + p = pagedata + 40*(packet-1) + packetoffset + 1; + else if (packet <= 25) + { + if (0 == pstCachedPage->pageinfo.p24) + return -1; + p = pstCachedPage->pageinfo.p24 + 40*(packet-24) + packetoffset + 1; + } + else + { + int descode = packet - 26; + if (0 == pstCachedPage->pageinfo.ext) + return -1; + if (0 == pstCachedPage->pageinfo.ext->p26[descode]) + return -1; + p = pstCachedPage->pageinfo.ext->p26[descode] + packetoffset; /* first byte (=designation code) is not cached */ + } + return deh24(p); +} + +#define RowAddress2Row(row) ((row == 40) ? 24 : (row - 40)) + +/* dump interpreted object data to stdout */ +/* in: 18 bit object data */ +/* out: termination info, >0 if end of object */ +void eval_object(int iONr, tstCachedPage *pstCachedPage, + unsigned char *pAPx, unsigned char *pAPy, + unsigned char *pAPx0, unsigned char *pAPy0, + tObjType ObjType, unsigned char* pagedata) +{ + int iOData; + int iONr1 = iONr + 1; /* don't terminate after first triplet */ + unsigned char drcssubp=0, gdrcssubp=0; + signed char endcol = -1; /* last column to which to extend attribute changes */ + tstPageAttr attrPassive = atrtable[ATR_PassiveDefault]; /* current attribute for passive objects */ + + do + { + iOData = iTripletNumber2Data(iONr, pstCachedPage,pagedata); /* get triplet data, next triplet */ + if (iOData < 0) /* invalid number, not cached, or hamming error: terminate */ + break; +#if TUXTXT_DEBUG + if (dumpl25) + printf(" t%03d ", iONr); +#endif + if (endcol < 0) + { + if (ObjType == OBJ_ACTIVE) + { + endcol = 40; + } + else if (ObjType == OBJ_ADAPTIVE) /* search end of line */ + { + int i; + for (i = iONr; i <= 506; i++) + { + int iTempOData = iTripletNumber2Data(i, pstCachedPage,pagedata); /* get triplet data, next triplet */ + int iAddress = (iTempOData ) & 0x3f; + int iMode = (iTempOData >> 6) & 0x1f; + //int iData = (iTempOData >> 11) & 0x7f; + if (iTempOData < 0 || /* invalid number, not cached, or hamming error: terminate */ + (iAddress >= 40 /* new row: row address and */ + && (iMode == 0x01 || /* Full Row Color or */ + iMode == 0x04 || /* Set Active Position */ + (iMode >= 0x15 && iMode <= 0x17) || /* Object Definition */ + iMode == 0x17))) /* Object Termination */ + break; + if (iAddress < 40 && iMode != 0x06) + endcol = iAddress; + } +#if TUXTXT_DEBUG + if (dumpl25) + printf(" endcol %02d", endcol); +#endif + } + } + iONr++; + } + while (0 == eval_triplet(iOData, pstCachedPage, pAPx, pAPy, pAPx0, pAPy0, &drcssubp, &gdrcssubp, &endcol, &attrPassive, pagedata) + || iONr1 == iONr); /* repeat until termination reached */ +} + +void eval_NumberedObject(int p, int s, int packet, int triplet, int high, + unsigned char *pAPx, unsigned char *pAPy, + unsigned char *pAPx0, unsigned char *pAPy0) +{ + if (!packet || 0 == tuxtxt_cache.astCachetable[p][s]) + return; + unsigned char pagedata[23*40]; + tuxtxt_decompress_page(p, s,pagedata); + + + int idata = deh24(pagedata + 40*(packet-1) + 1 + 3*triplet); + int iONr; + + if (idata < 0) /* hamming error: ignore triplet */ + return; + if (high) + iONr = idata >> 9; /* triplet number of odd object data */ + else + iONr = idata & 0x1ff; /* triplet number of even object data */ + if (iONr <= 506) + { +#if TUXTXT_DEBUG + if (dumpl25) + printf("P%xT%x%c %8s %c#%03d@%03d\n", packet, triplet, "LH"[!!high], /* pointer pos, type, number, data pos */ + ObjectType[triplet % 3], "PCD"[triplet % 3], 8*packet + 2*(triplet-1)/3, iONr); + +#endif + eval_object(iONr, tuxtxt_cache.astCachetable[p][s], pAPx, pAPy, pAPx0, pAPy0, (tObjType)(triplet % 3),pagedata); + } +} + +int eval_triplet(int iOData, tstCachedPage *pstCachedPage, + unsigned char *pAPx, unsigned char *pAPy, + unsigned char *pAPx0, unsigned char *pAPy0, + unsigned char *drcssubp, unsigned char *gdrcssubp, + signed char *endcol, tstPageAttr *attrPassive, unsigned char* pagedata) +{ + int iAddress = (iOData ) & 0x3f; + int iMode = (iOData >> 6) & 0x1f; + int iData = (iOData >> 11) & 0x7f; + + if (iAddress < 40) /* column addresses */ + { + int offset; /* offset to page_char and page_atrb */ + + if (iMode != 0x06) + *pAPx = iAddress; /* new Active Column */ + offset = (*pAPy0 + *pAPy) * 40 + *pAPx0 + *pAPx; /* offset to page_char and page_atrb */ +#if TUXTXT_DEBUG + if (dumpl25) + printf(" M%02xC%02xD%02x %d r:%d ch:%02x", iMode, iAddress, iData, *endcol,*pAPy0 + *pAPy,page_char[offset]); +#endif + + switch (iMode) + { + case 0x00: + if (0 == (iData>>5)) + { + int newcolor = iData & 0x1f; + if (*endcol < 0) /* passive object */ + attrPassive->fg = newcolor; + else if (*endcol == 40) /* active object */ + { + tstPageAttr *p = &page_atrb[offset]; + int oldcolor = (p)->fg; /* current color (set-after) */ + int c = *pAPx0 + *pAPx; /* current column absolute */ + do + { + p->fg = newcolor; + p++; + c++; + } while (c < 40 && p->fg == oldcolor); /* stop at change by level 1 page */ + } + else /* adaptive object */ + { + tstPageAttr *p = &page_atrb[offset]; + int c = *pAPx; /* current column relative to object origin */ + do + { + p->fg = newcolor; + p++; + c++; + } while (c <= *endcol); + } +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d FGCol T%x#%x", iAddress, (iData>>3)&0x03, iData&0x07); +#endif + } + break; + case 0x01: + if (iData >= 0x20) + { +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d BlockMosaic G1 #%02x", iAddress, iData); +#endif + page_char[offset] = iData; + if (*endcol < 0) /* passive object */ + { + attrPassive->charset = C_G1C; /* FIXME: separated? */ + page_atrb[offset] = *attrPassive; + } + else if (page_atrb[offset].charset != C_G1S) + page_atrb[offset].charset = C_G1C; /* FIXME: separated? */ + } + break; + case 0x02: + case 0x0b: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d G3 #%02x f%db%d", iAddress, iData,attrPassive->fg, attrPassive->bg); +#endif + page_char[offset] = iData; + if (*endcol < 0) /* passive object */ + { + attrPassive->charset = C_G3; + page_atrb[offset] = *attrPassive; + } + else + page_atrb[offset].charset = C_G3; + break; + case 0x03: + if (0 == (iData>>5)) + { + int newcolor = iData & 0x1f; + if (*endcol < 0) /* passive object */ + attrPassive->bg = newcolor; + else if (*endcol == 40) /* active object */ + { + tstPageAttr *p = &page_atrb[offset]; + int oldcolor = (p)->bg; /* current color (set-after) */ + int c = *pAPx0 + *pAPx; /* current column absolute */ + do + { + p->bg = newcolor; + if (newcolor == black) + p->IgnoreAtBlackBgSubst = 1; + p++; + c++; + } while (c < 40 && p->bg == oldcolor); /* stop at change by level 1 page */ + } + else /* adaptive object */ + { + tstPageAttr *p = &page_atrb[offset]; + int c = *pAPx; /* current column relative to object origin */ + do + { + p->bg = newcolor; + if (newcolor == black) + p->IgnoreAtBlackBgSubst = 1; + p++; + c++; + } while (c <= *endcol); + } +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d BGCol T%x#%x", iAddress, (iData>>3)&0x03, iData&0x07); +#endif + } + break; + case 0x06: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" PDC"); +#endif + /* ignore */ + break; + case 0x07: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d Flash M%xP%x", iAddress, iData & 0x03, (iData >> 2) & 0x07); +#endif + if ((iData & 0x60) != 0) break; // reserved data field + if (*endcol < 0) /* passive object */ + { + attrPassive->flashing=iData & 0x1f; + page_atrb[offset] = *attrPassive; + } + else + page_atrb[offset].flashing=iData & 0x1f; + break; + case 0x08: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d G0+G2 set #%02x (p105)", iAddress, iData); +#endif + if (*endcol < 0) /* passive object */ + { + attrPassive->setG0G2=iData & 0x3f; + page_atrb[offset] = *attrPassive; + } + else + page_atrb[offset].setG0G2=iData & 0x3f; + break; + case 0x09: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d G0 #%02x '%c'", iAddress, iData, iData); +#endif + page_char[offset] = iData; + if (*endcol < 0) /* passive object */ + { + attrPassive->charset = C_G0P; /* FIXME: secondary? */ + attrPassive->setX26 = 1; + page_atrb[offset] = *attrPassive; + } + else + { + page_atrb[offset].charset = C_G0P; /* FIXME: secondary? */ + page_atrb[offset].setX26 = 1; + } + break; +// case 0x0b: (see 0x02) + case 0x0c: + { +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d Attribute%s%s%s%s%s%s", iAddress, + (iData & 0x40) ? " DoubleWidth" : "", + (iData & 0x20) ? " UnderlineSep" : "", + (iData & 0x10) ? " InvColour" : "", + (iData & 0x04) ? " Conceal" : "", + (iData & 0x02) ? " Boxing" : "", + (iData & 0x01) ? " DoubleHeight" : ""); +#endif + int conc = (iData & 0x04); + int inv = (iData & 0x10); + int dw = (iData & 0x40 ?1:0); + int dh = (iData & 0x01 ?1:0); + int sep = (iData & 0x20); + int bw = (iData & 0x02 ?1:0); + if (*endcol < 0) /* passive object */ + { + if (conc) + { + attrPassive->concealed = 1; + attrPassive->fg = attrPassive->bg; + } + attrPassive->inverted = (inv ? 1- attrPassive->inverted : 0); + attrPassive->doubleh = dh; + attrPassive->doublew = dw; + attrPassive->boxwin = bw; + if (bw) attrPassive->IgnoreAtBlackBgSubst = 0; + if (sep) + { + if (attrPassive->charset == C_G1C) + attrPassive->charset = C_G1S; + else + attrPassive->underline = 1; + } + else + { + if (attrPassive->charset == C_G1S) + attrPassive->charset = C_G1C; + else + attrPassive->underline = 0; + } + } + else + { + + int c = *pAPx0 + (*endcol == 40 ? *pAPx : 0); /* current column */ + int c1 = offset; + tstPageAttr *p = &page_atrb[offset]; + do + { + p->inverted = (inv ? 1- p->inverted : 0); + if (conc) + { + p->concealed = 1; + p->fg = p->bg; + } + if (sep) + { + if (p->charset == C_G1C) + p->charset = C_G1S; + else + p->underline = 1; + } + else + { + if (p->charset == C_G1S) + p->charset = C_G1C; + else + p->underline = 0; + } + p->doublew = dw; + p->doubleh = dh; + p->boxwin = bw; + if (bw) p->IgnoreAtBlackBgSubst = 0; + p++; + c++; + c1++; + } while (c < *endcol); + } + break; + } + case 0x0d: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d %cDRCS #%02x", iAddress, (iData & 0x40) ? ' ' : 'G', iData & 0x3f); +#endif + page_char[offset] = iData & 0x3f; + if (*endcol < 0) /* passive object */ + { + attrPassive->charset = C_OFFSET_DRCS + ((iData & 0x40) ? (0x10 + *drcssubp) : *gdrcssubp); + page_atrb[offset] = *attrPassive; + } + else + page_atrb[offset].charset = C_OFFSET_DRCS + ((iData & 0x40) ? (0x10 + *drcssubp) : *gdrcssubp); + break; + case 0x0f: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d G2 #%02x", iAddress, iData); +#endif + page_char[offset] = iData; + if (*endcol < 0) /* passive object */ + { + attrPassive->charset = C_G2; + page_atrb[offset] = *attrPassive; + } + else + page_atrb[offset].charset = C_G2; + break; + default: + if (iMode == 0x10 && iData == 0x2a) + iData = '@'; + if (iMode >= 0x10) + { +#if TUXTXT_DEBUG + if (dumpl25) + printf(" ,%02d G0 #%02x %c +diacr. %x", iAddress, iData, iData, iMode & 0x0f); +#endif + page_char[offset] = iData; + if (*endcol < 0) /* passive object */ + { + attrPassive->charset = C_G0P; + attrPassive->diacrit = iMode & 0x0f; + attrPassive->setX26 = 1; + page_atrb[offset] = *attrPassive; + } + else + { + page_atrb[offset].charset = C_G0P; + page_atrb[offset].diacrit = iMode & 0x0f; + page_atrb[offset].setX26 = 1; + } + } + break; /* unsupported or not yet implemented mode: ignore */ + } /* switch (iMode) */ + } + else /* ================= (iAddress >= 40): row addresses ====================== */ + { +#if TUXTXT_DEBUG + if (dumpl25) + printf(" M%02xR%02xD%02x", iMode, iAddress, iData); +#endif + switch (iMode) + { + case 0x00: + if (0 == (iData>>5)) + { +#if TUXTXT_DEBUG + if (dumpl25) + printf(" FScrCol T%x#%x", (iData>>3)&0x03, iData&0x07); +#endif + FullScrColor = iData & 0x1f; + } + break; + case 0x01: + if (*endcol == 40) /* active object */ + { + *pAPy = RowAddress2Row(iAddress); /* new Active Row */ + + int color = iData & 0x1f; + int row = *pAPy0 + *pAPy; + int maxrow; +#if TUXTXT_DEBUG + if (dumpl25) + { + printf(" AP=%d,0", RowAddress2Row(iAddress)); + if (0 == (iData>>5)) + printf(" FRowCol T%x#%x", (iData>>3)&0x03, iData&0x07); + else if (3 == (iData>>5)) + printf(" FRowCol++ T%x#%x", (iData>>3)&0x03, iData&0x07); + } +#endif + if (row <= 24 && 0 == (iData>>5)) + maxrow = row; + else if (3 == (iData>>5)) + maxrow = 24; + else + maxrow = -1; + for (; row <= maxrow; row++) + FullRowColor[row] = color; + *endcol = -1; + } + break; + case 0x04: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" AP=%d,%d", RowAddress2Row(iAddress), iData); +#endif + *pAPy = RowAddress2Row(iAddress); /* new Active Row */ + if (iData < 40) + *pAPx = iData; /* new Active Column */ + *endcol = -1; /* FIXME: check if row changed? */ + break; + case 0x07: +#if TUXTXT_DEBUG + if (dumpl25) + { + if (iAddress == 0x3f) + printf(" AP=0,0"); + if (0 == (iData>>5)) + printf(" Address Display R0 FRowCol T%x#%x", (iData>>3)&0x03, iData&0x07); + else if (3 == (iData>>5)) + printf(" Address Display R0->24 FRowCol T%x#%x", (iData>>3)&0x03, iData&0x07); + } +#endif + if (iAddress == 0x3f) + { + *pAPx = *pAPy = 0; /* new Active Position 0,0 */ + if (*endcol == 40) /* active object */ + { + int color = iData & 0x1f; + int row = *pAPy0; // + *pAPy; + int maxrow; + + if (row <= 24 && 0 == (iData>>5)) + maxrow = row; + else if (3 == (iData>>5)) + maxrow = 24; + else + maxrow = -1; + for (; row <= maxrow; row++) + FullRowColor[row] = color; + } + *endcol = -1; + } + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" PDC"); +#endif + /* ignore */ + break; + case 0x10: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" AP=%d,%d temp. Origin Modifier", iAddress - 40, iData); +#endif + tAPy = iAddress - 40; + tAPx = iData; + break; + case 0x11: + case 0x12: + case 0x13: + if (iAddress & 0x10) /* POP or GPOP */ + { + unsigned char APx = 0, APy = 0; + unsigned char APx0 = *pAPx0 + *pAPx + tAPx, APy0 = *pAPy0 + *pAPy + tAPy; + int triplet = 3 * ((iData >> 5) & 0x03) + (iMode & 0x03); + int packet = (iAddress & 0x03) + 1; + int subp = iData & 0x0f; + int high = (iData >> 4) & 0x01; + + + if (APx0 < 40) /* not in side panel */ + { +#if TUXTXT_DEBUG + if (dumpl25) + printf(" Object Invocation %5s %8s S%xP%xT%x%c %c#%03d\n---", + ObjectSource[(iAddress >> 3) & 0x03], ObjectType[iMode & 0x03], + subp, + packet, + triplet, + "LH"[high], /* low/high */ + "PCD"[triplet % 3], + 8*packet + 2*(triplet-1)/3 + 1); +#endif + eval_NumberedObject((iAddress & 0x08) ? gpop : pop, subp, packet, triplet, high, &APx, &APy, &APx0, &APy0); +#if TUXTXT_DEBUG + if (dumpl25) + printf("---"); +#endif + } +#if TUXTXT_DEBUG + else if (dumpl25) + printf("Object Invocation for Side Panel - ignored"); +#endif + } + else if (iAddress & 0x08) /* local: eval invoked object */ + { + unsigned char APx = 0, APy = 0; + unsigned char APx0 = *pAPx0 + *pAPx + tAPx, APy0 = *pAPy0 + *pAPy + tAPy; + int descode = ((iAddress & 0x01) << 3) | (iData >> 4); + int triplet = iData & 0x0f; + + if (APx0 < 40) /* not in side panel */ + { +#if TUXTXT_DEBUG + if (dumpl25) + printf(" local Object Invocation %5s %8s D%xT%x:\n---", + ObjectSource[(iAddress >> 3) & 0x03], ObjectType[iMode & 0x03], descode, triplet); +#endif + eval_object(13 * 23 + 13 * descode + triplet, pstCachedPage, &APx, &APy, &APx0, &APy0, (tObjType)(triplet % 3), pagedata); +#if TUXTXT_DEBUG + if (dumpl25) + printf("---"); +#endif + } +#if TUXTXT_DEBUG + else if (dumpl25) + printf("local Object Invocation for Side Panel - ignored"); +#endif + } + break; + case 0x15: + case 0x16: + case 0x17: + if (0 == (iAddress & 0x08)) /* Object Definition illegal or only level 3.5 */ + break; /* ignore */ +#if TUXTXT_DEBUG + if (dumpl25) + { + printf(" Object Definition %8s", ObjectType[iMode & 0x03]); + { /* *POP */ + int triplet = 3 * ((iData >> 5) & 0x03) + (iMode & 0x03); + int packet = (iAddress & 0x03) + 1; + printf(" S%xP%xT%x%c %c#%03d", + iData & 0x0f, /* subpage */ + packet, + triplet, + "LH"[(iData >> 4) & 0x01], /* low/high */ + "PCD"[triplet % 3], + 8*packet + 2*(triplet-1)/3 + 1); + } + { /* local */ + int descode = ((iAddress & 0x03) << 3) | (iData >> 4); + int triplet = iData & 0x0f; + printf(" D%xT%x", descode, triplet); + } + putchar('\n'); + } +#endif + tAPx = tAPy = 0; + *endcol = -1; + return 0xFF; /* termination by object definition */ + break; + case 0x18: + if (0 == (iData & 0x10)) /* DRCS Mode reserved or only level 3.5 */ + break; /* ignore */ +#if TUXTXT_DEBUG + if (dumpl25) + printf(" %cDRCS S%x", (iData & 0x40) ? ' ' : 'G', iData & 0x0f); /* subpage */ +#endif + if (iData & 0x40) + *drcssubp = iData & 0x0f; + else + *gdrcssubp = iData & 0x0f; + break; + case 0x1f: +#if TUXTXT_DEBUG + if (dumpl25) + printf(" Termination Marker %x\n", iData); /* subpage */ +#endif + tAPx = tAPy = 0; + *endcol = -1; + return 0x80 | iData; /* explicit termination */ + break; + default: + break; /* unsupported or not yet implemented mode: ignore */ + } /* switch (iMode) */ + } /* (iAddress >= 40): row addresses */ +#if TUXTXT_DEBUG + if (dumpl25 && iAddress < 40) + putchar('\n'); +#endif + if (iAddress < 40 || iMode != 0x10) /* leave temp. AP-Offset unchanged only immediately after definition */ + tAPx = tAPy = 0; + + + return 0; /* normal exit, no termination */ +} +int setnational(unsigned char sec) +{ + switch (sec) + { + case 0x08: + return NAT_PL; //polish + case 0x16: + case 0x36: + return NAT_TR; //turkish + case 0x1d: + return NAT_SR; //serbian, croatian, slovenian + case 0x20: + case 0x24: + case 0x25: + return NAT_RU; // cyrillic + case 0x22: + return NAT_ET; // estonian + case 0x23: + return NAT_LV; // latvian, lithuanian + case 0x37: + return NAT_GR; // greek + case 0x47: + case 0x57: + // TODO : arabic + break; + case 0x55: + // TODO : hebrew + break; + + } + return countryconversiontable[sec & 0x07]; +} + +/* evaluate level 2.5 information */ +void eval_l25() +{ + memset(FullRowColor, 0, sizeof(FullRowColor)); + FullScrColor = black; + + if (!tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage]) + return; + +#if TUXTXT_DEBUG + if (dumpl25) + printf("=== %03x/%02x %d/%d===\n", tuxtxt_cache.page, tuxtxt_cache.subpage,tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage]->pageinfo.nationalvalid,tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage]->pageinfo.national); +#endif + +#if 0 //TUXTXT_DEBUG I don't think we need this any longer because this code is unreachable (HexPages are handled before eval_l25() is called) + if (pageinfo->function == FUNC_MOT) /* magazine organization table */ + { + int i; + unsigned char *p = pagedata; + + printf("(G)POP/(G)DRCS-associations:\n"); + printf(" 0011223344556677889900112233445566778899"); + for (i = 0; i < 200; i++) + { + if (p[i] == 0xff) + break; + if (0 == (i % 40)) + printf("\n%x ", i / 20); + putchar(number2char(p[i])); + } + putchar('\n'); + + p = pagedata + 18*40; + for (i = 0; i < 80; i += 10) + { + short pop = ((p[i] << 8) | (p[i+1] << 4) | p[i+2]) & 0x7ff; + unsigned char type = p[i+5] & 0x03; /* 1st default object */ + unsigned char triplet = 3 * ((p[i+7] >> 1) & 0x03) + type; + unsigned char packet = (p[i+7] & 0x08) >> 3; + unsigned char subp = p[i+6]; + if (pop < 0x100) + pop += 0x800; + printf("POP #%x %03x/%x p27prio:%x", i/10, pop, p[i+3], p[i] & 0x08); + printf(" DefObj S%xP%xT%x%c %c#%03d", tuxtxt_cache.subpage, packet, triplet, "LH"[p[i+7] & 0x01], + "-CDP"[type], 8*packet + 2*(triplet-1)/3 + 1); + type = (p[i+5] >> 2) & 0x03; /* 2nd default object */ + triplet = 3 * ((p[i+9] >> 1) & 0x03) + type; + packet = (p[i+9] & 0x08) >> 3; + subp = p[i+8]; + printf(", S%xP%xT%x%c %c#%03d", tuxtxt_cache.subpage, packet, triplet, "LH"[p[i+9] & 0x01], + "-CDP"[type], 8*packet + 2*(triplet-1)/3 + 1); + if ((p[i+4] & 0x01) == 0) + printf(" Sidep.:%c%c BgSubst.:%x", (p[i+4] & 0x02) ? 'L' : '-', (p[i+4] & 0x04) ? 'R' : '-', p[i+4] >> 3); + putchar('\n'); + if ((pop & 0xff) != 0xff && tuxtxt_cache.astCachetable[pop][0]) /* link valid && linked page cached */ + { + tstPageinfo *pageinfo_link = &(tuxtxt_cache.astCachetable[pop][0]->pageinfo); + if (!i) + pageinfo_link->function = FUNC_GPOP; + else + pageinfo_link->function = FUNC_POP; + } + } + + p = pagedata + 20*40; + for (i = 0; i < 4*8; i += 4) + { + short drcs = ((p[i] << 8) | (p[i+1] << 4) | p[i+2]) & 0x7ff; + if (drcs < 0x100) + drcs += 0x800; + printf("DRCS #%x %03x/%x p27prio:%x\n", i/4, drcs, p[i+3], p[i] & 0x08); + if ((drcs & 0xff) != 0xff && tuxtxt_cache.astCachetable[drcs][0]) /* link valid && linked page cached */ + { + tstPageinfo *pageinfo_link = &(tuxtxt_cache.astCachetable[drcs][0]->pageinfo); + if (!i) + pageinfo_link->function = FUNC_GDRCS; + else + pageinfo_link->function = FUNC_DRCS; + } + } + } /* function == FUNC_MOT */ + +// else if (pageinfo->function == FUNC_GPOP || pageinfo->function == FUNC_POP) /* object definitions */ + else if (!tuxtxt_is_dec(tuxtxt_cache.page) && pageinfo->function != FUNC_GDRCS && pageinfo->function != FUNC_DRCS) /* in case the function is not assigned properly */ + { + unsigned char APx0, APy0, APx, APy; + int packet; + + pop = gpop = tuxtxt_cache.page; + + for (packet = 1; packet <= 4; packet++) + { + unsigned char *ptriplet = pagedata + 40*(packet-1); + int idata = dehamming[*ptriplet]; + int triplet; + + if (idata == 0xff || 0 == (idata & 1)) /* hamming error or no pointer data: ignore packet */ + continue; + for (triplet = 1; triplet <= 12; triplet++) + { + APx0 = APy0 = APx = APy = tAPx = tAPy = 0; + eval_NumberedObject(tuxtxt_cache.page, tuxtxt_cache.subpage, packet, triplet, 0, &APx, &APy, &APx0, &APy0); + APx0 = APy0 = APx = APy = tAPx = tAPy = 0; + eval_NumberedObject(tuxtxt_cache.page, tuxtxt_cache.subpage, packet, triplet, 1, &APx, &APy, &APx0, &APy0); + } /* for triplet */ + } /* for packet */ + } /* function == FUNC_*POP */ +#endif /* TUXTXT_DEBUG */ + + /* normal page */ + if (tuxtxt_is_dec(tuxtxt_cache.page)) + { + unsigned char APx0, APy0, APx, APy; + tstPageinfo *pi = &(tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage]->pageinfo); + tstCachedPage *pmot = tuxtxt_cache.astCachetable[(tuxtxt_cache.page & 0xf00) | 0xfe][0]; + unsigned short *colortable = 0; + int p26Received = 0; + int BlackBgSubst = 0; + int ColorTableRemapping = 0; + + + pop = gpop = drcs = gdrcs = 0; + + + if (pi->ext) + { + tstExtData *e = pi->ext; + + if (e->p26[0]) + p26Received = 1; + + if (e->p27) + { + tstp27 *p27 = e->p27; + if (p27[0].l25) + gpop = p27[0].page; + if (p27[1].l25) + pop = p27[1].page; + if (p27[2].l25) + gdrcs = p27[2].page; + if (p27[3].l25) + drcs = p27[3].page; + } + + if (e->p28Received) + { + colortable = e->bgr; + BlackBgSubst = e->BlackBgSubst; + ColorTableRemapping = e->ColorTableRemapping; + memset(FullRowColor, e->DefRowColor, sizeof(FullRowColor)); + FullScrColor = e->DefScreenColor; + national_subset = setnational(e->DefaultCharset); + national_subset_secondary = setnational(e->SecondCharset); +#if TUXTXT_DEBUG + if (dumpl25) + { + int c; /* color */ + printf("p28/0: DefCharset %02x Sec %02x SidePanel %c%c%x DefScrCol %02x DefRowCol %02x BlBgSubst %x Map %x\n CBGR", + e->DefaultCharset, + e->SecondCharset, + e->LSP ? (e->SPL25 ? 'L' : 'l') : '-', /* left panel (small: only in level 3.5) */ + e->RSP ? (e->SPL25 ? 'R' : 'r') : '-', /* right panel (small: only in level 3.5) */ + e->LSPColumns, + e->DefScreenColor, + e->DefRowColor, + e->BlackBgSubst, + e->ColorTableRemapping); + for (c = 0; c < 16; c++) + printf(" %x%03x", c, e->bgr[c]); + putchar('\n'); + } +#endif + } /* e->p28Received */ + } + + if (!colortable && tuxtxt_cache.astP29[tuxtxt_cache.page >> 8]) + { + tstExtData *e = tuxtxt_cache.astP29[tuxtxt_cache.page >> 8]; + colortable = e->bgr; + BlackBgSubst = e->BlackBgSubst; + ColorTableRemapping = e->ColorTableRemapping; + memset(FullRowColor, e->DefRowColor, sizeof(FullRowColor)); + FullScrColor = e->DefScreenColor; + national_subset = setnational(e->DefaultCharset); + national_subset_secondary = setnational(e->SecondCharset); +#if TUXTXT_DEBUG + if (dumpl25) + { + int c; /* color */ + printf("p29/0: DefCharset %02x Sec %02x SidePanel %c%c%x DefScrCol %02x DefRowCol %02x BlBgSubst %x Map %x\n CBGR", + e->DefaultCharset, + e->SecondCharset, + e->LSP ? (e->SPL25 ? 'L' : 'l') : '-', /* left panel (small: only in level 3.5) */ + e->RSP ? (e->SPL25 ? 'R' : 'r') : '-', /* right panel (small: only in level 3.5) */ + e->LSPColumns, + e->DefScreenColor, + e->DefRowColor, + e->BlackBgSubst, + e->ColorTableRemapping); + for (c = 0; c < 16; c++) + printf(" %x%03x", c, e->bgr[c]); + putchar('\n'); + } +#endif + + } + + if (ColorTableRemapping) + { + int i; + for (i = 0; i < 25*40; i++) + { + page_atrb[i].fg += MapTblFG[ColorTableRemapping - 1]; + if (!BlackBgSubst || page_atrb[i].bg != black || page_atrb[i].IgnoreAtBlackBgSubst) + page_atrb[i].bg += MapTblBG[ColorTableRemapping - 1]; + } + } + + /* determine ?pop/?drcs from MOT */ + if (pmot) + { + unsigned char pmot_data[23*40]; + tuxtxt_decompress_page((tuxtxt_cache.page & 0xf00) | 0xfe,0,pmot_data); + + unsigned char *p = pmot_data; /* start of link data */ + int o = 2 * (((tuxtxt_cache.page & 0xf0) >> 4) * 10 + (tuxtxt_cache.page & 0x0f)); /* offset of links for current page */ + int opop = p[o] & 0x07; /* index of POP link */ + int odrcs = p[o+1] & 0x07; /* index of DRCS link */ + unsigned char obj[3*4*4]; // types* objects * (triplet,packet,subp,high) + unsigned char type,ct, tstart = 4*4; + memset(obj,0,sizeof(obj)); + + + if (p[o] & 0x08) /* GPOP data used */ + { + if (!gpop || !(p[18*40] & 0x08)) /* no p27 data or higher prio of MOT link */ + { + gpop = ((p[18*40] << 8) | (p[18*40+1] << 4) | p[18*40+2]) & 0x7ff; + if ((gpop & 0xff) == 0xff) + gpop = 0; + else + { + if (gpop < 0x100) + gpop += 0x800; + if (!p26Received) + { + ct=2; + while (ct) + { + ct--; + type = (p[18*40+5] >> 2*ct) & 0x03; + + if (type == 0) continue; + obj[(type-1)*(tstart)+ct*4 ] = 3 * ((p[18*40+7+ct*2] >> 1) & 0x03) + type; //triplet + obj[(type-1)*(tstart)+ct*4+1] = ((p[18*40+7+ct*2] & 0x08) >> 3) + 1 ; //packet + obj[(type-1)*(tstart)+ct*4+2] = p[18*40+6+ct*2] & 0x0f ; //subp + obj[(type-1)*(tstart)+ct*4+3] = p[18*40+7+ct*2] & 0x01 ; //high + +#if TUXTXT_DEBUG + if (dumpl25) + printf("GPOP DefObj%d S%xP%xT%x%c %c#%03d\n" + ,2-ct + , obj[(type-1)*(tstart)+ct*4+2] + , obj[(type-1)*(tstart)+ct*4+1] + , obj[(type-1)*(tstart)+ct*4] + , "LH"[obj[(type-1)*(tstart)+ct*4+3]] + , "-CDP"[type] + , 8*(obj[(type-1)*(tstart)+ct*4+1]-1) + 2*(obj[(type-1)*(tstart)+ct*4]-1)/3 + 1); +#endif + } + } + } + } + } + if (opop) /* POP data used */ + { + opop = 18*40 + 10*opop; /* offset to POP link */ + if (!pop || !(p[opop] & 0x08)) /* no p27 data or higher prio of MOT link */ + { + pop = ((p[opop] << 8) | (p[opop+1] << 4) | p[opop+2]) & 0x7ff; + if ((pop & 0xff) == 0xff) + pop = 0; + else + { + if (pop < 0x100) + pop += 0x800; + if (!p26Received) + { + ct=2; + while (ct) + { + ct--; + type = (p[opop+5] >> 2*ct) & 0x03; + + if (type == 0) continue; + obj[(type-1)*(tstart)+(ct+2)*4 ] = 3 * ((p[opop+7+ct*2] >> 1) & 0x03) + type; //triplet + obj[(type-1)*(tstart)+(ct+2)*4+1] = ((p[opop+7+ct*2] & 0x08) >> 3) + 1 ; //packet + obj[(type-1)*(tstart)+(ct+2)*4+2] = p[opop+6+ct*2] ; //subp + obj[(type-1)*(tstart)+(ct+2)*4+3] = p[opop+7+ct*2] & 0x01 ; //high +#if TUXTXT_DEBUG + if (dumpl25) + printf("POP DefObj%d S%xP%xT%x%c %c#%03d\n" + , 2-ct + , obj[(type-1)*(tstart)+(ct+2)*4+2] + , obj[(type-1)*(tstart)+(ct+2)*4+1] + , obj[(type-1)*(tstart)+(ct+2)*4] + , "LH"[obj[(type-1)*(tstart)+(ct+2)*4+3]] + , "-CDP"[type], 8*(obj[(type-1)*(tstart)+(ct+2)*4+1]-1) + 2*(obj[(type-1)*(tstart)+(ct+2)*4]-1)/3 + 1); +#endif + } + } + } + } + } + // eval default objects in correct order + for (ct = 0; ct < 12; ct++) + { +#if TUXTXT_DEBUG + if (dumpl25) + printf("eval DefObjs : %d S%xP%xT%x%c %c#%03d\n" + , ct + , obj[ct*4+2] + , obj[ct*4+1] + , obj[ct*4] + , "LH"[obj[ct*4+3]] + , "-CDP"[obj[ct*4 % 3]] + , 8*(obj[ct*4+1]-1) + 2*(obj[ct*4]-1)/3 + 1); +#endif + if (obj[ct*4] != 0) + { + APx0 = APy0 = APx = APy = tAPx = tAPy = 0; + eval_NumberedObject(ct % 4 > 1 ? pop : gpop, obj[ct*4+2], obj[ct*4+1], obj[ct*4], obj[ct*4+3], &APx, &APy, &APx0, &APy0); + } + } + + if (p[o+1] & 0x08) /* GDRCS data used */ + { + if (!gdrcs || !(p[20*40] & 0x08)) /* no p27 data or higher prio of MOT link */ + { + gdrcs = ((p[20*40] << 8) | (p[20*40+1] << 4) | p[20*40+2]) & 0x7ff; + if ((gdrcs & 0xff) == 0xff) + gdrcs = 0; + else if (gdrcs < 0x100) + gdrcs += 0x800; + } + } + if (odrcs) /* DRCS data used */ + { + odrcs = 20*40 + 4*odrcs; /* offset to DRCS link */ + if (!drcs || !(p[odrcs] & 0x08)) /* no p27 data or higher prio of MOT link */ + { + drcs = ((p[odrcs] << 8) | (p[odrcs+1] << 4) | p[odrcs+2]) & 0x7ff; + if ((drcs & 0xff) == 0xff) + drcs = 0; + else if (drcs < 0x100) + drcs += 0x800; + } + } + if (tuxtxt_cache.astCachetable[gpop][0]) + tuxtxt_cache.astCachetable[gpop][0]->pageinfo.function = FUNC_GPOP; + if (tuxtxt_cache.astCachetable[pop][0]) + tuxtxt_cache.astCachetable[pop][0]->pageinfo.function = FUNC_POP; + if (tuxtxt_cache.astCachetable[gdrcs][0]) + tuxtxt_cache.astCachetable[gdrcs][0]->pageinfo.function = FUNC_GDRCS; + if (tuxtxt_cache.astCachetable[drcs][0]) + tuxtxt_cache.astCachetable[drcs][0]->pageinfo.function = FUNC_DRCS; + } /* if mot */ + +#if TUXTXT_DEBUG + if (dumpl25) + printf("gpop %03x pop %03x gdrcs %03x drcs %03x p28/0: Func %x Natvalid %x Nat %x Box %x\n", + gpop, pop, gdrcs, drcs, + pi->function, pi->nationalvalid, pi->national, pi->boxed); +#endif + + /* evaluate local extension data from p26 */ + if (p26Received) + { +#if TUXTXT_DEBUG + if (dumpl25) + printf("p26/x:\n"); +#endif + APx0 = APy0 = APx = APy = tAPx = tAPy = 0; + eval_object(13 * (23-2 + 2), tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage], &APx, &APy, &APx0, &APy0, OBJ_ACTIVE, &page_char[40]); /* 1st triplet p26/0 */ + } + + { + int r, c; + int o = 0; + + + for (r = 0; r < 25; r++) + for (c = 0; c < 39; c++) + { + if (BlackBgSubst && page_atrb[o].bg == black && !(page_atrb[o].IgnoreAtBlackBgSubst)) + { + if (FullRowColor[r] == 0x08) + page_atrb[o].bg = FullScrColor; + else + page_atrb[o].bg = FullRowColor[r]; + } + o++; + } + } + + if (!hintmode) + { + int i; + for (i = 0; i < 25*40; i++) + { + if (page_atrb[i].concealed) page_atrb[i].fg = page_atrb[i].bg; + } + } + + if (boxed || transpmode) +// FullScrColor = transp; + FillBorder(transp); + else + FillBorder(FullScrColor); + if (colortable) /* as late as possible to shorten the time the old page is displayed with the new colors */ + setcolors(colortable, 16, 16); /* set colors for CLUTs 2+3 */ + } /* is_dec(page) */ + +} + +/****************************************************************************** + * main loop * + ******************************************************************************/ + +int tuxtx_main(int _rc, void * _fb, int pid, int x, int y, int w, int h) +{ + char cvs_revision[] = "$Revision: 1.95 $"; + +//printf("to init tuxtxt\n");fflush(stdout); +#if !TUXTXT_CFG_STANDALONE + int initialized = tuxtxt_init(); + if ( initialized ) + tuxtxt_cache.page = 0x100; +#endif + + /* show versioninfo */ + sscanf(cvs_revision, "%*s %s", versioninfo); + printf("TuxTxt %s\n", versioninfo); + printf("for 32bpp framebuffer\n"); + + if ((fb=open("/dev/fb/0", O_RDWR)) == -1) + { + perror("TuxTxt "); + return 0; + } + + rc = _rc; + lfb = (unsigned char *) _fb; + + tuxtxt_cache.vtxtpid = pid; + + if(tuxtxt_cache.vtxtpid == 0) + printf("[tuxtxt] No PID given, so scanning for PIDs ...\n\n"); + else + printf("[tuxtxt] using PID %x\n", tuxtxt_cache.vtxtpid); + + fcntl(rc, F_SETFL, fcntl(rc, F_GETFL) | O_EXCL | O_NONBLOCK); + + /* get fixed screeninfo */ + if (ioctl(fb, FBIOGET_FSCREENINFO, &fix_screeninfo) == -1) + { + perror("TuxTxt "); + return 0; + } + + /* get variable screeninfo */ + if (ioctl(fb, FBIOGET_VSCREENINFO, &var_screeninfo) == -1) + { + perror("TuxTxt "); + return 0; + } + + /* set variable screeninfo for double buffering */ + var_screeninfo.yoffset = 0; +#if 0 + sx = 80; + sy = 40; + ex = var_screeninfo.xres - sx; + ey = var_screeninfo.yres - sy; +#endif + sx = x + 10; + sy = y + 10; + ex = x + w - 10; + ey = y + h - 10; + /* initialisations */ + transpmode = 0; + + if (Init() == 0) + return 0; + + //transpmode = 1; + /* main loop */ + do { + if (GetRCCode() == 1) + { + if (transpmode == 2) /* TV mode */ + { + switch (RCCode) + { +//#if TUXTXT_DEBUG /* FIXME */ + case RC_OK: + if (showhex) + { + dump_page(); /* hexdump of page contents to stdout for debugging */ + } + continue; /* otherwise ignore key */ +//#endif /* TUXTXT_DEBUG */ + case RC_UP: + case RC_DOWN: + case RC_0: + case RC_1: + case RC_2: + case RC_3: + case RC_4: + case RC_5: + case RC_6: + case RC_7: + case RC_8: + case RC_9: + case RC_GREEN: + case RC_YELLOW: + case RC_BLUE: + case RC_PLUS: + case RC_MINUS: + case RC_DBOX: + case RC_STANDBY: + transpmode = 1; /* switch to normal mode */ + SwitchTranspMode(); + break; /* and evaluate key */ + + case RC_MUTE: /* regular toggle to transparent */ + case RC_TEXT: + break; + + case RC_HELP: /* switch to scart input and back */ + { + continue; /* otherwise ignore exit key */ + } + default: + continue; /* ignore all other keys */ + } + } + + switch (RCCode) + { + case RC_UP: + GetNextPageOne(!swapupdown); + break; + case RC_DOWN: + GetNextPageOne(swapupdown); + break; + case RC_RIGHT: + if (boxed) + { + subtitledelay++; + // display subtitledelay + PosY = StartY; + char ns[10]; + SetPosX(1); + sprintf(ns,"+%d ",subtitledelay); + RenderCharFB(ns[0],&atrtable[ATR_WB]); + RenderCharFB(ns[1],&atrtable[ATR_WB]); + RenderCharFB(ns[2],&atrtable[ATR_WB]); + RenderCharFB(ns[4],&atrtable[ATR_WB]); + } + else + GetNextSubPage(1); + break; + case RC_LEFT: + if (boxed) + { + subtitledelay--; + if (subtitledelay < 0) subtitledelay = 0; + // display subtitledelay + PosY = StartY; + char ns[10]; + SetPosX(1); + sprintf(ns,"+%d ",subtitledelay); + RenderCharFB(ns[0],&atrtable[ATR_WB]); + RenderCharFB(ns[1],&atrtable[ATR_WB]); + RenderCharFB(ns[2],&atrtable[ATR_WB]); + RenderCharFB(ns[4],&atrtable[ATR_WB]); + } + else + GetNextSubPage(-1); + break; + case RC_OK: + if (tuxtxt_cache.subpagetable[tuxtxt_cache.page] == 0xFF) + continue; + PageCatching(); + break; + + case RC_0: + case RC_1: + case RC_2: + case RC_3: + case RC_4: + case RC_5: + case RC_6: + case RC_7: + case RC_8: + case RC_9: + PageInput(RCCode - RC_0); + break; + case RC_RED: ColorKey(prev_100); break; + case RC_GREEN: ColorKey(prev_10); break; + case RC_YELLOW: ColorKey(next_10); break; + case RC_BLUE: ColorKey(next_100); break; + case RC_PLUS: SwitchZoomMode(); break; + case RC_MINUS: SwitchScreenMode(-1);prevscreenmode = screenmode; break; + case RC_MUTE: SwitchTranspMode(); break; + case RC_TEXT: + if(transpmode == 1) + RCCode = RC_HOME; + SwitchTranspMode(); + break; + case RC_HELP: SwitchHintMode(); break; + case RC_DBOX: ConfigMenu(0); break; + case RC_HOME: + break; + } + } + + /* update page or timestring and lcd */ + RenderPage(); + } while ((RCCode != RC_HOME) && (RCCode != RC_STANDBY)); + + /* exit */ + CleanUp(); + +#if 0 + close(rc); + close(lcd); +#endif + close(fb); + +#if 1 + if ( initialized ) + tuxtxt_close(); +#endif + + printf("Tuxtxt: plugin ended\n"); + return 1; +} + +/****************************************************************************** + * MyFaceRequester + ******************************************************************************/ + +FT_Error MyFaceRequester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *aface) +{ + FT_Error result; + + result = FT_New_Face(library, (char *) face_id, 0, aface); + +#if TUXTXT_DEBUG + if (!result) + printf("TuxTxt \n", (char*)face_id); + else + printf("TuxTxt \n", (char*)face_id); +#endif + + return result; +} + +/****************************************************************************** + * Init * + ******************************************************************************/ + +int Init() +{ + int error, i; + unsigned char magazine; + + /* init data */ + + + //page_atrb[32] = transp<<4 | transp; + inputcounter = 2; + + for (magazine = 1; magazine < 9; magazine++) + { + tuxtxt_cache.current_page [magazine] = -1; + tuxtxt_cache.current_subpage [magazine] = -1; + } +#if TUXTXT_CFG_STANDALONE +/* init data */ + memset(&tuxtxt_cache.astCachetable, 0, sizeof(tuxtxt_cache.astCachetable)); + memset(&tuxtxt_cache.subpagetable, 0xFF, sizeof(tuxtxt_cache.subpagetable)); + memset(&tuxtxt_cache.astP29, 0, sizeof(tuxtxt_cache.astP29)); + + memset(&tuxtxt_cache.basictop, 0, sizeof(tuxtxt_cache.basictop)); + memset(&tuxtxt_cache.adip, 0, sizeof(tuxtxt_cache.adip)); + memset(&tuxtxt_cache.flofpages, 0 , sizeof(tuxtxt_cache.flofpages)); + tuxtxt_cache.maxadippg = -1; + tuxtxt_cache.bttok = 0; + maxhotlist = -1; + + //page_atrb[32] = transp<<4 | transp; + inputcounter = 2; + tuxtxt_cache.cached_pages = 0; + + tuxtxt_cache.page_receiving = -1; + tuxtxt_cache.page = 0x100; +#endif + lastpage = tuxtxt_cache.page; + prev_100 = 0x100; + prev_10 = 0x100; + next_100 = 0x100; + next_10 = 0x100; + tuxtxt_cache.subpage = tuxtxt_cache.subpagetable[tuxtxt_cache.page]; + if (tuxtxt_cache.subpage == 0xff) + tuxtxt_cache.subpage = 0; + + tuxtxt_cache.pageupdate = 0; + + tuxtxt_cache.zap_subpage_manual = 0; + + subtitledelay = 0; + delaystarted = 0; + + /* init lcd */ + UpdateLCD(); + + /* config defaults */ + screenmode = 0; + screen_mode1 = 0; + screen_mode2 = 0; + color_mode = 10; + trans_mode = 10; + menulanguage = 0; /* german */ + national_subset = 0;/* default */ + auto_national = 1; + swapupdown = 0; + showhex = 0; + showflof = 1; + show39 = 1; + showl25 = 1; + dumpl25 = 0; + usettf = 0; + TTFWidthFactor16 = 28; + TTFHeightFactor16 = 16; + TTFShiftX = 0; + TTFShiftY = 0; + + /* load config */ + if ((conf = fopen(TUXTXTCONF, "rt")) == 0) + { + perror("TuxTxt "); + } + else + { + while(1) + { + char line[100]; + int ival; + + if (!fgets(line, sizeof(line), conf)) + break; + + if (1 == sscanf(line, "ScreenMode16x9Normal %i", &ival)) + screen_mode1 = ival & 1; + else if (1 == sscanf(line, "ScreenMode16x9Divided %i", &ival)) + screen_mode2 = ival & 1; + else if (1 == sscanf(line, "Brightness %i", &ival)) + color_mode = ival; + else if (1 == sscanf(line, "AutoNational %i", &ival)) + auto_national = ival & 1; + else if (1 == sscanf(line, "NationalSubset %i", &ival)) + { + if (ival >= 0 && ival <= (int) MAX_NATIONAL_SUBSET) + national_subset = ival; + } + else if (1 == sscanf(line, "MenuLanguage %i", &ival)) + { + if (ival >= 0 && ival <= MAXMENULANGUAGE) + menulanguage = ival; + } + else if (1 == sscanf(line, "SwapUpDown %i", &ival)) + swapupdown = ival & 1; + else if (1 == sscanf(line, "ShowHexPages %i", &ival)) + showhex = ival & 1; + else if (1 == sscanf(line, "Transparency %i", &ival)) + trans_mode = ival; + else if (1 == sscanf(line, "TTFWidthFactor16 %i", &ival)) + TTFWidthFactor16 = ival; + else if (1 == sscanf(line, "TTFHeightFactor16 %i", &ival)) + TTFHeightFactor16 = ival; + else if (1 == sscanf(line, "TTFShiftX %i", &ival)) + TTFShiftX = ival; + else if (1 == sscanf(line, "TTFShiftY %i", &ival)) + TTFShiftY = ival; + else if (1 == sscanf(line, "Screenmode %i", &ival)) + screenmode = ival; + else if (1 == sscanf(line, "ShowFLOF %i", &ival)) + showflof = ival & 1; + else if (1 == sscanf(line, "Show39 %i", &ival)) + show39 = ival & 1; + else if (1 == sscanf(line, "ShowLevel2p5 %i", &ival)) + showl25 = ival & 1; + else if (1 == sscanf(line, "DumpLevel2p5 %i", &ival)) + dumpl25 = ival & 1; + else if (1 == sscanf(line, "UseTTF %i", &ival)) + usettf = ival & 1; +#if 0 + else if (1 == sscanf(line, "StartX %i", &ival)) + sx = ival; + else if (1 == sscanf(line, "EndX %i", &ival)) + ex = ival; + else if (1 == sscanf(line, "StartY %i", &ival)) + sy = ival; + else if (1 == sscanf(line, "EndY %i", &ival)) + ey = ival; +#endif + } + fclose(conf); + } + saveconfig = 0; + savedscreenmode = screenmode; + national_subset_secondary = NAT_DEFAULT; + + + /* init fontlibrary */ + if ((error = FT_Init_FreeType(&library))) + { + printf("TuxTxt ", error); + return 0; + } + + if ((error = FTC_Manager_New(library, 7, 2, 0, &MyFaceRequester, NULL, &manager))) + { + FT_Done_FreeType(library); + printf("TuxTxt \n", error); + return 0; + } + + if ((error = FTC_SBitCache_New(manager, &cache))) + { + FTC_Manager_Done(manager); + FT_Done_FreeType(library); + printf("TuxTxt \n", error); + return 0; + } + + fontwidth = 0; /* initialize at first setting */ + + + /* calculate font dimensions */ + displaywidth = (ex-sx); + fontheight = (ey-sy) / 25; //21; + fontwidth_normal = (ex-sx) / 40; + setfontwidth(fontwidth_normal); + fontwidth_topmenumain = (TV43STARTX-sx) / 40; + fontwidth_topmenusmall = (ex- TOPMENUSTARTX) / TOPMENUCHARS; + fontwidth_small = (TV169FULLSTARTX-sx) / 40; + ymosaic[0] = 0; /* y-offsets for 2*3 mosaic */ + ymosaic[1] = (fontheight + 1) / 3; + ymosaic[2] = (fontheight * 2 + 1) / 3; + ymosaic[3] = fontheight; + { + int i; + for (i = 0; i <= 10; i++) + aydrcs[i] = (fontheight * i + 5) / 10; + } + + //FIXME center + /* center screen */ + StartX = sx; //+ (((ex-sx) - 40*fontwidth) / 2); + StartY = sy + (((ey-sy) - 25*fontheight) / 2); + + if (usettf) + { + typettf.face_id = (FTC_FaceID) TUXTXTTTFVAR; + typettf.height = (FT_UShort) fontheight * TTFHeightFactor16 / 16; + } + else + { + typettf.face_id = (FTC_FaceID) TUXTXTOTBVAR; + typettf.width = (FT_UShort) 23; + typettf.height = (FT_UShort) 23; + } + + typettf.flags = FT_LOAD_MONOCHROME; + + if ((error = FTC_Manager_LookupFace(manager, typettf.face_id, &face))) + { + typettf.face_id = (void *) (usettf ? (FTC_FaceID) TUXTXTTTF : TUXTXTOTB); + if ((error = FTC_Manager_LookupFace(manager, typettf.face_id, &face))) + { + printf("TuxTxt \n", error); + FTC_Manager_Done(manager); + FT_Done_FreeType(library); + return 0; + } + } + ascender = (usettf ? fontheight * face->ascender / face->units_per_EM : 16); +#if TUXTXT_DEBUG + printf("TuxTxt \n", + fontheight, fontwidth, fontwidth_small, fontwidth_topmenumain, fontwidth_topmenusmall, + ymosaic[0], ymosaic[1], ymosaic[2], StartX, StartY, ascender); +#endif + +#if 0 + /* get fixed screeninfo */ + if (ioctl(fb, FBIOGET_FSCREENINFO, &fix_screeninfo) == -1) + { + perror("TuxTxt "); + return 0; + } + + /* get variable screeninfo */ + if (ioctl(fb, FBIOGET_VSCREENINFO, &var_screeninfo) == -1) + { + perror("TuxTxt "); + return 0; + } + + /* set variable screeninfo for double buffering */ + var_screeninfo.yoffset = 0; +#endif +#if 0 + var_screeninfo.yres_virtual = 2*var_screeninfo.yres; + var_screeninfo.xres_virtual = var_screeninfo.xres; + + if (ioctl(fb, FBIOPUT_VSCREENINFO, &var_screeninfo) == -1) + { + perror("TuxTxt "); + return 0; + } + + if (ioctl(fb, FBIOGET_VSCREENINFO, &var_screeninfo) == -1) + { + perror("TuxTxt "); + return 0; + } +#endif +#if TUXTXT_DEBUG + printf("TuxTxt \n", + var_screeninfo.xres, var_screeninfo.yres, + var_screeninfo.xres_virtual, var_screeninfo.yres_virtual, + var_screeninfo.yoffset); +#endif + + + /* set new colormap */ + setcolors((unsigned short *)defaultcolors, 0, SIZECOLTABLE); +#if 0 + /* map framebuffer into memory */ + lfb = (unsigned char*)mmap(0, fix_screeninfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0); + + if (!lfb) + { + perror("TuxTxt "); + return 0; + } +#endif + ClearBB(transp); /* initialize backbuffer */ + for (i = 0; i < 40 * 25; i++) + { + page_char[i] = ' '; + page_atrb[i].fg = transp; + page_atrb[i].bg = transp; + page_atrb[i].charset = C_G0P; + page_atrb[i].doubleh = 0; + page_atrb[i].doublew = 0; + page_atrb[i].IgnoreAtBlackBgSubst = 0; + } + /* if no vtxtpid for current service, search PIDs */ + if (tuxtxt_cache.vtxtpid == 0) + { + /* get all vtxt-pids */ + getpidsdone = -1; /* don't kill thread */ + if (GetTeletextPIDs() == 0) + { + FTC_Manager_Done(manager); + FT_Done_FreeType(library); + //munmap(lfb, fix_screeninfo.smem_len); + return 0; + } + + if (auto_national) + national_subset = pid_table[0].national_subset; + if (pids_found > 1) + ConfigMenu(1); + else + { + tuxtxt_cache.vtxtpid = pid_table[0].vtxt_pid; + current_service = 0; + RenderMessage(ShowServiceName); + } + } + else + { + SDT_ready = 0; + getpidsdone = 0; +// tuxtxt_cache.pageupdate = 1; /* force display of message page not found (but not twice) */ + + } +#if TUXTXT_CFG_STANDALONE + tuxtxt_init_demuxer(); + tuxtxt_start_thread(); +#else + tuxtxt_start(tuxtxt_cache.vtxtpid); +#endif + fcntl(rc, F_SETFL, O_NONBLOCK); + gethotlist(); + SwitchScreenMode(screenmode); + prevscreenmode = screenmode; + + printf("TuxTxt: init ok\n"); + + /* init successfull */ + return 1; +} + +/****************************************************************************** + * Cleanup * + ******************************************************************************/ + +void CleanUp() +{ + int curscreenmode = screenmode; + + /* hide and close pig */ + if (screenmode) + SwitchScreenMode(0); /* turn off divided screen */ + //close(pig); + +#if TUXTXT_CFG_STANDALONE + tuxtxt_stop_thread(); + tuxtxt_clear_cache(); + if (tuxtxt_cache.dmx != -1) + close(tuxtxt_cache.dmx); + tuxtxt_cache.dmx = -1; +#else + //tuxtxt_stop(); +#endif + + memset(lfb,0, var_screeninfo.yres*fix_screeninfo.line_length); + + /* close freetype */ + FTC_Manager_Done(manager); + FT_Done_FreeType(library); + + if (hotlistchanged) + savehotlist(); + + /* save config */ + if (saveconfig || curscreenmode != savedscreenmode) + { + if ((conf = fopen(TUXTXTCONF, "wt")) == 0) + { + perror("TuxTxt "); + } + else + { + printf("TuxTxt \n"); + fprintf(conf, "ScreenMode16x9Normal %d\n", screen_mode1); + fprintf(conf, "ScreenMode16x9Divided %d\n", screen_mode2); + fprintf(conf, "Brightness %d\n", color_mode); + fprintf(conf, "MenuLanguage %d\n", menulanguage); + fprintf(conf, "AutoNational %d\n", auto_national); + fprintf(conf, "NationalSubset %d\n", national_subset); + fprintf(conf, "SwapUpDown %d\n", swapupdown); + fprintf(conf, "ShowHexPages %d\n", showhex); + fprintf(conf, "Transparency 0x%X\n", trans_mode); + fprintf(conf, "TTFWidthFactor16 %d\n", TTFWidthFactor16); + fprintf(conf, "TTFHeightFactor16 %d\n", TTFHeightFactor16); + fprintf(conf, "TTFShiftX %d\n", TTFShiftX); + fprintf(conf, "TTFShiftY %d\n", TTFShiftY); + fprintf(conf, "Screenmode %d\n", curscreenmode); + fprintf(conf, "ShowFLOF %d\n", showflof); + fprintf(conf, "Show39 %d\n", show39); + fprintf(conf, "ShowLevel2p5 %d\n", showl25); + fprintf(conf, "DumpLevel2p5 %d\n", dumpl25); + fprintf(conf, "UseTTF %d\n", usettf); +#if 0 + fprintf(conf, "StartX %d\n", sx); + fprintf(conf, "EndX %d\n", ex); + fprintf(conf, "StartY %d\n", sy); + fprintf(conf, "EndY %d\n", ey); +#endif + fclose(conf); + } + } +} +/****************************************************************************** + * GetTeletextPIDs * + ******************************************************************************/ +int GetTeletextPIDs() +{ + int pat_scan, pmt_scan, sdt_scan, desc_scan, pid_test, byte, diff, first_sdt_sec; + + unsigned char bufPAT[1024]; + unsigned char bufSDT[1024]; + unsigned char bufPMT[1024]; + + /* show infobar */ + RenderMessage(ShowInfoBar); + + unsigned char filter[DMX_FILTER_SIZE]; + unsigned char mask[DMX_FILTER_SIZE]; + int res; + + cDemux * dmx = new cDemux(1); + dmx->Open(DMX_PSI_CHANNEL); + + memset(filter, 0x00, DMX_FILTER_SIZE); + memset(mask, 0x00, DMX_FILTER_SIZE); + + //filter[0] = 0x00; + //mask[0] = 0xFF; + mask[0] = 0xFF; + mask[4] = 0xFF; + + dmx->sectionFilter(0, filter, mask, 1); + res = dmx->Read(bufPAT, sizeof(bufPAT)); + dmx->Stop(); + if(res <= 0) { + printf("TuxTxt failed"); + delete dmx; + return 0; + } + + /* scan each PMT for vtxt-pid */ + pids_found = 0; + + for (pat_scan = 0x0A; pat_scan < 0x0A + (((bufPAT[0x01]<<8 | bufPAT[0x02]) & 0x0FFF) - 9); pat_scan += 4) + { +#if TUXTXT_DEBUG + printf("PAT liefert:%04x, %04x \n",((bufPAT[pat_scan - 2]<<8) | (bufPAT[pat_scan - 1])),(bufPAT[pat_scan]<<8 | bufPAT[pat_scan+1]) & 0x1FFF); +#endif + if (((bufPAT[pat_scan - 2]<<8) | (bufPAT[pat_scan - 1])) == 0) + continue; + + int pid = (bufPAT[pat_scan]<<8 | bufPAT[pat_scan+1]) & 0x1FFF; + filter[0] = 0x02; + mask[0] = 0xFF; + + dmx->sectionFilter(pid, filter, mask, 1); + res = dmx->Read(bufPMT, sizeof(bufPMT)); + dmx->Stop(); + if(res <= 0) { + perror("TuxTxt "); + continue; + } + + for (pmt_scan = 0x0C + ((bufPMT[0x0A]<<8 | bufPMT[0x0B]) & 0x0FFF); + pmt_scan < (((bufPMT[0x01]<<8 | bufPMT[0x02]) & 0x0FFF) - 7); + pmt_scan += 5 + bufPMT[pmt_scan + 4]) + { + if (bufPMT[pmt_scan] == 6) + { + for (desc_scan = pmt_scan + 5; + desc_scan < pmt_scan + ((bufPMT[pmt_scan + 3]<<8 | bufPMT[pmt_scan + 4]) & 0x0FFF) + 5; + desc_scan += 2 + bufPMT[desc_scan + 1]) + { + if (bufPMT[desc_scan] == 0x56) + { + char country_code[4]; + + for (pid_test = 0; pid_test < pids_found; pid_test++) + if (pid_table[pid_test].vtxt_pid == ((bufPMT[pmt_scan + 1]<<8 | bufPMT[pmt_scan + 2]) & 0x1FFF)) + goto skip_pid; + + pid_table[pids_found].vtxt_pid = (bufPMT[pmt_scan + 1]<<8 | bufPMT[pmt_scan + 2]) & 0x1FFF; + pid_table[pids_found].service_id = bufPMT[0x03]<<8 | bufPMT[0x04]; + if (bufPMT[desc_scan + 1] == 5) + { + country_code[0] = bufPMT[desc_scan + 2] | 0x20; + country_code[1] = bufPMT[desc_scan + 3] | 0x20; + country_code[2] = bufPMT[desc_scan + 4] | 0x20; + country_code[3] = 0; + pid_table[pids_found].national_subset = GetNationalSubset(country_code); + } + else + { + country_code[0] = 0; + pid_table[pids_found].national_subset = NAT_DEFAULT; /* use default charset */ + } + +#if TUXTXT_DEBUG + printf("TuxTxt \n", + pid_table[pids_found].service_id, + country_code, + pid_table[pids_found].national_subset, + (pid_table[pids_found].vtxt_pid == tuxtxt_cache.vtxtpid) ? " * " : "" + ); +#endif + + pids_found++; +skip_pid: + ; + } + } + } + } + } + + /* check for teletext */ + if (pids_found == 0) + { + printf("TuxTxt \n"); + + RenderMessage(NoServicesFound); + sleep(3); + delete dmx; + return 0; + } + + /* read SDT to get servicenames */ + SDT_ready = 0; + + filter[0] = 0x42; + mask[0] = 0xFF; + + dmx->sectionFilter(0x0011, filter, mask, 1); + + first_sdt_sec = -1; + while (1) + { + res = dmx->Read(bufSDT, sizeof(bufSDT)); + if(res <= 0) { + perror("TuxTxt "); + delete dmx; + RenderMessage(ShowServiceName); + return 1; + } + + if (first_sdt_sec == bufSDT[6]) + break; + + if (first_sdt_sec == -1) + first_sdt_sec = bufSDT[6]; + + /* scan SDT to get servicenames */ + for (sdt_scan = 0x0B; sdt_scan < ((bufSDT[1]<<8 | bufSDT[2]) & 0x0FFF) - 7; sdt_scan += 5 + ((bufSDT[sdt_scan + 3]<<8 | bufSDT[sdt_scan + 4]) & 0x0FFF)) + { + for (pid_test = 0; pid_test < pids_found; pid_test++) + { + if ((bufSDT[sdt_scan]<<8 | bufSDT[sdt_scan + 1]) == pid_table[pid_test].service_id && bufSDT[sdt_scan + 5] == 0x48) + { + diff = 0; + pid_table[pid_test].service_name_len = bufSDT[sdt_scan+9 + bufSDT[sdt_scan+8]]; + + for (byte = 0; byte < pid_table[pid_test].service_name_len; byte++) + { + if (bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] == (unsigned char)'Ä') + bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] = 0x5B; + if (bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] == (unsigned char)'ä') + bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] = 0x7B; + if (bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] == (unsigned char)'Ö') + bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] = 0x5C; + if (bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] == (unsigned char)'ö') + bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] = 0x7C; + if (bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] == (unsigned char)'Ü') + bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] = 0x5D; + if (bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] == (unsigned char)'ü') + bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] = 0x7D; + if (bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] == (unsigned char)'ß') + bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] = 0x7E; + if (bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] >= 0x80 && bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte] <= 0x9F) + diff--; + else + pid_table[pid_test].service_name[byte + diff] = bufSDT[sdt_scan+10 + bufSDT[sdt_scan + 8] + byte]; + } + + pid_table[pid_test].service_name_len += diff; + } + } + } + } + delete dmx; + SDT_ready = 1; + + /* show current servicename */ + current_service = 0; + + if (tuxtxt_cache.vtxtpid != 0) + { + while (pid_table[current_service].vtxt_pid != tuxtxt_cache.vtxtpid && current_service < pids_found) + current_service++; + + if (auto_national && current_service < pids_found) + national_subset = pid_table[current_service].national_subset; + RenderMessage(ShowServiceName); + } + + getpidsdone = 1; + + RenderCharLCD(pids_found/10, 7, 44); + RenderCharLCD(pids_found%10, 19, 44); + + return 1; +} + +/****************************************************************************** + * GetNationalSubset * + ******************************************************************************/ + +int GetNationalSubset(char *cc) +{ + if (memcmp(cc, "cze", 3) == 0 || memcmp(cc, "ces", 3) == 0 || + memcmp(cc, "slo", 3) == 0 || memcmp(cc, "slk", 3) == 0) + return 0; + if (memcmp(cc, "eng", 3) == 0) + return 1; + if (memcmp(cc, "est", 3) == 0) + return 2; + if (memcmp(cc, "fre", 3) == 0 || memcmp(cc, "fra", 3) == 0) + return 3; + if (memcmp(cc, "ger", 3) == 0 || memcmp(cc, "deu", 3) == 0) + return 4; + if (memcmp(cc, "ita", 3) == 0) + return 5; + if (memcmp(cc, "lav", 3) == 0 || memcmp(cc, "lit", 3) == 0) + return 6; + if (memcmp(cc, "pol", 3) == 0) + return 7; + if (memcmp(cc, "spa", 3) == 0 || memcmp(cc, "por", 3) == 0) + return 8; + if (memcmp(cc, "rum", 3) == 0 || memcmp(cc, "ron", 3) == 0) + return 9; + if (memcmp(cc, "scc", 3) == 0 || memcmp(cc, "srp", 3) == 0 || + memcmp(cc, "scr", 3) == 0 || memcmp(cc, "hrv", 3) == 0 || + memcmp(cc, "slv", 3) == 0) + return 10; + if (memcmp(cc, "swe", 3) == 0 || + memcmp(cc, "dan", 3) == 0 || + memcmp(cc, "nor", 3) == 0 || + memcmp(cc, "fin", 3) == 0 || + memcmp(cc, "hun", 3) == 0) + return 11; + if (memcmp(cc, "tur", 3) == 0) + return 12; + if (memcmp(cc, "rus", 3) == 0 || + memcmp(cc, "bul", 3) == 0 || + memcmp(cc, "ser", 3) == 0 || + memcmp(cc, "cro", 3) == 0 || + memcmp(cc, "ukr", 3) == 0) + return NAT_RU; + if (memcmp(cc, "gre", 3) == 0) + return NAT_GR; + + return NAT_DEFAULT; /* use default charset */ +} + +/****************************************************************************** + * ConfigMenu * + ******************************************************************************/ +#if TUXTXT_DEBUG +void charpage() +{ + PosY = StartY; + PosX = StartX; + char cachefill[100]; + int fullsize =0,hexcount = 0, col, p,sp; + int escpage = 0; + tstCachedPage* pg; + ClearFB(black); + + int zipsize = 0; + for (p = 0; p < 0x900; p++) + { + for (sp = 0; sp < 0x80; sp++) + { + pg = tuxtxt_cache.astCachetable[p][sp]; + if (pg) + { + + fullsize+=23*40; + zipsize += tuxtxt_get_zipsize(p,sp); + } + } + } + + + memset(cachefill,' ',40); + sprintf(cachefill,"f:%d z:%d h:%d c:%d %03x",fullsize, zipsize, hexcount, tuxtxt_cache.cached_pages, escpage); + + for (col = 0; col < 40; col++) + { + RenderCharFB(cachefill[col], &atrtable[ATR_WB]); + } + tstPageAttr atr; + memcpy(&atr,&atrtable[ATR_WB],sizeof(tstPageAttr)); + int row; + atr.charset = C_G0P; + PosY = StartY+fontheight; + for (row = 0; row < 16; row++) + { + PosY+= fontheight; + SetPosX(1); + for (col=0; col < 6; col++) + { + RenderCharFB(col*16+row+0x20, &atr); + } + } + atr.setX26 = 1; + PosY = StartY+fontheight; + for (row = 0; row < 16; row++) + { + PosY+= fontheight; + SetPosX(10); + for (col=0; col < 6; col++) + { + RenderCharFB(col*16+row+0x20, &atr); + } + } + PosY = StartY+fontheight; + atr.charset = C_G2; + atr.setX26 = 0; + for (row = 0; row < 16; row++) + { + PosY+= fontheight; + SetPosX(20); + for (col=0; col < 6; col++) + { + RenderCharFB(col*16+row+0x20, &atr); + } + } + atr.charset = C_G3; + PosY = StartY+fontheight; + for (row = 0; row < 16; row++) + { + PosY+= fontheight; + SetPosX(30); + for (col=0; col < 6; col++) + { + RenderCharFB(col*16+row+0x20, &atr); + } + } + do + { + GetRCCode(); + } + while (RCCode != RC_OK && RCCode != RC_HOME); +} +#endif +void Menu_HighlightLine(char *menu, int line, int high) +{ + char hilitline[] = "0111111111111111111111111111102"; + int itext = Menu_Width*line; /* index start menuline */ + int byte; + int national_subset_bak = national_subset; + + PosX = Menu_StartX; + PosY = Menu_StartY + line*fontheight; + if (line == MenuLine[M_NAT]) + national_subset = national_subset_bak; + else + national_subset = menusubset[menulanguage]; + + for (byte = 0; byte < Menu_Width; byte++) + RenderCharFB(menu[itext + byte], + high ? + &atrtable[hilitline[byte] - '0' + ATR_MENUHIL0] : + &atrtable[menuatr[itext + byte] - '0' + ATR_MENU0]); + national_subset = national_subset_bak; +} + +void Menu_UpdateHotlist(char *menu, int hotindex, int menuitem) +{ + int i, j, k; + tstPageAttr *attr; + + PosX = Menu_StartX + 6*fontwidth; + PosY = Menu_StartY + (MenuLine[M_HOT]+1)*fontheight; + j = Menu_Width*(MenuLine[M_HOT]+1) + 6; /* start index in menu */ + + for (i = 0; i <= maxhotlist+1; i++) + { + if (i == maxhotlist+1) /* clear last+1 entry in case it was deleted */ + { + attr = &atrtable[ATR_MENU5]; + memset(&menu[j], ' ', 3); + } + else + { + if (i == hotindex) + attr = &atrtable[ATR_MENU1]; + else + attr = &atrtable[ATR_MENU5]; + hex2str(&menu[j+2], hotlist[i]); + } + + for (k = 0; k < 3; k++) + RenderCharFB(menu[j+k], attr); + + if (i == 4) + { + PosX = Menu_StartX + 6*fontwidth; + PosY += fontheight; + j += 2*Menu_Width - 4*4; + } + else + { + j += 4; /* one space distance */ + PosX += fontwidth; + } + } + + hex2str(&menu[Menu_Width*MenuLine[M_HOT] + hotlistpagecolumn[menulanguage]], (hotindex >= 0) ? hotlist[hotindex] : tuxtxt_cache.page); + memcpy(&menu[Menu_Width*MenuLine[M_HOT] + hotlisttextcolumn[menulanguage]], &hotlisttext[menulanguage][(hotindex >= 0) ? 5 : 0], 5); + PosX = Menu_StartX + 20*fontwidth; + PosY = Menu_StartY + MenuLine[M_HOT]*fontheight; + + Menu_HighlightLine(menu, MenuLine[M_HOT], (menuitem == M_HOT) ? 1 : 0); +} + +void Menu_Init(char *menu, int current_pid, int menuitem, int hotindex) +{ + int byte, line; + int national_subset_bak = national_subset; + + memcpy(menu, configmenu[menulanguage], Menu_Height*Menu_Width); + + if (getpidsdone) + { + memset(&menu[MenuLine[M_PID]*Menu_Width+3], 0x20,24); + if (SDT_ready) + memcpy(&menu[MenuLine[M_PID]*Menu_Width+3+(24-pid_table[current_pid].service_name_len)/2], &pid_table[current_pid].service_name, pid_table[current_pid].service_name_len); + else + hex2str(&menu[MenuLine[M_PID]*Menu_Width + 13 + 3], tuxtxt_cache.vtxtpid); + } + if (!getpidsdone || current_pid == 0 || pids_found == 1) + menu[MenuLine[M_PID]*Menu_Width + 1] = ' '; + + if (!getpidsdone || current_pid == pids_found - 1 || pids_found == 1) + menu[MenuLine[M_PID]*Menu_Width + 28] = ' '; + + + /* set 16:9 modi, colors & national subset */ + memcpy(&menu[Menu_Width*MenuLine[M_SC1] + Menu_Width - 5], &configonoff[menulanguage][screen_mode1 ? 3 : 0], 3); + memcpy(&menu[Menu_Width*MenuLine[M_SC2] + Menu_Width - 5], &configonoff[menulanguage][screen_mode2 ? 3 : 0], 3); + + menu[MenuLine[M_COL]*Menu_Width + 1] = (color_mode == 1 ? ' ' : 'í'); + menu[MenuLine[M_COL]*Menu_Width + 28] = (color_mode == 24 ? ' ' : 'î'); + memset(&menu[Menu_Width*MenuLine[M_COL] + 3 ], 0x7f,color_mode); + memset(&menu[Menu_Width*MenuLine[M_COL] + 3+color_mode ], 0x20,24-color_mode); +// memcpy(&menu[Menu_Width*MenuLine[M_COL] + Menu_Width - 5], &configonoff[menulanguage][color_mode ? 3 : 0], 3); + menu[MenuLine[M_TRA]*Menu_Width + 1] = (trans_mode == 1 ? ' ' : 'í'); + menu[MenuLine[M_TRA]*Menu_Width + 28] = (trans_mode == 24 ? ' ' : 'î'); + memset(&menu[Menu_Width*MenuLine[M_TRA] + 3 ], 0x7f,trans_mode); + memset(&menu[Menu_Width*MenuLine[M_TRA] + 3+trans_mode ], 0x20,24-trans_mode); + + memcpy(&menu[Menu_Width*MenuLine[M_AUN] + Menu_Width - 5], &configonoff[menulanguage][auto_national ? 3 : 0], 3); + if (national_subset != NAT_DE) + memcpy(&menu[Menu_Width*MenuLine[M_NAT] + 2], &countrystring[national_subset*COUNTRYSTRING_WIDTH], COUNTRYSTRING_WIDTH); + if (national_subset == 0 || auto_national) + menu[MenuLine[M_NAT]*Menu_Width + 1] = ' '; + if (national_subset == MAX_NATIONAL_SUBSET || auto_national) + menu[MenuLine[M_NAT]*Menu_Width + 28] = ' '; + if (showhex) + menu[MenuLine[M_PID]*Menu_Width + 27] = '?'; + /* render menu */ + PosY = Menu_StartY; + for (line = 0; line < Menu_Height; line++) + { + PosX = Menu_StartX; + if (line == MenuLine[M_NAT]) + national_subset = national_subset_bak; + else + national_subset = menusubset[menulanguage]; + + if (line == Menu_Height-2) + memcpy(&menu[line*Menu_Width + 21], versioninfo, 4); + + for (byte = 0; byte < Menu_Width; byte++) + RenderCharFB(menu[line*Menu_Width + byte], &atrtable[menuatr[line*Menu_Width + byte] - '0' + ATR_MENU0]); + + PosY += fontheight; + } + national_subset = national_subset_bak; + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + Menu_UpdateHotlist(menu, hotindex, menuitem); +} + +void ConfigMenu(int Init) +{ +printf("[tuxtxt] Menu\n"); + int val, menuitem = M_Start; + int current_pid = 0; + int hotindex; + int oldscreenmode, oldtrans = 0; + int i; + int national_subset_bak = national_subset; + char menu[Menu_Height*Menu_Width]; + + if (auto_national && tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage] && + tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage]->pageinfo.nationalvalid) + national_subset = countryconversiontable[tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage]->pageinfo.national]; + + if (getpidsdone) + { + /* set current vtxt */ + if (tuxtxt_cache.vtxtpid == 0) + tuxtxt_cache.vtxtpid = pid_table[0].vtxt_pid; + else + while(pid_table[current_pid].vtxt_pid != tuxtxt_cache.vtxtpid && current_pid < pids_found) + current_pid++; + } + + /* reset to normal mode */ + if (zoommode) + zoommode = 0; + + if (transpmode) + { + oldtrans = transpmode; + transpmode = 0; + ClearBB(black); + } + + oldscreenmode = screenmode; + if (screenmode) + SwitchScreenMode(0); /* turn off divided screen */ + + hotindex = getIndexOfPageInHotlist(); + + /* clear framebuffer */ + ClearFB(transp); + clearbbcolor = black; + Menu_Init(menu, current_pid, menuitem, hotindex); + + /* set blocking mode */ + val = fcntl(rc, F_GETFL); + fcntl(rc, F_SETFL, val &~ O_NONBLOCK); + + /* loop */ + do { + if (GetRCCode() == 1) + { + + if ( +#if (RC_1 > 0) + RCCode >= RC_1 && /* generates a warning... */ +#endif + RCCode <= RC_1+M_MaxDirect) /* direct access */ + { + Menu_HighlightLine(menu, MenuLine[menuitem], 0); + menuitem = RCCode-RC_1; + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + + if (menuitem != M_PID) /* just select */ + RCCode = RC_OK; + } + + switch (RCCode) + { + case RC_UP: + Menu_HighlightLine(menu, MenuLine[menuitem], 0); + if (--menuitem < 0) + menuitem = M_Number-1; + if (auto_national && (menuitem == M_NAT)) + menuitem--; + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + break; + + case RC_DOWN: + Menu_HighlightLine(menu, MenuLine[menuitem], 0); + if (++menuitem > M_Number-1) + menuitem = 0; + if (auto_national && (menuitem == M_NAT)) + menuitem++; + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + break; + + case RC_LEFT: + switch (menuitem) + { + case M_COL: + saveconfig = 1; + color_mode--; + if (color_mode < 1) color_mode = 1; + menu[MenuLine[M_COL]*Menu_Width + 1] = (color_mode == 1 ? ' ' : 'í'); + menu[MenuLine[M_COL]*Menu_Width + 28] = (color_mode == 24 ? ' ' : 'î'); + memset(&menu[Menu_Width*MenuLine[M_COL] + 3 ], 0x7f,color_mode); + memset(&menu[Menu_Width*MenuLine[M_COL] + 3+color_mode ], 0x20,24-color_mode); + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + setcolors((unsigned short *)defaultcolors, 0, SIZECOLTABLE); + Menu_Init(menu, current_pid, menuitem, hotindex); + break; + case M_TRA: + saveconfig = 1; + trans_mode--; + if (trans_mode < 1) trans_mode = 1; + menu[MenuLine[M_TRA]*Menu_Width + 1] = (trans_mode == 1 ? ' ' : 'í'); + menu[MenuLine[M_TRA]*Menu_Width + 28] = (trans_mode == 24 ? ' ' : 'î'); + memset(&menu[Menu_Width*MenuLine[M_TRA] + 3 ], 0x7f,trans_mode); + memset(&menu[Menu_Width*MenuLine[M_TRA] + 3+trans_mode ], 0x20,24-trans_mode); + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + setcolors((unsigned short *)defaultcolors, 0, SIZECOLTABLE); + Menu_Init(menu, current_pid, menuitem, hotindex); + break; + case M_PID: + { + if (!getpidsdone) + { + GetTeletextPIDs(); + ClearFB(transp); + /* set current vtxt */ + if (tuxtxt_cache.vtxtpid == 0) + tuxtxt_cache.vtxtpid = pid_table[0].vtxt_pid; + else + while(pid_table[current_pid].vtxt_pid != tuxtxt_cache.vtxtpid && current_pid < pids_found) + current_pid++; + Menu_Init(menu, current_pid, menuitem, hotindex); + } + if (current_pid > 0) + { + current_pid--; + + memset(&menu[MenuLine[M_PID]*Menu_Width + 3], ' ', 24); + + if (SDT_ready) + { + memcpy(&menu[MenuLine[M_PID]*Menu_Width+3+(24-pid_table[current_pid].service_name_len)/2], + &pid_table[current_pid].service_name, + pid_table[current_pid].service_name_len); + } + else + hex2str(&menu[MenuLine[M_PID]*Menu_Width + 13 + 3], tuxtxt_cache.vtxtpid); + + if (pids_found > 1) + { + if (current_pid == 0) + { + menu[MenuLine[M_PID]*Menu_Width + 1] = ' '; + menu[MenuLine[M_PID]*Menu_Width + 28] = 'î'; + } + else + { + menu[MenuLine[M_PID]*Menu_Width + 1] = 'í'; + menu[MenuLine[M_PID]*Menu_Width + 28] = 'î'; + } + } + + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + + if (auto_national) + { + national_subset = pid_table[current_pid].national_subset; + + memcpy(&menu[Menu_Width*MenuLine[M_NAT] + 2], &countrystring[national_subset*COUNTRYSTRING_WIDTH], COUNTRYSTRING_WIDTH); + Menu_HighlightLine(menu, MenuLine[M_NAT], 0); + } + } + break; + } + + case M_NAT: + saveconfig = 1; + if (national_subset > 0) + { + national_subset--; + + if (national_subset == 0) + { + menu[MenuLine[M_NAT]*Menu_Width + 1] = ' '; + menu[MenuLine[M_NAT]*Menu_Width + 28] = 'î'; + } + else + { + menu[MenuLine[M_NAT]*Menu_Width + 1] = 'í'; + menu[MenuLine[M_NAT]*Menu_Width + 28] = 'î'; + } + + Menu_Init(menu, current_pid, menuitem, hotindex); + } + break; + + case M_HOT: /* move towards top of hotlist */ + if (hotindex <= 0) /* if not found, start at end */ + hotindex = maxhotlist; + else + hotindex--; + Menu_UpdateHotlist(menu, hotindex, menuitem); + break; + + case M_LNG: + saveconfig = 1; + if (--menulanguage < 0) + menulanguage = MAXMENULANGUAGE; + Menu_Init(menu, current_pid, menuitem, hotindex); + break; + } /* switch menuitem */ + break; /* RC_LEFT */ + + case RC_RIGHT: + switch (menuitem) + { + case M_COL: + saveconfig = 1; + color_mode++; + if (color_mode > 24) color_mode = 24; + menu[MenuLine[M_COL]*Menu_Width + 1] = (color_mode == 1 ? ' ' : 'í'); + menu[MenuLine[M_COL]*Menu_Width + 28] = (color_mode == 24 ? ' ' : 'î'); + memset(&menu[Menu_Width*MenuLine[M_COL] + 3 ], 0x7f,color_mode); + memset(&menu[Menu_Width*MenuLine[M_COL] + 3+color_mode ], 0x20,24-color_mode); + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + setcolors((unsigned short *)defaultcolors, 0, SIZECOLTABLE); + Menu_Init(menu, current_pid, menuitem, hotindex); + break; + case M_TRA: + saveconfig = 1; + trans_mode++; + if (trans_mode > 24) trans_mode = 24; + menu[MenuLine[M_TRA]*Menu_Width + 1] = (trans_mode == 1 ? ' ' : 'í'); + menu[MenuLine[M_TRA]*Menu_Width + 28] = (trans_mode == 24 ? ' ' : 'î'); + memset(&menu[Menu_Width*MenuLine[M_TRA] + 3 ], 0x7f,trans_mode); + memset(&menu[Menu_Width*MenuLine[M_TRA] + 3+trans_mode ], 0x20,24-trans_mode); + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + setcolors((unsigned short *)defaultcolors, 0, SIZECOLTABLE); + Menu_Init(menu, current_pid, menuitem, hotindex); + break; + case M_PID: + if (!getpidsdone) + { + GetTeletextPIDs(); + ClearFB(transp); + /* set current vtxt */ + if (tuxtxt_cache.vtxtpid == 0) + tuxtxt_cache.vtxtpid = pid_table[0].vtxt_pid; + else + while(pid_table[current_pid].vtxt_pid != tuxtxt_cache.vtxtpid && current_pid < pids_found) + current_pid++; + Menu_Init(menu, current_pid, menuitem, hotindex); + } + if (current_pid < pids_found - 1) + { + current_pid++; + + memset(&menu[MenuLine[M_PID]*Menu_Width + 3], ' ', 24); + + if (SDT_ready) + memcpy(&menu[MenuLine[M_PID]*Menu_Width + 3 + + (24-pid_table[current_pid].service_name_len)/2], + &pid_table[current_pid].service_name, + pid_table[current_pid].service_name_len); + else + hex2str(&menu[MenuLine[M_PID]*Menu_Width + 13 + 3], pid_table[current_pid].vtxt_pid); + + if (pids_found > 1) + { + if (current_pid == pids_found - 1) + { + menu[MenuLine[M_PID]*Menu_Width + 1] = 'í'; + menu[MenuLine[M_PID]*Menu_Width + 28] = ' '; + } + else + { + menu[MenuLine[M_PID]*Menu_Width + 1] = 'í'; + menu[MenuLine[M_PID]*Menu_Width + 28] = 'î'; + } + } + + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + + if (auto_national) + { + if (getpidsdone) + national_subset = pid_table[current_pid].national_subset; + memcpy(&menu[Menu_Width*MenuLine[M_NAT] + 2], &countrystring[national_subset*COUNTRYSTRING_WIDTH], COUNTRYSTRING_WIDTH); + Menu_HighlightLine(menu, MenuLine[M_NAT], 0); + } + } + break; + + case M_NAT: + saveconfig = 1; + if (national_subset < (int) MAX_NATIONAL_SUBSET) + { + national_subset++; + + if (national_subset == (int) MAX_NATIONAL_SUBSET) + { + menu[MenuLine[M_NAT]*Menu_Width + 1] = 'í'; + menu[MenuLine[M_NAT]*Menu_Width + 28] = ' '; + } + else + { + menu[MenuLine[M_NAT]*Menu_Width + 1] = 'í'; + menu[MenuLine[M_NAT]*Menu_Width + 28] = 'î'; + } + + Menu_Init(menu, current_pid, menuitem, hotindex); + } + break; + + case M_HOT: /* select hotindex */ + if ((int)hotindex >= maxhotlist) /* if not found, start at 0 */ + hotindex = 0; + else + hotindex++; + Menu_UpdateHotlist(menu, hotindex, menuitem); + break; + + case M_LNG: + saveconfig = 1; + if (++menulanguage > MAXMENULANGUAGE) + menulanguage = 0; + Menu_Init(menu, current_pid, menuitem, hotindex); + break; + } + break; /* RC_RIGHT */ + + case RC_PLUS: + switch (menuitem) + { + case M_HOT: /* move towards end of hotlist */ + { + if (hotindex<0) /* not found: add page at end */ + { + if (maxhotlist < (int) (sizeof(hotlist)/sizeof(hotlist[0])-1)) /* only if still room left */ + { + hotindex = ++maxhotlist; + hotlist[hotindex] = tuxtxt_cache.page; + hotlistchanged = 1; + Menu_UpdateHotlist(menu, hotindex, menuitem); + } + } + else /* found */ + { + if (hotindex < maxhotlist) /* not already at end */ + { + int temp = hotlist[hotindex]; + hotlist[hotindex] = hotlist[hotindex+1]; + hotlist[hotindex+1] = temp; + hotindex++; + hotlistchanged = 1; + Menu_UpdateHotlist(menu, hotindex, menuitem); + } + } + } + break; + } + break; /* RC_PLUS */ + + case RC_MINUS: + switch (menuitem) + { + case M_HOT: /* move towards top of hotlist */ + { + if (hotindex<0) /* not found: add page at top */ + { + if (maxhotlist < (int) (sizeof(hotlist)/sizeof(hotlist[0])-1)) /* only if still room left */ + { + for (hotindex = maxhotlist; hotindex >= 0; hotindex--) /* move rest of list */ + { + hotlist[hotindex+1] = hotlist[hotindex]; + } + maxhotlist++; + hotindex = 0; + hotlist[hotindex] = tuxtxt_cache.page; + hotlistchanged = 1; + Menu_UpdateHotlist(menu, hotindex, menuitem); + } + } + else /* found */ + { + if (hotindex > 0) /* not already at front */ + { + int temp = hotlist[hotindex]; + hotlist[hotindex] = hotlist[hotindex-1]; + hotlist[hotindex-1] = temp; + hotindex--; + hotlistchanged = 1; + Menu_UpdateHotlist(menu, hotindex, menuitem); + } + } + } + break; + } + break; /* RC_MINUS */ + + case RC_HELP: + switch (menuitem) + { + case M_HOT: /* current page is added to / removed from hotlist */ + { + if (hotindex<0) /* not found: add page */ + { + if (maxhotlist < (int) (sizeof(hotlist)/sizeof(hotlist[0])-1)) /* only if still room left */ + { + hotlist[++maxhotlist] = tuxtxt_cache.page; + hotindex = maxhotlist; + hotlistchanged = 1; + Menu_UpdateHotlist(menu, hotindex, menuitem); + } + } + else /* found: remove */ + { + if (maxhotlist > 0) /* don't empty completely */ + { + int i; + + for (i=hotindex; i maxhotlist) + hotindex = maxhotlist; + hotlistchanged = 1; + Menu_UpdateHotlist(menu, hotindex, menuitem); + } + } + } + break; + case M_PID: + showhex ^= 1; + menu[MenuLine[M_PID]*Menu_Width + 27] = (showhex ? '?' : ' '); + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + break; +#if TUXTXT_DEBUG + case M_LNG: + charpage(); + ClearFB(transp); + Menu_Init(menu, current_pid, menuitem, hotindex); + break; +#endif + } + break; /* RC_MUTE */ + + case RC_OK: + switch (menuitem) + { + case M_PID: + if (!getpidsdone) + { + GetTeletextPIDs(); + ClearFB(transp); + /* set current vtxt */ + if (tuxtxt_cache.vtxtpid == 0) + tuxtxt_cache.vtxtpid = pid_table[0].vtxt_pid; + else + while(pid_table[current_pid].vtxt_pid != tuxtxt_cache.vtxtpid && current_pid < pids_found) + current_pid++; + Menu_Init(menu, current_pid, menuitem, hotindex); + } + else if (pids_found > 1) + { + if (hotlistchanged) + savehotlist(); + + if (Init || tuxtxt_cache.vtxtpid != pid_table[current_pid].vtxt_pid) + { +#if TUXTXT_CFG_STANDALONE + tuxtxt_stop_thread(); + tuxtxt_clear_cache(); +#else + tuxtxt_stop(); + if (Init) + tuxtxt_cache.vtxtpid = 0; // force clear cache +#endif + /* reset data */ + + + //page_atrb[32] = transp<<4 | transp; + inputcounter = 2; + + + tuxtxt_cache.page = 0x100; + lastpage = 0x100; + prev_100 = 0x100; + prev_10 = 0x100; + next_100 = 0x100; + next_10 = 0x100; + tuxtxt_cache.subpage = 0; + + tuxtxt_cache.pageupdate = 0; + tuxtxt_cache.zap_subpage_manual = 0; + hintmode = 0; + memset(page_char,' ',40 * 25); + + for (i = 0; i < 40*25; i++) + { + page_atrb[i].fg = transp; + page_atrb[i].bg = transp; + } + ClearFB(transp); + + + /* start demuxer with new vtxtpid */ + if (auto_national) + national_subset = pid_table[current_pid].national_subset; + +#if TUXTXT_CFG_STANDALONE + tuxtxt_cache.vtxtpid = pid_table[current_pid].vtxt_pid; + tuxtxt_start_thread(); +#else + tuxtxt_start(pid_table[current_pid].vtxt_pid); +#endif + } +// tuxtxt_cache.pageupdate = 1; + + ClearBB(black); + gethotlist(); + + /* show new teletext */ + current_service = current_pid; +// RenderMessage(ShowServiceName); + + fcntl(rc, F_SETFL, O_NONBLOCK); + RCCode = -1; + if (oldscreenmode) + SwitchScreenMode(oldscreenmode); /* restore divided screen */ +printf("[tuxtxt] Menu return from M_PID\n"); + transpmode = oldtrans; + return; + } + break; + + case M_SC1: + saveconfig = 1; + screen_mode1++; + screen_mode1 &= 1; + + memcpy(&menu[Menu_Width*MenuLine[M_SC1] + Menu_Width - 5], &configonoff[menulanguage][screen_mode1 ? 3 : 0], 3); + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + + break; + + case M_SC2: + saveconfig = 1; + screen_mode2++; + screen_mode2 &= 1; + + memcpy(&menu[Menu_Width*MenuLine[M_SC2] + Menu_Width - 5], &configonoff[menulanguage][screen_mode2 ? 3 : 0], 3); + Menu_HighlightLine(menu, MenuLine[menuitem], 1); + break; + + + case M_AUN: + saveconfig = 1; + auto_national++; + auto_national &= 1; + if (auto_national) + { + if (getpidsdone) + national_subset = pid_table[current_pid].national_subset; + else + { + if (tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage] && + tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage]->pageinfo.nationalvalid) + national_subset = countryconversiontable[tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage]->pageinfo.national]; + else + national_subset = national_subset_bak; + } + + } + Menu_Init(menu, current_pid, menuitem, hotindex); + break; + case M_HOT: /* show selected page */ + { + if (hotindex >= 0) /* not found: ignore */ + { + lastpage = tuxtxt_cache.page; + tuxtxt_cache.page = hotlist[hotindex]; + tuxtxt_cache.subpage = tuxtxt_cache.subpagetable[tuxtxt_cache.page]; + inputcounter = 2; + tuxtxt_cache.pageupdate = 1; + RCCode = RC_HOME; /* leave menu */ + } + } + break; + } /* RC_OK */ + break; + } + } + UpdateLCD(); /* update number of cached pages */ + } while ((RCCode != RC_HOME) && (RCCode != RC_DBOX) && (RCCode != RC_MUTE)); + + /* reset to nonblocking mode */ + fcntl(rc, F_SETFL, O_NONBLOCK); + tuxtxt_cache.pageupdate = 1; + RCCode = -1; + if (oldscreenmode) + SwitchScreenMode(oldscreenmode); /* restore divided screen */ + transpmode = oldtrans; +printf("[tuxtxt] Menu return\n"); +} + +/****************************************************************************** + * PageInput * + ******************************************************************************/ + +void PageInput(int Number) +{ + int zoom = 0; + + /* clear temp_page */ + if (inputcounter == 2) + temp_page = 0; + + /* check for 0 & 9 on first position */ + if (Number == 0 && inputcounter == 2) + { + /* set page */ + temp_page = lastpage; /* 0 toggles to last page as in program switching */ + inputcounter = -1; + } + else if (Number == 9 && inputcounter == 2) + { + /* set page */ + temp_page = getIndexOfPageInHotlist(); /* 9 toggles through hotlist */ + + if (temp_page<0 || temp_page==maxhotlist) /* from any (other) page go to first page in hotlist */ + temp_page = (maxhotlist >= 0) ? hotlist[0] : 0x100; + else + temp_page = hotlist[temp_page+1]; + + inputcounter = -1; + } + + /* show pageinput */ + if (zoommode == 2) + { + zoommode = 1; + CopyBB2FB(); + } + + if (zoommode == 1) + zoom = 1<<10; + + PosY = StartY; + + switch (inputcounter) + { + case 2: + SetPosX(1); + RenderCharFB(Number | '0', &atrtable[ATR_WB]); + RenderCharFB('-', &atrtable[ATR_WB]); + RenderCharFB('-', &atrtable[ATR_WB]); + break; + + case 1: + SetPosX(2); + RenderCharFB(Number | '0', &atrtable[ATR_WB]); + break; + + case 0: + SetPosX(3); + RenderCharFB(Number | '0', &atrtable[ATR_WB]); + break; + } + + /* generate pagenumber */ + temp_page |= Number << inputcounter*4; + + inputcounter--; + + if (inputcounter < 0) + { + /* disable subpage zapping */ + tuxtxt_cache.zap_subpage_manual = 0; + + /* reset input */ + inputcounter = 2; + + /* set new page */ + lastpage = tuxtxt_cache.page; + + tuxtxt_cache.page = temp_page; + hintmode = 0; + + /* check cache */ + int subp = tuxtxt_cache.subpagetable[tuxtxt_cache.page]; + if (subp != 0xFF) + { + tuxtxt_cache.subpage = subp; + tuxtxt_cache.pageupdate = 1; +#if TUXTXT_DEBUG + printf("TuxTxt \n", tuxtxt_cache.page, tuxtxt_cache.subpage); +#endif + } + else + { + tuxtxt_cache.subpage = 0; +// RenderMessage(PageNotFound); +#if TUXTXT_DEBUG + printf("TuxTxt \n", tuxtxt_cache.page); +#endif + } + } +} + +/****************************************************************************** + * GetNextPageOne * + ******************************************************************************/ + +void GetNextPageOne(int up) +{ + /* disable subpage zapping */ + tuxtxt_cache.zap_subpage_manual = 0; + + /* abort pageinput */ + inputcounter = 2; + + /* find next cached page */ + lastpage = tuxtxt_cache.page; + + int subp; + do { + if (up) + tuxtxt_next_dec(&tuxtxt_cache.page); + else + tuxtxt_prev_dec(&tuxtxt_cache.page); + subp = tuxtxt_cache.subpagetable[tuxtxt_cache.page]; + } while (subp == 0xFF && tuxtxt_cache.page != lastpage); + + /* update page */ + if (tuxtxt_cache.page != lastpage) + { + if (zoommode == 2) + zoommode = 1; + + tuxtxt_cache.subpage = subp; + hintmode = 0; + tuxtxt_cache.pageupdate = 1; +#if TUXTXT_DEBUG + printf("TuxTxt \n", tuxtxt_cache.page, tuxtxt_cache.subpage); +#endif + } +} + +/****************************************************************************** + * GetNextSubPage * + ******************************************************************************/ +void GetNextSubPage(int offset) +{ + int loop; + + /* abort pageinput */ + inputcounter = 2; + + for (loop = tuxtxt_cache.subpage + offset; loop != tuxtxt_cache.subpage; loop += offset) + { + if (loop < 0) + loop = 0x79; + else if (loop > 0x79) + loop = 0; + if (loop == tuxtxt_cache.subpage) + break; + + if (tuxtxt_cache.astCachetable[tuxtxt_cache.page][loop]) + { + /* enable manual subpage zapping */ + tuxtxt_cache.zap_subpage_manual = 1; + + /* update page */ + if (zoommode == 2) /* if zoomed to lower half */ + zoommode = 1; /* activate upper half */ + + tuxtxt_cache.subpage = loop; + hintmode = 0; + tuxtxt_cache.pageupdate = 1; +#if TUXTXT_DEBUG + printf("TuxTxt \n", tuxtxt_cache.page, tuxtxt_cache.subpage); +#endif + return; + } + } + +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif +} +/****************************************************************************** + * ColorKey * + ******************************************************************************/ + +void ColorKey(int target) +{ + if (!target) + return; + if (zoommode == 2) + zoommode = 1; + lastpage = tuxtxt_cache.page; + tuxtxt_cache.page = target; + tuxtxt_cache.subpage = tuxtxt_cache.subpagetable[tuxtxt_cache.page]; + inputcounter = 2; + hintmode = 0; + tuxtxt_cache.pageupdate = 1; +#if TUXTXT_DEBUG + printf("TuxTxt \n", tuxtxt_cache.page); +#endif +} + +/****************************************************************************** + * PageCatching * + ******************************************************************************/ + +void PageCatching() +{ + int val, byte; + int oldzoommode = zoommode; + + pagecatching = 1; + + /* abort pageinput */ + inputcounter = 2; + + /* show info line */ + zoommode = 0; + PosX = StartX; + PosY = StartY + 24*fontheight; + for (byte = 0; byte < 40-nofirst; byte++) + RenderCharFB(catchmenutext[menulanguage][byte], &atrtable[catchmenutext[menulanguage][byte+40] - '0' + ATR_CATCHMENU0]); + zoommode = oldzoommode; + + /* check for pagenumber(s) */ + catch_row = 1; + catch_col = 0; + catched_page = 0; + pc_old_row = pc_old_col = 0; /* no inverted page number to restore yet */ + CatchNextPage(0, 1); + + if (!catched_page) + { + pagecatching = 0; + tuxtxt_cache.pageupdate = 1; + return; + } + + /* set blocking mode */ + val = fcntl(rc, F_GETFL); + fcntl(rc, F_SETFL, val &~ O_NONBLOCK); + + /* loop */ + do { + GetRCCode(); + + switch (RCCode) + { + case RC_LEFT: + CatchNextPage(0, -1); + break; + case RC_RIGHT: + CatchNextPage(0, 1); + break; + case RC_UP: + CatchNextPage(-1, -1); + break; + case RC_DOWN: + CatchNextPage(1, 1); + break; + case RC_0: + case RC_1: + case RC_2: + case RC_3: + case RC_4: + case RC_5: + case RC_6: + case RC_7: + case RC_8: + case RC_9: + case RC_RED: + case RC_GREEN: + case RC_YELLOW: + case RC_BLUE: + case RC_PLUS: + case RC_MINUS: + case RC_DBOX: + case RC_HOME: + case RC_HELP: + case RC_MUTE: + fcntl(rc, F_SETFL, O_NONBLOCK); + tuxtxt_cache.pageupdate = 1; + pagecatching = 0; + RCCode = -1; + return; + } + UpdateLCD(); + } while (RCCode != RC_OK); + + /* set new page */ + if (zoommode == 2) + zoommode = 1; + + lastpage = tuxtxt_cache.page; + tuxtxt_cache.page = catched_page; + hintmode = 0; + tuxtxt_cache.pageupdate = 1; + pagecatching = 0; + + int subp = tuxtxt_cache.subpagetable[tuxtxt_cache.page]; + if (subp != 0xFF) + tuxtxt_cache.subpage = subp; + else + tuxtxt_cache.subpage = 0; + + /* reset to nonblocking mode */ + fcntl(rc, F_SETFL, O_NONBLOCK); +} + +/****************************************************************************** + * CatchNextPage * + ******************************************************************************/ + +void CatchNextPage(int firstlineinc, int inc) +{ + int tmp_page, allowwrap = 1; /* allow first wrap around */ + + /* catch next page */ + for(;;) + { + unsigned char *p = &(page_char[catch_row*40 + catch_col]); + tstPageAttr a = page_atrb[catch_row*40 + catch_col]; + + if (!(a.charset == C_G1C || a.charset == C_G1S) && /* no mosaic */ + (a.fg != a.bg) && /* not hidden */ + (*p >= '1' && *p <= '8' && /* valid page number */ + *(p+1) >= '0' && *(p+1) <= '9' && + *(p+2) >= '0' && *(p+2) <= '9') && + (catch_row == 0 || (*(p-1) < '0' || *(p-1) > '9')) && /* non-numeric char before and behind */ + (catch_row == 37 || (*(p+3) < '0' || *(p+3) > '9'))) + { + tmp_page = ((*p - '0')<<8) | ((*(p+1) - '0')<<4) | (*(p+2) - '0'); + +#if 0 + if (tmp_page != catched_page) /* confusing to skip identical page numbers - I want to reach what I aim to */ +#endif + { + catched_page = tmp_page; + RenderCatchedPage(); + catch_col += inc; /* FIXME: limit */ +#if TUXTXT_DEBUG + printf("TuxTxt 0) + { + catch_row++; + catch_col = 0; + firstlineinc = 0; + } + else if (firstlineinc < 0) + { + catch_row--; + catch_col = 37; + firstlineinc = 0; + } + else + catch_col += inc; + + if (catch_col > 37) + { + catch_row++; + catch_col = 0; + } + else if (catch_col < 0) + { + catch_row--; + catch_col = 37; + } + + if (catch_row > 23) + { + if (allowwrap) + { + allowwrap = 0; + catch_row = 1; + catch_col = 0; + } + else + { +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + return; + } + } + else if (catch_row < 1) + { + if (allowwrap) + { + allowwrap = 0; + catch_row = 23; + catch_col =37; + } + else + { +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + return; + } + } + } +} + + +/****************************************************************************** + * RenderCatchedPage * + ******************************************************************************/ + +void RenderCatchedPage() +{ + int zoom = 0; + + /* handle zoom */ + if (zoommode) + zoom = 1<<10; + + if (pc_old_row || pc_old_col) /* not at first call */ + { + /* restore pagenumber */ + SetPosX(pc_old_col); + + if (zoommode == 2) + PosY = StartY + (pc_old_row-12)*fontheight*((zoom>>10)+1); + else + PosY = StartY + pc_old_row*fontheight*((zoom>>10)+1); + + RenderCharFB(page_char[pc_old_row*40 + pc_old_col ], &page_atrb[pc_old_row*40 + pc_old_col ]); + RenderCharFB(page_char[pc_old_row*40 + pc_old_col + 1], &page_atrb[pc_old_row*40 + pc_old_col + 1]); + RenderCharFB(page_char[pc_old_row*40 + pc_old_col + 2], &page_atrb[pc_old_row*40 + pc_old_col + 2]); + } + + pc_old_row = catch_row; + pc_old_col = catch_col; + + /* mark pagenumber */ + if (zoommode == 1 && catch_row > 11) + { + zoommode = 2; + CopyBB2FB(); + } + else if (zoommode == 2 && catch_row < 12) + { + zoommode = 1; + CopyBB2FB(); + } + SetPosX(catch_col); + + + if (zoommode == 2) + PosY = StartY + (catch_row-12)*fontheight*((zoom>>10)+1); + else + PosY = StartY + catch_row*fontheight*((zoom>>10)+1); + + tstPageAttr a0 = page_atrb[catch_row*40 + catch_col ]; + tstPageAttr a1 = page_atrb[catch_row*40 + catch_col + 1]; + tstPageAttr a2 = page_atrb[catch_row*40 + catch_col + 2]; + int t; + + /* exchange colors */ + t = a0.fg; a0.fg = a0.bg; a0.bg = t; + t = a1.fg; a1.fg = a1.bg; a1.bg = t; + t = a2.fg; a2.fg = a2.bg; a2.bg = t; + + RenderCharFB(page_char[catch_row*40 + catch_col ], &a0); + RenderCharFB(page_char[catch_row*40 + catch_col + 1], &a1); + RenderCharFB(page_char[catch_row*40 + catch_col + 2], &a2); +} + +/****************************************************************************** + * SwitchZoomMode * + ******************************************************************************/ + +void SwitchZoomMode() +{ + if (tuxtxt_cache.subpagetable[tuxtxt_cache.page] != 0xFF) + { + /* toggle mode */ + zoommode++; + + if (zoommode == 3) + zoommode = 0; + +#if TUXTXT_DEBUG + printf("TuxTxt \n", zoommode); +#endif + /* update page */ + tuxtxt_cache.pageupdate = 1; /* FIXME */ + } +} + +/****************************************************************************** + * SwitchScreenMode * + ******************************************************************************/ + +void SwitchScreenMode(int newscreenmode) +{ + + //struct v4l2_format format; + + /* reset transparency mode */ + if (transpmode) + transpmode = 0; + //transpmode = 1; //NEW + + if (newscreenmode < 0) /* toggle mode */ + screenmode++; + else /* set directly */ + screenmode = newscreenmode; +// if ((screenmode > (screen_mode2 ? 2 : 1)) || (screenmode < 0)) + if ((screenmode > 2) || (screenmode < 0)) + screenmode = 0; + +#if TUXTXT_DEBUG + printf("TuxTxt \n", screenmode); +#endif + + /* update page */ + tuxtxt_cache.pageupdate = 1; + + /* clear back buffer */ + clearbbcolor = screenmode?transp:FullScrColor; + ClearBB(clearbbcolor); + + /* set mode */ + if (screenmode) /* split */ + { + ClearFB(clearbbcolor); + + int fw, fh, tx, ty, tw, th; + + if (screenmode==1) /* split with topmenu */ + { + fw = fontwidth_topmenumain; + fh = fontheight; + tw = TV43WIDTH; + displaywidth= (TV43STARTX -sx); + StartX = sx; //+ (((ex-sx) - (40*fw+2+tw)) / 2); /* center screen */ + tx = TV43STARTX; + ty = TV43STARTY; + th = TV43HEIGHT; + } + else /* 2: split with full height tv picture */ + { + fw = fontwidth_small; + fh = fontheight; + tx = TV169FULLSTARTX; + ty = TV169FULLSTARTY; + tw = TV169FULLWIDTH; + th = TV169FULLHEIGHT; + displaywidth= (TV169FULLSTARTX-sx); + } + + setfontwidth(fw); + +#if 0 + int sm = 0; + ioctl(pig, VIDIOC_OVERLAY, &sm); + sm = 1; + ioctl(pig, VIDIOC_G_FMT, &format); + format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + format.fmt.win.w.left = tx; + format.fmt.win.w.top = ty; + format.fmt.win.w.width = tw; + format.fmt.win.w.height = th; + ioctl(pig, VIDIOC_S_FMT, &format); + ioctl(pig, VIDIOC_OVERLAY, &sm); +#endif + } + else /* not split */ + { +#if 0 + ioctl(pig, VIDIOC_OVERLAY, &screenmode); +#endif + + setfontwidth(fontwidth_normal); + displaywidth= (ex-sx); + StartX = sx; //+ (ex-sx - 40*fontwidth) / 2; /* center screen */ + } +} + +/****************************************************************************** + * SwitchTranspMode * + ******************************************************************************/ + +void SwitchTranspMode() +{ + if (screenmode) + { + prevscreenmode = screenmode; + SwitchScreenMode(0); /* turn off divided screen */ + } + /* toggle mode */ +#if 0 // transparent first + if (transpmode == 2) + transpmode = 0; + else + transpmode++; /* backward to immediately switch to TV-screen */ +#endif + /* transpmode: 0 normal, 1 transparent, 2 off */ + transpmode ++; + if(transpmode > 2) + transpmode = 0; + +#if TUXTXT_DEBUG + printf("TuxTxt \n", transpmode); +#endif + + /* set mode */ + if (!transpmode) /* normal text-only */ + { + ClearBB(FullScrColor); + tuxtxt_cache.pageupdate = 1; + } + else if (transpmode == 1) /* semi-transparent BG with FG text */ + { + ClearBB(transp); + tuxtxt_cache.pageupdate = 1; + } + else /* TV mode */ + { + ClearFB(transp); + clearbbcolor = FullScrColor; + } +} + +/****************************************************************************** + * SwitchHintMode * + ******************************************************************************/ + +void SwitchHintMode() +{ + /* toggle mode */ + hintmode ^= 1; +#if TUXTXT_DEBUG + printf("TuxTxt \n", hintmode); +#endif + + if (!hintmode) /* toggle evaluation of level 2.5 information by explicitly switching off hintmode */ + { + showl25 ^= 1; +#if TUXTXT_DEBUG + printf("TuxTxt \n", showl25); +#endif + } + /* update page */ + tuxtxt_cache.pageupdate = 1; +} + +void RenderDRCS( //FIX ME + unsigned char *s, /* pointer to char data, parity undecoded */ + unsigned char *d, /* pointer to frame buffer of top left pixel */ + unsigned char *ax, /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */ + unsigned char fgcolor, unsigned char bgcolor) +{ + int bit, x, y, ltmp; + unsigned char *ay = ax + 13; /* array[0..10] of y-offsets for each pixel */ + + for (y = 0; y < 10; y++) /* 10*2 bytes a 6 pixels per char definition */ + { + unsigned char c1 = deparity[*s++]; + unsigned char c2 = deparity[*s++]; + int h = ay[y+1] - ay[y]; + + if (!h) + continue; + if (((c1 == ' ') && (*(s-2) != ' ')) || ((c2 == ' ') && (*(s-1) != ' '))) /* parity error: stop decoding FIXME */ + return; + for (bit = 0x20, x = 0; + bit; + bit >>= 1, x++) /* bit mask (MSB left), column counter */ + { + int i, f1, f2; + + f1 = (c1 & bit) ? fgcolor : bgcolor; + f2 = (c2 & bit) ? fgcolor : bgcolor; + + for (i = 0; i < h; i++) + { + if (ax[x+1] > ax[x]) + { +// memset(d + ax[x], f1, ax[x+1] - ax[x]); + for (ltmp=0 ; ltmp <= (ax[x+1]-ax[x]); ltmp++) + { + memcpy(d + ax[x]*4 +ltmp*4,bgra[f1],4); + } + } + if (ax[x+7] > ax[x+6]) + { +// memset(d + ax[x+6], f2, ax[x+7] - ax[x+6]); /* 2nd byte 6 pixels to the right */ + for (ltmp=0 ; ltmp <= (ax[x+7]-ax[x+6]); ltmp++) + { + memcpy(d + ax[x+6]*4 +ltmp*4,bgra[f2],4); + } + + } + d += fix_screeninfo.line_length; + } + d -= h * fix_screeninfo.line_length; + } + d += h * fix_screeninfo.line_length; + } +} + + +void DrawVLine(int x, int y, int l, int color) +{ + unsigned char *p = lfb + x*4 + y * fix_screeninfo.line_length; + + for ( ; l > 0 ; l--) + { + memcpy(p,bgra[color],4); + p += fix_screeninfo.line_length; + } +} + +void DrawHLine(int x, int y, int l, int color) +{ + int ltmp; + if (l > 0) + { + for (ltmp=0; ltmp <= l; ltmp++) + { + memcpy(lfb + x*4 + ltmp*4 + y * fix_screeninfo.line_length, bgra[color], 4); + } + } +} + +void FillRectMosaicSeparated(int x, int y, int w, int h, int fgcolor, int bgcolor, int set) +{ + FillRect(x, y, w, h, bgcolor); + if (set) + { + FillRect(x+1, y+1, w-2, h-2, fgcolor); + } +} + +void FillTrapez(int x0, int y0, int l0, int xoffset1, int h, int l1, int color) +{ + unsigned char *p = lfb + x0*4 + y0 * fix_screeninfo.line_length; + int xoffset, l; + int yoffset; + int ltmp; + + for (yoffset = 0; yoffset < h; yoffset++) + { + l = l0 + ((l1-l0) * yoffset + h/2) / h; + xoffset = (xoffset1 * yoffset + h/2) / h; + if (l > 0) + { + for (ltmp=0; ltmp <= l; ltmp++) + { + memcpy(p + xoffset*4 +ltmp*4, bgra[color], 4); + } + } + p += fix_screeninfo.line_length; + } +} +void FlipHorz(int x, int y, int w, int h) +{ + unsigned char buf[w*4]; + unsigned char *p = lfb + x*4 + y * fix_screeninfo.line_length; + int w1,h1; + + for (h1 = 0 ; h1 < h ; h1++) + { + memcpy(buf,p,w*4); + for (w1 = 0 ; w1 < w ; w1++) + { + memcpy(p+w1*4,buf+((w-w1)*4)-4,4); + } + p += fix_screeninfo.line_length; + } +} +void FlipVert(int x, int y, int w, int h) +{ + unsigned char buf[w*4]; + unsigned char *p = lfb + x*4 + y * fix_screeninfo.line_length, *p1, *p2; + int h1; + + for (h1 = 0 ; h1 < h/2 ; h1++) + { + p1 = (p+(h1*fix_screeninfo.line_length)); + p2 = (p+(h-(h1+1))*fix_screeninfo.line_length); + memcpy(buf,p1,w*4); + memcpy(p1,p2,w*4); + memcpy(p2,buf,w*4); + } +} + +int ShapeCoord(int param, int curfontwidth, int curfontheight) +{ + switch (param) + { + case S_W13: + return curfontwidth/3; + case S_W12: + return curfontwidth/2; + case S_W23: + return curfontwidth*2/3; + case S_W11: + return curfontwidth; + case S_WM3: + return curfontwidth-3; + case S_H13: + return curfontheight/3; + case S_H12: + return curfontheight/2; + case S_H23: + return curfontheight*2/3; + case S_H11: + return curfontheight; + default: + return param; + } +} + +void DrawShape(int x, int y, int shapenumber, int curfontwidth, int curfontheight, int fgcolor, int bgcolor, int clear) +{ + if (shapenumber < 0x20 || shapenumber > 0x7e || (shapenumber == 0x7e && clear)) + return; + + unsigned char *p = aShapes[shapenumber - 0x20]; + + if (*p == S_INV) + { + int t = fgcolor; + fgcolor = bgcolor; + bgcolor = t; + p++; + } + + if (clear) + FillRect(x, y, curfontwidth, fontheight, bgcolor); + while (*p != S_END) + switch (*p++) + { + case S_FHL: + { + int offset = ShapeCoord(*p++, curfontwidth, curfontheight); + DrawHLine(x, y + offset, curfontwidth, fgcolor); + break; + } + case S_FVL: + { + int offset = ShapeCoord(*p++, curfontwidth, curfontheight); + DrawVLine(x + offset, y, fontheight, fgcolor); + break; + } + case S_FLH: + FlipHorz(x,y,curfontwidth, fontheight); + break; + case S_FLV: + FlipVert(x,y,curfontwidth, fontheight); + break; + case S_BOX: + { + int xo = ShapeCoord(*p++, curfontwidth, curfontheight); + int yo = ShapeCoord(*p++, curfontwidth, curfontheight); + int w = ShapeCoord(*p++, curfontwidth, curfontheight); + int h = ShapeCoord(*p++, curfontwidth, curfontheight); + FillRect(x + xo, y + yo, w, h, fgcolor); + break; + } + case S_TRA: + { + int x0 = ShapeCoord(*p++, curfontwidth, curfontheight); + int y0 = ShapeCoord(*p++, curfontwidth, curfontheight); + int l0 = ShapeCoord(*p++, curfontwidth, curfontheight); + int x1 = ShapeCoord(*p++, curfontwidth, curfontheight); + int y1 = ShapeCoord(*p++, curfontwidth, curfontheight); + int l1 = ShapeCoord(*p++, curfontwidth, curfontheight); + FillTrapez(x + x0, y + y0, l0, x1-x0, y1-y0, l1, fgcolor); + break; + } + case S_BTR: + { + int x0 = ShapeCoord(*p++, curfontwidth, curfontheight); + int y0 = ShapeCoord(*p++, curfontwidth, curfontheight); + int l0 = ShapeCoord(*p++, curfontwidth, curfontheight); + int x1 = ShapeCoord(*p++, curfontwidth, curfontheight); + int y1 = ShapeCoord(*p++, curfontwidth, curfontheight); + int l1 = ShapeCoord(*p++, curfontwidth, curfontheight); + FillTrapez(x + x0, y + y0, l0, x1-x0, y1-y0, l1, bgcolor); + break; + } + case S_LNK: + { + DrawShape(x, y, ShapeCoord(*p, curfontwidth, curfontheight), curfontwidth, curfontheight, fgcolor, bgcolor, 0); + //p = aShapes[ShapeCoord(*p, curfontwidth, curfontheight) - 0x20]; + break; + } + default: + break; + } +} + + +/****************************************************************************** + * RenderChar * + ******************************************************************************/ + +void RenderChar(int Char, tstPageAttr *Attribute, int zoom, int yoffset) +{ + int Row, Pitch, Bit; + int error, glyph; + int bgcolor, fgcolor; + int factor, xfactor; + int national_subset_local = national_subset; + unsigned char *sbitbuffer; + + int curfontwidth = GetCurFontWidth(); + + if (Attribute->setX26) + { + national_subset_local = 0; // no national subset + } + + // G0+G2 set designation + if (Attribute->setG0G2 != 0x3f) + { + switch (Attribute->setG0G2) + { + case 0x20 : + case 0x24 : + case 0x25 : + national_subset_local = NAT_RU; + break; + case 0x37: + national_subset_local = NAT_GR; + break; + //TODO: arabic and hebrew + default: + national_subset_local = countryconversiontable[Attribute->setG0G2 & 0x07]; + break; + + } + + } + if (Attribute->charset == C_G0S) // use secondary charset + national_subset_local = national_subset_secondary; + if (zoom && Attribute->doubleh) + factor = 4; + else if (zoom || Attribute->doubleh) + factor = 2; + else + factor = 1; + + if (Attribute->doublew) + { + int t = curfontwidth; + PosX += t; + curfontwidth += GetCurFontWidth(); + PosX -= t; + xfactor = 2; + } + else + xfactor = 1; + + if (Char == 0xFF) /* skip doubleheight chars in lower line */ + { + PosX += curfontwidth; + return; + } + + /* get colors */ + if (Attribute->inverted) + { + int t = Attribute->fg; + Attribute->fg = Attribute->bg; + Attribute->bg = t; + } + fgcolor = Attribute->fg; + if (transpmode == 1 && PosY < StartY + 24*fontheight) + { + if (fgcolor == transp) /* outside boxed elements (subtitles, news) completely transparent */ + bgcolor = transp; + else + bgcolor = transp2; + } + else + bgcolor = Attribute->bg; + + /* handle mosaic */ + if ((Attribute->charset == C_G1C || Attribute->charset == C_G1S) && + ((Char&0xA0) == 0x20)) + { + int w1 = (curfontwidth / 2 ) *xfactor; + int w2 = (curfontwidth - w1) *xfactor; + int y; + + Char = (Char & 0x1f) | ((Char & 0x40) >> 1); + if (Attribute->charset == C_G1S) /* separated mosaic */ + for (y = 0; y < 3; y++) + { + FillRectMosaicSeparated(PosX, PosY + yoffset + ymosaic[y]*factor, w1, (ymosaic[y+1] - ymosaic[y])*factor, fgcolor, bgcolor, Char & 0x01); + FillRectMosaicSeparated(PosX + w1, PosY + yoffset + ymosaic[y]*factor, w2, (ymosaic[y+1] - ymosaic[y])*factor, fgcolor, bgcolor, Char & 0x02); + Char >>= 2; + } + else + for (y = 0; y < 3; y++) + { + FillRect(PosX, PosY + yoffset + ymosaic[y]*factor, w1, (ymosaic[y+1] - ymosaic[y])*factor, (Char & 0x01) ? fgcolor : bgcolor); + FillRect(PosX + w1, PosY + yoffset + ymosaic[y]*factor, w2, (ymosaic[y+1] - ymosaic[y])*factor, (Char & 0x02) ? fgcolor : bgcolor); + Char >>= 2; + } + + PosX += curfontwidth; + return; + } + + if (Attribute->charset == C_G3) + { + if (Char < 0x20 || Char > 0x7d) + { + Char = 0x20; + } + else + { + if (*aShapes[Char - 0x20] == S_CHR) + { + unsigned char *p = aShapes[Char - 0x20]; + Char = (*(p+1) <<8) + (*(p+2)); + } + else if (*aShapes[Char - 0x20] == S_ADT) + { + int x,y,f,c; + unsigned char* p = lfb + PosX*4 + (PosY+yoffset)* fix_screeninfo.line_length; + for (y=0; ycharset >= C_OFFSET_DRCS) + { + + tstCachedPage *pcache = tuxtxt_cache.astCachetable[(Attribute->charset & 0x10) ? drcs : gdrcs][Attribute->charset & 0x0f]; + if (pcache) + { + unsigned char drcs_data[23*40]; + tuxtxt_decompress_page((Attribute->charset & 0x10) ? drcs : gdrcs,Attribute->charset & 0x0f,drcs_data); + unsigned char *p; + if (Char < 23*2) + p = drcs_data + 20*Char; + else if (pcache->pageinfo.p24) + p = pcache->pageinfo.p24 + 20*(Char - 23*2); + else + { + FillRect(PosX, PosY + yoffset, curfontwidth, factor*fontheight, bgcolor); + PosX += curfontwidth; + return; + } + axdrcs[12] = curfontwidth; /* adjust last x-offset according to position, FIXME: double width */ + RenderDRCS(p, + lfb + PosX*4 + (yoffset + PosY) * fix_screeninfo.line_length, + axdrcs, fgcolor, bgcolor); + } + else + FillRect(PosX, PosY + yoffset, curfontwidth, factor*fontheight, bgcolor); + PosX += curfontwidth; + return; + } + else if (Attribute->charset == C_G2 && Char >= 0x20 && Char <= 0x7F) + { + if (national_subset_local == NAT_GR) + Char = G2table[2][Char-0x20]; + else if (national_subset_local == NAT_RU) + Char = G2table[1][Char-0x20]; + else + Char = G2table[0][Char-0x20]; + + if (Char == 0x7F) + { + FillRect(PosX, PosY + yoffset, curfontwidth, factor*ascender, fgcolor); + FillRect(PosX, PosY + yoffset + factor*ascender, curfontwidth, factor*(fontheight-ascender), bgcolor); + PosX += curfontwidth; + return; + } + } + else if (national_subset_local == NAT_GR && Char >= 0x40 && Char <= 0x7E) /* remap complete areas for greek */ + Char += 0x390 - 0x40; + else if (national_subset_local == NAT_GR && Char == 0x3c) + Char = '«'; + else if (national_subset_local == NAT_GR && Char == 0x3e) + Char = '»'; + else if (national_subset_local == NAT_GR && Char >= 0x23 && Char <= 0x24) + Char = nationaltable23[NAT_DE][Char-0x23]; /* #$ as in german option */ + else if (national_subset_local == NAT_RU && Char >= 0x40 && Char <= 0x7E) /* remap complete areas for cyrillic */ + Char = G0tablecyrillic[Char-0x20]; + else + { + /* load char */ + switch (Char) + { + case 0x00: + case 0x20: + FillRect(PosX, PosY + yoffset, curfontwidth, factor*fontheight, bgcolor); + PosX += curfontwidth; + return; + case 0x23: + case 0x24: + Char = nationaltable23[national_subset_local][Char-0x23]; + break; + case 0x40: + Char = nationaltable40[national_subset_local]; + break; + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + Char = nationaltable5b[national_subset_local][Char-0x5B]; + break; + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + Char = nationaltable7b[national_subset_local][Char-0x7B]; + break; + case 0x7F: + FillRect(PosX, PosY + yoffset, curfontwidth, factor*ascender, fgcolor); + FillRect(PosX, PosY + yoffset + factor*ascender, curfontwidth, factor*(fontheight-ascender), bgcolor); + PosX += curfontwidth; + return; + case 0xE0: /* |- */ + DrawHLine(PosX, PosY + yoffset, curfontwidth, fgcolor); + DrawVLine(PosX, PosY + yoffset +1, fontheight -1, fgcolor); + FillRect(PosX +1, PosY + yoffset +1, curfontwidth-1, fontheight-1, bgcolor); + PosX += curfontwidth; + return; + case 0xE1: /* - */ + DrawHLine(PosX, PosY + yoffset, curfontwidth, fgcolor); + FillRect(PosX, PosY + yoffset +1, curfontwidth, fontheight-1, bgcolor); + PosX += curfontwidth; + return; + case 0xE2: /* -| */ + DrawHLine(PosX, PosY + yoffset, curfontwidth, fgcolor); + DrawVLine(PosX + curfontwidth -1, PosY + yoffset +1, fontheight -1, fgcolor); + FillRect(PosX, PosY + yoffset +1, curfontwidth-1, fontheight-1, bgcolor); + PosX += curfontwidth; + return; + case 0xE3: /* | */ + DrawVLine(PosX, PosY + yoffset, fontheight, fgcolor); + FillRect(PosX +1, PosY + yoffset, curfontwidth -1, fontheight, bgcolor); + PosX += curfontwidth; + return; + case 0xE4: /* | */ + DrawVLine(PosX + curfontwidth -1, PosY + yoffset, fontheight, fgcolor); + FillRect(PosX, PosY + yoffset, curfontwidth -1, fontheight, bgcolor); + PosX += curfontwidth; + return; + case 0xE5: /* |_ */ + DrawHLine(PosX, PosY + yoffset + fontheight -1, curfontwidth, fgcolor); + DrawVLine(PosX, PosY + yoffset, fontheight -1, fgcolor); + FillRect(PosX +1, PosY + yoffset, curfontwidth-1, fontheight-1, bgcolor); + PosX += curfontwidth; + return; + case 0xE6: /* _ */ + DrawHLine(PosX, PosY + yoffset + fontheight -1, curfontwidth, fgcolor); + FillRect(PosX, PosY + yoffset, curfontwidth, fontheight-1, bgcolor); + PosX += curfontwidth; + return; + case 0xE7: /* _| */ + DrawHLine(PosX, PosY + yoffset + fontheight -1, curfontwidth, fgcolor); + DrawVLine(PosX + curfontwidth -1, PosY + yoffset, fontheight -1, fgcolor); + FillRect(PosX, PosY + yoffset, curfontwidth-1, fontheight-1, bgcolor); + PosX += curfontwidth; + return; + case 0xE8: /* Ii */ + FillRect(PosX +1, PosY + yoffset, curfontwidth -1, fontheight, bgcolor); + for (Row=0; Row < curfontwidth/2; Row++) + DrawVLine(PosX + Row, PosY + yoffset + Row, fontheight - Row, fgcolor); + PosX += curfontwidth; + return; + case 0xE9: /* II */ + FillRect(PosX, PosY + yoffset, curfontwidth/2, fontheight, fgcolor); + FillRect(PosX + curfontwidth/2, PosY + yoffset, (curfontwidth+1)/2, fontheight, bgcolor); + PosX += curfontwidth; + return; + case 0xEA: /* ° */ + FillRect(PosX, PosY + yoffset, curfontwidth, fontheight, bgcolor); + FillRect(PosX, PosY + yoffset, curfontwidth/2, curfontwidth/2, fgcolor); + PosX += curfontwidth; + return; + case 0xEB: /* ¬ */ + FillRect(PosX, PosY + yoffset +1, curfontwidth, fontheight -1, bgcolor); + for (Row=0; Row < curfontwidth/2; Row++) + DrawHLine(PosX + Row, PosY + yoffset + Row, curfontwidth - Row, fgcolor); + PosX += curfontwidth; + return; + case 0xEC: /* -- */ + FillRect(PosX, PosY + yoffset, curfontwidth, curfontwidth/2, fgcolor); + FillRect(PosX, PosY + yoffset + curfontwidth/2, curfontwidth, fontheight - curfontwidth/2, bgcolor); + PosX += curfontwidth; + return; + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + Char = arrowtable[Char - 0xED]; + break; + default: + break; + } + } + if (Char <= 0x20) + { +#if 0//TUXTXT_DEBUG + printf("TuxTxt found control char: %x \"%c\" \n", Char, Char); +#endif + FillRect(PosX, PosY + yoffset, curfontwidth, factor*fontheight, bgcolor); + PosX += curfontwidth; + return; + } + + + if (!(glyph = FT_Get_Char_Index(face, Char))) + { +#if 0// TUXTXT_DEBUG + printf("TuxTxt c%x a%x g%x w%d h%d x%d y%d\n", + error, Char, (int) Attribute, glyph, curfontwidth, fontheight, PosX, PosY); +#endif + FillRect(PosX, PosY + yoffset, curfontwidth, fontheight, bgcolor); + PosX += curfontwidth; + return; + } + + /* render char */ + sbitbuffer = sbit->buffer; + char localbuffer[1000]; // should be enough to store one character-bitmap... + // add diacritical marks + if (Attribute->diacrit) + { + FTC_SBit sbit_diacrit; + + if (national_subset_local == NAT_GR) + Char = G2table[2][0x20+ Attribute->diacrit]; + else if (national_subset_local == NAT_RU) + Char = G2table[1][0x20+ Attribute->diacrit]; + else + Char = G2table[0][0x20+ Attribute->diacrit]; + if ((glyph = FT_Get_Char_Index(face, Char))) + { + if ((error = FTC_SBitCache_Lookup(cache, &typettf, glyph, &sbit_diacrit, NULL)) == 0) + + { + sbitbuffer = (unsigned char*) localbuffer; + memcpy(sbitbuffer,sbit->buffer,sbit->pitch*sbit->height); + + for (Row = 0; Row < sbit->height; Row++) + { + for (Pitch = 0; Pitch < sbit->pitch; Pitch++) + { + if (sbit_diacrit->pitch > Pitch && sbit_diacrit->height > Row) + sbitbuffer[Row*sbit->pitch+Pitch] |= sbit_diacrit->buffer[Row*sbit->pitch+Pitch]; + } + } + } + } + } + + unsigned char *p; + int f; /* running counter for zoom factor */ + + Row = factor * (ascender - sbit->top + TTFShiftY); + FillRect(PosX, PosY + yoffset, curfontwidth, Row, bgcolor); /* fill upper margin */ + + if (ascender - sbit->top + TTFShiftY + sbit->height > fontheight) + sbit->height = fontheight - ascender + sbit->top - TTFShiftY; /* limit char height to defined/calculated fontheight */ + + + p = lfb + PosX*4 + (yoffset + PosY + Row) * fix_screeninfo.line_length; /* running pointer into framebuffer */ + for (Row = sbit->height; Row; Row--) /* row counts up, but down may be a little faster :) */ + { + int pixtodo = (usettf ? sbit->width : curfontwidth); + char *pstart = (char*) p; + + for (Bit = xfactor * (sbit->left + TTFShiftX); Bit > 0; Bit--) /* fill left margin */ + { + for (f = factor-1; f >= 0; f--) + memcpy((p + f*fix_screeninfo.line_length),bgra[bgcolor],4);/*bgcolor*/ + p+=4; + if (!usettf) + pixtodo--; + } + + for (Pitch = sbit->pitch; Pitch; Pitch--) + { + for (Bit = 0x80; Bit; Bit >>= 1) + { + int color; + + if (--pixtodo < 0) + break; + + if (*sbitbuffer & Bit) /* bit set -> foreground */ + color = fgcolor; + else /* bit not set -> background */ + color = bgcolor; + + for (f = factor-1; f >= 0; f--) + memcpy((p + f*fix_screeninfo.line_length),bgra[color],4); + p+=4; + + if (xfactor > 1) /* double width */ + { + for (f = factor-1; f >= 0; f--) + memcpy((p + f*fix_screeninfo.line_length),bgra[color],4); + p+=4; + + if (!usettf) + pixtodo--; + } + } + sbitbuffer++; + } + for (Bit = (usettf ? (curfontwidth - xfactor*(sbit->width + sbit->left + TTFShiftX)) : pixtodo); + Bit > 0; Bit--) /* fill rest of char width */ + { + for (f = factor-1; f >= 0; f--) + memcpy((p + f*fix_screeninfo.line_length),bgra[bgcolor],4); + p+=4; + } + + p = (unsigned char*) pstart + factor*fix_screeninfo.line_length; + } + + Row = ascender - sbit->top + sbit->height + TTFShiftY; + FillRect(PosX, PosY + yoffset + Row*factor, curfontwidth, (fontheight - Row) * factor, bgcolor); /* fill lower margin */ + if (Attribute->underline) + FillRect(PosX, PosY + yoffset + (fontheight-2)* factor, curfontwidth,2*factor, fgcolor); /* underline char */ + + PosX += curfontwidth; +} + +/****************************************************************************** + * RenderCharFB * + ******************************************************************************/ + +void RenderCharFB(int Char, tstPageAttr *Attribute) +{ + RenderChar(Char, Attribute, zoommode, var_screeninfo.yoffset); +} + +/****************************************************************************** + * RenderCharBB * + ******************************************************************************/ + +void RenderCharBB(int Char, tstPageAttr *Attribute) +{ + RenderChar(Char, Attribute, 0, var_screeninfo.yres-var_screeninfo.yoffset); +} + +/****************************************************************************** + * RenderCharLCD * + ******************************************************************************/ + +void RenderCharLCD(int Digit, int XPos, int YPos) +{ +#if 0 + int x, y; + + /* render digit to lcd backbuffer */ + for (y = 0; y < 15; y++) + { + for (x = 0; x < 10; x++) + { + if (lcd_digits[Digit*15*10 + x + y*10]) + lcd_backbuffer[XPos + x + ((YPos+y)/8)*120] |= 1 << ((YPos+y)%8); + else + lcd_backbuffer[XPos + x + ((YPos+y)/8)*120] &= ~(1 << ((YPos+y)%8)); + } + } +#endif +} + +#if 0 +void RenderCharLCDsmall(int Char, int XPos, int YPos) +{ + int old_width = fontwidth; + int old_height = fontheight; + setfontwidth(fontwidth_small_lcd); + typettf.font.pix_height = fontheight = fontwidth_small_lcd; + RenderChar(Char, 0, 0, -(YPos<<8 | XPos)); + setfontwidth(old_width); + typettf.font.pix_height = fontheight = old_height; +} +#endif + +/****************************************************************************** + * RenderMessage * + ******************************************************************************/ + +void RenderMessage(int Message) +{ + int byte; + int fbcolor, timecolor, menuatr; + int pagecolumn; + const char *msg; + + +/* 00000000001111111111222222222233333333334 */ +/* 01234567890123456789012345678901234567890 */ + char message_1[] = "àááááááá www.tuxtxt.com x.xx áááááááâè"; + char message_2[] = "ã äé"; +/* char message_3[] = "ã suche nach Teletext-Anbietern äé"; */ + char message_4[] = "ã äé"; + char message_5[] = "åæææææææææææææææææææææææææææææææææææçé"; + char message_6[] = "ëììììììììììììììììììììììììììììììììììììê"; + +/* char message_7[] = "ã kein Teletext auf dem Transponder äé"; */ +/* char message_8[] = "ã warte auf Empfang von Seite 100 äé"; */ +/* char message_9[] = "ã Seite 100 existiert nicht! äé"; */ + + memcpy(&message_1[24], versioninfo, 4); + /* reset zoom */ + zoommode = 0; + + /* set colors */ + fbcolor = transp; + timecolor = transp<<4 | transp; + menuatr = ATR_MSG0; + + /* clear framebuffer */ + ClearFB(fbcolor); + + /* hide header */ + page_atrb[32].fg = transp; + page_atrb[32].bg = transp; + + + /* set pagenumber */ + if (Message == ShowServiceName) + { + pagecolumn = message8pagecolumn[menulanguage]; + msg = message_8[menulanguage]; + memcpy(&message_4, msg, sizeof(message_4)); + hex2str(message_4+pagecolumn, tuxtxt_cache.page); + + if (SDT_ready) + memcpy(&message_2[2 + (35 - pid_table[current_service].service_name_len)/2], + &pid_table[current_service].service_name, pid_table[current_service].service_name_len); + else if (Message == ShowServiceName) + hex2str(&message_2[17+3], tuxtxt_cache.vtxtpid); + + msg = &message_3_blank[0]; + } + else if (Message == NoServicesFound) + msg = &message_7[menulanguage][0]; + else + msg = &message_3[menulanguage][0]; + + /* render infobar */ + PosX = StartX + fontwidth+5; + PosY = StartY + fontheight*16; + for (byte = 0; byte < 37; byte++) + RenderCharFB(message_1[byte], &atrtable[menuatr + ((byte >= 9 && byte <= 27) ? 1 : 0)]); + RenderCharFB(message_1[37], &atrtable[menuatr + 2]); + + PosX = StartX + fontwidth+5; + PosY = StartY + fontheight*17; + RenderCharFB(message_2[0], &atrtable[menuatr + 0]); + for (byte = 1; byte < 36; byte++) + RenderCharFB(message_2[byte], &atrtable[menuatr + 3]); + RenderCharFB(message_2[36], &atrtable[menuatr + 0]); + RenderCharFB(message_2[37], &atrtable[menuatr + 2]); + + PosX = StartX + fontwidth+5; + PosY = StartY + fontheight*18; + RenderCharFB(msg[0], &atrtable[menuatr + 0]); + for (byte = 1; byte < 36; byte++) + RenderCharFB(msg[byte], &atrtable[menuatr + 3]); + RenderCharFB(msg[36], &atrtable[menuatr + 0]); + RenderCharFB(msg[37], &atrtable[menuatr + 2]); + + PosX = StartX + fontwidth+5; + PosY = StartY + fontheight*19; + RenderCharFB(message_4[0], &atrtable[menuatr + 0]); + for (byte = 1; byte < 36; byte++) + RenderCharFB(message_4[byte], &atrtable[menuatr + 3]); + RenderCharFB(message_4[36], &atrtable[menuatr + 0]); + RenderCharFB(message_4[37], &atrtable[menuatr + 2]); + + PosX = StartX + fontwidth+5; + PosY = StartY + fontheight*20; + for (byte = 0; byte < 37; byte++) + RenderCharFB(message_5[byte], &atrtable[menuatr + 0]); + RenderCharFB(message_5[37], &atrtable[menuatr + 2]); + + PosX = StartX + fontwidth+5; + PosY = StartY + fontheight*21; + for (byte = 0; byte < 38; byte++) + RenderCharFB(message_6[byte], &atrtable[menuatr + 2]); +} + +/****************************************************************************** + * RenderPage * + ******************************************************************************/ + +void DoFlashing(int startrow) +{ + int row, col; + /* get national subset */ + if (auto_national && + national_subset <= NAT_MAX_FROM_HEADER && /* not for GR/RU as long as line28 is not evaluated */ + pageinfo && pageinfo->nationalvalid) /* individual subset according to page header */ + { + national_subset = countryconversiontable[pageinfo->national]; + } + /* Flashing */ + tstPageAttr flashattr; + char flashchar; + struct timeval tv; + gettimeofday(&tv,NULL); + long flashphase = (tv.tv_usec / 1000) % 1000; + int srow = startrow; + int erow = 24; + int factor=1; + switch (zoommode) + { + case 1: erow = 12; factor=2;break; + case 2: srow = 12; factor=2;break; + } + PosY = StartY + startrow*fontheight*factor; + for (row = srow; row < erow; row++) + { + int index = row * 40; + int dhset = 0; + int incflash = 3; + int decflash = 2; + PosX = StartX; + for (col = nofirst; col < 40; col++) + { + if (page_atrb[index + col].flashing && page_char[index + col] > 0x20 && page_char[index + col]!= 0xff ) + { + SetPosX(col); + flashchar = page_char[index + col]; + int doflash = 0; + memcpy(&flashattr,&page_atrb[index + col],sizeof(tstPageAttr)); + switch (flashattr.flashing &0x1c) // Flash Rate + { + case 0x00 : // 1 Hz + if (flashphase>500) doflash = 1; + break; + case 0x04 : // 2 Hz Phase 1 + if (flashphase<250) doflash = 1; + break; + case 0x08 : // 2 Hz Phase 2 + if (flashphase>=250 && flashphase<500) doflash = 1; + break; + case 0x0c : // 2 Hz Phase 3 + if (flashphase>=500 && flashphase<750) doflash = 1; + break; + case 0x10 : // incremental flash + incflash++; + if (incflash>3) incflash = 1; + switch (incflash) + { + case 1: if (flashphase<250) doflash = 1; break; + case 2: if (flashphase>=250 && flashphase<500) doflash = 1;break; + case 3: if (flashphase>=500 && flashphase<750) doflash = 1; + } + break; + case 0x11 : // decremental flash + decflash--; + if (decflash<1) decflash = 3; + switch (decflash) + { + case 1: if (flashphase<250) doflash = 1; break; + case 2: if (flashphase>=250 && flashphase<500) doflash = 1;break; + case 3: if (flashphase>=500 && flashphase<750) doflash = 1; + } + break; + + } + + switch (flashattr.flashing &0x03) // Flash Mode + { + case 0x01 : // normal Flashing + if (doflash) flashattr.fg = flashattr.bg; + break; + case 0x02 : // inverted Flashing + doflash = 1-doflash; + if (doflash) flashattr.fg = flashattr.bg; + break; + case 0x03 : // color Flashing + if (doflash) flashattr.fg = flashattr.fg + (flashattr.fg > 7 ? (-8) : 8); + break; + + } + RenderCharFB(flashchar,&flashattr); + if (flashattr.doublew) col++; + if (flashattr.doubleh) dhset = 1; + } + } + if (dhset) + { + row++; + PosY += fontheight*factor; + } + PosY += fontheight*factor; + } + +} +void RenderPage() +{ + int row, col, byte, startrow = 0;; + int national_subset_bak = national_subset; + + + /* update lcd */ + UpdateLCD(); + + if (transpmode != 2 && delaystarted) + { + struct timeval tv; + gettimeofday(&tv,NULL); + if (tv.tv_sec - tv_delay.tv_sec < subtitledelay) + return; + } + + + /* update page or timestring */ + if (transpmode != 2 && tuxtxt_cache.pageupdate && tuxtxt_cache.page_receiving != tuxtxt_cache.page && inputcounter == 2) + { + if (boxed && subtitledelay) + { + if (!delaystarted) + { + gettimeofday(&tv_delay,NULL); + delaystarted = 1; + return; + } + else + delaystarted = 0; + + } + + /* reset update flag */ + tuxtxt_cache.pageupdate = 0; + + + /* decode page */ + if (tuxtxt_cache.subpagetable[tuxtxt_cache.page] != 0xFF) + DecodePage(); + else + startrow = 1; + if (boxed) + { + if (screenmode != 0) + SwitchScreenMode(0); /* turn off divided screen */ + } + else + { + if (screenmode != prevscreenmode && !transpmode) + SwitchScreenMode(prevscreenmode); + } + + /* display first column? */ + nofirst = show39; + for (row = 1; row < 24; row++) + { + byte = page_char[row*40]; + if (byte != ' ' && byte != 0x00 && byte != 0xFF && + page_atrb[row*40].fg != page_atrb[row*40].bg) + { + nofirst = 0; + break; + } + } + fontwidth_normal = (ex-sx) / (40-nofirst); + setfontwidth(fontwidth_normal); + fontwidth_topmenumain = (TV43STARTX-sx) / (40-nofirst); + fontwidth_topmenusmall = (ex- TOPMENUSTARTX) / TOPMENUCHARS; + fontwidth_small = (TV169FULLSTARTX-sx) / (40-nofirst); + switch(screenmode) + { + case 0: setfontwidth(fontwidth_normal) ; displaywidth= (ex -sx);break; + case 1: setfontwidth(fontwidth_topmenumain); displaywidth= (TV43STARTX -sx);break; + case 2: setfontwidth(fontwidth_small) ; displaywidth= (TV169FULLSTARTX-sx);break; + } + if (transpmode || (boxed && !screenmode)) + { + FillBorder(transp);//ClearBB(transp); + clearbbcolor = transp; + } + + /* get national subset */ + if (auto_national && + national_subset <= NAT_MAX_FROM_HEADER && /* not for GR/RU as long as line28 is not evaluated */ + pageinfo && pageinfo->nationalvalid) /* individual subset according to page header */ + { + national_subset = countryconversiontable[pageinfo->national]; +#if TUXTXT_DEBUG + printf("p%03x b%d n%d v%d i%d\n", tuxtxt_cache.page,national_subset_bak, national_subset, pageinfo->nationalvalid, pageinfo->national); +#endif + } + /* render page */ + PosY = StartY + startrow*fontheight; + for (row = startrow; row < 24; row++) + { + int index = row * 40; + + PosX = StartX; + for (col = nofirst; col < 40; col++) + { + RenderCharBB(page_char[index + col], &page_atrb[index + col]); + + if (page_atrb[index + col].doubleh && page_char[index + col] != 0xff) /* disable lower char in case of doubleh setting in l25 objects */ + page_char[index + col + 40] = 0xff; + if (page_atrb[index + col].doublew) /* skip next column if double width */ + { + col++; + if (page_atrb[index + col-1].doubleh && page_char[index + col] != 0xff) /* disable lower char in case of doubleh setting in l25 objects */ + page_char[index + col + 40] = 0xff; + } + } + PosY += fontheight; + } + DoFlashing(startrow); + national_subset = national_subset_bak; + + /* update framebuffer */ + CopyBB2FB(); + } + else if (transpmode != 2) + { + if (zoommode != 2) + { + PosY = StartY; + if (tuxtxt_cache.subpagetable[tuxtxt_cache.page] == 0xff) + { + page_atrb[32].fg = yellow; + page_atrb[32].bg = menu1; + int showpage = tuxtxt_cache.page_receiving; + int showsubpage = tuxtxt_cache.subpagetable[showpage]; + if (showsubpage!=0xff) + { + + tstCachedPage *pCachedPage; + pCachedPage = tuxtxt_cache.astCachetable[showpage][showsubpage]; + if (pCachedPage && tuxtxt_is_dec(showpage)) + { + PosX = StartX; + if (inputcounter == 2) + { + if (tuxtxt_cache.bttok && !tuxtxt_cache.basictop[tuxtxt_cache.page]) /* page non-existent according to TOP (continue search anyway) */ + { + page_atrb[0].fg = white; + page_atrb[0].bg = red; + } + else + { + page_atrb[0].fg = yellow; + page_atrb[0].bg = menu1; + } + hex2str((char*) page_char+3, tuxtxt_cache.page); + for (col = nofirst; col < 7; col++) // selected page + { + RenderCharFB(page_char[col], &page_atrb[0]); + } + RenderCharFB(page_char[col], &page_atrb[32]); + } + else + SetPosX(8); + + memcpy(&page_char[8], pCachedPage->p0, 24); /* header line without timestring */ + for (col = 0; col < 24; col++) + { + RenderCharFB(pCachedPage->p0[col], &page_atrb[32]); + } + } + } + } + /* update timestring */ + SetPosX(32); + for (byte = 0; byte < 8; byte++) + { + if (!page_atrb[32+byte].flashing) + RenderCharFB(tuxtxt_cache.timestring[byte], &page_atrb[32]); + else + { + SetPosX(33+byte); + page_char[32+byte] = page_char[32+byte]; + } + + + } + } + DoFlashing(startrow); + national_subset = national_subset_bak; + } + else if (transpmode == 2 && tuxtxt_cache.pageupdate == 2) + { +#if TUXTXT_DEBUG + printf("received Update flag for page %03x\n",tuxtxt_cache.page); +#endif + // display pagenr. when page has been updated while in transparency mode + PosY = StartY; + + char ns[3]; + SetPosX(1); + hex2str(ns+2,tuxtxt_cache.page); + + RenderCharFB(ns[0],&atrtable[ATR_WB]); + RenderCharFB(ns[1],&atrtable[ATR_WB]); + RenderCharFB(ns[2],&atrtable[ATR_WB]); + + tuxtxt_cache.pageupdate=0; + } +} + +/****************************************************************************** + * CreateLine25 * + ******************************************************************************/ + +void showlink(int column, int linkpage) +{ + unsigned char *p, line[] = " >??? "; + int oldfontwidth = fontwidth; + int yoffset; + +#if 0 + if (var_screeninfo.yoffset) + yoffset = 0; + else + yoffset = var_screeninfo.yres; +#endif + yoffset = var_screeninfo.yres; //NEW + + int abx = ((displaywidth)%(40-nofirst) == 0 ? displaywidth+1 : (displaywidth)/(((displaywidth)%(40-nofirst)))+1);// distance between 'inserted' pixels + int width = displaywidth /4; + + PosY = StartY + 24*fontheight; + + if (boxed) + { + PosX = StartX + column*width; + FillRect(PosX, PosY+yoffset, displaywidth, fontheight, transp); + return; + } + + if (tuxtxt_cache.adip[linkpage][0]) + { + PosX = StartX + column*width; + int l = strlen((char*) tuxtxt_cache.adip[linkpage]); + + if (l > 9) /* smaller font, if no space for one half space at front and end */ + setfontwidth(oldfontwidth * 10 / (l+1)); + FillRect(PosX, PosY+yoffset, width+(displaywidth%4), fontheight, atrtable[ATR_L250 + column].bg); + PosX += ((width) - (l*fontwidth+l*fontwidth/abx))/2; /* center */ + for (p = tuxtxt_cache.adip[linkpage]; *p; p++) + RenderCharBB(*p, &atrtable[ATR_L250 + column]); + setfontwidth(oldfontwidth); + } + else /* display number */ + { + PosX = StartX + column*width; + FillRect(PosX, PosY+yoffset, displaywidth+sx-PosX, fontheight, atrtable[ATR_L250 + column].bg); + if (linkpage < tuxtxt_cache.page) + { + line[6] = '<'; + hex2str((char*) line + 5, linkpage); + } + else + hex2str((char*) line + 6, linkpage); + for (p = line; p < line+9; p++) + RenderCharBB(*p, &atrtable[ATR_L250 + column]); + } +} + +void CreateLine25() +{ + + if (!tuxtxt_cache.bttok) + /* btt completely received and not yet decoded */ + tuxtxt_decode_btt(); + if (tuxtxt_cache.maxadippg >= 0) + tuxtxt_decode_adip(); + + if (!showhex && showflof && + (tuxtxt_cache.flofpages[tuxtxt_cache.page][0] || tuxtxt_cache.flofpages[tuxtxt_cache.page][1] || tuxtxt_cache.flofpages[tuxtxt_cache.page][2] || tuxtxt_cache.flofpages[tuxtxt_cache.page][3])) // FLOF-Navigation present + { + int i; + + prev_100 = tuxtxt_cache.flofpages[tuxtxt_cache.page][0]; + prev_10 = tuxtxt_cache.flofpages[tuxtxt_cache.page][1]; + next_10 = tuxtxt_cache.flofpages[tuxtxt_cache.page][2]; + next_100 = tuxtxt_cache.flofpages[tuxtxt_cache.page][3]; + + PosY = StartY + 24*fontheight; + PosX = StartX; + for (i=nofirst; i<40; i++) + RenderCharBB(page_char[24*40 + i], &page_atrb[24*40 + i]); + } + else + { + /* normal: blk-1, grp+1, grp+2, blk+1 */ + /* hex: hex+1, blk-1, grp+1, blk+1 */ + if (showhex) + { + /* arguments: startpage, up, findgroup */ + prev_100 = tuxtxt_next_hex(tuxtxt_cache.page); + prev_10 = toptext_getnext(tuxtxt_cache.page, 0, 0); + next_10 = toptext_getnext(tuxtxt_cache.page, 1, 1); + } + else + { + prev_100 = toptext_getnext(tuxtxt_cache.page, 0, 0); + prev_10 = toptext_getnext(tuxtxt_cache.page, 1, 1); + next_10 = toptext_getnext(prev_10, 1, 1); + } + next_100 = toptext_getnext(next_10, 1, 0); + showlink(0, prev_100); + showlink(1, prev_10); + showlink(2, next_10); + showlink(3, next_100); + } + + if (//tuxtxt_cache.bttok && + screenmode == 1) /* TOP-Info present, divided screen -> create TOP overview */ + { + char line[TOPMENUCHARS]; + int current; + int prev10done, next10done, next100done, indent; + tstPageAttr *attrcol, *attr; /* color attribute for navigation keys and text */ + + int olddisplaywidth = displaywidth; + displaywidth = 1000*(40-nofirst); // disable pixelinsert; + setfontwidth(fontwidth_topmenusmall); + + PosY = TOPMENUSTARTY; + memset(line, ' ', TOPMENUCHARS); /* init with spaces */ + + memcpy(line+TOPMENUINDENTBLK, tuxtxt_cache.adip[prev_100], 12); + hex2str(&line[TOPMENUINDENTDEF+12+TOPMENUSPC+2], prev_100); + RenderClearMenuLineBB(line, &atrtable[ATR_L250], &atrtable[ATR_TOPMENU2]); + +/* 1: blk-1, grp-1, grp+1, blk+1 */ +/* 2: blk-1, grp+1, grp+2, blk+1 */ +#if (LINE25MODE == 1) + current = prev_10 - 1; +#else + current = tuxtxt_cache.page - 1; +#endif + + prev10done = next10done = next100done = 0; + while (PosY <= (TOPMENUENDY-fontheight)) + { + attr = 0; + attrcol = &atrtable[ATR_WB]; + if (!next100done && (PosY > (TOPMENUENDY - 2*fontheight))) /* last line */ + { + attrcol = &atrtable[ATR_L253]; + current = next_100; + } + else if (!next10done && (PosY > (TOPMENUENDY - 3*fontheight))) /* line before */ + { + attrcol = &atrtable[ATR_L252]; + current = next_10; + } + else if (!prev10done && (PosY > (TOPMENUENDY - 4*fontheight))) /* line before */ + { + attrcol = &atrtable[ATR_L251]; + current = prev_10; + } + else do + { + tuxtxt_next_dec(¤t); + if (current == prev_10) + { + attrcol = &atrtable[ATR_L251]; + prev10done = 1; + break; + } + else if (current == next_10) + { + attrcol = &atrtable[ATR_L252]; + next10done = 1; + break; + } + else if (current == next_100) + { + attrcol = &atrtable[ATR_L253]; + next100done = 1; + break; + } + else if (current == tuxtxt_cache.page) + { + attr = &atrtable[ATR_TOPMENU0]; + break; + } + } while (tuxtxt_cache.adip[current][0] == 0 && (tuxtxt_cache.basictop[current] < 2 || tuxtxt_cache.basictop[current] > 7)); + + if (!tuxtxt_cache.bttok || (tuxtxt_cache.basictop[current] >= 2 && tuxtxt_cache.basictop[current] <= 5)) /* block (also for FLOF) */ + { + indent = TOPMENUINDENTBLK; + if (!attr) + attr = &atrtable[tuxtxt_cache.basictop[current] <=3 ? ATR_TOPMENU1 : ATR_TOPMENU2]; /* green for program block */ + } + else if (tuxtxt_cache.basictop[current] >= 6 && tuxtxt_cache.basictop[current] <= 7) /* group */ + { + indent = TOPMENUINDENTGRP; + if (!attr) + attr = &atrtable[ATR_TOPMENU3]; + } + else + { + indent = TOPMENUINDENTDEF; + if (!attr) + attr = &atrtable[ATR_WB]; + } + memcpy(line+indent, tuxtxt_cache.adip[current], 12); + hex2str(&line[TOPMENUINDENTDEF+12+TOPMENUSPC+2], current); + RenderClearMenuLineBB(line, attrcol, attr); + } + displaywidth = olddisplaywidth; + setfontwidth(fontwidth_topmenumain); + } +} + +/****************************************************************************** + * CopyBB2FB * + ******************************************************************************/ + +void CopyBB2FB() +{ + unsigned char *src, *dst, *topsrc; + int fillcolor, i, screenwidth, swtmp; + +//printf("[tuxtxt] CopyBB2FB: zoommode %d\n", zoommode); + + /* line 25 */ + if (!pagecatching) + CreateLine25(); + /* copy backbuffer to framebuffer */ + if (!zoommode) + { + memcpy(lfb, lfb+fix_screeninfo.line_length * var_screeninfo.yres, fix_screeninfo.line_length*var_screeninfo.yres); +#if 0 + /* if yoffset != 0, we had active page 1, and activate 0 */ + /* else active was page 0, activate page 1 */ + if (var_screeninfo.yoffset) + var_screeninfo.yoffset = 0; + else + var_screeninfo.yoffset = var_screeninfo.yres; + + if (ioctl(fb, FBIOPAN_DISPLAY, &var_screeninfo) == -1) + perror("TuxTxt "); +#endif + + /* adapt background of backbuffer if changed */ + if (StartX > 0 && *lfb != *(lfb + fix_screeninfo.line_length * var_screeninfo.yres)) + FillBorder(*(lfb + fix_screeninfo.line_length * var_screeninfo.yoffset)); +// ClearBB(*(lfb + var_screeninfo.xres * var_screeninfo.yoffset)); + + if (clearbbcolor >= 0) + { +// ClearBB(clearbbcolor); + clearbbcolor = -1; + } + return; + } + + src = dst = topsrc = lfb + StartY*fix_screeninfo.line_length; + + if (var_screeninfo.yoffset) + dst += fix_screeninfo.line_length * var_screeninfo.yres; + else + { + src += fix_screeninfo.line_length * var_screeninfo.yres; + topsrc += fix_screeninfo.line_length * var_screeninfo.yres; + } + /* copy line25 in normal height */ + if (!pagecatching ) + memcpy(dst+(24*fontheight)*fix_screeninfo.line_length, src + (24*fontheight)*fix_screeninfo.line_length, fix_screeninfo.line_length*fontheight); + + if (transpmode) + fillcolor = transp; + else + fillcolor = FullScrColor; + + if (zoommode == 2) + src += 12*fontheight*fix_screeninfo.line_length; + + /* copy topmenu in normal height (since PIG also keeps dimensions) */ + if (screenmode == 1) + { + unsigned char *topdst = dst; + + screenwidth = ( TV43STARTX ) * 4; + + topsrc += screenwidth; + topdst += screenwidth; + for (i=0; i < 24*fontheight; i++) + { + memcpy(topdst, topsrc,ex-screenwidth); + topdst += fix_screeninfo.line_length; + topsrc += fix_screeninfo.line_length; + } + } + else if (screenmode == 2) + screenwidth = ( TV169FULLSTARTX ) * 4; + else + screenwidth = fix_screeninfo.line_length;//var_screeninfo.xres; + + for (i = StartY; i>0;i--) + { + for (swtmp=0; swtmp<=screenwidth; swtmp++) + { + memcpy(dst - i*fix_screeninfo.line_length+swtmp*4, bgra[fillcolor], 4); + } + } + + for (i = 12*fontheight; i; i--) + { + memcpy(dst, src, screenwidth); + dst += fix_screeninfo.line_length; + memcpy(dst, src, screenwidth); + dst += fix_screeninfo.line_length; + src += fix_screeninfo.line_length; + } + + for (i = var_screeninfo.yres - StartY - 25*fontheight; i >= 0;i--) + { + for (swtmp=0; swtmp<= screenwidth;swtmp++) + { + memcpy(dst + fix_screeninfo.line_length*(fontheight+i)+swtmp*4, bgra[fillcolor], 4); + } + } +} + +/****************************************************************************** + * UpdateLCD * + ******************************************************************************/ + +void UpdateLCD() +{ +#if 0 + static int init_lcd = 1, old_cached_pages = -1, old_page = -1, old_subpage = -1, old_subpage_max = -1, old_hintmode = -1; + int x, y, subpage_max = 0, update_lcd = 0; + + if (lcd == -1) return; // for Dreamboxes without LCD-Display (5xxx) + /* init or update lcd */ + if (init_lcd) + { + init_lcd = 0; + + for (y = 0; y < 64; y++) + { + int lcdbase = (y/8)*120; + int lcdmask = 1 << (y%8); + + for (x = 0; x < 120; ) + { + int rommask; + int rombyte = lcd_layout[x/8 + y*120/8]; + + for (rommask = 0x80; rommask; rommask >>= 1) + { + if (rombyte & rommask) + lcd_backbuffer[x + lcdbase] |= lcdmask; + else + lcd_backbuffer[x + lcdbase] &= ~lcdmask; + x++; + } + } + } + + write(lcd, &lcd_backbuffer, sizeof(lcd_backbuffer)); + + for (y = 16; y < 56; y += 8) /* clear rectangle in backbuffer */ + for (x = 1; x < 118; x++) + lcd_backbuffer[x + (y/8)*120] = 0; + + for (x = 3; x <= 116; x++) + lcd_backbuffer[x + (39/8)*120] |= 1 << (39%8); + + for (y = 42; y <= 60; y++) + lcd_backbuffer[35 + (y/8)*120] |= 1 << (y%8); + + for (y = 42; y <= 60; y++) + lcd_backbuffer[60 + (y/8)*120] |= 1 << (y%8); + + RenderCharLCD(10, 43, 20); + RenderCharLCD(11, 79, 20); + + return; + } + else + { + int p; + + if (inputcounter == 2) + p = tuxtxt_cache.page; + else + p = temp_page + (0xDD >> 4*(1-inputcounter)); /* partial pageinput (filled with spaces) */ + + /* page */ + if (old_page != p) + { + RenderCharLCD(p>>8, 7, 20); + RenderCharLCD((p&0x0F0)>>4, 19, 20); + RenderCharLCD(p&0x00F, 31, 20); + + old_page = p; + update_lcd = 1; + } + + /* current subpage */ + if (old_subpage != tuxtxt_cache.subpage) + { + if (!tuxtxt_cache.subpage) + { + RenderCharLCD(0, 55, 20); + RenderCharLCD(1, 67, 20); + } + else + { + if (tuxtxt_cache.subpage >= 0xFF) + tuxtxt_cache.subpage = 1; + else if (tuxtxt_cache.subpage > 99) + tuxtxt_cache.subpage = 0; + + RenderCharLCD(tuxtxt_cache.subpage>>4, 55, 20); + RenderCharLCD(tuxtxt_cache.subpage&0x0F, 67, 20); + } + + old_subpage = tuxtxt_cache.subpage; + update_lcd = 1; + } + + /* max subpage */ + for (x = 0; x <= 0x79; x++) + { + if (tuxtxt_cache.astCachetable[tuxtxt_cache.page][x]) + subpage_max = x; + } + + if (old_subpage_max != subpage_max) + { + if (!subpage_max) + { + RenderCharLCD(0, 91, 20); + RenderCharLCD(1, 103, 20); + } + else + { + RenderCharLCD(subpage_max>>4, 91, 20); + RenderCharLCD(subpage_max&0x0F, 103, 20); + } + + old_subpage_max = subpage_max; + update_lcd = 1; + } + + /* cachestatus */ + if (old_cached_pages != tuxtxt_cache.cached_pages) + { + #if 0 + int s; + int p = tuxtxt_cache.cached_pages; + for (s=107; s >= 107-4*fontwidth_small_lcd; s -= fontwidth_small_lcd) + { + int c = p % 10; + if (p) + RenderCharLCDsmall('0'+c, s, 44); + else + RenderCharLCDsmall(' ', s, 44); + p /= 10; + } + #else + RenderCharLCD(tuxtxt_cache.cached_pages/1000, 67, 44); + RenderCharLCD(tuxtxt_cache.cached_pages%1000/100, 79, 44); + RenderCharLCD(tuxtxt_cache.cached_pages%100/10, 91, 44); + RenderCharLCD(tuxtxt_cache.cached_pages%10, 103, 44); + #endif + + old_cached_pages = tuxtxt_cache.cached_pages; + update_lcd = 1; + } + + /* mode */ + if (old_hintmode != hintmode) + { + if (hintmode) + RenderCharLCD(12, 43, 44); + else + RenderCharLCD(13, 43, 44); + + old_hintmode = hintmode; + update_lcd = 1; + } + } + + if (update_lcd) + write(lcd, &lcd_backbuffer, sizeof(lcd_backbuffer)); +#endif +} + +/****************************************************************************** + * DecodePage * + ******************************************************************************/ + +void DecodePage() +{ + int row, col; + int hold, dhset; + int foreground, background, doubleheight, doublewidth, charset, mosaictype, IgnoreAtBlackBgSubst, concealed, flashmode, boxwin; + unsigned char held_mosaic, *p; + tstCachedPage *pCachedPage; + + /* copy page to decode buffer */ + if (tuxtxt_cache.subpagetable[tuxtxt_cache.page] == 0xff) /* not cached: do nothing */ + return; + if (tuxtxt_cache.zap_subpage_manual) + pCachedPage = tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpage]; + else + pCachedPage = tuxtxt_cache.astCachetable[tuxtxt_cache.page][tuxtxt_cache.subpagetable[tuxtxt_cache.page]]; + if (!pCachedPage) /* not cached: do nothing */ + return; + + tuxtxt_decompress_page(tuxtxt_cache.page,tuxtxt_cache.subpage,&page_char[40]); + + memcpy(&page_char[8], pCachedPage->p0, 24); /* header line without timestring */ + + pageinfo = &(pCachedPage->pageinfo); + if (pageinfo->p24) + memcpy(&page_char[24*40], pageinfo->p24, 40); /* line 25 for FLOF */ + + /* copy timestring */ + memcpy(&page_char[32], &tuxtxt_cache.timestring, 8); + + /* check for newsflash & subtitle */ + if (pageinfo->boxed && tuxtxt_is_dec(tuxtxt_cache.page)) + boxed = 1; + else + boxed = 0; + + + /* modify header */ + if (boxed) + memset(&page_char, ' ', 40); + else + { + memset(page_char, ' ', 8); + hex2str((char*) page_char+3, tuxtxt_cache.page); + if (tuxtxt_cache.subpage) + { + *(page_char+4) ='/'; + *(page_char+5) ='0'; + hex2str((char*) page_char+6, tuxtxt_cache.subpage); + } + + } + + if (!tuxtxt_is_dec(tuxtxt_cache.page)) + { + if (pageinfo->function == FUNC_MOT) /* magazine organization table */ + { +#if TUXTXT_DEBUG + printf("TuxTxt \n", tuxtxt_cache.page, tuxtxt_cache.subpage, pageinfo->function); +#endif + ClearBB(black); + for (col = 0; col < 24*40; col++) + page_atrb[col] = atrtable[ATR_WB]; + for (col = 40; col < 24*40; col++) + page_char[col] = number2char(page_char[col]); + boxed = 0; + return ; /* don't interpret irregular pages */ + } + else if (pageinfo->function == FUNC_GPOP || pageinfo->function == FUNC_POP) /* object definitions */ + { +#if TUXTXT_DEBUG + printf("TuxTxt \n", tuxtxt_cache.page, tuxtxt_cache.subpage, pageinfo->function); +#endif + ClearBB(black); + for (col = 0; col < 24*40; col++) + page_atrb[col] = atrtable[ATR_WB]; + p = page_char + 40; + for (row = 1; row < 12; row++) + { + *p++ = number2char(row); /* first column: number (0-9, A-..) */ + for (col = 1; col < 40; col += 3) + { + int d = deh24(p); + if (d < 0) + { + memcpy(p, "???", 3); + p += 3; + } + else + { + *p++ = number2char((d >> 6) & 0x1f); /* mode */ + *p++ = number2char(d & 0x3f); /* address */ + *p++ = number2char((d >> 11) & 0x7f); /* data */ + } + } + } + boxed = 0; + return ; /* don't interpret irregular pages */ + } + else if (pageinfo->function == FUNC_GDRCS || pageinfo->function == FUNC_DRCS) /* character definitions */ + { + #define DRCSROWS 8 + #define DRCSCOLS (48/DRCSROWS) + #define DRCSZOOMX 3 + #define DRCSZOOMY 5 + #define DRCSXSPC (12*DRCSZOOMX + 2) + #define DRCSYSPC (10*DRCSZOOMY + 2) + + unsigned char ax[] = { /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */ + DRCSZOOMX * 0, + DRCSZOOMX * 1, + DRCSZOOMX * 2, + DRCSZOOMX * 3, + DRCSZOOMX * 4, + DRCSZOOMX * 5, + DRCSZOOMX * 6, + DRCSZOOMX * 7, + DRCSZOOMX * 8, + DRCSZOOMX * 9, + DRCSZOOMX * 10, + DRCSZOOMX * 11, + DRCSZOOMX * 12, + DRCSZOOMY * 0, + DRCSZOOMY * 1, + DRCSZOOMY * 2, + DRCSZOOMY * 3, + DRCSZOOMY * 4, + DRCSZOOMY * 5, + DRCSZOOMY * 6, + DRCSZOOMY * 7, + DRCSZOOMY * 8, + DRCSZOOMY * 9, + DRCSZOOMY * 10 + }; +#if TUXTXT_DEBUG + printf("TuxTxt \n", tuxtxt_cache.page, tuxtxt_cache.subpage, pageinfo->function); +#endif + ClearBB(black); + for (col = 0; col < 24*40; col++) + page_atrb[col] = atrtable[ATR_WB]; + + for (row = 0; row < DRCSROWS; row++) + for (col = 0; col < DRCSCOLS; col++) + RenderDRCS( + page_char + 20 * (DRCSCOLS * row + col + 2), + lfb + + (StartY + fontheight + DRCSYSPC * row + var_screeninfo.yres - var_screeninfo.yoffset) * fix_screeninfo.line_length + + (StartX + DRCSXSPC * col)*4, + ax, white, black); + + memset(page_char + 40, 0xff, 24*40); /* don't render any char below row 0 */ + boxed = 0; + return ; /* don't interpret irregular pages */ + } + else + { + int i; + int h, parityerror = 0; + + for (i = 0; i < 8; i++) + page_atrb[i] = atrtable[ATR_WB]; + + /* decode parity/hamming */ + for (i = 40; i < (int) sizeof(page_char); i++) + { + page_atrb[i] = atrtable[ATR_WB]; + p = page_char + i; + h = dehamming[*p]; + if (parityerror && h != 0xFF) /* if no regular page (after any parity error) */ + hex2str((char *) p, h); /* first try dehamming */ + else + { + if (*p == ' ' || deparity[*p] != ' ') /* correct parity */ + *p &= 127; + else + { + parityerror = 1; + if (h != 0xFF) /* first parity error: try dehamming */ + hex2str((char *) p, h); + else + *p = ' '; + } + } + } + if (parityerror) + { + boxed = 0; + return ; /* don't interpret irregular pages */ + } + } + } + + /* decode */ + for (row = 0; + row < ((showflof && pageinfo->p24) ? 25 : 24); + row++) + { + /* start-of-row default conditions */ + foreground = white; + background = black; + doubleheight = 0; + doublewidth = 0; + charset = C_G0P; + mosaictype = 0; + concealed = 0; + flashmode = 0; + hold = 0; + boxwin = 0; + held_mosaic = ' '; + dhset = 0; + IgnoreAtBlackBgSubst = 0; + + if (boxed && memchr(&page_char[row*40], start_box, 40) == 0) + { + foreground = transp; + background = transp; + } + + for (col = 0; col < 40; col++) + { + int index = row*40 + col; + + page_atrb[index].fg = foreground; + page_atrb[index].bg = background; + page_atrb[index].charset = charset; + page_atrb[index].doubleh = doubleheight; + page_atrb[index].doublew = (col < 39 ? doublewidth : 0); + page_atrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst; + page_atrb[index].concealed = concealed; + page_atrb[index].flashing = flashmode; + page_atrb[index].boxwin = boxwin; + page_atrb[index].inverted = 0; // only relevant for Level 2.5 + page_atrb[index].underline = 0; // only relevant for Level 2.5 + page_atrb[index].diacrit = 0; // only relevant for Level 2.5 + page_atrb[index].setX26 = 0; // only relevant for Level 2.5 + page_atrb[index].setG0G2 = 0x3f; // only relevant for Level 2.5 + + if (page_char[index] < ' ') + { + switch (page_char[index]) + { + case alpha_black: + case alpha_red: + case alpha_green: + case alpha_yellow: + case alpha_blue: + case alpha_magenta: + case alpha_cyan: + case alpha_white: + concealed = 0; + foreground = page_char[index] - alpha_black + black; + if (col == 0 && page_char[index] == alpha_white) + page_atrb[index].fg = black; // indicate level 1 color change on column 0; (hack) + charset = C_G0P; + break; + + case flash: + flashmode = 1; + break; + case steady: + flashmode = 0; + page_atrb[index].flashing = 0; + break; + case end_box: + boxwin = 0; + IgnoreAtBlackBgSubst = 0; +/* if (boxed) + { + foreground = transp; + background = transp; + IgnoreAtBlackBgSubst = 0; + } +*/ + break; + + case start_box: + if (!boxwin) + { + boxwin = 1; + //background = 0x08; + } +/* if (boxed) + { + int rowstart = row * 40; + if (col > 0) + memset(&page_char[rowstart], ' ', col); + for (clear = 0; clear < col; clear++) + { + page_atrb[rowstart + clear].fg = page_atrb[rowstart + clear].bg = transp; + page_atrb[rowstart + clear].IgnoreAtBlackBgSubst = 0; + } + } +*/ + break; + + case normal_size: + doubleheight = 0; + doublewidth = 0; + page_atrb[index].doubleh = doubleheight; + page_atrb[index].doublew = doublewidth; + break; + + case double_height: + if (row < 23) + { + doubleheight = 1; + dhset = 1; + } + doublewidth = 0; + + break; + + case double_width: + if (col < 39) + doublewidth = 1; + doubleheight = 0; + break; + + case double_size: + if (row < 23) + { + doubleheight = 1; + dhset = 1; + } + if (col < 39) + doublewidth = 1; + break; + + case mosaic_black: + case mosaic_red: + case mosaic_green: + case mosaic_yellow: + case mosaic_blue: + case mosaic_magenta: + case mosaic_cyan: + case mosaic_white: + concealed = 0; + foreground = page_char[index] - mosaic_black + black; + charset = mosaictype ? C_G1S : C_G1C; + break; + + case conceal: + page_atrb[index].concealed = 1; + concealed = 1; + if (!hintmode) + { + foreground = background; + page_atrb[index].fg = foreground; + } + break; + + case contiguous_mosaic: + mosaictype = 0; + if (charset == C_G1S) + { + charset = C_G1C; + page_atrb[index].charset = charset; + } + break; + + case separated_mosaic: + mosaictype = 1; + if (charset == C_G1C) + { + charset = C_G1S; + page_atrb[index].charset = charset; + } + break; + + case esc: + if (charset == C_G0P) + charset = C_G0S; + else if (charset == C_G0S) + charset = C_G0P; + break; + + case black_background: + background = black; + IgnoreAtBlackBgSubst = 0; + page_atrb[index].bg = background; + page_atrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst; + break; + + case new_background: + background = foreground; + if (background == black) + IgnoreAtBlackBgSubst = 1; + else + IgnoreAtBlackBgSubst = 0; + page_atrb[index].bg = background; + page_atrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst; + break; + + case hold_mosaic: + hold = 1; + break; + + case release_mosaic: + hold = 2; + break; + } + + /* handle spacing attributes */ + if (hold && (page_atrb[index].charset == C_G1C || page_atrb[index].charset == C_G1S)) + page_char[index] = held_mosaic; + else + page_char[index] = ' '; + + if (hold == 2) + hold = 0; + } + else /* char >= ' ' */ + { + /* set new held-mosaic char */ + if ((charset == C_G1C || charset == C_G1S) && + ((page_char[index]&0xA0) == 0x20)) + held_mosaic = page_char[index]; + if (page_atrb[index].doubleh) + page_char[index + 40] = 0xFF; + + } + if (!(charset == C_G1C || charset == C_G1S)) + held_mosaic = ' '; /* forget if outside mosaic */ + + } /* for col */ + + /* skip row if doubleheight */ + if (row < 23 && dhset) + { + for (col = 0; col < 40; col++) + { + int index = row*40 + col; + page_atrb[index+40].bg = page_atrb[index].bg; + page_atrb[index+40].fg = white; + if (!page_atrb[index].doubleh) + page_char[index+40] = ' '; + page_atrb[index+40].flashing = 0; + page_atrb[index+40].charset = C_G0P; + page_atrb[index+40].doubleh = 0; + page_atrb[index+40].doublew = 0; + page_atrb[index+40].IgnoreAtBlackBgSubst = 0; + page_atrb[index+40].concealed = 0; + page_atrb[index+40].flashing = 0; + page_atrb[index+40].boxwin = page_atrb[index].boxwin; + } + row++; + } + } /* for row */ + FullScrColor = black; + + if (showl25) + eval_l25(); + + + /* handle Black Background Color Substitution and transparency (CLUT1#0) */ + { + int r, c; + int o = 0; + char bitmask ; + + + + for (r = 0; r < 25; r++) + { + for (c = 0; c < 40; c++) + { + bitmask = (page_atrb[o].bg == 0x08 ? 0x08 : 0x00) | (FullRowColor[r] == 0x08 ? 0x04 : 0x00) | (page_atrb[o].boxwin <<1) | boxed; + switch (bitmask) + { + case 0x08: + case 0x0b: + if (FullRowColor[r] == 0x08) + page_atrb[o].bg = FullScrColor; + else + page_atrb[o].bg = FullRowColor[r]; + break; + case 0x01: + case 0x05: + case 0x09: + case 0x0a: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + page_atrb[o].bg = transp; + break; + } + bitmask = (page_atrb[o].fg == 0x08 ? 0x08 : 0x00) | (FullRowColor[r] == 0x08 ? 0x04 : 0x00) | (page_atrb[o].boxwin <<1) | boxed; + switch (bitmask) + { + case 0x08: + case 0x0b: + if (FullRowColor[r] == 0x08) + page_atrb[o].fg = FullScrColor; + else + page_atrb[o].fg = FullRowColor[r]; + break; + case 0x01: + case 0x05: + case 0x09: + case 0x0a: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + page_atrb[o].fg = transp; + break; + } + o++; + } + } + } + return ; +} + +/****************************************************************************** + * GetRCCode * + ******************************************************************************/ + +int GetRCCode() +{ + struct input_event ev; + static __u16 rc_last_key = KEY_RESERVED; + + int val = fcntl(rc, F_GETFL); + if(!(val & O_NONBLOCK)) + printf("[tuxtxt] GetRCCode in blocking mode.\n"); + + /* get code */ + if (read(rc, &ev, sizeof(ev)) == sizeof(ev)) + { + if (ev.value) + { + if (ev.code != rc_last_key) + { + rc_last_key = ev.code; + switch (ev.code) + { + case KEY_UP: RCCode = RC_UP; break; + case KEY_DOWN: RCCode = RC_DOWN; break; + case KEY_LEFT: RCCode = RC_LEFT; break; + case KEY_RIGHT: RCCode = RC_RIGHT; break; + case KEY_OK: RCCode = RC_OK; break; + case KEY_0: RCCode = RC_0; break; + case KEY_1: RCCode = RC_1; break; + case KEY_2: RCCode = RC_2; break; + case KEY_3: RCCode = RC_3; break; + case KEY_4: RCCode = RC_4; break; + case KEY_5: RCCode = RC_5; break; + case KEY_6: RCCode = RC_6; break; + case KEY_7: RCCode = RC_7; break; + case KEY_8: RCCode = RC_8; break; + case KEY_9: RCCode = RC_9; break; + case KEY_RED: RCCode = RC_RED; break; + case KEY_GREEN: RCCode = RC_GREEN; break; + case KEY_YELLOW: RCCode = RC_YELLOW; break; + case KEY_BLUE: RCCode = RC_BLUE; break; + case KEY_VOLUMEUP: RCCode = RC_PLUS; break; + case KEY_VOLUMEDOWN: RCCode = RC_MINUS; break; + case KEY_MUTE: RCCode = RC_MUTE; break; + case KEY_TEXT: RCCode = RC_TEXT; break; + //case KEY_HELP: RCCode = RC_HELP; break; + case KEY_INFO: RCCode = RC_HELP; break; + case KEY_MENU: RCCode = RC_DBOX; break; + case KEY_EXIT: RCCode = RC_HOME; break; + case KEY_POWER: RCCode = RC_STANDBY; break; + } +printf("[tuxtxt] new key, code %X\n", RCCode); + return 1; + } + } + else + { + RCCode = -1; + rc_last_key = KEY_RESERVED; + } + } + + RCCode = -1; + usleep(1000000/100); + + return 0; +} +/* Local Variables: */ +/* indent-tabs-mode:t */ +/* tab-width:3 */ +/* c-basic-offset:3 */ +/* comment-column:0 */ +/* fill-column:120 */ +/* End: */ diff --git a/lib/libtuxtxt/tuxtxt.h b/lib/libtuxtxt/tuxtxt.h new file mode 100644 index 000000000..725256dbc --- /dev/null +++ b/lib/libtuxtxt/tuxtxt.h @@ -0,0 +1,1506 @@ +#ifndef __tuxtxt_h__ +#define __tuxtxt_h__ + +/****************************************************************************** + * <<< TuxTxt - Teletext Plugin >>> * + * * + * (c) Thomas "LazyT" Loewe 2002-2003 (LazyT@gmx.net) * + * * + * continued 2004-2005 by Roland Meier * + * and DBLuelle * + * * + * ported 2006 to Dreambox 7025 / 32Bit framebuffer * + * by Seddi * + * * + ******************************************************************************/ + +#define TUXTXT_CFG_STANDALONE 0 // 1:plugin only 0:use library +#define TUXTXT_DEBUG 0 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include "tuxtxt_def.h" + +#include +#include FT_FREETYPE_H +#include FT_CACHE_H +#include FT_CACHE_SMALL_BITMAPS_H + +/* devices */ + +#if TUXTXT_CFG_STANDALONE +#include "tuxtxt_common.h" +#else +/* variables and functions from libtuxtxt */ +extern tuxtxt_cache_struct tuxtxt_cache; +extern int tuxtxt_init(); +extern void tuxtxt_close(); +extern void tuxtxt_start(int tpid); // Start caching +extern int tuxtxt_stop(); // Stop caching +extern void tuxtxt_next_dec(int *i); /* skip to next decimal */ +extern void tuxtxt_prev_dec(int *i); /* counting down */ +extern int tuxtxt_is_dec(int i); +extern int tuxtxt_next_hex(int i); +extern void tuxtxt_decode_btt(); +extern void tuxtxt_decode_adip(); /* additional information table */ +extern void tuxtxt_compress_page(int p, int sp, unsigned char* buffer); +extern void tuxtxt_decompress_page(int p, int sp, unsigned char* buffer); +#if TUXTXT_DEBUG +extern int tuxtxt_get_zipsize(int p, int sp); +#endif +#endif + + +#define TUXTXTCONF CONFIGDIR "/tuxtxt/tuxtxt2.conf" + +/* fonts */ +#define TUXTXTTTF FONTDIR "/tuxtxt.ttf" +#define TUXTXTOTB FONTDIR "/tuxtxt.otb" +/* alternative fontdir */ +#define TUXTXTTTFVAR "/var/tuxtxt/tuxtxt.ttf" +#define TUXTXTOTBVAR "/var/tuxtxt/tuxtxt.otb" + +int TTFWidthFactor16, TTFHeightFactor16, TTFShiftX, TTFShiftY; /* parameters for adapting to various TTF fonts */ +int fontheight, fontwidth, fontwidth_normal, fontwidth_small, fontwidth_topmenumain, fontwidth_topmenusmall, ascender; +int ymosaic[4]; +int displaywidth; +#define fontwidth_small_lcd 8 + +#define TV43STARTX (ex - 146) //(StartX + 2 + (40-nofirst)*fontwidth_topmenumain + (40*fontwidth_topmenumain/abx)) +#define TV169FULLSTARTX (sx+ 8*40) //(sx +(ex +1 - sx)/2) +#define TVENDX ex +#define TVENDY (StartY + 25*fontheight) +#define TV43WIDTH 144 /* 120 */ +#define TV43HEIGHT 116 /* 96 */ +#define TV43STARTY (TVENDY - TV43HEIGHT) +#define TV169FULLSTARTY sy +#define TV169FULLWIDTH (ex - sx)/2 +#define TV169FULLHEIGHT (ey - sy) + +#define TOPMENUSTARTX TV43STARTX+2 +#define TOPMENUENDX TVENDX +#define TOPMENUSTARTY StartY +#define TOPMENUENDY TV43STARTY + +#define TOPMENULINEWIDTH ((TOPMENUENDX-TOPMENU43STARTX+fontwidth_topmenusmall-1)/fontwidth_topmenusmall) +#define TOPMENUINDENTBLK 0 +#define TOPMENUINDENTGRP 1 +#define TOPMENUINDENTDEF 2 +#define TOPMENUSPC 0 +#define TOPMENUCHARS (TOPMENUINDENTDEF+12+TOPMENUSPC+4) + +#define FLOFSIZE 4 + +/* spacing attributes */ +#define alpha_black 0x00 +#define alpha_red 0x01 +#define alpha_green 0x02 +#define alpha_yellow 0x03 +#define alpha_blue 0x04 +#define alpha_magenta 0x05 +#define alpha_cyan 0x06 +#define alpha_white 0x07 +#define flash 0x08 +#define steady 0x09 +#define end_box 0x0A +#define start_box 0x0B +#define normal_size 0x0C +#define double_height 0x0D +#define double_width 0x0E +#define double_size 0x0F +#define mosaic_black 0x10 +#define mosaic_red 0x11 +#define mosaic_green 0x12 +#define mosaic_yellow 0x13 +#define mosaic_blue 0x14 +#define mosaic_magenta 0x15 +#define mosaic_cyan 0x16 +#define mosaic_white 0x17 +#define conceal 0x18 +#define contiguous_mosaic 0x19 +#define separated_mosaic 0x1A +#define esc 0x1B +#define black_background 0x1C +#define new_background 0x1D +#define hold_mosaic 0x1E +#define release_mosaic 0x1F + +/* rc codes */ +#define RC_0 0x00 +#define RC_1 0x01 +#define RC_2 0x02 +#define RC_3 0x03 +#define RC_4 0x04 +#define RC_5 0x05 +#define RC_6 0x06 +#define RC_7 0x07 +#define RC_8 0x08 +#define RC_9 0x09 +#define RC_RIGHT 0x0A +#define RC_LEFT 0x0B +#define RC_UP 0x0C +#define RC_DOWN 0x0D +#define RC_OK 0x0E +#define RC_MUTE 0x0F +#define RC_STANDBY 0x10 +#define RC_GREEN 0x11 +#define RC_YELLOW 0x12 +#define RC_RED 0x13 +#define RC_BLUE 0x14 +#define RC_PLUS 0x15 +#define RC_MINUS 0x16 +#define RC_HELP 0x17 +#define RC_DBOX 0x18 +#define RC_TEXT 0x19 +#define RC_HOME 0x1F + +typedef enum /* object type */ +{ + OBJ_PASSIVE, + OBJ_ACTIVE, + OBJ_ADAPTIVE +} tObjType; + +const char *ObjectSource[] = +{ + "(illegal)", + "Local", + "POP", + "GPOP" +}; +const char *ObjectType[] = +{ + "Passive", + "Active", + "Adaptive", + "Passive" +}; + +/* messages */ +#define ShowInfoBar 0 +//#define PageNotFound 1 +#define ShowServiceName 2 +#define NoServicesFound 3 + +/* framebuffer stuff */ +static unsigned char *lfb = 0; +struct fb_var_screeninfo var_screeninfo; +struct fb_fix_screeninfo fix_screeninfo; + +/* freetype stuff */ +FT_Library library; +FTC_Manager manager; +static FTC_SBitCache cache; +FTC_SBit sbit; + +#define FONTTYPE FTC_ImageTypeRec + +FT_Face face; +FONTTYPE typettf; + + +// G2 Charset (0 = Latin, 1 = Cyrillic, 2 = Greek) +const unsigned short int G2table[3][6*16] = +{ + { ' ' ,'¡' ,'¢' ,'£' ,'$' ,'¥' ,'#' ,'§' ,'¤' ,'\'','\"','«' ,8592,8594,8595,8593, + '°' ,'±' ,'²' ,'³' ,'x' ,'µ' ,'¶' ,'·' ,'÷' ,'\'','\"','»' ,'¼' ,'½' ,'¾' ,'¿' , + ' ' ,'`' ,'´' ,710 ,732 ,'¯' ,728 ,729 ,733 ,716 ,730 ,719 ,'_' ,698 ,718 ,711 , + '­' ,'¹' ,'®' ,'©' ,8482,9834,8364,8240,945 ,' ' ,' ' ,' ' ,8539,8540,8541,8542, + 937 ,'Æ' ,272 ,'ª' ,294 ,' ' ,306 ,319 ,321 ,'Ø' ,338 ,'º' ,'Þ' ,358 ,330 ,329 , + 1082,'æ' ,273 ,'ð' ,295 ,305 ,307 ,320 ,322 ,'ø' ,339 ,'ß' ,'þ' ,359 ,951 ,0x7F}, + { ' ' ,'¡' ,'¢' ,'£' ,'$' ,'¥' ,' ' ,'§' ,' ' ,'\'','\"','«' ,8592,8594,8595,8593, + '°' ,'±' ,'²' ,'³' ,'x' ,'µ' ,'¶' ,'·' ,'÷' ,'\'','\"','»' ,'¼' ,'½' ,'¾' ,'¿' , + ' ' ,'`' ,'´' ,710 ,732 ,'¯' ,728 ,729 ,733 ,716 ,730 ,719 ,'_' ,698 ,718 ,711 , + '­' ,'¹' ,'®' ,'©' ,8482,9834,8364,8240,945 ,321 ,322 ,'ß' ,8539,8540,8541,8542, + 'D' ,'E' ,'F' ,'G' ,'I' ,'J' ,'K' ,'L' ,'N' ,'Q' ,'R' ,'S' ,'U' ,'V' ,'W' ,'Z' , + 'd' ,'e' ,'f' ,'g' ,'i' ,'j' ,'k' ,'l' ,'n' ,'q' ,'r' ,'s' ,'u' ,'v' ,'w' ,'z' }, + { ' ' ,'a' ,'b' ,'£' ,'e' ,'h' ,'i' ,'§' ,':' ,'\'','\"','k' ,8592,8594,8595,8593, + '°' ,'±' ,'²' ,'³' ,'x' ,'m' ,'n' ,'p' ,'÷' ,'\'','\"','t' ,'¼' ,'½' ,'¾' ,'x' , + ' ' ,'`' ,'´' ,710 ,732 ,'¯' ,728 ,729 ,733 ,716 ,730 ,719 ,'_' ,698 ,718 ,711 , + '?' ,'¹' ,'®' ,'©' ,8482,9834,8364,8240,945 ,906 ,910 ,911 ,8539,8540,8541,8542, + 'C' ,'D' ,'F' ,'G' ,'J' ,'L' ,'Q' ,'R' ,'S' ,'U' ,'V' ,'W' ,'Y' ,'Z' ,902 ,905 , + 'c' ,'d' ,'f' ,'g' ,'j' ,'l' ,'q' ,'r' ,'s' ,'u' ,'v' ,'w' ,'y' ,'z' ,904 ,0x7F} +}; +// cyrillic G0 Charset +// TODO: different maps for serbian/russian/ukrainian +const unsigned short int G0tablecyrillic[6*16] = +{ + ' ' ,'!' ,'\"','#' ,'$' ,'%' ,'&' ,'\'','(' ,')' ,'*' ,'+' ,',' ,'-' ,'.' ,'/' , + '0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,':' ,';' ,'<' ,'=' ,'>' ,'?' , + 1063,1040,1041,1062,1044,1045,1060,1043,1061,1048,1032,1050,1051,1052,1053,1054, + 1055,1036,1056,1057,1058,1059,1042,1027,1033,1034,1047,1035,1046,1026,1064,1119, + 1095,1072,1073,1094,1076,1077,1092,1075,1093,1080,1112,1082,1083,1084,1085,1086, + 1087,1116,1088,1089,1090,1091,1074,1107,1113,1114,1079,1115,1078,1106,1096,0x7F +}; + +const unsigned short int nationaltable23[14][2] = +{ + { '#', '¤' }, /* 0 */ + { '#', 367 }, /* 1 CS/SK */ + { '£', '$' }, /* 2 EN */ + { '#', 'õ' }, /* 3 ET */ + { 'é', 'ï' }, /* 4 FR */ + { '#', '$' }, /* 5 DE */ + { '£', '$' }, /* 6 IT */ + { '#', '$' }, /* 7 LV/LT */ + { '#', 329 }, /* 8 PL */ + { 'ç', '$' }, /* 9 PT/ES */ + { '#', '¤' }, /* A RO */ + { '#', 'Ë' }, /* B SR/HR/SL */ + { '#', '¤' }, /* C SV/FI/HU */ + { '£', 287 }, /* D TR ? */ +}; +const unsigned short int nationaltable40[14] = +{ + '@', /* 0 */ + 269, /* 1 CS/SK */ + '@', /* 2 EN */ + 352, /* 3 ET */ + 'à', /* 4 FR */ + '§', /* 5 DE */ + 'é', /* 6 IT */ + 352, /* 7 LV/LT */ + 261, /* 8 PL */ + '¡', /* 9 PT/ES */ + 354, /* A RO */ + 268, /* B SR/HR/SL */ + 'É', /* C SV/FI/HU */ + 304, /* D TR */ +}; +const unsigned short int nationaltable5b[14][6] = +{ + { '[','\\', ']', '^', '_', '`' }, /* 0 */ + { 357, 382, 'ý', 'í', 345, 'é' }, /* 1 CS/SK */ + {8592, '½',8594,8593, '#', 822 }, /* 2 EN */ + { 'Ä', 'Ö', 381, 'Ü', 'Õ', 353 }, /* 3 ET */ + { 'ë', 'ê', 'ù', 'î', '#', 'è' }, /* 4 FR */ + { 'Ä', 'Ö', 'Ü', '^', '_', '°' }, /* 5 DE */ + { '°', 'ç',8594,8593, '#', 'ù' }, /* 6 IT */ + { 'é', 553, 381, 269, 363, 353 }, /* 7 LV/LT */ + { 437, 346, 321, 263, 'ó', 281 }, /* 8 PL */ + { 'á', 'é', 'í', 'ó', 'ú', '¿' }, /* 9 PT/ES */ + { 'Â', 350, 461, 'Î', 305, 355 }, /* A RO */ + { 262, 381, 272, 352, 'ë', 269 }, /* B SR/HR/SL */ + { 'Ä', 'Ö', 'Å', 'Ü', '_', 'é' }, /* C SV/FI/HU */ + { 350, 'Ö', 'Ç', 'Ü', 486, 305 }, /* D TR */ +}; +const unsigned short int nationaltable7b[14][4] = +{ + { '{', '|', '}', '~' }, /* 0 */ + { 'á', 283, 'ú', 353 }, /* 1 CS/SK */ + { '¼',8214, '¾', '÷' }, /* 2 EN */ + { 'ä', 'ö', 382, 'ü' }, /* 3 ET */ + { 'â', 'ô', 'û', 'ç' }, /* 4 FR */ + { 'ä', 'ö', 'ü', 'ß' }, /* 5 DE */ + { 'à', 'ò', 'è', 'ì' }, /* 6 IT */ + { 261, 371, 382, 303 }, /* 7 LV/LT */ + { 380, 347, 322, 378 }, /* 8 PL */ + { 'ü', 'ñ', 'è', 'à' }, /* 9 PT/ES */ + { 'â', 351, 462, 'î' }, /* A RO */ + { 263, 382, 273, 353 }, /* B SR/HR/SL */ + { 'ä', 'ö', 'å', 'ü' }, /* C SV/FI/HU */ + { 351, 'ö', 231, 'ü' }, /* D TR */ +}; + +const unsigned short int arrowtable[] = +{ + 8592, 8594, 8593, 8595, 'O', 'K', 8592, 8592 +}; + +/* national subsets */ +const char countrystring[] = +" (#$@[\\]^_`{|}~) " /* 0 no subset specified */ +" CS/SK (#$@[\\]^_`{|}~) " /* 1 czech, slovak */ +" EN (#$@[\\]^_`{|}~) " /* 2 english */ +" ET (#$@[\\]^_`{|}~) " /* 3 estonian */ +" FR (#$@[\\]^_`{|}~) " /* 4 french */ +" DE (#$@[\\]^_`{|}~) " /* 5 german */ +" IT (#$@[\\]^_`{|}~) " /* 6 italian */ +" LV/LT (#$@[\\]^_`{|}~) " /* 7 latvian, lithuanian */ +" PL (#$@[\\]^_`{|}~) " /* 8 polish */ +" PT/ES (#$@[\\]^_`{|}~) " /* 9 portuguese, spanish */ +" RO (#$@[\\]^_`{|}~) " /* 10 romanian */ +" SR/HR/SL (#$@[\\]^_`{|}~) " /* 11 serbian, croatian, slovenian */ +" SV/FI/HU (#$@[\\]^_`{|}~) " /* 12 swedish, finnish, hungarian */ +" TR (#$@[\\]^_`{|}~) " /* 13 turkish */ +" RU/BUL/SER/CRO/UKR (cyr) " /* 14 cyrillic */ +" EK " /* 15 greek */ +; +#define COUNTRYSTRING_WIDTH 26 +#define MAX_NATIONAL_SUBSET (sizeof(countrystring) / COUNTRYSTRING_WIDTH - 1) + +enum +{ + NAT_DEFAULT = 0, + NAT_CZ = 1, + NAT_UK = 2, + NAT_ET = 3, + NAT_FR = 4, + NAT_DE = 5, + NAT_IT = 6, + NAT_LV = 7, + NAT_PL = 8, + NAT_SP = 9, + NAT_RO = 10, + NAT_SR = 11, + NAT_SW = 12, + NAT_TR = 13, + NAT_MAX_FROM_HEADER = 13, + NAT_RU = 14, + NAT_GR = 15 +}; + +const unsigned char countryconversiontable[] = { NAT_UK, NAT_DE, NAT_SW, NAT_IT, NAT_FR, NAT_SP, NAT_CZ, NAT_RO}; + + +/* some data */ +char versioninfo[16]; +int hotlist[10]; +int maxhotlist; + +int pig, rc, fb, lcd; +int sx, ex, sy, ey; +int PosX, PosY, StartX, StartY; +int lastpage; +int inputcounter; +int zoommode, screenmode, transpmode, hintmode, boxed, nofirst, savedscreenmode, showflof, show39, showl25, prevscreenmode; +char dumpl25; +int catch_row, catch_col, catched_page, pagecatching; +int prev_100, prev_10, next_10, next_100; +int screen_mode1, screen_mode2, color_mode, trans_mode, national_subset, national_subset_secondary, auto_national, swapupdown, showhex, menulanguage; +int pids_found, current_service, getpidsdone; +int SDT_ready; +int pc_old_row, pc_old_col; /* for page catching */ +int temp_page; /* for page input */ +char saveconfig, hotlistchanged; +signed char clearbbcolor = -1; +int usettf; +short pop, gpop, drcs, gdrcs; +unsigned char tAPx, tAPy; /* temporary offset to Active Position for objects */ +unsigned char axdrcs[12+1+10+1]; +#define aydrcs (axdrcs + 12+1) +unsigned char FullRowColor[25]; +unsigned char FullScrColor; +tstPageinfo *pageinfo = 0;/* pointer to cached info of last decoded page */ +const char * fncmodes[] = {"12", "6"}; +const char * saamodes[] = {"4:3_full_format", "16:9_full_format"}; + +struct timeval tv_delay; +int subtitledelay, delaystarted; +FILE *conf; + + +unsigned short RCCode; + +struct _pid_table +{ + int vtxt_pid; + int service_id; + int service_name_len; + char service_name[24]; + int national_subset; +}pid_table[128]; + +unsigned char restoreaudio = 0; +/* 0 Nokia, 1 Philips, 2 Sagem */ +/* typ_vcr/dvb: v1 a1 v2 a2 v3 a3 (vcr_only: fblk) */ + +/* language dependent texts */ +#define MAXMENULANGUAGE 8 /* 0 deutsch, 1 englisch, 2 französisch, 3 niederländisch, 4 griechisch, 5 italienisch, 6 polnisch, 7 schwedisch, 8 suomi */ +const int menusubset[] = { NAT_DE , NAT_UK , NAT_FR , NAT_UK , NAT_GR , NAT_IT , NAT_PL , NAT_SW, NAT_SW }; + + +#define Menu_StartX (StartX + fontwidth*9/2) +#define Menu_StartY (StartY + fontheight) +#define Menu_Height 24 +#define Menu_Width 31 + +const char MenuLine[] = +{ + 3,8,11,12,15,17,19,20,21 +}; + +enum +{ + M_HOT=0, + M_PID, + M_SC1, + M_SC2, + M_COL, + M_TRA, + M_AUN, + M_NAT, + M_LNG, + M_Number +}; + +#define M_Start M_HOT +#define M_MaxDirect M_AUN + +const char hotlistpagecolumn[] = /* last(!) column of page to show in each language */ +{ + 22, 26, 28, 27, 28, 27, 28, 21, 20 +}; +const char hotlisttextcolumn[] = +{ + 24, 14, 14, 15, 14, 15, 14, 23, 22 +}; +const char hotlisttext[][2*6] = +{ + { "dazu entf." }, + { " add rem. " }, + { "ajoutenlev" }, + { "toev.verw." }, + { "pq|shava_q" }, + { "agg. elim." }, + { "dodajkasuj" }, + { "ny bort " }, + { "lis{{pois " }, +}; + +const char configonoff[][2*4] = +{ + { "ausein" }, + { "offon " }, + { "desact" }, + { "uitaan" }, + { "emeape" }, + { "offon " }, + { "wy}w} " }, + { "p} av " }, + { "EI ON " }, +}; +const char menuatr[Menu_Height*(Menu_Width+1)] = +{ + "0000000000000000000000000000002" + "0111111111111111111111111111102" + "0000000000000000000000000000002" + "3144444444444444444444444444432" + "3556655555555555555555555555532" + "3555555555555555555555555555532" + "3333333333333333333333333333332" + "3144444444444444444444444444432" + "3555555555555555555555555555532" + "3333333333333333333333333333332" + "3444444444444444444444444444432" + "3155555555555555555555555555532" + "3155555555555555555555555555532" + "3333333333333333333333333333332" + "3144444444444444444444444444432" + "3555555555555555555555555555532" + "3144444444444444444444444444432" + "3555555555555555555555555555532" + "3144444444444444444444444444432" + "3555555555555555555555555555532" + "3555555555555555555555555555532" + "3555555555555555555555555555532" + "3334444444444444444444444443332" + "2222222222222222222222222222222" +}; +const char configmenu[][Menu_Height*(Menu_Width+1)] = +{ + { +/* 0000000000111111111122222222223 */ +/* 0123456789012345678901234567890 */ + "àááááááááááááááááááááááááááááâè" + "ã Konfigurationsmen} äé" + "åææææææææææææææææææææææææææææçé" + "ã1 Favoriten: Seite 111 dazu äé" + "ãíîñò äé" + "ã+-? äé" + "ã äé" + "ã2 Teletext-Auswahl äé" + "ãí suchen îäé" + "ã äé" + "ã Bildschirmformat äé" + "ã3 Standard-Modus 16:9 äé" + "ã4 TextBild-Modus 16:9 äé" + "ã äé" + "ã5 Helligkeit äé" + "ãí îäé" + "ã6 Transparenz äé" + "ãí îäé" + "ã7 nationaler Zeichensatz äé" + "ãautomatische Erkennung äé" + "ãí DE (#$@[\\]^_`{|}~) îäé" + "ãí Sprache/Language deutsch îäé" + "åæ www.tuxtxt.net x.xx æçé" + "ëìììììììììììììììììììììììììììììê" + }, +/* 0000000000111111111122222222223 */ +/* 0123456789012345678901234567890 */ + { + "àááááááááááááááááááááááááááááâè" + "ã Configuration menu äé" + "åææææææææææææææææææææææææææææçé" + "ã1 Favorites: add page 111 äé" + "ãíîñò äé" + "ã+-? äé" + "ã äé" + "ã2 Teletext selection äé" + "ãí search îäé" + "ã äé" + "ã Screen format äé" + "ã3 Standard mode 16:9 äé" + "ã4 Text/TV mode 16:9 äé" + "ã äé" + "ã5 Brightness äé" + "ãí îäé" + "ã6 Transparency äé" + "ãí îäé" + "ã7 national characterset äé" + "ã automatic recognition äé" + "ãí DE (#$@[\\]^_`{|}~) îäé" + "ãí Sprache/language english îäé" + "åæ www.tuxtxt.net x.xx æçé" + "ëìììììììììììììììììììììììììììììê" + }, +/* 0000000000111111111122222222223 */ +/* 0123456789012345678901234567890 */ + { + "àááááááááááááááááááááááááááááâè" + "ã Menu de configuration äé" + "åææææææææææææææææææææææææææææçé" + "ã1 Favorites: ajout. page 111äé" + "ãíîñò äé" + "ã+-? äé" + "ã äé" + "ã2 Selection de teletext äé" + "ãí recherche îäé" + "ã äé" + "ã Format de l'#cran äé" + "ã3 Mode standard 16:9 äé" + "ã4 Texte/TV 16:9 äé" + "ã äé" + "ã5 Clarte äé" + "ãí îäé" + "ã6 Transparence äé" + "ãí îäé" + "ã7 police nationale äé" + "ãreconn. automatique äé" + "ãí DE (#$@[\\]^_`{|}~) îäé" + "ãí Sprache/language francaisîäé" + "åæ www.tuxtxt.net x.xx æçé" + "ëìììììììììììììììììììììììììììììê" + }, +/* 0000000000111111111122222222223 */ +/* 0123456789012345678901234567890 */ + { + "àááááááááááááááááááááááááááááâè" + "ã Configuratiemenu äé" + "åææææææææææææææææææææææææææææçé" + "ã1 Favorieten: toev. pag 111 äé" + "ãíîñò äé" + "ã+-? äé" + "ã äé" + "ã2 Teletekst-selectie äé" + "ãí zoeken îäé" + "ã äé" + "ã Beeldschermformaat äé" + "ã3 Standaardmode 16:9 äé" + "ã4 Tekst/TV mode 16:9 äé" + "ã äé" + "ã5 Helderheid äé" + "ãí îäé" + "ã6 Transparantie äé" + "ãí îäé" + "ã7 nationale tekenset äé" + "ãautomatische herkenning äé" + "ãí DE (#$@[\\]^_`{|}~) îäé" + "ãí Sprache/Language nederl. îäé" + "åæ www.tuxtxt.net x.xx æçé" + "ëìììììììììììììììììììììììììììììê" + }, +/* 0000000000111111111122222222223 */ +/* 0123456789012345678901234567890 */ + { + "àááááááááááááááááááááááááááááâè" + "ã Lemo} quhl_seym äé" + "åææææææææææææææææææææææææææææçé" + "ã1 Vaboq_: pqo_h. sek. 111äé" + "ãíîñò äé" + "ã+-? äé" + "ã äé" + "ã2 Epikoc^ Teket]nt äé" + "ãí Amaf^tgsg îäé" + "ã äé" + "ã Loqv^ oh|mgr äé" + "ã3 Tq|por pq|tupor 16:9 äé" + "ã4 Tq|por eij. jeil. 16:9 äé" + "ã äé" + "ã5 Kalpq|tgta äé" + "ãí îäé" + "ã6 Diav\\meia äé" + "ãí îäé" + "ã7 Ehmij^ tuposeiq\\ äé" + "ãaut|latg amacm~qisg äé" + "ãí DE (#$@[\\]^_`{|}~) îäé" + "ãí Ck~ssa/Language ekkgmij\\ îäé" + "åæ www.tuxtxt.net x.xx æçé" + "ëìììììììììììììììììììììììììììììê" + }, +/* 0000000000111111111122222222223 */ +/* 0123456789012345678901234567890 */ + { + "àááááááááááááááááááááááááááááâè" + "ã Menu di configurazione äé" + "åææææææææææææææææææææææææææææçé" + "ã1 Preferiti: agg. pag.111 äé" + "ãíîñò äé" + "ã+-? äé" + "ã äé" + "ã2 Selezione televideo äé" + "ãí ricerca îäé" + "ã äé" + "ã Formato schermo äé" + "ã3 Modo standard 16:9 äé" + "ã4 Text/Mod.TV 16:9 äé" + "ã äé" + "ã5 Luminosit{ äé" + "ãí îäé" + "ã6 Trasparenza äé" + "ãí îäé" + "ã7 nazionalita'caratteri äé" + "ã riconoscimento automatico äé" + "ãí DE (#$@[\\]^_`{|}~) îäé" + "ãí Lingua/Language Italiana îäé" + "åæ www.tuxtxt.net x.xx æçé" + "ëìììììììììììììììììììììììììììììê" + }, +/* 0000000000111111111122222222223 */ +/* 0123456789012345678901234567890 */ + { + "àááááááááááááááááááááááááááááâè" + "ã Konfiguracja äé" + "åææææææææææææææææææææææææææææçé" + "ã1 Ulubione : kasuj str. 111äé" + "ãíîñò äé" + "ã+-? äé" + "ã äé" + "ã2 Wyb_r telegazety äé" + "ãí szukaj îäé" + "ã äé" + "ã Format obrazu äé" + "ã3 Tryb standard 16:9 äé" + "ã4 Telegazeta/TV 16:9 äé" + "ã äé" + "ã5 Jasno|^ äé" + "ãí îäé" + "ã6 Prze~roczysto|^ äé" + "ãí îäé" + "ã7 Znaki charakterystyczne äé" + "ã automatyczne rozpozn. äé" + "ãí DE (#$@[\\]^_`{|}~) îäé" + "ãí J`zyk/Language polski îäé" + "åæ www.tuxtxt.net x.xx æçé" + "ëìììììììììììììììììììììììììììììê" + }, +/* 0000000000111111111122222222223 */ +/* 0123456789012345678901234567890 */ + { + "àááááááááááááááááááááááááááááâè" + "ã Konfigurationsmeny äé" + "åææææææææææææææææææææææææææææçé" + "ã1 Favoriter: sida 111 ny äé" + "ãíîñò äé" + "ã+-? äé" + "ã äé" + "ã2 TextTV v{ljaren äé" + "ãí s|k îäé" + "ã äé" + "ã TV- format äé" + "ã3 Standard l{ge 16:9 äé" + "ã4 Text/Bild l{ge 16:9 äé" + "ã äé" + "ã5 Ljusstyrka äé" + "ãí îäé" + "ã6 Genomskinlighet äé" + "ãí îäé" + "ã7nationell teckenupps{ttningäé" + "ã automatisk igenk{nning äé" + "ãí DE (#$@[\\]^_`{|}~) îäé" + "ãí Sprache/language svenska îäé" + "åæ www.tuxtxt.net x.xx æçé" + "ëìììììììììììììììììììììììììììììê" + }, +/* 0000000000111111111122222222223 */ +/* 0123456789012345678901234567890 */ + { + "àááááááááááááááááááááááááááááâè" + "ã Asetusvalikko äé" + "åææææææææææææææææææææææææææææçé" + "ã1 Suosikit: sivu 111 lis{{ äé" + "ãíîñò äé" + "ã+-? äé" + "ã äé" + "ã2 Tekstikanavan valinta äé" + "ãí search îäé" + "ã äé" + "ã N{ytt|tila äé" + "ã3 Vakiotila 16:9 äé" + "ã4 Teksti/TV 16:9 äé" + "ã äé" + "ã5 Kirkkaus äé" + "ãí îäé" + "ã6 L{pin{kyvyys äé" + "ãí îäé" + "ã7 kansallinen merkist| äé" + "ã automaattinen tunnistus äé" + "ãí DE (#$@[\\]^_`{|}~) îäé" + "ãí Kieli suomi îäé" + "åæ www.tuxtxt.net x.xx æçé" + "ëìììììììììììììììììììììììììììììê" + }, +}; + +const char catchmenutext[][81] = +{ + { " íïðî w{hlen ñò anzeigen " + "0000000011110000000000110000000000000000" }, + { " íïðî select ñò show " + "0000000011110000000000110000000000000000" }, + { " íïðî selectionner ñò montrer " + "0011110000000000000000110000000000000000" }, + { " íïðî kiezen ñò tonen " + "0000000011110000000000110000000000000000" }, + { " íïðî epikoc^ ñò pqobok^ " + "0000000011110000000000110000000000000000" }, + { " íïðîseleziona ñò mostra " + "0000000011110000000000110000000000000000" }, + { " íïðî wybiez ñò wyswietl " + "0000000011110000000000110000000000000000" }, + { " íïðî v{lj ñò visa " + "0000000011110000000000110000000000000000" }, + { " íïðî valitse ñò n{yt{ " + "0000000011110000000000110000000000000000" }, +}; + +const char message_3[][39] = +{ + { "ã suche nach Teletext-Anbietern äé" }, + { "ã searching for teletext Services äé" }, + { "ã recherche des services teletext äé" }, + { "ã zoeken naar teletekst aanbieders äé" }, + { "ã amaf^tgsg voq]ym Teket]nt äé" }, + { "ã attesa opzioni televideo äé" }, + { "ã poszukiwanie sygna}u telegazety äé" }, + { "ã s|ker efter TextTV tj{nster äé" }, + { "ã etsit{{n Teksti-TV -palvelua äé" }, +}; +const char message_3_blank[] = "ã äé"; +const char message_7[][39] = +{ + { "ã kein Teletext auf dem Transponder äé" }, + { "ã no teletext on the transponder äé" }, + { "ã pas de teletext sur le transponderäé" }, + { "ã geen teletekst op de transponder äé" }, + { "ã jal]la Teket]nt ston amaletadot^ äé" }, + { "ã nessun televideo sul trasponder äé" }, + { "ã brak sygna}u na transponderze äé" }, + { "ã ingen TextTV p} denna transponder äé" }, + { "ã Ei Teksti-TV:t{ l{hettimell{ äé" }, +}; +const char message_8[][39] = +{ +/* 00000000001111111111222222222233333333334 */ +/* 01234567890123456789012345678901234567890 */ + { "ã warte auf Empfang von Seite 100 äé" }, + { "ã waiting for reception of page 100 äé" }, + { "ã attentre la réception de page 100 äé" }, + { "ãwachten op ontvangst van pagina 100äé" }, + { "ã amal]my k^xg sek_dar 100 äé" }, + { "ã attesa ricezione pagina 100 äé" }, + { "ã oczekiwanie na stron` 100 äé" }, + { "ã v{ntar p} mottagning av sida 100 äé" }, + { "ã Odotetaan sivua 100 äé" }, +}; +const char message8pagecolumn[] = /* last(!) column of page to show in each language */ +{ + 33, 34, 34, 35, 29, 30, 30, 34, 34 +}; + +enum /* options for charset */ +{ + C_G0P = 0, /* primary G0 */ + C_G0S, /* secondary G0 */ + C_G1C, /* G1 contiguous */ + C_G1S, /* G1 separate */ + C_G2, + C_G3, + C_OFFSET_DRCS = 32 + /* 32..47: 32+subpage# GDRCS (offset/20 in page_char) */ + /* 48..63: 48+subpage# DRCS (offset/20 in page_char) */ +}; + +/* struct for page attributes */ +typedef struct +{ + unsigned char fg :6; /* foreground color */ + unsigned char bg :6; /* background color */ + unsigned char charset :6; /* see enum above */ + unsigned char doubleh :1; /* double height */ + unsigned char doublew :1; /* double width */ + /* ignore at Black Background Color Substitution */ + /* black background set by New Background ($1d) instead of start-of-row default or Black Backgr. ($1c) */ + /* or black background set by level 2.5 extensions */ + unsigned char IgnoreAtBlackBgSubst:1; + unsigned char concealed:1; /* concealed information */ + unsigned char inverted :1; /* colors inverted */ + unsigned char flashing :5; /* flash mode */ + unsigned char diacrit :4; /* diacritical mark */ + unsigned char underline:1; /* Text underlined */ + unsigned char boxwin :1; /* Text boxed/windowed */ + unsigned char setX26 :1; /* Char is set by packet X/26 (no national subset used) */ + unsigned char setG0G2 :7; /* G0+G2 set designation */ +} tstPageAttr; + +enum /* indices in atrtable */ +{ + ATR_WB, /* white on black */ + ATR_PassiveDefault, /* Default for passive objects: white on black, ignore at Black Background Color Substitution */ + ATR_L250, /* line25 */ + ATR_L251, /* line25 */ + ATR_L252, /* line25 */ + ATR_L253, /* line25 */ + ATR_TOPMENU0, /* topmenu */ + ATR_TOPMENU1, /* topmenu */ + ATR_TOPMENU2, /* topmenu */ + ATR_TOPMENU3, /* topmenu */ + ATR_MSG0, /* message */ + ATR_MSG1, /* message */ + ATR_MSG2, /* message */ + ATR_MSG3, /* message */ + ATR_MSGDRM0, /* message */ + ATR_MSGDRM1, /* message */ + ATR_MSGDRM2, /* message */ + ATR_MSGDRM3, /* message */ + ATR_MENUHIL0, /* hilit menu line */ + ATR_MENUHIL1, /* hilit menu line */ + ATR_MENUHIL2, /* hilit menu line */ + ATR_MENU0, /* menu line */ + ATR_MENU1, /* menu line */ + ATR_MENU2, /* menu line */ + ATR_MENU3, /* menu line */ + ATR_MENU4, /* menu line */ + ATR_MENU5, /* menu line */ + ATR_MENU6, /* menu line */ + ATR_CATCHMENU0, /* catch menu line */ + ATR_CATCHMENU1 /* catch menu line */ +}; + +/* define color names */ +enum +{ + black = 0, + red, /* 1 */ + green, /* 2 */ + yellow, /* 3 */ + blue, /* 4 */ + magenta, /* 5 */ + cyan, /* 6 */ + white, /* 7 */ + menu1 = (4*8), + menu2, + menu3, + transp, + transp2, + SIZECOLTABLE +}; + +//const (avoid warnings :<) +tstPageAttr atrtable[] = +{ + { white , black , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_WB */ + { white , black , C_G0P, 0, 0, 1 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_PassiveDefault */ + { white , red , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L250 */ + { black , green , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L251 */ + { black , yellow, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L252 */ + { white , blue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L253 */ + { magenta, black , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU0 */ + { green , black , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU1 */ + { yellow , black , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU2 */ + { cyan , black , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU3 */ + { menu2 , menu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG0 */ + { yellow , menu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG1 */ + { menu2 , transp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG2 */ + { white , menu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG3 */ + { menu2 , menu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM0 */ + { yellow , menu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM1 */ + { menu2 , black , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM2 */ + { white , menu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM3 */ + { menu1 , blue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL0 5a Z */ + { white , blue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL1 58 X */ + { menu2 , transp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL2 9b › */ + { menu2 , menu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU0 ab « */ + { yellow , menu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU1 a4 ¤ */ + { menu2 , transp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU2 9b › */ + { menu2 , menu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU3 cb Ë */ + { cyan , menu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU4 c7 Ç */ + { white , menu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU5 c8 È */ + { white , menu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU6 a8 ¨ */ + { yellow , menu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_CATCHMENU0 a4 ¤ */ + { white , menu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f} /* ATR_CATCHMENU1 a8 ¨ */ +}; +/* buffers */ +unsigned char lcd_backbuffer[120*64 / 8]; +unsigned char page_char[40 * 25]; +tstPageAttr page_atrb[40 * 25]; + +//unsigned short page_atrb[40 * 25]; /* ?????:h:cc:bbbb:ffff -> ?=reserved, h=double height, c=charset (0:G0 / 1:G1c / 2:G1s), b=background, f=foreground */ + + +/* colormap */ +const unsigned short defaultcolors[] = /* 0x0bgr */ +{ + 0x000, 0x00f, 0x0f0, 0x0ff, 0xf00, 0xf0f, 0xff0, 0xfff, + 0x000, 0x007, 0x070, 0x077, 0x700, 0x707, 0x770, 0x777, + 0x50f, 0x07f, 0x7f0, 0xbff, 0xac0, 0x005, 0x256, 0x77c, + 0x333, 0x77f, 0x7f7, 0x7ff, 0xf77, 0xf7f, 0xff7, 0xddd, + 0x420, 0x210, 0x420, 0x000, 0x000 +}; + +/* 32bit colortable */ +unsigned char bgra[][5] = { +"\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", +"\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", +"\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", +"\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", +"\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", +"\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", +"\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", +"\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xFF", +"\0\0\0\xFF", "\0\0\0\xFF", "\0\0\0\xC0", "\0\0\0\x00", +"\0\0\0\x33" }; + +/* old 8bit color table */ +unsigned short rd0[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0x00<<8, 0x00<<8, 0x00<<8, 0, 0 }; +unsigned short gn0[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0x20<<8, 0x10<<8, 0x20<<8, 0, 0 }; +unsigned short bl0[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0x40<<8, 0x20<<8, 0x40<<8, 0, 0 }; +unsigned short tr0[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0x0000 , 0x0000 , 0x0A00 , 0xFFFF, 0x3000 }; +struct fb_cmap colormap_0 = {0, SIZECOLTABLE, rd0, gn0, bl0, tr0}; + +/* tables for color table remapping, first entry (no remapping) skipped, offsets for color index */ +const unsigned char MapTblFG[] = { 0, 0, 8, 8, 16, 16, 16 }; +const unsigned char MapTblBG[] = { 8, 16, 8, 16, 8, 16, 24 }; + + +/* shapes */ +enum +{ + S_END = 0, + S_FHL, /* full horizontal line: y-offset */ + S_FVL, /* full vertical line: x-offset */ + S_BOX, /* rectangle: x-offset, y-offset, width, height */ + S_TRA, /* trapez: x0, y0, l0, x1, y1, l1 */ + S_BTR, /* trapez in bgcolor: x0, y0, l0, x1, y1, l1 */ + S_INV, /* invert */ + S_LNK, /* call other shape: shapenumber */ + S_CHR, /* Character from freetype hibyte, lowbyte */ + S_ADT, /* Character 2F alternating raster */ + S_FLH, /* flip horizontal */ + S_FLV /* flip vertical */ +}; + +/* shape coordinates */ +enum +{ + S_W13 = 5, /* width*1/3 */ + S_W12, /* width*1/2 */ + S_W23, /* width*2/3 */ + S_W11, /* width */ + S_WM3, /* width-3 */ + S_H13, /* height*1/3 */ + S_H12, /* height*1/2 */ + S_H23, /* height*2/3 */ + S_H11, /* height */ + S_NrShCoord +}; + +/* G3 characters */ +unsigned char aG3_20[] = { S_TRA, 0, S_H23, 1, 0, S_H11, S_W12, S_END }; +unsigned char aG3_21[] = { S_TRA, 0, S_H23, 1, 0, S_H11, S_W11, S_END }; +unsigned char aG3_22[] = { S_TRA, 0, S_H12, 1, 0, S_H11, S_W12, S_END }; +unsigned char aG3_23[] = { S_TRA, 0, S_H12, 1, 0, S_H11, S_W11, S_END }; +unsigned char aG3_24[] = { S_TRA, 0, 0, 1, 0, S_H11, S_W12, S_END }; +unsigned char aG3_25[] = { S_TRA, 0, 0, 1, 0, S_H11, S_W11, S_END }; +unsigned char aG3_26[] = { S_INV, S_LNK, 0x66, S_END }; +unsigned char aG3_27[] = { S_INV, S_LNK, 0x67, S_END }; +unsigned char aG3_28[] = { S_INV, S_LNK, 0x68, S_END }; +unsigned char aG3_29[] = { S_INV, S_LNK, 0x69, S_END }; +unsigned char aG3_2a[] = { S_INV, S_LNK, 0x6a, S_END }; +unsigned char aG3_2b[] = { S_INV, S_LNK, 0x6b, S_END }; +unsigned char aG3_2c[] = { S_INV, S_LNK, 0x6c, S_END }; +unsigned char aG3_2d[] = { S_INV, S_LNK, 0x6d, S_END }; +unsigned char aG3_2e[] = { S_BOX, 2, 0, 3, S_H11, S_END }; +unsigned char aG3_2f[] = { S_ADT }; +unsigned char aG3_30[] = { S_LNK, 0x20, S_FLH, S_END }; +unsigned char aG3_31[] = { S_LNK, 0x21, S_FLH, S_END }; +unsigned char aG3_32[] = { S_LNK, 0x22, S_FLH, S_END }; +unsigned char aG3_33[] = { S_LNK, 0x23, S_FLH, S_END }; +unsigned char aG3_34[] = { S_LNK, 0x24, S_FLH, S_END }; +unsigned char aG3_35[] = { S_LNK, 0x25, S_FLH, S_END }; +unsigned char aG3_36[] = { S_INV, S_LNK, 0x76, S_END }; +unsigned char aG3_37[] = { S_INV, S_LNK, 0x77, S_END }; +unsigned char aG3_38[] = { S_INV, S_LNK, 0x78, S_END }; +unsigned char aG3_39[] = { S_INV, S_LNK, 0x79, S_END }; +unsigned char aG3_3a[] = { S_INV, S_LNK, 0x7a, S_END }; +unsigned char aG3_3b[] = { S_INV, S_LNK, 0x7b, S_END }; +unsigned char aG3_3c[] = { S_INV, S_LNK, 0x7c, S_END }; +unsigned char aG3_3d[] = { S_INV, S_LNK, 0x7d, S_END }; +unsigned char aG3_3e[] = { S_LNK, 0x2e, S_FLH, S_END }; +unsigned char aG3_3f[] = { S_BOX, 0, 0, S_W11, S_H11, S_END }; +unsigned char aG3_40[] = { S_BOX, 0, S_H13, S_W11, S_H13, S_LNK, 0x7e, S_END }; +unsigned char aG3_41[] = { S_BOX, 0, S_H13, S_W11, S_H13, S_LNK, 0x7e, S_FLV, S_END }; +unsigned char aG3_42[] = { S_LNK, 0x50, S_BOX, S_W12, S_H13, S_W12, S_H13, S_END }; +unsigned char aG3_43[] = { S_LNK, 0x50, S_BOX, 0, S_H13, S_W12, S_H13, S_END }; +unsigned char aG3_44[] = { S_LNK, 0x48, S_FLV, S_LNK, 0x48, S_END }; +unsigned char aG3_45[] = { S_LNK, 0x44, S_FLH, S_END }; +unsigned char aG3_46[] = { S_LNK, 0x47, S_FLV, S_END }; +unsigned char aG3_47[] = { S_LNK, 0x48, S_FLH, S_LNK, 0x48, S_END }; +unsigned char aG3_48[] = { S_TRA, 0, 0, S_W23, 0, S_H23, 0, S_BTR, 0, 0, S_W13, 0, S_H13, 0, S_END }; +unsigned char aG3_49[] = { S_LNK, 0x48, S_FLH, S_END }; +unsigned char aG3_4a[] = { S_LNK, 0x48, S_FLV, S_END }; +unsigned char aG3_4b[] = { S_LNK, 0x48, S_FLH, S_FLV, S_END }; +unsigned char aG3_4c[] = { S_LNK, 0x50, S_BOX, 0, S_H13, S_W11, S_H13, S_END }; +unsigned char aG3_4d[] = { S_CHR, 0x25, 0xE6 }; +unsigned char aG3_4e[] = { S_CHR, 0x25, 0xCF }; +unsigned char aG3_4f[] = { S_CHR, 0x25, 0xCB }; +unsigned char aG3_50[] = { S_BOX, S_W12, 0, 2, S_H11, S_FLH, S_BOX, S_W12, 0, 2, S_H11,S_END }; +unsigned char aG3_51[] = { S_BOX, 0, S_H12, S_W11, 2, S_FLV, S_BOX, 0, S_H12, S_W11, 2,S_END }; +unsigned char aG3_52[] = { S_LNK, 0x55, S_FLH, S_FLV, S_END }; +unsigned char aG3_53[] = { S_LNK, 0x55, S_FLV, S_END }; +unsigned char aG3_54[] = { S_LNK, 0x55, S_FLH, S_END }; +unsigned char aG3_55[] = { S_LNK, 0x7e, S_FLV, S_BOX, 0, S_H12, S_W12, 2, S_FLV, S_BOX, 0, S_H12, S_W12, 2, S_END }; +unsigned char aG3_56[] = { S_LNK, 0x57, S_FLH, S_END}; +unsigned char aG3_57[] = { S_LNK, 0x55, S_LNK, 0x50 , S_END}; +unsigned char aG3_58[] = { S_LNK, 0x59, S_FLV, S_END}; +unsigned char aG3_59[] = { S_LNK, 0x7e, S_LNK, 0x51 , S_END}; +unsigned char aG3_5a[] = { S_LNK, 0x50, S_LNK, 0x51 , S_END}; +unsigned char aG3_5b[] = { S_CHR, 0x21, 0x92}; +unsigned char aG3_5c[] = { S_CHR, 0x21, 0x90}; +unsigned char aG3_5d[] = { S_CHR, 0x21, 0x91}; +unsigned char aG3_5e[] = { S_CHR, 0x21, 0x93}; +unsigned char aG3_5f[] = { S_CHR, 0x00, 0x20}; +unsigned char aG3_60[] = { S_INV, S_LNK, 0x20, S_END }; +unsigned char aG3_61[] = { S_INV, S_LNK, 0x21, S_END }; +unsigned char aG3_62[] = { S_INV, S_LNK, 0x22, S_END }; +unsigned char aG3_63[] = { S_INV, S_LNK, 0x23, S_END }; +unsigned char aG3_64[] = { S_INV, S_LNK, 0x24, S_END }; +unsigned char aG3_65[] = { S_INV, S_LNK, 0x25, S_END }; +unsigned char aG3_66[] = { S_LNK, 0x20, S_FLV, S_END }; +unsigned char aG3_67[] = { S_LNK, 0x21, S_FLV, S_END }; +unsigned char aG3_68[] = { S_LNK, 0x22, S_FLV, S_END }; +unsigned char aG3_69[] = { S_LNK, 0x23, S_FLV, S_END }; +unsigned char aG3_6a[] = { S_LNK, 0x24, S_FLV, S_END }; +unsigned char aG3_6b[] = { S_BOX, 0, 0, S_W11, S_H13, S_TRA, 0, S_H13, S_W11, 0, S_H23, 1, S_END }; +unsigned char aG3_6c[] = { S_TRA, 0, 0, 1, 0, S_H12, S_W12, S_FLV, S_TRA, 0, 0, 1, 0, S_H12, S_W12, S_BOX, 0, S_H12, S_W12,1, S_END }; +unsigned char aG3_6d[] = { S_TRA, 0, 0, S_W12, S_W12, S_H12, 0, S_FLH, S_TRA, 0, 0, S_W12, S_W12, S_H12, 0, S_END }; +unsigned char aG3_6e[] = { S_CHR, 0x00, 0x20}; +unsigned char aG3_6f[] = { S_CHR, 0x00, 0x20}; +unsigned char aG3_70[] = { S_INV, S_LNK, 0x30, S_END }; +unsigned char aG3_71[] = { S_INV, S_LNK, 0x31, S_END }; +unsigned char aG3_72[] = { S_INV, S_LNK, 0x32, S_END }; +unsigned char aG3_73[] = { S_INV, S_LNK, 0x33, S_END }; +unsigned char aG3_74[] = { S_INV, S_LNK, 0x34, S_END }; +unsigned char aG3_75[] = { S_INV, S_LNK, 0x35, S_END }; +unsigned char aG3_76[] = { S_LNK, 0x66, S_FLH, S_END }; +unsigned char aG3_77[] = { S_LNK, 0x67, S_FLH, S_END }; +unsigned char aG3_78[] = { S_LNK, 0x68, S_FLH, S_END }; +unsigned char aG3_79[] = { S_LNK, 0x69, S_FLH, S_END }; +unsigned char aG3_7a[] = { S_LNK, 0x6a, S_FLH, S_END }; +unsigned char aG3_7b[] = { S_LNK, 0x6b, S_FLH, S_END }; +unsigned char aG3_7c[] = { S_LNK, 0x6c, S_FLH, S_END }; +unsigned char aG3_7d[] = { S_LNK, 0x6d, S_FLV, S_END }; +unsigned char aG3_7e[] = { S_BOX, S_W12, 0, 2, S_H12, S_FLH, S_BOX, S_W12, 0, 2, S_H12, S_END };// help char, not printed directly (only by S_LNK) + +unsigned char *aShapes[] = +{ + aG3_20, aG3_21, aG3_22, aG3_23, aG3_24, aG3_25, aG3_26, aG3_27, aG3_28, aG3_29, aG3_2a, aG3_2b, aG3_2c, aG3_2d, aG3_2e, aG3_2f, + aG3_30, aG3_31, aG3_32, aG3_33, aG3_34, aG3_35, aG3_36, aG3_37, aG3_38, aG3_39, aG3_3a, aG3_3b, aG3_3c, aG3_3d, aG3_3e, aG3_3f, + aG3_40, aG3_41, aG3_42, aG3_43, aG3_44, aG3_45, aG3_46, aG3_47, aG3_48, aG3_49, aG3_4a, aG3_4b, aG3_4c, aG3_4d, aG3_4e, aG3_4f, + aG3_50, aG3_51, aG3_52, aG3_53, aG3_54, aG3_55, aG3_56, aG3_57, aG3_58, aG3_59, aG3_5a, aG3_5b, aG3_5c, aG3_5d, aG3_5e, aG3_5f, + aG3_60, aG3_61, aG3_62, aG3_63, aG3_64, aG3_65, aG3_66, aG3_67, aG3_68, aG3_69, aG3_6a, aG3_6b, aG3_6c, aG3_6d, aG3_6e, aG3_6f, + aG3_70, aG3_71, aG3_72, aG3_73, aG3_74, aG3_75, aG3_76, aG3_77, aG3_78, aG3_79, aG3_7a, aG3_7b, aG3_7c, aG3_7d, aG3_7e +}; + + + + +/* lcd layout */ +const char lcd_layout[] = +{ +#define ____ 0x0 +#define ___X 0x1 +#define __X_ 0x2 +#define __XX 0x3 +#define _X__ 0x4 +#define _X_X 0x5 +#define _XX_ 0x6 +#define _XXX 0x7 +#define X___ 0x8 +#define X__X 0x9 +#define X_X_ 0xA +#define X_XX 0xB +#define XX__ 0xC +#define XX_X 0xD +#define XXX_ 0xE +#define XXXX 0xF + +#define i <<4| + + ____ i _XXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXX_ i ____, + ___X i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i X___, + __XX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XX__ i ____,XXX_ i _X__,_XXX i __X_,__XX i X___,___X i XX__,X___ i XXX_,____ i _XXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XX__, + _XXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,X_XX i XXXX,_X_X i X_XX,X_X_ i XX_X,XX_X i _XXX,XXX_ i X_XX,_XXX i _X_X,XXXX i X_XX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXX_, + _XXX i XXXX,X___ i ____,____ i ____,____ i __XX,X_XX i XXXX,_X_X i X_XX,X_X_ i XX_X,XX_X i _XXX,XXX_ i X_XX,_XXX i _X_X,XXXX i X_XX,X___ i ____,____ i ____,____ i ___X,XXXX i XXX_, + XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,X_XX i XXXX,_X_X i X_XX,X_X_ i XX_X,XX_X i _XXX,XXX_ i X_XX,_XXX i _X_X,XXXX i X_XX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX, + XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XX__ i XX__,XX_X i X_XX,X_X_ i XXXX,XX_X i X__X,X__X i X_XX,XXXX i _XX_,_XX_ i _XXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX, + XXXX i XX__,____ i ____,____ i ____,____ i __XX,XXX_ i XX_X,XX_X i X_XX,X_XX i _XXX,__XX i XX_X,X_XX i XX_X,XX__ i XXXX,_XX_ i XXXX,X___ i ____,____ i ____,____ i ____,__XX i XXXX, + XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXX_ i XX_X,XX_X i X_XX,X_X_ i XXXX,XX_X i XX_X,X_XX i X_XX,XXXX i _XXX,_XX_ i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX, + XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXX_ i XX_X,XX_X i X_XX,X_X_ i XX_X,XX_X i XX_X,X_XX i X_XX,_XXX i _XXX,_XX_ i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX, + XXX_ i ____,____ i ____,____ i ____,____ i __XX,XXX_ i XX_X,XX_X i XXXX,X_X_ i XX_X,XX_X i XX_X,X_XX i X_XX,_XXX i _XXX,_XX_ i XXXX,X___ i ____,____ i ____,____ i ____,____ i _XXX, + XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXX_ i XX_X,XX_X i XXXX,X_X_ i XX_X,XX_X i XX_X,X_XX i X_XX,_XXX i _XXX,_XX_ i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX, + XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i __XX,XXX_ i ____,_XXX i __X_,__XX i XXX_,_XXX i XX__,X___ i XXXX,X__X i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX, + XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX, + XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i XX__,_XXX i XXX_,__XX i ___X,XXXX i X___,XX__ i _XXX,XXX_ i __XX,____ i ___X,X___ i XXXX,XX__ i _XX_,__XX i XXXX,___X i XXXX,X___ i XX_X,XX__ i _XXX,XXX_ i __XX,XXXX i ___X, + X__X i __X_,X___ i ___X,_X__ i X_X_,____ i _X_X,__X_ i X___,___X i _X__,X___ i __X_,_X_X i ____,__X_ i X__X,_X__ i ____,X_X_ i ____,_X_X i __X_,__X_ i X___,___X i _X__,____ i X__X, + X__X i __X_,X___ i ___X,_X__ i X_X_,____ i _X_X,__X_ i X___,___X i _X__,X___ i __X_,_X_X i ____,__X_ i X__X,_X__ i ____,X_X_ i ____,_X_X i __X_,__X_ i X___,___X i _X__,____ i X__X, + X__X i __X_,X___ i ___X,_X__ i X_X_,____ i _X_X,__X_ i X___,___X i _X__,X___ i __X_,_X_X i ____,__X_ i X__X,_X__ i ____,X_X_ i ____,_X_X i __X_,__X_ i X___,___X i _X__,____ i X__X, + X__X i __X_,X__X i ___X,_X__ i X__X,X__X i X__X,__X_ i X__X,___X i _X__,X___ i __X_,_X_X i __XX,XX__ i X__X,_X__ i XXXX,__X_ i _X__,_X_X i __X_,__X_ i X__X,___X i _X__,XXXX i ___X, + X__X i __X_,X__X i ___X,_X__ i X___,X__X i ___X,__X_ i X___,___X i _X__,X___ i __X_,_X_X i ____,__X_ i X__X,_X__ i ____,X_X_ i ___X,X__X i __X_,__X_ i X__X,___X i _X__,X___ i X__X, + X__X i __X_,X__X i ___X,_X__ i X___,X__X i ___X,__X_ i X___,___X i _X__,X___ i __X_,_X_X i ____,__X_ i X__X,_X__ i ____,X_X_ i ____,_X_X i __X_,__X_ i X__X,___X i _X__,X___ i X__X, + X__X i __X_,X__X i ___X,_X__ i X___,X__X i ___X,__X_ i X__X,___X i _X__,XXXX i __X_,_X__ i XXX_,__X_ i X__X,_X__ i XXXX,__X_ i _X__,_X_X i __X_,__X_ i X__X,___X i _X__,X___ i X__X, + X__X i __X_,X__X i ___X,_X__ i X___,X__X i ___X,__X_ i X__X,___X i _X__,____ i X_X_,_X_X i ____,__X_ i X__X,_X__ i ____,X_X_ i _X__,_X_X i ____,__X_ i X__X,___X i _X__,____ i X__X, + X__X i __X_,X__X i ___X,_X__ i X___,X__X i ___X,__X_ i X__X,___X i _X__,____ i X_X_,_X_X i ____,__X_ i X__X,_X__ i ____,X_X_ i _X__,_X_X i ____,__X_ i X__X,___X i _X__,____ i X__X, + X___ i XX__,XXX_ i XXXX,__XX i ____,_XX_ i ____,XX__ i _XX_,XXX_ i __XX,XXXX i ___X,X___ i XXXX,XX__ i _XX_,__XX i XXXX,___X i X_XX,X___ i XXXX,XX__ i _XX_,XXX_ i __XX,XXXX i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,XXXX i XXXX,X___ i XXXX,XX__ i _XXX,XXXX i XX__,_XXX i XXX_,__XX i XXXX,___X i XXXX,X___ i ____,__XX i XXXX,___X i X___,XXXX i XX__,_XXX i XXX_,__XX i XXXX,____ i ___X, + X___ i ___X,____ i ____,_X_X i ____,__X_ i X___,____ i __X_,X___ i ___X,_X__ i ____,X_X_ i ____,_X__ i ____,_X__ i ____,X_X_ i _X_X,____ i __X_,X___ i ___X,_X__ i ____,X___ i ___X, + X___ i ___X,____ i ____,_X_X i ____,__X_ i X___,____ i __X_,X___ i ___X,_X__ i ____,X_X_ i ____,_X__ i ____,_X__ i ____,X_X_ i _X_X,____ i __X_,X___ i ___X,_X__ i ____,X___ i ___X, + X___ i ___X,____ i ____,_X_X i ____,__X_ i X___,____ i __X_,X___ i ___X,_X__ i ____,X_X_ i ____,_X__ i ____,_X__ i XX__,X_X_ i _X_X,____ i __X_,X___ i ___X,_X__ i ____,X___ i ___X, + X___ i ___X,__X_ i __X_,_X_X i __X_,__X_ i X__X,___X i __X_,X__X i XXX_,_X__ i X___,X__X i X__X,X___ i ____,_X__ i ____,X_X_ i _X__,XX__ i XX__,_XX_ i _XX_,_X__ i XXXX,____ i ___X, + X___ i ___X,__X_ i __X_,_X_X i __X_,__X_ i X__X,___X i __X_,X___ i ___X,_X__ i X___,X___ i X__X,____ i ____,_X__ i __XX,__X_ i _X__,_X__ i X___,__X_ i _X__,_X__ i ____,X___ i ___X, + X___ i ___X,__X_ i __X_,_X_X i __X_,__X_ i X__X,___X i __X_,X___ i ___X,_X__ i X___,X___ i X__X,____ i ____,_X__ i ____,X_X_ i _X__,_X__ i X___,__X_ i _X__,_X__ i ____,X___ i ___X, + X___ i ___X,__X_ i __X_,_X_X i __X_,__X_ i X__X,___X i __X_,X__X i XXX_,_X__ i X___,X___ i X__X,____ i ____,_X__ i XX__,X_X_ i _X__,_X__ i X___,__X_ i _X__,_X__ i XXXX,____ i ___X, + X___ i ___X,__X_ i __X_,_X_X i ____,__X_ i X__X,___X i __X_,X___ i ___X,_X__ i X___,X___ i X__X,____ i ____,_X__ i ____,X_X_ i _X__,_X__ i X___,__X_ i _X__,_X__ i ____,X___ i ___X, + X___ i ___X,__X_ i __X_,_X_X i ____,__X_ i X__X,___X i __X_,X___ i ___X,_X__ i X___,X___ i X__X,____ i ____,_X__ i ____,X_X_ i _X__,_X__ i X___,__X_ i _X__,_X__ i ____,X___ i ___X, + X___ i ____,XX_X i XX_X,X___ i XXXX,XX__ i _XX_,XXX_ i XX__,_XXX i XXX_,__XX i _XXX,____ i _XX_,____ i ____,__XX i XXXX,___X i X___,__XX i ____,___X i X___,__XX i XXXX,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + X___ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ___X, + _X__ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i __X_, + _X__ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i __X_, + __X_ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i _X__, + ___X i X___,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,____ i ____,___X i X___, + ____ i _XXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXXX i XXXX,XXX_ i ____, + +#undef i +}; + +/* lcd digits */ +const char lcd_digits[] = +{ + 0,1,1,1,1,1,1,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,1,1,0,0,0,1, + 1,0,0,0,1,1,0,0,0,1, + 1,0,0,0,1,1,0,0,0,1, + 1,0,0,0,1,1,0,0,0,1, + 1,0,0,0,1,1,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,1,1, + 0,1,1,1,1,1,1,1,1,0, + + 0,0,0,1,1,1,1,0,0,0, + 0,0,1,1,0,0,1,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,1,0,0,1,1,0,0, + 0,0,0,1,1,1,1,0,0,0, + + 0,1,1,1,1,1,1,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 0,1,1,1,1,1,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,1,1, + 1,0,0,0,0,1,1,1,1,0, + 1,0,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,1,1, + 0,1,1,1,1,1,1,1,1,0, + + 0,1,1,1,1,1,1,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 0,1,1,1,1,1,0,0,0,1, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 0,1,1,1,1,1,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,1,1, + 0,1,1,1,1,1,1,1,1,0, + + 0,1,1,1,0,1,1,1,1,0, + 1,1,0,1,1,1,0,0,1,1, + 1,0,0,0,1,0,0,0,0,1, + 1,0,0,0,1,0,0,0,0,1, + 1,0,0,0,1,0,0,0,0,1, + 1,0,0,0,1,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 0,1,1,1,1,0,0,0,0,1, + 0,0,0,0,1,0,0,0,0,1, + 0,0,0,0,1,0,0,0,0,1, + 0,0,0,0,1,0,0,0,0,1, + 0,0,0,0,1,1,0,0,1,1, + 0,0,0,0,0,1,1,1,1,0, + + 0,1,1,1,1,1,1,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,1,1, + 1,0,0,0,0,1,1,1,1,0, + 1,0,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 0,1,1,1,1,1,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,1,1, + 0,1,1,1,1,1,1,1,1,0, + + 0,1,1,1,1,1,1,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,1,1, + 1,0,0,0,0,1,1,1,1,0, + 1,0,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,1,1,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,1,1, + 0,1,1,1,1,1,1,1,1,0, + + 0,1,1,1,1,1,1,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 0,1,1,1,1,0,0,0,0,1, + 0,0,0,0,1,0,0,0,0,1, + 0,0,0,0,1,0,0,0,0,1, + 0,0,0,0,1,0,0,0,0,1, + 0,0,0,0,1,0,0,0,0,1, + 0,0,0,0,1,0,0,0,0,1, + 0,0,0,0,1,0,0,0,0,1, + 0,0,0,0,1,0,0,0,0,1, + 0,0,0,0,1,1,0,0,1,1, + 0,0,0,0,0,1,1,1,1,0, + + 0,1,1,1,1,1,1,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,1,1,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,1,1, + 0,1,1,0,0,0,0,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,1,1,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,1,1, + 0,1,1,1,1,1,1,1,1,0, + + 0,1,1,1,1,1,1,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,1,1,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 0,1,1,1,1,0,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,1,1, + 0,1,1,1,1,1,1,1,1,0, + + /* 10: - */ + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,1,1,0,0, + 0,1,0,0,0,0,0,0,1,0, + 0,1,0,0,0,0,0,0,1,0, + 0,1,0,0,0,0,0,0,1,0, + 0,0,1,1,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + + /* 11: / */ + 0,0,0,0,1,1,1,1,0,0, + 0,0,0,1,0,0,0,0,1,0, + 0,0,0,1,0,0,0,0,1,0, + 0,0,0,1,0,0,0,0,1,0, + 0,0,0,1,0,0,0,0,1,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0, + 0,1,0,0,0,0,1,0,0,0, + 0,1,0,0,0,0,1,0,0,0, + 0,1,0,0,0,0,1,0,0,0, + 0,1,0,0,0,0,1,0,0,0, + 0,0,1,1,1,1,0,0,0,0, + + /* 12: ? */ + 0,1,1,1,1,1,1,1,1,0, + 1,1,0,0,0,0,0,0,1,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 0,1,1,1,1,1,0,0,0,1, + 1,1,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,1,1, + 1,1,1,1,1,1,1,1,1,0, + 1,0,0,0,0,1,0,0,0,0, + 1,0,0,0,0,1,0,0,0,0, + 1,0,0,0,0,1,0,0,0,0, + 1,1,0,0,1,1,0,0,0,0, + 0,1,1,1,1,0,0,0,0,0, + + /* 13: " " */ + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, +}; + +/* functions */ +void ConfigMenu(int Init); +void CleanUp(); +void PageInput(int Number); +void ColorKey(int); +void PageCatching(); +void CatchNextPage(int, int); +void GetNextPageOne(int up); +void GetNextSubPage(int offset); +void SwitchZoomMode(); +void SwitchScreenMode(int newscreenmode); +void SwitchTranspMode(); +void SwitchHintMode(); +void CreateLine25(); +void CopyBB2FB(); +void RenderCatchedPage(); +void RenderCharFB(int Char, tstPageAttr *Attribute); +void RenderCharBB(int Char, tstPageAttr *Attribute); +void RenderCharLCD(int Digit, int XPos, int YPos); +void RenderMessage(int Message); +void RenderPage(); +void DecodePage(); +void UpdateLCD(); +int Init(); +int GetNationalSubset(char *country_code); +int GetTeletextPIDs(); +int GetRCCode(); +int eval_triplet(int iOData, tstCachedPage *pstCachedPage, + unsigned char *pAPx, unsigned char *pAPy, + unsigned char *pAPx0, unsigned char *pAPy0, + unsigned char *drcssubp, unsigned char *gdrcssubp, + signed char *endcol, tstPageAttr *attrPassive, unsigned char* pagedata); +void eval_object(int iONr, tstCachedPage *pstCachedPage, + unsigned char *pAPx, unsigned char *pAPy, + unsigned char *pAPx0, unsigned char *pAPy0, + tObjType ObjType, unsigned char* pagedata); + + +#endif diff --git a/lib/libtuxtxt/tuxtxt_common.h b/lib/libtuxtxt/tuxtxt_common.h new file mode 100644 index 000000000..d7a346ef7 --- /dev/null +++ b/lib/libtuxtxt/tuxtxt_common.h @@ -0,0 +1,1098 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#if TUXTXT_COMPRESS == 1 +#include +#endif + +#include + +tuxtxt_cache_struct tuxtxt_cache; +static pthread_mutex_t tuxtxt_cache_lock = PTHREAD_MUTEX_INITIALIZER; +int tuxtxt_get_zipsize(int p,int sp) +{ + tstCachedPage* pg = tuxtxt_cache.astCachetable[p][sp]; + if (!pg) return 0; +#if TUXTXT_COMPRESS == 1 + return pg->ziplen; +#elif TUXTXT_COMPRESS == 2 + pthread_mutex_lock(&tuxtxt_cache_lock); + int zipsize = 0,i,j; + for (i = 0; i < 23*5; i++) + for (j = 0; j < 8; j++) + zipsize += pg->bitmask[i]>>j & 0x01; + + zipsize+=23*5;//bitmask + pthread_mutex_unlock(&tuxtxt_cache_lock); + return zipsize; +#else + return 23*40; +#endif +} +void tuxtxt_compress_page(int p, int sp, unsigned char* buffer) +{ + pthread_mutex_lock(&tuxtxt_cache_lock); + tstCachedPage* pg = tuxtxt_cache.astCachetable[p][sp]; + if (!pg) + { + printf("tuxtxt: trying to compress a not allocated page!!\n"); + pthread_mutex_unlock(&tuxtxt_cache_lock); + return; + } + +#if TUXTXT_COMPRESS == 1 + unsigned char pagecompressed[23*40]; + uLongf comprlen = 23*40; + if (compress2(pagecompressed,&comprlen,buffer,23*40,Z_BEST_SPEED) == Z_OK) + { + if (pg->pData) free(pg->pData);//realloc(pg->pData,j); realloc scheint nicht richtig zu funktionieren? + pg->pData = malloc(comprlen); + pg->ziplen = 0; + if (pg->pData) + { + pg->ziplen = comprlen; + memcpy(pg->pData,pagecompressed,comprlen); + } + } +#elif TUXTXT_COMPRESS == 2 + int i,j=0; + unsigned char cbuf[23*40]; + memset(pg->bitmask,0,sizeof(pg->bitmask)); + for (i = 0; i < 23*40; i++) + { + if (i && buffer[i] == buffer[i-1]) + continue; + pg->bitmask[i>>3] |= 0x80>>(i&0x07); + cbuf[j++]=buffer[i]; + } + if (pg->pData) free(pg->pData);//realloc(pg->pData,j); realloc scheint nicht richtig zu funktionieren? + pg->pData = (unsigned char*)malloc(j); + if (pg->pData) + { + memcpy(pg->pData,cbuf,j); + } + else + memset(pg->bitmask,0,sizeof(pg->bitmask)); + +#else + //if (pg->pData) + memcpy(pg->data,buffer,23*40); +#endif + pthread_mutex_unlock(&tuxtxt_cache_lock); + +} +void tuxtxt_decompress_page(int p, int sp, unsigned char* buffer) +{ + pthread_mutex_lock(&tuxtxt_cache_lock); + tstCachedPage* pg = tuxtxt_cache.astCachetable[p][sp]; + memset(buffer,' ',23*40); + if (!pg) + { + printf("tuxtxt: trying to decompress a not allocated page!!\n"); + pthread_mutex_unlock(&tuxtxt_cache_lock); + return; + } +#if TUXTXT_COMPRESS == 1 + if (pg->pData) + { + if (pg->ziplen) + { + uLongf comprlen = 23*40; + uncompress(buffer,&comprlen,pg->pData,pg->ziplen); + } + +#elif TUXTXT_COMPRESS == 2 + if (pg->pData) + { + int i,j=0; + char c=0x20; + for (i = 0; i < 23*40; i++) + { + if (pg->bitmask[i>>3] & 0x80>>(i&0x07)) + c = pg->pData[j++]; + buffer[i] = c; + } +#else + { + memcpy(buffer,pg->data,23*40); +#endif + } + pthread_mutex_unlock(&tuxtxt_cache_lock); +} +void tuxtxt_next_dec(int *i) /* skip to next decimal */ +{ + (*i)++; + + if ((*i & 0x0F) > 0x09) + *i += 0x06; + + if ((*i & 0xF0) > 0x90) + *i += 0x60; + + if (*i > 0x899) + *i = 0x100; +} + +void tuxtxt_prev_dec(int *i) /* counting down */ +{ + (*i)--; + + if ((*i & 0x0F) > 0x09) + *i -= 0x06; + + if ((*i & 0xF0) > 0x90) + *i -= 0x60; + + if (*i < 0x100) + *i = 0x899; +} + +int tuxtxt_is_dec(int i) +{ + return ((i & 0x00F) <= 9) && ((i & 0x0F0) <= 0x90); +} + +int tuxtxt_next_hex(int i) /* return next existing non-decimal page number */ +{ + int startpage = i; + if (startpage < 0x100) + startpage = 0x100; + + do + { + i++; + if (i > 0x8FF) + i = 0x100; + if (i == startpage) + break; + } while ((tuxtxt_cache.subpagetable[i] == 0xFF) || tuxtxt_is_dec(i)); + return i; +} +/* + * TOP-Text + * Info entnommen aus videotext-0.6.19991029, + * Copyright (c) 1994-96 Martin Buck + */ +void tuxtxt_decode_btt() +{ + /* basic top table */ + int i, current, b1, b2, b3, b4; + unsigned char btt[23*40]; + + if (tuxtxt_cache.subpagetable[0x1f0] == 0xff || 0 == tuxtxt_cache.astCachetable[0x1f0][tuxtxt_cache.subpagetable[0x1f0]]) /* not yet received */ + return; + tuxtxt_decompress_page(0x1f0,tuxtxt_cache.subpagetable[0x1f0],btt); + if (btt[799] == ' ') /* not completely received or error */ + return; + + current = 0x100; + for (i = 0; i < 800; i++) + { + b1 = btt[i]; + if (b1 == ' ') + b1 = 0; + else + { + b1 = dehamming[b1]; + if (b1 == 0xFF) /* hamming error in btt */ + { + btt[799] = ' '; /* mark btt as not received */ + return; + } + } + tuxtxt_cache.basictop[current] = b1; + tuxtxt_next_dec(¤t); + } + /* page linking table */ + tuxtxt_cache.maxadippg = -1; /* rebuild table of adip pages */ + for (i = 0; i < 10; i++) + { + b1 = dehamming[btt[800 + 8*i +0]]; + + if (b1 == 0xE) + continue; /* unused */ + else if (b1 == 0xF) + break; /* end */ + + b4 = dehamming[btt[800 + 8*i +7]]; + + if (b4 != 2) /* only adip, ignore multipage (1) */ + continue; + + b2 = dehamming[btt[800 + 8*i +1]]; + b3 = dehamming[btt[800 + 8*i +2]]; + + if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF) + { + printf("TuxTxt \n", i); + btt[799] = ' '; /* mark btt as not received */ + return; + } + + b1 = b1<<8 | b2<<4 | b3; /* page number */ + tuxtxt_cache.adippg[++tuxtxt_cache.maxadippg] = b1; + } +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + tuxtxt_cache.bttok = 1; +} + +void tuxtxt_decode_adip() /* additional information table */ +{ + int i, p, j, b1, b2, b3, charfound; + unsigned char padip[23*40]; + + for (i = 0; i <= tuxtxt_cache.maxadippg; i++) + { + p = tuxtxt_cache.adippg[i]; + if (!p || tuxtxt_cache.subpagetable[p] == 0xff || 0 == tuxtxt_cache.astCachetable[p][tuxtxt_cache.subpagetable[p]]) /* not cached (avoid segfault) */ + continue; + + tuxtxt_decompress_page(p,tuxtxt_cache.subpagetable[p],padip); + for (j = 0; j < 44; j++) + { + b1 = dehamming[padip[20*j+0]]; + if (b1 == 0xE) + continue; /* unused */ + + if (b1 == 0xF) + break; /* end */ + + b2 = dehamming[padip[20*j+1]]; + b3 = dehamming[padip[20*j+2]]; + + if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF) + { + printf("TuxTxt \n", p, j, + padip[20*j+0], + padip[20*j+1], + padip[20*j+2], + b1, b2, b3 + ); + return; + } + + if (b1>8 || b2>9 || b3>9) /* ignore extries with invalid or hex page numbers */ + { + continue; + } + + b1 = b1<<8 | b2<<4 | b3; /* page number */ + charfound = 0; /* flag: no printable char found */ + + for (b2 = 11; b2 >= 0; b2--) + { + b3 = deparity[padip[20*j + 8 + b2]]; + if (b3 < ' ') + b3 = ' '; + + if (b3 == ' ' && !charfound) + tuxtxt_cache.adip[b1][b2] = '\0'; + else + { + tuxtxt_cache.adip[b1][b2] = b3; + charfound = 1; + } + } + } /* next link j */ + tuxtxt_cache.adippg[i] = 0; /* completely decoded: clear entry */ +#if TUXTXT_DEBUG + printf("TuxTxt \n", p); +#endif + } /* next adip page i */ + + while (!tuxtxt_cache.adippg[tuxtxt_cache.maxadippg] && (tuxtxt_cache.maxadippg >= 0)) /* and shrink table */ + tuxtxt_cache.maxadippg--; +} +/****************************************************************************** + * GetSubPage * + ******************************************************************************/ +int tuxtxt_GetSubPage(int page, int subpage, int offset) +{ + int loop; + + + for (loop = subpage + offset; loop != subpage; loop += offset) + { + if (loop < 0) + loop = 0x79; + else if (loop > 0x79) + loop = 0; + if (loop == subpage) + break; + + if (tuxtxt_cache.astCachetable[page][loop]) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n", page, subpage); +#endif + return loop; + } + } + +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + return subpage; +} + +/****************************************************************************** + * clear_cache * + ******************************************************************************/ + +void tuxtxt_clear_cache() +{ + pthread_mutex_lock(&tuxtxt_cache_lock); + int clear_page, clear_subpage, d26; + tuxtxt_cache.maxadippg = -1; + tuxtxt_cache.bttok = 0; + tuxtxt_cache.cached_pages = 0; + tuxtxt_cache.page_receiving = -1; + tuxtxt_cache.vtxtpid = -1; + memset(&tuxtxt_cache.subpagetable, 0xFF, sizeof(tuxtxt_cache.subpagetable)); + memset(&tuxtxt_cache.basictop, 0, sizeof(tuxtxt_cache.basictop)); + memset(&tuxtxt_cache.adip, 0, sizeof(tuxtxt_cache.adip)); + memset(&tuxtxt_cache.flofpages, 0 , sizeof(tuxtxt_cache.flofpages)); + memset(&tuxtxt_cache.timestring, 0x20, 8); + unsigned char magazine; + for (magazine = 1; magazine < 9; magazine++) + { + tuxtxt_cache.current_page [magazine] = -1; + tuxtxt_cache.current_subpage [magazine] = -1; + } + + for (clear_page = 0; clear_page < 0x900; clear_page++) + for (clear_subpage = 0; clear_subpage < 0x80; clear_subpage++) + if (tuxtxt_cache.astCachetable[clear_page][clear_subpage]) + { + tstPageinfo *p = &(tuxtxt_cache.astCachetable[clear_page][clear_subpage]->pageinfo); + if (p->p24) + free(p->p24); + if (p->ext) + { + if (p->ext->p27) + free(p->ext->p27); + for (d26=0; d26 < 16; d26++) + if (p->ext->p26[d26]) + free(p->ext->p26[d26]); + free(p->ext); + } +#if TUXTXT_COMPRESS >0 + if (tuxtxt_cache.astCachetable[clear_page][clear_subpage]->pData) + free(tuxtxt_cache.astCachetable[clear_page][clear_subpage]->pData); +#endif + free(tuxtxt_cache.astCachetable[clear_page][clear_subpage]); + tuxtxt_cache.astCachetable[clear_page][clear_subpage] = 0; + } + for (clear_page = 0; clear_page < 9; clear_page++) + { + if (tuxtxt_cache.astP29[clear_page]) + { + if (tuxtxt_cache.astP29[clear_page]->p27) + free(tuxtxt_cache.astP29[clear_page]->p27); + for (d26=0; d26 < 16; d26++) + if (tuxtxt_cache.astP29[clear_page]->p26[d26]) + free(tuxtxt_cache.astP29[clear_page]->p26[d26]); + free(tuxtxt_cache.astP29[clear_page]); + tuxtxt_cache.astP29[clear_page] = 0; + } + tuxtxt_cache.current_page [clear_page] = -1; + tuxtxt_cache.current_subpage [clear_page] = -1; + } + memset(&tuxtxt_cache.astCachetable, 0, sizeof(tuxtxt_cache.astCachetable)); + memset(&tuxtxt_cache.astP29, 0, sizeof(tuxtxt_cache.astP29)); +#if TUXTXT_DEBUG + printf("TuxTxt cache cleared\n"); +#endif + pthread_mutex_unlock(&tuxtxt_cache_lock); +} +/****************************************************************************** + * init_demuxer * + ******************************************************************************/ +static cDemux * dmx = NULL; +int tuxtxt_init_demuxer() +{ + + if(dmx == NULL) { + dmx = new cDemux(0); + dmx->Open(DMX_PES_CHANNEL, NULL, 2* 3008 * 62 /*64*1024*/); + } +#if TUXTXT_DEBUG + printf("TuxTxt: initialized\n"); +#endif + /* init successfull */ + + return 1; +} +/****************************************************************************** + * CacheThread support functions * + ******************************************************************************/ + +void tuxtxt_decode_p2829(unsigned char *vtxt_row, tstExtData **ptExtData) +{ + int bitsleft, colorindex; + unsigned char *p; + int t1 = deh24(&vtxt_row[7-4]); + int t2 = deh24(&vtxt_row[10-4]); + + if (t1 < 0 || t2 < 0) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + return; + } + + if (!(*ptExtData)) + (*ptExtData) = (tstExtData*)calloc(1, sizeof(tstExtData)); + if (!(*ptExtData)) + return; + + (*ptExtData)->p28Received = 1; + (*ptExtData)->DefaultCharset = (t1>>7) & 0x7f; + (*ptExtData)->SecondCharset = ((t1>>14) & 0x0f) | ((t2<<4) & 0x70); + (*ptExtData)->LSP = !!(t2 & 0x08); + (*ptExtData)->RSP = !!(t2 & 0x10); + (*ptExtData)->SPL25 = !!(t2 & 0x20); + (*ptExtData)->LSPColumns = (t2>>6) & 0x0f; + + bitsleft = 8; /* # of bits not evaluated in val */ + t2 >>= 10; /* current data */ + p = &vtxt_row[13-4]; /* pointer to next data triplet */ + for (colorindex = 0; colorindex < 16; colorindex++) + { + if (bitsleft < 12) + { + t2 |= deh24(p) << bitsleft; + if (t2 < 0) /* hamming error */ + break; + p += 3; + bitsleft += 18; + } + (*ptExtData)->bgr[colorindex] = t2 & 0x0fff; + bitsleft -= 12; + t2 >>= 12; + } + if (t2 < 0 || bitsleft != 14) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n", t2, bitsleft); +#endif + (*ptExtData)->p28Received = 0; + return; + } + (*ptExtData)->DefScreenColor = t2 & 0x1f; + t2 >>= 5; + (*ptExtData)->DefRowColor = t2 & 0x1f; + (*ptExtData)->BlackBgSubst = !!(t2 & 0x20); + t2 >>= 6; + (*ptExtData)->ColorTableRemapping = t2 & 0x07; +} + +void tuxtxt_erase_page(int magazine) +{ + pthread_mutex_lock(&tuxtxt_cache_lock); + tstCachedPage* pg = tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]]; + if (pg) + { + memset(&(pg->pageinfo), 0, sizeof(tstPageinfo)); /* struct pageinfo */ + memset(pg->p0, ' ', 24); +#if TUXTXT_COMPRESS == 1 + if (pg->pData) {free(pg->pData); pg->pData = NULL;} +#elif TUXTXT_COMPRESS == 2 + memset(pg->bitmask, 0, 23*5); +#else + memset(pg->data, ' ', 23*40); +#endif + } + pthread_mutex_unlock(&tuxtxt_cache_lock); +} + +void tuxtxt_allocate_cache(int magazine) +{ + /* check cachetable and allocate memory if needed */ + if (tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]] == 0) + { + + tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]] = (tstCachedPage*) malloc(sizeof(tstCachedPage)); + if (tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]] ) + { +#if TUXTXT_COMPRESS >0 + tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]]->pData = 0; +#endif + tuxtxt_erase_page(magazine); + tuxtxt_cache.cached_pages++; + } + } +} +/****************************************************************************** + * CacheThread * + ******************************************************************************/ +//#define TUXTXT_DEBUG 1 //FIXME +static int stop_cache = 0; +void *tuxtxt_CacheThread(void *arg) +{ + const unsigned char rev_lut[32] = { + 0x00,0x08,0x04,0x0c, /* upper nibble */ + 0x02,0x0a,0x06,0x0e, + 0x01,0x09,0x05,0x0d, + 0x03,0x0b,0x07,0x0f, + 0x00,0x80,0x40,0xc0, /* lower nibble */ + 0x20,0xa0,0x60,0xe0, + 0x10,0x90,0x50,0xd0, + 0x30,0xb0,0x70,0xf0 }; + unsigned char pes_packet[184*20]; + unsigned char vtxt_row[42]; + int line, byte/*, bit*/; + int b1, b2, b3, b4; + int packet_number; + int doupdate=0; + unsigned char magazine = 0xff; + unsigned char pagedata[9][23*40]; + tstPageinfo *pageinfo_thread; + + printf("TuxTxt running thread...(%03x)\n",tuxtxt_cache.vtxtpid); + tuxtxt_cache.receiving = 1; + nice(3); + while (!stop_cache) + { + /* check stopsignal */ + pthread_testcancel(); + + if (!tuxtxt_cache.receiving) continue; + + /* read packet */ + ssize_t readcnt; + + readcnt = dmx->Read(pes_packet, sizeof (pes_packet), 1000); + //if (readcnt != sizeof(pes_packet)) + if ((readcnt <= 0) || (readcnt % 184)) + { +#if TUXTXT_DEBUG + if(readcnt > 0) + printf ("TuxTxt: readerror: %d\n", readcnt); +#endif + continue; + } + + /* analyze it */ + for (line = 0; line < readcnt/0x2e /*4*/; line++) + { + unsigned char *vtx_rowbyte = &pes_packet[line*0x2e]; + if ((vtx_rowbyte[1] == 0x2C) && (vtx_rowbyte[0] == 0x02 || vtx_rowbyte[0] == 0x03)) + { + /* clear rowbuffer */ + /* convert row from lsb to msb (begin with magazin number) */ + for (byte = 4; byte < 46; byte++) + { + unsigned char upper,lower; + upper = (vtx_rowbyte[byte] >> 4) & 0xf; + lower = vtx_rowbyte[byte] & 0xf; + vtxt_row[byte-4] = (rev_lut[upper]) | (rev_lut[lower+16]); + } + + /* get packet number */ + b1 = dehamming[vtxt_row[0]]; + b2 = dehamming[vtxt_row[1]]; + + if (b1 == 0xFF || b2 == 0xFF) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + continue; + } + + b1 &= 8; + + packet_number = b1>>3 | b2<<1; + + /* get magazine number */ + magazine = dehamming[vtxt_row[0]] & 7; + if (!magazine) magazine = 8; + + if (packet_number == 0 && tuxtxt_cache.current_page[magazine] != -1 && tuxtxt_cache.current_subpage[magazine] != -1) + tuxtxt_compress_page(tuxtxt_cache.current_page[magazine],tuxtxt_cache.current_subpage[magazine],pagedata[magazine]); + +//printf("********************** receiving packet %d page %03x subpage %02x\n",packet_number, tuxtxt_cache.current_page[magazine],tuxtxt_cache.current_subpage[magazine]);//FIXME + + /* analyze row */ + if (packet_number == 0) + { + /* get pagenumber */ + b2 = dehamming[vtxt_row[3]]; + b3 = dehamming[vtxt_row[2]]; + + if (b2 == 0xFF || b3 == 0xFF) + { + tuxtxt_cache.current_page[magazine] = tuxtxt_cache.page_receiving = -1; +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + continue; + } + + tuxtxt_cache.current_page[magazine] = tuxtxt_cache.page_receiving = magazine<<8 | b2<<4 | b3; + + if (b2 == 0x0f && b3 == 0x0f) + { + tuxtxt_cache.current_subpage[magazine] = -1; /* ?ff: ignore data transmissions */ + continue; + } + + /* get subpagenumber */ + b1 = dehamming[vtxt_row[7]]; + b2 = dehamming[vtxt_row[6]]; + b3 = dehamming[vtxt_row[5]]; + b4 = dehamming[vtxt_row[4]]; + + if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF || b4 == 0xFF) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + tuxtxt_cache.current_subpage[magazine] = -1; + continue; + } + + b1 &= 3; + b3 &= 7; + + if (tuxtxt_is_dec(tuxtxt_cache.page_receiving)) /* ignore other subpage bits for hex pages */ + { +#if 0 /* ? */ + if (b1 != 0 || b2 != 0) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n", tuxtxt_cache.page_receiving, b1, b2, b3, b4); +#endif + tuxtxt_cache.current_subpage[magazine] = -1; + continue; + } + else +#endif + tuxtxt_cache.current_subpage[magazine] = b3<<4 | b4; + } + else + tuxtxt_cache.current_subpage[magazine] = b4; /* max 16 subpages for hex pages */ + + /* store current subpage for this page */ + tuxtxt_cache.subpagetable[tuxtxt_cache.current_page[magazine]] = tuxtxt_cache.current_subpage[magazine]; + + tuxtxt_allocate_cache(magazine); + tuxtxt_decompress_page(tuxtxt_cache.current_page[magazine],tuxtxt_cache.current_subpage[magazine],pagedata[magazine]); + pageinfo_thread = &(tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]]->pageinfo); + + if ((tuxtxt_cache.page_receiving & 0xff) == 0xfe) /* ?fe: magazine organization table (MOT) */ + pageinfo_thread->function = FUNC_MOT; + + /* check controlbits */ + if (dehamming[vtxt_row[5]] & 8) /* C4 -> erase page */ + { +#if TUXTXT_COMPRESS == 1 + tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]]->ziplen = 0; +#elif TUXTXT_COMPRESS == 2 + memset(tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]]->bitmask, 0, 23*5); +#else + memset(tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]]->data, ' ', 23*40); +#endif + memset(pagedata[magazine],' ', 23*40); + } + if (dehamming[vtxt_row[9]] & 8) /* C8 -> update page */ + doupdate = tuxtxt_cache.page_receiving; + + pageinfo_thread->boxed = !!(dehamming[vtxt_row[7]] & 0x0c); + + /* get country control bits */ + b1 = dehamming[vtxt_row[9]]; + if (b1 == 0xFF) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + } + else + { + pageinfo_thread->nationalvalid = 1; + pageinfo_thread->national = rev_lut[b1] & 0x07; + } + + /* check parity, copy line 0 to cache (start and end 8 bytes are not needed and used otherwise) */ + unsigned char *p = tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]]->p0; + for (byte = 10; byte < 42-8; byte++) + *p++ = deparity[vtxt_row[byte]]; + + if (!tuxtxt_is_dec(tuxtxt_cache.page_receiving)) + continue; /* valid hex page number: just copy headline, ignore timestring */ + + /* copy timestring */ + p = tuxtxt_cache.timestring; + for (; byte < 42; byte++) + *p++ = deparity[vtxt_row[byte]]; + } /* (packet_number == 0) */ + else if (packet_number == 29 && dehamming[vtxt_row[2]]== 0) /* packet 29/0 replaces 28/0 for a whole magazine */ + { + tuxtxt_decode_p2829(vtxt_row, &(tuxtxt_cache.astP29[magazine])); + } + else if (tuxtxt_cache.current_page[magazine] != -1 && tuxtxt_cache.current_subpage[magazine] != -1) + /* packet>0, 0 has been correctly received, buffer allocated */ + { + pageinfo_thread = &(tuxtxt_cache.astCachetable[tuxtxt_cache.current_page[magazine]][tuxtxt_cache.current_subpage[magazine]]->pageinfo); + /* pointer to current info struct */ + + if (packet_number <= 25) + { + unsigned char *p = NULL; + if (packet_number < 24) + p = pagedata[magazine] + 40*(packet_number-1); + else + { + if (!(pageinfo_thread->p24)) + pageinfo_thread->p24 = (unsigned char*) calloc(2, 40); + if (pageinfo_thread->p24) + p = pageinfo_thread->p24 + (packet_number - 24) * 40; + } + if (p) + { + if (tuxtxt_is_dec(tuxtxt_cache.current_page[magazine])) + for (byte = 2; byte < 42; byte++) + *p++ = deparity[vtxt_row[byte]]; /* check/remove parity bit */ + else if ((tuxtxt_cache.current_page[magazine] & 0xff) == 0xfe) + for (byte = 2; byte < 42; byte++) + *p++ = dehamming[vtxt_row[byte]]; /* decode hamming 8/4 */ + else /* other hex page: no parity check, just copy */ + memcpy(p, &vtxt_row[2], 40); + } + } + else if (packet_number == 27) + { + int descode = dehamming[vtxt_row[2]]; /* designation code (0..15) */ + + if (descode == 0xff) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + continue; + } + if (descode == 0) // reading FLOF-Pagelinks + { + b1 = dehamming[vtxt_row[0]]; + if (b1 != 0xff) + { + b1 &= 7; + + for (byte = 0; byte < FLOFSIZE; byte++) + { + b2 = dehamming[vtxt_row[4+byte*6]]; + b3 = dehamming[vtxt_row[3+byte*6]]; + + if (b2 != 0xff && b3 != 0xff) + { + b4 = ((b1 ^ (dehamming[vtxt_row[8+byte*6]]>>1)) & 6) | + ((b1 ^ (dehamming[vtxt_row[6+byte*6]]>>3)) & 1); + if (b4 == 0) + b4 = 8; + if (b2 <= 9 && b3 <= 9) + tuxtxt_cache.flofpages[tuxtxt_cache.current_page[magazine] ][byte] = b4<<8 | b2<<4 | b3; + } + } + + /* copy last 2 links to adip for TOP-Index */ + if (pageinfo_thread->p24) /* packet 24 received */ + { + int a, a1, e=39, l=3; + char *p = (char*) pageinfo_thread->p24; + do + { + for (; + l >= 2 && 0 == tuxtxt_cache.flofpages[tuxtxt_cache.current_page[magazine]][l]; + l--) + ; /* find used linkindex */ + for (; + e >= 1 && !isalnum(p[e]); + e--) + ; /* find end */ + for (a = a1 = e - 1; + a >= 0 && p[a] >= ' '; + a--) /* find start */ + if (p[a] > ' ') + a1 = a; /* first non-space */ + if (a >= 0 && l >= 2) + { + strncpy((char *) tuxtxt_cache.adip[tuxtxt_cache.flofpages[tuxtxt_cache.current_page[magazine]][l]], + &p[a1], + 12); + if (e-a1 < 11) + tuxtxt_cache.adip[tuxtxt_cache.flofpages[tuxtxt_cache.current_page[magazine]][l]][e-a1+1] = '\0'; +#if 0 //TUXTXT_DEBUG + printf(" %03x/%02x %d %d %d %d %03x %s\n", + tuxtxt_cache.current_page[magazine], tuxtxt_cache.current_subpage[magazine], + l, a, a1, e, + tuxtxt_cache.flofpages[tuxtxt_cache.current_page[magazine]][l], + tuxtxt_cache.adip[tuxtxt_cache.flofpages[tuxtxt_cache.current_page[magazine]][l]] + ); +#endif + } + e = a - 1; + l--; + } while (l >= 2); + } + } + } + else if (descode == 4) /* level 2.5 links (ignore level 3.5 links of /4 and /5) */ + { + int i; + tstp27 *p; + + if (!pageinfo_thread->ext) + pageinfo_thread->ext = (tstExtData*) calloc(1, sizeof(tstExtData)); + if (!pageinfo_thread->ext) + continue; + if (!(pageinfo_thread->ext->p27)) + pageinfo_thread->ext->p27 = (tstp27*) calloc(4, sizeof(tstp27)); + if (!(pageinfo_thread->ext->p27)) + continue; + p = pageinfo_thread->ext->p27; + for (i = 0; i < 4; i++) + { + int d1 = deh24(&vtxt_row[6*i + 3]); + int d2 = deh24(&vtxt_row[6*i + 6]); + if (d1 < 0 || d2 < 0) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + continue; + } + p->local = i & 0x01; + p->drcs = !!(i & 0x02); + p->l25 = !!(d1 & 0x04); + p->l35 = !!(d1 & 0x08); + p->page = + (((d1 & 0x000003c0) >> 6) | + ((d1 & 0x0003c000) >> (14-4)) | + ((d1 & 0x00003800) >> (11-8))) ^ + (dehamming[vtxt_row[0]] << 8); + if (p->page < 0x100) + p->page += 0x800; + p->subpage = d2 >> 2; + if ((p->page & 0xff) == 0xff) + p->page = 0; + else if (p->page > 0x899) + { + // workaround for crash on RTL + printf("[TuxTxt] page > 0x899 ... ignore!!!!!!\n"); + continue; + } + else if (tuxtxt_cache.astCachetable[p->page][0]) /* link valid && linked page cached */ + { + tstPageinfo *pageinfo_link = &(tuxtxt_cache.astCachetable[p->page][0]->pageinfo); + if (p->local) + pageinfo_link->function = p->drcs ? FUNC_DRCS : FUNC_POP; + else + pageinfo_link->function = p->drcs ? FUNC_GDRCS : FUNC_GPOP; + } + p++; /* */ + } + } + } + + else if (packet_number == 26) + { + int descode = dehamming[vtxt_row[2]]; /* designation code (0..15) */ + + if (descode == 0xff) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + continue; + } + if (!pageinfo_thread->ext) + pageinfo_thread->ext = (tstExtData*) calloc(1, sizeof(tstExtData)); + if (!pageinfo_thread->ext) + continue; + if (!(pageinfo_thread->ext->p26[descode])) + pageinfo_thread->ext->p26[descode] = (unsigned char*) malloc(13 * 3); + if (pageinfo_thread->ext->p26[descode]) + memcpy(pageinfo_thread->ext->p26[descode], &vtxt_row[3], 13 * 3); +#if 0//TUXTXT_DEBUG + int i, t, m; + + printf("P%03x/%02x %02d/%x", + tuxtxt_cache.current_page[magazine], tuxtxt_cache.current_subpage[magazine], + packet_number, dehamming[vtxt_row[2]]); + for (i=7-4; i <= 45-4; i+=3) /* dump all triplets */ + { + t = deh24(&vtxt_row[i]); /* mode/adr/data */ + m = (t>>6) & 0x1f; + printf(" M%02xA%02xD%03x", m, t & 0x3f, (t>>11) & 0x7f); + if (m == 0x1f) /* terminator */ + break; + } + putchar('\n'); +#endif + } + else if (packet_number == 28) + { + int descode = dehamming[vtxt_row[2]]; /* designation code (0..15) */ + + if (descode == 0xff) + { +#if TUXTXT_DEBUG + printf("TuxTxt \n"); +#endif + continue; + } + if (descode != 2) + { + int t1 = deh24(&vtxt_row[7-4]); + pageinfo_thread->function = t1 & 0x0f; + if (!pageinfo_thread->nationalvalid) + { + pageinfo_thread->nationalvalid = 1; + pageinfo_thread->national = (t1>>4) & 0x07; + } + } + + switch (descode) /* designation code */ + { + case 0: /* basic level 1 page */ + { + tuxtxt_decode_p2829(vtxt_row, &(pageinfo_thread->ext)); + break; + } + case 1: /* G0/G1 designation for older decoders, level 3.5: DCLUT4/16, colors for multicolored bitmaps */ + { + break; /* ignore */ + } + case 2: /* page key */ + { + break; /* ignore */ + } + case 3: /* types of PTUs in DRCS */ + { + break; /* TODO */ + } + case 4: /* CLUTs 0/1, only level 3.5 */ + { + break; /* ignore */ + } + default: + { + break; /* invalid, ignore */ + } + } /* switch designation code */ + } + else if (packet_number == 30) + { +#if 0//TUXTXT_DEBUG + int i; + + printf("p%03x/%02x %02d/%x ", + tuxtxt_cache.current_page[magazine], tuxtxt_cache.current_subpage[magazine], + packet_number, dehamming[vtxt_row[2]]); + for (i=26-4; i <= 45-4; i++) /* station ID */ + putchar(deparity[vtxt_row[i]]); + putchar('\n'); +#endif + } + } + /* set update flag */ + if (tuxtxt_cache.current_page[magazine] == tuxtxt_cache.page && tuxtxt_cache.current_subpage[magazine] != -1) + { + tuxtxt_compress_page(tuxtxt_cache.current_page[magazine],tuxtxt_cache.current_subpage[magazine],pagedata[magazine]); + tuxtxt_cache.pageupdate = 1+(doupdate == tuxtxt_cache.page ? 1: 0); + doupdate=0; + if (!tuxtxt_cache.zap_subpage_manual) + tuxtxt_cache.subpage = tuxtxt_cache.current_subpage[magazine]; + } + } +#if 0 + else + printf("line %d row %X %X, continue\n", line, vtx_rowbyte[0], vtx_rowbyte[1]); +#endif + } + } + return 0; +} +/****************************************************************************** + * start_thread * + ******************************************************************************/ +int tuxtxt_start_thread() +{ + if (tuxtxt_cache.vtxtpid == -1) return 0; + + + tuxtxt_cache.thread_starting = 1; + tuxtxt_init_demuxer(); + + dmx->pesFilter(tuxtxt_cache.vtxtpid); + dmx->Start(); + stop_cache = 0; + + /* create decode-thread */ + if (pthread_create(&tuxtxt_cache.thread_id, NULL, tuxtxt_CacheThread, NULL) != 0) + { + perror("TuxTxt "); + tuxtxt_cache.thread_starting = 0; + return 0; + } +#if 1//TUXTXT_DEBUG + printf("TuxTxt service started %x\n", tuxtxt_cache.vtxtpid); +#endif + tuxtxt_cache.receiving = 1; + tuxtxt_cache.thread_starting = 0; + return 1; +} +/****************************************************************************** + * stop_thread * + ******************************************************************************/ + +int tuxtxt_stop_thread() +{ + /* stop decode-thread */ + if (tuxtxt_cache.thread_id != 0) + { +#if 0 + if (pthread_cancel(tuxtxt_cache.thread_id) != 0) + { + perror("TuxTxt "); + return 0; + } +#endif + stop_cache = 1; + if (pthread_join(tuxtxt_cache.thread_id, &tuxtxt_cache.thread_result) != 0) + { + perror("TuxTxt "); + return 0; + } + tuxtxt_cache.thread_id = 0; + } + if(dmx) { + dmx->Stop(); + delete dmx; + dmx = NULL; + } +#if 0 + if (tuxtxt_cache.dmx != -1) + { + //ioctl(tuxtxt_cache.dmx, DMX_STOP); + +// close(tuxtxt_cache.dmx); + } +// tuxtxt_cache.dmx = -1; +#endif +#if 1//TUXTXT_DEBUG + printf("TuxTxt stopped service %x\n", tuxtxt_cache.vtxtpid); +#endif + return 1; +} diff --git a/lib/libtuxtxt/tuxtxt_def.h b/lib/libtuxtxt/tuxtxt_def.h new file mode 100644 index 000000000..255db1f74 --- /dev/null +++ b/lib/libtuxtxt/tuxtxt_def.h @@ -0,0 +1,370 @@ +/****************************************************************************** + * definitions for plugin and lib * + ******************************************************************************/ +#define TUXTXT_COMPRESS 2 // compress page data: 0 no compression, 1 with zlib, 2 with own algorithm + +#include + +#define FLOFSIZE 4 + +#define PAGESIZE (40*25) + + +enum /* page function */ +{ + FUNC_LOP = 0, /* Basic Level 1 Teletext page (LOP) */ + FUNC_DATA, /* Data broadcasting page coded according to EN 300 708 [2] clause 4 */ + FUNC_GPOP, /* Global Object definition page (GPOP) - (see clause 10.5.1) */ + FUNC_POP, /* Normal Object definition page (POP) - (see clause 10.5.1) */ + FUNC_GDRCS, /* Global DRCS downloading page (GDRCS) - (see clause 10.5.2) */ + FUNC_DRCS, /* Normal DRCS downloading page (DRCS) - (see clause 10.5.2) */ + FUNC_MOT, /* Magazine Organization table (MOT) - (see clause 10.6) */ + FUNC_MIP, /* Magazine Inventory page (MIP) - (see clause 11.3) */ + FUNC_BTT, /* Basic TOP table (BTT) } */ + FUNC_AIT, /* Additional Information Table (AIT) } (see clause 11.2) */ + FUNC_MPT, /* Multi-page table (MPT) } */ + FUNC_MPTEX, /* Multi-page extension table (MPT-EX) } */ + FUNC_TRIGGER /* Page contain trigger messages defined according to [8] */ +}; + + +/* struct for (G)POP/(G)DRCS links for level 2.5, allocated at reception of p27/4 or /5, initialized with 0 after allocation */ +typedef struct +{ + short page; /* linked page number */ + unsigned short subpage; /* 1 bit for each needed (1) subpage */ + unsigned char l25:1; /* 1: page required at level 2.5 */ + unsigned char l35:1; /* 1: page required at level 3.5 */ + unsigned char drcs:1; /* 1: link to (G)DRCS, 0: (G)POP */ + unsigned char local:1; /* 1: global (G*), 0: local */ +} tstp27; + +/* struct for extension data for level 2.5, allocated at reception, initialized with 0 after allocation */ +typedef struct +{ + unsigned char *p26[16]; /* array of pointers to max. 16 designation codes of packet 26 */ + tstp27 *p27; /* array of 4 structs for (G)POP/(G)DRCS links for level 2.5 */ + unsigned short bgr[16]; /* CLUT 2+3, 2*8 colors, 0x0bgr */ + unsigned char DefaultCharset:7; /* default G0/G2 charset + national option */ + unsigned char LSP:1; /* 1: left side panel to be displayed */ + unsigned char SecondCharset:7; /* second G0 charset */ + unsigned char RSP:1; /* 1: right side panel to be displayed */ + unsigned char DefScreenColor:5; /* default screen color (above and below lines 0..24) */ + unsigned char ColorTableRemapping:3; /* 1: index in table of CLUTs to use */ + unsigned char DefRowColor:5; /* default row color (left and right to lines 0..24) */ + unsigned char BlackBgSubst:1; /* 1: substitute black background (as result of start-of-line or 1c, not 00/10+1d) */ + unsigned char SPL25:1; /* 1: side panel required at level 2.5 */ + unsigned char p28Received:1; /* 1: extension data valid (p28/0 received) */ + unsigned char LSPColumns:4; /* number of columns in left side panel, 0->16, rsp=16-lsp */ +} tstExtData; + + +/* struct for pageinfo, max. 16 Bytes, at beginning of each cached page buffer, initialized with 0 after allocation */ +typedef struct +{ + unsigned char *p24; /* pointer to lines 25+26 (packets 24+25) (2*40 bytes) for FLOF or level 2.5 data */ + tstExtData *ext; /* pointer to array[16] of data for level 2.5 */ + unsigned char boxed :1; /* p0: boxed (newsflash or subtitle) */ + unsigned char nationalvalid :1; /* p0: national option character subset is valid (no biterror detected) */ + unsigned char national :3; /* p0: national option character subset */ + unsigned char function :3; /* p28/0: page function */ +} tstPageinfo; + +/* one cached page: struct for pageinfo, 24 lines page data */ +typedef struct +{ + tstPageinfo pageinfo; + unsigned char p0[24]; /* packet 0: center of headline */ +#if TUXTXT_COMPRESS == 1 + unsigned char * pData;/* packet 1-23 */ + unsigned short ziplen; +#elif TUXTXT_COMPRESS == 2 + unsigned char * pData;/* packet 1-23 */ + unsigned char bitmask[23*5]; +#else + unsigned char data[23*40]; /* packet 1-23 */ +#endif +} tstCachedPage; + +/* main data structure */ +typedef struct +{ + short flofpages[0x900][FLOFSIZE]; + unsigned char adip[0x900][13]; + unsigned char subpagetable[0x900]; + int dmx; + int vtxtpid; + int cached_pages, page, subpage, pageupdate,page_receiving, current_page[9], current_subpage[9]; + int receiving, thread_starting, zap_subpage_manual; + char bttok; + int adippg[10]; + int maxadippg; + unsigned char basictop[0x900]; + + unsigned char timestring[8]; + /* cachetable for packets 29 (one for each magazine) */ + tstExtData *astP29[9]; + /* cachetable */ + tstCachedPage *astCachetable[0x900][0x80]; + + pthread_t thread_id; + void *thread_result; +} tuxtxt_cache_struct; + +/* hamming table */ +const unsigned char dehamming[] = +{ + 0x01, 0xFF, 0x01, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x02, 0x01, 0xFF, 0x0A, 0xFF, 0xFF, 0x07, + 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x06, 0xFF, 0xFF, 0x0B, 0xFF, 0x00, 0x03, 0xFF, + 0xFF, 0x0C, 0x01, 0xFF, 0x04, 0xFF, 0xFF, 0x07, 0x06, 0xFF, 0xFF, 0x07, 0xFF, 0x07, 0x07, 0x07, + 0x06, 0xFF, 0xFF, 0x05, 0xFF, 0x00, 0x0D, 0xFF, 0x06, 0x06, 0x06, 0xFF, 0x06, 0xFF, 0xFF, 0x07, + 0xFF, 0x02, 0x01, 0xFF, 0x04, 0xFF, 0xFF, 0x09, 0x02, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0x03, 0xFF, + 0x08, 0xFF, 0xFF, 0x05, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x03, 0xFF, 0x03, 0x03, + 0x04, 0xFF, 0xFF, 0x05, 0x04, 0x04, 0x04, 0xFF, 0xFF, 0x02, 0x0F, 0xFF, 0x04, 0xFF, 0xFF, 0x07, + 0xFF, 0x05, 0x05, 0x05, 0x04, 0xFF, 0xFF, 0x05, 0x06, 0xFF, 0xFF, 0x05, 0xFF, 0x0E, 0x03, 0xFF, + 0xFF, 0x0C, 0x01, 0xFF, 0x0A, 0xFF, 0xFF, 0x09, 0x0A, 0xFF, 0xFF, 0x0B, 0x0A, 0x0A, 0x0A, 0xFF, + 0x08, 0xFF, 0xFF, 0x0B, 0xFF, 0x00, 0x0D, 0xFF, 0xFF, 0x0B, 0x0B, 0x0B, 0x0A, 0xFF, 0xFF, 0x0B, + 0x0C, 0x0C, 0xFF, 0x0C, 0xFF, 0x0C, 0x0D, 0xFF, 0xFF, 0x0C, 0x0F, 0xFF, 0x0A, 0xFF, 0xFF, 0x07, + 0xFF, 0x0C, 0x0D, 0xFF, 0x0D, 0xFF, 0x0D, 0x0D, 0x06, 0xFF, 0xFF, 0x0B, 0xFF, 0x0E, 0x0D, 0xFF, + 0x08, 0xFF, 0xFF, 0x09, 0xFF, 0x09, 0x09, 0x09, 0xFF, 0x02, 0x0F, 0xFF, 0x0A, 0xFF, 0xFF, 0x09, + 0x08, 0x08, 0x08, 0xFF, 0x08, 0xFF, 0xFF, 0x09, 0x08, 0xFF, 0xFF, 0x0B, 0xFF, 0x0E, 0x03, 0xFF, + 0xFF, 0x0C, 0x0F, 0xFF, 0x04, 0xFF, 0xFF, 0x09, 0x0F, 0xFF, 0x0F, 0x0F, 0xFF, 0x0E, 0x0F, 0xFF, + 0x08, 0xFF, 0xFF, 0x05, 0xFF, 0x0E, 0x0D, 0xFF, 0xFF, 0x0E, 0x0F, 0xFF, 0x0E, 0x0E, 0xFF, 0x0E +}; + +/* odd parity table, error=0x20 (space) */ +const unsigned char deparity[] = +{ + ' ' , 0x01, 0x02, ' ' , 0x04, ' ' , ' ' , 0x07, 0x08, ' ' , ' ' , 0x0b, ' ' , 0x0d, 0x0e, ' ' , + 0x10, ' ' , ' ' , 0x13, ' ' , 0x15, 0x16, ' ' , ' ' , 0x19, 0x1a, ' ' , 0x1c, ' ' , ' ' , 0x1f, + 0x20, ' ' , ' ' , 0x23, ' ' , 0x25, 0x26, ' ' , ' ' , 0x29, 0x2a, ' ' , 0x2c, ' ' , ' ' , 0x2f, + ' ' , 0x31, 0x32, ' ' , 0x34, ' ' , ' ' , 0x37, 0x38, ' ' , ' ' , 0x3b, ' ' , 0x3d, 0x3e, ' ' , + 0x40, ' ' , ' ' , 0x43, ' ' , 0x45, 0x46, ' ' , ' ' , 0x49, 0x4a, ' ' , 0x4c, ' ' , ' ' , 0x4f, + ' ' , 0x51, 0x52, ' ' , 0x54, ' ' , ' ' , 0x57, 0x58, ' ' , ' ' , 0x5b, ' ' , 0x5d, 0x5e, ' ' , + ' ' , 0x61, 0x62, ' ' , 0x64, ' ' , ' ' , 0x67, 0x68, ' ' , ' ' , 0x6b, ' ' , 0x6d, 0x6e, ' ' , + 0x70, ' ' , ' ' , 0x73, ' ' , 0x75, 0x76, ' ' , ' ' , 0x79, 0x7a, ' ' , 0x7c, ' ' , ' ' , 0x7f, + 0x00, ' ' , ' ' , 0x03, ' ' , 0x05, 0x06, ' ' , ' ' , 0x09, 0x0a, ' ' , 0x0c, ' ' , ' ' , 0x0f, + ' ' , 0x11, 0x12, ' ' , 0x14, ' ' , ' ' , 0x17, 0x18, ' ' , ' ' , 0x1b, ' ' , 0x1d, 0x1e, ' ' , + ' ' , 0x21, 0x22, ' ' , 0x24, ' ' , ' ' , 0x27, 0x28, ' ' , ' ' , 0x2b, ' ' , 0x2d, 0x2e, ' ' , + 0x30, ' ' , ' ' , 0x33, ' ' , 0x35, 0x36, ' ' , ' ' , 0x39, 0x3a, ' ' , 0x3c, ' ' , ' ' , 0x3f, + ' ' , 0x41, 0x42, ' ' , 0x44, ' ' , ' ' , 0x47, 0x48, ' ' , ' ' , 0x4b, ' ' , 0x4d, 0x4e, ' ' , + 0x50, ' ' , ' ' , 0x53, ' ' , 0x55, 0x56, ' ' , ' ' , 0x59, 0x5a, ' ' , 0x5c, ' ' , ' ' , 0x5f, + 0x60, ' ' , ' ' , 0x63, ' ' , 0x65, 0x66, ' ' , ' ' , 0x69, 0x6a, ' ' , 0x6c, ' ' , ' ' , 0x6f, + ' ' , 0x71, 0x72, ' ' , 0x74, ' ' , ' ' , 0x77, 0x78, ' ' , ' ' , 0x7b, ' ' , 0x7d, 0x7e, ' ' , +}; + +#if 1 /* lookup-table algorithm for decoding Hamming 24/18, credits to: */ +/* + * libzvbi - Error correction functions + * + * Copyright (C) 2001 Michael H. Schimek + * + * Based on code from AleVT 1.5.1 + * Copyright (C) 1998, 1999 Edgar Toernig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * [AleVT] + * + * This table generates the parity checks for hamm24/18 decoding. + * Bit 0 is for test A, 1 for B, ... + * + * Thanks to R. Gancarz for this fine table *g* + */ +const unsigned char hamm24par[3][256] = { + { + /* Parities of first byte */ + 0, 33, 34, 3, 35, 2, 1, 32, 36, 5, 6, 39, 7, 38, 37, 4, + 37, 4, 7, 38, 6, 39, 36, 5, 1, 32, 35, 2, 34, 3, 0, 33, + 38, 7, 4, 37, 5, 36, 39, 6, 2, 35, 32, 1, 33, 0, 3, 34, + 3, 34, 33, 0, 32, 1, 2, 35, 39, 6, 5, 36, 4, 37, 38, 7, + 39, 6, 5, 36, 4, 37, 38, 7, 3, 34, 33, 0, 32, 1, 2, 35, + 2, 35, 32, 1, 33, 0, 3, 34, 38, 7, 4, 37, 5, 36, 39, 6, + 1, 32, 35, 2, 34, 3, 0, 33, 37, 4, 7, 38, 6, 39, 36, 5, + 36, 5, 6, 39, 7, 38, 37, 4, 0, 33, 34, 3, 35, 2, 1, 32, + 40, 9, 10, 43, 11, 42, 41, 8, 12, 45, 46, 15, 47, 14, 13, 44, + 13, 44, 47, 14, 46, 15, 12, 45, 41, 8, 11, 42, 10, 43, 40, 9, + 14, 47, 44, 13, 45, 12, 15, 46, 42, 11, 8, 41, 9, 40, 43, 10, + 43, 10, 9, 40, 8, 41, 42, 11, 15, 46, 45, 12, 44, 13, 14, 47, + 15, 46, 45, 12, 44, 13, 14, 47, 43, 10, 9, 40, 8, 41, 42, 11, + 42, 11, 8, 41, 9, 40, 43, 10, 14, 47, 44, 13, 45, 12, 15, 46, + 41, 8, 11, 42, 10, 43, 40, 9, 13, 44, 47, 14, 46, 15, 12, 45, + 12, 45, 46, 15, 47, 14, 13, 44, 40, 9, 10, 43, 11, 42, 41, 8 + }, { + /* Parities of second byte */ + 0, 41, 42, 3, 43, 2, 1, 40, 44, 5, 6, 47, 7, 46, 45, 4, + 45, 4, 7, 46, 6, 47, 44, 5, 1, 40, 43, 2, 42, 3, 0, 41, + 46, 7, 4, 45, 5, 44, 47, 6, 2, 43, 40, 1, 41, 0, 3, 42, + 3, 42, 41, 0, 40, 1, 2, 43, 47, 6, 5, 44, 4, 45, 46, 7, + 47, 6, 5, 44, 4, 45, 46, 7, 3, 42, 41, 0, 40, 1, 2, 43, + 2, 43, 40, 1, 41, 0, 3, 42, 46, 7, 4, 45, 5, 44, 47, 6, + 1, 40, 43, 2, 42, 3, 0, 41, 45, 4, 7, 46, 6, 47, 44, 5, + 44, 5, 6, 47, 7, 46, 45, 4, 0, 41, 42, 3, 43, 2, 1, 40, + 48, 25, 26, 51, 27, 50, 49, 24, 28, 53, 54, 31, 55, 30, 29, 52, + 29, 52, 55, 30, 54, 31, 28, 53, 49, 24, 27, 50, 26, 51, 48, 25, + 30, 55, 52, 29, 53, 28, 31, 54, 50, 27, 24, 49, 25, 48, 51, 26, + 51, 26, 25, 48, 24, 49, 50, 27, 31, 54, 53, 28, 52, 29, 30, 55, + 31, 54, 53, 28, 52, 29, 30, 55, 51, 26, 25, 48, 24, 49, 50, 27, + 50, 27, 24, 49, 25, 48, 51, 26, 30, 55, 52, 29, 53, 28, 31, 54, + 49, 24, 27, 50, 26, 51, 48, 25, 29, 52, 55, 30, 54, 31, 28, 53, + 28, 53, 54, 31, 55, 30, 29, 52, 48, 25, 26, 51, 27, 50, 49, 24 + }, { + /* Parities of third byte */ + 63, 14, 13, 60, 12, 61, 62, 15, 11, 58, 57, 8, 56, 9, 10, 59, + 10, 59, 56, 9, 57, 8, 11, 58, 62, 15, 12, 61, 13, 60, 63, 14, + 9, 56, 59, 10, 58, 11, 8, 57, 61, 12, 15, 62, 14, 63, 60, 13, + 60, 13, 14, 63, 15, 62, 61, 12, 8, 57, 58, 11, 59, 10, 9, 56, + 8, 57, 58, 11, 59, 10, 9, 56, 60, 13, 14, 63, 15, 62, 61, 12, + 61, 12, 15, 62, 14, 63, 60, 13, 9, 56, 59, 10, 58, 11, 8, 57, + 62, 15, 12, 61, 13, 60, 63, 14, 10, 59, 56, 9, 57, 8, 11, 58, + 11, 58, 57, 8, 56, 9, 10, 59, 63, 14, 13, 60, 12, 61, 62, 15, + 31, 46, 45, 28, 44, 29, 30, 47, 43, 26, 25, 40, 24, 41, 42, 27, + 42, 27, 24, 41, 25, 40, 43, 26, 30, 47, 44, 29, 45, 28, 31, 46, + 41, 24, 27, 42, 26, 43, 40, 25, 29, 44, 47, 30, 46, 31, 28, 45, + 28, 45, 46, 31, 47, 30, 29, 44, 40, 25, 26, 43, 27, 42, 41, 24, + 40, 25, 26, 43, 27, 42, 41, 24, 28, 45, 46, 31, 47, 30, 29, 44, + 29, 44, 47, 30, 46, 31, 28, 45, 41, 24, 27, 42, 26, 43, 40, 25, + 30, 47, 44, 29, 45, 28, 31, 46, 42, 27, 24, 41, 25, 40, 43, 26, + 43, 26, 25, 40, 24, 41, 42, 27, 31, 46, 45, 28, 44, 29, 30, 47 + } +}; + +/* + * [AleVT] + * + * Table to extract the lower 4 bit from hamm24/18 encoded bytes + */ +const unsigned char hamm24val[256] = { + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, + 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7, + 8, 8, 8, 8, 9, 9, 9, 9, 8, 8, 8, 8, 9, 9, 9, 9, + 10, 10, 10, 10, 11, 11, 11, 11, 10, 10, 10, 10, 11, 11, 11, 11, + 12, 12, 12, 12, 13, 13, 13, 13, 12, 12, 12, 12, 13, 13, 13, 13, + 14, 14, 14, 14, 15, 15, 15, 15, 14, 14, 14, 14, 15, 15, 15, 15, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, + 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 7, + 8, 8, 8, 8, 9, 9, 9, 9, 8, 8, 8, 8, 9, 9, 9, 9, + 10, 10, 10, 10, 11, 11, 11, 11, 10, 10, 10, 10, 11, 11, 11, 11, + 12, 12, 12, 12, 13, 13, 13, 13, 12, 12, 12, 12, 13, 13, 13, 13, + 14, 14, 14, 14, 15, 15, 15, 15, 14, 14, 14, 14, 15, 15, 15, 15 +}; + +const signed char hamm24err[64] = { + 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +/* + * [AleVT] + * + * Mapping from parity checks made by table hamm24par to faulty bit + * in the decoded 18 bit word. + */ +const unsigned int hamm24cor[64] = { + 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, + 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, + 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, + 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, + 0x00000, 0x00000, 0x00000, 0x00001, 0x00000, 0x00002, 0x00004, 0x00008, + 0x00000, 0x00010, 0x00020, 0x00040, 0x00080, 0x00100, 0x00200, 0x00400, + 0x00000, 0x00800, 0x01000, 0x02000, 0x04000, 0x08000, 0x10000, 0x20000, + 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, +}; + +/** + * @internal + * @param p Pointer to a byte triplet, bytes in transmission order, + * lsb first transmitted. + * + * This function decodes a Hamming 24/18 protected byte triplet + * as specified in ETS 300 706 8.3. + * + * @return + * Triplet data bits D18 [msb] ... D1 [lsb] or a negative + * value if the triplet contained incorrectable errors. + */ +static signed int deh24(unsigned char *p) +{ + int e = hamm24par[0][p[0]] + ^ hamm24par[1][p[1]] + ^ hamm24par[2][p[2]]; + + int x = hamm24val[p[0]] + + (p[1] & 127) * 16 + + (p[2] & 127) * 2048; + + return (x ^ hamm24cor[e]) | hamm24err[e]; +} + +#else /* my (rm) slower but smaller solution without lookup tables */ + +/* calc parity */ +int parity(int c) +{ + int n = 0; + for (; c; c &= (c-1)) /* reset least significant set bit */ + n ^= 1; + return n; +} + +#if 0 /* just for testing */ +/* encode hamming 24/18 */ +unsigned int ham24(unsigned int val) +{ + val = ((val & 0x000001) << 2) | + ((val & 0x00000e) << 3) | + ((val & 0x0007f0) << 4) | + ((val & 0x03f800) << 5); + val |= parity(val & 0x555554); + val |= parity(val & 0x666664) << 1; + val |= parity(val & 0x787870) << 3; + val |= parity(val & 0x007f00) << 7; + val |= parity(val & 0x7f0000) << 15; + val |= parity(val) << 23; + return val; +} +#endif + +/* decode hamming 24/18, error=-1 */ +signed int deh24(unsigned char *ph24) +{ + int h24 = *ph24 | (*(ph24+1)<<8) | (*(ph24+2)<<16); + int a = parity(h24 & 0x555555); + int f = parity(h24 & 0xaaaaaa) ^ a; + a |= (parity(h24 & 0x666666) << 1) | + (parity(h24 & 0x787878) << 2) | + (parity(h24 & 0x007f80) << 3) | + (parity(h24 & 0x7f8000) << 4); + if (a != 0x1f) + { + if (f) /* 2 biterrors */ + return -1; + else /* correct 1 biterror */ + h24 ^= (1 << ((a ^ 0x1f)-1)); + } + return + ((h24 & 0x000004) >> 2) | + ((h24 & 0x000070) >> 3) | + ((h24 & 0x007f00) >> 4) | + ((h24 & 0x7f0000) >> 5); +} +#endif /* table or serial */ diff --git a/lib/libupnpclient/Makefile.am b/lib/libupnpclient/Makefile.am new file mode 100644 index 000000000..87168ef65 --- /dev/null +++ b/lib/libupnpclient/Makefile.am @@ -0,0 +1,8 @@ +noinst_LIBRARIES = libtuxbox-upnpclient.a + +AM_CPPFLAGS = -fno-rtti + +INCLUDES = \ + -I$(top_srcdir)/lib/xmltree + +libtuxbox_upnpclient_a_SOURCES = UPNPSocket.cpp UPNPDevice.cpp UPNPService.cpp diff --git a/lib/libupnpclient/UPNPDevice.cpp b/lib/libupnpclient/UPNPDevice.cpp new file mode 100644 index 000000000..86afef8d2 --- /dev/null +++ b/lib/libupnpclient/UPNPDevice.cpp @@ -0,0 +1,465 @@ +/*********************************************************************************** + * UPNPDevice.cpp + * + * Copyright (c) 2007 Jochen Friedrich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ***********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "upnpclient.h" +#include + +struct ToLower +{ + char operator() (char c) const { return std::tolower(c); } +}; + +static void trim(std::string &buf) +{ + std::string::size_type pos1, pos2; + + pos1 = buf.find_first_not_of(" \t\n\r"); + pos2 = buf.find_last_not_of(" \t\n\r"); + if ((pos1 == std::string::npos) || (pos2 == std::string::npos)) + buf=""; + else + buf = buf.substr(pos1, pos2 - pos1 + 1); +} + +bool CUPnPDevice::check_response(std::string header, std::string& charset, std::string& rcode) +{ + std::string::size_type pos; + std::string content, attrib, chars; + + charset="ISO-8859-1"; + + pos = header.find("\r"); + if (pos == std::string::npos) + return false; + + rcode = header.substr(0, pos); + if (rcode.substr(0,5) != "HTTP/") + return false; + + pos = rcode.find(" "); + if (pos == std::string::npos) + return false; + + rcode.erase(0, pos); + trim(rcode); + + pos = rcode.find(" "); + if (pos != std::string::npos) + { + rcode.erase(pos); + trim(rcode); + } + + std::transform(header.begin(), header.end(), header.begin(), ToLower()); + + pos = header.find("content-type:"); + if (pos == std::string::npos) + return false; + + content = header.substr(pos); + content.erase(0,13); + pos = content.find("\n"); + if (pos != std::string::npos) + content.erase(pos); + + trim(content); + + pos=content.find(";"); + if (pos!=std::string::npos) + { + attrib=content.substr(pos+1); + content.erase(pos); + trim(content); + } + if (content != "text/xml") + return false; + + trim(attrib); + if (attrib.substr(0,8) == "charset=") + { + attrib.erase(0,8); + pos = attrib.find("\""); + if (pos!=std::string::npos) + { + attrib.erase(0,pos+1); + pos = attrib.find("\""); + if (pos==std::string::npos) + return false; + chars=attrib.substr(0,pos); + } + else + chars=attrib; + if (!strcasecmp(chars.c_str(), "utf-8")) + charset = "UTF-8"; + } + return true; +} + +CUPnPDevice::CUPnPDevice(std::string url) +{ + std::string result, head, body, charset, urlbase; + std::string curl, eurl, name, mimetype, iurl, rcode; + std::string::size_type pos; + XMLTreeNode *root, *device, *service, *node, *snode, *icon; + int width = 0; + int height = 0; + int depth = 0; + bool servicefound = false; + + descurl = url; + urlbase = url.substr(7); + pos = urlbase.find("/"); + if (pos != std::string::npos) + urlbase=url.substr(0,pos+7); + else + urlbase=url; + + result = HTTP(url); + + pos = result.find("\r\n\r\n"); + + if (pos == std::string::npos) + throw std::runtime_error(std::string("no desc body")); + + head = result.substr(0,pos); + body = result.substr(pos+4); + + if (body == "") + throw std::runtime_error(std::string("desc body empty")); + + if (!check_response(head, charset, rcode)) + throw std::runtime_error(std::string("protocol error")); + + if (rcode != "200") + throw std::runtime_error(std::string("description url returned ") + rcode); + XMLTreeParser parser(charset.c_str()); + parser.Parse(body.c_str(), body.size(), 1); + root = parser.RootNode(); + if (!root) + throw std::runtime_error(std::string("XML: no root node")); + + if (strcmp(root->GetType(),"root")) + throw std::runtime_error(std::string("XML: no root")); + + for (node = root->GetChild(); node; node=node->GetNext()) + { + if (!strcmp(node->GetType(),"URLBase")) + { + urlbase = std::string(node->GetData()); + if ((urlbase.length() > 0) && (urlbase[urlbase.length()-1] == '/')) + urlbase.erase(urlbase.length()-1); + } + + } + + node = root->GetChild(); + if (!node) + throw std::runtime_error(std::string("XML: no root child")); + + while (strcmp(node->GetType(),"device")) + { + node = node->GetNext(); + if (!node) + throw std::runtime_error(std::string("XML: no device")); + } + device = node; + + for (node=device->GetChild(); node; node=node->GetNext()) + { + if (!strcmp(node->GetType(),"deviceType")) + devicetype = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"friendlyName")) + friendlyname = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"manufacturer")) + manufacturer = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"manufacturerURL")) + manufacturerurl = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"modelDescription")) + modeldescription = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"modelName")) + modelname = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"modelNumber")) + modelnumber = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"modelURL")) + modelurl = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"serialNumber")) + serialnumber = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"UDN")) + udn = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"UPC")) + upc = std::string(node->GetData()?node->GetData():""); + + if (!strcmp(node->GetType(),"iconList")) + { + for (icon=node->GetChild(); icon; icon=icon->GetNext()) + { + bool foundm = false; + bool foundw = false; + bool foundh = false; + bool foundd = false; + bool foundu = false; + + if (strcmp(icon->GetType(),"icon")) + throw std::runtime_error(std::string("XML: no icon")); + for (snode=icon->GetChild(); snode; snode=snode->GetNext()) + { + if (!strcmp(snode->GetType(),"mimetype")) + { + mimetype=std::string(snode->GetData()?snode->GetData():""); + foundm = true; + } + if (!strcmp(snode->GetType(),"width")) + { + width=snode->GetData()?atoi(snode->GetData()):0; + foundw = true; + } + if (!strcmp(snode->GetType(),"height")) + { + height=snode->GetData()?atoi(snode->GetData()):0; + foundh = true; + } + if (!strcmp(snode->GetType(),"depth")) + { + depth=snode->GetData()?atoi(snode->GetData()):0; + foundd = true; + } + if (!strcmp(snode->GetType(),"url")) + { + url=std::string(snode->GetData()?snode->GetData():""); + foundu = true; + } + } + if (!foundm) + throw std::runtime_error(std::string("XML: icon without mime")); + if (!foundw) + throw std::runtime_error(std::string("XML: icon without width")); + if (!foundh) + throw std::runtime_error(std::string("XML: icon without height")); + if (!foundd) + throw std::runtime_error(std::string("XML: icon without depth")); + if (!foundu) + throw std::runtime_error(std::string("XML: icon without url")); + UPnPIcon e={mimetype, url, width, height, depth}; + icons.push_back(e); + } + } + if (!strcmp(node->GetType(),"serviceList")) + { + servicefound = true; + for (service=node->GetChild(); service; service=service->GetNext()) + { + bool foundc = false; + bool founde = false; + bool foundn = false; + + if (strcmp(service->GetType(),"service")) + throw std::runtime_error(std::string("XML: no service")); + for (snode=service->GetChild(); snode; snode=snode->GetNext()) + { + if (!strcmp(snode->GetType(),"serviceType")) + { + name=std::string(snode->GetData()?snode->GetData():""); + foundn = true; + } + if (!strcmp(snode->GetType(),"eventSubURL")) + { + char *p; + p = snode->GetData(); + if (!p) + eurl=urlbase + "/"; + else if (p[0]=='/') + eurl=urlbase + std::string(p); + else + eurl=urlbase + "/" + std::string(p); + founde = true; + } + if (!strcmp(snode->GetType(),"controlURL")) + { + char *p; + p = snode->GetData(); + if (!p) + curl=urlbase + "/"; + else if (p[0]=='/') + curl=urlbase + std::string(p); + else + curl=urlbase + "/" + std::string(p); + foundc = true; + } + } + if (!foundn) + throw std::runtime_error(std::string("XML: no service type")); + if (!founde) + throw std::runtime_error(std::string("XML: no event url")); + if (!foundc) + throw std::runtime_error(std::string("XML: no control url")); + //try + { + services.push_back(CUPnPService(this, curl, eurl, name)); + } + //catch (std::runtime_error error) + //{ + // std::cout << "error " << error.what() << "\n"; + //} + } + } + } + if (!servicefound) + throw std::runtime_error(std::string("XML: no service list")); +} + +CUPnPDevice::~CUPnPDevice() +{ +} + +std::string CUPnPDevice::HTTP(std::string url, std::string post, std::string action) +{ + std::string portname; + std::string hostname; + std::string path; + int port, t_socket, result, received; + std::stringstream command, reply; + std::string commandstr, line; + struct sockaddr_in socktcp; + struct hostent *hp; + std::string::size_type pos1, pos2; + char buf[4096]; + + if (url.substr(0,7) != "http://") + return ""; + + url.erase(0,7); + + pos1 = url.find(":", 0); + pos2 = url.find("/", 0); + + if (pos2 == std::string::npos) + return ""; + if ((pos1 == std::string::npos) || (pos1 > pos2)) + { + hostname = url.substr(0,pos2); + port=80; + } + else + { + hostname = url.substr(0,pos1); + portname = url.substr(pos1+1, pos2-pos1-1); + port = atoi(portname.c_str()); + } + path = url.substr(pos2); + + if (post.size()) + command << "POST " << path << " HTTP/1.0\r\n"; + else + command << "GET " << path << " HTTP/1.0\r\n"; + + command << "Host: " << hostname << ":" << port << "\r\n"; + command << "User-Agent: TuxBox\r\n"; + command << "Accept: text/xml\r\n"; + command << "Connection: Close\r\n"; + + if (post.size()) + { + command << "Content-Length: " << post.size() << "\r\n"; + command << "Content-Type: text/xml\r\n"; + } + + if (action.size()) + command << "SOAPAction: \"" << action << "\"\r\n"; + + command << "\r\n"; + + if (post.size()) + command << post; + + t_socket = socket(PF_INET, SOCK_STREAM, 0); + if (!t_socket) + throw std::runtime_error(std::string("create TCP socket")); + + hp = gethostbyname(hostname.c_str()); + if (!hp) + throw std::runtime_error(std::string("resolve name")); + + memset(&socktcp, 0, sizeof(struct sockaddr_in)); + socktcp.sin_family = AF_INET; + socktcp.sin_port = htons(port); + memcpy((char *)&socktcp.sin_addr, hp->h_addr, hp->h_length); + + if (connect(t_socket, (struct sockaddr*) &socktcp, sizeof(struct sockaddr_in))) + { + close(t_socket); + throw std::runtime_error(std::string("connect")); + } + + commandstr = command.str(); + result = send(t_socket, commandstr.c_str(), commandstr.size(), 0); + while ((received = recv(t_socket, buf, sizeof(buf)-1, 0)) > 0) + { + buf[received] = 0; + reply << buf; + } + return reply.str(); +} + +std::list CUPnPDevice::SendSOAP(std::string servicename, std::string action, std::list attribs) +{ + std::list::iterator i; + std::list empty; + + for (i=services.begin(); i != services.end(); i++) + { + if (i->servicename == servicename) + return i->SendSOAP(action, attribs); + } + return empty; +} + +std::list CUPnPDevice::GetServices(void) +{ + std::list::iterator i; + std::list result; + + for (i=services.begin(); i != services.end(); i++) + result.push_back(i->servicename); + return result; +} + diff --git a/lib/libupnpclient/UPNPService.cpp b/lib/libupnpclient/UPNPService.cpp new file mode 100644 index 000000000..7944a8aa1 --- /dev/null +++ b/lib/libupnpclient/UPNPService.cpp @@ -0,0 +1,172 @@ +/*********************************************************************************** + * UPNPService.cpp + * + * Copyright (c) 2007 Jochen Friedrich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ***********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "upnpclient.h" + +CUPnPService::CUPnPService(CUPnPDevice* dev, std::string curl, std::string eurl, std::string name) +{ + device = dev; + controlurl = curl; + eventurl = eurl; + servicename = name; +} + +CUPnPService::~CUPnPService() +{ +} + +std::list CUPnPService::SendSOAP(std::string action, std::list attribs) +{ + std::stringstream post; + std::string soapaction; + std::string result, head, body, charset, envelope, soapbody, soapresponse, rcode; + std::list::iterator i; + std::list results; + XMLTreeNode *root, *node, *snode; + std::string::size_type pos; + + post << "\r\n" + "" + ""; + post << ""; + } else { + post << ">"; + for (i = attribs.begin(); i != attribs.end(); i++) + { + if (i->second == "") + post << "<" << i->first << "/>"; + else + { + post << "<" << i->first << ">"; + post << i->second; + post << "first << ">"; + } + } + post << ""; + } + post << "\r\n"; + soapaction = servicename + "#" + action; + result = device->HTTP(controlurl, post.str(), soapaction); + + pos = result.find("\r\n\r\n"); + + if (pos == std::string::npos) + throw std::runtime_error(std::string("no soap body")); + + head = result.substr(0,pos); + body = result.substr(pos+4); + + if (!device->check_response(head, charset, rcode)) + throw std::runtime_error(std::string("protocol error")); + + XMLTreeParser parser(charset.c_str()); + parser.Parse(body.c_str(), body.size(), 1); + root = parser.RootNode(); + if (!root) + throw std::runtime_error(std::string("XML: no root node")); + + envelope=std::string(root->GetType()); + pos = envelope.find(":"); + if (pos !=std::string::npos) + envelope.erase(0,pos+1); + + if (envelope != "Envelope") + throw std::runtime_error(std::string("XML: no envelope")); + + node = root->GetChild(); + if (!node) + throw std::runtime_error(std::string("XML: no envelope child")); + + soapbody=std::string(node->GetType()); + pos = soapbody.find(":"); + if (pos !=std::string::npos) + soapbody.erase(0,pos+1); + + if (soapbody != "Body") + throw std::runtime_error(std::string("XML: no soap body")); + + node = node->GetChild(); + if (!node) + throw std::runtime_error(std::string("XML: no soap body child")); + + soapresponse=std::string(node->GetType()); + pos = soapresponse.find(":"); + if (pos !=std::string::npos) + soapresponse.erase(0,pos+1); + + if (rcode != "200") + { + std::string faultstring, upnpcode, upnpdesc, errstr; + if (soapresponse != "Fault") + throw std::runtime_error(std::string("XML: http error without soap fault: ")+rcode); + for (node=node->GetChild(); node; node=node->GetNext()) + { + if (!strcmp(node->GetType(),"detail")) + { + snode=node->GetChild(); + if (snode) + for (snode=snode->GetChild(); snode; snode=snode->GetNext()) + { + errstr=snode->GetType(); + pos = errstr.find(":"); + if (pos !=std::string::npos) + errstr.erase(0,pos+1); + if (errstr=="errorCode") + upnpcode=std::string(snode->GetData()?snode->GetData():""); + if (errstr=="errorDescription") + upnpdesc=std::string(snode->GetData()?snode->GetData():""); + } + + } + if (!strcmp(node->GetType(),"faultstring")) + faultstring=std::string(node->GetData()?node->GetData():""); + } + if (faultstring != "") + throw std::runtime_error(faultstring + " " + upnpcode + " " + upnpdesc); + else + throw std::runtime_error(std::string("XML: http error with unknown soap: ")+rcode); + } + if (soapresponse != action + "Response") + throw std::runtime_error(std::string("XML: no soap response")); + + for (node=node->GetChild(); node; node=node->GetNext()) + results.push_back(UPnPAttribute(node->GetType(), node->GetData())); + + return results; +} diff --git a/lib/libupnpclient/UPNPSocket.cpp b/lib/libupnpclient/UPNPSocket.cpp new file mode 100644 index 000000000..b56e269f5 --- /dev/null +++ b/lib/libupnpclient/UPNPSocket.cpp @@ -0,0 +1,159 @@ +/*********************************************************************************** + * UPNPSocket.cpp + * + * Copyright (c) 2007 Jochen Friedrich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ***********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "upnpclient.h" + +CUPnPSocket::CUPnPSocket() +{ + struct sockaddr_in sockudp; + int opt=1; + + m_socket = socket(PF_INET, SOCK_DGRAM, 0); + if (!m_socket) + throw std::runtime_error(std::string("create UDP socket")); + + memset(&sockudp, 0, sizeof(struct sockaddr_in)); + sockudp.sin_family = AF_INET; + sockudp.sin_addr.s_addr = INADDR_ANY; + + if (setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) + { + close(m_socket); + throw std::runtime_error(std::string("socket option")); + } + + if (bind(m_socket, (struct sockaddr*) &sockudp, sizeof(struct sockaddr_in))) + { + close(m_socket); + throw std::runtime_error(std::string("bind")); + } +} + +CUPnPSocket::~CUPnPSocket() +{ + close(m_socket); +} + +void CUPnPSocket::SetTTL(int ttl) +{ + int result; + + result = setsockopt(m_socket, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl)); + if (!result) + throw std::runtime_error(std::string("set ttl")); +} + +std::vector CUPnPSocket::Discover(std::string service) +{ + struct sockaddr_in sockudp; + std::stringstream command, reply; + std::string commandstr, line; + std::vector devices; + int result; + std::string::size_type pos; + struct pollfd fds[1]; + char bufr[1536]; + + memset(&sockudp, 0, sizeof(struct sockaddr_in)); + sockudp.sin_family = AF_INET; + sockudp.sin_port = htons(MULTICAST_PORT); + sockudp.sin_addr.s_addr = inet_addr(MULTICAST_IP); + + command << "M-SEARCH * HTTP/1.1\r\n" << + "HOST: " << MULTICAST_IP << ":" << MULTICAST_PORT << "\r\n" << + "ST: " << service << "\r\n" << + "MAN: \"ssdp:discover\"\r\n" << + "MX: 3\r\n" << + "\r\n"; + + commandstr = command.str(); + result = sendto(m_socket, commandstr.c_str(), commandstr.size(), 0, (struct sockaddr*) &sockudp, sizeof(struct sockaddr_in)); + + if (result < 0) { + throw std::runtime_error(std::string(strerror(errno))); + } +// result = sendto(m_socket, commandstr.c_str(), commandstr.size(), 0, (struct sockaddr*) &sockudp, sizeof(struct sockaddr_in)); + + fds[0].fd = m_socket; + fds[0].events = POLLIN; + + for(;;) + { + result = poll(fds, 1, 4000); + if (result < 0) + throw std::runtime_error(std::string("poll")); + if (result == 0) + return devices; + + result = recv(m_socket, bufr, sizeof(bufr), 0); + if (result < 0) + throw std::runtime_error(std::string("recv")); + + bufr[result]=0; + + reply.clear(); + reply.str(std::string(bufr)); + + while (!reply.eof()) + { + getline(reply, line); + pos=line.find("\r", 0); + if (pos!=std::string::npos) + line.erase(pos); + std::string location = line.substr(0,9); + if (!strcasecmp(location.c_str(), "location:")) + { + line.erase(0, 9); + while ((line.length() > 0 )&& ((line[0] == ' ') || (line[0] == '\t'))) + line.erase(0, 1); + if (line.substr(0,7) == "http://") + { + std::vector::iterator i; + for (i=devices.begin(); i != devices.end(); i++) + if (line == i->descurl) + goto found; + try + { + devices.push_back(CUPnPDevice(line)); + } + catch (std::runtime_error error) + { + std::cout << "error " << error.what() << "\n"; + } + } + found: ; + } + } + } +} diff --git a/lib/libupnpclient/upnpclient.h b/lib/libupnpclient/upnpclient.h new file mode 100644 index 000000000..952f5cb9b --- /dev/null +++ b/lib/libupnpclient/upnpclient.h @@ -0,0 +1,119 @@ +/*********************************************************************************** + * upnpclient.h + * + * Copyright (c) 2007 Jochen Friedrich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ***********************************************************************************/ + +#ifndef __UPNP_H +#define __UPNP_H + +#include +#include +#include +#include + +#define MULTICAST_PORT 1900 +#define MULTICAST_IP "239.255.255.250" + +typedef std::pair UPnPAttribute; + +struct UPnPIcon +{ + std::string mimetype; + std::string url; + int width; + int heigth; + int depth; +}; + +class CUPnPService; + +/****************************************** + * Class: CUPnPDevice + ******************************************/ + +class CUPnPDevice +{ + friend class CUPnPService; + friend class CUPnPSocket; + +private: + std::string descurl; + std::list services; + std::string HTTP(std::string url,std::string post="", std::string action=""); + bool check_response(std::string header, std::string& charset, std::string& rcode); + std::list icons; + +public: + std::string friendlyname; + std::string devicetype; + std::string manufacturer; + std::string manufacturerurl; + std::string modeldescription; + std::string modelname; + std::string modelnumber; + std::string modelurl; + std::string serialnumber; + std::string udn; + std::string upc; + std::list SendSOAP(std::string service, std::string action, std::list attribs); + std::list GetServices(void); + std::list GetIcons() const { return icons; }; + + CUPnPDevice(std::string url); + ~CUPnPDevice(); +}; + +/****************************************** + * Class: CUPnPService + ******************************************/ + +class CUPnPService +{ + +public: + std::string controlurl; + std::string eventurl; + std::string servicename; + CUPnPDevice *device; + + CUPnPService(CUPnPDevice *dev, std::string curl, std::string eurl, std::string service); + ~CUPnPService(); + std::list SendSOAP(std::string action, std::list attribs); +}; + +/****************************************** + * Class: CUPnPSocket + ******************************************/ + +class CUPnPSocket +{ + +public: + CUPnPSocket(); + ~CUPnPSocket(); + + void SetTTL(int ttl); + std::vector Discover(std::string service); + +private: + int m_socket; + +}; + +#endif diff --git a/lib/sectionsdclient/Makefile.am b/lib/sectionsdclient/Makefile.am new file mode 100644 index 000000000..40b7fde20 --- /dev/null +++ b/lib/sectionsdclient/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/connection \ + -I$(top_srcdir)/lib/libeventserver + +noinst_LIBRARIES = libsectionsdclient.a + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +libsectionsdclient_a_SOURCES = sectionsdclient.cpp + +bin_PROGRAMS = sectionsdcontrol + +sectionsdcontrol_SOURCES = sectionsdcontrol.cpp +sectionsdcontrol_LDADD = \ + $(top_builddir)/lib/sectionsdclient/libsectionsdclient.a \ + $(top_builddir)/lib/connection/libtuxbox-connection.a diff --git a/lib/sectionsdclient/sectionsdMsg.h b/lib/sectionsdclient/sectionsdMsg.h new file mode 100644 index 000000000..e7123fb3d --- /dev/null +++ b/lib/sectionsdclient/sectionsdMsg.h @@ -0,0 +1,375 @@ +#ifndef SECTIONSDMSG_H +#define SECTIONSDMSG_H +// +// $Id: sectionsdMsg.h,v 1.16 2007/01/07 23:34:55 guenther Exp $ +// +// sectionsdMsg.h (header file with msg-definitions for sectionsd) +// (dbox-II-project) +// +// Copyright (C) 2001 by fnbrd, +// 2002 by thegoodguy +// +// Homepage: http://dbox2.elxsi.de +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include /* t_channel_id */ + + +#define SECTIONSD_UDS_NAME "/tmp/sectionsd.sock" + + +struct sectionsd +{ + static const CBasicMessage::t_version ACTVERSION = 5; + + struct msgRequestHeader + { + unsigned char version; + unsigned char command; + unsigned short stuff_bytes; + unsigned int dataLength; + } __attribute__ ((packed)) ; + + struct msgResponseHeader + { + unsigned int dataLength; + } __attribute__ ((packed)) ; + + enum commands + { + /* actualEPGchannelName=0,*/ + dummy1, + dummy3, //actualEventListTVshort, // commandEventListTV + /*currentNextInformation,*/ + dummy2, + dumpStatusinformation, // commandDumpStatusInformation + /*allEventsChannelName,*/ + allEventsChannelIDSearch, // commandAllEventsChannelIDSearch + dummy4, // setHoursToCache, + dummy5, // setHoursExtendedCache, + dummy6, // setEventsAreOldInMinutes, + dummy7, // dumpAllServices, // commandDumpAllServices + dummy8, // actualEventListRadioshort, // commandEventListRadio + dummy9, // getNextEPG, // commandGetNextEPG + dummy10,// getNextShort, // commandGetNextShort + pauseScanning, // commandPauseScanning // for the grabbers ;) + getIsScanningActive, // commandGetIsScanningActive + actualEPGchannelID, // commandActualEPGchannelID + actualEventListTVshortIDs, // commandEventListTVids + actualEventListRadioShortIDs, // commandEventListRadioIDs + currentNextInformationID, // commandCurrentNextInfoChannelID + epgEPGid, // commandEPGepgID + epgEPGidShort, // commandEPGepgIDshort + ComponentTagsUniqueKey, // commandComponentTagsUniqueKey + allEventsChannelID_, // commandAllEventsChannelID + timesNVODservice, // commandTimesNVODservice + getEPGPrevNext, // commandGetEPGPrevNext + getIsTimeSet, // commandGetIsTimeSet + serviceChanged, // commandserviceChanged + LinkageDescriptorsUniqueKey, // commandLinkageDescriptorsUniqueKey + pauseSorting, // commandPauseSorting + CMD_registerEvents, // commandRegisterEventClient + CMD_unregisterEvents, // commandUnRegisterEventClient +#ifdef ENABLE_PPT + setPrivatePid, // commandSetPrivatePid +#else + dummy11_setPrivatePid, +#endif + setSectionsdScanMode, // commandSetSectionsdScanMode + freeMemory, // commandFreeMemory + readSIfromXML, // commandReadSIfromXML + writeSI2XML, // commandWriteSI2XML + + LoadLanguages, // commandLoadLanguages + SaveLanguages, // commandSaveLanguages + SetLanguages, // commandSetLanguages + GetLanguages, // commandGetLanguages + SetLanguageMode, // commandSetLanguageMode + GetLanguageMode, // commandGetLanguageMode + setConfig, // commandSetConfig + Restart, // commandRestart + ping, + + numberOfCommands // <- no actual command, end of command marker + }; + + struct commandGetEPGid + { + unsigned long long eventid; + time_t starttime; + } __attribute__ ((packed)) ; + + struct commandSetServiceChanged + { + t_channel_id channel_id; + bool requestEvent; + }; + + struct responseIsTimeSet + { + bool IsTimeSet; + }; + + struct commandSetConfig + { + int scanMode; + int epg_cache; + int epg_old_events; + unsigned int epg_max_events; + int network_ntprefresh; + int network_ntpenable; + int epg_extendedcache; +// std::string network_ntpserver; +// std::string epg_dir; + }; + +}; + +// +// Description of Commands: +// +// If a command is recognize then sectionsd will always send a response. +// When requested datas are not found the data length of the response is 0. +// +// actualEPGchannelName: +// data of request: +// is channel name with trailing 0 (c-string) +// data of response: +// is a string (c-string) describing the EPG (for +// compatibility with old epgd) +// +// actualEventListTVshort: +// data of request: +// - +// data of response: +// is a string (c-string) with all cached actual events, +// 3 lines per service, first line unique-event-key, second line service name, third line event name +// +// currentNextInformation: +// data of request: +// is channel name with trailing 0 (c-string) +// data of response: +// is a string (c-string) describing the current/next EPGs +// +// dumpStatusinformation: +// data of request: +// - +// data of response: +// is a string (c-string) describing current status of sectionsd +// +// allEventsChannelName: +// data of request: +// is channel name with trailing 0 (c-string) +// data of response: +// is a string (c-string) describing the cached events for the requestet channel +// 1 line per event, format: uniqueEventKey DD.MM HH:MM durationInMinutes Event name +// +// setHoursToCache +// data of request: +// unsigned short (hours to cache) +// data of response: +// - +// +// setEventsAreOldInMinutes +// data of request: +// unsigned short (minutes after events are old (after their end time)) +// data of response: +// - +// +// dumpAllServicesinformation: +// data of request: +// - +// data of response: +// is a string (c-string) with all cached services +// 3 lines per service +// 1. line: unique-service-key, service-ID, service-type, eitScheduleFlag (bool), +// eitPresentFollowingFlag (bool), runningStatus (bool), +// freeCAmode (bool), number of nvod services +// 2. line: service name +// 3. line: provider name +// +// actualEventListRadioshort: +// data of request: +// - +// data of response: +// is a string (c-string) with all cached actual events, +// 3 lines per service, first line unique-event-key, second line service name, third line event name +// +// getNextEPG: +// data of request: +// 8 bytes (long long in 32 bit world) with unique key (binary) of the event for wich the next should be delivered +// 4 bytes with start time (ctime) of the above event +// data of response: +// is a string (c-string) describing the EPG: +// unique key (long long, hex) 0xff name 0xff text 0xff extended text 0xff start time GMT (ctime, hex ) 0xff duration (seconds, hex) +// +// getNextShort: +// data of request: +// 8 bytes (long long in 32 bit world) with unique key (binary) of the event for wich the next should be delivered +// 4 bytes with start time (ctime) of the above event +// data of response: +// is a string (c-string) describing the Event in short terms: +// 1. line unique key (long long, hex), 2. line name, 3. line start time GMT (ctime, hex ), 4 line duration (seconds, hex) +// +// pauseScanning: +// data of request: +// int (1 = pause, 0 = continue) +// data of response: +// - +// +// actualEPGchannelID: +// data of request: +// is channel ID +// data of response: +// is a string (c-string) describing the EPG: +// unique key (long long, hex) 0xff name 0xff text 0xff extended text 0xff start time GMT (ctime, hex ) 0xff duration (seconds, hex) 0xff +// +// actualEventListTVshortIDs: +// data of request: +// - +// data of response: +// for every service: +// 1. unique-service-key (4 bytes) +// 2. unique-event-key (8 bytes) +// 3. event name (c-string with 0) +// +// actualEventListRadioShortIDs: +// data of request: +// - +// data of response: +// 1. unique-service-key (4 bytes) +// 2. unique-event-key (8 bytes) +// 3. event name (c-string with 0) +// +// currentNextInformationID: +// data of request: +// 4 byte channel ID (4 byte, onid<<16+sid) +// 1 byte number of Events (noch nicht implementiert) +// data of response: +// is a string (c-string) describing the current/next EPGs +// every event: +// 1. 8 bytes unique key (unsigned long long), +// 2. struct sectionsdTime (8 bytes) +// 3. name (c-string with 0) +// +// epgEPGid: +// data of request: +// unique epg ID (8 byte) +// time_t starttime GMT (4 bytes) +// data of response: +// is a string (c-string) describing the EPG: +// name 0xff text 0xff extended text 0xff start time GMT (ctime, hex ) 0xff duration (seconds, hex) 0xff +// +// epgEPGidShort: +// data of request: +// unique epg ID (8 byte) +// data of response: +// is a string (c-string) describing the EPG: +// name 0xff text 0xff extended text 0xff +// +// CurrentComponentTags +// - gets all ComponentDescriptor-Tags for the currently running Event +// +// data of request: +// is channel ID (4 byte, onid<<16+sid) +// data of response: +// for each component-descriptor (zB %02hhx %02hhx %02hhx\n%s\n) +// componentTag +// componentType +// streamContent +// component.c_str +// +// allEventsChannelID: +// data of request: +// is channel ID +// data of response: +// is a string (c-string) describing the cached events for the requestet channel +// 1 line per event, format: uniqueEventKey DD.MM HH:MM durationInMinutes Event name +// +// timesNVODservice +// data of request: +// is channel ID +// data of response: +// for every (sub-)channel +// channelID (4 byte, onid<<16+sid) +// transportStreamID (2 byte) +// start time (4 bytes ctime) +// duration (4 bytes unsigned) +// +// getEPGPrevNext +// data of request: +// 8 bytes (long long in 32 bit world) with unique key (binary) of the event for wich the next should be delivered +// 4 bytes with start time (ctime) of the above event +// data of response: +// is a string (c-string) describing the EPG: +// unique key (long long, hex) 0xff start time GMT (ctime, hex ) for previous event +// unique key (long long, hex) 0xff start time GMT (ctime, hex ) for next event + +// +// LoadLanguages +// data of request: +// none +// data of response: +// success status (sizeof(bool)) +// +// SaveLanguages +// data of request: +// none +// data of response: +// success status (sizeof(bool)) +// +// SetLanguages +// data of request: +// n * 3 bytes (iso_639_2 language codes) +// data of response: +// success status (sizeof(bool)) +// +// GetLanguages +// data of request: +// none +// data of response: +// n * 3 bytes (iso_639_2 language codes) +// +// SetLanguageMode +// data of request: +// mode (sizeof(CSectionsdClient::SIlanguageMode_t), +// ALL, FIRST_FIRST, FIRST_ALL, ALL_FIRST or ALL_ALL) +// data of response: +// success status (sizeof(bool)) +// +// GetLanguageMode +// data of request: +// none +// data of response: +// mode (see above) +// +// setConfig +// data of request: +// int scanMode; -> updating of services and bouquets -> saved in auto_scanning +// int epg_cache; -> in days -> saved in secondsToCache +// int epg_old_events; -> in hours -> saved in oldEventsAre +// unsigned int epg_max_events; -> #of saved events -> saved in max_events +// int network_ntprefresh; -> time refresh intervall -> saved in ntprefresh +// int network_ntpenable; -> time refresh via ntp server -> saved in ntpenable +// std::string network_ntpserver; -> ntpserver -> saved in ntpserver +// std::string epg_dir; -> epg_dir to im/export the epg xml files -> saved in epg_file +// data of response: +// - + +#endif // SECTIONSDMSG_H diff --git a/lib/sectionsdclient/sectionsdclient.cpp b/lib/sectionsdclient/sectionsdclient.cpp new file mode 100644 index 000000000..9f73160b1 --- /dev/null +++ b/lib/sectionsdclient/sectionsdclient.cpp @@ -0,0 +1,803 @@ +/* + Client-Interface für zapit - DBoxII-Project + + $Id: sectionsdclient.cpp,v 1.53 2007/01/12 22:57:57 houdini Exp $ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include + +#include +#include + + +const unsigned char CSectionsdClient::getVersion () const +{ + return sectionsd::ACTVERSION; +} + +const char * CSectionsdClient::getSocketName() const +{ + return SECTIONSD_UDS_NAME; +} + +int CSectionsdClient::readResponse(char* data,unsigned int size) +{ + struct sectionsd::msgResponseHeader responseHeader; + if (!receive_data((char*)&responseHeader, sizeof(responseHeader))) + return 0; + + if ( data != NULL ) + { + if ( responseHeader.dataLength != (unsigned)size ) + return -1; + else + return receive_data(data, size); + } + else + return responseHeader.dataLength; +} + + +bool CSectionsdClient::send(const unsigned char command, const char* data, const unsigned int size) +{ + sectionsd::msgRequestHeader msgHead; + + msgHead.version = getVersion(); + msgHead.command = command; + msgHead.dataLength = size; + + open_connection(); // if the return value is false, the next send_data call will return false, too + + if (!send_data((char*)&msgHead, sizeof(msgHead))) + return false; + + if (size != 0) + return send_data(data, size); + + return true; +} + +void CSectionsdClient::registerEvent(const unsigned int eventID, const unsigned int clientID, const char * const udsName) +{ + CEventServer::commandRegisterEvent msg2; + + msg2.eventID = eventID; + msg2.clientID = clientID; + + strcpy(msg2.udsName, udsName); + + send(sectionsd::CMD_registerEvents, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} + +void CSectionsdClient::unRegisterEvent(const unsigned int eventID, const unsigned int clientID) +{ + CEventServer::commandUnRegisterEvent msg2; + + msg2.eventID = eventID; + msg2.clientID = clientID; + + send(sectionsd::CMD_unregisterEvents, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} + +bool CSectionsdClient::getIsTimeSet() +{ + sectionsd::responseIsTimeSet rmsg; + + if (send(sectionsd::getIsTimeSet)) + { + readResponse((char*)&rmsg, sizeof(rmsg)); + close_connection(); + + return rmsg.IsTimeSet; + } + else + { + close_connection(); + return false; + } +} + + +#if 0 +void CSectionsdClient::setEventsAreOldInMinutes(const unsigned short minutes) +{ + send(sectionsd::setEventsAreOldInMinutes, (char*)&minutes, sizeof(minutes)); + + readResponse(); + close_connection(); +} +#endif + +void CSectionsdClient::setPauseSorting(const bool doPause) +{ + int PauseIt = (doPause) ? 1 : 0; + + send(sectionsd::pauseSorting, (char*)&PauseIt, sizeof(PauseIt)); + + readResponse(); + close_connection(); +} + +void CSectionsdClient::setPauseScanning(const bool doPause) +{ + int PauseIt = (doPause) ? 1 : 0; + + send(sectionsd::pauseScanning, (char*)&PauseIt, sizeof(PauseIt)); + + readResponse(); + close_connection(); +} + +bool CSectionsdClient::getIsScanningActive() +{ + int scanning; + + if (send(sectionsd::getIsScanningActive)) + { + readResponse((char*)&scanning, sizeof(scanning)); + close_connection(); + + return scanning; + } + else + { + close_connection(); + return false; + } +} + +void CSectionsdClient::setServiceChanged(const t_channel_id channel_id, const bool requestEvent) +{ + sectionsd::commandSetServiceChanged msg; + + msg.channel_id = channel_id; + msg.requestEvent = requestEvent; + + send(sectionsd::serviceChanged, (char *)&msg, sizeof(msg)); + + readResponse(); + close_connection(); +} + + +bool CSectionsdClient::getComponentTagsUniqueKey(const event_id_t uniqueKey, CSectionsdClient::ComponentTagList& tags) +{ + if (send(sectionsd::ComponentTagsUniqueKey, (char*)&uniqueKey, sizeof(uniqueKey))) + { + tags.clear(); + + int nBufSize = readResponse(); + + char* pData = new char[nBufSize]; + receive_data(pData, nBufSize); + char* dp = pData; + + int count= *(int *) pData; + dp+= sizeof(int); + + CSectionsdClient::responseGetComponentTags response; + for (int i= 0; i 0) + { + char* pData = new char[nBufSize]; + receive_data(pData, nBufSize); + + char* dp = pData; + + while(dp < pData + nBufSize) + { + CChannelEvent aEvent; + + aEvent.eventID = *((event_id_t *) dp); + dp+=sizeof(aEvent.eventID); + + aEvent.startTime = *((time_t *) dp); + dp+=sizeof(aEvent.startTime); + + aEvent.duration = *((unsigned *) dp); + dp+=sizeof(aEvent.duration); + + aEvent.description= dp; + dp+=strlen(dp)+1; + + aEvent.text= dp; + dp+=strlen(dp)+1; + + eList.push_back(aEvent); + } + delete[] pData; + } + } + close_connection(); + return eList; +} + +//GU:EPG +/* This function does initiate a search for a keyword in all EPG Event of the Channel channel_id in sectionsd. + The parameter search_typ does specify the search mode + 0: none -> all EPG events of the channel are returned + 1: keyword search in EPG Title + 2: keyword search in EPG short description (INFO1) + 3: keyword search in EPG description (INFO2) + In case of a match, the EPG event is added to the Eventlist eList. + */ +bool CSectionsdClient::getEventsServiceKeySearchAdd(CChannelEventList& eList,const t_channel_id channel_id,char search_typ,std::string& search_text) +{ + int nBufSize=0; + + nBufSize += sizeof(t_channel_id); + nBufSize += sizeof(char); + nBufSize += search_text.size()+1; + + char* pSData = new char[nBufSize]; + char* pSData_ptr = pSData; + + *(t_channel_id*)pSData_ptr = channel_id; + pSData_ptr += sizeof(t_channel_id); + *pSData_ptr = search_typ; + pSData_ptr += sizeof(char); + strcpy(pSData_ptr,search_text.c_str()); + + if (send(sectionsd::allEventsChannelIDSearch, pSData, nBufSize)) + { + int nBufSize = readResponse(); + + if( nBufSize > 0) + { + char* pData = new char[nBufSize]; + receive_data(pData, nBufSize); + + char* dp = pData; + +// int a = eList.size(); + + while(dp < pData + nBufSize) + { + CChannelEvent aEvent; + + aEvent.eventID = *((event_id_t *) dp); + dp+=sizeof(aEvent.eventID); + + aEvent.startTime = *((time_t *) dp); + dp+=sizeof(aEvent.startTime); + + aEvent.duration = *((unsigned *) dp); + dp+=sizeof(aEvent.duration); + + aEvent.description= dp; + dp+=aEvent.description.length()+1; + + aEvent.text= dp; + dp+=aEvent.text.length()+1; + + eList.push_back(aEvent); + } +// int b = eList.size() -a; + delete[] pData; + } + } + delete[] pSData; + + close_connection(); + return true; +} + +CChannelEventList CSectionsdClient::getEventsServiceKey(const t_channel_id channel_id) +{ + CChannelEventList eList; + + if (send(sectionsd::allEventsChannelID_, (char*)&channel_id, sizeof(channel_id))) + { + int nBufSize = readResponse(); + + if( nBufSize > 0) + { + char* pData = new char[nBufSize]; + receive_data(pData, nBufSize); + + char* dp = pData; + + while(dp < pData + nBufSize) + { + CChannelEvent aEvent; + + aEvent.eventID = *((event_id_t *) dp); + dp+=sizeof(aEvent.eventID); + + aEvent.startTime = *((time_t *) dp); + dp+=sizeof(aEvent.startTime); + + aEvent.duration = *((unsigned *) dp); + dp+=sizeof(aEvent.duration); + + aEvent.description= dp; + dp+=strlen(dp)+1; + + aEvent.text= dp; + dp+=strlen(dp)+1; + + eList.push_back(aEvent); + } + delete[] pData; + } + } + + close_connection(); + return eList; +} +void showhexdumpa (char *label, unsigned char * from, int len) +{ + int i, j, k; + char buf[128]; + char abuf[128]; + unsigned char fl, ol; + + fl = len / 16; + ol = len % 16; + if (label) { + time_t tt = time (0); + printf("\n%s -- %s", label, ctime (&tt)); + printf("----------------------------------------------------\n"); + } + + for (i = 0; i < fl; i++) { + j = i * 16; + sprintf (buf, "%03X: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", i * 16, from[j + 0], from[j + 1], from[j + 2], from[j + 3], from[j + 4], from[j + 5], from[j + 6], from[j + 7], from[j + 8], from[j + 9], from[j + 10], from[j + 11], from[j + 12], from[j + 13], from[j + 14], from[j + 15]); + printf ("%s ", buf); + for (k = 0; k < 16; k++) { + abuf[k] = (from[j + k] >= 0x20 && from[j + k] <= 0x7b) ? from[j + k] : 0x2E; + } + abuf[16] = 0; + printf("%s\n", abuf); + } + if (ol) { + j = fl * 16; + sprintf (buf, "%03X: ", j); + for (i = 0; i < ol; i++) { + sprintf (&buf[5 + i * 3], "%02x ", from[j + i]); + abuf[i] = (from[j + i] >= 0x20 && from[j + i] <= 0x7b) ? from[j + i] : 0x2E; + } + abuf[ol] = 0; + for (i = ol; i < 16; i++) + sprintf (&buf[5 + i * 3], " "); + printf ("%s ", buf); + printf ("%s\n", abuf); + } + printf ("\n"); +} + +// 21.07.2005 - rainerk +// Convert line-terminated extended events to vector of strings +char * CSectionsdClient::parseExtendedEvents(char * dp, CEPGData * epgdata) { + char * pItemDescriptions = dp, * pItemDescriptionStart; + dp+=strlen(dp)+1; + char * pItems = dp, * pItemStart; + dp+=strlen(dp)+1; + /* Clear vector since epgdata seems to be reused */ + epgdata->itemDescriptions.clear(); + while (*pItemDescriptions) { + pItemDescriptionStart = pItemDescriptions; + while (*pItemDescriptions && '\n' != *pItemDescriptions) { + pItemDescriptions++; + } + char pp = *pItemDescriptions; + *pItemDescriptions = 0; + epgdata->itemDescriptions.push_back(pItemDescriptionStart); +/*printf("CSectionsdClient::parseExtendedEvents: desc %s\n", pItemDescriptionStart);*/ + if(!pp) + break; + pItemDescriptions++; + } + /* Clear vector since epgdata seems to be reused */ + epgdata->items.clear(); + while (*pItems) { + pItemStart = pItems; + while (*pItems && '\n' != *pItems) { + pItems++; + } + char pp = *pItemDescriptions; + *pItems = 0; + epgdata->items.push_back(pItemStart); +/*printf("CSectionsdClient::parseExtendedEvents: item %s\n", pItemStart);*/ + if(!pp) + break; + pItems++; + } + return dp; +} + +bool CSectionsdClient::getActualEPGServiceKey(const t_channel_id channel_id, CEPGData * epgdata) +{ + epgdata->title = ""; + + if (send(sectionsd::actualEPGchannelID, (char*)&channel_id, sizeof(channel_id))) + { + int nBufSize = readResponse(); + if( nBufSize > 0) + { + char* pData = new char[nBufSize]; + receive_data(pData, nBufSize); + close_connection(); + + char* dp = pData; + + epgdata->eventID = *((event_id_t *)dp); + dp+= sizeof(epgdata->eventID); + + epgdata->title = dp; + dp+=strlen(dp)+1; + epgdata->info1 = dp; + dp+=strlen(dp)+1; + epgdata->info2 = dp; + dp+=strlen(dp)+1; + // 21.07.2005 - rainerk + // Convert line-terminated extended events to vector of strings +//showhexdumpa("Data:", (unsigned char *)pData, nBufSize); + dp = parseExtendedEvents(dp, epgdata); + + // *dp is the length, dp+1 is the chararray[] + epgdata->contentClassification = std::string(dp+1, *dp); + dp+=*dp+1; + epgdata->userClassification = std::string(dp+1, *dp); + dp+=*dp+1; + + epgdata->fsk = *dp++; + + epgdata->epg_times.startzeit = ((CSectionsdClient::sectionsdTime *) dp)->startzeit; + epgdata->epg_times.dauer = ((CSectionsdClient::sectionsdTime *) dp)->dauer; + dp+= sizeof(CSectionsdClient::sectionsdTime); + + delete[] pData; + return true; + } + else + printf("no response from sectionsd\n"); + } + + close_connection(); + + return false; +} + + +bool CSectionsdClient::getEPGid(const event_id_t eventid, const time_t starttime, CEPGData * epgdata) +{ + sectionsd::commandGetEPGid msg; + + msg.eventid = eventid; + msg.starttime = starttime; + + if (send(sectionsd::epgEPGid, (char *)&msg, sizeof(msg))) + { + int nBufSize = readResponse(); + if (nBufSize > 0) + { + char* pData = new char[nBufSize]; + receive_data(pData, nBufSize); + close_connection(); + + char* dp = pData; + + epgdata->eventID = *((event_id_t *)dp); + dp+= sizeof(epgdata->eventID); + + epgdata->title = dp; + dp+=strlen(dp)+1; + epgdata->info1 = dp; + dp+=strlen(dp)+1; + epgdata->info2 = dp; + dp+=strlen(dp)+1; + // 21.07.2005 - rainerk + // Convert line-terminated extended events to vector of strings + dp = parseExtendedEvents(dp, epgdata); + + // *dp is the length, dp+1 is the chararray[] + epgdata->contentClassification = std::string(dp+1, *dp); + dp+=*dp+1; + epgdata->userClassification = std::string(dp+1, *dp); + dp+=*dp+1; + + epgdata->fsk = *dp++; + + epgdata->epg_times.startzeit = ((CSectionsdClient::sectionsdTime *) dp)->startzeit; + epgdata->epg_times.dauer = ((CSectionsdClient::sectionsdTime *) dp)->dauer; + dp+= sizeof(CSectionsdClient::sectionsdTime); + + delete[] pData; + return true; + } + else + printf("no response from sectionsd\n"); + } + + close_connection(); + + return false; +} + + +bool CSectionsdClient::getEPGidShort(const event_id_t eventid, CShortEPGData * epgdata) +{ + if (send(sectionsd::epgEPGidShort, (char*)&eventid, sizeof(eventid))) + { + int nBufSize = readResponse(); + if( nBufSize > 0) + { + char* pData = new char[nBufSize]; + receive_data(pData, nBufSize); + + close_connection(); + + char* dp = pData; + + for(int i = 0; i < nBufSize;i++) + if(((unsigned char)pData[i]) == 0xff) + pData[i] = 0; + + epgdata->title = dp; + dp+=strlen(dp)+1; + epgdata->info1 = dp; + dp+=strlen(dp)+1; + epgdata->info2 = dp; + dp+=strlen(dp)+1; +// printf("titel: %s\n",epgdata->title.c_str()); + + + delete[] pData; + return true; + } + else + printf("no response from sectionsd\n"); + } + + close_connection(); + + return false; +} +#ifdef ENABLE_PPT +void CSectionsdClient::setPrivatePid(const unsigned short pid) +{ + send(sectionsd::setPrivatePid, (char*)&pid, sizeof(pid)); + + readResponse(); + close_connection(); +} +#endif +#if 0 +void CSectionsdClient::setSectionsdScanMode(const int scanMode) +{ + send(sectionsd::setSectionsdScanMode, (char*)&scanMode, sizeof(scanMode)); + + readResponse(); + close_connection(); +} +#endif + +void CSectionsdClient::freeMemory() +{ + send(sectionsd::freeMemory); + + readResponse(); + close_connection(); +} + +void CSectionsdClient::readSIfromXML(const char * epgxmlname) +{ + send(sectionsd::readSIfromXML, (char*) epgxmlname, strlen(epgxmlname)); + + readResponse(); + close_connection(); +} + +void CSectionsdClient::writeSI2XML(const char * epgxmlname) +{ + send(sectionsd::writeSI2XML, (char*) epgxmlname, strlen(epgxmlname)); + + readResponse(); + close_connection(); +} + +void CSectionsdClient::setConfig(const epg_config config) +{ + sectionsd::commandSetConfig *msg; + char* pData = new char[sizeof(sectionsd::commandSetConfig) + config.network_ntpserver.length() + 1 + config.epg_dir.length() + 1]; + msg = (sectionsd::commandSetConfig *)pData; + + msg->scanMode = config.scanMode; + msg->epg_cache = config.epg_cache; + msg->epg_old_events = config.epg_old_events; + msg->epg_max_events = config.epg_max_events; + msg->network_ntprefresh = config.network_ntprefresh; + msg->network_ntpenable = config.network_ntpenable; + msg->epg_extendedcache = config.epg_extendedcache; +// config.network_ntpserver: + strcpy(&pData[sizeof(sectionsd::commandSetConfig)], config.network_ntpserver.c_str()); +// config.epg_dir: + strcpy(&pData[sizeof(sectionsd::commandSetConfig) + config.network_ntpserver.length() + 1], config.epg_dir.c_str()); + + send(sectionsd::setConfig, (char*)pData, sizeof(sectionsd::commandSetConfig) + config.network_ntpserver.length() + 1 + config.epg_dir.length() + 1); + readResponse(); + close_connection(); + delete[] pData; +} + +void CSectionsdClient::dumpStatus() +{ + send(sectionsd::dumpStatusinformation); + close_connection(); +} diff --git a/lib/sectionsdclient/sectionsdclient.h b/lib/sectionsdclient/sectionsdclient.h new file mode 100644 index 000000000..458a2f764 --- /dev/null +++ b/lib/sectionsdclient/sectionsdclient.h @@ -0,0 +1,251 @@ +#ifndef __sectionsdclient__ +#define __sectionsdclient__ +/* + Client-Interface für zapit - DBoxII-Project + + $Id: sectionsdclient.h,v 1.42 2007/01/12 22:57:57 houdini Exp $ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include + +#include + +class CShortEPGData +{ + public: + std::string title; + std::string info1; + std::string info2; + + CShortEPGData() + { + title = ""; + info1 = ""; + info2 = ""; + }; +}; + +class CEPGData; + +class CChannelEvent +{ + public: + t_channel_id get_channel_id(void) const { return GET_CHANNEL_ID_FROM_EVENT_ID(eventID); } + event_id_t eventID; + std::string description; + std::string text; + time_t startTime; + unsigned duration; +}; + +typedef std::vector CChannelEventList; + +class CSectionsdClient : private CBasicClient +{ + private: + virtual const unsigned char getVersion () const; + virtual const char * getSocketName() const; + + int readResponse(char* data = NULL, unsigned int size = 0); + bool send(const unsigned char command, const char* data = NULL, const unsigned int size = 0); + char * parseExtendedEvents(char * dp, CEPGData * epgdata); + + public: + enum SIlanguageMode_t { + ALL, + FIRST_FIRST, + FIRST_ALL, + ALL_FIRST, + ALL_ALL, + LANGUAGE_MODE_OFF + }; + + enum events + { + EVT_TIMESET, + EVT_GOT_CN_EPG, + EVT_SERVICES_UPDATE, + EVT_BOUQUETS_UPDATE, + EVT_WRITE_SI_FINISHED + }; + + struct epgflags { + enum + { + has_anything = 0x01, + has_later = 0x02, + has_current = 0x04, + not_broadcast = 0x08, + has_next = 0x10, + has_no_current= 0x20, + current_has_linkagedescriptors= 0x40 + }; + }; + + struct responseGetComponentTags + { + std::string component; // Text aus dem Component Descriptor + unsigned char componentType; // Component Descriptor + unsigned char componentTag; // Component Descriptor + unsigned char streamContent; // Component Descriptor + }; + typedef std::vector ComponentTagList; + + struct responseGetLinkageDescriptors + { + std::string name; + t_transport_stream_id transportStreamId; + t_original_network_id originalNetworkId; + t_service_id serviceId; + }; + typedef std::vector LinkageDescriptorList; + + struct sectionsdTime + { + time_t startzeit; + unsigned dauer; + } __attribute__ ((packed)) ; + + struct responseGetNVODTimes + { + t_service_id service_id; + t_original_network_id original_network_id; + t_transport_stream_id transport_stream_id; + CSectionsdClient::sectionsdTime zeit; + }; + typedef std::vector NVODTimesList; + + struct responseGetCurrentNextInfoChannelID + { + event_id_t current_uniqueKey; + CSectionsdClient::sectionsdTime current_zeit; + std::string current_name; + char current_fsk; + event_id_t next_uniqueKey; + CSectionsdClient::sectionsdTime next_zeit; + std::string next_name; + unsigned flags; + }; + + struct CurrentNextInfo : public responseGetCurrentNextInfoChannelID + {}; + + typedef struct + { + int scanMode; + int epg_cache; + int epg_old_events; + int epg_max_events; + int network_ntprefresh; + int network_ntpenable; + int epg_extendedcache; + std::string network_ntpserver; + std::string epg_dir; + } epg_config; + + bool getComponentTagsUniqueKey(const event_id_t uniqueKey, CSectionsdClient::ComponentTagList& tags); + + bool getLinkageDescriptorsUniqueKey(const event_id_t uniqueKey, CSectionsdClient::LinkageDescriptorList& descriptors); + + bool getNVODTimesServiceKey(const t_channel_id channel_id, CSectionsdClient::NVODTimesList& nvod_list); + + bool getCurrentNextServiceKey(const t_channel_id channel_id, CSectionsdClient::responseGetCurrentNextInfoChannelID& current_next); + + bool getIsTimeSet(); + +// void setEventsAreOldInMinutes(const unsigned short minutes); + + void setPauseScanning(const bool doPause); + + bool getIsScanningActive(); + + void setPauseSorting(const bool doPause); + + void setServiceChanged(const t_channel_id channel_id, const bool requestEvent); + + CChannelEventList getChannelEvents(const bool tv_mode = true, t_channel_id* = NULL, int size = 0); + + CChannelEventList getEventsServiceKey(const t_channel_id channel_id); + + bool getEventsServiceKeySearchAdd(CChannelEventList& evtlist,const t_channel_id channel_id,char m_search_typ,std::string& m_search_text); + + bool getEPGid(const event_id_t eventid, const time_t starttime, CEPGData * epgdata); + + bool getActualEPGServiceKey(const t_channel_id channel_id, CEPGData * epgdata); + + bool getEPGidShort(const event_id_t eventid, CShortEPGData * epgdata); + + void setPrivatePid(const unsigned short pid); + +// void setSectionsdScanMode(const int scanMode); + + void freeMemory(); + + void readSIfromXML(const char * epgxmlname); + + void writeSI2XML(const char * epgxmlname); + + /* + ein beliebiges Event anmelden + */ + void registerEvent(const unsigned int eventID, const unsigned int clientID, const char * const udsName); + + /* + ein beliebiges Event abmelden + */ + void unRegisterEvent(const unsigned int eventID, const unsigned int clientID); + + void setConfig(const epg_config config); + void dumpStatus(void); + +}; + +class CEPGData +{ + public: + unsigned long long eventID; + CSectionsdClient::sectionsdTime epg_times; + std::string title; + std::string info1; + std::string info2; + // 21.07.2005 - extended event data + std::vector itemDescriptions; + std::vector items; + char fsk; + std::string contentClassification; + std::string userClassification; + + CEPGData() + { + eventID = 0; + title = ""; + info1 = ""; + info2 = ""; + fsk = 0; + contentClassification = ""; + userClassification = ""; + }; + +}; + +#endif diff --git a/lib/sectionsdclient/sectionsdcontrol.cpp b/lib/sectionsdclient/sectionsdcontrol.cpp new file mode 100644 index 000000000..fb40c867b --- /dev/null +++ b/lib/sectionsdclient/sectionsdcontrol.cpp @@ -0,0 +1,75 @@ +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/lib/sectionsdclient/sectionsdcontrol.cpp,v 1.2 2003/06/18 12:19:22 alexw Exp $ + * + * Sectionsd command line interface - The Tuxbox Project + * + * (C) 2003 by thegoodguy + * + * License: GPL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +#include + +CSectionsdClient client; + +int main(int argc, char** argv) +{ + for (int i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "--pause")) + { + printf("setPauseScanning true\n"); + client.setPauseScanning(true); + } + else + if (!strcmp(argv[i], "--nopause")) + { + printf("setPauseScanning false\n"); + client.setPauseScanning(false); + } + else + if (!strcmp(argv[i], "--state")) + printf("Scanning is active: %s\n", client.getIsScanningActive()?"true":"false"); + else + if (!strcmp(argv[i], "--saveepg")) { + if(argv[i+1]) { + char path[255]; + sprintf(path, "%s/", argv[i+1]); + printf("writing epg cache to %s...\n", path); + client.writeSI2XML(path); + } + } + else + if (!strcmp(argv[i], "--readepg")) { + if(argv[i+1]) { + char path[255]; + sprintf(path, "%s/", argv[i+1]); + printf("Reading epg cache from %s....\n", path); + client.readSIfromXML(path); + } + } + else + if (!strcmp(argv[i], "--dump")) { + client.dumpStatus(); + } + } + + return 0; +} diff --git a/lib/sectionsdclient/sectionsdtypes.h b/lib/sectionsdclient/sectionsdtypes.h new file mode 100644 index 000000000..54f07fecb --- /dev/null +++ b/lib/sectionsdclient/sectionsdtypes.h @@ -0,0 +1,33 @@ +/* + * $Id: sectionsdtypes.h,v 1.1 2004/02/13 14:36:19 thegoodguy Exp $ + * + * sectionsd's types which are used by the clientlib - d-box2 linux project + * + * (C) 2004 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __sectionsdtypes_h__ +#define __sectionsdtypes_h__ + +#include /* t_channel_id, t_service_id, t_original_network_id, t_transport_stream_id; */ + +typedef uint64_t event_id_t; +#define CREATE_EVENT_ID(channel_id,event_nr) ((((event_id_t)channel_id) << 16) | event_nr) +#define GET_CHANNEL_ID_FROM_EVENT_ID(event_id) ((t_channel_id)((event_id) >> 16)) + +#endif /* __sectionsdtypes_h__ */ diff --git a/lib/timerdclient/Makefile.am b/lib/timerdclient/Makefile.am new file mode 100644 index 000000000..ead4c2c73 --- /dev/null +++ b/lib/timerdclient/Makefile.am @@ -0,0 +1,11 @@ +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/connection \ + -I$(top_srcdir)/lib/libeventserver + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +noinst_LIBRARIES = libtimerdclient.a + +libtimerdclient_a_SOURCES = timerdclient.cpp diff --git a/lib/timerdclient/timerdclient.cpp b/lib/timerdclient/timerdclient.cpp new file mode 100644 index 000000000..3348b32f6 --- /dev/null +++ b/lib/timerdclient/timerdclient.cpp @@ -0,0 +1,483 @@ +/* + Timer Daemon - DBoxII-Project + + Copyright (C) 2002 Dirk Szymanski 'Dirch' + + $Id: timerdclient.cpp,v 1.55 2007/10/09 20:46:05 guenther Exp $ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +#include +#include +#include + + +const unsigned char CTimerdClient::getVersion () const +{ + return CTimerdMsg::ACTVERSION; +} + +const char * CTimerdClient::getSocketName() const +{ + return TIMERD_UDS_NAME; +} + +//------------------------------------------------------------------------- + +void CTimerdClient::registerEvent(unsigned int eventID, unsigned int clientID, const char * const udsName) +{ + CEventServer::commandRegisterEvent msg2; + + msg2.eventID = eventID; + msg2.clientID = clientID; + + strcpy(msg2.udsName, udsName); + + send(CTimerdMsg::CMD_REGISTEREVENT, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} +//------------------------------------------------------------------------- + +void CTimerdClient::unRegisterEvent(unsigned int eventID, unsigned int clientID) +{ + CEventServer::commandUnRegisterEvent msg2; + + msg2.eventID = eventID; + msg2.clientID = clientID; + + send(CTimerdMsg::CMD_UNREGISTEREVENT, (char*)&msg2, sizeof(msg2)); + + close_connection(); +} +//------------------------------------------------------------------------- + +int CTimerdClient::setSleeptimer(time_t announcetime, time_t alarmtime, int timerid) +{ + int timerID; + + if(timerid == 0) + timerID = getSleeptimerID(); + else + timerID = timerid; + + if(timerID != 0) + { + modifyTimerEvent(timerID, announcetime, alarmtime, 0); + } + else + { + timerID = addTimerEvent(CTimerd::TIMER_SLEEPTIMER,NULL,announcetime,alarmtime,0); + } + + return timerID; +} +//------------------------------------------------------------------------- + +int CTimerdClient::getSleeptimerID() +{ + send(CTimerdMsg::CMD_GETSLEEPTIMER); + CTimerdMsg::responseGetSleeptimer response; + if(!receive_data((char*)&response, sizeof(CTimerdMsg::responseGetSleeptimer))) + response.eventID =0; + close_connection(); + return response.eventID; +} +//------------------------------------------------------------------------- + +int CTimerdClient::getSleepTimerRemaining() +{ + int timerID; + if((timerID = getSleeptimerID()) != 0) + { + CTimerd::responseGetTimer timer; + getTimer( timer, timerID); + int min=(((timer.alarmTime + 1 - time(NULL)) / 60)+1); //aufrunden auf n�chst gr��erere Min. + if(min <1) + min=1; + return min; + } + else + return 0; +} +//------------------------------------------------------------------------- + +void CTimerdClient::getTimerList(CTimerd::TimerList &timerlist) +{ + CTimerdMsg::generalInteger responseInteger; + CTimerd::responseGetTimer response; + + send(CTimerdMsg::CMD_GETTIMERLIST); + + timerlist.clear(); + + if (CBasicClient::receive_data((char* )&responseInteger, sizeof(responseInteger))) + { + while (responseInteger.number-- > 0) + { + if (CBasicClient::receive_data((char*)&response, sizeof(response))) + if (response.eventState != CTimerd::TIMERSTATE_TERMINATED) + timerlist.push_back(response); + }; + } + + close_connection(); +} +//------------------------------------------------------------------------- + +void CTimerdClient::getTimer( CTimerd::responseGetTimer &timer, unsigned timerID) +{ + send(CTimerdMsg::CMD_GETTIMER, (char*)&timerID, sizeof(timerID)); + + CTimerd::responseGetTimer response; + receive_data((char*)&response, sizeof(CTimerd::responseGetTimer)); + timer = response; + close_connection(); +} +//------------------------------------------------------------------------- + + +bool CTimerdClient::modifyTimerEvent(int eventid, time_t announcetime, time_t alarmtime, time_t stoptime, CTimerd::CTimerEventRepeat evrepeat, uint32_t repeatcount) +{ + return modifyTimerEvent(eventid,announcetime,alarmtime,stoptime,evrepeat,repeatcount,NULL); +} +//------------------------------------------------------------------------- + +bool CTimerdClient::modifyTimerEvent(int eventid, time_t announcetime, time_t alarmtime, time_t stoptime, CTimerd::CTimerEventRepeat evrepeat, uint32_t repeatcount, void *data, + int datalen) +{ + // set new time values for event eventid + + CTimerdMsg::commandModifyTimer msgModifyTimer; + msgModifyTimer.eventID = eventid; + msgModifyTimer.announceTime = announcetime; + msgModifyTimer.alarmTime = alarmtime; + msgModifyTimer.stopTime = stoptime; + msgModifyTimer.eventRepeat = evrepeat; + msgModifyTimer.repeatCount = repeatcount; + send(CTimerdMsg::CMD_MODIFYTIMER, (char*) &msgModifyTimer, sizeof(msgModifyTimer)); + + if (data && datalen) + send_data((char*)data,datalen); + + CTimerdMsg::responseStatus response; + receive_data((char*)&response, sizeof(response)); + + close_connection(); + return true; +} +//------------------------------------------------------------------------- + +bool CTimerdClient::modifyRecordTimerEvent(int eventid, time_t announcetime, time_t alarmtime, time_t stoptime, CTimerd::CTimerEventRepeat evrepeat, uint32_t repeatcount, + const char * const recordingdir) +{ + CTimerdMsg::commandRecordDir rdir; + strncpy(rdir.recDir,recordingdir,RECORD_DIR_MAXLEN-1); + return modifyTimerEvent(eventid,announcetime,alarmtime,stoptime,evrepeat,repeatcount,&rdir,sizeof(rdir)); +} +//------------------------------------------------------------------------- + +bool CTimerdClient::rescheduleTimerEvent(int eventid, time_t diff) +{ + rescheduleTimerEvent(eventid,diff,diff,diff); + return true; +} +//------------------------------------------------------------------------- + +bool CTimerdClient::rescheduleTimerEvent(int eventid, time_t announcediff, time_t alarmdiff, time_t stopdiff) +{ + CTimerdMsg::commandModifyTimer msgModifyTimer; + msgModifyTimer.eventID = eventid; + msgModifyTimer.announceTime = announcediff; + msgModifyTimer.alarmTime = alarmdiff; + msgModifyTimer.stopTime = stopdiff; + + send(CTimerdMsg::CMD_RESCHEDULETIMER, (char*) &msgModifyTimer, sizeof(msgModifyTimer)); + + CTimerdMsg::responseStatus response; + receive_data((char*)&response, sizeof(response)); + + close_connection(); + return response.status; +} +//------------------------------------------------------------------------- + +/* +int CTimerdClient::addTimerEvent( CTimerEventTypes evType, void* data , int min, int hour, int day, int month, CTimerd::CTimerEventRepeat evrepeat) +{ + time_t actTime_t; + time(&actTime_t); + struct tm* actTime = localtime(&actTime_t); + + actTime->tm_min = min; + actTime->tm_hour = hour; + + if (day > 0) + actTime->tm_mday = day; + if (month > 0) + actTime->tm_mon = month -1; + + addTimerEvent(evType,true,data,0,mktime(actTime),0); +} +*/ +//------------------------------------------------------------------------- +int CTimerdClient::addTimerEvent( CTimerd::CTimerEventTypes evType, void* data, time_t announcetime, time_t alarmtime,time_t stoptime, + CTimerd::CTimerEventRepeat evrepeat, uint32_t repeatcount,bool forceadd) +{ + + if (!forceadd) + { + //printf("[CTimerdClient] checking for overlapping timers\n"); + CTimerd::TimerList overlappingTimer; + overlappingTimer = getOverlappingTimers(alarmtime, stoptime); + if (overlappingTimer.size() > 0) + { + // timerd starts eventID at 0 so we can return -1 + return -1; + } + } + + CTimerd::TransferEventInfo tei; + CTimerd::TransferRecordingInfo tri; + CTimerdMsg::commandAddTimer msgAddTimer; + msgAddTimer.alarmTime = alarmtime; + msgAddTimer.announceTime = announcetime; + msgAddTimer.stopTime = stoptime; + msgAddTimer.eventType = evType; + msgAddTimer.eventRepeat = evrepeat; + msgAddTimer.repeatCount = repeatcount; + int length; + if( evType == CTimerd::TIMER_SHUTDOWN || evType == CTimerd::TIMER_SLEEPTIMER ) + { + length = 0; + } + else if(evType == CTimerd::TIMER_NEXTPROGRAM || evType == CTimerd::TIMER_ZAPTO || + evType == CTimerd::TIMER_IMMEDIATE_RECORD ) + { + CTimerd::EventInfo *ei=static_cast(data); + tei.apids = ei->apids; + tei.channel_id = ei->channel_id; + tei.epg_starttime = ei->epg_starttime; + tei.epgID = ei->epgID; + tei.recordingSafety = ei->recordingSafety; + length = sizeof( CTimerd::TransferEventInfo); + data = &tei; + } + else if(evType == CTimerd::TIMER_RECORD) + { + CTimerd::RecordingInfo *ri=static_cast(data); + tri.apids = ri->apids; + tri.channel_id = ri->channel_id; + tri.epg_starttime = ri->epg_starttime; + tri.epgID = ri->epgID; + tri.recordingSafety = ri->recordingSafety; + strncpy(tri.recordingDir, ri->recordingDir, RECORD_DIR_MAXLEN-1); + length = sizeof( CTimerd::TransferRecordingInfo); + data = &tri; + } + else if(evType == CTimerd::TIMER_STANDBY) + { + length = sizeof(CTimerdMsg::commandSetStandby); + } + else if(evType == CTimerd::TIMER_REMIND) + { + length = sizeof(CTimerdMsg::commandRemind); + } + else if(evType == CTimerd::TIMER_EXEC_PLUGIN) + { + length = sizeof(CTimerdMsg::commandExecPlugin); + } + else + { + length = 0; + } + + send(CTimerdMsg::CMD_ADDTIMER, (char*)&msgAddTimer, sizeof(msgAddTimer)); + + if((data != NULL) && (length > 0)) + send_data((char*)data, length); + + CTimerdMsg::responseAddTimer response; + receive_data((char*)&response, sizeof(response)); + close_connection(); + + return( response.eventID); +} +//------------------------------------------------------------------------- + +void CTimerdClient::removeTimerEvent( int evId) +{ + CTimerdMsg::commandRemoveTimer msgRemoveTimer; + + msgRemoveTimer.eventID = evId; + + send(CTimerdMsg::CMD_REMOVETIMER, (char*) &msgRemoveTimer, sizeof(msgRemoveTimer)); + + close_connection(); +} +//------------------------------------------------------------------------- + +bool CTimerdClient::isTimerdAvailable() +{ + if(!send(CTimerdMsg::CMD_TIMERDAVAILABLE)) + return false; + + CTimerdMsg::responseAvailable response; + bool ret=receive_data((char*)&response, sizeof(response)); + close_connection(); + return ret; +} +//------------------------------------------------------------------------- + +CTimerd::TimerList CTimerdClient::getOverlappingTimers(time_t& startTime, time_t& stopTime) +{ + CTimerd::TimerList timerlist; + CTimerd::TimerList overlapping; + int timerPre; + int timerPost; + + getTimerList(timerlist); + getRecordingSafety(timerPre,timerPost); + + for (CTimerd::TimerList::iterator it = timerlist.begin(); + it != timerlist.end();it++) + { + if(it->stopTime != 0 && stopTime != 0) + { + // Check if both timers have start and end. In this case do not show conflict, if endtime is the same than the starttime of the following timer + if ((stopTime+timerPost > it->alarmTime) && (startTime-timerPre < it->stopTime)) + { + overlapping.push_back(*it); + } + } + else + { + if (!((stopTime < it->announceTime) || (startTime > it->stopTime))) + { + overlapping.push_back(*it); + } + } + } + return overlapping; +} + +//------------------------------------------------------------------------- + +bool CTimerdClient::shutdown() +{ + send(CTimerdMsg::CMD_SHUTDOWN); + + CTimerdMsg::responseStatus response; + receive_data((char*)&response, sizeof(response)); + + close_connection(); + return response.status; +} +//------------------------------------------------------------------------- +void CTimerdClient::modifyTimerAPid(int eventid, unsigned char apids) +{ + CTimerdMsg::commandSetAPid data; + data.eventID=eventid; + data.apids = apids; + send(CTimerdMsg::CMD_SETAPID, (char*) &data, sizeof(data)); + close_connection(); +} + +//------------------------------------------------------------------------- +void CTimerdClient::setRecordingSafety(int pre, int post) +{ + CTimerdMsg::commandRecordingSafety data; + data.pre = pre; + data.post = post; + send(CTimerdMsg::CMD_SETRECSAFETY, (char*) &data, sizeof(data)); + close_connection(); +} + +//------------------------------------------------------------------------- +void CTimerdClient::getRecordingSafety(int &pre, int &post) +{ + send(CTimerdMsg::CMD_GETRECSAFETY); + CTimerdMsg::commandRecordingSafety data; + + bool success = receive_data((char*)&data, sizeof(data)); + close_connection(); + if (success) + { + pre = data.pre; + post = data.post; + } + else + { + /* fill with default values (cf. timermanager.cpp) */ + pre = 0; + post = 0; + } +} + +//------------------------------------------------------------------------- +//void CTimerdClient::getWeekdaysFromStr(int *rep, const char* str) +void CTimerdClient::getWeekdaysFromStr(CTimerd::CTimerEventRepeat *eventRepeat, const char* str) +{ + int rep = (int) *eventRepeat; + if(rep >= (int)CTimerd::TIMERREPEAT_WEEKDAYS) + { + for(int n=0;n<7;n++) + { + if(str[n]=='X' || str[n]=='x') + { + rep |= (1 << (n+9)); + } + else + { + rep &= (~(1 << (n+9))); + } + } + } + *eventRepeat = (CTimerd::CTimerEventRepeat) rep; +} +//------------------------------------------------------------------------- +void CTimerdClient::setWeekdaysToStr(CTimerd::CTimerEventRepeat rep, char* str) +{ + if(rep >= CTimerd::TIMERREPEAT_WEEKDAYS) + { + for(int n=0;n<7;n++) + { + if(rep & (1 << (n+9))) + str[n]='X'; + else + str[n]='-'; + } + str[7]=0; + } + else + strcpy(str,"-------"); +} +//------------------------------------------------------------------------- +void CTimerdClient::stopTimerEvent( int evId) +{ + CTimerdMsg::commandRemoveTimer msgRemoveTimer; + + msgRemoveTimer.eventID = evId; + + send(CTimerdMsg::CMD_STOPTIMER, (char*) &msgRemoveTimer, sizeof(msgRemoveTimer)); + + close_connection(); +} + diff --git a/lib/timerdclient/timerdclient.h b/lib/timerdclient/timerdclient.h new file mode 100644 index 000000000..debc061fc --- /dev/null +++ b/lib/timerdclient/timerdclient.h @@ -0,0 +1,175 @@ +/* + Timer-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + $Id: timerdclient.h,v 1.47 2006/02/14 22:38:28 zwen Exp $ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __timerdclient__ +#define __timerdclient__ + +#include +#include + +#include + +#include + +class CTimerdClient:private CBasicClient +{ + private: + virtual const unsigned char getVersion () const; + virtual const char * getSocketName() const; + + public: + enum events + { + EVT_SHUTDOWN = 1, + EVT_ANNOUNCE_SHUTDOWN, + EVT_ZAPTO, + EVT_ANNOUNCE_ZAPTO, + EVT_NEXTPROGRAM, + EVT_ANNOUNCE_NEXTPROGRAM, + EVT_STANDBY_ON, + EVT_STANDBY_OFF, + EVT_RECORD_START, + EVT_RECORD_STOP, + EVT_ANNOUNCE_RECORD, + EVT_ANNOUNCE_SLEEPTIMER, + EVT_SLEEPTIMER, + EVT_REMIND, + EVT_EXEC_PLUGIN + }; + + void registerEvent(unsigned int eventID, unsigned int clientID, const char * const udsName); + void unRegisterEvent(unsigned int eventID, unsigned int clientID); + + bool isTimerdAvailable(); // check if timerd is running + + CTimerd::TimerList getOverlappingTimers(time_t& announcetime, time_t& stoptime); + + int addTimerEvent( CTimerd::CTimerEventTypes evType, void* data, time_t alarmtime,time_t announcetime = 0, time_t stoptime = 0, + CTimerd::CTimerEventRepeat evrepeat = CTimerd::TIMERREPEAT_ONCE, uint32_t repeatcount = 0, bool forceadd=true); + + void removeTimerEvent( int evId); // remove timer event + void stopTimerEvent( int evId); // set timer state to stoped (rescedule on demand) + + void getTimerList( CTimerd::TimerList &timerlist); // returns the list of all timers + void getTimer( CTimerd::responseGetTimer &timer, unsigned timerID); // returns specified timer + + // modify existing timer event + bool modifyTimerEvent(int eventid, time_t announcetime, time_t alarmtime, time_t stoptime, CTimerd::CTimerEventRepeat evrepeat = CTimerd::TIMERREPEAT_ONCE, uint32_t repeatcount=0); + bool modifyTimerEvent(int eventid, time_t announcetime, time_t alarmtime, time_t stoptime, CTimerd::CTimerEventRepeat evrepeat, uint32_t repeatcount, + void *data,int datalen=0); + + bool modifyRecordTimerEvent(int eventid, time_t announcetime, time_t alarmtime, time_t stoptime, CTimerd::CTimerEventRepeat evrepeat, uint32_t repeatcount, const char * const recordingdir); + + void modifyTimerAPid(int eventid, unsigned char apids); + + // set existing sleeptimer to new times or create new sleeptimer with these times + int setSleeptimer(time_t announcetime, time_t alarmtime, int timerid = 0); + + // returns the id of sleeptimer, 0 of no sleeptimer exists + int getSleeptimerID(); + // returns remaining mins, -1 if no sleeptimer exists + int getSleepTimerRemaining(); + + + // add diff to existing timer event + bool rescheduleTimerEvent(int eventid, time_t diff); + + // add diff to existing timer event + bool rescheduleTimerEvent(int eventid, time_t announcediff, time_t alarmdiff, time_t stoptime); + + // adds new sleeptimer event + int addSleepTimerEvent(time_t announcetime,time_t alarmtime) // sleeptimer setzen + {return addTimerEvent(CTimerd::TIMER_SLEEPTIMER, NULL, announcetime, alarmtime, 0);}; + + // adds new shutdown timer event + int addShutdownTimerEvent(time_t alarmtime, time_t announcetime = 0, time_t stoptime = 0) + {return addTimerEvent(CTimerd::TIMER_SHUTDOWN, NULL, announcetime, alarmtime, stoptime);}; + + // adds new record timer event + int addRecordTimerEvent(const t_channel_id channel_id, time_t alarmtime, time_t stoptime, + unsigned long long epgID=0, time_t epg_starttime=0, time_t announcetime = 0, + unsigned char apids=TIMERD_APIDS_STD, bool safety=false,std::string recDir="", bool forceAdd=true) + { + CTimerd::RecordingInfo eventInfo; + eventInfo.channel_id = channel_id; + eventInfo.epgID = epgID; + eventInfo.epg_starttime = epg_starttime; + eventInfo.apids = apids; + eventInfo.recordingSafety = safety; + strncpy(eventInfo.recordingDir, recDir.c_str(), RECORD_DIR_MAXLEN); + return addTimerEvent(CTimerd::TIMER_RECORD, &eventInfo, announcetime, alarmtime, stoptime,CTimerd::TIMERREPEAT_ONCE, 0,forceAdd); + }; + + int addImmediateRecordTimerEvent(const t_channel_id channel_id, time_t alarmtime, time_t stoptime, + unsigned long long epgID=0, time_t epg_starttime=0,unsigned char apids=TIMERD_APIDS_STD) + { + CTimerd::EventInfo eventInfo; + eventInfo.channel_id = channel_id; + eventInfo.epgID = epgID; + eventInfo.epg_starttime = epg_starttime; + eventInfo.apids = apids; + eventInfo.recordingSafety = false; + return addTimerEvent(CTimerd::TIMER_IMMEDIATE_RECORD, &eventInfo, 0, alarmtime, stoptime); + }; + + // adds new standby timer event + int addStandbyTimerEvent(bool standby_on,time_t alarmtime, time_t announcetime = 0, time_t stoptime = 0) + {return addTimerEvent(CTimerd::TIMER_STANDBY, &standby_on, announcetime, alarmtime, stoptime);}; + + // adds new zapto timer event + int addZaptoTimerEvent(const t_channel_id channel_id, time_t alarmtime, time_t announcetime = 0, + time_t stoptime = 0, unsigned long long epgID=0, time_t epg_starttime=0, + unsigned char apids=TIMERD_APIDS_STD) + { + CTimerd::EventInfo eventInfo; + eventInfo.channel_id = channel_id; + eventInfo.epgID = epgID; + eventInfo.epg_starttime = epg_starttime; + eventInfo.apids = apids; + return addTimerEvent(CTimerd::TIMER_ZAPTO, &eventInfo, announcetime, alarmtime, stoptime); + }; + + int addNextProgramTimerEvent(CTimerd::EventInfo eventInfo,time_t alarmtime, time_t announcetime = 0, time_t stoptime = 0) + { + // mal auf verdacht eingebaut + // keine ahnung ob / was hier noch fehlt + return addTimerEvent(CTimerd::TIMER_NEXTPROGRAM, &eventInfo, alarmtime, announcetime, stoptime); + }; + + // Exit timerd and programm wakeup + bool shutdown(); + + // set and get recording safety time (in sec) + void setRecordingSafety(int pre, int post); + void getRecordingSafety(int &pre, int &post); + + // Convert String of O and X to repeat type and vice versa + //void getWeekdaysFromStr(int *rep, const char* str); + void getWeekdaysFromStr(CTimerd::CTimerEventRepeat *rep, const char* str); + void setWeekdaysToStr(CTimerd::CTimerEventRepeat rep, char* str); +}; + +#endif diff --git a/lib/timerdclient/timerdmsg.h b/lib/timerdclient/timerdmsg.h new file mode 100644 index 000000000..9efb9d61f --- /dev/null +++ b/lib/timerdclient/timerdmsg.h @@ -0,0 +1,155 @@ +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/lib/timerdclient/timerdmsg.h,v 1.11 2006/02/14 22:38:28 zwen Exp $ + * + * types used for clientlib <-> timerd communication - d-box2 linux project + * + * (C) 2002 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __timerdmsg_h__ +#define __timerdmsg_h__ + + +#include + +#include "timerdtypes.h" // REMINDER_MESSAGE_MAXLEN + + +#define TIMERD_UDS_NAME "/tmp/timerd.sock" + + +class CTimerdMsg : public CBasicMessage +{ + + public: + + static const CBasicMessage::t_version ACTVERSION = 2; + + enum commands + { + CMD_ADDTIMER = 1, + CMD_REMOVETIMER, + CMD_GETTIMER, + CMD_GETTIMERLIST, + CMD_MODIFYTIMER, + CMD_GETSLEEPTIMER, + CMD_RESCHEDULETIMER, + + CMD_REGISTEREVENT, + CMD_UNREGISTEREVENT, + CMD_TIMERDAVAILABLE, + CMD_SHUTDOWN, + CMD_SETAPID, + CMD_GETRECSAFETY, + CMD_SETRECSAFETY, + CMD_STOPTIMER + }; + + + struct commandAddTimer + { + CTimerd::CTimerEventTypes eventType; + CTimerd::CTimerEventRepeat eventRepeat; + time_t alarmTime; + time_t announceTime; + time_t stopTime; + uint32_t repeatCount; + }; + + struct commandGetTimer + { + int eventID; + }; + + struct commandModifyTimer + { + int eventID; + time_t announceTime; + time_t alarmTime; + time_t stopTime; + CTimerd::CTimerEventRepeat eventRepeat; + uint32_t repeatCount; + }; + + + struct commandRemind + { + char message[REMINDER_MESSAGE_MAXLEN]; + }; + + struct commandExecPlugin + { + char name[EXEC_PLUGIN_NAME_MAXLEN]; + }; + + struct commandRecordDir + { + char recDir[RECORD_DIR_MAXLEN]; + }; + + struct commandSetAPid + { + int eventID; + unsigned char apids; + }; + + struct commandRemoveTimer + { + int eventID; + }; + + struct commandSetStandby + { + bool standby_on; + }; + + struct commandRecordingSafety + { + int pre; + int post; + }; + + + struct generalInteger + { + int number; + }; + + struct responseAddTimer + { + int eventID; + }; + + struct responseAvailable + { + bool available; + }; + + struct responseGetSleeptimer + { + int eventID; + }; + + struct responseStatus + { + bool status; + }; + +}; + +#endif /* __timerdmsg_h__ */ diff --git a/lib/timerdclient/timerdtypes.h b/lib/timerdclient/timerdtypes.h new file mode 100644 index 000000000..2bf9ce6a7 --- /dev/null +++ b/lib/timerdclient/timerdtypes.h @@ -0,0 +1,168 @@ +/* + Timer-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + $Id: timerdtypes.h,v 1.20 2006/02/28 21:51:01 zwen Exp $ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __timerdtypes__ +#define __timerdtypes__ + +#include +#include + +#include + +#define REMINDER_MESSAGE_MAXLEN 31 +#define EXEC_PLUGIN_NAME_MAXLEN 31 +#define RECORD_DIR_MAXLEN 100 +#define EPG_TITLE_MAXLEN 50 + +#define TIMERD_APIDS_CONF 0x00 +#define TIMERD_APIDS_STD 0x01 +#define TIMERD_APIDS_ALT 0x02 +#define TIMERD_APIDS_AC3 0x04 +#define TIMERD_APIDS_ALL 0xFF + +class CTimerd +{ + public: + enum CTimerEventRepeat + { + TIMERREPEAT_ONCE = 0, + TIMERREPEAT_DAILY, + TIMERREPEAT_WEEKLY, + TIMERREPEAT_BIWEEKLY, + TIMERREPEAT_FOURWEEKLY, + TIMERREPEAT_MONTHLY, + TIMERREPEAT_BYEVENTDESCRIPTION, + TIMERREPEAT_WEEKDAYS = 0x100 // Bits 9-15 specify weekdays (9=mo,10=di,...) + }; + + enum CTimerEventTypes + { + TIMER_SHUTDOWN = 1, + TIMER_NEXTPROGRAM, + TIMER_ZAPTO, + TIMER_STANDBY, + TIMER_RECORD, + TIMER_REMIND, + TIMER_SLEEPTIMER, + TIMER_EXEC_PLUGIN, + TIMER_IMMEDIATE_RECORD + }; + + enum CTimerEventStates + { + TIMERSTATE_SCHEDULED, + TIMERSTATE_PREANNOUNCE, + TIMERSTATE_ISRUNNING, + TIMERSTATE_HASFINISHED, + TIMERSTATE_TERMINATED + }; + + struct EventInfo + { + event_id_t epgID; + time_t epg_starttime; + t_channel_id channel_id; + unsigned char apids; + bool recordingSafety; + }; + + struct TransferEventInfo + { + event_id_t epgID; + time_t epg_starttime; + t_channel_id channel_id; + unsigned char apids; + bool recordingSafety; + }; + + struct TransferRecordingInfo : TransferEventInfo + { + char recordingDir[RECORD_DIR_MAXLEN]; + char epgTitle[EPG_TITLE_MAXLEN]; + + }; + + class RecordingInfo : public EventInfo + { + public: + RecordingInfo(){}; + RecordingInfo(EventInfo& e) + { + apids = e.apids; + channel_id = e.channel_id; + epgID = e.epgID; + epg_starttime = e.epg_starttime; + recordingSafety = e.recordingSafety; + }; + RecordingInfo& operator = (EventInfo& e) + { + apids = e.apids; + channel_id = e.channel_id; + epgID = e.epgID; + epg_starttime = e.epg_starttime; + recordingSafety = e.recordingSafety; + return *this; + } + unsigned char apids; + int eventID; + char recordingDir[RECORD_DIR_MAXLEN]; + char epgTitle[EPG_TITLE_MAXLEN]; + }; + + struct RecordingStopInfo + { + int eventID; + }; + + struct responseGetTimer + { + int eventID; + CTimerEventTypes eventType; + CTimerEventStates eventState; + CTimerEventRepeat eventRepeat; + uint32_t repeatCount; + time_t alarmTime; + time_t announceTime; + time_t stopTime; + t_channel_id channel_id; //only filled if applicable + event_id_t epgID; //only filled if applicable + time_t epg_starttime; //only filled if applicable + unsigned char apids; //only filled if applicable + bool standby_on; //only filled if applicable + char message[REMINDER_MESSAGE_MAXLEN]; //only filled if applicable + char pluginName[EXEC_PLUGIN_NAME_MAXLEN]; //only filled if applicable + char recordingDir[RECORD_DIR_MAXLEN]; //only filled if applicable + char epgTitle[EPG_TITLE_MAXLEN]; //only filled if applicable + + bool operator< (const responseGetTimer& a) const + { + return this->alarmTime < a.alarmTime ; + } + }; + + typedef std::vector TimerList; +}; +#endif diff --git a/lib/xmltree/Makefile.am b/lib/xmltree/Makefile.am new file mode 100644 index 000000000..045af2a79 --- /dev/null +++ b/lib/xmltree/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = -I$(srcdir)/xmltok + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +noinst_LIBRARIES = libtuxbox-xmltree.a + +libtuxbox_xmltree_a_SOURCES = \ + hashtab.c xmlparse.cpp xmlrole.c xmltok.c xmltree.cpp xmlinterface.cpp diff --git a/lib/xmltree/asciitab.h b/lib/xmltree/asciitab.h new file mode 100644 index 000000000..f7d78da4f --- /dev/null +++ b/lib/xmltree/asciitab.h @@ -0,0 +1,52 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): +*/ + +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_NMSTRT, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/lib/xmltree/hashtab.c b/lib/xmltree/hashtab.c new file mode 100644 index 000000000..9e164a959 --- /dev/null +++ b/lib/xmltree/hashtab.c @@ -0,0 +1,134 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +csompliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): +*/ + +#include +#include + +#include "xmldef.h" +#include "hashtab.h" + +#ifdef XML_UNICODE +#define keycmp wcscmp +#else +#define keycmp strcmp +#endif + +#define INIT_SIZE 64 + +static +unsigned long hash(KEY s) +{ + unsigned long h = 0; + while (*s) + h = (h << 5) + h + (unsigned char)*s++; + return h; +} + +NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize) +{ + size_t i; + if (table->size == 0) { + if (!createSize) + return 0; + table->v = (NAMED**)calloc(INIT_SIZE, sizeof(NAMED *)); + if (!table->v) + return 0; + table->size = INIT_SIZE; + table->usedLim = INIT_SIZE / 2; + i = hash(name) & (table->size - 1); + } + else { + unsigned long h = hash(name); + for (i = h & (table->size - 1); + table->v[i]; + i == 0 ? i = table->size - 1 : --i) { + if (keycmp(name, table->v[i]->name) == 0) + return table->v[i]; + } + if (!createSize) + return 0; + if (table->used == table->usedLim) { + /* check for overflow */ + size_t newSize = table->size * 2; + NAMED **newV = (NAMED**)calloc(newSize, sizeof(NAMED *)); + if (!newV) + return 0; + for (i = 0; i < table->size; i++) + if (table->v[i]) { + size_t j; + for (j = hash(table->v[i]->name) & (newSize - 1); + newV[j]; + j == 0 ? j = newSize - 1 : --j) + ; + newV[j] = table->v[i]; + } + free(table->v); + table->v = newV; + table->size = newSize; + table->usedLim = newSize/2; + for (i = h & (table->size - 1); + table->v[i]; + i == 0 ? i = table->size - 1 : --i) + ; + } + } + table->v[i] = (NAMED*)calloc(1, createSize); + if (!table->v[i]) + return 0; + table->v[i]->name = name; + (table->used)++; + return table->v[i]; +} + +void hashTableDestroy(HASH_TABLE *table) +{ + size_t i; + for (i = 0; i < table->size; i++) { + NAMED *p = table->v[i]; + if (p) + free(p); + } + free(table->v); +} + +void hashTableInit(HASH_TABLE *p) +{ + p->size = 0; + p->usedLim = 0; + p->used = 0; + p->v = 0; +} + +void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) +{ + iter->p = table->v; + iter->end = iter->p + table->size; +} + +NAMED *hashTableIterNext(HASH_TABLE_ITER *iter) +{ + while (iter->p != iter->end) { + NAMED *tem = *(iter->p)++; + if (tem) + return tem; + } + return 0; +} + diff --git a/lib/xmltree/hashtab.h b/lib/xmltree/hashtab.h new file mode 100644 index 000000000..27de67086 --- /dev/null +++ b/lib/xmltree/hashtab.h @@ -0,0 +1,59 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): +*/ + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef XML_UNICODE +typedef const wchar_t *KEY; +#else +typedef const char *KEY; +#endif + +typedef struct { + KEY name; +} NAMED; + +typedef struct { + NAMED **v; + size_t size; + size_t used; + size_t usedLim; +} HASH_TABLE; + +NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize); +void hashTableInit(HASH_TABLE *); +void hashTableDestroy(HASH_TABLE *); + +typedef struct { + NAMED **p; + NAMED **end; +} HASH_TABLE_ITER; + +void hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); +NAMED *hashTableIterNext(HASH_TABLE_ITER *); + +#ifdef __cplusplus +} +#endif diff --git a/lib/xmltree/iasctab.h b/lib/xmltree/iasctab.h new file mode 100644 index 000000000..d89407477 --- /dev/null +++ b/lib/xmltree/iasctab.h @@ -0,0 +1,53 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): +*/ + +/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_NMSTRT, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/lib/xmltree/xmlinterface.cpp b/lib/xmltree/xmlinterface.cpp new file mode 100644 index 000000000..82d262534 --- /dev/null +++ b/lib/xmltree/xmlinterface.cpp @@ -0,0 +1,178 @@ +/* + * $Header: /cvs/tuxbox/apps/dvb/zapit/src/xmlinterface.cpp,v 1.25 2004/04/07 19:33:21 thegoodguy Exp $ + * + * xmlinterface for zapit - d-box2 linux project + * + * (C) 2002 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include + +#include + +#ifdef USE_LIBXML +#include +#include +#include +#else /* USE_LIBXML */ +#include +#endif /* USE_LIBXML */ + + +unsigned long xmlGetNumericAttribute(const xmlNodePtr node, char *name, const int base) +{ + char *ptr = xmlGetAttribute(node, name); + + if (!ptr) + return 0; + + return strtoul(ptr, 0, base); +} + +long xmlGetSignedNumericAttribute(const xmlNodePtr node, char *name, const int base) +{ + char *ptr = xmlGetAttribute(node, name); + + if (!ptr) + return 0; + + return strtol(ptr, 0, base); +} + +xmlNodePtr xmlGetNextOccurence(xmlNodePtr cur, const char * s) +{ + while ((cur != NULL) && (strcmp(xmlGetName(cur), s) != 0)) + cur = cur->xmlNextNode; + return cur; +} + + +std::string Unicode_Character_to_UTF8(const int character) +{ +#ifdef USE_LIBXML + xmlChar buf[5]; + int length = xmlCopyChar(4, buf, character); + return std::string((char*)buf, length); +#else /* USE_LIBXML */ + char buf[XML_UTF8_ENCODE_MAX]; + int length = XmlUtf8Encode(character, buf); + return std::string(buf, length); +#endif /* USE_LIBXML */ +} + +#ifdef USE_LIBXML +xmlDocPtr parseXmlFile(const char * filename) +{ + xmlDocPtr doc; + xmlNodePtr cur; + + doc = xmlParseFile(filename); + + if (doc == NULL) + { + WARN("Error parsing \"%s\"", filename); + return NULL; + } + else + { + cur = xmlDocGetRootElement(doc); + if (cur == NULL) + { + WARN("Empty document\n"); + xmlFreeDoc(doc); + return NULL; + } + else + return doc; + } +} +#else /* USE_LIBXML */ +xmlDocPtr parseXml(const char * data) +{ + XMLTreeParser* tree_parser; + + tree_parser = new XMLTreeParser(NULL); + + if (!tree_parser->Parse(data, strlen(data), true)) + { + printf("Error parsing XML Data: %s at line %d\n", + tree_parser->ErrorString(tree_parser->GetErrorCode()), + tree_parser->GetCurrentLineNumber()); + + delete tree_parser; + return NULL; + } + + if (!tree_parser->RootNode()) + { + printf("Error: No Root Node\n"); + delete tree_parser; + return NULL; + } + return tree_parser; +} + +xmlDocPtr parseXmlFile(const char * filename) +{ + char buffer[2048]; + XMLTreeParser* tree_parser; + size_t done; + size_t length; + FILE* xml_file; + + xml_file = fopen(filename, "r"); + + if (xml_file == NULL) + { + perror(filename); + return NULL; + } + + tree_parser = new XMLTreeParser(NULL); + + do + { + length = fread(buffer, 1, sizeof(buffer), xml_file); + done = length < sizeof(buffer); + + if (!tree_parser->Parse(buffer, length, done)) + { + printf("Error parsing \"%s\": %s at line %d\n", + filename, + tree_parser->ErrorString(tree_parser->GetErrorCode()), + tree_parser->GetCurrentLineNumber()); + + fclose(xml_file); + delete tree_parser; + return NULL; + } + } + while (!done); + + fclose(xml_file); + + if (!tree_parser->RootNode()) + { + delete tree_parser; + return NULL; + } + return tree_parser; +} +#endif /* USE_LIBXML */ diff --git a/lib/xmltree/xmlinterface.h b/lib/xmltree/xmlinterface.h new file mode 100644 index 000000000..c1faddd46 --- /dev/null +++ b/lib/xmltree/xmlinterface.h @@ -0,0 +1,93 @@ +/* + * $Header: /cvs/tuxbox/apps/dvb/zapit/include/zapit/xmlinterface.h,v 1.21 2004/04/07 19:33:21 thegoodguy Exp $ + * + * xmlinterface for zapit - d-box2 linux project + * + * (C) 2002 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __xmlinterface_h__ +#define __xmlinterface_h__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef USE_LIBXML +#include +#define xmlNextNode next +inline char* xmlGetAttribute (xmlNodePtr cur, const char * s) { return (char *)xmlGetProp(cur, (const xmlChar *)s); }; +inline char* xmlGetName (xmlNodePtr cur) { return (char *)(cur->name); }; + +#else /* use libxmltree */ +#include +typedef XMLTreeParser* xmlDocPtr; +typedef XMLTreeNode* xmlNodePtr; +#define xmlChildrenNode GetChild() +#define xmlNextNode GetNext() +inline xmlNodePtr xmlDocGetRootElement(xmlDocPtr doc) { return doc->RootNode(); }; +inline void xmlFreeDoc (xmlDocPtr doc) { delete doc; }; +inline char* xmlGetAttribute (xmlNodePtr cur, char * s) { return cur->GetAttributeValue(s); }; +inline char* xmlGetName (xmlNodePtr cur) { return cur->GetType(); }; +inline char* xmlGetData (xmlNodePtr cur) { return cur->GetData(); }; +#endif /* USE_LIBXML */ + + +unsigned long xmlGetNumericAttribute (const xmlNodePtr node, char *name, const int base); +long xmlGetSignedNumericAttribute (const xmlNodePtr node, char *name, const int base); +xmlNodePtr xmlGetNextOccurence (xmlNodePtr cur, const char * s); + +std::string Unicode_Character_to_UTF8(const int character); + +inline std::string convert_UTF8_To_UTF8_XML(const char * s) +{ + std::string r; + + while ((*s) != 0) + { + /* cf. http://www.w3.org/TR/xhtml1/dtds.html */ + switch (*s) + { + case '<': + r += "<"; + break; + case '>': + r += ">"; + break; + case '&': + r += "&"; + break; + case '\"': + r += """; + break; + case '\'': + r += "'"; + break; + default: + r += *s; + } + s++; + } + return r; +} +xmlDocPtr parseXml(const char *data); +xmlDocPtr parseXmlFile(const char * filename); + +#endif /* __xmlinterface_h__ */ diff --git a/lib/xmltree/xmlparse.cpp b/lib/xmltree/xmlparse.cpp new file mode 100644 index 000000000..666976bb0 --- /dev/null +++ b/lib/xmltree/xmlparse.cpp @@ -0,0 +1,2734 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): + + Fabian Giesen - converted this monster to C++ (at least the core) + +ChangeLog: + + $Log: xmlparse.cpp,v $ + Revision 1.3 2003/03/14 05:13:04 obi + compileable with -W -Werror + + Revision 1.2 2003/02/26 22:21:24 obi + Mismatched free() / delete / delete [] + + Revision 1.1 2002/01/18 20:22:39 tmbinc + initial checkin + + Revision 1.1.1.1 2001/10/07 13:01:18 tmbinc + Import of ezap2-200110070 + + Revision 1.1 1999/01/11 23:01:59 cvs + Another try to commit this. + +*/ + +#include +#include +#include + +#include "xmldef.h" + +#ifdef XML_UNICODE +#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX +#define XmlConvert XmlUtf16Convert +#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding +#define XmlEncode XmlUtf16Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1)) +typedef unsigned short ICHAR; +#else +#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX +#define XmlConvert XmlUtf8Convert +#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding +#define XmlEncode XmlUtf8Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf8) +typedef char ICHAR; +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_T(x) L ## x +#else +#define XML_T(x) x +#endif + +/* Round up n to be a multiple of sz, where sz is a power of 2. */ +#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) + +#include "xmlparse.h" + +static int dtdInit(DTD *); +static void dtdDestroy(DTD *); +static int dtdCopy(DTD *newDtd, const DTD *oldDtd); + +static void poolInit(STRING_POOL *); +static void poolClear(STRING_POOL *); +static void poolDestroy(STRING_POOL *); +static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr, const char *end); +static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, const char *ptr, const char *end); +static int poolGrow(STRING_POOL *pool); +static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s); +static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n); + +#define poolStart(pool) ((pool)->start) +#define poolEnd(pool) ((pool)->ptr) +#define poolLength(pool) ((pool)->ptr - (pool)->start) +#define poolChop(pool) ((void)--(pool->ptr)) +#define poolLastChar(pool) (((pool)->ptr)[-1]) +#define poolDiscard(pool) ((pool)->ptr = (pool)->start) +#define poolFinish(pool) ((pool)->start = (pool)->ptr) +#define poolAppendChar(pool, c) (((pool)->ptr == (pool)->end && !poolGrow(pool)) ? 0 : ((*((pool)->ptr)++ = c), 1)) + +XML_Parser::XML_Parser(const XML_Char *encodingName) +{ + processor=prologInitProcessor; + XmlPrologStateInit(&prologState); + + buffer=0; + bufferPtr=0; + bufferEnd=0; + parseEndByteIndex=0; + parseEndPtr=0; + bufferLim=0; + declElementType=0; + declAttributeId=0; + declEntity=0; + declNotationName=0; + declNotationPublicId=0; + + startElementHandler=0; + endElementHandler=0; + characterDataHandler=0; + processingInstructionHandler=0; + defaultHandler=0; + unparsedEntityDeclHandler=0; + notationDeclHandler=0; + externalEntityRefHandler=0; + unknownEncodingHandler=0; + + memset(&position, 0, sizeof(POSITION)); + + errorCode=XML_ERROR_NONE; + eventPtr=0; + eventEndPtr=0; + positionPtr=0; + tagLevel=0; + tagStack=0; + freeTagList=0; + attsSize=INIT_ATTS_SIZE; + atts=new ATTRIBUTE[attsSize]; + dataBuf=new XML_Char[INIT_DATA_BUF_SIZE]; + groupSize=0; + groupConnector=0; + hadExternalDoctype=0; + unknownEncodingMem=0; + unknownEncodingRelease=0; + unknownEncodingData=0; + unknownEncodingHandlerData=0; + + poolInit(&tempPool); + poolInit(&temp2Pool); + + protocolEncodingName=encodingName ? poolCopyString(&tempPool, encodingName) : 0; + + if (!dtdInit(&dtd) || !atts || !dataBuf || (encodingName && !protocolEncodingName)) + { + poolDestroy(&tempPool); + poolDestroy(&temp2Pool); + + if (atts) delete[] atts; + if (dataBuf) delete[] dataBuf; + + return; + }; + + dataBufEnd=dataBuf+INIT_DATA_BUF_SIZE; + XmlInitEncoding(&initEncoding, &encoding, 0); +}; + +XML_Parser *XML_Parser::ExternalEntityParserCreate(const XML_Char *openEntityNames, const XML_Char *encodingName) +{ + XML_Parser *parser; + + parser=new XML_Parser(encodingName); + if (!parser) return 0; + + if (!dtdCopy(&parser->dtd, &dtd) || !parser->setOpenEntityNames(openEntityNames)) + { + delete parser; + return 0; + }; + + parser->processor=externalEntityInitProcessor; + return parser; +}; + +XML_Parser::~XML_Parser() +{ + for (;;) + { + TAG *p; + + if (!tagStack) + { + if (!freeTagList) break; + + tagStack=freeTagList; + freeTagList=0; + }; + + p=tagStack; + tagStack=tagStack->parent; + + delete[] p->buf; + delete p; + }; + + poolDestroy(&tempPool); + poolDestroy(&temp2Pool); + dtdDestroy(&dtd); + + delete[] atts; + free(groupConnector); + free(buffer); + delete[] dataBuf; + free(unknownEncodingMem); + + if (unknownEncodingRelease) + unknownEncodingRelease(unknownEncodingData); +}; + +int XML_Parser::SetBase(const XML_Char *p) +{ + if (p) + { + p=poolCopyString(&dtd.pool, p); + if (!p) return 0; + + dtd.base=p; + } + else + dtd.base=0; + + return 1; +}; + +const XML_Char *XML_Parser::GetBase() +{ + return dtd.base; +}; + +int XML_Parser::Parse(const char *s, int len, int isFinal) +{ + if (!len) + { + if (!isFinal) return 1; + + errorCode=processor(this, bufferPtr, parseEndPtr=bufferEnd, 0); + if (errorCode==XML_ERROR_NONE) return 1; + + eventEndPtr=eventPtr; + return 0; + } + else if (bufferPtr==bufferEnd) + { + const char *end; + int nLeftOver; + + parseEndByteIndex+=len; + positionPtr=s; + + if (isFinal) + { + errorCode=processor(this, s, parseEndPtr=s+len, 0); + if (errorCode==XML_ERROR_NONE) return 1; + + eventEndPtr=eventPtr; + return 0; + }; + + errorCode=processor(this, s, parseEndPtr=s+len, &end); + if (errorCode!=XML_ERROR_NONE) + { + eventEndPtr=eventPtr; + return 0; + }; + + XmlUpdatePosition(encoding, positionPtr, end, &position); + + nLeftOver=s+len-end; + if (nLeftOver) + { + if (!buffer || nLeftOver>bufferLim-buffer) + { + buffer=buffer==0 ? (char *) malloc(len*2) : (char *) realloc(buffer, len*2); + + if (!buffer) + { + errorCode=XML_ERROR_NO_MEMORY; + eventPtr=eventEndPtr=0; + return 0; + }; + + bufferLim=buffer+len*2; + }; + + memcpy(buffer, end, nLeftOver); + + bufferPtr=buffer; + bufferEnd=buffer+nLeftOver; + }; + + return 1; + } + else + { + memcpy(GetBuffer(len), s, len); + return ParseBuffer(len, isFinal); + }; +}; + +int XML_Parser::ParseBuffer(int len, int isFinal) +{ + const char *start = bufferPtr; + + positionPtr=start; + bufferEnd+=len; + parseEndByteIndex+=len; + + errorCode=processor(this, start, parseEndPtr=bufferEnd, + isFinal ? (const char **) 0: &bufferPtr); + + if (errorCode==XML_ERROR_NONE) + { + if (!isFinal) + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + + return 1; + } + else + { + eventEndPtr=eventPtr; + return 0; + }; +}; + +void *XML_Parser::GetBuffer(int len) +{ + if (len>bufferLim-bufferEnd) + { + int neededSize=len+(bufferEnd-bufferPtr); + + if (neededSize<=bufferLim-buffer) + { + memmove(buffer, bufferPtr, bufferEnd-bufferPtr); + bufferEnd=buffer+(bufferEnd-bufferPtr); + bufferPtr=buffer; + } + else + { + char *newBuf; + int bufferSize=bufferLim-bufferPtr; + + if (!bufferSize) + bufferSize=INIT_BUFFER_SIZE; + + do + { + bufferSize*=2; + } while (bufferSize 0 && (unsigned)code < sizeof(message)/sizeof(message[0])) + return message[code]; + + return 0; +}; + +enum XML_Error contentProcessor(void *parser, const char *start, const char *end, const char **endPtr) +{ + XML_Parser *p=(XML_Parser *) parser; + + return p->doContent(0, p->encoding, start, end, endPtr); +}; + +enum XML_Error externalEntityInitProcessor(void *parser, const char *start, const char *end, const char **endPtr) +{ + XML_Parser *p=(XML_Parser *) parser; + + enum XML_Error result = p->initializeEncoding(); + if (result != XML_ERROR_NONE) + return result; + + p->processor = externalEntityInitProcessor2; + return externalEntityInitProcessor2(p, start, end, endPtr); +} + +enum XML_Error externalEntityInitProcessor2(void *parser, const char *start, const char *end, const char **endPtr) +{ + XML_Parser *p=(XML_Parser *) parser; + const char *next; + + int tok=XmlContentTok(p->encoding, start, end, &next); + switch (tok) + { + case XML_TOK_BOM: + start=next; + break; + + case XML_TOK_PARTIAL: + if (endPtr) + { + *endPtr=start; + return XML_ERROR_NONE; + }; + + p->eventPtr=start; + return XML_ERROR_UNCLOSED_TOKEN; + + case XML_TOK_PARTIAL_CHAR: + if (endPtr) + { + *endPtr=start; + return XML_ERROR_NONE; + }; + + p->eventPtr=start; + return XML_ERROR_PARTIAL_CHAR; + }; + + p->processor=externalEntityInitProcessor3; + return externalEntityInitProcessor3(parser, start, end, endPtr); +} + +enum XML_Error externalEntityInitProcessor3(void *parser, const char *start, const char *end, const char **endPtr) +{ + XML_Parser *p=(XML_Parser *) parser; + const char *next; + + int tok=XmlContentTok(p->encoding, start, end, &next); + + switch (tok) { + case XML_TOK_XML_DECL: + { + enum XML_Error result=p->processXmlDecl(1, start, next); + + if (result!=XML_ERROR_NONE) + return result; + + start=next; + }; + + break; + + case XML_TOK_PARTIAL: + if (endPtr) + { + *endPtr=start; + return XML_ERROR_NONE; + }; + + p->eventPtr=start; + return XML_ERROR_UNCLOSED_TOKEN; + + case XML_TOK_PARTIAL_CHAR: + if (endPtr) + { + *endPtr=start; + return XML_ERROR_NONE; + }; + + p->eventPtr=start; + return XML_ERROR_PARTIAL_CHAR; + } + + p->processor=externalEntityContentProcessor; + p->tagLevel=1; + + return p->doContent(1, p->encoding, start, end, endPtr); +} + +enum XML_Error externalEntityContentProcessor(void *parser, const char *start, const char *end, const char **endPtr) +{ + XML_Parser *p=(XML_Parser *) parser; + + return p->doContent(1, p->encoding, start, end, endPtr); +} + +enum XML_Error XML_Parser::doContent(int startTagLevel, const ENCODING *enc, const char *s, const char *end, const char **nextPtr) +{ + const ENCODING *internalEnc=XmlGetInternalEncoding(); + const char *dummy; + const char **eventPP; + const char **eventEndPP; + + if (enc==encoding) + { + eventPP=&eventPtr; + *eventPP=s; + eventEndPP=&eventEndPtr; + } + else + eventPP=eventEndPP=&dummy; + + for (;;) + { + const char *next; + int tok=XmlContentTok(enc, s, end, &next); + *eventEndPP = next; + + switch (tok) { + case XML_TOK_TRAILING_CR: + if (nextPtr) + { + *nextPtr=s; + return XML_ERROR_NONE; + } + + *eventEndPP=end; + + if (characterDataHandler) + { + XML_Char c=XML_T('\n'); + CharacterDataHandler(&c, 1); + } + else + if (defaultHandler) + reportDefault(enc, s, end); + + if (!startTagLevel) return XML_ERROR_NO_ELEMENTS; + if (tagLevel!=startTagLevel) return XML_ERROR_ASYNC_ENTITY; + + return XML_ERROR_NONE; + + case XML_TOK_NONE: + if (nextPtr) + { + *nextPtr=s; + return XML_ERROR_NONE; + }; + + if (startTagLevel > 0) + { + if (tagLevel!=startTagLevel) return XML_ERROR_ASYNC_ENTITY; + + return XML_ERROR_NONE; + }; + + return XML_ERROR_NO_ELEMENTS; + + case XML_TOK_INVALID: + *eventPP=next; + return XML_ERROR_INVALID_TOKEN; + + case XML_TOK_PARTIAL: + if (nextPtr) + { + *nextPtr=s; + return XML_ERROR_NONE; + }; + + return XML_ERROR_UNCLOSED_TOKEN; + + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) + { + *nextPtr=s; + return XML_ERROR_NONE; + }; + + return XML_ERROR_PARTIAL_CHAR; + + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + XML_Char ch=XmlPredefinedEntityName(enc, + s+enc->minBytesPerChar, + next-enc->minBytesPerChar); + + if (ch) + { + if (characterDataHandler) + CharacterDataHandler(&ch, 1); + else if (defaultHandler) + reportDefault(enc, s, next); + + break; + }; + + name=poolStoreString(&dtd.pool, enc, s+enc->minBytesPerChar, + next-enc->minBytesPerChar); + + if (!name) return XML_ERROR_NO_MEMORY; + + entity=(ENTITY *) lookup(&dtd.generalEntities, name, 0); + poolDiscard(&dtd.pool); + + if (!entity) + { + if (dtd.complete || dtd.standalone) + return XML_ERROR_UNDEFINED_ENTITY; + + if (defaultHandler) + reportDefault(enc, s, next); + + break; + }; + + if (entity->open) return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->notation) return XML_ERROR_BINARY_ENTITY_REF; + + if (entity) + { + if (entity->textPtr) + { + enum XML_Error result; + + if (defaultHandler) + { + reportDefault(enc, s, next); + break; + }; + + /* Protect against the possibility that somebody sets + the defaultHandler from inside another handler. */ + + *eventEndPP=*eventPP; + entity->open=1; + + result=doContent(tagLevel, internalEnc, + (char *) entity->textPtr, + (char *) (entity->textPtr+entity->textLen), + 0); + + entity->open = 0; + + if (result) return result; + } + else if (externalEntityRefHandler) + { + const XML_Char *openEntityNames; + + entity->open=1; + openEntityNames=getOpenEntityNames(); + entity->open=0; + + if (!openEntityNames) return XML_ERROR_NO_MEMORY; + if (!ExternalEntityRefHandler(openEntityNames, dtd.base, entity->systemId, entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + + poolDiscard(&tempPool); + } + else if (defaultHandler) + reportDefault(enc, s, next); + }; + break; + } + + case XML_TOK_START_TAG_WITH_ATTS: + if (!startElementHandler) + { + enum XML_Error result=storeAtts(enc, 0, s); + + if (result) return result; + }; + + // fall through + + case XML_TOK_START_TAG_NO_ATTS: + { + TAG *tag; + + if (freeTagList) + { + tag=freeTagList; + freeTagList=freeTagList->parent; + } + else + { + tag=new TAG; + if (!tag) return XML_ERROR_NO_MEMORY; + + tag->buf=new char[INIT_TAG_BUF_SIZE]; + if (!tag->buf) return XML_ERROR_NO_MEMORY; + + tag->bufEnd=tag->buf+INIT_TAG_BUF_SIZE; + } + + tag->parent=tagStack; + tagStack=tag; + + tag->rawName=s+enc->minBytesPerChar; + tag->rawNameLength=XmlNameLength(enc, tag->rawName); + + if (nextPtr) + { + if (tag->rawNameLength>tag->bufEnd-tag->buf) + { + int bufSize=ROUND_UP(tag->rawNameLength*4, sizeof(XML_Char)); + + tag->buf=(char *) realloc(tag->buf, bufSize); + if (!tag->buf) return XML_ERROR_NO_MEMORY; + + tag->bufEnd=tag->buf+bufSize; + }; + + memcpy(tag->buf, tag->rawName, tag->rawNameLength); + tag->rawName=tag->buf; + }; + + tagLevel++; + + if (startElementHandler) + { + enum XML_Error result; + XML_Char *toPtr; + + for (;;) + { + const char *rawNameEnd=tag->rawName+tag->rawNameLength; + const char *fromPtr=tag->rawName; + int bufSize; + + if (nextPtr) + toPtr=(XML_Char *) (tag->buf+ROUND_UP(tag->rawNameLength, sizeof(XML_Char))); + else + toPtr=(XML_Char *) tag->buf; + + tag->name=toPtr; + + XmlConvert(enc, &fromPtr, rawNameEnd, + (ICHAR **) &toPtr, (ICHAR *) tag->bufEnd-1); + + if (fromPtr==rawNameEnd) break; + + bufSize=(tag->bufEnd-tag->buf) << 1; + tag->buf=(char *) realloc(tag->buf, bufSize); + + if (!tag->buf) return XML_ERROR_NO_MEMORY; + + tag->bufEnd=tag->buf+bufSize; + + if (nextPtr) tag->rawName=tag->buf; + }; + + *toPtr=XML_T('\0'); + + result=storeAtts(enc, tag->name, s); + if (result) return result; + + StartElementHandler(tag->name, (const XML_Char **) atts); + poolClear(&tempPool); + } + else + { + tag->name=0; + + if (defaultHandler) reportDefault(enc, s, next); + }; + + break; + } + + case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: + + if (!startElementHandler) + { + enum XML_Error result=storeAtts(enc, 0, s); + + if (result) return result; + }; + + // fall through */ + + case XML_TOK_EMPTY_ELEMENT_NO_ATTS: + if (startElementHandler || endElementHandler) + { + const char *rawName=s+enc->minBytesPerChar; + const XML_Char *name=poolStoreString(&tempPool, enc, rawName, + rawName + + XmlNameLength(enc, rawName)); + + if (!name) return XML_ERROR_NO_MEMORY; + + poolFinish(&tempPool); + + if (startElementHandler) + { + enum XML_Error result=storeAtts(enc, name, s); + + if (result) return result; + + StartElementHandler(name, (const XML_Char **) atts); + }; + + if (endElementHandler) + { + if (startElementHandler) *eventPP=*eventEndPP; + + EndElementHandler(name); + }; + + poolClear(&tempPool); + } + else if (defaultHandler) + reportDefault(enc, s, next); + + if (!tagLevel) + return epilogProcessor(this, next, end, nextPtr); + + break; + + case XML_TOK_END_TAG: + if (tagLevel==startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + else + { + int len; + const char *rawName; + + TAG *tag=tagStack; + tagStack=tag->parent; + tag->parent=freeTagList; + freeTagList=tag; + + rawName=s+enc->minBytesPerChar*2; + len=XmlNameLength(enc, rawName); + + if (len!=tag->rawNameLength || memcmp(tag->rawName, rawName, len)!=0) + { + *eventPP = rawName; + return XML_ERROR_TAG_MISMATCH; + }; + + --tagLevel; + + if (endElementHandler) + { + if (tag->name) + EndElementHandler(tag->name); + else + { + const XML_Char *name=poolStoreString(&tempPool, enc, rawName, + rawName+len); + + if (!name) return XML_ERROR_NO_MEMORY; + + EndElementHandler(name); + poolClear(&tempPool); + }; + } + else if (defaultHandler) + reportDefault(enc, s, next); + + if (!tagLevel) + return epilogProcessor(this, next, end, nextPtr); + }; + + break; + + case XML_TOK_CHAR_REF: + { + int n=XmlCharRefNumber(enc, s); + + if (n<0) return XML_ERROR_BAD_CHAR_REF; + + if (characterDataHandler) + { + XML_Char buf[XML_ENCODE_MAX]; + CharacterDataHandler(buf, XmlEncode(n, (ICHAR *) buf)); + } + else if (defaultHandler) + reportDefault(enc, s, next); + } + + break; + + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) + { + XML_Char c=XML_T('\n'); + CharacterDataHandler(&c, 1); + } + else if (defaultHandler) + reportDefault(enc, s, next); + + break; + + case XML_TOK_CDATA_SECT_OPEN: + { + enum XML_Error result; + + if (characterDataHandler) + CharacterDataHandler(dataBuf, 0); + else if (defaultHandler) + reportDefault(enc, s, next); + + result=doCdataSection(enc, &next, end, nextPtr); + + if (!next) + { + processor=cdataSectionProcessor; + return result; + }; + }; + + break; + + case XML_TOK_TRAILING_RSQB: + if (nextPtr) + { + *nextPtr=s; + return XML_ERROR_NONE; + }; + + if (characterDataHandler) + { + if (MUST_CONVERT(enc, s)) + { + ICHAR *dataPtr=(ICHAR *) dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *) dataBufEnd); + + CharacterDataHandler(dataBuf, dataPtr - (ICHAR *) dataBuf); + } + else + CharacterDataHandler((XML_Char *) s, (XML_Char *) end-(XML_Char *) s); + } + else if (defaultHandler) + reportDefault(enc, s, end); + + if (!startTagLevel) + { + *eventPP=end; + return XML_ERROR_NO_ELEMENTS; + }; + + if (tagLevel!=startTagLevel) + { + *eventPP=end; + return XML_ERROR_ASYNC_ENTITY; + }; + + return XML_ERROR_NONE; + + case XML_TOK_DATA_CHARS: + if (characterDataHandler) + { + if (MUST_CONVERT(enc, s)) + { + for (;;) + { + ICHAR *dataPtr=(ICHAR *) dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *) dataBufEnd); + + *eventEndPP = s; + CharacterDataHandler(dataBuf, dataPtr-(ICHAR *) dataBuf); + + if (s==next) break; + *eventPP = s; + }; + } + else + CharacterDataHandler((XML_Char *) s, (XML_Char *) next-(XML_Char *) s); + } + else if (defaultHandler) + reportDefault(enc, s, next); + + break; + + case XML_TOK_PI: + if (!reportProcessingInstruction(enc, s, next)) + return XML_ERROR_NO_MEMORY; + + break; + + default: + if (defaultHandler) + reportDefault(enc, s, next); + + break; + }; + + *eventPP=s=next; + }; + + // not reached +}; + +/* If tagName is non-null, build a real list of attributes, +otherwise just check the attributes for well-formedness. */ + +enum XML_Error XML_Parser::storeAtts(const ENCODING *enc, const XML_Char *tagName, const char *s) +{ + ELEMENT_TYPE *elementType=0; + int nDefaultAtts=0; + const XML_Char **appAtts; + int i; + int n; + + if (tagName) + { + elementType=(ELEMENT_TYPE *) lookup(&dtd.elementTypes, tagName, 0); + + if (elementType) + nDefaultAtts=elementType->nDefaultAtts; + } + + n=XmlGetAttributes(enc, s, attsSize, atts); + + if (n+nDefaultAtts>attsSize) + { + int oldAttsSize=attsSize; + + attsSize=n+nDefaultAtts+INIT_ATTS_SIZE; + + atts=(ATTRIBUTE *) realloc((void *) atts, attsSize*sizeof(ATTRIBUTE)); + + if (!atts) return XML_ERROR_NO_MEMORY; + + if (n>oldAttsSize) XmlGetAttributes(enc, s, n, atts); + }; + + appAtts=(const XML_Char **) atts; + + for (i=0; iname)[-1]) + { + if (enc==encoding) eventPtr=atts[i].name; + + return XML_ERROR_DUPLICATE_ATTRIBUTE; + }; + + (attId->name)[-1]=1; + + appAtts[i<<1]=attId->name; + + if (!atts[i].normalized) + { + enum XML_Error result; + int isCdata=1; + + if (attId->maybeTokenized) + { + for (int j=0; jdefaultAtts[j].id) + { + isCdata=elementType->defaultAtts[j].isCdata; + break; + }; + }; + }; + + result=storeAttributeValue(enc, isCdata, atts[i].valuePtr, + atts[i].valueEnd, &tempPool); + + if (result) return result; + + if (tagName) + { + appAtts[(i<<1)+1]=poolStart(&tempPool); + poolFinish(&tempPool); + } + else + poolDiscard(&tempPool); + } + else if (tagName) + { + appAtts[(i<<1)+1]=poolStoreString(&tempPool, enc, atts[i].valuePtr, atts[i].valueEnd); + + if (appAtts[(i<<1)+1]==0) return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + }; + }; + + if (tagName) + { + for (int j=0; jdefaultAtts+j; + + if (!(da->id->name)[-1] && da->value) + { + (da->id->name)[-1]=1; + appAtts[i<<1]=da->id->name; + appAtts[(i<<1)+1]=da->value; + i++; + }; + }; + appAtts[i<<1]=0; + }; + + while (i-->0) ((XML_Char *)appAtts[i<<1])[-1]=0; + + return XML_ERROR_NONE; +}; + +/* The idea here is to avoid using stack for each CDATA section when +the whole file is parsed with one call. */ + +enum XML_Error cdataSectionProcessor(void *parser, const char *start, const char *end, const char **endPtr) +{ + XML_Parser *p=(XML_Parser *) parser; + + enum XML_Error result=p->doCdataSection(p->encoding, &start, end, endPtr); + + if (start) + { + p->processor=contentProcessor; + return contentProcessor(parser, start, end, endPtr); + }; + + return result; +}; + +/* startPtr gets set to non-null is the section is closed, and to null if +the section is not yet closed. */ + +enum XML_Error XML_Parser::doCdataSection(const ENCODING *enc, const char **startPtr, const char *end, const char **nextPtr) +{ + const char *s=*startPtr; + const char *dummy; + const char **eventPP; + const char **eventEndPP; + + if (enc==encoding) + { + eventPP=&eventPtr; + *eventPP=s; + eventEndPP=&eventEndPtr; + } + else + eventPP=eventEndPP=&dummy; + + *startPtr=0; + + for (;;) + { + const char *next; + + int tok=XmlCdataSectionTok(enc, s, end, &next); + + *eventEndPP = next; + + switch (tok) + { + case XML_TOK_CDATA_SECT_CLOSE: + if (characterDataHandler) + CharacterDataHandler(dataBuf, 0); + else if (defaultHandler) + reportDefault(enc, s, next); + + *startPtr = next; + return XML_ERROR_NONE; + + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) + { + XML_Char c=XML_T('\n'); + CharacterDataHandler(&c, 1); + } + else if (defaultHandler) + reportDefault(enc, s, next); + + break; + + case XML_TOK_DATA_CHARS: + if (characterDataHandler) + { + if (MUST_CONVERT(enc, s)) + { + for (;;) + { + ICHAR *dataPtr=(ICHAR *) dataBuf; + + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *) dataBufEnd); + + *eventEndPP=next; + CharacterDataHandler(dataBuf, dataPtr-(ICHAR *) dataBuf); + + if (s==next) break; + *eventPP=s; + }; + } + else + CharacterDataHandler((XML_Char *) s, (XML_Char *) next-(XML_Char *) s); + } + else if (defaultHandler) + reportDefault(enc, s, next); + + break; + + case XML_TOK_INVALID: + *eventPP=next; + return XML_ERROR_INVALID_TOKEN; + + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) + { + *nextPtr=s; + return XML_ERROR_NONE; + }; + + return XML_ERROR_PARTIAL_CHAR; + + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (nextPtr) + { + *nextPtr=s; + return XML_ERROR_NONE; + } + + return XML_ERROR_UNCLOSED_CDATA_SECTION; + default: + abort(); + }; + + *eventPP=s=next; + }; + + // not reached +}; + +enum XML_Error XML_Parser::initializeEncoding() +{ + const char *s; +#ifdef XML_UNICODE + char encodingBuf[128]; + + if (!protocolEncodingName) + s=0; + else + { + for (int i=0; protocolEncodingName[i]; i++) + { + if (i==sizeof(encodingBuf)-1 + || protocolEncodingName[i]>=0x80 + || protocolEncodingName[i]<0) + { + encodingBuf[0]='\0'; + break; + }; + + encodingBuf[i]=(char) protocolEncodingName[i]; + }; + + encodingBuf[i]='\0'; + s=encodingBuf; + }; +#else + s=protocolEncodingName; +#endif + + if (XmlInitEncoding(&initEncoding, &encoding, s)) return XML_ERROR_NONE; + + return handleUnknownEncoding(protocolEncodingName); +}; + +enum XML_Error XML_Parser::processXmlDecl(int isGeneralTextEntity, const char *s, const char *next) +{ + const char *encodingName=0; + const ENCODING *newEncoding=0; + const char *version; + int standalone=-1; + + if (!XmlParseXmlDecl(isGeneralTextEntity, encoding, s, next, &eventPtr, + &version, &encodingName, &newEncoding, &standalone)) + return XML_ERROR_SYNTAX; + + if (!isGeneralTextEntity && standalone==1) dtd.standalone=1; + + if (defaultHandler) reportDefault(encoding, s, next); + + if (!protocolEncodingName) + { + if (newEncoding) + { + if (newEncoding->minBytesPerChar!=encoding->minBytesPerChar) + { + eventPtr=encodingName; + return XML_ERROR_INCORRECT_ENCODING; + }; + + encoding=newEncoding; + } + else if (encodingName) + { + enum XML_Error result; + const XML_Char *s=poolStoreString(&tempPool, encoding, encodingName, + encodingName + + XmlNameLength(encoding, encodingName)); + + if (!s) return XML_ERROR_NO_MEMORY; + + result=handleUnknownEncoding(s); + + poolDiscard(&tempPool); + + if (result==XML_ERROR_UNKNOWN_ENCODING) eventPtr=encodingName; + return result; + }; + }; + + return XML_ERROR_NONE; +}; + +enum XML_Error XML_Parser::handleUnknownEncoding(const XML_Char *encodingName) +{ + if (unknownEncodingHandler) + { + XML_Encoding info; + + for (int i=0; i<256; i++) info.map[i]=-1; + + info.convert=0; + info.data=0; + info.release=0; + + if (UnknownEncodingHandler(unknownEncodingHandlerData, encodingName, &info)) + { + ENCODING *enc; + unknownEncodingMem=malloc(XmlSizeOfUnknownEncoding()); + if (!unknownEncodingMem) + { + if (info.release) info.release(info.data); + return XML_ERROR_NO_MEMORY; + }; + + enc=XmlInitUnknownEncoding(unknownEncodingMem, info.map, info.convert, + info.data); + + if (enc) + { + unknownEncodingData=info.data; + unknownEncodingRelease=info.release; + encoding=enc; + return XML_ERROR_NONE; + }; + }; + + if (info.release) info.release(info.data); + }; + + return XML_ERROR_UNKNOWN_ENCODING; +}; + +enum XML_Error prologInitProcessor(void *parser, const char *s, const char *end, const char **nextPtr) +{ + XML_Parser *p=(XML_Parser *) parser; + + enum XML_Error result=p->initializeEncoding(); + + if (result!=XML_ERROR_NONE) return result; + + p->processor=prologProcessor; + return prologProcessor(parser, s, end, nextPtr); +} + +enum XML_Error prologProcessor(void *parser, const char *s, const char *end, const char **nextPtr) +{ + XML_Parser *p=(XML_Parser *) parser; + + for (;;) + { + const char *next; + + int tok=XmlPrologTok(p->encoding, s, end, &next); + + if (tok<=0) + { + if (nextPtr!=0 && tok!=XML_TOK_INVALID) + { + *nextPtr=s; + return XML_ERROR_NONE; + }; + + switch (tok) + { + case XML_TOK_INVALID: + p->eventPtr=next; + return XML_ERROR_INVALID_TOKEN; + + case XML_TOK_NONE: + return XML_ERROR_NO_ELEMENTS; + + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + + case XML_TOK_TRAILING_CR: + p->eventPtr=s+p->encoding->minBytesPerChar; + return XML_ERROR_NO_ELEMENTS; + + default: + abort(); + }; + }; + + switch (XmlTokenRole(&p->prologState, tok, s, next, p->encoding)) + { + case XML_ROLE_XML_DECL: + { + enum XML_Error result=p->processXmlDecl(0, s, next); + + if (result!=XML_ERROR_NONE) return result; + } + break; + + case XML_ROLE_DOCTYPE_SYSTEM_ID: + p->hadExternalDoctype=1; + break; + + case XML_ROLE_DOCTYPE_PUBLIC_ID: + case XML_ROLE_ENTITY_PUBLIC_ID: + if (!XmlIsPublicId(p->encoding, s, next, &p->eventPtr)) + return XML_ERROR_SYNTAX; + + if (p->declEntity) + { + XML_Char *tem=poolStoreString(&p->dtd.pool, p->encoding, + s+p->encoding->minBytesPerChar, + next-p->encoding->minBytesPerChar); + + if (!tem) return XML_ERROR_NO_MEMORY; + + p->normalizePublicId(tem); + p->declEntity->publicId=tem; + poolFinish(&p->dtd.pool); + } + + break; + + case XML_ROLE_INSTANCE_START: + p->processor=contentProcessor; + + if (p->hadExternalDoctype) p->dtd.complete=0; + + return contentProcessor(parser, s, end, nextPtr); + + case XML_ROLE_ATTLIST_ELEMENT_NAME: + { + const XML_Char *name=poolStoreString(&p->dtd.pool, p->encoding, s, next); + + if (!name) return XML_ERROR_NO_MEMORY; + + p->declElementType=(ELEMENT_TYPE *) lookup(&p->dtd.elementTypes, name, sizeof(ELEMENT_TYPE)); + + if (!p->declElementType) return XML_ERROR_NO_MEMORY; + + if (p->declElementType->name!=name) + poolDiscard(&p->dtd.pool); + else + poolFinish(&p->dtd.pool); + + break; + }; + + case XML_ROLE_ATTRIBUTE_NAME: + p->declAttributeId=p->getAttributeId(p->encoding, s, next); + + if (!p->declAttributeId) return XML_ERROR_NO_MEMORY; + + p->declAttributeIsCdata=0; + + break; + + case XML_ROLE_ATTRIBUTE_TYPE_CDATA: + p->declAttributeIsCdata=1; + break; + + case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: + case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: + if (p->dtd.complete && + !p->defineAttribute(p->declElementType, p->declAttributeId, p->declAttributeIsCdata, 0)) + return XML_ERROR_NO_MEMORY; + + break; + + case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: + case XML_ROLE_FIXED_ATTRIBUTE_VALUE: + { + const XML_Char *attVal; + enum XML_Error result=p->storeAttributeValue(p->encoding, p->declAttributeIsCdata, + s+p->encoding->minBytesPerChar, + next-p->encoding->minBytesPerChar, &p->dtd.pool); + + if (result) return result; + + attVal=poolStart(&p->dtd.pool); + poolFinish(&p->dtd.pool); + + if (p->dtd.complete && + !p->defineAttribute(p->declElementType, p->declAttributeId, p->declAttributeIsCdata, attVal)) + return XML_ERROR_NO_MEMORY; + + break; + }; + + case XML_ROLE_ENTITY_VALUE: + { + enum XML_Error result=p->storeEntityValue(s, next); + if (result!=XML_ERROR_NONE) return result; + }; + + break; + + case XML_ROLE_ENTITY_SYSTEM_ID: + if (p->declEntity) + { + p->declEntity->systemId=poolStoreString(&p->dtd.pool, p->encoding, + s+p->encoding->minBytesPerChar, + next-p->encoding->minBytesPerChar); + + if (!p->declEntity->systemId) return XML_ERROR_NO_MEMORY; + + p->declEntity->base=p->dtd.base; + poolFinish(&p->dtd.pool); + }; + + break; + + case XML_ROLE_ENTITY_NOTATION_NAME: + if (p->declEntity) + { + p->declEntity->notation=poolStoreString(&p->dtd.pool, p->encoding, s, next); + + if (!p->declEntity->notation) return XML_ERROR_NO_MEMORY; + + poolFinish(&p->dtd.pool); + + if (p->unparsedEntityDeclHandler) + { + p->eventPtr=p->eventEndPtr=s; + + p->UnparsedEntityDeclHandler(p->declEntity->name, p->declEntity->base, + p->declEntity->systemId, p->declEntity->publicId, + p->declEntity->notation); + }; + }; + + break; + + case XML_ROLE_GENERAL_ENTITY_NAME: + { + const XML_Char *name; + + if (XmlPredefinedEntityName(p->encoding, s, next)) + { + p->declEntity=0; + break; + }; + + name=poolStoreString(&p->dtd.pool, p->encoding, s, next); + + if (!name) return XML_ERROR_NO_MEMORY; + + if (p->dtd.complete) + { + p->declEntity=(ENTITY *) lookup(&p->dtd.generalEntities, name, sizeof(ENTITY)); + + if (!p->declEntity) return XML_ERROR_NO_MEMORY; + + if (p->declEntity->name!=name) + { + poolDiscard(&p->dtd.pool); + p->declEntity=0; + } + else + poolFinish(&p->dtd.pool); + } + else + { + poolDiscard(&p->dtd.pool); + p->declEntity=0; + }; + }; + + break; + + case XML_ROLE_PARAM_ENTITY_NAME: + p->declEntity=0; + break; + + case XML_ROLE_NOTATION_NAME: + p->declNotationPublicId=0; + p->declNotationName=0; + + if (p->notationDeclHandler) + { + p->declNotationName=poolStoreString(&p->tempPool, p->encoding, s, next); + + if (!p->declNotationName) return XML_ERROR_NO_MEMORY; + poolFinish(&p->tempPool); + }; + + break; + + case XML_ROLE_NOTATION_PUBLIC_ID: + if (!XmlIsPublicId(p->encoding, s, next, &p->eventPtr)) + return XML_ERROR_SYNTAX; + + if (p->declNotationName) + { + XML_Char *tem=poolStoreString(&p->tempPool, p->encoding, + s+p->encoding->minBytesPerChar, + next-p->encoding->minBytesPerChar); + + if (!tem) return XML_ERROR_NO_MEMORY; + + p->normalizePublicId(tem); + p->declNotationPublicId=tem; + poolFinish(&p->tempPool); + }; + + break; + + case XML_ROLE_NOTATION_SYSTEM_ID: + if (p->declNotationName && p->notationDeclHandler) + { + const XML_Char *systemId=poolStoreString(&p->tempPool, p->encoding, + s+p->encoding->minBytesPerChar, + next-p->encoding->minBytesPerChar); + + if (!systemId) return XML_ERROR_NO_MEMORY; + + p->eventPtr=p->eventEndPtr=s; + + p->NotationDeclHandler(p->declNotationName, p->dtd.base, systemId, + p->declNotationPublicId); + }; + + poolClear(&p->tempPool); + break; + + case XML_ROLE_NOTATION_NO_SYSTEM_ID: + if (p->declNotationPublicId && p->notationDeclHandler) + { + p->eventPtr=p->eventEndPtr=s; + + p->NotationDeclHandler(p->declNotationName, p->dtd.base, 0, + p->declNotationPublicId); + }; + + poolClear(&p->tempPool); + break; + + case XML_ROLE_ERROR: + p->eventPtr=s; + + switch (tok) + { + case XML_TOK_PARAM_ENTITY_REF: + return XML_ERROR_PARAM_ENTITY_REF; + + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + + default: + return XML_ERROR_SYNTAX; + }; + + case XML_ROLE_GROUP_OPEN: + if (p->prologState.level>=p->groupSize) + { + if (p->groupSize) + p->groupConnector=(char *) realloc(p->groupConnector, p->groupSize*=2); + else + p->groupConnector=(char *) malloc(p->groupSize=32); + + if (!p->groupConnector) return XML_ERROR_NO_MEMORY; + }; + + p->groupConnector[p->prologState.level]=0; + break; + + case XML_ROLE_GROUP_SEQUENCE: + if (p->groupConnector[p->prologState.level]=='|') + { + p->eventPtr=s; + return XML_ERROR_SYNTAX; + }; + + p->groupConnector[p->prologState.level]=','; + break; + + case XML_ROLE_GROUP_CHOICE: + if (p->groupConnector[p->prologState.level]==',') + { + p->eventPtr=s; + return XML_ERROR_SYNTAX; + }; + + p->groupConnector[p->prologState.level]='|'; + break; + + case XML_ROLE_PARAM_ENTITY_REF: + p->dtd.complete=0; + break; + + case XML_ROLE_NONE: + switch (tok) + { + case XML_TOK_PI: + p->eventPtr=s; + p->eventEndPtr=next; + + if (!p->reportProcessingInstruction(p->encoding, s, next)) + return XML_ERROR_NO_MEMORY; + + break; + }; + + break; + }; + + if (p->defaultHandler) + { + switch (tok) + { + case XML_TOK_PI: + case XML_TOK_BOM: + case XML_TOK_XML_DECL: + break; + + default: + p->eventPtr=s; + p->eventEndPtr=next; + p->reportDefault(p->encoding, s, next); + }; + }; + + s=next; + }; + + // not reached +}; + +enum XML_Error epilogProcessor(void *parser, const char *s, const char *end, const char **nextPtr) +{ + XML_Parser *p=(XML_Parser *) parser; + + p->processor=epilogProcessor; + p->eventPtr=s; + + for (;;) + { + const char *next; + + int tok=XmlPrologTok(p->encoding, s, end, &next); + p->eventEndPtr=next; + + switch (tok) { + case XML_TOK_TRAILING_CR: + if (p->defaultHandler) + { + p->eventEndPtr=end; + p->reportDefault(p->encoding, s, end); + }; + + // fall through + + case XML_TOK_NONE: + if (nextPtr) *nextPtr=end; + return XML_ERROR_NONE; + + case XML_TOK_PROLOG_S: + case XML_TOK_COMMENT: + if (p->defaultHandler) p->reportDefault(p->encoding, s, next); + break; + + case XML_TOK_PI: + if (!p->reportProcessingInstruction(p->encoding, s, next)) + return XML_ERROR_NO_MEMORY; + + break; + + case XML_TOK_INVALID: + p->eventPtr=next; + return XML_ERROR_INVALID_TOKEN; + + case XML_TOK_PARTIAL: + if (nextPtr) + { + *nextPtr=s; + return XML_ERROR_NONE; + }; + + return XML_ERROR_UNCLOSED_TOKEN; + + case XML_TOK_PARTIAL_CHAR: + if (nextPtr) + { + *nextPtr=s; + return XML_ERROR_NONE; + }; + + return XML_ERROR_PARTIAL_CHAR; + + default: + return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; + }; + + p->eventPtr=s=next; + }; +}; + +enum XML_Error errorProcessor(void *parser, const char* /*s*/, const char* /*end*/, const char** /*nextPtr*/) +{ + XML_Parser *p=(XML_Parser *) parser; + + return p->errorCode; +}; + +enum XML_Error XML_Parser::storeAttributeValue(const ENCODING *enc, int isCdata, const char *ptr, const char *end, STRING_POOL *pool) +{ + enum XML_Error result=appendAttributeValue(enc, isCdata, ptr, end, pool); + + if (result) return result; + + if (!isCdata && poolLength(pool) && poolLastChar(pool) == XML_T(' ')) + poolChop(pool); + + if (!poolAppendChar(pool, XML_T('\0'))) return XML_ERROR_NO_MEMORY; + + return XML_ERROR_NONE; +}; + +enum XML_Error XML_Parser::appendAttributeValue(const ENCODING *enc, int isCdata, const char *ptr, const char *end, STRING_POOL *pool) +{ + const ENCODING *internalEnc=XmlGetInternalEncoding(); + + for (;;) + { + const char *next; + int tok=XmlAttributeValueTok(enc, ptr, end, &next); + + switch (tok) + { + case XML_TOK_NONE: + return XML_ERROR_NONE; + + case XML_TOK_INVALID: + if (enc==encoding) eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + + case XML_TOK_PARTIAL: + if (enc==encoding) eventPtr = ptr; + return XML_ERROR_INVALID_TOKEN; + + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n=XmlCharRefNumber(enc, ptr); + + if (n<0) + { + if (enc==encoding) eventPtr=ptr; + return XML_ERROR_BAD_CHAR_REF; + }; + + if (!isCdata && n==0x20 && (poolLength(pool)==0 || + poolLastChar(pool)==XML_T(' '))) break; + + n=XmlEncode(n, (ICHAR *) buf); + + if (!n) + { + if (enc==encoding) eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + }; + + for (i=0; iminBytesPerChar; + // fall through + + case XML_TOK_ATTRIBUTE_VALUE_S: + case XML_TOK_DATA_NEWLINE: + if (!isCdata && (poolLength(pool)==0 || poolLastChar(pool)==XML_T(' '))) + break; + + if (!poolAppendChar(pool, XML_T(' '))) return XML_ERROR_NO_MEMORY; + break; + + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + XML_Char ch=XmlPredefinedEntityName(enc, + ptr+enc->minBytesPerChar, + next-enc->minBytesPerChar); + + if (ch) + { + if (!poolAppendChar(pool, ch)) return XML_ERROR_NO_MEMORY; + break; + }; + + name=poolStoreString(&temp2Pool, enc, + ptr+enc->minBytesPerChar, + next-enc->minBytesPerChar); + + if (!name) return XML_ERROR_NO_MEMORY; + + entity=(ENTITY *) lookup(&dtd.generalEntities, name, 0); + + poolDiscard(&temp2Pool); + + if (!entity) + { + if (dtd.complete) + { + if (enc==encoding) eventPtr=ptr; + return XML_ERROR_UNDEFINED_ENTITY; + }; + } + else if (entity->open) + { + if (enc==encoding) eventPtr = ptr; + return XML_ERROR_RECURSIVE_ENTITY_REF; + } + else if (entity->notation) + { + if (enc==encoding) eventPtr=ptr; + return XML_ERROR_BINARY_ENTITY_REF; + } + else if (!entity->textPtr) + { + if (enc==encoding) eventPtr=ptr; + return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; + } + else + { + enum XML_Error result; + const XML_Char *textEnd=entity->textPtr+entity->textLen; + + entity->open=1; + result=appendAttributeValue(internalEnc, isCdata, (char *) entity->textPtr, (char *) textEnd, pool); + entity->open = 0; + + if (result) return result; + }; + }; + break; + + default: + abort(); + }; + + ptr=next; + }; + + // not reached +}; + +enum XML_Error XML_Parser::storeEntityValue(const char *entityTextPtr, const char *entityTextEnd) +{ +// const ENCODING *internalEnc=XmlGetInternalEncoding(); + STRING_POOL *pool=&(dtd.pool); + + entityTextPtr+=encoding->minBytesPerChar; + entityTextEnd-=encoding->minBytesPerChar; + + for (;;) + { + const char *next; + + int tok=XmlEntityValueTok(encoding, entityTextPtr, entityTextEnd, &next); + + switch (tok) + { + case XML_TOK_PARAM_ENTITY_REF: + eventPtr=entityTextPtr; + return XML_ERROR_SYNTAX; + + case XML_TOK_NONE: + if (declEntity) + { + declEntity->textPtr=pool->start; + declEntity->textLen=pool->ptr-pool->start; + poolFinish(pool); + } + else + poolDiscard(pool); + + return XML_ERROR_NONE; + + case XML_TOK_ENTITY_REF: + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, encoding, entityTextPtr, next)) + return XML_ERROR_NO_MEMORY; + break; + + case XML_TOK_TRAILING_CR: + next=entityTextPtr+encoding->minBytesPerChar; + // fall through + + case XML_TOK_DATA_NEWLINE: + if (pool->end==pool->ptr && !poolGrow(pool)) + return XML_ERROR_NO_MEMORY; + + *(pool->ptr)++=XML_T('\n'); + break; + + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n=XmlCharRefNumber(encoding, entityTextPtr); + + if (n<0) + { + eventPtr=entityTextPtr; + return XML_ERROR_BAD_CHAR_REF; + }; + + n=XmlEncode(n, (ICHAR *) buf); + + if (!n) + { + eventPtr=entityTextPtr; + return XML_ERROR_BAD_CHAR_REF; + }; + + for (i=0; iend==pool->ptr && !poolGrow(pool)) + return XML_ERROR_NO_MEMORY; + + *(pool->ptr)++=buf[i]; + }; + }; + + break; + + case XML_TOK_PARTIAL: + eventPtr=entityTextPtr; + return XML_ERROR_INVALID_TOKEN; + + case XML_TOK_INVALID: + eventPtr=next; + return XML_ERROR_INVALID_TOKEN; + + default: + abort(); + }; + + entityTextPtr=next; + }; + + // not reached +}; + +static void normalizeLines(XML_Char *s) +{ + XML_Char *p; + + for (;; s++) + { + if (*s==XML_T('\0')) return; + if (*s==XML_T('\r')) break; + }; + + p=s; + + do + { + if (*s==XML_T('\r')) + { + *p++=XML_T('\n'); + if (*++s==XML_T('\n')) s++; + } + else + *p++ = *s++; + } while (*s); + + *p=XML_T('\0'); +}; + +int XML_Parser::reportProcessingInstruction(const ENCODING *enc, const char *start, const char *end) +{ + const XML_Char *target; + XML_Char *data; + const char *tem; + + if (!processingInstructionHandler) + { + if (defaultHandler) reportDefault(enc, start, end); + return 1; + }; + + start+=enc->minBytesPerChar*2; + tem=start+XmlNameLength(enc, start); + + target=poolStoreString(&tempPool, enc, start, tem); + if (!target) return 0; + + poolFinish(&tempPool); + + data=poolStoreString(&tempPool, enc, XmlSkipS(enc, tem), end-enc->minBytesPerChar*2); + if (!data) return 0; + + normalizeLines(data); + + ProcessingInstructionHandler(target, data); + + poolClear(&tempPool); + + return 1; +}; + +void XML_Parser::reportDefault(const ENCODING *enc, const char *s, const char *end) +{ + if (MUST_CONVERT(enc, s)) + { + for (;;) + { + ICHAR *dataPtr=(ICHAR *) dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *) dataBufEnd); + + if (s==end) + { + DefaultHandler(dataBuf, dataPtr-(ICHAR *) dataBuf); + break; + }; + + if (enc==encoding) + { + eventEndPtr=s; + DefaultHandler(dataBuf, dataPtr-(ICHAR *) dataBuf); + eventPtr=s; + } + else + DefaultHandler(dataBuf, dataPtr-(ICHAR *) dataBuf); + }; + } + else + DefaultHandler((XML_Char *) s, (XML_Char *) end-(XML_Char *) s); +}; + +int XML_Parser::defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, int isCdata, const XML_Char *value) +{ + DEFAULT_ATTRIBUTE *att; + + if (type->nDefaultAtts==type->allocDefaultAtts) + { + if (type->allocDefaultAtts==0) + { + type->allocDefaultAtts=8; + type->defaultAtts=new DEFAULT_ATTRIBUTE[type->allocDefaultAtts]; + } + else + { + type->allocDefaultAtts*=2; + type->defaultAtts=(DEFAULT_ATTRIBUTE *) realloc(type->defaultAtts, type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); + }; + + if (!type->defaultAtts) return 0; + }; + + att=type->defaultAtts+type->nDefaultAtts; + + att->id=attId; + att->value=value; + att->isCdata=isCdata; + + if (!isCdata) attId->maybeTokenized=1; + + type->nDefaultAtts+=1; + + return 1; +}; + +ATTRIBUTE_ID *XML_Parser::getAttributeId(const ENCODING *enc, const char *start, const char *end) +{ + ATTRIBUTE_ID *id; + const XML_Char *name; + + if (!poolAppendChar(&dtd.pool, XML_T('\0'))) return 0; + + name=poolStoreString(&dtd.pool, enc, start, end); + if (!name) return 0; + ++name; + + id=(ATTRIBUTE_ID *) lookup(&dtd.attributeIds, name, sizeof(ATTRIBUTE_ID)); + if (!id) return 0; + + if (id->name!=name) + poolDiscard(&dtd.pool); + else + poolFinish(&dtd.pool); + + return id; +}; + +const XML_Char *XML_Parser::getOpenEntityNames() +{ + HASH_TABLE_ITER iter; + + hashTableIterInit(&iter, &(dtd.generalEntities)); + + for (;;) + { + const XML_Char *s; + ENTITY *e=(ENTITY *) hashTableIterNext(&iter); + + if (!e) break; + if (!e->open) continue; + + if (poolLength(&tempPool)>0 && !poolAppendChar(&tempPool, XML_T(' '))) + return 0; + + for (s = e->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return 0; + }; + + if (!poolAppendChar(&tempPool, XML_T('\0'))) return 0; + + return tempPool.start; +}; + +int XML_Parser::setOpenEntityNames(const XML_Char *openEntityNames) +{ + const XML_Char *s=openEntityNames; + + while (*openEntityNames!=XML_T('\0')) + { + if (*s==XML_T(' ') || *s==XML_T('\0')) + { + ENTITY *e; + + if (!poolAppendChar(&tempPool, XML_T('\0'))) return 0; + + e=(ENTITY *)lookup(&dtd.generalEntities, poolStart(&tempPool), 0); + + if (e) e->open = 1; + if (*s == XML_T(' ')) s++; + + openEntityNames=s; + poolDiscard(&tempPool); + } + else + { + if (!poolAppendChar(&tempPool, *s)) return 0; + s++; + }; + }; + + return 1; +}; + + +void XML_Parser::normalizePublicId(XML_Char *publicId) +{ + XML_Char *p=publicId; + XML_Char *s; + + for (s=publicId; *s; s++) + { + switch (*s) + { + case XML_T(' '): + case XML_T('\r'): + case XML_T('\n'): + if (p!=publicId && p[-1]!=XML_T(' ')) *p++=XML_T(' '); + break; + + default: + *p++=*s; + }; + }; + + if (p!=publicId && p[-1]==XML_T(' ')) --p; + *p=XML_T('\0'); +}; + +static int dtdInit(DTD *p) +{ + poolInit(&(p->pool)); + + hashTableInit(&(p->generalEntities)); + hashTableInit(&(p->elementTypes)); + hashTableInit(&(p->attributeIds)); + + p->complete=1; + p->standalone=0; + p->base=0; + + return 1; +}; + +static void dtdDestroy(DTD *p) +{ + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + + for (;;) + { + ELEMENT_TYPE *e=(ELEMENT_TYPE *) hashTableIterNext(&iter); + + if (!e) break; + if (e->allocDefaultAtts!=0) free(e->defaultAtts); + }; + + hashTableDestroy(&(p->generalEntities)); + hashTableDestroy(&(p->elementTypes)); + hashTableDestroy(&(p->attributeIds)); + + poolDestroy(&(p->pool)); +}; + +/* Do a deep copy of the DTD. Return 0 for out of memory; non-zero otherwise. + The new DTD has already been initialized. */ + +static int dtdCopy(DTD *newDtd, const DTD *oldDtd) +{ + HASH_TABLE_ITER iter; + + if (oldDtd->base) + { + const XML_Char *tem=poolCopyString(&(newDtd->pool), oldDtd->base); + if (!tem) return 0; + newDtd->base=tem; + }; + + hashTableIterInit(&iter, &(oldDtd->attributeIds)); + + // Copy the attribute id table. + + for (;;) + { + ATTRIBUTE_ID *newA; + const XML_Char *name; + const ATTRIBUTE_ID *oldA=(ATTRIBUTE_ID *) hashTableIterNext(&iter); + + if (!oldA) break; + + // Remember to allocate the scratch byte before the name. + + if (!poolAppendChar(&(newDtd->pool), XML_T('\0'))) return 0; + + name=poolCopyString(&(newDtd->pool), oldA->name); + + if (!name) return 0; + ++name; + + newA=(ATTRIBUTE_ID *) lookup(&(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); + + if (!newA) return 0; + newA->maybeTokenized=oldA->maybeTokenized; + } + + // Copy the element type table. + + hashTableIterInit(&iter, &(oldDtd->elementTypes)); + + for (;;) + { + int i; + ELEMENT_TYPE *newE; + const XML_Char *name; + const ELEMENT_TYPE *oldE=(ELEMENT_TYPE *)hashTableIterNext(&iter); + + if (!oldE) break; + name=poolCopyString(&(newDtd->pool), oldE->name); + if (!name) return 0; + + newE=(ELEMENT_TYPE *) lookup(&(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); + if (!newE) return 0; + + newE->defaultAtts=new DEFAULT_ATTRIBUTE[oldE->nDefaultAtts]; + if (!newE->defaultAtts) return 0; + + newE->allocDefaultAtts=newE->nDefaultAtts=oldE->nDefaultAtts; + + for (i=0; inDefaultAtts; i++) + { + newE->defaultAtts[i].id=(ATTRIBUTE_ID *) lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + newE->defaultAtts[i].isCdata=oldE->defaultAtts[i].isCdata; + + if (oldE->defaultAtts[i].value) + { + newE->defaultAtts[i].value=poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value); + if (!newE->defaultAtts[i].value) return 0; + } + else + newE->defaultAtts[i].value=0; + }; + }; + + // Copy the entity table. + + hashTableIterInit(&iter, &(oldDtd->generalEntities)); + + for (;;) + { + ENTITY *newE; + const XML_Char *name; + const ENTITY *oldE=(ENTITY *)hashTableIterNext(&iter); + + if (!oldE) break; + + name=poolCopyString(&(newDtd->pool), oldE->name); + if (!name) return 0; + + newE=(ENTITY *) lookup(&(newDtd->generalEntities), name, sizeof(ENTITY)); + if (!newE) return 0; + + if (oldE->systemId) + { + const XML_Char *tem=poolCopyString(&(newDtd->pool), oldE->systemId); + if (!tem) return 0; + newE->systemId = tem; + + if (oldE->base) + { + if (oldE->base==oldDtd->base) newE->base=newDtd->base; + + tem=poolCopyString(&(newDtd->pool), oldE->base); + if (!tem) return 0; + + newE->base=tem; + }; + } + else + { + const XML_Char *tem=poolCopyStringN(&(newDtd->pool), oldE->textPtr, oldE->textLen); + if (!tem) return 0; + newE->textPtr=tem; + newE->textLen=oldE->textLen; + }; + + if (oldE->notation) + { + const XML_Char *tem=poolCopyString(&(newDtd->pool), oldE->notation); + if (!tem) return 0; + newE->notation=tem; + }; + }; + + newDtd->complete=oldDtd->complete; + newDtd->standalone=oldDtd->standalone; + + return 1; +}; + +static void poolInit(STRING_POOL *pool) +{ + pool->blocks=0; + pool->freeBlocks=0; + pool->start=0; + pool->ptr=0; + pool->end=0; +}; + +static void poolClear(STRING_POOL *pool) +{ + if (!pool->freeBlocks) + pool->freeBlocks = pool->blocks; + else + { + BLOCK *p=pool->blocks; + while (p) + { + BLOCK *tem=p->next; + p->next=pool->freeBlocks; + pool->freeBlocks=p; + p=tem; + }; + }; + + pool->blocks=0; + pool->start=0; + pool->ptr=0; + pool->end=0; +}; + +void poolDestroy(STRING_POOL *pool) +{ + BLOCK *p=pool->blocks; + + while (p) + { + BLOCK *tem=p->next; + free(p); + p=tem; + }; + + pool->blocks=0; + p=pool->freeBlocks; + + while (p) + { + BLOCK *tem=p->next; + free(p); + p=tem; + }; + + pool->freeBlocks=0; + pool->ptr=0; + pool->start=0; + pool->end=0; +}; + +static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr, const char *end) +{ + if (!pool->ptr && !poolGrow(pool)) return 0; + + for (;;) + { + XmlConvert(enc, &ptr, end, (ICHAR **) &(pool->ptr), (ICHAR *) pool->end); + + if (ptr == end) break; + if (!poolGrow(pool)) return 0; + }; + + return pool->start; +}; + +static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s) +{ + do + { + if (!poolAppendChar(pool, *s)) return 0; + } while (*s++); + + s=pool->start; + poolFinish(pool); + + return s; +}; + +static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) +{ + if (!pool->ptr && !poolGrow(pool)) return 0; + + for (; n > 0; --n, s++) + { + if (!poolAppendChar(pool, *s)) return 0; + }; + + s=pool->start; + poolFinish(pool); + return s; +}; + +static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, const char *ptr, const char *end) +{ + if (!poolAppend(pool, enc, ptr, end)) return 0; + + if (pool->ptr==pool->end && !poolGrow(pool)) return 0; + *(pool->ptr)++=0; + + return pool->start; +}; + +static int poolGrow(STRING_POOL *pool) +{ + if (pool->freeBlocks) + { + if (pool->start==0) + { + pool->blocks=pool->freeBlocks; + pool->freeBlocks=pool->freeBlocks->next; + pool->blocks->next=0; + pool->start=pool->blocks->s; + pool->end=pool->start+pool->blocks->size; + pool->ptr=pool->start; + + return 1; + }; + + if (pool->end-pool->startfreeBlocks->size) + { + BLOCK *tem=pool->freeBlocks->next; + + pool->freeBlocks->next=pool->blocks; + pool->blocks=pool->freeBlocks; + pool->freeBlocks=tem; + + memcpy(pool->blocks->s, pool->start, (pool->end-pool->start)*sizeof(XML_Char)); + + pool->ptr=pool->blocks->s+(pool->ptr-pool->start); + pool->start=pool->blocks->s; + pool->end=pool->start+pool->blocks->size; + + return 1; + }; + }; + + if (pool->blocks && pool->start==pool->blocks->s) + { + int blockSize=(pool->end-pool->start)*2; + + pool->blocks=(BLOCK *) realloc(pool->blocks, offsetof(BLOCK, s)+blockSize*sizeof(XML_Char)); + + if (!pool->blocks) return 0; + + pool->blocks->size=blockSize; + pool->ptr=pool->blocks->s+(pool->ptr-pool->start); + pool->start=pool->blocks->s; + pool->end=pool->start+blockSize; + } + else + { + BLOCK *tem; + + int blockSize=pool->end-pool->start; + + if (blockSizesize=blockSize; + tem->next=pool->blocks; + + pool->blocks=tem; + + memcpy(tem->s, pool->start, (pool->ptr-pool->start)*sizeof(XML_Char)); + + pool->ptr=tem->s+(pool->ptr-pool->start); + pool->start=tem->s; + pool->end=tem->s+blockSize; + }; + + return 1; +}; diff --git a/lib/xmltree/xmlparse.h b/lib/xmltree/xmlparse.h new file mode 100644 index 000000000..50b4966ce --- /dev/null +++ b/lib/xmltree/xmlparse.h @@ -0,0 +1,317 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): + + Fabian Giesen - converted this monster to C++ (at least the core) + +ChangeLog: + + $Log: xmlparse.h,v $ + Revision 1.2 2003/03/14 05:13:04 obi + compileable with -W -Werror + + Revision 1.1 2002/01/18 20:22:39 tmbinc + initial checkin + + Revision 1.1.1.1 2001/10/07 13:01:16 tmbinc + Import of ezap2-200110070 + + Revision 1.2 1999/01/24 16:00:05 cvs + First release of the XMLTree API (ryg) + + Revision 1.1 1999/01/11 23:01:58 cvs + Another try to commit this. + +*/ + +#ifndef XmlParse_INCLUDED +#define XmlParse_INCLUDED 1 + +#ifndef XMLPARSEAPI +#define XMLPARSEAPI /* as nothing */ +#endif + +#ifdef XML_UNICODE_WCHAR_T + +/* XML_UNICODE_WCHAR_T will work only if sizeof(wchar_t) == 2 and wchar_t +uses Unicode. */ +/* Information is UTF-16 encoded as wchar_ts */ + +#ifndef XML_UNICODE +#define XML_UNICODE +#endif + +#include +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; + +#else /* not XML_UNICODE_WCHAR_T */ + +#ifdef XML_UNICODE + +/* Information is UTF-16 encoded as unsigned shorts */ +typedef unsigned short XML_Char; +typedef char XML_LChar; + +#else /* not XML_UNICODE */ + +/* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; + +#endif /* not XML_UNICODE */ + +#endif /* not XML_UNICODE_WCHAR_T */ + +#include "xmltok.h" +#include "xmlrole.h" +#include "hashtab.h" + +typedef struct { + int map[256]; + void *data; + int (*convert)(void *data, const char *s); + void (*release)(void *data); +} XML_Encoding; + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING +}; + +#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ +#define INIT_DATA_BUF_SIZE 1024 +#define INIT_ATTS_SIZE 16 +#define INIT_BLOCK_SIZE 1024 +#define INIT_BUFFER_SIZE 1024 + +typedef struct tag { + struct tag *parent; + const char *rawName; + int rawNameLength; + const XML_Char *name; + char *buf; + char *bufEnd; +} TAG; + +typedef struct { + const XML_Char *name; + const XML_Char *textPtr; + int textLen; + const XML_Char *systemId; + const XML_Char *base; + const XML_Char *publicId; + const XML_Char *notation; + char open; +} ENTITY; + +typedef struct block { + struct block *next; + int size; + XML_Char s[1]; +} BLOCK; + +typedef struct { + BLOCK *blocks; + BLOCK *freeBlocks; + const XML_Char *end; + XML_Char *ptr; + XML_Char *start; +} STRING_POOL; + +/* The XML_Char before the name is used to determine whether +an attribute has been specified. */ +typedef struct { + XML_Char *name; + char maybeTokenized; +} ATTRIBUTE_ID; + +typedef struct { + const ATTRIBUTE_ID *id; + char isCdata; + const XML_Char *value; +} DEFAULT_ATTRIBUTE; + +typedef struct { + const XML_Char *name; + int nDefaultAtts; + int allocDefaultAtts; + DEFAULT_ATTRIBUTE *defaultAtts; +} ELEMENT_TYPE; + +typedef struct { + HASH_TABLE generalEntities; + HASH_TABLE elementTypes; + HASH_TABLE attributeIds; + STRING_POOL pool; + int complete; + int standalone; + const XML_Char *base; +} DTD; + +typedef enum XML_Error Processor(void *parser, + const char *start, + const char *end, + const char **endPtr); + +extern Processor prologProcessor; +extern Processor prologInitProcessor; +extern Processor contentProcessor; +extern Processor cdataSectionProcessor; +extern Processor epilogProcessor; +extern Processor errorProcessor; +extern Processor externalEntityInitProcessor; +extern Processor externalEntityInitProcessor2; +extern Processor externalEntityInitProcessor3; +extern Processor externalEntityContentProcessor; + + +class XML_Parser +{ + friend Processor prologProcessor; + friend Processor prologInitProcessor; + friend Processor contentProcessor; + friend Processor cdataSectionProcessor; + friend Processor epilogProcessor; + friend Processor errorProcessor; + friend Processor externalEntityInitProcessor; + friend Processor externalEntityInitProcessor2; + friend Processor externalEntityInitProcessor3; + friend Processor externalEntityContentProcessor; + + protected: + char *buffer; + /* first character to be parsed */ + const char *bufferPtr; + /* past last character to be parsed */ + char *bufferEnd; + /* allocated end of buffer */ + const char *bufferLim; + long parseEndByteIndex; + const char *parseEndPtr; + XML_Char *dataBuf; + XML_Char *dataBufEnd; + const ENCODING *encoding; + INIT_ENCODING initEncoding; + const XML_Char *protocolEncodingName; + void *unknownEncodingMem; + void *unknownEncodingData; + void *unknownEncodingHandlerData; + void (*unknownEncodingRelease)(void *); + PROLOG_STATE prologState; + Processor *processor; + enum XML_Error errorCode; + const char *eventPtr; + const char *eventEndPtr; + const char *positionPtr; + int tagLevel; + ENTITY *declEntity; + const XML_Char *declNotationName; + const XML_Char *declNotationPublicId; + ELEMENT_TYPE *declElementType; + ATTRIBUTE_ID *declAttributeId; + char declAttributeIsCdata; + DTD dtd; + TAG *tagStack; + TAG *freeTagList; + int attsSize; + ATTRIBUTE *atts; + POSITION position; + STRING_POOL tempPool; + STRING_POOL temp2Pool; + char *groupConnector; + unsigned groupSize; + int hadExternalDoctype; + + int startElementHandler, endElementHandler, characterDataHandler; + int processingInstructionHandler, defaultHandler; + int unparsedEntityDeclHandler, notationDeclHandler; + int externalEntityRefHandler, unknownEncodingHandler; + + virtual enum XML_Error handleUnknownEncoding(const XML_Char *encodingName); + virtual enum XML_Error processXmlDecl(int isGeneralTextEntity, const char *, const char *); + virtual enum XML_Error initializeEncoding(); + virtual enum XML_Error doContent(int startTagLevel, const ENCODING *enc, const char *start, const char *end, const char **endPtr); + virtual enum XML_Error doCdataSection(const ENCODING *, const char **startPtr, const char *end, const char **nextPtr); + virtual enum XML_Error storeAtts(const ENCODING *, const XML_Char *tagName, const char *s); + virtual int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, int isCdata, const XML_Char *dfltValue); + virtual enum XML_Error storeAttributeValue(const ENCODING *, int isCdata, const char *, const char *, STRING_POOL *); + virtual enum XML_Error appendAttributeValue(const ENCODING *, int isCdata, const char *, const char *, STRING_POOL *); + virtual ATTRIBUTE_ID *getAttributeId(const ENCODING *enc, const char *start, const char *end); + virtual enum XML_Error storeEntityValue(const char *start, const char *end); + virtual int reportProcessingInstruction(const ENCODING *enc, const char *start, const char *end); + virtual void reportDefault(const ENCODING *enc, const char *start, const char *end); + + virtual const XML_Char *getOpenEntityNames(); + virtual int setOpenEntityNames(const XML_Char *openEntityNames); + virtual void normalizePublicId(XML_Char *s); + + virtual void StartElementHandler(const XML_Char* /*name*/, const XML_Char** /*atts*/) {}; + virtual void EndElementHandler(const XML_Char* /*name*/) {}; + virtual void CharacterDataHandler(const XML_Char* /*s*/, int /*len*/) {}; + virtual void ProcessingInstructionHandler(const XML_Char* /*target*/, const XML_Char* /*data*/) {}; + virtual void DefaultHandler(const XML_Char* /*s*/, int /*len*/) {}; + virtual void UnparsedEntityDeclHandler(const XML_Char* /*entityName*/, const XML_Char* /*base*/, const XML_Char* /*systemId*/, const XML_Char* /*publicId*/, const XML_Char* /*notationName*/) {}; + virtual void NotationDeclHandler(const XML_Char* /*notationName*/, const XML_Char* /*base*/, const XML_Char* /*systemId*/, const XML_Char* /*publicId*/) {}; + virtual int ExternalEntityRefHandler(const XML_Char* /*openEntityNames*/, const XML_Char* /*base*/, const XML_Char* /*systemId*/, const XML_Char* /*publicId*/) {return 0;}; + virtual int UnknownEncodingHandler(void* /*encodingHandlerData*/, const XML_Char* /*name*/, XML_Encoding* /*info*/) {return 0;}; + + virtual void DefaultCurrent(); + + public: + XML_Parser(const XML_Char *encoding); + virtual ~XML_Parser(); + + virtual int SetBase(const XML_Char *base); + virtual const XML_Char *GetBase(); + + virtual int Parse(const char *s, int len, int isFinal); + virtual void *GetBuffer(int len); + virtual int ParseBuffer(int len, int isFinal); + virtual XML_Parser *ExternalEntityParserCreate(const XML_Char *openEntityNames, const XML_Char *encoding); + + virtual enum XML_Error GetErrorCode(); + + virtual int GetCurrentLineNumber(); + virtual int GetCurrentColumnNumber(); + virtual long GetCurrentByteIndex(); + + virtual const XML_LChar *ErrorString(int code); +}; + +#endif /* not XmlParse_INCLUDED */ diff --git a/lib/xmltree/xmlrole.c b/lib/xmltree/xmlrole.c new file mode 100644 index 000000000..27d5c41ce --- /dev/null +++ b/lib/xmltree/xmlrole.c @@ -0,0 +1,1269 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): +*/ + +#include "xmldef.h" +#include "xmlrole.h" + +/* Doesn't check: + + that ,| are not mixed in a model group + content of literals + +*/ + +#ifndef MIN_BYTES_PER_CHAR +#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar) +#endif + +typedef int PROLOG_HANDLER(struct prolog_state *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + +static PROLOG_HANDLER + prolog0, prolog1, prolog2, + doctype0, doctype1, doctype2, doctype3, doctype4, doctype5, + internalSubset, + entity0, entity1, entity2, entity3, entity4, entity5, entity6, + entity7, entity8, entity9, + notation0, notation1, notation2, notation3, notation4, + attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6, + attlist7, attlist8, attlist9, + element0, element1, element2, element3, element4, element5, element6, + element7, + declClose, + error; + +static +int syntaxError(PROLOG_STATE *); + +static +int prolog0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + state->handler = prolog1; + return XML_ROLE_NONE; + case XML_TOK_XML_DECL: + state->handler = prolog1; + return XML_ROLE_XML_DECL; + case XML_TOK_PI: + state->handler = prolog1; + return XML_ROLE_NONE; + case XML_TOK_COMMENT: + state->handler = prolog1; + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + "DOCTYPE")) + break; + state->handler = doctype0; + return XML_ROLE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return syntaxError(state); +} + +static +int prolog1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + case XML_TOK_COMMENT: + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + "DOCTYPE")) + break; + state->handler = doctype0; + return XML_ROLE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return syntaxError(state); +} + +static +int prolog2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + case XML_TOK_COMMENT: + return XML_ROLE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return syntaxError(state); +} + +static +int doctype0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = doctype1; + return XML_ROLE_DOCTYPE_NAME; + } + return syntaxError(state); +} + +static +int doctype1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) { + state->handler = doctype3; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) { + state->handler = doctype2; + return XML_ROLE_NONE; + } + break; + } + return syntaxError(state); +} + +static +int doctype2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype3; + return XML_ROLE_DOCTYPE_PUBLIC_ID; + } + return syntaxError(state); +} + +static +int doctype3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype4; + return XML_ROLE_DOCTYPE_SYSTEM_ID; + } + return syntaxError(state); +} + +static +int doctype4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return syntaxError(state); +} + +static +int doctype5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return syntaxError(state); +} + +static +int internalSubset(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + "ENTITY")) { + state->handler = entity0; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + "ATTLIST")) { + state->handler = attlist0; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + "ELEMENT")) { + state->handler = element0; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + "NOTATION")) { + state->handler = notation0; + return XML_ROLE_NONE; + } + break; + case XML_TOK_PI: + case XML_TOK_COMMENT: + return XML_ROLE_NONE; + case XML_TOK_PARAM_ENTITY_REF: + return XML_ROLE_PARAM_ENTITY_REF; + case XML_TOK_CLOSE_BRACKET: + state->handler = doctype5; + return XML_ROLE_NONE; + } + return syntaxError(state); +} + +static +int entity0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PERCENT: + state->handler = entity1; + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = entity2; + return XML_ROLE_GENERAL_ENTITY_NAME; + } + return syntaxError(state); +} + +static +int entity1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = entity7; + return XML_ROLE_PARAM_ENTITY_NAME; + } + return syntaxError(state); +} + +static +int entity2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) { + state->handler = entity4; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) { + state->handler = entity3; + return XML_ROLE_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_ENTITY_VALUE; + } + return syntaxError(state); +} + +static +int entity3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = entity4; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return syntaxError(state); +} + + +static +int entity4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = entity5; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return syntaxError(state); +} + +static +int entity5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = internalSubset; + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, "NDATA")) { + state->handler = entity6; + return XML_ROLE_NONE; + } + break; + } + return syntaxError(state); +} + +static +int entity6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = declClose; + return XML_ROLE_ENTITY_NOTATION_NAME; + } + return syntaxError(state); +} + +static +int entity7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) { + state->handler = entity9; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) { + state->handler = entity8; + return XML_ROLE_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_ENTITY_VALUE; + } + return syntaxError(state); +} + +static +int entity8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = entity9; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return syntaxError(state); +} + +static +int entity9(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return syntaxError(state); +} + +static +int notation0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = notation1; + return XML_ROLE_NOTATION_NAME; + } + return syntaxError(state); +} + +static +int notation1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, "SYSTEM")) { + state->handler = notation3; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, "PUBLIC")) { + state->handler = notation2; + return XML_ROLE_NONE; + } + break; + } + return syntaxError(state); +} + +static +int notation2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = notation4; + return XML_ROLE_NOTATION_PUBLIC_ID; + } + return syntaxError(state); +} + +static +int notation3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_NOTATION_SYSTEM_ID; + } + return syntaxError(state); +} + +static +int notation4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + return XML_ROLE_NOTATION_SYSTEM_ID; + case XML_TOK_DECL_CLOSE: + state->handler = internalSubset; + return XML_ROLE_NOTATION_NO_SYSTEM_ID; + } + return syntaxError(state); +} + +static +int attlist0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = attlist1; + return XML_ROLE_ATTLIST_ELEMENT_NAME; + } + return syntaxError(state); +} + +static +int attlist1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = internalSubset; + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = attlist2; + return XML_ROLE_ATTRIBUTE_NAME; + default: + return syntaxError(state); + } +} + +static +int attlist2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + { + static const char *types[] = { + "CDATA", + "ID", + "IDREF", + "IDREFS", + "ENTITY", + "ENTITIES", + "NMTOKEN", + "NMTOKENS", + }; + + int i; + + for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++) + if (XmlNameMatchesAscii(enc, ptr, types[i])) { + state->handler = attlist8; + return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i; + } + + if (XmlNameMatchesAscii(enc, ptr, "NOTATION")) { + state->handler = attlist5; + return XML_ROLE_NONE; + } + + return syntaxError(state); + } + case XML_TOK_OPEN_PAREN: + state->handler = attlist3; + return XML_ROLE_NONE; + default: + return syntaxError(state); + } +} + +static +int attlist3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NMTOKEN: + case XML_TOK_NAME: + state->handler = attlist4; + return XML_ROLE_ATTRIBUTE_ENUM_VALUE; + default: + return syntaxError(state); + } +} + +static +int attlist4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_NONE; + case XML_TOK_OR: + state->handler = attlist3; + return XML_ROLE_NONE; + default: + return syntaxError(state); + } +} + +static +int attlist5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_PAREN: + state->handler = attlist6; + return XML_ROLE_NONE; + default: + return syntaxError(state); + } +} + + +static +int attlist6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = attlist7; + return XML_ROLE_ATTRIBUTE_NOTATION_VALUE; + default: + return syntaxError(state); + } +} + +static +int attlist7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_NONE; + case XML_TOK_OR: + state->handler = attlist6; + return XML_ROLE_NONE; + default: + return syntaxError(state); + } +} + +/* default value */ +static +int attlist8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), "IMPLIED")) { + state->handler = attlist1; + return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), "REQUIRED")) { + state->handler = attlist1; + return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), "FIXED")) { + state->handler = attlist9; + return XML_ROLE_NONE; + } + return syntaxError(state); + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE; + default: + return syntaxError(state); + } +} + +static +int attlist9(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_FIXED_ATTRIBUTE_VALUE; + default: + return syntaxError(state); + } +} + +static +int element0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = element1; + return XML_ROLE_ELEMENT_NAME; + default: + return syntaxError(state); + } +} + +static +int element1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, "EMPTY")) { + state->handler = declClose; + return XML_ROLE_CONTENT_EMPTY; + } + if (XmlNameMatchesAscii(enc, ptr, "ANY")) { + state->handler = declClose; + return XML_ROLE_CONTENT_ANY; + } + return syntaxError(state); + case XML_TOK_OPEN_PAREN: + state->handler = element2; + state->level = 1; + return XML_ROLE_GROUP_OPEN; + default: + return syntaxError(state); + } +} + +static +int element2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)end; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), "PCDATA")) { + state->handler = element3; + return XML_ROLE_CONTENT_PCDATA; + } + return syntaxError(state); + case XML_TOK_OPEN_PAREN: + state->level = 2; + state->handler = element6; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + default: + return syntaxError(state); + } +} + +static +int element3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_NONE; + default: + return syntaxError(state); + } +} + +static +int element4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + state->handler = element5; + return XML_ROLE_CONTENT_ELEMENT; + default: + return syntaxError(state); + } +} + +static +int element5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_NONE; + default: + return syntaxError(state); + } +} + +static +int element6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_PAREN: + state->level += 1; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + default: + return syntaxError(state); + } +} + +static +int element7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_PAREN: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_CLOSE_PAREN_QUESTION: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_OPT; + case XML_TOK_CLOSE_PAREN_PLUS: + state->level -= 1; + if (state->level == 0) + state->handler = declClose; + return XML_ROLE_GROUP_CLOSE_PLUS; + case XML_TOK_COMMA: + state->handler = element6; + return XML_ROLE_GROUP_SEQUENCE; + case XML_TOK_OR: + state->handler = element6; + return XML_ROLE_GROUP_CHOICE; + default: + return syntaxError(state); + } + +} + +static +int declClose(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = internalSubset; + return XML_ROLE_NONE; + default: + return syntaxError(state); + } +} + +#if 0 + +static +int ignore(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)ptr; + (void)end; + (void)enc; + + switch (tok) { + case XML_TOK_DECL_CLOSE: + state->handler = internalSubset; + return 0; + default: + return XML_ROLE_NONE; + } +} +#endif + +static +int error(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + (void)state; + (void)tok; + (void)ptr; + (void)end; + (void)enc; + return XML_ROLE_NONE; +} + +static +int syntaxError(PROLOG_STATE *state) +{ + state->handler = error; + return XML_ROLE_ERROR; +} + +void XmlPrologStateInit(PROLOG_STATE *state) +{ + state->handler = prolog0; +} diff --git a/lib/xmltree/xmlrole.h b/lib/xmltree/xmlrole.h new file mode 100644 index 000000000..ecbcc26df --- /dev/null +++ b/lib/xmltree/xmlrole.h @@ -0,0 +1,101 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): +*/ + +#ifndef XmlRole_INCLUDED +#define XmlRole_INCLUDED 1 + +#include "xmltok.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + XML_ROLE_ERROR = -1, + XML_ROLE_NONE = 0, + XML_ROLE_XML_DECL, + XML_ROLE_INSTANCE_START, + XML_ROLE_DOCTYPE_NAME, + XML_ROLE_DOCTYPE_SYSTEM_ID, + XML_ROLE_DOCTYPE_PUBLIC_ID, + XML_ROLE_DOCTYPE_CLOSE, + XML_ROLE_GENERAL_ENTITY_NAME, + XML_ROLE_PARAM_ENTITY_NAME, + XML_ROLE_ENTITY_VALUE, + XML_ROLE_ENTITY_SYSTEM_ID, + XML_ROLE_ENTITY_PUBLIC_ID, + XML_ROLE_ENTITY_NOTATION_NAME, + XML_ROLE_NOTATION_NAME, + XML_ROLE_NOTATION_SYSTEM_ID, + XML_ROLE_NOTATION_NO_SYSTEM_ID, + XML_ROLE_NOTATION_PUBLIC_ID, + XML_ROLE_ATTRIBUTE_NAME, + XML_ROLE_ATTRIBUTE_TYPE_CDATA, + XML_ROLE_ATTRIBUTE_TYPE_ID, + XML_ROLE_ATTRIBUTE_TYPE_IDREF, + XML_ROLE_ATTRIBUTE_TYPE_IDREFS, + XML_ROLE_ATTRIBUTE_TYPE_ENTITY, + XML_ROLE_ATTRIBUTE_TYPE_ENTITIES, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS, + XML_ROLE_ATTRIBUTE_ENUM_VALUE, + XML_ROLE_ATTRIBUTE_NOTATION_VALUE, + XML_ROLE_ATTLIST_ELEMENT_NAME, + XML_ROLE_IMPLIED_ATTRIBUTE_VALUE, + XML_ROLE_REQUIRED_ATTRIBUTE_VALUE, + XML_ROLE_DEFAULT_ATTRIBUTE_VALUE, + XML_ROLE_FIXED_ATTRIBUTE_VALUE, + XML_ROLE_ELEMENT_NAME, + XML_ROLE_CONTENT_ANY, + XML_ROLE_CONTENT_EMPTY, + XML_ROLE_CONTENT_PCDATA, + XML_ROLE_GROUP_OPEN, + XML_ROLE_GROUP_CLOSE, + XML_ROLE_GROUP_CLOSE_REP, + XML_ROLE_GROUP_CLOSE_OPT, + XML_ROLE_GROUP_CLOSE_PLUS, + XML_ROLE_GROUP_CHOICE, + XML_ROLE_GROUP_SEQUENCE, + XML_ROLE_CONTENT_ELEMENT, + XML_ROLE_CONTENT_ELEMENT_REP, + XML_ROLE_CONTENT_ELEMENT_OPT, + XML_ROLE_CONTENT_ELEMENT_PLUS, + XML_ROLE_PARAM_ENTITY_REF +}; + +typedef struct prolog_state { + int (*handler)(struct prolog_state *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + unsigned level; +} PROLOG_STATE; + +void XMLTOKAPI XmlPrologStateInit(PROLOG_STATE *); + +#define XmlTokenRole(state, tok, ptr, end, enc) \ + (((state)->handler)(state, tok, ptr, end, enc)) + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlRole_INCLUDED */ diff --git a/lib/xmltree/xmltimpl.c b/lib/xmltree/xmltimpl.c new file mode 100644 index 000000000..173b2c57a --- /dev/null +++ b/lib/xmltree/xmltimpl.c @@ -0,0 +1,1655 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): +*/ + +#ifndef IS_INVALID_CHAR +#define IS_INVALID_CHAR(enc, ptr, n) (0) +#endif + +#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_INVALID_CHAR(enc, ptr, n)) { \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define INVALID_CASES(ptr, nextTokPtr) \ + INVALID_LEAD_CASE(2, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(3, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(4, ptr, nextTokPtr) \ + case BT_NONXML: \ + case BT_MALFORM: \ + case BT_TRAIL: \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; + +#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NAME_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + case BT_DIGIT: \ + case BT_NAME: \ + case BT_MINUS: \ + ptr += MINBPC; \ + break; \ + CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr) + +#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + ptr += MINBPC; \ + break; \ + CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr) + +#ifndef PREFIX +#define PREFIX(ident) ident +#endif + +/* ptr points to character following "')) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC; + return XML_TOK_COMMENT; + } + break; + default: + ptr += MINBPC; + break; + } + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following " */ + switch (BYTE_TYPE(enc, ptr + MINBPC)) { + case BT_S: case BT_CR: case BT_LF: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + /* fall through */ + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DECL_OPEN; + case BT_NMSTRT: + case BT_HEX: + ptr += MINBPC; + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, const char *end, int *tokPtr) +{ + (void)enc; + + int upper = 0; + *tokPtr = XML_TOK_PI; + if (end - ptr != MINBPC*3) + return 1; + switch (BYTE_TO_ASCII(enc, ptr)) { + case 'x': + break; + case 'X': + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC; + switch (BYTE_TO_ASCII(enc, ptr)) { + case 'm': + break; + case 'M': + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC; + switch (BYTE_TO_ASCII(enc, ptr)) { + case 'l': + break; + case 'L': + upper = 1; + break; + default: + return 1; + } + if (upper) + return 0; + *tokPtr = XML_TOK_XML_DECL; + return 1; +} + +/* ptr points to character following "')) { + *nextTokPtr = ptr + MINBPC; + return tok; + } + break; + default: + ptr += MINBPC; + break; + } + } + return XML_TOK_PARTIAL; + case BT_QUEST: + if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + ptr += MINBPC; + if (ptr == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, '>')) { + *nextTokPtr = ptr + MINBPC; + return tok; + } + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + + +static +int PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + (void)enc; + + int i; + /* CDATA[ */ + if (end - ptr < 6 * MINBPC) + return XML_TOK_PARTIAL; + for (i = 0; i < 6; i++, ptr += MINBPC) { + if (!CHAR_MATCHES(enc, ptr, "CDATA["[i])) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + *nextTokPtr = ptr; + return XML_TOK_CDATA_SECT_OPEN; +} + +static +int PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_NONE; +#if MINBPC > 1 + { + size_t n = end - ptr; + if (n & (MINBPC - 1)) { + n &= ~(MINBPC - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } +#endif + switch (BYTE_TYPE(enc, ptr)) { + case BT_RSQB: + ptr += MINBPC; + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ']')) + break; + ptr += MINBPC; + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, '>')) { + ptr -= MINBPC; + break; + } + *nextTokPtr = ptr + MINBPC; + return XML_TOK_CDATA_SECT_CLOSE; + case BT_CR: + ptr += MINBPC; + if (ptr == end) + return XML_TOK_PARTIAL; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC; + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_DATA_NEWLINE; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC; + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + case BT_RSQB: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC; + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "')) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC; + return XML_TOK_EMPTY_ELEMENT_WITH_ATTS; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + break; + } + break; + } + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "<" */ + +static +int PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_EXCL: + if ((ptr += MINBPC) == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_MINUS: + return PREFIX(scanComment)(enc, ptr + MINBPC, end, nextTokPtr); + case BT_LSQB: + return PREFIX(scanCdataSection)(enc, ptr + MINBPC, end, nextTokPtr); + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_QUEST: + return PREFIX(scanPi)(enc, ptr + MINBPC, end, nextTokPtr); + case BT_SOL: + return PREFIX(scanEndTag)(enc, ptr + MINBPC, end, nextTokPtr); + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + /* we have a start-tag */ + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_CR: case BT_LF: + { + ptr += MINBPC; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_GT: + goto gt; + case BT_SOL: + goto sol; + case BT_S: case BT_CR: case BT_LF: + ptr += MINBPC; + continue; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr); + } + return XML_TOK_PARTIAL; + } + case BT_GT: + gt: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_START_TAG_NO_ATTS; + case BT_SOL: + sol: + ptr += MINBPC; + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, '>')) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC; + return XML_TOK_EMPTY_ELEMENT_NO_ATTS; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_NONE; +#if MINBPC > 1 + { + size_t n = end - ptr; + if (n & (MINBPC - 1)) { + n &= ~(MINBPC - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } +#endif + switch (BYTE_TYPE(enc, ptr)) { + case BT_LT: + return PREFIX(scanLt)(enc, ptr + MINBPC, end, nextTokPtr); + case BT_AMP: + return PREFIX(scanRef)(enc, ptr + MINBPC, end, nextTokPtr); + case BT_CR: + ptr += MINBPC; + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC; + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_DATA_NEWLINE; + case BT_RSQB: + ptr += MINBPC; + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ']')) + break; + ptr += MINBPC; + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, '>')) { + ptr -= MINBPC; + break; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC; + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_RSQB: + if (ptr + MINBPC != end) { + if (!CHAR_MATCHES(enc, ptr + MINBPC, ']')) { + ptr += MINBPC; + break; + } + if (ptr + 2*MINBPC != end) { + if (!CHAR_MATCHES(enc, ptr + 2*MINBPC, '>')) { + ptr += MINBPC; + break; + } + *nextTokPtr = ptr + 2*MINBPC; + return XML_TOK_INVALID; + } + } + /* fall through */ + case BT_AMP: + case BT_LT: + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC; + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "%" */ + +static +int PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_LF: case BT_CR: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_PERCENT; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_SEMI: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_PARAM_ENTITY_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_CR: case BT_LF: case BT_S: + case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR: + *nextTokPtr = ptr; + return XML_TOK_POUND_NAME; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(scanLit)(int open, const ENCODING *enc, + const char *ptr, const char *end, + const char **nextTokPtr) +{ + while (ptr != end) { + int t = BYTE_TYPE(enc, ptr); + switch (t) { + INVALID_CASES(ptr, nextTokPtr) + case BT_QUOT: + case BT_APOS: + ptr += MINBPC; + if (t != open) + break; + if (ptr == end) + return XML_TOK_PARTIAL; + *nextTokPtr = ptr; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_CR: case BT_LF: + case BT_GT: case BT_PERCNT: case BT_LSQB: + return XML_TOK_LITERAL; + default: + return XML_TOK_INVALID; + } + default: + ptr += MINBPC; + break; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + int tok; + if (ptr == end) + return XML_TOK_NONE; +#if MINBPC > 1 + { + size_t n = end - ptr; + if (n & (MINBPC - 1)) { + n &= ~(MINBPC - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } +#endif + switch (BYTE_TYPE(enc, ptr)) { + case BT_QUOT: + return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC, end, nextTokPtr); + case BT_APOS: + return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC, end, nextTokPtr); + case BT_LT: + { + ptr += MINBPC; + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_EXCL: + return PREFIX(scanDecl)(enc, ptr + MINBPC, end, nextTokPtr); + case BT_QUEST: + return PREFIX(scanPi)(enc, ptr + MINBPC, end, nextTokPtr); + case BT_NMSTRT: + case BT_HEX: + case BT_NONASCII: + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + *nextTokPtr = ptr - MINBPC; + return XML_TOK_INSTANCE_START; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + case BT_CR: + if (ptr + MINBPC == end) + return XML_TOK_TRAILING_CR; + /* fall through */ + case BT_S: case BT_LF: + for (;;) { + ptr += MINBPC; + if (ptr == end) + break; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_LF: + break; + case BT_CR: + /* don't split CR/LF pair */ + if (ptr + MINBPC != end) + break; + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + } + } + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + case BT_PERCNT: + return PREFIX(scanPercent)(enc, ptr + MINBPC, end, nextTokPtr); + case BT_COMMA: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_COMMA; + case BT_LSQB: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_OPEN_BRACKET; + case BT_RSQB: + ptr += MINBPC; + if (ptr == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ']')) { + if (ptr + MINBPC == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr + MINBPC, '>')) { + *nextTokPtr = ptr + 2*MINBPC; + return XML_TOK_COND_SECT_CLOSE; + } + } + *nextTokPtr = ptr; + return XML_TOK_CLOSE_BRACKET; + case BT_LPAR: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_OPEN_PAREN; + case BT_RPAR: + ptr += MINBPC; + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_AST: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_CLOSE_PAREN_ASTERISK; + case BT_QUEST: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_CLOSE_PAREN_QUESTION; + case BT_PLUS: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_CLOSE_PAREN_PLUS; + case BT_CR: case BT_LF: case BT_S: + case BT_GT: case BT_COMMA: case BT_VERBAR: + case BT_RPAR: + *nextTokPtr = ptr; + return XML_TOK_CLOSE_PAREN; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_VERBAR: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_OR; + case BT_GT: + *nextTokPtr = ptr + MINBPC; + return XML_TOK_DECL_CLOSE; + case BT_NUM: + return PREFIX(scanPoundName)(enc, ptr + MINBPC, end, nextTokPtr); +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NAME; \ + break; \ + } \ + if (IS_NAME_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NMTOKEN; \ + break; \ + } \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NMSTRT: + case BT_HEX: + tok = XML_TOK_NAME; + ptr += MINBPC; + break; + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + tok = XML_TOK_NMTOKEN; + ptr += MINBPC; + break; + case BT_NONASCII: + if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC; + tok = XML_TOK_NAME; + break; + } + if (IS_NAME_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC; + tok = XML_TOK_NMTOKEN; + break; + } + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_GT: case BT_RPAR: case BT_COMMA: + case BT_VERBAR: case BT_LSQB: case BT_PERCNT: + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return tok; + case BT_PLUS: + if (tok != XML_TOK_NAME) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC; + return XML_TOK_NAME_PLUS; + case BT_AST: + if (tok != XML_TOK_NAME) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC; + return XML_TOK_NAME_ASTERISK; + case BT_QUEST: + if (tok != XML_TOK_NAME) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC; + return XML_TOK_NAME_QUESTION; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static +int PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC, end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LT: + /* this is for inside entity references */ + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC; + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC; + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_S: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC; + return XML_TOK_ATTRIBUTE_VALUE_S; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC; + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +static +int PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC, end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_PERCNT: + if (ptr == start) + return PREFIX(scanPercent)(enc, ptr + MINBPC, end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC; + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC; + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC; + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +static +int PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr) +{ + ptr += MINBPC; + end -= MINBPC; + for (; ptr != end; ptr += MINBPC) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + case BT_MINUS: + case BT_APOS: + case BT_LPAR: + case BT_RPAR: + case BT_PLUS: + case BT_COMMA: + case BT_SOL: + case BT_EQUALS: + case BT_QUEST: + case BT_CR: + case BT_LF: + case BT_SEMI: + case BT_EXCL: + case BT_AST: + case BT_PERCNT: + case BT_NUM: + break; + case BT_S: + if (CHAR_MATCHES(enc, ptr, '\t')) { + *badPtr = ptr; + return 0; + } + break; + case BT_NAME: + case BT_NMSTRT: + if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f)) + break; + default: + switch (BYTE_TO_ASCII(enc, ptr)) { + case 0x24: /* $ */ + case 0x40: /* @ */ + break; + default: + *badPtr = ptr; + return 0; + } + break; + } + } + return 1; +} + +/* This must only be called for a well-formed start-tag or empty element tag. +Returns the number of attributes. Pointers to the first attsMax attributes +are stored in atts. */ + +static +int PREFIX(getAtts)(const ENCODING *enc, const char *ptr, + int attsMax, ATTRIBUTE *atts) +{ + enum { other, inName, inValue } state = inName; + int nAtts = 0; + int open=0; + + for (ptr += MINBPC;; ptr += MINBPC) { + switch (BYTE_TYPE(enc, ptr)) { +#define START_NAME \ + if (state == other) { \ + if (nAtts < attsMax) { \ + atts[nAtts].name = ptr; \ + atts[nAtts].normalized = 1; \ + } \ + state = inName; \ + } +#define LEAD_CASE(n) \ + case BT_LEAD ## n: START_NAME ptr += (n - MINBPC); break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + START_NAME + break; +#undef START_NAME + case BT_QUOT: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC; + state = inValue; + open = BT_QUOT; + } + else if (open == BT_QUOT) { + state = other; + if (nAtts < attsMax) + atts[nAtts++].valueEnd = ptr; + } + break; + case BT_APOS: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC; + state = inValue; + open = BT_APOS; + } + else if (open == BT_APOS) { + state = other; + if (nAtts < attsMax) + atts[nAtts++].valueEnd = ptr; + } + break; + case BT_AMP: + if (nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_S: + if (state == inName) + state = other; + else if (state == inValue + && nAtts < attsMax + && atts[nAtts].normalized + && (ptr == atts[nAtts].valuePtr + || BYTE_TO_ASCII(enc, ptr) != ' ' + || BYTE_TO_ASCII(enc, ptr + MINBPC) == ' ' + || BYTE_TYPE(enc, ptr + MINBPC) == open)) + atts[nAtts].normalized = 0; + break; + case BT_CR: case BT_LF: + /* This case ensures that the first attribute name is counted + Apart from that we could just change state on the quote. */ + if (state == inName) + state = other; + else if (state == inValue && nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_GT: + case BT_SOL: + if (state != inValue) + return nAtts; + break; + default: + break; + } + } + /* not reached */ +} + +static +int PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) +{ + int result = 0; + (void)enc; + /* skip &# */ + ptr += 2*MINBPC; + if (CHAR_MATCHES(enc, ptr, 'x')) { + for (ptr += MINBPC; !CHAR_MATCHES(enc, ptr, ';'); ptr += MINBPC) { + int c = BYTE_TO_ASCII(enc, ptr); + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + result <<= 4; + result |= (c - '0'); + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + result <<= 4; + result += 10 + (c - 'A'); + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + result <<= 4; + result += 10 + (c - 'a'); + break; + } + if (result >= 0x110000) + return -1; + } + } + else { + for (; !CHAR_MATCHES(enc, ptr, ';'); ptr += MINBPC) { + int c = BYTE_TO_ASCII(enc, ptr); + result *= 10; + result += (c - '0'); + if (result >= 0x110000) + return -1; + } + } + return checkCharRefNumber(result); +} + +static +int PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, const char *end) +{ + (void)enc; + switch (end - ptr) { + case 2 * MINBPC: + if (CHAR_MATCHES(enc, ptr + MINBPC, 't')) { + switch (BYTE_TO_ASCII(enc, ptr)) { + case 'l': + return '<'; + case 'g': + return '>'; + } + } + break; + case 3 * MINBPC: + if (CHAR_MATCHES(enc, ptr, 'a')) { + ptr += MINBPC; + if (CHAR_MATCHES(enc, ptr, 'm')) { + ptr += MINBPC; + if (CHAR_MATCHES(enc, ptr, 'p')) + return '&'; + } + } + break; + case 4 * MINBPC: + switch (BYTE_TO_ASCII(enc, ptr)) { + case 'q': + ptr += MINBPC; + if (CHAR_MATCHES(enc, ptr, 'u')) { + ptr += MINBPC; + if (CHAR_MATCHES(enc, ptr, 'o')) { + ptr += MINBPC; + if (CHAR_MATCHES(enc, ptr, 't')) + return '"'; + } + } + break; + case 'a': + ptr += MINBPC; + if (CHAR_MATCHES(enc, ptr, 'p')) { + ptr += MINBPC; + if (CHAR_MATCHES(enc, ptr, 'o')) { + ptr += MINBPC; + if (CHAR_MATCHES(enc, ptr, 's')) + return '\''; + } + } + break; + } + } + return 0; +} + +static +int PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr1)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (*ptr1++ != *ptr2++) \ + return 0; + LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2) +#undef LEAD_CASE + /* fall through */ + if (*ptr1++ != *ptr2++) + return 0; + break; + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + if (*ptr2++ != *ptr1++) + return 0; +#if MINBPC > 1 + if (*ptr2++ != *ptr1++) + return 0; +#if MINBPC > 2 + if (*ptr2++ != *ptr1++) + return 0; +#if MINBPC > 3 + if (*ptr2++ != *ptr1++) + return 0; +#endif +#endif +#endif + break; + default: +#if MINBPC == 1 + if (*ptr1 == *ptr2) + return 1; +#endif + switch (BYTE_TYPE(enc, ptr2)) { + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + return 0; + default: + return 1; + } + } + } + /* not reached */ +} + +static +int PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1, const char *ptr2) +{ + for (; *ptr2; ptr1 += MINBPC, ptr2++) { + if (!CHAR_MATCHES(end, ptr1, *ptr2)) + return 0; + } + switch (BYTE_TYPE(enc, ptr1)) { + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + return 0; + default: + return 1; + } +} + +static +int PREFIX(nameLength)(const ENCODING *enc, const char *ptr) +{ + const char *start = ptr; + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + ptr += MINBPC; + break; + default: + return ptr - start; + } + } +} + +static +const char *PREFIX(skipS)(const ENCODING *enc, const char *ptr) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_LF: + case BT_CR: + case BT_S: + ptr += MINBPC; + break; + default: + return ptr; + } + } +} + +static +void PREFIX(updatePosition)(const ENCODING *enc, + const char *ptr, + const char *end, + POSITION *pos) +{ + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_LF: + pos->columnNumber = (unsigned)-1; + pos->lineNumber++; + ptr += MINBPC; + break; + case BT_CR: + pos->lineNumber++; + ptr += MINBPC; + if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC; + pos->columnNumber = (unsigned)-1; + break; + default: + ptr += MINBPC; + break; + } + pos->columnNumber++; + } +} + +#undef DO_LEAD_CASE +#undef MULTIBYTE_CASES +#undef INVALID_CASES +#undef CHECK_NAME_CASE +#undef CHECK_NAME_CASES +#undef CHECK_NMSTRT_CASE +#undef CHECK_NMSTRT_CASES diff --git a/lib/xmltree/xmltimpl.h b/lib/xmltree/xmltimpl.h new file mode 100644 index 000000000..3b0444ad2 --- /dev/null +++ b/lib/xmltree/xmltimpl.h @@ -0,0 +1,60 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): +*/ + +enum { + BT_NONXML, + BT_MALFORM, + BT_LT, + BT_AMP, + BT_RSQB, + BT_LEAD2, + BT_LEAD3, + BT_LEAD4, + BT_TRAIL, + BT_CR, + BT_LF, + BT_GT, + BT_QUOT, + BT_APOS, + BT_EQUALS, + BT_QUEST, + BT_EXCL, + BT_SOL, + BT_SEMI, + BT_NUM, + BT_LSQB, + BT_S, + BT_NMSTRT, + BT_HEX, + BT_DIGIT, + BT_NAME, + BT_MINUS, + BT_OTHER, /* known not to be a name or name start character */ + BT_NONASCII, /* might be a name or name start character */ + BT_PERCNT, + BT_LPAR, + BT_RPAR, + BT_AST, + BT_PLUS, + BT_COMMA, + BT_VERBAR +}; + +#include diff --git a/lib/xmltree/xmltok.c b/lib/xmltree/xmltok.c new file mode 100644 index 000000000..4634a0356 --- /dev/null +++ b/lib/xmltree/xmltok.c @@ -0,0 +1,1164 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): +*/ + +#include "xmldef.h" +#include "xmltok.h" +#include "nametab.h" + +#define VTABLE1 \ + { PREFIX(prologTok), PREFIX(contentTok), PREFIX(cdataSectionTok) }, \ + { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \ + PREFIX(sameName), \ + PREFIX(nameMatchesAscii), \ + PREFIX(nameLength), \ + PREFIX(skipS), \ + PREFIX(getAtts), \ + PREFIX(charRefNumber), \ + PREFIX(predefinedEntityName), \ + PREFIX(updatePosition), \ + PREFIX(isPublicId) + +#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16) + +#define UCS2_GET_NAMING(pages, hi, lo) \ + (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F))) + +/* A 2 byte UTF-8 representation splits the characters 11 bits +between the bottom 5 and 6 bits of the bytes. +We need 8 bits to index into pages, 3 bits to add to that index and +5 bits to generate the mask. */ +#define UTF8_GET_NAMING2(pages, byte) \ + (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ + + ((((byte)[0]) & 3) << 1) \ + + ((((byte)[1]) >> 5) & 1)] \ + & (1 << (((byte)[1]) & 0x1F))) + +/* A 3 byte UTF-8 representation splits the characters 16 bits +between the bottom 4, 6 and 6 bits of the bytes. +We need 8 bits to index into pages, 3 bits to add to that index and +5 bits to generate the mask. */ +#define UTF8_GET_NAMING3(pages, byte) \ + (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ + + ((((byte)[1]) >> 2) & 0xF)] \ + << 3) \ + + ((((byte)[1]) & 3) << 1) \ + + ((((byte)[2]) >> 5) & 1)] \ + & (1 << (((byte)[2]) & 0x1F))) + +#define UTF8_GET_NAMING(pages, p, n) \ + ((n) == 2 \ + ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \ + : ((n) == 3 \ + ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \ + : 0)) + +#define UTF8_INVALID3(p) \ + ((*p) == 0xED \ + ? (((p)[1] & 0x20) != 0) \ + : ((*p) == 0xEF \ + ? ((p)[1] == 0xBF && ((p)[2] == 0xBF || (p)[2] == 0xBE)) \ + : 0)) + +#define UTF8_INVALID4(p) ((*p) == 0xF4 && ((p)[1] & 0x30) != 0) + +static +int isNever(const ENCODING *enc, const char *p) +{ + (void)enc; + (void)p; + return 0; +} + +static +int utf8_isName2(const ENCODING *enc, const char *p) +{ + (void)enc; + return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); +} + +static +int utf8_isName3(const ENCODING *enc, const char *p) +{ + (void)enc; + return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); +} + +#define utf8_isName4 isNever + +static +int utf8_isNmstrt2(const ENCODING *enc, const char *p) +{ + (void)enc; + return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); +} + +static +int utf8_isNmstrt3(const ENCODING *enc, const char *p) +{ + (void)enc; + return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); +} + +#define utf8_isNmstrt4 isNever + +#define utf8_isInvalid2 isNever + +static +int utf8_isInvalid3(const ENCODING *enc, const char *p) +{ + (void)enc; + return UTF8_INVALID3((const unsigned char *)p); +} + +static +int utf8_isInvalid4(const ENCODING *enc, const char *p) +{ + (void)enc; + return UTF8_INVALID4((const unsigned char *)p); +} + +struct normal_encoding { + ENCODING enc; + unsigned char type[256]; + int (*isName2)(const ENCODING *, const char *); + int (*isName3)(const ENCODING *, const char *); + int (*isName4)(const ENCODING *, const char *); + int (*isNmstrt2)(const ENCODING *, const char *); + int (*isNmstrt3)(const ENCODING *, const char *); + int (*isNmstrt4)(const ENCODING *, const char *); + int (*isInvalid2)(const ENCODING *, const char *); + int (*isInvalid3)(const ENCODING *, const char *); + int (*isInvalid4)(const ENCODING *, const char *); +}; + +#define NORMAL_VTABLE(E) \ + E ## isName2, \ + E ## isName3, \ + E ## isName4, \ + E ## isNmstrt2, \ + E ## isNmstrt3, \ + E ## isNmstrt4, \ + E ## isInvalid2, \ + E ## isInvalid3, \ + E ## isInvalid4 + +static int checkCharRefNumber(int); + +#include "xmltimpl.h" + +/* minimum bytes per character */ +#define MINBPC 1 +#define BYTE_TYPE(enc, p) \ + (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) +#define BYTE_TO_ASCII(enc, p) (*p) + +#define IS_NAME_CHAR(enc, p, n) \ + (((const struct normal_encoding *)(enc))->isName ## n(enc, p)) +#define IS_NMSTRT_CHAR(enc, p, n) \ + (((const struct normal_encoding *)(enc))->isNmstrt ## n(enc, p)) +#define IS_INVALID_CHAR(enc, p, n) \ + (((const struct normal_encoding *)(enc))->isInvalid ## n(enc, p)) + +#define IS_NAME_CHAR_MINBPC(enc, p) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0) + +/* c is an ASCII character */ +#define CHAR_MATCHES(enc, p, c) (*(p) == c) + +#define PREFIX(ident) normal_ ## ident +#include "xmltimpl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */ + UTF8_cval1 = 0x00, + UTF8_cval2 = 0xc0, + UTF8_cval3 = 0xe0, + UTF8_cval4 = 0xf0 +}; + +static +void utf8_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + char *to; + const char *from; + (void)enc; + if (fromLim - *fromP > toLim - *toP) { + /* Avoid copying partial characters. */ + for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--) + if (((unsigned char)fromLim[-1] & 0xc0) != 0x80) + break; + } + for (to = *toP, from = *fromP; from != fromLim; from++, to++) + *to = *from; + *fromP = from; + *toP = to; +} + +static +void utf8_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + unsigned short *to = *toP; + const char *from = *fromP; + while (from != fromLim && to != toLim) { + switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) { + case BT_LEAD2: + *to++ = ((from[0] & 0x1f) << 6) | (from[1] & 0x3f); + from += 2; + break; + case BT_LEAD3: + *to++ = ((from[0] & 0xf) << 12) | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f); + from += 3; + break; + case BT_LEAD4: + { + unsigned long n; + if (to + 1 == toLim) + break; + n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f); + n -= 0x10000; + to[0] = (unsigned short)((n >> 10) | 0xD800); + to[1] = (unsigned short)((n & 0x3FF) | 0xDC00); + to += 2; + from += 4; + } + break; + default: + *to++ = *from++; + break; + } + } + *fromP = from; + *toP = to; +} + +static const struct normal_encoding utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +#include "utf8tab.h" + }, + NORMAL_VTABLE(utf8_) +}; + +static const struct normal_encoding internal_utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "iasctab.h" +#include "utf8tab.h" + }, + NORMAL_VTABLE(utf8_) +}; + +static +void latin1_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + (void)enc; + for (;;) { + unsigned char c; + if (*fromP == fromLim) + break; + c = (unsigned char)**fromP; + if (c & 0x80) { + if (toLim - *toP < 2) + break; + *(*toP)++ = ((c >> 6) | UTF8_cval2); + *(*toP)++ = ((c & 0x3f) | 0x80); + (*fromP)++; + } + else { + if (*toP == toLim) + break; + *(*toP)++ = *(*fromP)++; + } + } +} + +static +void latin1_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + (void)enc; + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = (unsigned char)*(*fromP)++; +} + +static const struct normal_encoding latin1_encoding = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +static +void ascii_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + (void)enc; + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = *(*fromP)++; +} + +static const struct normal_encoding ascii_encoding = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +/* BT_NONXML == 0 */ + }, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +#undef PREFIX + +static int unicode_byte_type(char hi, char lo) +{ + switch ((unsigned char)hi) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + return BT_LEAD4; + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return BT_TRAIL; + case 0xFF: + switch ((unsigned char)lo) { + case 0xFF: + case 0xFE: + return BT_NONXML; + } + break; + } + return BT_NONASCII; +} + +#define DEFINE_UTF16_TO_UTF8 \ +static \ +void PREFIX(toUtf8)(const ENCODING *enc, \ + const char **fromP, const char *fromLim, \ + char **toP, const char *toLim) \ +{ \ + (void)enc; \ + const char *from; \ + for (from = *fromP; from != fromLim; from += 2) { \ + int plane; \ + unsigned char lo2; \ + unsigned char lo = GET_LO(from); \ + unsigned char hi = GET_HI(from); \ + switch (hi) { \ + case 0: \ + if (lo < 0x80) { \ + if (*toP == toLim) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = lo; \ + break; \ + } \ + /* fall through */ \ + case 0x1: case 0x2: case 0x3: \ + case 0x4: case 0x5: case 0x6: case 0x7: \ + if (toLim - *toP < 2) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + default: \ + if (toLim - *toP < 3) { \ + *fromP = from; \ + return; \ + } \ + /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \ + *(*toP)++ = ((hi >> 4) | UTF8_cval3); \ + *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + case 0xD8: case 0xD9: case 0xDA: case 0xDB: \ + if (toLim - *toP < 4) { \ + *fromP = from; \ + return; \ + } \ + plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \ + *(*toP)++ = ((plane >> 2) | UTF8_cval4); \ + *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \ + from += 2; \ + lo2 = GET_LO(from); \ + *(*toP)++ = (((lo & 0x3) << 4) \ + | ((GET_HI(from) & 0x3) << 2) \ + | (lo2 >> 6) \ + | 0x80); \ + *(*toP)++ = ((lo2 & 0x3f) | 0x80); \ + break; \ + } \ + } \ + *fromP = from; \ +} + +#define DEFINE_UTF16_TO_UTF16 \ +static \ +void PREFIX(toUtf16)(const ENCODING *enc, \ + const char **fromP, const char *fromLim, \ + unsigned short **toP, const unsigned short *toLim) \ +{ \ + (void)enc; \ + /* Avoid copying first half only of surrogate */ \ + if (fromLim - *fromP > ((toLim - *toP) << 1) \ + && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \ + fromLim -= 2; \ + for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \ + *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \ +} + +#define PREFIX(ident) little2_ ## ident +#define MINBPC 2 +#define BYTE_TYPE(enc, p) \ + ((p)[1] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ + : unicode_byte_type((p)[1], (p)[0])) +#define BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1) +#define CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c) +#define IS_NAME_CHAR(enc, p, n) (0) +#define IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) + +#include "xmltimpl.c" + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8))) +#define GET_LO(ptr) ((unsigned char)(ptr)[0]) +#define GET_HI(ptr) ((unsigned char)(ptr)[1]) + +DEFINE_UTF16_TO_UTF8 +DEFINE_UTF16_TO_UTF16 + +#undef SET2 +#undef GET_LO +#undef GET_HI +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +static const struct normal_encoding little2_encoding = { + { VTABLE, 2, 0, +#if BYTE_ORDER == 12 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +#if BYTE_ORDER != 21 + +static const struct normal_encoding internal_little2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#include "iasctab.h" +#include "latin1tab.h" + }, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +#endif + +#undef PREFIX + +#define PREFIX(ident) big2_ ## ident +#define MINBPC 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) \ + ((p)[0] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ + : unicode_byte_type((p)[0], (p)[1])) +#define BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1) +#define CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) + +#include "xmltimpl.c" + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF))) +#define GET_LO(ptr) ((unsigned char)(ptr)[1]) +#define GET_HI(ptr) ((unsigned char)(ptr)[0]) + +DEFINE_UTF16_TO_UTF8 +DEFINE_UTF16_TO_UTF16 + +#undef SET2 +#undef GET_LO +#undef GET_HI +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +static const struct normal_encoding big2_encoding = { + { VTABLE, 2, 0, +#if BYTE_ORDER == 21 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +#if BYTE_ORDER != 12 + +static const struct normal_encoding internal_big2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#include "iasctab.h" +#include "latin1tab.h" + }, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +#endif + +#undef PREFIX + +static +int streqci(const char *s1, const char *s2) +{ + for (;;) { + char c1 = *s1++; + char c2 = *s2++; + if ('a' <= c1 && c1 <= 'z') + c1 += 'A' - 'a'; + if ('a' <= c2 && c2 <= 'z') + c2 += 'A' - 'a'; + if (c1 != c2) + return 0; + if (!c1) + break; + } + return 1; +} + +static +int initScan(const ENCODING *enc, int state, const char *ptr, const char *end, + const char **nextTokPtr) +{ + const ENCODING **encPtr; + + if (ptr == end) + return XML_TOK_NONE; + encPtr = ((const INIT_ENCODING *)enc)->encPtr; + if (ptr + 1 == end) { + switch ((unsigned char)*ptr) { + case 0xFE: + case 0xFF: + case 0x00: + case 0x3C: + return XML_TOK_PARTIAL; + } + } + else { + switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) { + case 0x003C: + *encPtr = &big2_encoding.enc; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + case 0xFEFF: + *nextTokPtr = ptr + 2; + *encPtr = &big2_encoding.enc; + return XML_TOK_BOM; + case 0x3C00: + *encPtr = &little2_encoding.enc; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + case 0xFFFE: + *nextTokPtr = ptr + 2; + *encPtr = &little2_encoding.enc; + return XML_TOK_BOM; + } + } + *encPtr = &utf8_encoding.enc; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); +} + +static +int initScanProlog(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr); +} + +static +int initScanContent(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr); +} + +static +void initUpdatePosition(const ENCODING *enc, const char *ptr, + const char *end, POSITION *pos) +{ + (void)enc; + normal_updatePosition(&utf8_encoding.enc, ptr, end, pos); +} + +const ENCODING *XmlGetUtf8InternalEncoding() +{ + return &internal_utf8_encoding.enc; +} + +const ENCODING *XmlGetUtf16InternalEncoding() +{ +#if BYTE_ORDER == 12 + return &internal_little2_encoding.enc; +#elif BYTE_ORDER == 21 + return &internal_big2_encoding.enc; +#else + const short n = 1; + return *(const char *)&n ? &internal_little2_encoding.enc : &internal_big2_encoding.enc; +#endif +} + +int XmlInitEncoding(INIT_ENCODING *p, const ENCODING **encPtr, const char *name) +{ + if (name) { + if (streqci(name, "ISO-8859-1")) { + *encPtr = &latin1_encoding.enc; + return 1; + } + if (streqci(name, "UTF-8")) { + *encPtr = &utf8_encoding.enc; + return 1; + } + if (streqci(name, "US-ASCII")) { + *encPtr = &ascii_encoding.enc; + return 1; + } + if (!streqci(name, "UTF-16")) + return 0; + } + p->initEnc.scanners[XML_PROLOG_STATE] = initScanProlog; + p->initEnc.scanners[XML_CONTENT_STATE] = initScanContent; + p->initEnc.updatePosition = initUpdatePosition; + p->initEnc.minBytesPerChar = 1; + p->encPtr = encPtr; + *encPtr = &(p->initEnc); + return 1; +} + +static +int toAscii(const ENCODING *enc, const char *ptr, const char *end) +{ + char buf[1]; + char *p = buf; + XmlUtf8Convert(enc, &ptr, end, &p, p + 1); + if (p == buf) + return -1; + else + return buf[0]; +} + +static +int isSpace(int c) +{ + switch (c) { + case ' ': + case '\r': + case '\n': + case '\t': + return 1; + } + return 0; +} + +/* Return 1 if there's just optional white space +or there's an S followed by name=val. */ +static +int parsePseudoAttribute(const ENCODING *enc, + const char *ptr, + const char *end, + const char **namePtr, + const char **valPtr, + const char **nextTokPtr) +{ + int c; + char open; + if (ptr == end) { + *namePtr = 0; + return 1; + } + if (!isSpace(toAscii(enc, ptr, end))) { + *nextTokPtr = ptr; + return 0; + } + do { + ptr += enc->minBytesPerChar; + } while (isSpace(toAscii(enc, ptr, end))); + if (ptr == end) { + *namePtr = 0; + return 1; + } + *namePtr = ptr; + for (;;) { + c = toAscii(enc, ptr, end); + if (c == -1) { + *nextTokPtr = ptr; + return 0; + } + if (c == '=') + break; + if (isSpace(c)) { + do { + ptr += enc->minBytesPerChar; + } while (isSpace(c = toAscii(enc, ptr, end))); + if (c != '=') { + *nextTokPtr = ptr; + return 0; + } + break; + } + ptr += enc->minBytesPerChar; + } + if (ptr == *namePtr) { + *nextTokPtr = ptr; + return 0; + } + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + while (isSpace(c)) { + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + } + if (c != '"' && c != '\'') { + *nextTokPtr = ptr; + return 0; + } + open = c; + ptr += enc->minBytesPerChar; + *valPtr = ptr; + for (;; ptr += enc->minBytesPerChar) { + c = toAscii(enc, ptr, end); + if (c == open) + break; + if (!('a' <= c && c <= 'z') + && !('A' <= c && c <= 'Z') + && !('0' <= c && c <= '9') + && c != '.' + && c != '-' + && c != '_') { + *nextTokPtr = ptr; + return 0; + } + } + *nextTokPtr = ptr + enc->minBytesPerChar; + return 1; +} + +static +const ENCODING *findEncoding(const ENCODING *enc, const char *ptr, const char *end) +{ +#define ENCODING_MAX 128 + char buf[ENCODING_MAX]; + char *p = buf; + int i; + XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); + if (ptr != end) + return 0; + *p = 0; + for (i = 0; buf[i]; i++) { + if ('a' <= buf[i] && buf[i] <= 'z') + buf[i] += 'A' - 'a'; + } + if (streqci(buf, "UTF-8")) + return &utf8_encoding.enc; + if (streqci(buf, "ISO-8859-1")) + return &latin1_encoding.enc; + if (streqci(buf, "US-ASCII")) + return &ascii_encoding.enc; + if (streqci(buf, "UTF-16")) { +// static const unsigned short n = 1; + if (enc->minBytesPerChar == 2) + return enc; + return &big2_encoding.enc; + } + return 0; +} + +int XmlParseXmlDecl(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + const char *val = 0; + const char *name = 0; + ptr += 5 * enc->minBytesPerChar; + end -= 2 * enc->minBytesPerChar; + if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr) || !name) { + *badPtr = ptr; + return 0; + } + if (!XmlNameMatchesAscii(enc, name, "version")) { + if (!isGeneralTextEntity) { + *badPtr = name; + return 0; + } + } + else { + if (versionPtr) + *versionPtr = val; + if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) + return 1; + } + if (XmlNameMatchesAscii(enc, name, "encoding")) { + int c = toAscii(enc, val, end); + if (!('a' <= c && c <= 'z') && !('A' <= c && c <= 'Z')) { + *badPtr = val; + return 0; + } + if (encodingName) + *encodingName = val; + if (encoding) + *encoding = findEncoding(enc, val, ptr - enc->minBytesPerChar); + if (!parsePseudoAttribute(enc, ptr, end, &name, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) + return 1; + } + if (!XmlNameMatchesAscii(enc, name, "standalone") || isGeneralTextEntity) { + *badPtr = name; + return 0; + } + if (XmlNameMatchesAscii(enc, val, "yes")) { + if (standalone) + *standalone = 1; + } + else if (XmlNameMatchesAscii(enc, val, "no")) { + if (standalone) + *standalone = 0; + } + else { + *badPtr = val; + return 0; + } + while (isSpace(toAscii(enc, ptr, end))) + ptr += enc->minBytesPerChar; + if (ptr != end) { + *badPtr = ptr; + return 0; + } + return 1; +} + +static +int checkCharRefNumber(int result) +{ + switch (result >> 8) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return -1; + case 0: + if (latin1_encoding.type[result] == BT_NONXML) + return -1; + break; + case 0xFF: + if (result == 0xFFFE || result == 0xFFFF) + return -1; + break; + } + return result; +} + +int XmlUtf8Encode(int c, char *buf) +{ + enum { + /* minN is minimum legal resulting value for N byte sequence */ + min2 = 0x80, + min3 = 0x800, + min4 = 0x10000 + }; + + if (c < 0) + return 0; + if (c < min2) { + buf[0] = (c | UTF8_cval1); + return 1; + } + if (c < min3) { + buf[0] = ((c >> 6) | UTF8_cval2); + buf[1] = ((c & 0x3f) | 0x80); + return 2; + } + if (c < min4) { + buf[0] = ((c >> 12) | UTF8_cval3); + buf[1] = (((c >> 6) & 0x3f) | 0x80); + buf[2] = ((c & 0x3f) | 0x80); + return 3; + } + if (c < 0x110000) { + buf[0] = ((c >> 18) | UTF8_cval4); + buf[1] = (((c >> 12) & 0x3f) | 0x80); + buf[2] = (((c >> 6) & 0x3f) | 0x80); + buf[3] = ((c & 0x3f) | 0x80); + return 4; + } + return 0; +} + +int XmlUtf16Encode(int charNum, unsigned short *buf) +{ + if (charNum < 0) + return 0; + if (charNum < 0x10000) { + buf[0] = charNum; + return 1; + } + if (charNum < 0x110000) { + charNum -= 0x10000; + buf[0] = (charNum >> 10) + 0xD800; + buf[1] = (charNum & 0x3FF) + 0xDC00; + return 2; + } + return 0; +} + +typedef struct unknown_encoding { + struct normal_encoding normal; + int (*convert)(void *userData, const char *p); + void *userData; + unsigned short utf16[256]; + char utf8[256][4]; +} unknown_encoding; + +int XmlSizeOfUnknownEncoding() +{ + return sizeof(struct unknown_encoding); +} + +static +int unknown_isName(const ENCODING *enc, const char *p) +{ + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); +} + +static +int unknown_isNmstrt(const ENCODING *enc, const char *p) +{ + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); +} + +static +int unknown_isInvalid(const ENCODING *enc, const char *p) +{ + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, p); + return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; +} + +static +void unknown_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + char buf[XML_UTF8_ENCODE_MAX]; + for (;;) { + const char *utf8; + int n; + if (*fromP == fromLim) + break; + utf8 = ((const struct unknown_encoding *)enc)->utf8[(unsigned char)**fromP]; + n = *utf8++; + if (n == 0) { + int c = ((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, *fromP); + n = XmlUtf8Encode(c, buf); + if (n > toLim - *toP) + break; + utf8 = buf; + *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2); + } + else { + if (n > toLim - *toP) + break; + (*fromP)++; + } + do { + *(*toP)++ = *utf8++; + } while (--n != 0); + } +} + +static +void unknown_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + while (*fromP != fromLim && *toP != toLim) { + unsigned short c + = ((const struct unknown_encoding *)enc)->utf16[(unsigned char)**fromP]; + if (c == 0) { + c = (unsigned short)((const struct unknown_encoding *)enc) + ->convert(((const struct unknown_encoding *)enc)->userData, *fromP); + *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2); + } + else + (*fromP)++; + *(*toP)++ = c; + } +} + +ENCODING * +XmlInitUnknownEncoding(void *mem, + int *table, + int (*convert)(void *userData, const char *p), + void *userData) +{ + int i; + struct unknown_encoding *e = (unknown_encoding*)mem; + for (i = 0; i < (int)sizeof(struct normal_encoding); i++) + ((char *)mem)[i] = ((char *)&latin1_encoding)[i]; + for (i = 0; i < 128; i++) + if (latin1_encoding.type[i] != BT_OTHER + && latin1_encoding.type[i] != BT_NONXML + && table[i] != i) + return 0; + for (i = 0; i < 256; i++) { + int c = table[i]; + if (c == -1) { + e->normal.type[i] = BT_MALFORM; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else if (c < 0) { + if (c < -4) + return 0; + e->normal.type[i] = BT_LEAD2 - (c + 2); + e->utf8[i][0] = 0; + e->utf16[i] = 0; + } + else if (c < 0x80) { + if (latin1_encoding.type[c] != BT_OTHER + && latin1_encoding.type[c] != BT_NONXML + && c != i) + return 0; + e->normal.type[i] = latin1_encoding.type[c]; + e->utf8[i][0] = 1; + e->utf8[i][1] = (char)c; + e->utf16[i] = c == 0 ? 0xFFFF : c; + } + else if (checkCharRefNumber(c) < 0) { + e->normal.type[i] = BT_NONXML; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else { + if (c > 0xFFFF) + return 0; + if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NMSTRT; + else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NAME; + else + e->normal.type[i] = BT_OTHER; + e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1); + e->utf16[i] = c; + } + } + e->userData = userData; + e->convert = convert; + if (convert) { + e->normal.isName2 = unknown_isName; + e->normal.isName3 = unknown_isName; + e->normal.isName4 = unknown_isName; + e->normal.isNmstrt2 = unknown_isNmstrt; + e->normal.isNmstrt3 = unknown_isNmstrt; + e->normal.isNmstrt4 = unknown_isNmstrt; + e->normal.isInvalid2 = unknown_isInvalid; + e->normal.isInvalid3 = unknown_isInvalid; + e->normal.isInvalid4 = unknown_isInvalid; + } + e->normal.enc.utf8Convert = unknown_toUtf8; + e->normal.enc.utf16Convert = unknown_toUtf16; + return &(e->normal.enc); +} diff --git a/lib/xmltree/xmltok.h b/lib/xmltree/xmltok.h new file mode 100644 index 000000000..6d0b91dff --- /dev/null +++ b/lib/xmltree/xmltok.h @@ -0,0 +1,276 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998 +James Clark. All Rights Reserved. + +Contributor(s): +*/ + +#ifndef XmlTok_INCLUDED +#define XmlTok_INCLUDED 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef XMLTOKAPI +#define XMLTOKAPI /* as nothing */ +#endif + +/* The following token may be returned by XmlContentTok */ +#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be start of + illegal ]]> sequence */ +/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */ +#define XML_TOK_NONE -4 /* The string to be scanned is empty */ +#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan; + might be part of CRLF sequence */ +#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ +#define XML_TOK_PARTIAL -1 /* only part of a token */ +#define XML_TOK_INVALID 0 + +/* The following tokens are returned by XmlContentTok; some are also + returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok */ + +#define XML_TOK_START_TAG_WITH_ATTS 1 +#define XML_TOK_START_TAG_NO_ATTS 2 +#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag */ +#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 +#define XML_TOK_END_TAG 5 +#define XML_TOK_DATA_CHARS 6 +#define XML_TOK_DATA_NEWLINE 7 +#define XML_TOK_CDATA_SECT_OPEN 8 +#define XML_TOK_ENTITY_REF 9 +#define XML_TOK_CHAR_REF 10 /* numeric character reference */ + +/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */ +#define XML_TOK_PI 11 /* processing instruction */ +#define XML_TOK_XML_DECL 12 /* XML decl or text decl */ +#define XML_TOK_COMMENT 13 +#define XML_TOK_BOM 14 /* Byte order mark */ + +/* The following tokens are returned only by XmlPrologTok */ +#define XML_TOK_PROLOG_S 15 +#define XML_TOK_DECL_OPEN 16 /* */ +#define XML_TOK_NAME 18 +#define XML_TOK_NMTOKEN 19 +#define XML_TOK_POUND_NAME 20 /* #name */ +#define XML_TOK_OR 21 /* | */ +#define XML_TOK_PERCENT 22 +#define XML_TOK_OPEN_PAREN 23 +#define XML_TOK_CLOSE_PAREN 24 +#define XML_TOK_OPEN_BRACKET 25 +#define XML_TOK_CLOSE_BRACKET 26 +#define XML_TOK_LITERAL 27 +#define XML_TOK_PARAM_ENTITY_REF 28 +#define XML_TOK_INSTANCE_START 29 + +/* The following occur only in element type declarations */ +#define XML_TOK_NAME_QUESTION 30 /* name? */ +#define XML_TOK_NAME_ASTERISK 31 /* name* */ +#define XML_TOK_NAME_PLUS 32 /* name+ */ +#define XML_TOK_COND_SECT_OPEN 33 /* */ +#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ +#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ +#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ +#define XML_TOK_COMMA 38 + +/* The following token is returned only by XmlAttributeValueTok */ +#define XML_TOK_ATTRIBUTE_VALUE_S 39 + +/* The following token is returned only by XmlCdataSectionTok */ +#define XML_TOK_CDATA_SECT_CLOSE 40 + +#define XML_N_STATES 3 +#define XML_PROLOG_STATE 0 +#define XML_CONTENT_STATE 1 +#define XML_CDATA_SECTION_STATE 2 + +#define XML_N_LITERAL_TYPES 2 +#define XML_ATTRIBUTE_VALUE_LITERAL 0 +#define XML_ENTITY_VALUE_LITERAL 1 + +/* The size of the buffer passed to XmlUtf8Encode must be at least this. */ +#define XML_UTF8_ENCODE_MAX 4 +/* The size of the buffer passed to XmlUtf16Encode must be at least this. */ +#define XML_UTF16_ENCODE_MAX 2 + +typedef struct position { + /* first line and first column are 0 not 1 */ + unsigned long lineNumber; + unsigned long columnNumber; +} POSITION; + +typedef struct { + const char *name; + const char *valuePtr; + const char *valueEnd; + char normalized; +} ATTRIBUTE; + +struct encoding; +typedef struct encoding ENCODING; + +struct encoding { + int (*scanners[XML_N_STATES])(const ENCODING *, + const char *, + const char *, + const char **); + int (*literalScanners[XML_N_LITERAL_TYPES])(const ENCODING *, + const char *, + const char *, + const char **); + int (*sameName)(const ENCODING *, + const char *, const char *); + int (*nameMatchesAscii)(const ENCODING *, + const char *, const char *); + int (*nameLength)(const ENCODING *, const char *); + const char *(*skipS)(const ENCODING *, const char *); + int (*getAtts)(const ENCODING *enc, const char *ptr, + int attsMax, ATTRIBUTE *atts); + int (*charRefNumber)(const ENCODING *enc, const char *ptr); + int (*predefinedEntityName)(const ENCODING *, const char *, const char *); + void (*updatePosition)(const ENCODING *, + const char *ptr, + const char *end, + POSITION *); + int (*isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr); + void (*utf8Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + char **toP, + const char *toLim); + void (*utf16Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + unsigned short **toP, + const unsigned short *toLim); + int minBytesPerChar; + char isUtf8; + char isUtf16; +}; + +/* +Scan the string starting at ptr until the end of the next complete token, +but do not scan past eptr. Return an integer giving the type of token. + +Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set. + +Return XML_TOK_PARTIAL when the string does not contain a complete token; +nextTokPtr will not be set. + +Return XML_TOK_INVALID when the string does not start a valid token; nextTokPtr +will be set to point to the character which made the token invalid. + +Otherwise the string starts with a valid token; nextTokPtr will be set to point +to the character following the end of that token. + +Each data character counts as a single token, but adjacent data characters +may be returned together. Similarly for characters in the prolog outside +literals, comments and processing instructions. +*/ + + +#define XmlTok(enc, state, ptr, end, nextTokPtr) \ + (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) + +#define XmlPrologTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) + +#define XmlContentTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) + +#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) + +/* This is used for performing a 2nd-level tokenization on +the content of a literal that has already been returned by XmlTok. */ + +#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ + (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) + +#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2)) + +#define XmlNameMatchesAscii(enc, ptr1, ptr2) \ + (((enc)->nameMatchesAscii)(enc, ptr1, ptr2)) + +#define XmlNameLength(enc, ptr) \ + (((enc)->nameLength)(enc, ptr)) + +#define XmlSkipS(enc, ptr) \ + (((enc)->skipS)(enc, ptr)) + +#define XmlGetAttributes(enc, ptr, attsMax, atts) \ + (((enc)->getAtts)(enc, ptr, attsMax, atts)) + +#define XmlCharRefNumber(enc, ptr) \ + (((enc)->charRefNumber)(enc, ptr)) + +#define XmlPredefinedEntityName(enc, ptr, end) \ + (((enc)->predefinedEntityName)(enc, ptr, end)) + +#define XmlUpdatePosition(enc, ptr, end, pos) \ + (((enc)->updatePosition)(enc, ptr, end, pos)) + +#define XmlIsPublicId(enc, ptr, end, badPtr) \ + (((enc)->isPublicId)(enc, ptr, end, badPtr)) + +#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) + +#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) + +typedef struct { + ENCODING initEnc; + const ENCODING **encPtr; +} INIT_ENCODING; + +int XMLTOKAPI XmlParseXmlDecl(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, + int *standalonePtr); + +int XMLTOKAPI XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING XMLTOKAPI *XmlGetUtf8InternalEncoding(); +const ENCODING XMLTOKAPI *XmlGetUtf16InternalEncoding(); +int XMLTOKAPI XmlUtf8Encode(int charNumber, char *buf); +int XMLTOKAPI XmlUtf16Encode(int charNumber, unsigned short *buf); + +int XMLTOKAPI XmlSizeOfUnknownEncoding(); +ENCODING XMLTOKAPI * +XmlInitUnknownEncoding(void *mem, + int *table, + int (*convert)(void *userData, const char *p), + void *userData); + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlTok_INCLUDED */ diff --git a/lib/xmltree/xmltok/latin1tab.h b/lib/xmltree/xmltok/latin1tab.h new file mode 100644 index 000000000..48609aa8f --- /dev/null +++ b/lib/xmltree/xmltok/latin1tab.h @@ -0,0 +1,62 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + +/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, +/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, diff --git a/lib/xmltree/xmltok/nametab.h b/lib/xmltree/xmltok/nametab.h new file mode 100644 index 000000000..b05e62c77 --- /dev/null +++ b/lib/xmltree/xmltok/nametab.h @@ -0,0 +1,150 @@ +static const unsigned namingBitmap[] = { +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE, +0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, +0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF, +0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, +0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000, +0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, +0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, +0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003, +0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, +0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, +0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003, +0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, +0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, +0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003, +0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000, +0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, +0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, +0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB, +0x40000000, 0xF580C900, 0x00000007, 0x02010800, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF, +0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, +0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, +0x00000000, 0x00004C40, 0x00000000, 0x00000000, +0x00000007, 0x00000000, 0x00000000, 0x00000000, +0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, +0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF, +0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000, +0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, +0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, +0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, +0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, +0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, +0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF, +0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, +0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, +0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0, +0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, +0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, +0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80, +0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, +0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, +0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, +0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000, +0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, +0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, +0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, +0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF, +}; +static const unsigned char nmstrtPages[] = { +0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, +0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, +0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const unsigned char namePages[] = { +0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, +0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, +0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/lib/xmltree/xmltok/utf8tab.h b/lib/xmltree/xmltok/utf8tab.h new file mode 100644 index 000000000..a38fe624e --- /dev/null +++ b/lib/xmltree/xmltok/utf8tab.h @@ -0,0 +1,63 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + + +/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, +/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, diff --git a/lib/xmltree/xmltok/xmldef.h b/lib/xmltree/xmltok/xmldef.h new file mode 100644 index 000000000..49ce9ed63 --- /dev/null +++ b/lib/xmltree/xmltok/xmldef.h @@ -0,0 +1,63 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + +#include + +#ifdef XML_WINLIB + +#define WIN32_LEAN_AND_MEAN +#define STRICT +#include + +#define malloc(x) HeapAlloc(GetProcessHeap(), 0, (x)) +#define calloc(x, y) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x)*(y)) +#define free(x) HeapFree(GetProcessHeap(), 0, (x)) +#define realloc(x, y) HeapReAlloc(GetProcessHeap(), 0, x, y) +#define abort() /* as nothing */ + +#else /* not XML_WINLIB */ + +#include + +#endif /* not XML_WINLIB */ + +/* This file can be used for any definitions needed in +particular environments. */ + +#ifdef MOZILLA + +#include "nspr.h" +#define malloc(x) PR_Malloc(x) +#define realloc(x, y) PR_Realloc((x), (y)) +#define calloc(x, y) PR_Calloc((x),(y)) +#define free(x) PR_Free(x) +#define int int32 + +#endif /* MOZILLA */ diff --git a/lib/xmltree/xmltree.cpp b/lib/xmltree/xmltree.cpp new file mode 100644 index 000000000..3d03fad4c --- /dev/null +++ b/lib/xmltree/xmltree.cpp @@ -0,0 +1,446 @@ +/* xmltree.cpp + * + * XMLTree API implementation + * + * $Id: xmltree.cpp,v 1.2 2003/03/14 05:13:04 obi Exp $ + * + * Changelog: + * $Log: xmltree.cpp,v $ + * Revision 1.2 2003/03/14 05:13:04 obi + * compileable with -W -Werror + * + * Revision 1.1 2002/01/18 20:22:39 tmbinc + * initial checkin + * + * Revision 1.1.1.1 2001/10/07 13:01:18 tmbinc + * Import of ezap2-200110070 + * + * Revision 1.4 1999/02/26 13:17:21 cvs + * - thousands of bugs fixed (really) + * - modifications in the XML part + * - added a new object for testing, cpiwButton (usable already, see + * win32/ts.cpp) + * - modified ts.cpp to create a pseudo-GUI again (for testing the + * buttons) + * - ts now exits on a click in the windows + * - ts has no titlebar anymore (will soon by replace by a special + * widget) + * + * (ryg) + * + * Revision 1.3 1999/01/25 18:05:27 cvs + * ARG! tmb, next time you look bevor you say shit, okay? (ryg) + * + * Revision 1.1 1999/01/24 16:01:14 cvs + * First release of the XMLTree API (ryg) + * + */ + +#define stricmp strcasecmp + +#include +#include +#include "xmltree.h" + +/* XMLAttribute class */ + +XMLAttribute::XMLAttribute() +{ + name=value=0; + next=prev=0; +} + +XMLAttribute::XMLAttribute(char *nam, char *val) +{ + name=value=0; + next=prev=0; + + SetName(nam); + SetValue(val); +} + +XMLAttribute::XMLAttribute(XMLAttribute *prv, char *nam, char *val) +{ + name=value=0; + + SetName(nam); + SetValue(val); + SetPrevious(prv); + + next=0; +} + +XMLAttribute::XMLAttribute(XMLAttribute *prv, char *nam, char *val, XMLAttribute *nxt) +{ + name=value=0; + + SetName(nam); + SetValue(val); + + SetPrevious(prv); + SetNext(nxt); +} + +XMLAttribute::~XMLAttribute() +{ + if (name) { free(name); name=0; }; + if (value) { free(value); value=0; }; + + next=prev=0; +} + +void XMLAttribute::SetName(char *nam) +{ + if (name) free(name); + + name=strdup(nam); +} + +void XMLAttribute::SetValue(char *val) +{ + if (value) free(value); + + value=strdup(val); +} + +void XMLAttribute::SetNext(XMLAttribute *nxt) +{ + next=nxt; +} + +void XMLAttribute::SetPrevious(XMLAttribute *prv) +{ + prev=prv; +} + +/* XMLTreeNode class */ + +XMLTreeNode::XMLTreeNode(XMLTreeNode *prnt) +{ + attributes=0; + next=child=0; + type=data=0; + dataSize=0; + + SetMatchingMode(prnt?prnt->mmode:MATCH_CASE); + SetParent(prnt); +} + +XMLTreeNode::XMLTreeNode(XMLTreeNode *prnt, char *typ) +{ + attributes=0; + next=child=0; + type=data=0; + dataSize=0; + + SetType(typ); + SetMatchingMode(prnt?prnt->mmode:MATCH_CASE); + SetParent(prnt); +} + +XMLTreeNode::XMLTreeNode(XMLTreeNode *prnt, char *typ, char *dta, unsigned int dtaSize) +{ + attributes=0; + next=child=0; + type=0; + + SetType(typ); + SetData(dta, dtaSize); + SetMatchingMode(prnt?prnt->mmode:MATCH_CASE); + SetParent(prnt); +} + +XMLTreeNode::XMLTreeNode(XMLTreeNode *prnt, char *typ, char *dta, unsigned int dtaSize, XMLTreeNode *cld) +{ + attributes=0; + next=0; + type=0; + + SetType(typ); + SetData(dta, dtaSize); + SetChild(cld); + SetMatchingMode(prnt?prnt->mmode:MATCH_CASE); + SetParent(prnt); +} + +XMLTreeNode::XMLTreeNode(XMLTreeNode *prnt, char *typ, char *dta, unsigned int dtaSize, XMLTreeNode *cld, XMLTreeNode *nxt) +{ + attributes=0; + type=0; + + SetType(typ); + SetData(dta, dtaSize); + SetChild(cld); + SetNext(nxt); + SetMatchingMode(prnt?prnt->mmode:MATCH_CASE); + SetParent(prnt); +} + +XMLTreeNode::~XMLTreeNode() +{ + DeleteAttributes(); + DeleteChildren(); + + if (type) { free(type); type=0; }; + if (data) { delete[] data; dataSize=0; }; + + next=0; +} + +XMLAttribute *XMLTreeNode::GetAttribute(char *name) const +{ + XMLAttribute *a; + + a=attributes; + + while (a) + { + if (a->GetName()) + { + switch (mmode) + { + case MATCH_CASE: + if (!strcmp(a->GetName(), name)) return a; + + case MATCH_NOCASE: + if (!stricmp(a->GetName(), name)) return a; + } + } + + a=a->GetNext(); + } + + return 0; +} + +char *XMLTreeNode::GetAttributeValue(char *name) const +{ + XMLAttribute *a; + + a=GetAttribute(name); + if (a) return a->GetValue(); + + return 0; +} + +void XMLTreeNode::AddNode(XMLTreeNode *node, addmode mode) +{ + XMLTreeNode *n=0; + + if (!node) return; + node->next=0; + + switch (mode) + { + case ADD_NEIGHBOUR: + n=this; + + case ADD_CHILD: + n=child; + } + + if (n) + { + while (n->next) n=n->next; + + n->next=node; + } + else + child=node; +} + +XMLTreeNode *XMLTreeNode::AddNode(addmode mode) +{ + XMLTreeNode *n=new XMLTreeNode(this); + + AddNode(n, mode); + + return n; +} + +void XMLTreeNode::SetNext(XMLTreeNode *nxt) +{ + next=nxt; +} + +void XMLTreeNode::SetChild(XMLTreeNode *cld) +{ + child=cld; +} + +void XMLTreeNode::SetParent(XMLTreeNode *prnt) +{ + parent=prnt; +} + +void XMLTreeNode::SetAttribute(char *name, char *value) +{ + XMLAttribute *a; + + a=GetAttribute(name); + + if (a) + a->SetValue(value); + else + { + a=attributes; + + if (a) + { + while (a->GetNext()) a=a->GetNext(); + + a->SetNext(new XMLAttribute(a, name, value, 0)); + } + else + { + a=attributes=new XMLAttribute(0, name, value, 0); + } + } +} + +void XMLTreeNode::SetType(char *typ) +{ + if (type) free(type); + + type=strdup(typ); +} + +void XMLTreeNode::SetData(char *dat, unsigned int datSize) +{ + if (data) delete[] data; + + dataSize=datSize; + data=new char[dataSize+1]; + data[dataSize]=0; + + memcpy(data, dat, datSize); +} + +void XMLTreeNode::AppendData(char *dat, unsigned int datSize) +{ + if (!data) + SetData(dat, datSize); + else + { + char *tmp; + + tmp=new char[dataSize+datSize]; + memcpy(tmp, data, dataSize); + memcpy(tmp+dataSize, dat, datSize); + + SetData(tmp, dataSize+datSize); + + delete[] tmp; + } +} + +void XMLTreeNode::SetPDataOff(int pdo) +{ + pdataOff=pdo; +} + +void XMLTreeNode::SetMatchingMode(matchmode mode) +{ + mmode=mode; +}; + +void XMLTreeNode::DeleteAttribute(char *name) +{ + XMLAttribute *a, *next, *prev; + + a=GetAttribute(name); + if (!a) return; + + next=a->GetNext(); + prev=a->GetPrevious(); + + if (prev) prev->SetNext(next); + if (next) next->SetPrevious(prev); + + delete a; +} + +void XMLTreeNode::DeleteAttributes() +{ + XMLAttribute *a, *b; + + a=attributes; + + while (a) + { + b=a->GetNext(); delete a; + a=b; + } + + attributes=0; +} + +void XMLTreeNode::DeleteChildren() +{ + XMLTreeNode *a, *b; + + if (!child) return; + a=child; + + while (a) + { + b=a->next; delete a; + a=b; + } + + child=0; +} + +void XMLTreeParser::StartElementHandler(const XML_Char *name, const XML_Char **atts) +{ + XMLTreeNode *n; + const XML_Char **a=atts; + + n=new XMLTreeNode(current, (char *) name); + + if (a) + { + while (*a) { n->SetAttribute((char *) a[0], (char *) a[1]); a+=2; }; + } + + if (current) + { + n->SetPDataOff(current->GetDataSize()); + current->AddNode(n, XMLTreeNode::ADD_CHILD); + current=n; + } + else + { + root=current=n; + } +} + +void XMLTreeParser::EndElementHandler(const XML_Char* /*name*/) +{ + if (current) + { + if (current->GetParent()) current=current->GetParent(); + } +} + +void XMLTreeParser::CharacterDataHandler(const XML_Char *s, int len) +{ + if (current) + current->AppendData((char *) s, len); +} + +XMLTreeParser::XMLTreeParser(const XML_Char *encoding): XML_Parser(encoding) +{ + root=current=0; + + startElementHandler=endElementHandler=characterDataHandler=1; +} + +XMLTreeParser::~XMLTreeParser() +{ + if (root) + { + delete root; + root=current=0; + } +} diff --git a/lib/xmltree/xmltree.h b/lib/xmltree/xmltree.h new file mode 100644 index 000000000..4e9abdf53 --- /dev/null +++ b/lib/xmltree/xmltree.h @@ -0,0 +1,156 @@ +/* xmltree.h + * + * XMLTree API header + * + * $Id: xmltree.h,v 1.1 2002/01/18 20:22:39 tmbinc Exp $ + * + * Changelog: + * $Log: xmltree.h,v $ + * Revision 1.1 2002/01/18 20:22:39 tmbinc + * initial checkin + * + * Revision 1.1.1.1 2001/10/07 13:01:15 tmbinc + * Import of ezap2-200110070 + * + * Revision 1.4 1999/02/26 13:17:22 cvs + * - thousands of bugs fixed (really) + * - modifications in the XML part + * - added a new object for testing, cpiwButton (usable already, see + * win32/ts.cpp) + * - modified ts.cpp to create a pseudo-GUI again (for testing the + * buttons) + * - ts now exits on a click in the windows + * - ts has no titlebar anymore (will soon by replace by a special + * widget) + * + * (ryg) + * + * Revision 1.3 1999/01/25 18:05:27 cvs + * ARG! tmb, next time you look bevor you say shit, okay? (ryg) + * + * Revision 1.1 1999/01/24 16:01:15 cvs + * First release of the XMLTree API (ryg) + * + */ + +#ifndef __XMLTREE_H +#define __XMLTREE_H + +#include "xmlparse.h" + +class XMLAttribute +{ + private: + char *name, *value; + XMLAttribute *next, *prev; + + public: + XMLAttribute(); + XMLAttribute(char *nam, char *val); + XMLAttribute(XMLAttribute *prv, char *nam, char *val); + XMLAttribute(XMLAttribute *prv, char *nam, char *val, XMLAttribute *nxt); + ~XMLAttribute(); + + char *GetName() { return name; } + char *GetValue() { return value; } + XMLAttribute *GetNext() { return next; } + XMLAttribute *GetPrevious() { return prev; } + + void SetName(char *nam); + void SetValue(char *val); + void SetNext(XMLAttribute *nxt); + void SetPrevious(XMLAttribute *prv); +}; + +class XMLTreeNode +{ + public: + // matching mode: case insensitive or case sensitive? + + enum matchmode + { + MATCH_CASE = 0, + MATCH_NOCASE = 1 + }; + + private: + XMLAttribute *attributes; + XMLTreeNode *next; + XMLTreeNode *child; + XMLTreeNode *parent; + + char *type; + char *data; + unsigned int dataSize; + unsigned int pdataOff; + + matchmode mmode; + + public: + XMLTreeNode(XMLTreeNode *prnt); + XMLTreeNode(XMLTreeNode *prnt, char *typ); + XMLTreeNode(XMLTreeNode *prnt, char *typ, char *dta, unsigned int dtaSize); + XMLTreeNode(XMLTreeNode *prnt, char *typ, char *dta, unsigned int dtaSize, XMLTreeNode *cld); + XMLTreeNode(XMLTreeNode *prnt, char *typ, char *dta, unsigned int dtaSize, XMLTreeNode *cld, XMLTreeNode *nxt); + ~XMLTreeNode(); + + // add modes: add the node as child or neighbour? + + enum addmode + { + ADD_NEIGHBOUR = 0, + ADD_CHILD = 1 + }; + + XMLTreeNode *GetNext() const { return next; } + XMLTreeNode *GetChild() const { return child; } + XMLTreeNode *GetParent() const { return parent; }; + + XMLAttribute *GetAttributes() const { return attributes; } + XMLAttribute *GetAttribute(char *name) const; + char *GetAttributeValue(char *name) const; + + matchmode GetMatchingMode() const { return mmode; } + + char *GetType() const { return type; } + char *GetData() const { return data; } + unsigned int GetDataSize() const { return dataSize; } + unsigned int GetPDataOff() const { return pdataOff; } + + void AddNode(XMLTreeNode *node, addmode mode); + XMLTreeNode *AddNode(addmode mode); + + void SetNext(XMLTreeNode *nxt); + void SetChild(XMLTreeNode *cld); + void SetParent(XMLTreeNode *prnt); + + void SetAttribute(char *name, char *value); + void SetType(char *typ); + void SetData(char *dat, unsigned int datSize); + void AppendData(char *dat, unsigned int datSize); + void SetPDataOff(int pdo); + + void SetMatchingMode(matchmode mode); + + void DeleteAttribute(char *name); + void DeleteAttributes(); + void DeleteChildren(); +}; + +class XMLTreeParser:public XML_Parser +{ + protected: + XMLTreeNode *root, *current; + + virtual void StartElementHandler(const XML_Char *name, const XML_Char **atts); + virtual void EndElementHandler(const XML_Char *name); + virtual void CharacterDataHandler(const XML_Char *s, int len); + + public: + XMLTreeParser(const XML_Char *encoding); + virtual ~XMLTreeParser(); + + XMLTreeNode *RootNode() { return root; }; +}; + +#endif // __XMLTREE_H diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 000000000..ad613693e --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,71 @@ +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +SUBDIRS = zapit gui daemonc driver system sectionsd timerd nhttpd + +INCLUDES = \ + -I$(top_srcdir)/daemons \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/connection \ + -I$(top_srcdir)/lib/libeventserver \ + -I$(top_srcdir)/lib/libconfigfile \ + -I$(top_srcdir)/lib/libnet \ + -I$(top_srcdir)/lib/xmltree \ + -I$(top_srcdir)/lib/libmd5sum \ + -I$(top_srcdir)/lib/libcoolstream \ + -I$(top_srcdir)/lib/libupnpclient \ + @FREETYPE_CFLAGS@ \ + @LIBCS_CFLAGS@ + +bin_PROGRAMS = neutrino + +neutrino_SOURCES = neutrino_menue.cpp neutrino.cpp + +neutrino_LDADD = \ + daemonc/libneutrino_daemonc.a \ + gui/bedit/libneutrino_gui_bedit.a \ + gui/libtimerlist.a \ + gui/libneutrino_gui.a \ + gui/widget/libneutrino_gui_widget.a \ + gui/widget/libneutrino_gui_widget2.a \ + driver/pictureviewer/libneutrino_pictureviewer.a \ + system/libneutrino_system.a \ + driver/libneutrino_driver.a \ + gui/movieinfo.o \ + driver/audiodec/libneutrino_driver_audiodec.a \ + driver/libneutrino_driver_netfile.a \ + gui/libneutrino_gui2.a \ + sectionsd/libsectionsd.a \ + timerd/libtimerd.a \ + zapit/src/libzapit.a \ + nhttpd/libnhttpd.a \ + nhttpd/tuxboxapi/libnhttpd_tuxboxapi.a \ + nhttpd/yhttpd_mods/libyhttpdmods.a \ + nhttpd/yhttpd_core/libyhttpd.a \ + $(top_builddir)/lib/controldclient/libcontroldclient.la \ + $(top_builddir)/lib/sectionsdclient/libsectionsdclient.a \ + $(top_builddir)/lib/timerdclient/libtimerdclient.a \ + $(top_builddir)/src/zapit/lib/libzapitclient.a \ + $(top_builddir)/lib/libconfigfile/libtuxbox-configfile.a \ + $(top_builddir)/lib/connection/libtuxbox-connection.a \ + $(top_builddir)/lib/libeventserver/libtuxbox-eventserver.a \ + $(top_builddir)/lib/xmltree/libtuxbox-xmltree.a \ + $(top_builddir)/lib/libnet/libtuxbox-net.a \ + $(top_builddir)/lib/libmd5sum/libtuxbox-md5sum.a \ + $(top_builddir)/lib/libtuxtxt/libtuxtxt.a \ + $(top_builddir)/lib/libdvbsub/libdvbsub.a \ + $(top_builddir)/lib/libupnpclient/libtuxbox-upnpclient.a \ + @CURL_LIBS@ \ + @FREETYPE_LIBS@ \ + @PNG_LIBS@ \ + @MAD_LIBS@ \ + @ID3TAG_LIBS@ \ + @LIBCS_LIBS@ \ + @AVFORMAT_LIBS@ \ + @AVUTIL_LIBS@ \ + -lvorbisfile -lvorbis -logg \ + -lungif \ + -ljpeg \ + -lcoolstream \ + -lnxp \ + -lrt -lpthread diff --git a/src/daemonc/Makefile.am b/src/daemonc/Makefile.am new file mode 100644 index 000000000..3bd3d0ec9 --- /dev/null +++ b/src/daemonc/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +INCLUDES = \ + -I$(top_srcdir)/daemons \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/libeventserver \ + -I$(top_srcdir)/lib/libconfigfile \ + -I$(top_srcdir)/lib/libnet \ + -I$(top_srcdir)/lib/xmltree \ + @FREETYPE_CFLAGS@ \ + -I$(top_srcdir)/lib + +noinst_LIBRARIES = libneutrino_daemonc.a + +libneutrino_daemonc_a_SOURCES = remotecontrol.cpp diff --git a/src/daemonc/remotecontrol.cpp b/src/daemonc/remotecontrol.cpp new file mode 100644 index 000000000..7ab245b90 --- /dev/null +++ b/src/daemonc/remotecontrol.cpp @@ -0,0 +1,692 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include + +#ifndef TUXTXT_CFG_STANDALONE +extern int tuxtxt_init(); +extern void tuxtxt_start(int tpid); +extern int tuxtxt_stop(); +extern void tuxtxt_close(); +extern void dvbsub_pause(bool pause); +#endif +//FIXME: auto-timeshift +extern bool autoshift; +extern uint32_t shift_timer; +extern uint32_t scrambled_timer; +extern t_channel_id live_channel_id; //zapit + +bool sectionsd_getComponentTagsUniqueKey(const event_id_t uniqueKey, CSectionsdClient::ComponentTagList& tags); +bool sectionsd_getLinkageDescriptorsUniqueKey(const event_id_t uniqueKey, CSectionsdClient::LinkageDescriptorList& descriptors); +bool sectionsd_getNVODTimesServiceKey(const t_channel_id uniqueServiceKey, CSectionsdClient::NVODTimesList& nvod_list); +void sectionsd_setPrivatePid(unsigned short pid); + +CSubService::CSubService(const t_original_network_id anoriginal_network_id, const t_service_id aservice_id, const t_transport_stream_id atransport_stream_id, const std::string &asubservice_name) +{ + service.original_network_id = anoriginal_network_id; + service.service_id = aservice_id; + service.transport_stream_id = atransport_stream_id; + startzeit = 0; + dauer = 0; + subservice_name = asubservice_name; +} + +CSubService::CSubService(const t_original_network_id anoriginal_network_id, const t_service_id aservice_id, const t_transport_stream_id atransport_stream_id, const time_t astartzeit, const unsigned adauer) +{ + service.original_network_id = anoriginal_network_id; + service.service_id = aservice_id; + service.transport_stream_id = atransport_stream_id; + startzeit = astartzeit; + dauer = adauer; + subservice_name = ""; +} + +t_channel_id CSubService::getChannelID(void) const +{ + return CREATE_CHANNEL_ID_FROM_SERVICE_ORIGINALNETWORK_TRANSPORTSTREAM_ID(service.service_id, service.original_network_id, service.transport_stream_id); +} + + +CRemoteControl::CRemoteControl() +{ + current_channel_id = live_channel_id; + current_sub_channel_id = 0; + current_channel_name = ""; + + zap_completion_timeout = 0; + + current_EPGid = 0; + next_EPGid = 0; + memset(¤t_PIDs.PIDs, 0, sizeof(current_PIDs.PIDs) ); + has_ac3 = false; + selected_subchannel = -1; + needs_nvods = false; + director_mode = 0; + current_programm_timer = 0; + is_video_started = true; +} + +#include +#include +extern tallchans allchans; +extern CBouquetManager *g_bouquetManager; + +int CRemoteControl::handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t data) +{ +//printf("[neutrino] MSG %x\n", msg); + if ( zap_completion_timeout != 0 ) { + if ((msg == NeutrinoMessages::EVT_ZAP_COMPLETE) || (msg == NeutrinoMessages::EVT_ZAP_FAILED ) || + (msg == NeutrinoMessages::EVT_ZAP_ISNVOD )) { +//printf("[neutrino] timeout EVT_ZAP current %llx data %llx\n", current_channel_id, *(t_channel_id *)data); + if ((*(t_channel_id *)data) != current_channel_id) { + g_InfoViewer->chanready = 0; + g_Zapit->zapTo_serviceID_NOWAIT(current_channel_id ); + g_Sectionsd->setServiceChanged(current_channel_id &0xFFFFFFFFFFFFULL, false); + + zap_completion_timeout = getcurrenttime() + 2 * (long long) 1000000; + + return messages_return::handled; + } + else { + zap_completion_timeout = 0; + g_InfoViewer->chanready = 1; + } + if ((!is_video_started) && (g_settings.parentallock_prompt != PARENTALLOCK_PROMPT_NEVER)) + g_RCInput->postMsg( NeutrinoMessages::EVT_PROGRAMLOCKSTATUS, 0x100, false ); + } + } else { + if ((msg == NeutrinoMessages::EVT_ZAP_COMPLETE) || (msg == NeutrinoMessages::EVT_ZAP_FAILED ) || + (msg == NeutrinoMessages::EVT_ZAP_ISNVOD )) + { +//printf("[neutrino] EVT_ZAP current %llx data %llx\n", current_channel_id, *(t_channel_id *)data); + g_InfoViewer->chanready = 1; + // warte auf keine Meldung vom ZAPIT -> jemand anderer hat das zappen ausgelöst... + if ((*(t_channel_id *)data) != current_channel_id) { + t_channel_id new_id = *(t_channel_id *)data; + tallchans_iterator cit = allchans.find(new_id); + if ( cit != allchans.end() ) + current_channel_name = cit->second.getName(); + + CVFD::getInstance()->showServicename(current_channel_name); // UTF-8 + current_channel_id = new_id; + is_video_started= true; + + current_EPGid = 0; + next_EPGid = 0; + + memset(¤t_PIDs.PIDs, 0, sizeof(current_PIDs.PIDs) ); + + current_PIDs.APIDs.clear(); + has_ac3 = false; + + subChannels.clear(); + selected_subchannel = -1; + director_mode = 0; + needs_nvods = (msg == NeutrinoMessages:: EVT_ZAP_ISNVOD); + + g_Sectionsd->setServiceChanged( current_channel_id&0xFFFFFFFFFFFFULL, true ); + CNeutrinoApp::getInstance()->channelList->adjustToChannelID(current_channel_id); + if ( g_InfoViewer->is_visible ) + g_RCInput->postMsg( NeutrinoMessages::SHOW_INFOBAR , 0 ); + } + if ((!is_video_started) && (g_settings.parentallock_prompt != PARENTALLOCK_PROMPT_NEVER)) + g_RCInput->postMsg( NeutrinoMessages::EVT_PROGRAMLOCKSTATUS, 0x100, false ); + } + else + if ((msg == NeutrinoMessages::EVT_ZAP_SUB_COMPLETE) || (msg == NeutrinoMessages:: EVT_ZAP_SUB_FAILED )) { +//printf("[neutrino] EVT_ZAP_SUB current %llx data %llx\n", current_sub_channel_id, *(t_channel_id *)data); + if ((*(t_channel_id *)data) != current_sub_channel_id) + { + current_sub_channel_id = *(t_channel_id *)data; + + for(unsigned int i = 0; i < subChannels.size(); i++) + if (subChannels[i].getChannelID() == (*(t_channel_id *)data)) + { + selected_subchannel = i; + break; + } + } + } + } + + if ( msg == NeutrinoMessages::EVT_CURRENTEPG ) { + CSectionsdClient::CurrentNextInfo* info_CN = (CSectionsdClient::CurrentNextInfo*) data; + +//printf("[neutrino] got EVT_CURRENTEPG, uniqueKey %llx chid %llx flags %x\n", info_CN->current_uniqueKey, current_channel_id, info_CN->flags); +//printf("[neutrino] comparing: uniqueKey %llx chid %llx\n", info_CN->current_uniqueKey >> 16, current_channel_id & 0xFFFFFFFFFFFFULL); + if ( ( info_CN->current_uniqueKey >> 16) == (current_channel_id&0xFFFFFFFFFFFFULL)) + { +//printf("[neutrino] channel match\n"); + //CURRENT-EPG für den aktuellen Kanal bekommen!; + + if ( info_CN->current_uniqueKey != current_EPGid ) + { +//printf("[neutrino] info_CN->current_uniqueKey != current_EPGid\n"); + if ( current_EPGid != 0 ) + { + // ist nur ein neues Programm, kein neuer Kanal + + // PIDs neu holen + g_Zapit->getPIDS( current_PIDs ); + + // APID Bearbeitung neu anstossen + has_unresolved_ctags = true; + } + + current_EPGid= info_CN->current_uniqueKey; + + if ( has_unresolved_ctags ) + processAPIDnames(); + + if ( info_CN->flags & CSectionsdClient::epgflags::current_has_linkagedescriptors ) { +//printf("[neutrino] info_CN->flags have current_has_linkaged\n"); + subChannels.clear(); + getSubChannels(); + } + + if ( needs_nvods ) + getNVODs(); + + if ( current_programm_timer != 0 ) + g_RCInput->killTimer( current_programm_timer ); + + time_t end_program= info_CN->current_zeit.startzeit+ info_CN->current_zeit.dauer; + current_programm_timer = g_RCInput->addTimer( &end_program ); + + // is_video_started is only false if channel is locked + if (((!is_video_started) && (info_CN->current_fsk == 0)) || ((!is_video_started) && (g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_CHANGETOLOCKED))) + g_RCInput->postMsg( NeutrinoMessages::EVT_PROGRAMLOCKSTATUS, 0x100, false ); + else + g_RCInput->postMsg( NeutrinoMessages::EVT_PROGRAMLOCKSTATUS, info_CN->current_fsk, false ); + } + } + return messages_return::handled; + } + else if ( msg == NeutrinoMessages::EVT_NEXTEPG ) + { + CSectionsdClient::CurrentNextInfo* info_CN = (CSectionsdClient::CurrentNextInfo*) data; + + if ( ( info_CN->next_uniqueKey >> 16) == (current_channel_id&0xFFFFFFFFFFFFULL) ) + { + // next-EPG für den aktuellen Kanal bekommen, current ist leider net da?!; + if ( info_CN->next_uniqueKey != next_EPGid ) + { + next_EPGid= info_CN->next_uniqueKey; + + // timer setzen + + if ( current_programm_timer != 0 ) + g_RCInput->killTimer( current_programm_timer ); + + time_t end_program= info_CN->next_zeit.startzeit; + current_programm_timer = g_RCInput->addTimer( &end_program ); + } + } + if ( !is_video_started ) + g_RCInput->postMsg( NeutrinoMessages::EVT_PROGRAMLOCKSTATUS, 0x100, false ); + + return messages_return::handled; + } + else if (msg == NeutrinoMessages::EVT_NOEPG_YET) + { + if ((*(t_channel_id *)data) == (current_channel_id&0xFFFFFFFFFFFFULL)) + { + if ( !is_video_started ) + g_RCInput->postMsg( NeutrinoMessages::EVT_PROGRAMLOCKSTATUS, 0x100, false ); + } + return messages_return::handled; + } + else if ((msg == NeutrinoMessages::EVT_ZAP_COMPLETE)|| + (msg == NeutrinoMessages::EVT_ZAP_SUB_COMPLETE)) { + + if ((*(t_channel_id *)data) == ((msg == NeutrinoMessages::EVT_ZAP_COMPLETE) ? current_channel_id : current_sub_channel_id)) + { + CVFD::getInstance()->showServicename(current_channel_name); // UTF-8 + g_Zapit->getPIDS( current_PIDs ); + //g_Sectionsd->setPrivatePid( current_PIDs.PIDs.privatepid ); + sectionsd_setPrivatePid( current_PIDs.PIDs.privatepid ); + //tuxtxt +#if 1 + tuxtxt_stop(); + if(g_settings.cacheTXT) { + printf("TuxTXT pid: %X\n", current_PIDs.PIDs.vtxtpid); + if(current_PIDs.PIDs.vtxtpid != 0) + tuxtxt_start(current_PIDs.PIDs.vtxtpid); + } +#endif + t_channel_id * p = new t_channel_id; + *p = current_channel_id; + g_RCInput->postMsg(NeutrinoMessages::EVT_ZAP_GOTPIDS, (const neutrino_msg_data_t)p, false); // data is pointer to allocated memory + + processAPIDnames(); + } + return messages_return::handled; + } + else if (msg == NeutrinoMessages::EVT_ZAP_ISNVOD) + { + if ((*(t_channel_id *)data) == current_channel_id) + { + needs_nvods = true; + CVFD::getInstance()->showServicename(std::string("[") + current_channel_name + ']'); // UTF-8 + if ( current_EPGid != 0) + { + getNVODs(); + if (subChannels.empty()) + g_Sectionsd->setServiceChanged( current_channel_id&0xFFFFFFFFFFFFULL, true ); + } + else + // EVENT anfordern! + g_Sectionsd->setServiceChanged( current_channel_id&0xFFFFFFFFFFFFULL, true ); + + } + return messages_return::handled; + } + else if ( ( msg == NeutrinoMessages::EVT_TIMER ) && ( data == current_programm_timer ) ) + { + //printf("new program !\n"); + + t_channel_id * p = new t_channel_id; + *p = current_channel_id; + g_RCInput->postMsg(NeutrinoMessages::EVT_NEXTPROGRAM, (const neutrino_msg_data_t)p, false); // data is pointer to allocated memory + + return messages_return::handled; + } + //else if (msg == NeutrinoMessages::EVT_ZAP_FAILED || msg == NeutrinoMessages::EVT_ZAP_SUB_FAILED) + //return messages_return::handled; + else + return messages_return::unhandled; +} + +void CRemoteControl::getSubChannels() +{ +//printf("[neutrino] getSubChannels, current_EPGid %llx\n", current_EPGid); + if ( subChannels.size() == 0 ) + { + CSectionsdClient::LinkageDescriptorList linkedServices; + //if ( g_Sectionsd->getLinkageDescriptorsUniqueKey( current_EPGid, linkedServices ) ) + if ( sectionsd_getLinkageDescriptorsUniqueKey( current_EPGid, linkedServices ) ) + { + if ( linkedServices.size()> 1 ) + { + are_subchannels = true; +//printf("CRemoteControl::getSubChannels linkedServices.size %d\n", linkedServices.size()); + for (unsigned int i=0; i< linkedServices.size(); i++) + { +//printf("CRemoteControl::getSubChannels %s\n", linkedServices[i].name.c_str()); + subChannels.push_back(CSubService( + linkedServices[i].originalNetworkId, + linkedServices[i].serviceId, + linkedServices[i].transportStreamId, + linkedServices[i].name)); + if (subChannels[i].getChannelID() == (current_channel_id&0xFFFFFFFFFFFFULL)) + selected_subchannel = i; + } + copySubChannelsToZapit(); + + t_channel_id * p = new t_channel_id; + *p = current_channel_id; + g_RCInput->postMsg(NeutrinoMessages::EVT_ZAP_GOT_SUBSERVICES, (const neutrino_msg_data_t)p, false); // data is pointer to allocated memory + } + } + } +} + +void CRemoteControl::getNVODs() +{ +//printf("[neutrino] getNVODs, current_EPGid %llx\n", current_EPGid); + if ( subChannels.size() == 0 ) + { + CSectionsdClient::NVODTimesList NVODs; + //if ( g_Sectionsd->getNVODTimesServiceKey( current_channel_id & 0xFFFFFFFFFFFFULL, NVODs ) ) + if ( sectionsd_getNVODTimesServiceKey( current_channel_id & 0xFFFFFFFFFFFFULL, NVODs ) ) + { + are_subchannels = false; +//printf("CRemoteControl::getNVODs NVODs.size %d\n", NVODs.size()); + for (unsigned int i=0; i< NVODs.size(); i++) + { + if ( NVODs[i].zeit.dauer> 0 ) + { + CSubService newService( + NVODs[i].original_network_id, + NVODs[i].service_id, + NVODs[i].transport_stream_id, + NVODs[i].zeit.startzeit, + NVODs[i].zeit.dauer); + + CSubServiceListSorted::iterator e= subChannels.begin(); + for(; e!=subChannels.end(); ++e) + { + if ( e->startzeit > newService.startzeit ) + break; + } + subChannels.insert( e, newService ); + } + + } + + copySubChannelsToZapit(); + + t_channel_id * p = new t_channel_id; + *p = current_channel_id; + g_RCInput->postMsg(NeutrinoMessages::EVT_ZAP_GOT_SUBSERVICES, (const neutrino_msg_data_t)p, false); // data is pointer to allocated memory + + if ( selected_subchannel == -1 ) + { + // beim ersten Holen letzten NVOD-Kanal setzen! + setSubChannel( subChannels.size()- 1 ); + } + else + { + // sollte nur passieren, wenn die aktuelle Sendung vorbei ist?! + selected_subchannel = -1; + } + } + } +} + +void CRemoteControl::processAPIDnames() +{ + has_unresolved_ctags= false; + has_ac3 = false; + + for(unsigned int count=0; count< current_PIDs.APIDs.size(); count++) + { + if ( current_PIDs.APIDs[count].component_tag != 0xFF ) + { + has_unresolved_ctags= true; + } + if ( strlen( current_PIDs.APIDs[count].desc ) == 3 ) + { + // unaufgeloeste Sprache... + strcpy( current_PIDs.APIDs[count].desc, getISO639Description( current_PIDs.APIDs[count].desc ) ); + } + + if ( current_PIDs.APIDs[count].is_ac3 ) + { + strncat(current_PIDs.APIDs[count].desc, " (AC3)", 25); + has_ac3 = true; + } +//printf("Neutrino: have apid name= %s pid= %X english= %d\n", current_PIDs.APIDs[count].desc, current_PIDs.APIDs[count].pid, g_settings.audio_english); + } + + if ( has_unresolved_ctags ) + { + if ( current_EPGid != 0 ) + { + CSectionsdClient::ComponentTagList tags; + //if ( g_Sectionsd->getComponentTagsUniqueKey( current_EPGid, tags ) ) + if ( sectionsd_getComponentTagsUniqueKey( current_EPGid, tags ) ) + { + has_unresolved_ctags = false; + has_ac3 = false; + + for (unsigned int i=0; i< tags.size(); i++) + { + for (unsigned int j=0; j< current_PIDs.APIDs.size(); j++) + { + if ( current_PIDs.APIDs[j].component_tag == tags[i].componentTag ) + { + // workaround for buggy ZDF ctags / or buggy sectionsd/drivers , who knows... + if(!tags[i].component.empty()) + { + strncpy(current_PIDs.APIDs[j].desc, tags[i].component.c_str(), 25); + if (current_PIDs.APIDs[j].is_ac3) + strncat(current_PIDs.APIDs[j].desc, " (AC3)", 25); + } + current_PIDs.APIDs[j].component_tag = -1; + break; + } + } + } + + CZapitClient::APIDList::iterator e = current_PIDs.APIDs.begin(); + while ( e != current_PIDs.APIDs.end() ) + { + if ( e->is_ac3 ) + { + has_ac3 = true; + } + e++; + } + + if ( ( g_settings.audio_english == 0) && (g_settings.audio_DolbyDigital == 1)) + { + for (unsigned int j=0; j< current_PIDs.APIDs.size(); j++) + if ( current_PIDs.APIDs[j].is_ac3 ) + { + setAPID( j ); + break; + } + } + if ( current_PIDs.PIDs.selected_apid >= current_PIDs.APIDs.size() ) + { + setAPID( 0 ); + } + } + } + } + if ( (g_settings.audio_english == 1) && (current_PIDs.APIDs.size() > 1) ) + { + for (unsigned int j=0; j< current_PIDs.APIDs.size(); j++) + { + if ( strstr(current_PIDs.APIDs[j].desc, "eng") || strstr(current_PIDs.APIDs[j].desc, "Tonoption 2") || strstr(current_PIDs.APIDs[j].desc, "Eng") || strstr(current_PIDs.APIDs[j].desc, "ENG")) + { + printf("Neutrino: set apid name= %s pid= %X\n", current_PIDs.APIDs[j].desc, current_PIDs.APIDs[j].pid); + setAPID( j ); + break; + } + } + } + + t_channel_id * p = new t_channel_id; + *p = current_channel_id; + g_RCInput->postMsg(NeutrinoMessages::EVT_ZAP_GOTAPIDS, (const neutrino_msg_data_t)p, false); // data is pointer to allocated memory +} + + +void CRemoteControl::copySubChannelsToZapit(void) +{ + CZapitClient::subServiceList zapitList; + + for (CSubServiceListSorted::const_iterator e = subChannels.begin(); e != subChannels.end(); e++) + zapitList.push_back(e->getAsZapitSubService()); + + g_Zapit->setSubServices(zapitList); +} + + +void CRemoteControl::setAPID( uint32_t APID ) +{ + if ((current_PIDs.PIDs.selected_apid == APID ) || + (APID >= current_PIDs.APIDs.size())) + return; + + current_PIDs.PIDs.selected_apid = APID; + g_Zapit->setAudioChannel( APID ); +} + +static const std::string empty_string; + +const std::string & CRemoteControl::setSubChannel(const int numSub, const bool force_zap) +{ + if ((numSub < 0) || (numSub >= (int)subChannels.size())) + return empty_string; + + if ((selected_subchannel == numSub ) && (!force_zap)) + return empty_string; + + selected_subchannel = numSub; + current_sub_channel_id = subChannels[numSub].getChannelID(); + g_InfoViewer->chanready = 0; + if(scrambled_timer) { + g_RCInput->killTimer(scrambled_timer); + scrambled_timer = 0; + } + + g_Zapit->zapTo_subServiceID_NOWAIT( current_sub_channel_id ); + // Houdini: to restart reading the private EPG when switching to a new option + g_Sectionsd->setServiceChanged( current_sub_channel_id , true ); + + return subChannels[numSub].subservice_name; +} + +const std::string & CRemoteControl::subChannelUp(void) +{ + //return setSubChannel((subChannels.size() == 0) ? -1 : (int)((selected_subchannel + 1) % subChannels.size())); + // if there are any NVOD/subchannels switch these else switch audio channel (if any) + if (subChannels.size() > 0 || !g_settings.audiochannel_up_down_enable) + { + return setSubChannel((subChannels.size() == 0) ? -1 : (int)((selected_subchannel + 1) % subChannels.size())); + } + else + { + if (current_PIDs.APIDs.size() > 0) + { + setAPID((current_PIDs.PIDs.selected_apid + 1) % current_PIDs.APIDs.size()); + } + return (empty_string); + } +} + +const std::string & CRemoteControl::subChannelDown(void) +{ + //return setSubChannel((selected_subchannel <= 0) ? (subChannels.size() - 1) : (selected_subchannel - 1)); + // if there are any NVOD/subchannels switch these else switch audio channel (if any) + if (subChannels.size() > 0 || !g_settings.audiochannel_up_down_enable) + { + return setSubChannel((selected_subchannel <= 0) ? (subChannels.size() - 1) : (selected_subchannel - 1)); + } + else + { + if (current_PIDs.APIDs.size() > 0) + { + if (current_PIDs.PIDs.selected_apid <= 0) + setAPID(current_PIDs.APIDs.size() - 1); + else + setAPID((current_PIDs.PIDs.selected_apid - 1)); + } + return (empty_string); + } +} + +void stopAutoRecord(); +extern int abort_zapit; +void CRemoteControl::zapTo_ChannelID(const t_channel_id channel_id, const std::string & channame, const bool start_video) // UTF-8 +{ + current_channel_id = channel_id; + current_channel_name = channame; +//printf("zapTo_ChannelID: start_video: %d\n", start_video); + if (start_video) + startvideo(); + else + stopvideo(); + + current_sub_channel_id = 0; + current_EPGid = 0; + next_EPGid = 0; + + memset(¤t_PIDs.PIDs, 0, sizeof(current_PIDs.PIDs) ); + + current_PIDs.APIDs.clear(); + has_ac3 = false; + + subChannels.clear(); + selected_subchannel = -1; + needs_nvods = false; + director_mode = 0; + + unsigned long long now = getcurrenttime(); + if ( zap_completion_timeout < now ) + { + g_InfoViewer->chanready = 0; + if(autoshift) { + stopAutoRecord(); + CNeutrinoApp::getInstance ()->recordingstatus = 0; + } + if(scrambled_timer) { + g_RCInput->killTimer(scrambled_timer); + scrambled_timer = 0; + } + //dvbsub_pause(true); + abort_zapit = 1; + g_Zapit->zapTo_serviceID_NOWAIT(channel_id); + g_Sectionsd->setServiceChanged( current_channel_id&0xFFFFFFFFFFFFULL, false ); + abort_zapit = 0; + + zap_completion_timeout = now + 2 * (long long) 1000000; + if ( current_programm_timer != 0 ) + { + g_RCInput->killTimer( current_programm_timer ); + current_programm_timer = 0; + } + } +} + +void CRemoteControl::startvideo() +{ + if ( !is_video_started ) + { + is_video_started= true; + //g_Zapit->startPlayBack(); + g_Zapit->unlockPlayBack(); + } +} + +void CRemoteControl::stopvideo() +{ + if ( is_video_started ) + { + is_video_started= false; + //g_Zapit->stopPlayBack(); + g_Zapit->lockPlayBack(); + } +} + +void CRemoteControl::radioMode() +{ + g_Zapit->setMode( CZapitClient::MODE_RADIO ); +} + +void CRemoteControl::tvMode() +{ + g_Zapit->setMode( CZapitClient::MODE_TV ); +} diff --git a/src/daemonc/remotecontrol.h b/src/daemonc/remotecontrol.h new file mode 100644 index 000000000..192985fa8 --- /dev/null +++ b/src/daemonc/remotecontrol.h @@ -0,0 +1,121 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __remotecontrol__ +#define __remotecontrol__ + +#include /* neutrino_msg_t, neutrino_msg_data_t */ + +#include + +#include +#include + +struct st_rmsg +{ + unsigned char version; + unsigned char cmd; + unsigned char param; + unsigned short param2; + char param3[30]; +}; + +class CSubService +{ + private: + struct CZapitClient::commandAddSubServices service; + + public: + time_t startzeit; + unsigned dauer; + std::string subservice_name; + + CSubService(const t_original_network_id, const t_service_id, const t_transport_stream_id, const std::string &asubservice_name); + CSubService(const t_original_network_id, const t_service_id, const t_transport_stream_id, const time_t astartzeit, const unsigned adauer); + + t_channel_id getChannelID (void) const; + inline const struct CZapitClient::commandAddSubServices getAsZapitSubService(void) const { return service; } +}; + +typedef std::vector CSubServiceListSorted; + +class CRemoteControl +{ + unsigned int current_programm_timer; + unsigned long long zap_completion_timeout; + std::string current_channel_name; + t_channel_id current_sub_channel_id; + + void getNVODs(); + void getSubChannels(); + void copySubChannelsToZapit(void); + +public: + t_channel_id current_channel_id; + unsigned long long current_EPGid; + unsigned long long next_EPGid; + CZapitClient::responseGetPIDs current_PIDs; + + // APID - Details + bool has_ac3; + bool has_unresolved_ctags; + + // SubChannel/NVOD - Details + CSubServiceListSorted subChannels; + int selected_subchannel; + bool are_subchannels; + bool needs_nvods; + int director_mode; + + // Video / Parental-Lock + bool is_video_started; + + CRemoteControl(); + void zapTo_ChannelID(const t_channel_id channel_id, const std::string & channame, const bool start_video = true); // UTF-8 + void startvideo(); + void stopvideo(); + void queryAPIDs(); + void setAPID(uint32_t APID); + void processAPIDnames(); + const std::string & setSubChannel(const int numSub, const bool force_zap = false); + const std::string & subChannelUp(void); + const std::string & subChannelDown(void); + + void radioMode(); + void tvMode(); + + int handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t data); + inline const std::string & getCurrentChannelName(void) const { return current_channel_name; } +}; + + +#endif diff --git a/src/driver/Makefile.am b/src/driver/Makefile.am new file mode 100644 index 000000000..a76fdf683 --- /dev/null +++ b/src/driver/Makefile.am @@ -0,0 +1,42 @@ +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +SUBDIRS = pictureviewer audiodec + +INCLUDES = \ + -I$(top_srcdir)/daemons \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/libeventserver \ + -I$(top_srcdir)/lib/libnet \ + -I$(top_srcdir)/lib/libconfigfile \ + -I$(top_srcdir)/lib/libcoolstream \ + -I$(top_srcdir)/lib/connection \ + -I$(top_srcdir)/lib/libeventserver \ + @FREETYPE_CFLAGS@ \ + -I$(top_srcdir)/lib + +noinst_LIBRARIES = libneutrino_driver.a libneutrino_driver_netfile.a + +libneutrino_driver_a_SOURCES = \ + ringbuffer.c \ + encoding.cpp \ + fontrenderer.cpp \ + framebuffer.cpp \ + fb_window.cpp \ + rcinput.cpp \ + vcrcontrol.cpp \ + audioplay.cpp \ + vfd.cpp \ + stream2file.cpp \ + screen_max.cpp \ + slotbuffer.c \ + file.cpp \ + audiometadata.cpp \ + audiofile.cpp \ + shutdown_count.cpp \ + genpsi.c \ + streamts.cpp \ + rfmod.cpp + +libneutrino_driver_netfile_a_SOURCES = netfile.cpp + diff --git a/src/driver/audiodec/Makefile.am b/src/driver/audiodec/Makefile.am new file mode 100644 index 000000000..908cd01ba --- /dev/null +++ b/src/driver/audiodec/Makefile.am @@ -0,0 +1,22 @@ +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +INCLUDES = \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/libconfigfile \ + -I$(top_srcdir)/lib/libcoolstream \ + @FREETYPE_CFLAGS@ \ + @VORBISIDEC_CFLAGS@ + +noinst_LIBRARIES = libneutrino_driver_audiodec.a + +libneutrino_driver_audiodec_a_SOURCES = \ + basedec.cpp \ + cdrdec.cpp \ + mp3dec.cpp \ + oggdec.cpp \ + wavdec.cpp \ + tag.c \ + crc.c \ + vis.cpp diff --git a/src/driver/audiodec/basedec.cpp b/src/driver/audiodec/basedec.cpp new file mode 100644 index 000000000..6d2b0e0ef --- /dev/null +++ b/src/driver/audiodec/basedec.cpp @@ -0,0 +1,241 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2004 Zwen + base decoder class + Homepage: http://www.cyberphoria.org/ + + Kommentar: + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // for ShoutcastCallback() + +#include +#include +#include + +unsigned int CBaseDec::mSamplerate=0; + +void ShoutcastCallback(void *arg) +{ + CAudioPlayer::getInstance()->sc_callback(arg); +} + +CBaseDec::RetCode CBaseDec::DecoderBase(CAudiofile* const in, + const int OutputFd, State* const state, + time_t* const t, + unsigned int* const secondsToSkip) +{ + RetCode Status = OK; + + FILE* fp = fopen( in->Filename.c_str(), "r" ); + if ( fp == NULL ) + { + fprintf( stderr, "Error opening file %s for decoding.\n", + in->Filename.c_str() ); + Status = INTERNAL_ERR; + } + /* jump to first audio frame; audio_start_pos is only set for FILE_MP3 */ + else if ( in->MetaData.audio_start_pos && + fseek( fp, in->MetaData.audio_start_pos, SEEK_SET ) == -1 ) + { + fprintf( stderr, "fseek() failed.\n" ); + Status = INTERNAL_ERR; + } + + if ( Status == OK ) + { + if( in->FileType == CFile::STREAM_AUDIO ) + { + if ( fstatus( fp, ShoutcastCallback ) < 0 ) + { + fprintf( stderr, "Error adding shoutcast callback: %s", + err_txt ); + } + if(ftype(fp, (char *) "ogg")) + { + Status = COggDec::getInstance()->Decoder( fp, OutputFd, state, + &in->MetaData, t, + secondsToSkip ); + } + else + { + Status = CMP3Dec::getInstance()->Decoder( fp, OutputFd, state, + &in->MetaData, t, + secondsToSkip ); + } + } + else if( in->FileType == CFile::FILE_MP3) + { + Status = CMP3Dec::getInstance()->Decoder( fp, OutputFd, state, + &in->MetaData, t, + secondsToSkip ); + } + else if( in->FileType == CFile::FILE_OGG ) + { + Status = COggDec::getInstance()->Decoder( fp, OutputFd, state, + &in->MetaData, t, + secondsToSkip ); + } + else if( in->FileType == CFile::FILE_WAV ) + { + Status = CWavDec::getInstance()->Decoder( fp, OutputFd, state, + &in->MetaData, t, + secondsToSkip ); + } + else if( in->FileType == CFile::FILE_CDR ) + { + Status = CCdrDec::getInstance()->Decoder( fp, OutputFd, state, + &in->MetaData, t, + secondsToSkip ); + } + else + { + fprintf( stderr, "DecoderBase: Supplied filetype is not " ); + fprintf( stderr, "supported by Audioplayer.\n" ); + Status = INTERNAL_ERR; + } + + if ( fclose( fp ) == EOF ) + { + fprintf( stderr, "Could not close file %s.\n", + in->Filename.c_str() ); + } + } + + return Status; +} + +bool CBaseDec::GetMetaDataBase(CAudiofile* const in, const bool nice) +{ + bool Status = true; + + if ( in->FileType == CFile::FILE_MP3 || in->FileType == CFile::FILE_OGG || + in->FileType == CFile::FILE_WAV || in->FileType == CFile::FILE_CDR ) + { + FILE* fp = fopen( in->Filename.c_str(), "r" ); + if ( fp == NULL ) + { + fprintf( stderr, "Error opening file %s for meta data reading.\n", + in->Filename.c_str() ); + Status = false; + } + else + { + if(in->FileType == CFile::FILE_MP3) + { + Status = CMP3Dec::getInstance()->GetMetaData(fp, nice, + &in->MetaData); + } + else if(in->FileType == CFile::FILE_OGG) + { + Status = COggDec::getInstance()->GetMetaData(fp, nice, + &in->MetaData); + } + else if(in->FileType == CFile::FILE_WAV) + { + Status = CWavDec::getInstance()->GetMetaData(fp, nice, + &in->MetaData); + } + else if(in->FileType == CFile::FILE_CDR) + { + Status = CCdrDec::getInstance()->GetMetaData(fp, nice, + &in->MetaData); + } + + if ( fclose( fp ) == EOF ) + { + fprintf( stderr, "Could not close file %s.\n", + in->Filename.c_str() ); + } + } + } + else + { + fprintf( stderr, "GetMetaDataBase: Filetype is not supported for " ); + fprintf( stderr, "meta data reading.\n" ); + Status = false; + } + + return Status; +} + +bool CBaseDec::SetDSP(int soundfd, int fmt, unsigned int dsp_speed, unsigned int channels) +{ + bool crit_error=false; + + if (::ioctl(soundfd, SNDCTL_DSP_RESET)) + printf("reset failed\n"); + if(::ioctl(soundfd, SNDCTL_DSP_SETFMT, &fmt)) + printf("setfmt failed\n"); + if(::ioctl(soundfd, SNDCTL_DSP_CHANNELS, &channels)) + printf("channel set failed\n"); + if (dsp_speed != mSamplerate) + { + // mute audio to reduce pops when changing samplerate (avia_reset) + //bool was_muted = avs_mute(true); + if (::ioctl(soundfd, SNDCTL_DSP_SPEED, &dsp_speed)) + { + printf("speed set failed\n"); + crit_error=true; + } + else + { +#if 0 + unsigned int rs = 0; + ::ioctl(soundfd, SNDCTL_DSP_SPEED, &rs); + mSamplerate = dsp_speed; + // disable iec aka digi out (avia reset enables it again) + //g_Zapit->IecOff(); +#endif + } + //usleep(400000); + //if (!was_muted) + // avs_mute(false); + } +//printf("Debug: SNDCTL_DSP_RESET %d / SNDCTL_DSP_SPEED %d / SNDCTL_DSP_CHANNELS %d / SNDCTL_DSP_SETFMT %d\n", +// SNDCTL_DSP_RESET, SNDCTL_DSP_SPEED, SNDCTL_DSP_CHANNELS, SNDCTL_DSP_SETFMT); + return crit_error; +} + +bool CBaseDec::avs_mute(bool mute) +{ + return true; +} + +void CBaseDec::Init() +{ + mSamplerate=0; +} + diff --git a/src/driver/audiodec/basedec.h b/src/driver/audiodec/basedec.h new file mode 100644 index 000000000..5715e3e7f --- /dev/null +++ b/src/driver/audiodec/basedec.h @@ -0,0 +1,63 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2004 Zwen + + Decoder base class + Homepage: http://www.dbox2.info/ + + Kommentar: + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __BASE_DEC__ +#define __BASE_DEC__ + +#include +#include +#include + +class CBaseDec +{ +public: + enum State {STOP = 0, STOP_REQ, PLAY, PAUSE, FF, REV}; + enum RetCode { OK = 0, READ_ERR, WRITE_ERR, DSPSET_ERR, DATA_ERR, INTERNAL_ERR }; + + // the follwing two methods have to be implemented for new decoders + //@param secondsToSkip: a value of 0 indicates that normal FF/REV operation was requested + // a value > 0 indicates that *one* jump forwards (FF) or backwards (REV) was requested + virtual RetCode Decoder(FILE *, const int, State* const, CAudioMetaData*, time_t* const, unsigned int* const)=0; + virtual bool GetMetaData(FILE *in, const bool nice, CAudioMetaData* m)=0; + + static RetCode DecoderBase(CAudiofile* const in, const int OutputFd, + State* const state, time_t* const t, + unsigned int* const secondsToSkip); + static bool GetMetaDataBase(CAudiofile* const in, const bool nice); + static void Init(); + + CBaseDec(){}; + static bool SetDSP(int soundfd, int fmt, unsigned int dsp_speed, unsigned int channels); +private: + static bool avs_mute(bool mute); + unsigned static int mSamplerate; +}; + + +#endif + diff --git a/src/driver/audiodec/cdrdec.cpp b/src/driver/audiodec/cdrdec.cpp new file mode 100644 index 000000000..1d483d4ee --- /dev/null +++ b/src/driver/audiodec/cdrdec.cpp @@ -0,0 +1,65 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2004 thegoodguy + + Homepage: http://www.dbox2.info/ + + Kommentar: + + cdr audio decoder + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +CCdrDec* CCdrDec::getInstance() +{ + static CCdrDec* CdrDec = NULL; + if (CdrDec == NULL) + { + CdrDec = new CCdrDec(); + } + return CdrDec; +} + +bool CCdrDec::SetMetaData(FILE* in, CAudioMetaData* m) +{ + header_size = 0; + + fseek(in, 0, SEEK_END); + int filesize = ftell(in); + + m->type = CAudioMetaData::CDR; + m->bitrate = 44100 * 2 * 2 * 8; + m->samplerate = 44100; + mBitsPerSample = 16; + mChannels = 2; + m->total_time = filesize / (44100 * 2 * 2); + m->type_info = "CDR / 2 channels / 16 bit"; + m->changed=true; + return true; +} + + diff --git a/src/driver/audiodec/cdrdec.h b/src/driver/audiodec/cdrdec.h new file mode 100644 index 000000000..65217aa3e --- /dev/null +++ b/src/driver/audiodec/cdrdec.h @@ -0,0 +1,43 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2004 thegoodguy + + cdr audio decoder + Homepage: http://www.dbox2.info/ + + Kommentar: + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __CDR_DEC__ +#define __CDR_DEC__ + +#include + +class CCdrDec : public CWavDec +{ + public: + static CCdrDec* getInstance(); + protected: + virtual bool SetMetaData(FILE* in, CAudioMetaData* m); +}; + +#endif + diff --git a/src/driver/audiodec/crc.c b/src/driver/audiodec/crc.c new file mode 100644 index 000000000..8495224e9 --- /dev/null +++ b/src/driver/audiodec/crc.c @@ -0,0 +1,109 @@ +/* + * madplay - MPEG audio decoder and player + * Copyright (C) 2000-2004 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: crc.c,v 1.1 2004/08/28 14:11:58 rasc Exp $ + */ + +#ifdef INCLUDE_UNUSED_STUFF +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +//# include "global.h" + +# include "crc.h" + +/* + * It would be nice to use the code in libmad to compute all CRC-16 values, + * but unfortunately the LAME tag uses reflected CRCs whereas MPEG audio + * frames do not. Therefore we are forced to write yet another CRC routine. + */ + +static +unsigned short const crc_table[256] = { + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 +}; + +/* + * NAME: crc->compute() + * DESCRIPTION: calculate reflected CRC-16 value (polynomial 0x8005) + */ +unsigned short crc_compute(char const *data, unsigned int length, + unsigned short init) +{ + register unsigned int crc; + + for (crc = init; length >= 8; length -= 8) { + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + } + + switch (length) { + case 7: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 6: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 5: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 4: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 3: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 2: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 1: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); + case 0: break; + } + + return crc; +} +#endif /* INCLUDE_UNUSED_STUFF */ diff --git a/src/driver/audiodec/crc.h b/src/driver/audiodec/crc.h new file mode 100644 index 000000000..e882668de --- /dev/null +++ b/src/driver/audiodec/crc.h @@ -0,0 +1,29 @@ +/* + * madplay - MPEG audio decoder and player + * Copyright (C) 2000-2004 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: crc.h,v 1.1 2004/08/28 14:11:58 rasc Exp $ + */ + +#ifdef INCLUDE_UNUSED_STUFF +# ifndef __CRC_H__ +# define __CRC_H__ + +unsigned short crc_compute(char const *, unsigned int, unsigned short); + +# endif /* __CRC_H__ */ +#endif /* INCLUDE_UNUSED_STUFF */ diff --git a/src/driver/audiodec/fft.c b/src/driver/audiodec/fft.c new file mode 100644 index 000000000..ba6ace9e1 --- /dev/null +++ b/src/driver/audiodec/fft.c @@ -0,0 +1,274 @@ +/* fft.c: Iterative implementation of a FFT + * Copyright (C) 1999 Richard Boulton + * Convolution stuff by Ralph Loader + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * TODO + * Remove compiling in of FFT_BUFFER_SIZE? (Might slow things down, but would + * be nice to be able to change size at runtime.) + * Finish making / checking thread-safety. + * More optimisations. + */ + +#include "fft.h" + +#include +#include +#ifndef PI + #ifdef M_PI + #define PI M_PI + #else + #define PI 3.14159265358979323846 /* pi */ + #endif +#endif + +/* ########### */ +/* # Structs # */ +/* ########### */ + +struct _struct_fft_state { + /* Temporary data stores to perform FFT in. */ + float real[FFT_BUFFER_SIZE]; + float imag[FFT_BUFFER_SIZE]; +}; + +/* ############################# */ +/* # Local function prototypes # */ +/* ############################# */ + +static void fft_prepare(const sound_sample *input, float * re, float * im); +static void fft_calculate(float * re, float * im); +static void fft_output(const float *re, const float *im, float *output); +static int reverseBits(unsigned int initial); + +/* #################### */ +/* # Global variables # */ +/* #################### */ + +/* Table to speed up bit reverse copy */ +static unsigned int bitReverse[FFT_BUFFER_SIZE]; + +/* The next two tables could be made to use less space in memory, since they + * overlap hugely, but hey. */ +static float sintable[FFT_BUFFER_SIZE / 2]; +static float costable[FFT_BUFFER_SIZE / 2]; + +/* ############################## */ +/* # Externally called routines # */ +/* ############################## */ + +/* --------- */ +/* FFT stuff */ +/* --------- */ + +/* + * Initialisation routine - sets up tables and space to work in. + * Returns a pointer to internal state, to be used when performing calls. + * On error, returns NULL. + * The pointer should be freed when it is finished with, by fft_close(). + */ +fft_state *fft_init(void) { + fft_state *state; + unsigned int i; + + state = (fft_state *) malloc (sizeof(fft_state)); + if(!state) return NULL; + + for(i = 0; i < FFT_BUFFER_SIZE; i++) { + bitReverse[i] = reverseBits(i); + } + for(i = 0; i < FFT_BUFFER_SIZE / 2; i++) { + float j = 2 * PI * i / FFT_BUFFER_SIZE; + costable[i] = cos(j); + sintable[i] = sin(j); + } + + return state; +} + +/* + * Do all the steps of the FFT, taking as input sound data (as described in + * sound.h) and returning the intensities of each frequency as floats in the + * range 0 to ((FFT_BUFFER_SIZE / 2) * 32768) ^ 2 + * + * FIXME - the above range assumes no frequencies present have an amplitude + * larger than that of the sample variation. But this is false: we could have + * a wave such that its maximums are always between samples, and it's just + * inside the representable range at the places samples get taken. + * Question: what _is_ the maximum value possible. Twice that value? Root + * two times that value? Hmmm. Think it depends on the frequency, too. + * + * The input array is assumed to have FFT_BUFFER_SIZE elements, + * and the output array is assumed to have (FFT_BUFFER_SIZE / 2 + 1) elements. + * state is a (non-NULL) pointer returned by fft_init. + */ +void fft_perform(const sound_sample *input, float *output, fft_state *state) { + /* Convert data from sound format to be ready for FFT */ + fft_prepare(input, state->real, state->imag); + + /* Do the actual FFT */ + fft_calculate(state->real, state->imag); + + /* Convert the FFT output into intensities */ + fft_output(state->real, state->imag, output); +} + +/* + * Free the state. + */ +void fft_close(fft_state *state) { + if(state) free(state); +} + +/* ########################### */ +/* # Locally called routines # */ +/* ########################### */ + +/* + * Prepare data to perform an FFT on + */ +static void fft_prepare(const sound_sample *input, float * re, float * im) { + unsigned int i; + float *realptr = re; + float *imagptr = im; + + /* Get input, in reverse bit order */ + for(i = 0; i < FFT_BUFFER_SIZE; i++) { + *realptr++ = input[bitReverse[i]]; + *imagptr++ = 0; + } +} + +/* + * Take result of an FFT and calculate the intensities of each frequency + * Note: only produces half as many data points as the input had. + * This is roughly a consequence of the Nyquist sampling theorm thingy. + * (FIXME - make this comment better, and helpful.) + * + * The two divisions by 4 are also a consequence of this: the contributions + * returned for each frequency are split into two parts, one at i in the + * table, and the other at FFT_BUFFER_SIZE - i, except for i = 0 and + * FFT_BUFFER_SIZE which would otherwise get float (and then 4* when squared) + * the contributions. + */ +static void fft_output(const float * re, const float * im, float *output) { + float *outputptr = output; + const float *realptr = re; + const float *imagptr = im; + float *endptr = output + FFT_BUFFER_SIZE / 2; + +#ifdef DEBUG + unsigned int i, j; +#endif + + while(outputptr <= endptr) { + *outputptr = (*realptr * *realptr) + (*imagptr * *imagptr); + outputptr++; realptr++; imagptr++; + } + /* Do divisions to keep the constant and highest frequency terms in scale + * with the other terms. */ + *output /= 4; + *endptr /= 4; + +#ifdef DEBUG + printf("Recalculated input:\n"); + for(i = 0; i < FFT_BUFFER_SIZE; i++) { + float val_real = 0; + float val_imag = 0; + for(j = 0; j < FFT_BUFFER_SIZE; j++) { + float fact_real = cos(- 2 * j * i * PI / FFT_BUFFER_SIZE); + float fact_imag = sin(- 2 * j * i * PI / FFT_BUFFER_SIZE); + val_real += fact_real * re[j] - fact_imag * im[j]; + val_imag += fact_real * im[j] + fact_imag * re[j]; + } + printf("%5d = %8f + i * %8f\n", i, + val_real / FFT_BUFFER_SIZE, + val_imag / FFT_BUFFER_SIZE); + } + printf("\n"); +#endif +} + +/* + * Actually perform the FFT + */ +static void fft_calculate(float * re, float * im) { + unsigned int i, j, k; + unsigned int exchanges; + float fact_real, fact_imag; + float tmp_real, tmp_imag; + unsigned int factfact; + + /* Set up some variables to reduce calculation in the loops */ + exchanges = 1; + factfact = FFT_BUFFER_SIZE / 2; + + /* Loop through the divide and conquer steps */ + for(i = FFT_BUFFER_SIZE_LOG; i != 0; i--) { + /* In this step, we have 2 ^ (i - 1) exchange groups, each with + * 2 ^ (FFT_BUFFER_SIZE_LOG - i) exchanges + */ + /* Loop through the exchanges in a group */ + for(j = 0; j != exchanges; j++) { + /* Work out factor for this exchange + * factor ^ (exchanges) = -1 + * So, real = cos(j * PI / exchanges), + * imag = sin(j * PI / exchanges) + */ + fact_real = costable[j * factfact]; + fact_imag = sintable[j * factfact]; + + /* Loop through all the exchange groups */ + for(k = j; k < FFT_BUFFER_SIZE; k += exchanges << 1) { + int k1 = k + exchanges; + /* newval[k] := val[k] + factor * val[k1] + * newval[k1] := val[k] - factor * val[k1] + **/ +#ifdef DEBUG + printf("%d %d %d\n", i,j,k); + printf("Exchange %d with %d\n", k, k1); + printf("Factor %9f + i * %8f\n", fact_real, fact_imag); +#endif + /* FIXME - potential scope for more optimization here? */ + tmp_real = fact_real * re[k1] - fact_imag * im[k1]; + tmp_imag = fact_real * im[k1] + fact_imag * re[k1]; + re[k1] = re[k] - tmp_real; + im[k1] = im[k] - tmp_imag; + re[k] += tmp_real; + im[k] += tmp_imag; +#ifdef DEBUG + for(k1 = 0; k1 < FFT_BUFFER_SIZE; k1++) { + printf("%5d = %8f + i * %8f\n", k1, real[k1], imag[k1]); + } +#endif + } + } + exchanges <<= 1; + factfact >>= 1; + } +} + +static int reverseBits(unsigned int initial) { + unsigned int reversed = 0, loop; + for(loop = 0; loop < FFT_BUFFER_SIZE_LOG; loop++) { + reversed <<= 1; + reversed += (initial & 1); + initial >>= 1; + } + return reversed; +} diff --git a/src/driver/audiodec/fft.h b/src/driver/audiodec/fft.h new file mode 100644 index 000000000..9816ac478 --- /dev/null +++ b/src/driver/audiodec/fft.h @@ -0,0 +1,43 @@ +/* fft.h: Header for iterative implementation of a FFT + * Copyright (C) 1999 Richard Boulton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _FFT_H_ +#define _FFT_H_ + +#define FFT_BUFFER_SIZE_LOG 9 + +#define FFT_BUFFER_SIZE (1 << FFT_BUFFER_SIZE_LOG) + +/* sound sample - should be an signed 16 bit value */ +typedef short int sound_sample; + +#ifdef __cplusplus +extern "C" { +#endif + +/* FFT library */ +typedef struct _struct_fft_state fft_state; +fft_state *fft_init (void); +void fft_perform (const sound_sample *input, float *output, fft_state *state); +void fft_close (fft_state *state); + +#ifdef __cplusplus +} +#endif + +#endif /* _FFT_H_ */ diff --git a/src/driver/audiodec/int_fft.c b/src/driver/audiodec/int_fft.c new file mode 100644 index 000000000..1909606d3 --- /dev/null +++ b/src/driver/audiodec/int_fft.c @@ -0,0 +1,528 @@ +/* fix_fft.c - Fixed-point Fast Fourier Transform */ +/* + fix_fft() perform FFT or inverse FFT + window() applies a Hanning window to the (time) input + fix_loud() calculates the loudness of the signal, for + each freq point. Result is an integer array, + units are dB (values will be negative). + iscale() scale an integer value by (numer/denom). + fix_mpy() perform fixed-point multiplication. + Sinewave[1024] sinewave normalized to 32767 (= 1.0). + Loudampl[100] Amplitudes for lopudnesses from 0 to -99 dB. + Low_pass Low-pass filter, cutoff at sample_freq / 4. + + + All data are fixed-point short integers, in which + -32768 to +32768 represent -1.0 to +1.0. Integer arithmetic + is used for speed, instead of the more natural floating-point. + + For the forward FFT (time -> freq), fixed scaling is + performed to prevent arithmetic overflow, and to map a 0dB + sine/cosine wave (i.e. amplitude = 32767) to two -6dB freq + coefficients; the one in the lower half is reported as 0dB + by fix_loud(). The return value is always 0. + + For the inverse FFT (freq -> time), fixed scaling cannot be + done, as two 0dB coefficients would sum to a peak amplitude of + 64K, overflowing the 32k range of the fixed-point integers. + Thus, the fix_fft() routine performs variable scaling, and + returns a value which is the number of bits LEFT by which + the output must be shifted to get the actual amplitude + (i.e. if fix_fft() returns 3, each value of fr[] and fi[] + must be multiplied by 8 (2**3) for proper scaling. + Clearly, this cannot be done within the fixed-point short + integers. In practice, if the result is to be used as a + filter, the scale_shift can usually be ignored, as the + result will be approximately correctly normalized as is. + + + TURBO C, any memory model; uses inline assembly for speed + and for carefully-scaled arithmetic. + + Written by: Tom Roberts 11/8/89 + Made portable: Malcolm Slaney 12/15/94 malcolm@interval.com + + Timing on a Macintosh PowerBook 180.... (using Symantec C6.0) + fix_fft (1024 points) 8 ticks + fft (1024 points - Using SANE) 112 Ticks + fft (1024 points - Using FPU) 11 + +*/ + +/* FIX_MPY() - fixed-point multiplication macro. + This macro is a statement, not an expression (uses asm). + BEWARE: make sure _DX is not clobbered by evaluating (A) or DEST. + args are all of type fixed. + Scaling ensures that 32767*32767 = 32767. */ +#define dosFIX_MPY(DEST,A,B) { \ + _DX = (B); \ + _AX = (A); \ + asm imul dx; \ + asm add ax,ax; \ + asm adc dx,dx; \ + DEST = _DX; } + +#define FIX_MPY(DEST,A,B) DEST = ((long)(A) * (long)(B))>>15 + +#define N_WAVE 1024 /* dimension of Sinewave[] */ +#define LOG2_N_WAVE 10 /* log2(N_WAVE) */ +#define N_LOUD 100 /* dimension of Loudampl[] */ +#ifndef fixed +#define fixed short +#endif + +extern fixed Sinewave[N_WAVE]; /* placed at end of this file for clarity */ +extern fixed Loudampl[N_LOUD]; +int db_from_ampl(fixed re, fixed im); +fixed fix_mpy(fixed a, fixed b); + +/* + fix_fft() - perform fast Fourier transform. + + if n>0 FFT is done, if n<0 inverse FFT is done + fr[n],fi[n] are real,imaginary arrays, INPUT AND RESULT. + size of data = 2**m + set inverse to 0=dft, 1=idft +*/ +int fix_fft(fixed fr[], fixed fi[], int m, int inverse) +{ + int mr,nn,i,j,l,k,istep, n, scale, shift; + fixed qr,qi,tr,ti,wr,wi; + + n = 1< N_WAVE) + return -1; + + mr = 0; + nn = n - 1; + scale = 0; + + /* decimation in time - re-order data */ + for(m=1; m<=nn; ++m) { + l = n; + do { + l >>= 1; + } while(mr+l > nn); + mr = (mr & (l-1)) + l; + + if(mr <= m) continue; + tr = fr[m]; + fr[m] = fr[mr]; + fr[mr] = tr; + ti = fi[m]; + fi[m] = fi[mr]; + fi[mr] = ti; + } + + l = 1; + k = LOG2_N_WAVE-1; + while(l < n) { + if(inverse) { + /* variable scaling, depending upon data */ + shift = 0; + for(i=0; i 16383 || m > 16383) { + shift = 1; + break; + } + } + if(shift) + ++scale; + } else { + /* fixed scaling, for proper normalization - + there will be log2(n) passes, so this + results in an overall factor of 1/n, + distributed to maximize arithmetic accuracy. */ + shift = 1; + } + /* it may not be obvious, but the shift will be performed + on each data point exactly once, during this pass. */ + istep = l << 1; + for(m=0; m>= 1; + wi >>= 1; + } + for(i=m; i>= 1; + qi >>= 1; + } + fr[j] = qr - tr; + fi[j] = qi - ti; + fr[i] = qr + tr; + fi[i] = qi + ti; + } + } + --k; + l = istep; + } + + return scale; +} + + +/* window() - apply a Hanning window */ +void window(fixed fr[], int n) +{ + int i,j,k; + + j = N_WAVE/n; + n >>= 1; + for(i=0,k=N_WAVE/4; i>1)); + n <<= 1; + for(k-=j; i>1)); +} + +/* fix_loud() - compute loudness of freq-spectrum components. + n should be ntot/2, where ntot was passed to fix_fft(); + 6 dB is added to account for the omitted alias components. + scale_shift should be the result of fix_fft(), if the time-series + was obtained from an inverse FFT, 0 otherwise. + loud[] is the loudness, in dB wrt 32767; will be +10 to -N_LOUD. +*/ +void fix_loud(fixed loud[], fixed fr[], fixed fi[], int n, int scale_shift) +{ + int i, max; + + max = 0; + if(scale_shift > 0) + max = 10; + scale_shift = (scale_shift+1) * 6; + + for(i=0; i max) + loud[i] = max; + } +} + +/* db_from_ampl() - find loudness (in dB) from + the complex amplitude. +*/ +int db_from_ampl(fixed re, fixed im) +{ + static long loud2[N_LOUD] = {0}; + long v; + int i; + + if(loud2[0] == 0) { + loud2[0] = (long)Loudampl[0] * (long)Loudampl[0]; + for(i=1; i>4; + off &= 0x000F; + pa = MK_FP(seg,off); + */ + sum = 0L; + while(n--) { + a = *pa++; + b = *pb++; + FIX_MPY(a,a,b); + sum += a; + } + + if(sum > 0x7FFF) + sum = 0x7FFF; + else if(sum < -0x7FFF) + sum = -0x7FFF; + + return (fixed)sum; +#ifdef DOS + /* ASSUMES hpa is already normalized so FP_OFF(hpa) < 16 */ + asm push ds + asm lds si,hpa + asm les di,pb + asm xor bx,bx + + asm xor cx,cx + +loop: /* intermediate values can overflow by a factor of 2 without + causing an error; the final value must not overflow! */ + asm lodsw +. + asm imul word ptr es:[di] + asm add bx,ax + asm adc cx,dx + asm jo overflow + asm add di,2 + asm dec word ptr n + asm jg loop + + asm add bx,bx + asm adc cx,cx + asm jo overflow + + asm pop ds + return _CX; + +overflow: + asm mov cx,7FFFH + asm adc cx,0 + + asm pop ds + return _CX; +#endif + +} + + +#if N_WAVE != 1024 + ERROR: N_WAVE != 1024 +#endif +fixed Sinewave[1024] = { + 0, 201, 402, 603, 804, 1005, 1206, 1406, + 1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011, + 3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608, + 4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195, + 6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766, + 7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319, + 9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849, + 11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353, + 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827, + 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268, + 15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672, + 16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036, + 18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357, + 19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631, + 20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855, + 22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027, + 23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143, + 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201, + 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198, + 26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132, + 27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001, + 28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802, + 28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534, + 29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195, + 30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783, + 30851, 30918, 30984, 31049, + 31113, 31175, 31236, 31297, + 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735, + 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097, + 32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382, + 32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588, + 32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717, + 32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766, + 32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736, + 32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628, + 32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441, + 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176, + 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833, + 31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413, + 31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918, + 30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349, + 30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706, + 29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992, + 28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208, + 28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355, + 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437, + 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456, + 25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413, + 24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311, + 23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153, + 22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942, + 20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680, + 19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371, + 18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017, + 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623, + 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191, + 14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724, + 12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227, + 11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703, + 9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156, + 7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589, + 6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006, + 4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411, + 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808, + 1607, 1406, 1206, 1005, 804, 603, 402, 201, + 0, -201, -402, -603, -804, -1005, -1206, -1406, + -1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011, + -3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608, + -4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195, + -6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766, + -7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319, + -9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849, + -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353, + -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, + -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268, + -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672, + -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036, + -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357, + -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631, + -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855, + -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027, + -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143, + -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201, + -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198, + -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132, + -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001, + -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802, + -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534, + -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195, + -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783, + -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297, + -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, + -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097, + -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382, + -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588, + -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717, + -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766, + -32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736, + -32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628, + -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441, + -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176, + -32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833, + -31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413, + -31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918, + -30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349, + -30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706, + -29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992, + -28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208, + -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355, + -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, + -26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456, + -25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413, + -24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311, + -23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153, + -22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942, + -20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680, + -19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371, + -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017, + -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623, + -15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191, + -14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724, + -12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227, + -11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703, + -9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156, + -7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589, + -6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006, + -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411, + -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808, + -1607, -1406, -1206, -1005, -804, -603, -402, -201, +}; + +#if N_LOUD != 100 + ERROR: N_LOUD != 100 +#endif +fixed Loudampl[100] = { + 32767, 29203, 26027, 23197, 20674, 18426, 16422, 14636, + 13044, 11626, 10361, 9234, 8230, 7335, 6537, 5826, + 5193, 4628, 4125, 3676, 3276, 2920, 2602, 2319, + 2067, 1842, 1642, 1463, 1304, 1162, 1036, 923, + 823, 733, 653, 582, 519, 462, 412, 367, + 327, 292, 260, 231, 206, 184, 164, 146, + 130, 116, 103, 92, 82, 73, 65, 58, + 51, 46, 41, 36, 32, 29, 26, 23, + 20, 18, 16, 14, 13, 11, 10, 9, + 8, 7, 6, 5, 5, 4, 4, 3, + 3, 2, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +}; + +#ifdef MAIN + +#include +#include + +#define M 4 +#define N (1< + (C) 2002,2003,2004 Zwen + + libmad MP3 low-level core + Homepage: http://www.cyberphoria.org/ + + Kommentar: + + based on + ************************************ + *** madlld -- Mad low-level *** v 1.0p1, 2002-01-08 + *** demonstration/decoder *** (c) 2001, 2002 Bertrand Petit + ************************************ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +/**************************************************************************** + * Includes * + ****************************************************************************/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +extern cAudio * audioDecoder; + +//#define SPECTRUM + +#ifdef SPECTRUM +void sanalyzer_render_freq(short data[1024]); +#endif +/* libid3tag extension: This is neccessary in order to call fclose + on the file. Normally libid3tag closes the file implicit. + For the netfile extension to work properly netfiles fclose must be called. + To close an id3 file (usually by calling id3_file_close) without fclosing it, + call following i3_finish_file function. It's just a copy of libid3tags + finish_file function. */ +extern "C" +{ +void id3_tag_addref(struct id3_tag *); +void id3_tag_delref(struct id3_tag *); +struct filetag { + struct id3_tag *tag; + unsigned long location; + id3_length_t length; +}; +struct id3_file { + FILE *iofile; + enum id3_file_mode mode; + char *path; + int flags; + struct id3_tag *primary; + unsigned int ntags; + struct filetag *tags; +}; +void id3_finish_file(struct id3_file* file); +} + +// Frames to skip in ff/rev mode +#define FRAMES_TO_SKIP 50 // 75 +// nr of frames to play after skipping in rev/ff mode +#define FRAMES_TO_PLAY 5 + +#define ProgName "CMP3Dec" + +/**************************************************************************** + * Global variables. * + ****************************************************************************/ + +/**************************************************************************** + * Return an error string associated with a mad error code. * + ****************************************************************************/ +/* Mad version 0.14.2b introduced the mad_stream_errorstr() function. + * For previous library versions a replacement is provided below. + */ +#if (MAD_VERSION_MAJOR>=1) || \ + ((MAD_VERSION_MAJOR==0) && \ + (((MAD_VERSION_MINOR==14) && \ + (MAD_VERSION_PATCH>=2)) || \ + (MAD_VERSION_MINOR>14))) +#define MadErrorString(x) mad_stream_errorstr(x) +#else +const char *CMP3Dec::MadErrorString(const struct mad_stream *Stream) +{ + switch(Stream->error) + { + /* Generic unrecoverable errors. */ + case MAD_ERROR_BUFLEN: + return("input buffer too small (or EOF)"); + case MAD_ERROR_BUFPTR: + return("invalid (null) buffer pointer"); + case MAD_ERROR_NOMEM: + return("not enough memory"); + + /* Frame header related unrecoverable errors. */ + case MAD_ERROR_LOSTSYNC: + return("lost synchronization"); + case MAD_ERROR_BADLAYER: + return("reserved header layer value"); + case MAD_ERROR_BADBITRATE: + return("forbidden bitrate value"); + case MAD_ERROR_BADSAMPLERATE: + return("reserved sample frequency value"); + case MAD_ERROR_BADEMPHASIS: + return("reserved emphasis value"); + + /* Recoverable errors */ + case MAD_ERROR_BADCRC: + return("CRC check failed"); + case MAD_ERROR_BADBITALLOC: + return("forbidden bit allocation value"); + case MAD_ERROR_BADSCALEFACTOR: + return("bad scalefactor index"); + case MAD_ERROR_BADFRAMELEN: + return("bad frame length"); + case MAD_ERROR_BADBIGVALUES: + return("bad big_values count"); + case MAD_ERROR_BADBLOCKTYPE: + return("reserved block_type"); + case MAD_ERROR_BADSCFSI: + return("bad scalefactor selection info"); + case MAD_ERROR_BADDATAPTR: + return("bad main_data_begin pointer"); + case MAD_ERROR_BADPART3LEN: + return("bad audio data length"); + case MAD_ERROR_BADHUFFTABLE: + return("bad Huffman table select"); + case MAD_ERROR_BADHUFFDATA: + return("Huffman data overrun"); + case MAD_ERROR_BADSTEREO: + return("incompatible block_type for JS"); + + /* Unknown error. This swich may be out of sync with libmad's + * defined error codes. + */ + default: + return("Unknown error code"); + } +} +#endif + +/**************************************************************************** + * Converts a sample from mad's fixed point number format to a signed * + * short (16 bits). * + ****************************************************************************/ +#if 1 +struct audio_dither { + mad_fixed_t error[3]; + mad_fixed_t random; +}; +static struct audio_dither left_dither, right_dither; +static inline +unsigned long prng(unsigned long state) +{ + return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; +} + +inline signed short CMP3Dec::MadFixedToSShort(const mad_fixed_t Fixed, bool left) +{ + unsigned int scalebits; + mad_fixed_t output, mask, random; + struct audio_dither *dither = left ? &left_dither : &right_dither; + unsigned int bits = 16; + mad_fixed_t sample = Fixed; + + enum { + MIN = -MAD_F_ONE, + MAX = MAD_F_ONE - 1 + }; + + /* noise shape */ + sample += dither->error[0] - dither->error[1] + dither->error[2]; + + dither->error[2] = dither->error[1]; + dither->error[1] = dither->error[0] / 2; + + /* bias */ + output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1)); + + scalebits = MAD_F_FRACBITS + 1 - bits; + mask = (1L << scalebits) - 1; + + /* dither */ + random = prng(dither->random); + output += (random & mask) - (dither->random & mask); + + dither->random = random; + + /* clip */ +#if 0 + if (output >= MAD_F_ONE) + output = 32767; + else if (output < -MAD_F_ONE) + output = -32768; +#endif + + if (output > MAX) + output = MAX; + else if (output < MIN) + output = MIN; + + /* quantize */ + output &= ~mask; + + /* error feedback */ + dither->error[0] = sample - output; + + /* scale */ + return (signed short) (output >> scalebits); +} +#else + +inline signed short CMP3Dec::MadFixedToSShort(const mad_fixed_t Fixed) +{ + /* A fixed point number is formed of the following bit pattern: + * + * SWWWFFFFFFFFFFFFFFFFFFFFFFFFFFFF + * MSB LSB + * S ==> Sign (0 is positive, 1 is negative) + * W ==> Whole part bits + * F ==> Fractional part bits + * + * This pattern contains MAD_F_FRACBITS fractional bits, one + * should alway use this macro when working on the bits of a fixed + * point number. It is not guaranteed to be constant over the + * different platforms supported by libmad. + * + * The unsigned short value is formed by the least significant + * whole part bit, followed by the 15 most significant fractional + * part bits. Warning: this is a quick and dirty way to compute + * the 16-bit number, madplay includes much better algorithms. + */ + if (Fixed >= MAD_F_ONE) + return 32767; + else if (Fixed < -MAD_F_ONE) + return -32768; + + return (signed short)(Fixed >> (MAD_F_FRACBITS + 1 - 16)); +} +#endif +/**************************************************************************** + * Print human readable informations about an audio MPEG frame. * + ****************************************************************************/ +void CMP3Dec::CreateInfo(CAudioMetaData* m, int FrameNumber) +{ + if ( !m ) + return; + + if ( !m->hasInfoOrXingTag ) + { + m->total_time = m->avg_bitrate != 0 ? + static_cast( round( static_cast( m->filesize ) + / m->avg_bitrate ) ) + : 0; + } + + if ( FrameNumber == 1 ) + { + using namespace std; + string Layer, Mode; + + /* Convert the layer number to it's printed representation. */ + switch(m->layer) + { + case MAD_LAYER_I: + Layer="I"; + break; + case MAD_LAYER_II: + Layer="II"; + break; + case MAD_LAYER_III: + Layer="III"; + break; + default: + Layer="?"; + break; + } + + /* Convert the audio mode to it's printed representation. */ + switch(m->mode) + { + case MAD_MODE_SINGLE_CHANNEL: + Mode="single channel"; + break; + case MAD_MODE_DUAL_CHANNEL: + Mode="dual channel"; + break; + case MAD_MODE_JOINT_STEREO: + Mode="joint stereo"; + break; + case MAD_MODE_STEREO: + Mode="normal stereo"; + break; + default: + Mode="unkn. mode"; + break; + } + +#ifdef INCLUDE_UNUSED_STUFF + const char *Emphasis, *Vbr; + + /* Convert the emphasis to it's printed representation. */ + switch(m->emphasis) + { + case MAD_EMPHASIS_NONE: + Emphasis="no"; + break; + case MAD_EMPHASIS_50_15_US: + Emphasis="50/15 us"; + break; + case MAD_EMPHASIS_CCITT_J_17: + Emphasis="CCITT J.17"; + break; + default: + Emphasis="(unexpected emphasis value)"; + break; + } + + if(m->vbr) + Vbr="VBR "; + else + Vbr=""; +#endif /* INCLUDE_UNUSED_STUFF */ + + m->type_info = string("MPEG Layer ") + Layer + string(" / ") + Mode; + } + + m->changed = true; +} + +/**************************************************************************** + * Main decoding loop. This is where mad is used. * + ****************************************************************************/ +#define INPUT_BUFFER_SIZE (2*8192) //(5*8192) /* enough to skip big id3 tags */ +#define OUTPUT_BUFFER_SIZE 8192 +#define SPECTRUM_CNT 4 +CBaseDec::RetCode CMP3Dec::Decoder(FILE *InputFp, const int OutputFd, + State* const state, + CAudioMetaData* meta_data, + time_t* const time_played, + unsigned int* const secondsToSkip) +{ + struct mad_stream Stream; + struct mad_frame Frame; + struct mad_synth Synth; + mad_timer_t Timer; + unsigned char InputBuffer[INPUT_BUFFER_SIZE], + OutputBuffer[OUTPUT_BUFFER_SIZE], + *OutputPtr=OutputBuffer; + const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE; + RetCode Status=OK; + int ret; + unsigned long FrameCount=0; + +#ifdef SPECTRUM + bool update_lcd = false; + int i = 0, j = 0; + signed short data[1024]; + if(g_settings.spectrum) + CVFD::getInstance ()->Lock (); + int scnt = 0; +#endif + signed short ll, rr; + + /* First the structures used by libmad must be initialized. */ + mad_stream_init(&Stream); + mad_frame_init(&Frame); + mad_synth_init(&Synth); + mad_timer_reset(&Timer); + + // used as kind of mutex for single jumps in the file + // to make sure the amount of frames is calculated + // before jumping (without this state/secondsToSkip could change + // anytime within the loop) + bool jumpDone=false; + + /* Decoding options can here be set in the options field of the + * Stream structure. + */ + + /* This is the decoding loop. */ + do + { + int secondsToJump = *secondsToSkip; + if(*state==PAUSE) + { + // in pause mode do nothing + usleep(100000); + continue; + } + /* The input bucket must be filled if it becomes empty or if + * it's the first execution of the loop. + */ + if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN) + { + size_t ReadSize, + Remaining; + unsigned char *ReadStart; + + /* {1} libmad may not consume all bytes of the input + * buffer. If the last frame in the buffer is not wholly + * contained by it, then that frame's start is pointed by + * the next_frame member of the Stream structure. This + * common situation occurs when mad_frame_decode() fails, + * sets the stream error code to MAD_ERROR_BUFLEN, and + * sets the next_frame pointer to a non NULL value. (See + * also the comment marked {2} bellow.) + * + * When this occurs, the remaining unused bytes must be + * put back at the beginning of the buffer and taken in + * account before refilling the buffer. This means that + * the input buffer must be large enough to hold a whole + * frame at the highest observable bit-rate (currently 448 + * kb/s). XXX=XXX Is 2016 bytes the size of the largest + * frame? (448000*(1152/32000))/8 + */ + if(Stream.next_frame!=NULL) + { + Remaining=Stream.bufend-Stream.next_frame; + memmove(InputBuffer,Stream.next_frame,Remaining); + ReadStart=InputBuffer+Remaining; + ReadSize=INPUT_BUFFER_SIZE-Remaining; + } + else + ReadSize=INPUT_BUFFER_SIZE, + ReadStart=InputBuffer, + Remaining=0; + + /* Fill-in the buffer. If an error occurs print a message + * and leave the decoding loop. If the end of stream is + * reached we also leave the loop but the return status is + * left untouched. + */ + ReadSize=fread(ReadStart,1,ReadSize,InputFp); + if(ReadSize<=0) + { + if(ferror(InputFp)) + { + fprintf(stderr,"%s: read error on bitstream (%s)\n", + ProgName,strerror(errno)); + Status=READ_ERR; + } + if(feof(InputFp)) + fprintf(stderr,"%s: end of input stream\n",ProgName); + break; + } + + /* Pipe the new buffer content to libmad's stream decoder + * facility. */ + mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining); + Stream.error=(mad_error)0; + } + + long actFramesToSkip=FRAMES_TO_SKIP; + // Calculate the amount of frames within the custom period + if(((*state==FF) || (*state==REV)) && ((secondsToJump)!=0)) + { + jumpDone=false; + + // what is 1152? grabbed it from the documentation above {1} ;) + actFramesToSkip=secondsToJump * meta_data->samplerate/1152; + //printf("secsToSkip: %d, framesToSkip: %ld\n", secondsToJump,actFramesToSkip); + } + + /* Decode the next mpeg frame. The streams is read from the + * buffer, its constituents are break down and stored the the + * Frame structure, ready for examination/alteration or PCM + * synthesis. Decoding options are carried in the Frame + * structure from the Stream structure. + * + * Error handling: mad_frame_decode() returns a non zero value + * when an error occurs. The error condition can be checked in + * the error member of the Stream structure. A mad error is + * recoverable or fatal, the error status is checked with the + * MAD_RECOVERABLE macro. + * + * {2} When a fatal error is encountered all decoding + * activities shall be stopped, except when a MAD_ERROR_BUFLEN + * is signaled. This condition means that the + * mad_frame_decode() function needs more input to achieve + * it's work. One shall refill the buffer and repeat the + * mad_frame_decode() call. Some bytes may be left unused at + * the end of the buffer if those bytes forms an incomplete + * frame. Before refilling, the remainign bytes must be moved + * to the begining of the buffer and used for input for the +q * next mad_frame_decode() invocation. (See the comments marked + * {1} earlier for more details.) + * + * Recoverable errors are caused by malformed bit-streams, in + * this case one can call again mad_frame_decode() in order to + * skip the faulty part and re-sync to the next frame. + */ + // decode 'FRAMES_TO_PLAY' frames each 'FRAMES_TO_SKIP' frames in ff/rev mode + if( (*state!=FF && + *state!=REV) || + FrameCount % actFramesToSkip < FRAMES_TO_PLAY ) + ret=mad_frame_decode(&Frame,&Stream); + else if(*state==FF) // in FF mode just decode the header, this sets bufferptr to next frame and also gives stats about the frame for totals + if (secondsToJump != 0 && !jumpDone) + { + jumpDone=true; + // jump forwards + long bytesForward = (Stream.bufend - Stream.this_frame) + ((ftell(InputFp)+Stream.this_frame-Stream.bufend) / FrameCount)*(actFramesToSkip + FRAMES_TO_PLAY); + //printf("jump forwards by %d secs and %ld bytes",secondsToJump, bytesForward); + + if (fseek(InputFp, bytesForward, SEEK_CUR)!=0) + { + // Reached end, do nothing + } + else + { + // Calculate timer + mad_timer_t m; + mad_timer_set(&m, 0, 32 * MAD_NSBSAMPLES(&Frame.header) *(actFramesToSkip + FRAMES_TO_PLAY), Frame.header.samplerate); + Timer.seconds += m.seconds; + if((Timer.fraction + m.fraction)*MAD_TIMER_RESOLUTION>=1) + { + Timer.seconds++; + Timer.fraction-= m.fraction; + } + else + Timer.fraction+= m.fraction; + // in case we calculated wrong... + if(Timer.seconds < 0) + { + Timer.seconds=0; + Timer.fraction=0; + } + *time_played=Timer.seconds; + FrameCount+=actFramesToSkip + FRAMES_TO_PLAY; + } + Stream.buffer=NULL; + Stream.next_frame=NULL; + // if a custom value was set we only jump once + *state=PLAY; + continue; + } else + { + ret=mad_header_decode(&Frame.header,&Stream); + } + else + { //REV + // Jump back + long bytesBack = (Stream.bufend - Stream.this_frame) + ((ftell(InputFp)+Stream.this_frame-Stream.bufend) / FrameCount)*(actFramesToSkip + FRAMES_TO_PLAY); + + if (secondsToJump!=0) + { + jumpDone=true; + //printf("jumping backwards by %d secs and %ld bytes\n",secondsToJump, bytesBack); + } + if (fseek(InputFp, -1*(bytesBack), SEEK_CUR)!=0) + { + // Reached beginning + fseek(InputFp, 0, SEEK_SET); + Timer.fraction=0; + Timer.seconds=0; + FrameCount=0; + *state=PLAY; + } + else + { + // Calculate timer + mad_timer_t m; + mad_timer_set(&m, 0, 32 * MAD_NSBSAMPLES(&Frame.header) *(actFramesToSkip + FRAMES_TO_PLAY), Frame.header.samplerate); + Timer.seconds -= m.seconds; + if(Timer.fraction < m.fraction) + { + Timer.seconds--; + Timer.fraction+= MAD_TIMER_RESOLUTION - m.fraction; + } + else + Timer.fraction-= m.fraction; + // in case we calculated wrong... + if(Timer.seconds < 0) + { + Timer.seconds=0; + Timer.fraction=0; + } + *time_played=Timer.seconds; + FrameCount-=actFramesToSkip + FRAMES_TO_PLAY; + } + Stream.buffer=NULL; + Stream.next_frame=NULL; + // if a custom value was set we only jump once + if (secondsToJump != 0) { + *state=PLAY; + } + continue; + } + + if(ret) + { + if(MAD_RECOVERABLE(Stream.error)) + { + // no errrors in FF mode + if(*state!=FF && + *state!=REV) + { + fprintf(stderr,"%s: recoverable frame level error (%s)\n", + ProgName,MadErrorString(&Stream)); + fflush(stderr); + } + continue; + } + else + if(Stream.error==MAD_ERROR_BUFLEN) + continue; + else + { + fprintf(stderr,"%s: unrecoverable frame level error (%s).\n", + ProgName,MadErrorString(&Stream)); + Status=DATA_ERR; + break; + } + } + + /* On first frame set DSP & save header info + * The first frame is representative of the entire + * stream. + */ + FrameCount++; + if (FrameCount == 1) + { +#if 0 + if (SetDSP(OutputFd, AFMT_S16_NE, Frame.header.samplerate, 2)) + { + Status=DSPSET_ERR; + break; + } +#endif + audioDecoder->PrepareClipPlay(2, Frame.header.samplerate, 16, 1); + + if ( !meta_data ) + { + meta_data = new CAudioMetaData; + } + meta_data->samplerate = Frame.header.samplerate; + meta_data->bitrate = Frame.header.bitrate; + meta_data->mode = Frame.header.mode; + meta_data->layer = Frame.header.layer; + CreateInfo( meta_data, FrameCount ); + } + else + { + if ( meta_data->bitrate != Frame.header.bitrate ) + { + /* bitrate of actual frame */ + meta_data->vbr = true; + meta_data->bitrate = Frame.header.bitrate; + + /* approximate average bitrate */ + meta_data->avg_bitrate -= + meta_data->avg_bitrate / FrameCount; + meta_data->avg_bitrate += + Frame.header.bitrate / FrameCount; + CreateInfo( meta_data, FrameCount ); + } + } + + // if played time was modified from outside, take this value... + if(*time_played!=Timer.seconds) + { + mad_timer_reset(&Timer); + Timer.seconds = *time_played; + } + + /* Accounting. The computed frame duration is in the frame + * header structure. It is expressed as a fixed point number + * whole data type is mad_timer_t. It is different from the + * samples fixed point format and unlike it, it can't directly + * be added or substracted. The timer module provides several + * functions to operate on such numbers. Be careful there, as + * some functions of mad's timer module receive some of their + * mad_timer_t arguments by value! + */ + mad_timer_add(&Timer,Frame.header.duration); + //mad_timer_string(Timer,m_timePlayed,"%lu:%02lu", + // MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0); + *time_played = Timer.seconds; + + + // decode 5 frames each 75 frames in ff mode + if( *state!=FF || FrameCount % actFramesToSkip < FRAMES_TO_PLAY) + { + + /* Once decoded the frame is synthesized to PCM samples. No errors + * are reported by mad_synth_frame(); + */ + mad_synth_frame(&Synth, &Frame); + + + /* Synthesized samples must be converted from mad's fixed + * point number to the consumer format. Here we use signed + * 16 bit native endian integers on two channels. Integer samples + * are temporarily stored in a buffer that is flushed when + * full. + */ + + if (MAD_NCHANNELS(&Frame.header) == 2) + { + mad_fixed_t * leftchannel = Synth.pcm.samples[0]; + mad_fixed_t * rightchannel = Synth.pcm.samples[1]; + + while (Synth.pcm.length-- > 0) + { + ll = MadFixedToSShort(*(leftchannel++), true); + rr = MadFixedToSShort(*(rightchannel++), false); + *((signed short *)OutputPtr) = ll; + *(((signed short *)OutputPtr) + 1) = rr; + + OutputPtr += 4; +#ifdef SPECTRUM +#define DDIFF 0 + if(g_settings.spectrum) { +#if HAVE_DBOX2 + if(scnt == SPECTRUM_CNT-2) +#endif + { + j += 4; + if((i < 512) && (j > DDIFF)) { +//if(i == 0) printf("Filling on j = %d\n", j); + int tmp = (ll+rr)/2; + data[i] = (signed short)tmp; + i++; + } + } + } +#endif + + /* Flush the buffer if it is full. */ + if (OutputPtr == OutputBufferEnd) + { + //if (write(OutputFd, OutputBuffer, OUTPUT_BUFFER_SIZE) != OUTPUT_BUFFER_SIZE) + if(audioDecoder->WriteClip(OutputBuffer, OUTPUT_BUFFER_SIZE) != OUTPUT_BUFFER_SIZE) + { + fprintf(stderr,"%s: PCM write error in stereo (%s).\n", ProgName, strerror(errno)); + Status = WRITE_ERR; + break; + } + + OutputPtr = OutputBuffer; +#ifdef SPECTRUM + if(g_settings.spectrum) { + i = 0; + j = 0; + update_lcd = true; + +//gettimeofday (&tv2, NULL); +//int ms = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000; +//if(ms)printf("Write takes %dms\n", ms); + //sanalyzer_render_vu(data); + scnt++; +#if HAVE_DBOX2 + if(scnt >= SPECTRUM_CNT) +#endif + { + scnt = 0; + sanalyzer_render_freq(data); + } + } +#endif + } + } + } + else + { + mad_fixed_t * leftchannel = Synth.pcm.samples[0]; + + while (Synth.pcm.length-- > 0) + { + /* Left channel => copy to right channel */ + + //*(((signed short *)OutputPtr) + 1) = *((signed short *)OutputPtr) = MadFixedToSShort(*(leftchannel++)); + ll = MadFixedToSShort(*(leftchannel++), false); + rr = ll; + *(((signed short *)OutputPtr) + 1) = *((signed short *)OutputPtr) = ll; + + OutputPtr += 4; +#ifdef SPECTRUM +#define DDIFF 1024 + if(g_settings.spectrum) { +#if HAVE_DBOX2 + if(scnt == SPECTRUM_CNT-2) +#endif + { + j += 4; + if((i < 512) && (j > DDIFF)) { +//if(i == 0) printf("Filling on j = %d\n", j); + int tmp = (ll+rr)/2; + data[i] = (signed short)tmp; + i++; + } + } + } +#endif + + /* Flush the buffer if it is full. */ + if (OutputPtr == OutputBufferEnd) + { + //if (write(OutputFd, OutputBuffer, OUTPUT_BUFFER_SIZE) != OUTPUT_BUFFER_SIZE) + if(audioDecoder->WriteClip(OutputBuffer, OUTPUT_BUFFER_SIZE) != OUTPUT_BUFFER_SIZE) + { + fprintf(stderr,"%s: PCM write error in mono (%s).\n", ProgName, strerror(errno)); + Status = WRITE_ERR; + break; + } + + OutputPtr = OutputBuffer; +#ifdef SPECTRUM + if(g_settings.spectrum) { + i = 0; + j = 0; + update_lcd = true; + +//gettimeofday (&tv2, NULL); +//int ms = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000; +//if(ms)printf("Write takes %dms\n", ms); +#if HAVE_DBOX2 + if(scnt >= SPECTRUM_CNT) +#endif + { + sanalyzer_render_freq(data); + } + } +#endif + } + } + } + } + + // if a custom value was set we only jump once + if ((*state==FF || *state==REV) && secondsToJump != 0 && !jumpDone) { + jumpDone=true; + *state=PLAY; + } + + }while(*state!=STOP_REQ); + + /* Mad is no longer used, the structures that were initialized must + * now be cleared. + */ + mad_synth_finish(&Synth); + mad_frame_finish(&Frame); + mad_stream_finish(&Stream); + + /* If the output buffer is not empty and no error occured during + * the last write, then flush it. + */ + if(OutputPtr!=OutputBuffer && Status!=WRITE_ERR) + { + ssize_t BufferSize=OutputPtr-OutputBuffer; + + //if(write(OutputFd, OutputBuffer, BufferSize)!=BufferSize) + if(audioDecoder->WriteClip(OutputBuffer, BufferSize) != BufferSize) + { + fprintf(stderr,"%s: PCM write error at the end (%s).\n", ProgName,strerror(errno)); + Status=WRITE_ERR; + } + } + audioDecoder->StopClip(); + CVFD::getInstance ()->Unlock (); + /* Accounting report if no error occured. */ + if(Status==OK) + { + /* The duration timer is converted to a human readable string + * with the versatile but still constrained mad_timer_string() + * function, in a fashion not unlike strftime(). The main + * difference is that the timer is break-down into several + * values according some of it's arguments. The units and + * fracunits arguments specify the intended conversion to be + * executed. + * + * The conversion unit (MAD_UNIT_MINUTES in our example) also + * specify the order and kind of conversion specifications + * that can be used in the format string. + * + * It is best to examine mad's timer.c source-code for details + * of the available units, fraction of units, their meanings, + * the format arguments, etc. + */ + // mad_timer_string(Timer,m_timePlayed,"%lu:%02lu", + // MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0); + *time_played = Timer.seconds; + +// fprintf(stderr,"%s: %lu frames decoded (%s).\n", +// ProgName,FrameCount,Buffer); + } + + /* That's the end of the world (in the H. G. Wells way). */ + return Status; +} + +CMP3Dec* CMP3Dec::getInstance() +{ + static CMP3Dec* MP3Dec = NULL; + if(MP3Dec == NULL) + { + MP3Dec = new CMP3Dec(); + } + return MP3Dec; +} + +bool CMP3Dec::GetMetaData(FILE* in, const bool nice, CAudioMetaData* const m) +{ + bool res; + if ( in && m ) + { + res = GetMP3Info(in, nice, m); + GetID3(in, m); + } + else + { + res = false; + } + + return res; +} + +/* + * Scans MP3 header for Xing, Info and Lame tag. Returns -1 on failure, + * >= 0 on success. The returned value specifies the location of the + * first audio frame. + * + * @author Christian Schlotter + * @date 2004 + * + * Based on scan_header() from Robert Leslie's "MAD Plug-in for Winamp". + */ +#define BUFFER_SIZE (5*8192) // big enough to skip id3 tags containing jpegs +long CMP3Dec::scanHeader( FILE* input, struct mad_header* const header, + struct tag* const ftag, const bool nice ) +{ + struct mad_stream stream; + struct mad_frame frame; + unsigned char buffer[BUFFER_SIZE]; + unsigned int buflen = 0; + int count = 0; + short refillCount = 4; /* buffer may be refilled refillCount times */ + long filePos = 0; /* return value */ + + mad_stream_init( &stream ); + mad_frame_init( &frame ); + + if ( ftag ) + tag_init( ftag ); + + while ( true ) + { + if ( buflen < sizeof(buffer) ) + { + if ( nice ) + usleep( 15000 ); + + filePos = ftell( input ); /* remember where reading started */ + if ( filePos == -1 ) + { + perror( "ftell()" ); + } + + /* fill buffer */ + int readbytes = fread( buffer+buflen, 1, sizeof(buffer)-buflen, + input ); + if ( readbytes <= 0 ) + { + if ( readbytes == -1 ) + filePos = -1; + break; + } + + buflen += readbytes; + } + + mad_stream_buffer( &stream, buffer, buflen ); + + while ( true ) + { + const unsigned char* const actualFrame = stream.this_frame; + if ( mad_frame_decode( &frame, &stream ) == -1 ) + { + if ( !MAD_RECOVERABLE( stream.error ) ) + break; + + /* check if id3 tag is in the way */ + long tagsize = + id3_tag_query( stream.this_frame, + stream.bufend - stream.this_frame ); + + if ( tagsize > 0 ) /* id3 tag recognized */ + { + mad_stream_skip( &stream, tagsize ); + continue; + } + else if ( mad_stream_sync( &stream ) != -1 ) /* try to sync */ + { + continue; + } + else /* syncing attempt failed */ + { + /* we have to set some limit here, otherwise we would scan + junk files completely */ + if ( refillCount-- ) + { + stream.error = MAD_ERROR_BUFLEN; + } + break; + } + } + + if ( count++ || ( ftag && tag_parse(ftag, &stream) == -1 ) ) + { + filePos += actualFrame - buffer; /* start of audio data */ + break; + } + } + + if ( count || stream.error != MAD_ERROR_BUFLEN ) + break; + + if ( refillCount-- ) + { + memmove( buffer, stream.next_frame, + buflen = &buffer[buflen] - stream.next_frame ); + } + else + { + break; + } + } + + if ( count ) + { + if ( header ) + { + *header = frame.header; + } + } + else + { + filePos = -1; + } + + mad_frame_finish( &frame ); + mad_stream_finish( &stream ); + + return filePos; +} + +/* + * Function retrieves MP3 metadata. Returns false on failure, true on success. + * + * Inspired by get_fileinfo() from Robert Leslie's "MAD Plug-in for Winamp" and + * decode_filter() from Robert Leslie's "madplay". + */ +bool CMP3Dec::GetMP3Info( FILE* input, const bool nice, + CAudioMetaData* const meta ) +{ + struct mad_header header; + struct tag ftag; + mad_header_init( &header ); + tag_init( &ftag ); + bool result = true; + + if ( ( meta->audio_start_pos = scanHeader(input, &header, &ftag, nice) ) + != -1 ) + { + meta->type = CAudioMetaData::MP3; + meta->bitrate = header.bitrate; + meta->layer = header.layer; + meta->mode = header.mode; + meta->samplerate = header.samplerate; + + if ( fseek( input, 0, SEEK_END ) ) + { + perror( "fseek()" ); + result = false; + } + /* this is still not 100% accurate, because it does not take + id3 tags at the end of the file in account */ + meta->filesize = ( ftell( input ) - meta->audio_start_pos ) * 8; + + /* valid Xing vbr tag present? */ + if ( ( ftag.flags & TAG_XING ) && + ( ftag.xing.flags & TAG_XING_FRAMES ) ) + { + meta->hasInfoOrXingTag = true; + mad_timer_t timer = header.duration; + mad_timer_multiply( &timer, ftag.xing.frames ); + + meta->total_time = mad_timer_count( timer, MAD_UNITS_SECONDS ); + } + else /* no valid Xing vbr tag present */ + { + meta->total_time = header.bitrate != 0 + ? meta->filesize / header.bitrate : 0; + } + + /* vbr file */ + if ( ftag.flags & TAG_VBR ) + { + meta->vbr = true; + meta->avg_bitrate = meta->total_time != 0 + ? static_cast( round( static_cast(meta->filesize) + / meta->total_time ) ) + : 0; + } + else /* we do not know wether the file is vbr or not */ + { + meta->vbr = false; + meta->avg_bitrate = header.bitrate; + + } + } + else /* scanning failed */ + { + result = false; + } + + if ( !result ) + { + meta->clear(); + } + + return result; +} + + +//------------------------------------------------------------------------ +void CMP3Dec::GetID3(FILE* in, CAudioMetaData* const m) +{ + unsigned int i; + struct id3_frame const *frame; + id3_ucs4_t const *ucs4; + id3_utf8_t *utf8; + char const spaces[] = " "; + + struct + { + char const *id; + char const *name; + } const info[] = + { + { ID3_FRAME_TITLE, "Title"}, + { "TIT3", 0}, /* Subtitle */ + { "TCOP", 0,}, /* Copyright */ + { "TPRO", 0,}, /* Produced */ + { "TCOM", "Composer"}, + { ID3_FRAME_ARTIST, "Artist"}, + { "TPE2", "Orchestra"}, + { "TPE3", "Conductor"}, + { "TEXT", "Lyricist"}, + { ID3_FRAME_ALBUM, "Album"}, + { ID3_FRAME_YEAR, "Year"}, + { ID3_FRAME_TRACK, "Track"}, + { "TPUB", "Publisher"}, + { ID3_FRAME_GENRE, "Genre"}, + { "TRSN", "Station"}, + { "TENC", "Encoder"} + }; + + /* text information */ + + struct id3_file *id3file = id3_file_fdopen(fileno(in), ID3_FILE_MODE_READONLY); + if(id3file == 0) + printf("error open id3 file\n"); + else + { + id3_tag *tag=id3_file_tag(id3file); + if(tag) + { + for(i = 0; i < sizeof(info) / sizeof(info[0]); ++i) + { + union id3_field const *field; + unsigned int nstrings, namelen, j; + char const *name; + + frame = id3_tag_findframe(tag, info[i].id, 0); + if(frame == 0) + continue; + + field = &frame->fields[1]; + nstrings = id3_field_getnstrings(field); + + name = info[i].name; + namelen = name ? strlen(name) : 0; + assert(namelen < sizeof(spaces)); + + for(j = 0; j < nstrings; ++j) + { + ucs4 = id3_field_getstrings(field, j); + assert(ucs4); + + if(strcmp(info[i].id, ID3_FRAME_GENRE) == 0) + ucs4 = id3_genre_name(ucs4); + + utf8 = id3_ucs4_utf8duplicate(ucs4); + if (utf8 == NULL) + goto fail; + + if (j == 0 && name) + { + if(strcmp(name,"Title") == 0) + m->title = (char *) utf8; + if(strcmp(name,"Artist") == 0) + m->artist = (char *) utf8; + if(strcmp(name,"Year") == 0) + m->date = (char *) utf8; + if(strcmp(name,"Album") == 0) + m->album = (char *) utf8; + if(strcmp(name,"Genre") == 0) + m->genre = (char *) utf8; + } + else + { + if(strcmp(info[i].id, "TCOP") == 0 || strcmp(info[i].id, "TPRO") == 0) + { + //printf("%s %s %s\n", spaces, (info[i].id[1] == 'C') ? ("Copyright (C)") : ("Produced (P)"), latin1); + } + //else + //printf("%s %s\n", spaces, latin1); + } + + free(utf8); + } + } + +#ifdef INCLUDE_UNUSED_STUFF + /* comments */ + + i = 0; + while((frame = id3_tag_findframe(tag, ID3_FRAME_COMMENT, i++))) + { + id3_utf8_t *ptr, *newline; + int first = 1; + + ucs4 = id3_field_getstring(&frame->fields[2]); + assert(ucs4); + + if(*ucs4) + continue; + + ucs4 = id3_field_getfullstring(&frame->fields[3]); + assert(ucs4); + + utf8 = id3_ucs4_utf8duplicate(ucs4); + if (utf8 == 0) + goto fail; + + ptr = utf8; + while(*ptr) + { + newline = (id3_utf8_t *) strchr((char*)ptr, '\n'); + if(newline) + *newline = 0; + + if(strlen((char *)ptr) > 66) + { + id3_utf8_t *linebreak; + + linebreak = ptr + 66; + + while(linebreak > ptr && *linebreak != ' ') + --linebreak; + + if(*linebreak == ' ') + { + if(newline) + *newline = '\n'; + + newline = linebreak; + *newline = 0; + } + } + + if(first) + { + char const *name; + unsigned int namelen; + + name = "Comment"; + namelen = strlen(name); + assert(namelen < sizeof(spaces)); + mp3->Comment = (char *) ptr; + //printf("%s%s: %s\n", &spaces[namelen], name, ptr); + first = 0; + } + else + //printf("%s %s\n", spaces, ptr); + + ptr += strlen((char *) ptr) + (newline ? 1 : 0); + } + + free(utf8); + break; + } +#endif + id3_tag_delete(tag); + } + else + printf("error open id3 tag\n"); + + id3_finish_file(id3file); + } + if(0) + { + fail: + printf("id3: not enough memory to display tag\n"); + } +} + +// this is a copy of static libid3tag function "finish_file" +// which cannot be called from outside +void id3_finish_file(struct id3_file* file) +{ + unsigned int i; + + if (file->path) + free(file->path); + + if (file->primary) { + id3_tag_delref(file->primary); + id3_tag_delete(file->primary); + } + + for (i = 0; i < file->ntags; ++i) { + struct id3_tag *tag; + + tag = file->tags[i].tag; + if (tag) { + id3_tag_delref(tag); + id3_tag_delete(tag); + } + } + + if (file->tags) + free(file->tags); + + free(file); +} + diff --git a/src/driver/audiodec/mp3dec.h b/src/driver/audiodec/mp3dec.h new file mode 100644 index 000000000..b18924a9d --- /dev/null +++ b/src/driver/audiodec/mp3dec.h @@ -0,0 +1,81 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2002 Bjoern Kalkbrenner + Copyright (C) 2002,2003 Dirch + Copyright (C) 2002,2003,2004 Zwen + + libmad MP3 low-level core + Homepage: http://www.dbox2.info/ + + Kommentar: + + based on + ************************************ + *** madlld -- Mad low-level *** v 1.0p1, 2002-01-08 + *** demonstration/decoder *** (c) 2001, 2002 Bertrand Petit + ************************************ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __MP3_DEC__ +#define __MP3_DEC__ + +#include +#include +#include +#include +#include +#include +#include +extern "C" +{ +#include "driver/audiodec/tag.h" +} + +class CMP3Dec : public CBaseDec +{ +private: +#if !((MAD_VERSION_MAJOR>=1) || \ + ((MAD_VERSION_MAJOR==0) && \ + (((MAD_VERSION_MINOR==14) && \ + (MAD_VERSION_PATCH>=2)) || \ + (MAD_VERSION_MINOR>14)))) + const char* MadErrorString(const struct mad_stream *Stream); +#endif + signed short MadFixedToSShort(const mad_fixed_t Fixed, bool left = false); + void CreateInfo(CAudioMetaData* const, const int); + bool GetMP3Info(FILE*, const bool, CAudioMetaData* const); + void GetID3(FILE*, CAudioMetaData* const); + long scanHeader( FILE*, struct mad_header* const, struct tag* const, + const bool ); + +public: + static CMP3Dec* getInstance(); + virtual RetCode Decoder(FILE *InputFp, const int OutputFd, + State* const state, CAudioMetaData* m, + time_t* const t, unsigned int* const secondsToSkip); + bool GetMetaData(FILE *in, const bool nice, CAudioMetaData* const m); + CMP3Dec(){}; + +}; + + +#endif + diff --git a/src/driver/audiodec/oggdec.cpp b/src/driver/audiodec/oggdec.cpp new file mode 100644 index 000000000..6757a7749 --- /dev/null +++ b/src/driver/audiodec/oggdec.cpp @@ -0,0 +1,348 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2004 Sania, Zwen + + Homepage: http://www.dbox2.info/ + + Kommentar: + + ogg vorbis audio decoder + uses tremor libvorbisidec + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +extern cAudio * audioDecoder; + +#define ProgName "OggDec" +// nr of msecs to skip in ff/rev mode +#define MSECS_TO_SKIP 3000 +// nr of msecs to play in ff/rev mode +#define MSECS_TO_PLAY 200 + +/* at first, define our own callback functions used in */ +/* tremor to access the data. These functions are simple mappers */ +size_t ogg_read(void *buf, size_t size, size_t nmemb, void *data) +{ + return fread(buf, size, nmemb, (FILE*)data); +} + +int ogg_seek(void *data, ogg_int64_t offset, int whence) +{ + return fseek((FILE*)data, (long)offset, whence); +} + +int ogg_close(void *data) +{ + return 0; +} + +long ogg_tell(void *data) +{ + return ftell((FILE*)data); +} + +#define PCMBUFFER 4096 //4096 max for libtremor +#define MAX_OUTPUT_SAMPLES 2048 /* AVIA_GT_PCM_MAX_SAMPLES-1 */ + +CBaseDec::RetCode COggDec::Decoder(FILE *in, const int OutputFd, State* const state, CAudioMetaData* meta_data, time_t* const time_played, unsigned int* const secondsToSkip) +{ + OggVorbis_File vf; + int bitstream, rval; + ogg_int64_t jumptime=0; + Status=OK; + mOutputFd = OutputFd; + mState = state; + mTimePlayed=time_played; + + if (!Open(in, &vf)) + { + Status=DATA_ERR; + return Status; + } + + SetMetaData(&vf, meta_data); + + audioDecoder->PrepareClipPlay(ov_info(&vf,0)->channels, ov_info(&vf,0)->rate, 16, 1); + + /* up and away ... */ + mSlotSize = MAX_OUTPUT_SAMPLES * 2 * ov_info(&vf,0)->channels; + for(int i = 0 ; i < DECODE_SLOTS ; i++) + { + if ((mPcmSlots[i] = (char*) malloc(mSlotSize)) == NULL) + { + for (int j = i - 1; j >= 0; j--) + { + free(mPcmSlots[j]); + } + Status=INTERNAL_ERR; + return Status; + } + mSlotTime[i]=0; + } + mReadSlot=mWriteSlot=0; + + pthread_t OutputThread; + if (pthread_create (&OutputThread, 0, OutputDsp, (void *) this) != 0 ) + { + for(int i = 0 ; i < DECODE_SLOTS ; i++) + free(mPcmSlots[i]); + Status=INTERNAL_ERR; + return Status; + } + + int bytes; + State oldstate=*state; + do + { + // clear buffer on state change + if(oldstate!=*state) + { + if(*state!=PAUSE && (*state!=PLAY || oldstate!=PAUSE)) + { + mWriteSlot=mReadSlot=0; + oldstate=*state; + } + } + while((mWriteSlot+1)%DECODE_SLOTS == mReadSlot) + { + usleep(10000); + } + bytes=0; + if(mSeekable) +#ifdef DBOX + mSlotTime[mWriteSlot] = ov_time_tell(&vf); +#else + mSlotTime[mWriteSlot] = (ogg_int64_t)(1000 * ov_time_tell(&vf)); +#endif + do + { +#ifdef DBOX + rval = ov_read(&vf, mPcmSlots[mWriteSlot]+bytes, mSlotSize-bytes, &bitstream); +#else + rval = ov_read(&vf, mPcmSlots[mWriteSlot]+bytes, mSlotSize-bytes, 0, 2, 1, &bitstream); +#endif + bytes+=rval; +//printf("Ogg: read buf 0x%x size %d / %d done %d\n", mPcmSlots[mWriteSlot]+bytes, rval, mSlotSize, bytes); + } while (rval > 0 && bytes !=mSlotSize); +//printf("\n"); + int actMSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip * 1000 : MSECS_TO_SKIP; + if((*state==FF || *state==REV) && mSeekable ) + { + if((std::abs((long int)( mSlotTime[mWriteSlot]-jumptime))) > MSECS_TO_PLAY) + { + if(*state==FF) + { + ov_time_seek_page(&vf, mSlotTime[mWriteSlot] + actMSecsToSkip); + jumptime=mSlotTime[mWriteSlot]+actMSecsToSkip; + } + else + { + if(mSlotTime[mWriteSlot] < actMSecsToSkip) + { + ov_time_seek(&vf, 0); + *state=PLAY; + } + else + { + ov_time_seek_page(&vf, mSlotTime[mWriteSlot] - actMSecsToSkip); + jumptime=mSlotTime[mWriteSlot]-actMSecsToSkip; + } + } + } + if (*secondsToSkip != 0) { + *state=PLAY; + } + } + if(bytes == mSlotSize) + mWriteSlot=(mWriteSlot+1) % DECODE_SLOTS; + } while (rval != 0 && *state!=STOP_REQ && Status==OK); + + //printf("COggDec::Decoder: read loop stop, rval %d state %d status %d\n", rval, *state, Status); + // let buffer run dry + while(rval==0 && *state!=STOP_REQ && Status==OK && mReadSlot != mWriteSlot) + usleep(100000); + + //pthread_cancel(OutputThread); + //printf("COggDec::Decoder: OutputThread join\n"); + Status = WRITE_ERR; + pthread_join(OutputThread, NULL); + //printf("COggDec::Decoder: OutputThread join done\n"); + audioDecoder->StopClip(); + for(int i = 0 ; i < DECODE_SLOTS ; i++) + free(mPcmSlots[i]); + + /* clean up the junk from the party */ + ov_clear(&vf); + + /* and drive home ;) */ + return Status; +} + +void* COggDec::OutputDsp(void * arg) +{ + COggDec* dec = (COggDec*) arg; + while(dec->Status == OK/*true*/) + { + while(dec->mReadSlot==dec->mWriteSlot || *dec->mState==PAUSE) + { + if(dec->Status != OK) + return NULL; + usleep(10000); + } + //if (write(dec->mOutputFd, dec->mPcmSlots[dec->mReadSlot], dec->mSlotSize) != dec->mSlotSize) + if (audioDecoder->WriteClip((unsigned char *)dec->mPcmSlots[dec->mReadSlot], dec->mSlotSize) != dec->mSlotSize) + { + fprintf(stderr,"%s: PCM write error (%s).\n", ProgName, strerror(errno)); + dec->Status=WRITE_ERR; + break; + } + *dec->mTimePlayed = (int)(dec->mSlotTime[dec->mReadSlot]/1000); + dec->mReadSlot=(dec->mReadSlot+1)%DECODE_SLOTS; + } + return NULL; +} + +bool COggDec::GetMetaData(FILE *in, const bool nice, CAudioMetaData* m) +{ + OggVorbis_File vf; + if (!Open(in, &vf)) + { + return false; + } + SetMetaData(&vf, m); + ov_clear(&vf); + return true; +} + +COggDec* COggDec::getInstance() +{ + static COggDec* OggDec = NULL; + if(OggDec == NULL) + { + OggDec = new COggDec(); + } + return OggDec; +} + +void COggDec::ParseUserComments(vorbis_comment* vc, CAudioMetaData* m) +{ + for(int i=0; i < vc->comments ; i++) + { + char* search; + if((search=strstr(vc->user_comments[i],"Artist"))!=NULL || + (search=strstr(vc->user_comments[i],"ARTIST"))!=NULL) + m->artist = search+7; + else if((search=strstr(vc->user_comments[i],"Album"))!=NULL || + (search=strstr(vc->user_comments[i],"ALBUM"))!=NULL) + m->album = search+6; + else if((search=strstr(vc->user_comments[i],"Title"))!=NULL || + (search=strstr(vc->user_comments[i],"TITLE"))!=NULL) + m->title = search+6; + else if((search=strstr(vc->user_comments[i],"Genre"))!=NULL || + (search=strstr(vc->user_comments[i],"GENRE"))!=NULL) + m->genre = search+6; + else if((search=strstr(vc->user_comments[i],"Date"))!=NULL || + (search=strstr(vc->user_comments[i],"DATE"))!=NULL) + m->date = search+5; + else if((search=strstr(vc->user_comments[i],"TrackNumber"))!=NULL || + (search=strstr(vc->user_comments[i],"TRACKNUMBER"))!=NULL) + m->track = search+12; + } +} + + +void COggDec::SetMetaData(OggVorbis_File* vf, CAudioMetaData* m) +{ + /* Set Metadata */ + m->type = CAudioMetaData::OGG; + m->bitrate = ov_info(vf,0)->bitrate_nominal; + m->samplerate = ov_info(vf,0)->rate; + if(mSeekable) +#ifdef DBOX + m->total_time = (time_t) ov_time_total(vf, 0) / 1000; +#else + m->total_time = (time_t) ov_time_total(vf, 0); +#endif + std::stringstream ss; + ss << "OGG V." << ov_info(vf,0)->version << " / " << ov_info(vf,0)->channels << "channel(s)"; + m->type_info = ss.str(); + ParseUserComments(ov_comment(vf, 0), m); + m->changed=true; +} + +bool COggDec::Open(FILE* in, OggVorbis_File* vf) +{ + int rval; + ov_callbacks cb; + /* we need to use our own functions, because we have */ + /* the netfile layer hooked in here. If we would not */ + /* provide callbacks, the tremor lib and the netfile */ + /* layer would clash and steal each other the data */ + /* from the stream ! */ + + cb.read_func = ogg_read; + cb.seek_func = ogg_seek; + cb.close_func = ogg_close; + cb.tell_func = ogg_tell; + + /* test the dope ... */ + //rval = ov_test_callbacks((void*)in, vf, NULL, 0, cb); + rval = ov_open_callbacks(in, vf, NULL, 0, cb); + + /* and tell our friends about the quality of the stuff */ + // initialize the sound device here + + if(rval<0) + { + switch(rval) + { + /* err_txt from netfile.cpp */ + case OV_EREAD: sprintf(err_txt, "media read error"); break; + case OV_ENOTVORBIS: sprintf(err_txt, "no vorbis stream"); break; + case OV_EVERSION: sprintf(err_txt, "incompatible vorbis version"); break; + case OV_EBADHEADER: sprintf(err_txt, "invalid bvorbis bitstream header"); break; + case OV_EFAULT: sprintf(err_txt, "internal logic fault (tremor)"); break; + default: sprintf(err_txt, "unknown error, code: %d", rval); + } + fprintf(stderr,"%s: %s\n", ProgName, err_txt); + return false; + } + + /* finish the opening and ignite the joint */ + //ov_test_open(vf); + + if(ov_seekable(vf)) + mSeekable = true; + else + mSeekable = false; + + return true; +} diff --git a/src/driver/audiodec/oggdec.h b/src/driver/audiodec/oggdec.h new file mode 100644 index 000000000..2860b4b7e --- /dev/null +++ b/src/driver/audiodec/oggdec.h @@ -0,0 +1,78 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2002,2003,2004 Sania,Zwen + + ogg vorbis audio decoder + Homepage: http://www.dbox2.info/ + + Kommentar: + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __OGG_DEC__ +#define __OGG_DEC__ + +//#define DBOX + +#include +#include +#include +#include +#include +#include +#include +#ifdef DBOX +#include +#include +#else +#include +#include +#endif + +#define DECODE_SLOTS 30 + +class COggDec : public CBaseDec +{ + +public: + static COggDec* getInstance(); + virtual RetCode Decoder(FILE *, const int, State* const, CAudioMetaData*, time_t* const, unsigned int* const); + bool GetMetaData(FILE *in, const bool nice, CAudioMetaData* m); + COggDec(){}; +private: + void ParseUserComments(vorbis_comment*, CAudioMetaData*); + bool Open(FILE* , OggVorbis_File*); + void SetMetaData(OggVorbis_File*, CAudioMetaData*); + RetCode Status; + char* mPcmSlots[DECODE_SLOTS]; + ogg_int64_t mSlotTime[DECODE_SLOTS]; + int mWriteSlot; + int mReadSlot; + int mSlotSize; + int mOutputFd; + State* mState; + bool mSeekable; + time_t* mTimePlayed; + static void* OutputDsp(void *); +}; + + +#endif + diff --git a/src/driver/audiodec/tag.c b/src/driver/audiodec/tag.c new file mode 100644 index 000000000..1aeefd20a --- /dev/null +++ b/src/driver/audiodec/tag.c @@ -0,0 +1,331 @@ +/* + * madplay - MPEG audio decoder and player + * Copyright (C) 2000-2004 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: tag.c,v 1.1 2004/08/28 14:11:58 rasc Exp $ + */ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +//# include "global.h" + +# include + +#ifdef INCLUDE_UNUSED_STUFF +# include +#endif /* INCLUDE_UNUSED_STUFF */ +# include + +# define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g') +# define INFO_MAGIC (('I' << 24) | ('n' << 16) | ('f' << 8) | 'o') +# define LAME_MAGIC (('L' << 24) | ('A' << 16) | ('M' << 8) | 'E') + +/* + * NAME: tag->init() + * DESCRIPTION: initialize tag structure + */ +void tag_init(struct tag *tag) +{ + tag->flags = 0; +#ifdef INCLUDE_UNUSED_STUFF + tag->encoder[0] = 0; +#endif /* INCLUDE_UNUSED_STUFF */ +} + +/* + * NAME: parse_xing() + * DESCRIPTION: parse a Xing VBR tag + */ +static +int parse_xing(struct tag_xing *xing, + struct mad_bitptr *ptr, unsigned int *bitlen) +{ + if (*bitlen < 32) + goto fail; + + xing->flags = mad_bit_read(ptr, 32); + *bitlen -= 32; + + if (xing->flags & TAG_XING_FRAMES) { + if (*bitlen < 32) + goto fail; + + xing->frames = mad_bit_read(ptr, 32); + *bitlen -= 32; + } + + if (xing->flags & TAG_XING_BYTES) { + if (*bitlen < 32) + goto fail; + + xing->bytes = mad_bit_read(ptr, 32); + *bitlen -= 32; + } + + if (xing->flags & TAG_XING_TOC) { + int i; + + if (*bitlen < 800) + goto fail; + + for (i = 0; i < 100; ++i) + xing->toc[i] = mad_bit_read(ptr, 8); + + *bitlen -= 800; + } + + if (xing->flags & TAG_XING_SCALE) { + if (*bitlen < 32) + goto fail; + + xing->scale = mad_bit_read(ptr, 32); + *bitlen -= 32; + } + + return 0; + + fail: + xing->flags = 0; + return -1; +} + +#ifdef INCLUDE_UNUSED_STUFF +/* + * NAME: tag->parse_rgain() + * DESCRIPTION: parse a 16-bit Replay Gain field + */ +void tag_parse_rgain(struct tag_rgain *rgain, struct mad_bitptr *ptr) +{ + int negative; + + rgain->name = mad_bit_read(ptr, 3); + rgain->originator = mad_bit_read(ptr, 3); + + negative = mad_bit_read(ptr, 1); + rgain->adjustment = mad_bit_read(ptr, 9); + + if (negative) + rgain->adjustment = -rgain->adjustment; +} + +/* + * NAME: parse_lame() + * DESCRIPTION: parse a LAME tag + */ +static +int parse_lame(struct tag_lame *lame, + struct mad_bitptr *ptr, unsigned int *bitlen, + unsigned short crc) +{ + struct mad_bitptr save = *ptr; + + if (*bitlen < 36 * 8) + goto fail; + + /* bytes $9A-$A4: Encoder short VersionString */ + + mad_bit_skip(ptr, 9 * 8); + + /* byte $A5: Info Tag revision + VBR method */ + + lame->revision = mad_bit_read(ptr, 4); + if (lame->revision == 15) + goto fail; + + lame->vbr_method = mad_bit_read(ptr, 4); + + /* byte $A6: Lowpass filter value (Hz) */ + + lame->lowpass_filter = mad_bit_read(ptr, 8) * 100; + + /* bytes $A7-$AA: 32 bit "Peak signal amplitude" */ + + lame->peak = mad_bit_read(ptr, 32) << 5; + + /* bytes $AB-$AC: 16 bit "Radio Replay Gain" */ + + tag_parse_rgain(&lame->replay_gain[0], ptr); + + /* bytes $AD-$AE: 16 bit "Audiophile Replay Gain" */ + + tag_parse_rgain(&lame->replay_gain[1], ptr); + + /* byte $AF: Encoding flags + ATH Type */ + + lame->flags = mad_bit_read(ptr, 4); + lame->ath_type = mad_bit_read(ptr, 4); + + /* byte $B0: if ABR {specified bitrate} else {minimal bitrate} */ + + lame->bitrate = mad_bit_read(ptr, 8); + + /* bytes $B1-$B3: Encoder delays */ + + lame->start_delay = mad_bit_read(ptr, 12); + lame->end_padding = mad_bit_read(ptr, 12); + + /* byte $B4: Misc */ + + lame->source_samplerate = mad_bit_read(ptr, 2); + + if (mad_bit_read(ptr, 1)) + lame->flags |= TAG_LAME_UNWISE; + + lame->stereo_mode = mad_bit_read(ptr, 3); + lame->noise_shaping = mad_bit_read(ptr, 2); + + /* byte $B5: MP3 Gain */ + + lame->gain = mad_bit_read(ptr, 8); + + /* bytes $B6-B7: Preset and surround info */ + + mad_bit_skip(ptr, 2); + + lame->surround = mad_bit_read(ptr, 3); + lame->preset = mad_bit_read(ptr, 11); + + /* bytes $B8-$BB: MusicLength */ + + lame->music_length = mad_bit_read(ptr, 32); + + /* bytes $BC-$BD: MusicCRC */ + + lame->music_crc = mad_bit_read(ptr, 16); + + /* bytes $BE-$BF: CRC-16 of Info Tag */ + + if (mad_bit_read(ptr, 16) != crc) + goto fail; + + *bitlen -= 36 * 8; + + return 0; + + fail: + *ptr = save; + return -1; +} +#endif /* INCLUDE_UNUSED_STUFF */ + +/* + * NAME: tag->parse() + * DESCRIPTION: parse Xing/LAME tag(s) + */ +int tag_parse(struct tag *tag, struct mad_stream const *stream) +{ + struct mad_bitptr ptr = stream->anc_ptr; + struct mad_bitptr start = ptr; + unsigned int bitlen = stream->anc_bitlen; + unsigned long magic; +#ifdef INCLUDE_UNUSED_STUFF + int i; +#endif /* INCLUDE_UNUSED_STUFF */ + + if (bitlen < 32) + return -1; + + magic = mad_bit_read(&ptr, 32); + bitlen -= 32; + + if (magic != XING_MAGIC + && magic != INFO_MAGIC + && magic != LAME_MAGIC) + { + /* + * Due to an unfortunate historical accident, a Xing VBR tag may be + * misplaced in a stream with CRC protection. We check for this by + * assuming the tag began two octets prior and the high bits of the + * following flags field are always zero. + */ + + if (magic != ((XING_MAGIC << 16) & 0xffffffffL) + && magic != ((INFO_MAGIC << 16) & 0xffffffffL)) + return -1; + + magic >>= 16; + + /* backtrack the bit pointer */ + + ptr = start; + mad_bit_skip(&ptr, 16); + bitlen += 16; + } + + if ((magic & 0x0000ffffL) == (XING_MAGIC & 0x0000ffffL)) + tag->flags |= TAG_VBR; + + /* Xing tag */ + + if (magic == LAME_MAGIC) { + ptr = start; + bitlen += 32; + } + else if (parse_xing(&tag->xing, &ptr, &bitlen) == 0) + tag->flags |= TAG_XING; + +#ifdef INCLUDE_UNUSED_STUFF + /* encoder string */ + + if (bitlen >= 20 * 8) { + start = ptr; + + for (i = 0; i < 20; ++i) { + tag->encoder[i] = mad_bit_read(&ptr, 8); + + if (tag->encoder[i] == 0) + break; + + /* keep only printable ASCII chars */ + + if (tag->encoder[i] < 0x20 || tag->encoder[i] >= 0x7f) { + tag->encoder[i] = 0; + break; + } + } + + tag->encoder[20] = 0; + ptr = start; + } + + /* LAME tag */ + + if (stream->next_frame - stream->this_frame >= 192 && + parse_lame(&tag->lame, &ptr, &bitlen, + crc_compute(stream->this_frame, 190, 0x0000)) == 0) { + tag->flags |= TAG_LAME; + tag->encoder[9] = 0; + } + else { + for (i = 0; i < 20; ++i) { + if (tag->encoder[i] == 0) + break; + + /* stop at padding chars */ + + if (tag->encoder[i] == 0x55) { + tag->encoder[i] = 0; + break; + } + } + } +#endif /* INCLUDE_UNUSED_STUFF */ + + return 0; +} diff --git a/src/driver/audiodec/tag.h b/src/driver/audiodec/tag.h new file mode 100644 index 000000000..6dc05ceea --- /dev/null +++ b/src/driver/audiodec/tag.h @@ -0,0 +1,183 @@ +/* + * madplay - MPEG audio decoder and player + * Copyright (C) 2000-2004 Robert Leslie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: tag.h,v 1.1 2004/08/28 14:11:58 rasc Exp $ + */ + +# ifndef __TAG_H__ +# define __TAG_H__ + +# include + +enum { + TAG_XING = 0x0001, + TAG_LAME = 0x0002, + TAG_VBR = 0x0100 +}; + +enum { + TAG_XING_FRAMES = 0x00000001L, + TAG_XING_BYTES = 0x00000002L, + TAG_XING_TOC = 0x00000004L, + TAG_XING_SCALE = 0x00000008L +}; + +#ifdef INCLUDE_UNUSED_STUFF +enum { + TAG_LAME_NSPSYTUNE = 0x01, + TAG_LAME_NSSAFEJOINT = 0x02, + TAG_LAME_NOGAP_NEXT = 0x04, + TAG_LAME_NOGAP_PREV = 0x08, + TAG_LAME_UNWISE = 0x10 +}; + +enum tag_lame_vbr { + TAG_LAME_VBR_CONSTANT = 1, + TAG_LAME_VBR_ABR = 2, + TAG_LAME_VBR_METHOD1 = 3, + TAG_LAME_VBR_METHOD2 = 4, + TAG_LAME_VBR_METHOD3 = 5, + TAG_LAME_VBR_METHOD4 = 6, + TAG_LAME_VBR_CONSTANT2PASS = 8, + TAG_LAME_VBR_ABR2PASS = 9 +}; + +enum tag_lame_source { + TAG_LAME_SOURCE_32LOWER = 0x00, + TAG_LAME_SOURCE_44_1 = 0x01, + TAG_LAME_SOURCE_48 = 0x02, + TAG_LAME_SOURCE_HIGHER48 = 0x03 +}; + +enum tag_lame_mode { + TAG_LAME_MODE_MONO = 0x00, + TAG_LAME_MODE_STEREO = 0x01, + TAG_LAME_MODE_DUAL = 0x02, + TAG_LAME_MODE_JOINT = 0x03, + TAG_LAME_MODE_FORCE = 0x04, + TAG_LAME_MODE_AUTO = 0x05, + TAG_LAME_MODE_INTENSITY = 0x06, + TAG_LAME_MODE_UNDEFINED = 0x07 +}; + +enum tag_lame_surround { + TAG_LAME_SURROUND_NONE = 0, + TAG_LAME_SURROUND_DPL = 1, + TAG_LAME_SURROUND_DPL2 = 2, + TAG_LAME_SURROUND_AMBISONIC = 3 +}; + +enum tag_lame_preset { + TAG_LAME_PRESET_NONE = 0, + TAG_LAME_PRESET_V9 = 410, + TAG_LAME_PRESET_V8 = 420, + TAG_LAME_PRESET_V7 = 430, + TAG_LAME_PRESET_V6 = 440, + TAG_LAME_PRESET_V5 = 450, + TAG_LAME_PRESET_V4 = 460, + TAG_LAME_PRESET_V3 = 470, + TAG_LAME_PRESET_V2 = 480, + TAG_LAME_PRESET_V1 = 490, + TAG_LAME_PRESET_V0 = 500, + TAG_LAME_PRESET_R3MIX = 1000, + TAG_LAME_PRESET_STANDARD = 1001, + TAG_LAME_PRESET_EXTREME = 1002, + TAG_LAME_PRESET_INSANE = 1003, + TAG_LAME_PRESET_STANDARD_FAST = 1004, + TAG_LAME_PRESET_EXTREME_FAST = 1005, + TAG_LAME_PRESET_MEDIUM = 1006, + TAG_LAME_PRESET_MEDIUM_FAST = 1007 +}; +#endif /* INCLUDE_UNUSED_STUFF */ + +struct tag_xing { + long flags; /* valid fields (see below) */ + unsigned long frames; /* total number of frames */ + unsigned long bytes; /* total number of bytes */ + unsigned char toc[100]; /* 100-point seek table */ + long scale; /* VBR quality indicator (0 best - 100 worst) */ +}; + +#ifdef INCLUDE_UNUSED_STUFF +enum tag_rgain_name { + TAG_RGAIN_NAME_NOT_SET = 0x0, + TAG_RGAIN_NAME_RADIO = 0x1, + TAG_RGAIN_NAME_AUDIOPHILE = 0x2 +}; + +enum tag_rgain_originator { + TAG_RGAIN_ORIGINATOR_UNSPECIFIED = 0x0, + TAG_RGAIN_ORIGINATOR_PRESET = 0x1, + TAG_RGAIN_ORIGINATOR_USER = 0x2, + TAG_RGAIN_ORIGINATOR_AUTOMATIC = 0x3 +}; + +struct tag_rgain { + enum tag_rgain_name name; + enum tag_rgain_originator originator; + signed short adjustment; +}; + +struct tag_lame { + unsigned char revision; + unsigned char flags; + + enum tag_lame_vbr vbr_method; + unsigned short lowpass_filter; + + mad_fixed_t peak; + struct tag_rgain replay_gain[2]; + + unsigned char ath_type; + unsigned char bitrate; + + unsigned short start_delay; + unsigned short end_padding; + + enum tag_lame_source source_samplerate; + enum tag_lame_mode stereo_mode; + unsigned char noise_shaping; + + signed char gain; + enum tag_lame_surround surround; + enum tag_lame_preset preset; + + unsigned long music_length; + unsigned short music_crc; +}; +#endif /* INCLUDE_UNUSED_STUFF */ + +struct tag { + int flags; + struct tag_xing xing; +#ifdef INCLUDE_UNUSED_STUFF + struct tag_lame lame; + char encoder[21]; +#endif /* INCLUDE_UNUSED_STUFF */ +}; + +void tag_init(struct tag *); + +# define tag_finish(tag) /* nothing */ + +int tag_parse(struct tag *, struct mad_stream const *); +#ifdef INCLUDE_UNUSED_STUFF +void tag_parse_rgain(struct tag_rgain *, struct mad_bitptr *); +#endif /* INCLUDE_UNUSED_STUFF */ + +# endif /* __TAG_H__ */ diff --git a/src/driver/audiodec/vis.cpp b/src/driver/audiodec/vis.cpp new file mode 100644 index 000000000..79c3600e6 --- /dev/null +++ b/src/driver/audiodec/vis.cpp @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "int_fft.c" +typedef signed short gint16; +typedef int gint; +typedef float gfloat; +typedef double gdouble; + +#define NUM_BANDS 16 +#define WIDTH (120/NUM_BANDS) +#define HEIGHT 64 +#define FALL 2 +#define FALLOFF 1 + +static int bar_heights[NUM_BANDS]; +static int falloffs[NUM_BANDS]; +static gdouble scale = 0; + +static gint xscale128[] = { 0, 1, 2, 3, 4, 6, 8, 9, 10, 14, 20, 27, 37, 50, 67, 94, 127 }; +static gint xscale256[] = { 0, 1, 2, 3, 5, 7, 10, 14, 20, 28, 40, 54, 74, 101, 137, 187, 255 }; +static gint xscale512[] = { 0, 2, 4, 6, 10, 14, 20, 28, 40, 56, 80, 108, 148, 202, 274, 374, 510 }; + +//#define DEBUG +#if HAVE_DBOX2 +#define SAMPLES 256 +#define LOG 8 +#define xscale xscale128 +#else +#define SAMPLES 512 +#define LOG 9 +#define xscale xscale256 +#endif + +static void do_fft(gint16 out_data[], gint16 in_data[]) +{ + gint16 im[SAMPLES]; + + memset(im, 0, sizeof(im)); + window(in_data, SAMPLES); + fix_fft(in_data, im, LOG, 0); + fix_loud(out_data, in_data, im, SAMPLES/2, 0); +} + +static int threshold = -60; +void sanalyzer_render_freq (gint16 in_data[]) +{ +#if 0 + gint i, c; + gint y; + gint16 freq_data[1024]; + static int fl = 0; + +#ifdef DEBUG +struct timeval tv1, tv2; +gettimeofday (&tv1, NULL); +#endif + do_fft (freq_data, in_data); + + CVFD::getInstance ()->Clear (); +#ifdef DEBUG +//gettimeofday (&tv1, NULL); +#endif + for (i = 0; i < NUM_BANDS; i++) { + y = 0; + +#if 0 // using max value + for (c = xscale[i]; c < xscale[i + 1]; c++) { + if(freq_data[c] > threshold) { + int val = freq_data[c]-threshold; + if (val > y) + y = val; + } + } +#else + int val = 0; + int cnt = 0; + for (c = xscale[i]; c < xscale[i + 1]; c++) { + if(freq_data[c] > threshold) { + val += freq_data[c]-threshold; + cnt++; + } + } + if(cnt) y = val/cnt; +#endif + + if (y > HEIGHT - 1) + y = HEIGHT - 1; + + if (y > bar_heights[i]) + bar_heights[i] = y; + else if (bar_heights[i] > FALL) + bar_heights[i] -= FALL; + else + bar_heights[i] = 0; + + if (y > falloffs[i]) + falloffs[i] = y; + else if (falloffs[i] > FALLOFF) { + fl ++; + if(fl > 2) { + fl = 0; + falloffs[i] -= FALLOFF; + } + } + else + falloffs[i] = 0; + CVFD::getInstance ()->drawBar (i*WIDTH, 64-falloffs[i]-5, WIDTH, 2); + y = bar_heights[i]; + CVFD::getInstance ()->drawBar (i*WIDTH, 64-y, WIDTH, y); + } + +#ifdef DEBUG +gettimeofday (&tv2, NULL); +printf("Calc takes %dns\n", (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec)); +#endif + CVFD::getInstance ()->Update (); +#endif +} +#if 0 +void sanalyzer_render_vu (gint16 in_data[2][512]) +{ + long delay_value; + int a = 0,b = 0, c; + float max = 32767.50; + float db_min = (float) -91; + float channel_data[2] = { 0.0, 0.0}; + static int olda = 0, oldb = 0; +return; +#ifdef DEBUG +//struct timeval tv1, tv2; +//gettimeofday (&tv1, NULL); +#endif + for (c = 0; c < 512; c += 2) { + channel_data[0] += (float) (in_data[0][c] * in_data[0][c]); + channel_data[1] += (float) (in_data[1][c] * in_data[1][c]); + } + channel_data[0] = 20 * log10 (sqrt (channel_data[0] / 256.0) / max); + channel_data[1] = 20 * log10 (sqrt (channel_data[1] / 256.0) / max); + + a = channel_data[0] + 91; + b = channel_data[1] + 91; +//printf ("channel0: %d\n", a); +//printf ("channel1: %d\n", b); +#ifdef DEBUG +//gettimeofday (&tv2, NULL); +//printf("Calc takes %dms\n", (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000); +#endif + if(a != olda || b != oldb) { + CVFD::getInstance ()->Clear (); + CVFD::getInstance ()->drawBar (0, 8, a, 20); + CVFD::getInstance ()->drawBar (0, 36, b, 20); +#ifdef DEBUG +//gettimeofday (&tv1, NULL); +#endif + CVFD::getInstance ()->Update (); +#ifdef DEBUG +//gettimeofday (&tv2, NULL); +//int ms = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000; +//if(ms) printf("Update takes %dms\n", ms); +#endif + } + return; +} +#endif diff --git a/src/driver/audiodec/wavdec.cpp b/src/driver/audiodec/wavdec.cpp new file mode 100644 index 000000000..552d12987 --- /dev/null +++ b/src/driver/audiodec/wavdec.cpp @@ -0,0 +1,213 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2004 Zwen + + Homepage: http://www.dbox2.info/ + + Kommentar: + + wav audio decoder + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ProgName "WavDec" +// nr of msecs to skip in ff/rev mode +#define MSECS_TO_SKIP 3000 +// nr of msecs to play in ff/rev mode +#define MSECS_TO_PLAY 200 + +struct WavHeader +{ + char ChunkID[4]; + int ChunkSize; + char Format[4]; + char Subchunk1ID[4]; + int Subchunk1Size; + short AudioFormat; + short NumChannels; + int SampleRate; + int ByteRate; + short BlockAlign; + short BitsPerSample; + char Subchunk2ID[4]; + int Subchunk2Size; +} __attribute__ ((packed)); + +int endianTest=1; +#define Swap32IfBE(l) \ + (*(char *)&endianTest ? (l) : \ + ((((l) & 0xff000000) >> 24) | \ + (((l) & 0x00ff0000) >> 8) | \ + (((l) & 0x0000ff00) << 8) | \ + (((l) & 0x000000ff) << 24))) +#define Swap16IfBE(l) \ + (*(char *)&endianTest ? (l) : \ + ((((l) & 0xff00) >> 8) | \ + (((l) & 0x00ff) << 8))) + +#define MAX_OUTPUT_SAMPLES 1022 /* AVIA_GT_PCM_MAX_SAMPLES-1 */ + +CBaseDec::RetCode CWavDec::Decoder(FILE *in, int OutputFd, State* state, CAudioMetaData* meta_data, time_t* time_played, unsigned int* secondsToSkip) +{ + char* buffer; + RetCode Status=OK; + + if (!SetMetaData(in, meta_data)) + { + Status=DATA_ERR; + return Status; + } + fseek(in, header_size, SEEK_SET); + int fmt; + switch(mBitsPerSample) + { + case 8 : fmt = AFMT_U8; + break; + case 16 : fmt = header_size == 0 ? AFMT_S16_BE : AFMT_S16_LE; + break; + default: + printf("%s: wrong bits per sample (%d)\n", ProgName, mBitsPerSample); + Status=DATA_ERR; + return Status; + } + + if (SetDSP(OutputFd, fmt, meta_data->samplerate , mChannels)) + { + Status=DSPSET_ERR; + return Status; + } + int actSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip : MSECS_TO_SKIP / 1000; + unsigned int oldSecsToSkip = *secondsToSkip; + int jumppos=0; + int bytes; + int bytes_to_play = (int) (1.0 * MSECS_TO_PLAY / 1000 * meta_data->bitrate / 8); + int bytes_to_skip = (int) (1.0 * actSecsToSkip * meta_data->bitrate / 8); + int buffersize = MAX_OUTPUT_SAMPLES * mChannels * mBitsPerSample / 8; + buffer = (char*) malloc (buffersize); + do + { + while(*state==PAUSE) + usleep(10000); + + if(*state==FF || *state==REV) + { + if (oldSecsToSkip != *secondsToSkip) + { + actSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip : MSECS_TO_SKIP / 1000; + bytes_to_skip = (int) (1.0 * actSecsToSkip * meta_data->bitrate / 8); + oldSecsToSkip = *secondsToSkip; + } + //printf("skipping %d secs and %d bytes\n",actSecsToSkip,bytes_to_skip); + if(std::abs(ftell(in)-jumppos) > bytes_to_play) + { + if(*state==FF) + { + fseek(in, bytes_to_skip, SEEK_CUR); + jumppos=ftell(in); + } + else + { + if(ftell(in) < bytes_to_skip) + { + fseek(in, header_size, SEEK_SET); + *state=PLAY; + } + else + { + fseek(in, -bytes_to_skip, SEEK_CUR); + jumppos=ftell(in); + } + } + } + // if a custom value was set we only jump once + if (*secondsToSkip != 0) { + *state=PLAY; + } + } + + bytes = fread(buffer, 1, buffersize, in); + if (write(OutputFd, buffer, bytes) != bytes) + { + fprintf(stderr,"%s: PCM write error (%s).\n", ProgName, strerror(errno)); + Status=WRITE_ERR; + } + *time_played = (meta_data->bitrate!=0) ? (ftell(in)-header_size)*8/meta_data->bitrate : 0; + } while (bytes > 0 && *state!=STOP_REQ && Status==OK); + free(buffer); + return Status; +} + +bool CWavDec::GetMetaData(FILE *in, const bool nice, CAudioMetaData* m) +{ + return SetMetaData(in, m); +} + +CWavDec* CWavDec::getInstance() +{ + static CWavDec* WavDec = NULL; + if(WavDec == NULL) + { + WavDec = new CWavDec(); + } + return WavDec; +} + +bool CWavDec::SetMetaData(FILE* in, CAudioMetaData* m) +{ + /* Set Metadata */ + struct WavHeader wh; + + header_size = 44; + + fseek(in, 0, SEEK_END); + int filesize = ftell(in); + fseek(in, 0, SEEK_SET); + if(fread(&wh, sizeof(wh), 1, in)!=1) + return false; + if(memcmp(wh.ChunkID, "RIFF", 4)!=0 || + memcmp(wh.Format, "WAVE", 4)!=0 || + Swap16IfBE(wh.AudioFormat) != 1) + { + printf("%s: wrong format (header)\n", ProgName); + return false; + } + m->type = CAudioMetaData::WAV; + m->bitrate = Swap32IfBE(wh.ByteRate)*8; + m->samplerate = Swap32IfBE(wh.SampleRate); + mBitsPerSample = Swap16IfBE(wh.BitsPerSample); + mChannels = Swap16IfBE(wh.NumChannels); + m->total_time = (m->bitrate!=0) ? (filesize-header_size)*8 / m->bitrate : 0; + std::stringstream ss; + ss << "Riff/Wave / " << mChannels << "channel(s) / " << mBitsPerSample << "bit"; + m->type_info = ss.str(); + m->changed=true; + return true; +} diff --git a/src/driver/audiodec/wavdec.h b/src/driver/audiodec/wavdec.h new file mode 100644 index 000000000..5a9a9fadb --- /dev/null +++ b/src/driver/audiodec/wavdec.h @@ -0,0 +1,54 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2004 Zwen + + wav audio decoder + Homepage: http://www.dbox2.info/ + + Kommentar: + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __WAV_DEC__ +#define __WAV_DEC__ + +#include +#include + +class CWavDec : public CBaseDec +{ + +public: + static CWavDec* getInstance(); + virtual RetCode Decoder(FILE *,int , State* , CAudioMetaData* m, time_t* t, unsigned int* secondsToSkip); + bool GetMetaData(FILE *in, const bool nice, CAudioMetaData* m); + CWavDec(){}; + +protected: + virtual bool SetMetaData(FILE* in, CAudioMetaData* m); + + int mBitsPerSample; + int mChannels; + int header_size; +}; + + +#endif + diff --git a/src/driver/audiofile.cpp b/src/driver/audiofile.cpp new file mode 100644 index 000000000..d271eae2c --- /dev/null +++ b/src/driver/audiofile.cpp @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: non-nil; c-basic-offset: 4 -*- */ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +/* default constructor */ +CAudiofile::CAudiofile() + : MetaData(), Filename(), FileType( CFile::FILE_UNKNOWN ) +{ +} + +/* constructor */ +CAudiofile::CAudiofile( std::string name, CFile::FileType type ) + : MetaData(), Filename( name ), FileType( type ) +{ +} + +/* copy constructor */ +CAudiofile::CAudiofile( const CAudiofile& src ) + : MetaData( src.MetaData ), Filename( src.Filename ), + FileType( src.FileType ) +{ +} + +/* assignment operator */ +void CAudiofile::operator=( const CAudiofile& src ) +{ + MetaData = src.MetaData; + Filename = src.Filename; + FileType = src.FileType; +} + +void CAudiofile::clear() +{ + MetaData.clear(); + Filename.clear(); + FileType = CFile::FILE_UNKNOWN; +} diff --git a/src/driver/audiofile.h b/src/driver/audiofile.h new file mode 100644 index 000000000..f662418d8 --- /dev/null +++ b/src/driver/audiofile.h @@ -0,0 +1,58 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __AUDIOFILE_H__ +#define __AUDIOFILE_H__ + +#include +#include +#include "driver/audiometadata.h" +#include "driver/file.h" + +class CAudiofile +{ + public: + /* constructors */ + CAudiofile(); + CAudiofile( std::string name, CFile::FileType type ); + CAudiofile( const CAudiofile& src ); + + void operator=( const CAudiofile& src ); + void clear(); + + CAudioMetaData MetaData; + std::string Filename; + CFile::FileType FileType; +}; + +typedef std::vector CPlayList; + +#endif /* __AUDIOFILE_H__ */ diff --git a/src/driver/audiometadata.cpp b/src/driver/audiometadata.cpp new file mode 100644 index 000000000..600c4f32b --- /dev/null +++ b/src/driver/audiometadata.cpp @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: non-nil; c-basic-offset: 4 -*- */ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2002 Bjoern Kalkbrenner + Copyright (C) 2002,2003 Dirch + Copyright (C) 2002,2003,2004 Zwen + + libmad MP3 low-level core + Homepage: http://www.dbox2.info/ + + Kommentar: + + based on + ************************************ + *** madlld -- Mad low-level *** v 1.0p1, 2002-01-08 + *** demonstration/decoder *** (c) 2001, 2002 Bertrand Petit + ************************************ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +// constructor +CAudioMetaData::CAudioMetaData() +{ + clear(); +} + +// copy constructor +CAudioMetaData::CAudioMetaData( const CAudioMetaData& src ) + : type( src.type ), type_info( src.type_info ), + filesize( src.filesize ), bitrate( src.bitrate ), + avg_bitrate( src.avg_bitrate ), samplerate( src.samplerate ), + layer( src.layer ), mode( src.mode ), total_time( src.total_time ), + audio_start_pos( src.audio_start_pos ), vbr( src.vbr ), + hasInfoOrXingTag( src.hasInfoOrXingTag ), artist( src.artist ), + title( src.title ), album( src.album ), sc_station( src.sc_station ), + date( src.date ), genre( src.genre ), track( src.track ), + changed( src.changed ) +{ +} + +// assignment operator +void CAudioMetaData::operator=( const CAudioMetaData& src ) +{ + // self assignment check + if ( &src == this ) + return; + + type = src.type; + type_info = src.type_info; + filesize = src.filesize; + bitrate = src.bitrate; + avg_bitrate = src.avg_bitrate; + samplerate = src.samplerate; + layer = src.layer; + mode = src.mode; + total_time = src.total_time; + audio_start_pos = src.audio_start_pos; + vbr = src.vbr; + hasInfoOrXingTag = src.hasInfoOrXingTag; + artist = src.artist; + title = src.title; + album = src.album; + date = src.date; + genre = src.genre; + track = src.track; + sc_station = src.sc_station; + changed = src.changed; +} + +void CAudioMetaData::clear() +{ + type=NONE; + type_info.clear(); + filesize=0; + bitrate=0; + avg_bitrate=0; + samplerate=0; + total_time=0; + audio_start_pos=0; + vbr=false; + hasInfoOrXingTag=false; + artist.clear(); + title.clear(); + album.clear(); + sc_station.clear(); + date.clear(); + genre.clear(); + track.clear(); + changed=false; +} diff --git a/src/driver/audiometadata.h b/src/driver/audiometadata.h new file mode 100644 index 000000000..7cd6272b5 --- /dev/null +++ b/src/driver/audiometadata.h @@ -0,0 +1,88 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2002 Bjoern Kalkbrenner + Copyright (C) 2002,2003 Dirch + Copyright (C) 2002,2003,2004 Zwen + + libmad MP3 low-level core + Homepage: http://www.dbox2.info/ + + Kommentar: + + based on + ************************************ + *** madlld -- Mad low-level *** v 1.0p1, 2002-01-08 + *** demonstration/decoder *** (c) 2001, 2002 Bertrand Petit + ************************************ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __AUDIO_METADATA__ +#define __AUDIO_METADATA__ + +#include +#include + +class CAudioMetaData +{ +public: + // constructor + CAudioMetaData(); + // copy constructor + CAudioMetaData( const CAudioMetaData& src ); + // assignment operator + void operator=( const CAudioMetaData& src ); + void clear(); + + enum AudioType + { + NONE, + CDR, + MP3, + OGG, + WAV + }; + AudioType type; + std::string type_info; + + long filesize; /* filesize in bits (for mp3: without leading id3 tag) */ + + unsigned int bitrate; /* overall bitrate, vbr file: current bitrate */ + unsigned int avg_bitrate; /* average bitrate in case of vbr file */ + unsigned int samplerate; + enum mad_layer layer; + enum mad_mode mode; + time_t total_time; + long audio_start_pos; /* position of first audio frame */ + bool vbr; + /* if the variable hasInfoOrXingTag is true, this means the values of + VBR and Duration are correct and should not be changed by the + decoder */ + bool hasInfoOrXingTag; + + std::string artist; + std::string title; + std::string album; + std::string sc_station; + std::string date; + std::string genre; + std::string track; + bool changed; +}; +#endif /* __AUDIO_METADATA__ */ diff --git a/src/driver/audioplay.cpp b/src/driver/audioplay.cpp new file mode 100644 index 000000000..73b352520 --- /dev/null +++ b/src/driver/audioplay.cpp @@ -0,0 +1,223 @@ +/* + Neutrino-GUI - DBoxII-Project + + audioplayer + Copyright (C) 2002 Bjoern Kalkbrenner + Copyright (C) 2002,2003 Dirch + Copyright (C) 2002,2003,2004 Zwen + Homepage: http://www.dbox2.info/ + + Kommentar: + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DBOX + +/**************************************************************************** + * Includes * + ****************************************************************************/ +#ifdef HAVE_CONFIG_H +#include +#endif +#include "global.h" +#include +#include +#include + +#include +#include +#include + +void CAudioPlayer::stop() +{ + state = CBaseDec::STOP_REQ; + if(thrPlay) + pthread_join(thrPlay,NULL); + thrPlay = 0; +} +void CAudioPlayer::pause() +{ + if(state==CBaseDec::PLAY || state==CBaseDec::FF || state==CBaseDec::REV) + state=CBaseDec::PAUSE; + else if(state==CBaseDec::PAUSE) + state=CBaseDec::PLAY; +} +void CAudioPlayer::ff(unsigned int seconds) +{ + m_SecondsToSkip = seconds; + if(state==CBaseDec::PLAY || state==CBaseDec::PAUSE || state==CBaseDec::REV) + state=CBaseDec::FF; + else if(state==CBaseDec::FF) + state=CBaseDec::PLAY; +} +void CAudioPlayer::rev(unsigned int seconds) +{ + m_SecondsToSkip = seconds; + if(state==CBaseDec::PLAY || state==CBaseDec::PAUSE || state==CBaseDec::FF) + state=CBaseDec::REV; + else if(state==CBaseDec::REV) + state=CBaseDec::PLAY; +} +CAudioPlayer* CAudioPlayer::getInstance() +{ + static CAudioPlayer* AudioPlayer = NULL; + if(AudioPlayer == NULL) + { + AudioPlayer = new CAudioPlayer(); + } + return AudioPlayer; +} + +void* CAudioPlayer::PlayThread( void* dummy ) +{ + int soundfd = -1; + g_RCInput->close_click(); + /* Decode stdin to stdout. */ + CBaseDec::RetCode Status = + CBaseDec::DecoderBase( &getInstance()->m_Audiofile, soundfd, + &getInstance()->state, + &getInstance()->m_played_time, + &getInstance()->m_SecondsToSkip ); + + if (Status != CBaseDec::OK) + { + fprintf( stderr, "Error during decoding: %s.\n", + ( Status == CBaseDec::READ_ERR ) ? "READ_ERR" : + ( Status == CBaseDec::WRITE_ERR ) ? "WRITE_ERR" : + ( Status == CBaseDec::DSPSET_ERR ) ? "DSPSET_ERR" : + ( Status == CBaseDec::DATA_ERR ) ? "DATA_ERR" : + ( Status == CBaseDec::INTERNAL_ERR ) ? "INTERNAL_ERR" : + "unknown" ); + } + + g_RCInput->open_click(); + + getInstance()->state = CBaseDec::STOP; + pthread_exit(0); + return NULL; +} + +bool CAudioPlayer::play(const CAudiofile* file, const bool highPrio) +{ + if (state != CBaseDec::STOP) + stop(); + getInstance()->clearFileData(); + + /* + transfer information from CAudiofile to member variable, + so that it does not have to be gathered again + + this assignment is important, otherwise the player would + crash if the file currently played was deleted from the + playlist + */ + m_Audiofile = *file; + + state = CBaseDec::PLAY; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + if(highPrio) + { + struct sched_param param; + pthread_attr_setschedpolicy(&attr, SCHED_RR); + param.sched_priority=1; + pthread_attr_setschedparam(&attr, ¶m); + usleep(100000); // give the event thread some time to handle his stuff + // without this sleep there were duplicated events... + } + + bool ret = true; +#warning fixme: There must be a way to call the playing thread without arguments. (NULL did not work for me) + if (pthread_create (&thrPlay, &attr, PlayThread, (void*)&ret) != 0 ) + { + perror("audioplay: pthread_create(PlayThread)"); + ret = false; + } + + pthread_attr_destroy(&attr); + return ret; +} + +CAudioPlayer::CAudioPlayer() +{ + init(); +} + +void CAudioPlayer::init() +{ + CBaseDec::Init(); + state = CBaseDec::STOP; + thrPlay = 0; +} + +void CAudioPlayer::sc_callback(void *arg) +{ + bool changed=false; + CSTATE *stat = (CSTATE*)arg; + if(m_Audiofile.MetaData.artist != stat->artist) + { + m_Audiofile.MetaData.artist = stat->artist; + changed=true; + } + if (m_Audiofile.MetaData.title != stat->title) + { + m_Audiofile.MetaData.title = stat->title; + changed=true; + } + if (m_Audiofile.MetaData.sc_station != stat->station) + { + m_Audiofile.MetaData.sc_station = stat->station; + changed=true; + } + if (m_Audiofile.MetaData.genre != stat->genre) + { + m_Audiofile.MetaData.genre = stat->genre; + changed=true; + } + if(changed) + { + m_played_time = 0; + } + m_sc_buffered = stat->buffered; + m_Audiofile.MetaData.changed = changed; + //printf("Callback %s %s %s %d\n",stat->artist, stat->title, stat->station, stat->buffered); +} + +void CAudioPlayer::clearFileData() +{ + m_Audiofile.clear(); + m_played_time=0; + m_sc_buffered=0; +} + +CAudioMetaData CAudioPlayer::getMetaData() +{ + CAudioMetaData m = m_Audiofile.MetaData; + m_Audiofile.MetaData.changed=false; + return m; +} + +bool CAudioPlayer::hasMetaDataChanged() +{ + return m_Audiofile.MetaData.changed; +} + +bool CAudioPlayer::readMetaData(CAudiofile* const file, const bool nice) +{ + return CBaseDec::GetMetaDataBase(file, nice); +} + diff --git a/src/driver/audioplay.h b/src/driver/audioplay.h new file mode 100644 index 000000000..e56516a97 --- /dev/null +++ b/src/driver/audioplay.h @@ -0,0 +1,77 @@ +/* + Neutrino-GUI - DBoxII-Project + + Homepage: http://www.dbox2.info/ + + Kommentar: + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __AUDIO_PLAY__ +#define __AUDIO_PLAY__ + +#include +#include +#include +#include +#include + +class CAudioPlayer +{ +private: + time_t m_played_time; + int m_sc_buffered; + FILE *soundfd; + pthread_t thrPlay; + FILE *fp; + CBaseDec::State state; + static void* PlayThread(void*); + void clearFileData(); + unsigned int m_SecondsToSkip; + +protected: + CAudiofile m_Audiofile; + bool SetDSP(int soundfd, int fmt, unsigned int dsp_speed, unsigned int channels); + +public: + static CAudioPlayer* getInstance(); + bool play(const CAudiofile*, const bool highPrio=false); + void stop(); + void pause(); + void init(); + void ff(unsigned int seconds=0); + void rev(unsigned int seconds=0); + CAudioMetaData getMetaData(); + bool hasMetaDataChanged(); + bool readMetaData(CAudiofile* const, const bool); + time_t getTimePlayed(){return m_played_time;} + time_t getTimeTotal(){return m_Audiofile.MetaData.total_time;} + int getScBuffered(){return m_sc_buffered;} + void sc_callback(void *arg); // see comment in .cpp + CBaseDec::State getState(){return state;} + + CAudioPlayer(); + ~CAudioPlayer(); + + +}; + + +#endif + diff --git a/src/driver/aviaext.cpp b/src/driver/aviaext.cpp new file mode 100644 index 000000000..8873ad96b --- /dev/null +++ b/src/driver/aviaext.cpp @@ -0,0 +1,170 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2004 Zwen@tuxbox.org + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#if HAVE_DVB_API_VERSION >= 3 +#include +#include + +#define AVIAEXT_DEV "/dev/dbox/aviaEXT" + +CAViAExt* CAViAExt::getInstance() +{ + static CAViAExt* AViAExt = NULL; + if(AViAExt == NULL) + { + AViAExt = new CAViAExt(); + } + return AViAExt; +} + +void CAViAExt::iecOn() +{ + int res,fd; + + if ((fd = open(AVIAEXT_DEV,O_RDWR))<0) + { + if (errno==ENOENT) + fprintf (stderr,"%s does not exist, did you forget to load the aviaEXT module?\n",AVIAEXT_DEV); + else + perror ("aviaext: error opening /dev/dbox/aviaEXT"); + return; + } + res = ioctl(fd, AVIA_EXT_IEC_SET, 1); + if (res<0) + perror("aviaext: ioctl"); + close(fd); +} + +void CAViAExt::iecOff() +{ + int res,fd; + + if ((fd = open(AVIAEXT_DEV,O_RDWR))<0) + { + if (errno==ENOENT) + fprintf (stderr,"%s does not exist, did you forget to load the aviaEXT module?\n",AVIAEXT_DEV); + else + perror ("aviaext: error opening /dev/dbox/aviaEXT"); + return; + } + res = ioctl(fd, AVIA_EXT_IEC_SET, 0); + if (res<0) + perror("aviaext: ioctl"); + close(fd); +} + +int CAViAExt::iecState() +{ + int res,fd; + unsigned int param; + + if ((fd = open(AVIAEXT_DEV,O_RDWR))<0) + { + if (errno==ENOENT) + fprintf (stderr,"%s does not exist, did you forget to load the aviaEXT module?\n",AVIAEXT_DEV); + else + perror ("aviaext: error opening /dev/dbox/aviaEXT"); + return -1; + } + res = ioctl(fd, AVIA_EXT_IEC_GET, ¶m); + + close(fd); + + if (res<0) + { + perror("aviaext: ioctl"); + return -1; + } + return param; +} + +void CAViAExt::playbackSPTS() +{ + int res,fd; + + if ((fd = open(AVIAEXT_DEV,O_RDWR))<0) + { + if (errno==ENOENT) + fprintf (stderr,"%s does not exist, did you forget to load the aviaEXT module?\n",AVIAEXT_DEV); + else + perror ("aviaext: error opening /dev/dbox/aviaEXT"); + return; + } + res = ioctl(fd, AVIA_EXT_AVIA_PLAYBACK_MODE_SET, 1); + if (res<0) + perror("aviaext: ioctl"); + close(fd); +} + +void CAViAExt::playbackPES() +{ + int res,fd; + + if ((fd = open(AVIAEXT_DEV,O_RDWR))<0) + { + if (errno==ENOENT) + fprintf (stderr,"%s does not exist, did you forget to load the aviaEXT module?\n",AVIAEXT_DEV); + else + perror ("aviaext: error opening /dev/dbox/aviaEXT"); + return; + } + res = ioctl(fd, AVIA_EXT_AVIA_PLAYBACK_MODE_SET, 0); + if (res<0) + perror("aviaext: ioctl"); + close(fd); +} + +int CAViAExt::playbackState() +{ + int res,fd; + unsigned int param; + + if ((fd = open(AVIAEXT_DEV,O_RDWR))<0) + { + if (errno==ENOENT) + fprintf (stderr,"%s does not exist, did you forget to load the aviaEXT module?\n",AVIAEXT_DEV); + else + perror ("aviaext: error opening /dev/dbox/aviaEXT"); + return -1; + } + res = ioctl(fd, AVIA_EXT_AVIA_PLAYBACK_MODE_GET, ¶m); + + close(fd); + + if (res<0) + { + perror("aviaext: ioctl"); + return -1; + } + return param; +} +#endif diff --git a/src/driver/bigclock.cpp b/src/driver/bigclock.cpp new file mode 100644 index 000000000..e5264f59b --- /dev/null +++ b/src/driver/bigclock.cpp @@ -0,0 +1,125 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include "bigclock.h" + + +void doppelpunkt(CLCDDisplay* display, int pos) +{ + int i,j; + + for (i=1;i<=4;i++) + for (j=1;j<=4;j++) + display->draw_point(i+10+pos*24-3,j+23,CLCDDisplay::PIXEL_ON); + for (i=1;i<=4;i++) + for (j=1;j<=4;j++) + display->draw_point(i+10+pos*24-3,j+37,CLCDDisplay::PIXEL_ON); +} + + +void balken(CLCDDisplay* display, int pos, int balken) +{ + int i,j; + + if (balken==3||balken==6||balken==7) + { + //horizontaler balken + if (balken == 6) for (i=1;i<=14;i++) for (j=1;j<=4;j++) display->draw_point(i+5+pos*24-3,j+14,CLCDDisplay::PIXEL_ON); + if (balken == 7) for (i=1;i<=8;i++) for (j=1;j<=4;j++) display->draw_point(i+8+pos*24-3,j+30,CLCDDisplay::PIXEL_ON); + } if (balken == 3) for (i=1;i<=14;i++) for (j=1;j<=4;j++) display->draw_point(i+5+pos*24-3,j+46,CLCDDisplay::PIXEL_ON); + else + { + //vertikaler balken + if (balken == 1) for (i=1;i<=4;i++) for (j=1;j<=13;j++) display->draw_point(i+19+pos*24-3,j+18,CLCDDisplay::PIXEL_ON); + if (balken == 2) for (i=1;i<=4;i++) for (j=1;j<=13;j++) display->draw_point(i+19+pos*24-3,j+33,CLCDDisplay::PIXEL_ON); + if (balken == 5) for (i=1;i<=4;i++) for (j=1;j<=13;j++) display->draw_point(i+1+pos*24-3,j+18,CLCDDisplay::PIXEL_ON); + if (balken == 4) for (i=1;i<=4;i++) for (j=1;j<=13;j++) display->draw_point(i+1+pos*24-3,j+33,CLCDDisplay::PIXEL_ON); + + } +} + +void showBigClock(CLCDDisplay* display, int h, int m) +{ + + //stunden einer + if (h==0||h==10||h==20) + { balken(display, 1,1); balken(display, 1,2); balken(display, 1,3); balken(display, 1,4); balken(display, 1,5); balken(display, 1,6);} + if (h==1||h==11||h==21) + { balken(display, 1,1); balken(display, 1,2);} + if (h==2||h==12||h==22) + { balken(display, 1,1); balken(display, 1,7); balken(display, 1,3); balken(display, 1,4); balken(display, 1,6);} + if (h==3||h==13||h==23) + { balken(display, 1,1); balken(display, 1,2); balken(display, 1,3); balken(display, 1,7); balken(display, 1,6);} + if (h==4||h==14) + { balken(display, 1,1); balken(display, 1,2); balken(display, 1,7); balken(display, 1,5);} + if (h==5||h==15) + { balken(display, 1,2); balken(display, 1,3); balken(display, 1,5); balken(display, 1,6); balken(display, 1,7);} + if (h==6||h==16) + { balken(display, 1,7); balken(display, 1,2); balken(display, 1,3); balken(display, 1,4); balken(display, 1,5); balken(display, 1,6);} + if (h==7||h==17) + { balken(display, 1,1); balken(display, 1,2); balken(display, 1,6);} + if (h==8||h==18) + { balken(display, 1,1); balken(display, 1,2); balken(display, 1,3); balken(display, 1,4); balken(display, 1,5); balken(display, 1,6); balken(display, 1,7);} + if (h==9||h==19) + { balken(display, 1,1); balken(display, 1,2); balken(display, 1,3); balken(display, 1,7); balken(display, 1,5); balken(display, 1,6);} + //stunden zehner + if (h>9&&h<20){ balken(display, 0,1); balken(display, 0,2);} + if (h>19) { balken(display, 0,1); balken(display, 0,7); balken(display, 0,3); balken(display, 0,4); balken(display, 0,6);} + + + //minuten einer + if (m==0||m==10||m==20||m==30||m==40||m==50) + { balken(display, 4,1); balken(display, 4,2); balken(display, 4,3); balken(display, 4,4); balken(display, 4,5); balken(display, 4,6);} + if (m==1||m==11||m==21||m==31||m==41||m==51) + { balken(display, 4,1); balken(display, 4,2);} + if (m==2||m==12||m==22||m==32||m==42||m==52) + { balken(display, 4,1); balken(display, 4,7); balken(display, 4,3); balken(display, 4,4); balken(display, 4,6);} + if (m==3||m==13||m==23||m==33||m==43||m==53) + { balken(display, 4,1); balken(display, 4,2); balken(display, 4,3); balken(display, 4,7); balken(display, 4,6);} + if (m==4||m==14||m==24||m==34||m==44||m==54) + { balken(display, 4,1); balken(display, 4,2); balken(display, 4,7); balken(display, 4,5);} + if (m==5||m==15||m==25||m==35||m==45||m==55) + { balken(display, 4,2); balken(display, 4,3); balken(display, 4,5); balken(display, 4,6); balken(display, 4,7);} + if (m==6||m==16||m==26||m==36||m==46||m==56) + { balken(display, 4,7); balken(display, 4,2); balken(display, 4,3); balken(display, 4,4); balken(display, 4,5); balken(display, 4,6);} + if (m==7||m==17||m==27||m==37||m==47||m==57) + { balken(display, 4,1); balken(display, 4,2); balken(display, 4,6);} + if (m==8||m==18||m==28||m==38||m==48||m==58) + { balken(display, 4,1); balken(display, 4,2); balken(display, 4,3); balken(display, 4,4); balken(display, 4,5); balken(display, 4,6); balken(display, 4,7);} + if (m==9||m==19||m==29||m==39||m==49||m==59) + { balken(display, 4,1); balken(display, 4,2); balken(display, 4,3); balken(display, 4,7); balken(display, 4,5); balken(display, 4,6);} + + //minuten zehner + if (m<10) + { balken(display, 3,1); balken(display, 3,2); balken(display, 3,3); balken(display, 3,4); balken(display, 3,5); balken(display, 3,6);} + if (m>9&&m<20){ balken(display, 3,1); balken(display, 3,2);} + if (m>19&&m<30){ balken(display, 3,1); balken(display, 3,7); balken(display, 3,3); balken(display, 3,4); balken(display, 3,6);} + if (m>29&&m<40){ balken(display, 3,1); balken(display, 3,2); balken(display, 3,3); balken(display, 3,7); balken(display, 3,6);} + if (m>39&&m<50){ balken(display, 3,1); balken(display, 3,2); balken(display, 3,7); balken(display, 3,5);} + if (m>=50) { balken(display, 3,2); balken(display, 3,3); balken(display, 3,5); balken(display, 3,6); balken(display, 3,7);} + + doppelpunkt(display, 2); + } diff --git a/src/driver/bigclock.h b/src/driver/bigclock.h new file mode 100644 index 000000000..91735f93c --- /dev/null +++ b/src/driver/bigclock.h @@ -0,0 +1,35 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __bigclock__ +#define __bigclock__ + +#include + + +void showBigClock(CLCDDisplay* display, int h,int m); + + +#endif diff --git a/src/driver/capture.cpp b/src/driver/capture.cpp new file mode 100644 index 000000000..35c580b42 --- /dev/null +++ b/src/driver/capture.cpp @@ -0,0 +1,308 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + + + + +#include +#include +#include +#include +#include +#include +#include + +#include "capture.h" + + +#include +#warning "experimental..." + + +// +// -- TV Picture Capture +// -- This module is a class to provide a capture abstraction layer +// -- +// -- 2003-12 rasc +// + + + +// +// -- Constructor +// + +CCAPTURE::CCAPTURE() +{ + fd = -1; +} + + +CCAPTURE::CCAPTURE(int capture_nr) +{ + fd = -1; + fd = captureopen(capture_nr); +} + + +CCAPTURE::CCAPTURE(int capture_nr, int x, int y, int w, int h) +{ + fd = -1; + fd = captureopen (capture_nr); + set_coord (x,y, w,h); +} + + + + +CCAPTURE::~CCAPTURE() +{ + captureclose (); // cleanup anyway!! +} + + +// +// -- open Capture device +// -- return >=0: ok +// + +int CCAPTURE::captureopen (int cap_nr) +{ + char *capturedevs[] = { + CAPTURE_DEV "0" // CAPTURE device 0 + // CAPTURE_DEV "1", // CAPTURE device 1 + // CAPTURE_DEV "2", // CAPTURE device 2 + // CAPTURE_DEV "3" // CAPTURE device 3 + }; + + + if ( (cap_nr>0) || (cap_nr < (int)(sizeof (capturedevs)/sizeof(char *))) ) { + + if (fd < 0) { + fd = open( capturedevs[cap_nr], O_RDWR ); + if (fd >= 0) { + cx = cy = cw = ch = 0; + out_w = out_h = 0; + stride = 0; + } else perror (capturedevs[cap_nr]); + return fd; + } + + } + + return -1; +} + + +// +// -- close Capture Device +// + +void CCAPTURE::captureclose () +{ + if (fd >=0 ) { + close (fd); + fd = -1; + cx = cy = cw = ch = 0; + out_w = out_h = 0; + stride = 0; + } + return; +} + + + + +/* + -- Coordination routines... + */ + +void CCAPTURE::set_coord (int x, int y, int w, int h) +{ + if (( x != cx ) || ( y != cy )) { + cx = x; + cy = y; + cw = w; + ch = h; + _set_window (cx,cy,cw,ch); + } +} + + +void CCAPTURE::set_xy (int x, int y) +{ + if (( x != cx ) || ( y != cy )) { + cx = x; + cy = y; + _set_window (cx,cy,cw,ch); + } +} + + + +void CCAPTURE::set_size (int w, int h) +{ + if (( w != cw ) || ( h != ch )) { + cw = w; + ch = h; + _set_window (cx,cy,cw,ch); + } +} + + + + +// +// -- set Capture Position +// + +void CCAPTURE::_set_window (int x, int y, int w, int h) +{ +#ifdef __v4l_capture + + struct v4l2_crop crop; + + crop.c.left = x; + crop.c.top = y; + crop.c.width = w; + crop.c.height = h; + if( ioctl(fd, VIDIOC_S_CROP, &crop) < 0) + perror ("error VIDIOC_S_CROP"); + +#else + + capture_set_input_pos(fd, x, y); + capture_set_input_size(fd, w, h); + +#endif +} + + + +void CCAPTURE::set_output_size (int w, int h) +{ +#ifdef __v4l_capture + + struct v4l2_format format; + + out_w = w; + out_h = h; + format.fmt.pix.width = w; + format.fmt.pix.height = h; + + if (ioctl(fd, VIDIOC_S_FMT, &format) < 0) + perror ("error VIDIOC_S_FMT"); + +#else + + out_w = w; + out_h = h; + capture_set_output_size(fd, w, h); + +#endif +} + + +// +// -- capture a frame +// -- if buffer == NULL, routine will alloc memory! +// -- destroy will not free this allocated memory! +// -- otherwise buffer has to be large enough! +// + +u_char *CCAPTURE::readframe (u_char *buf) +{ +#ifdef __v4l_capture + + struct v4l2_format vid; + int n; + u_char *b; + + if (fd >= 0) { + // get capture information + vid.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl(fd, VIDIOC_G_FMT, &vid) < 0) + perror ("Error getting info with VIDIOC_G_FMT"); + + printf ("reported bytesperline: %d, height: %d, sizeimage: %d\n", + vid.fmt.pix.bytesperline, + vid.fmt.pix.height, + vid.fmt.pix.sizeimage); + + b = (buf != NULL) + ? buf + : (u_char *) malloc (vid.fmt.pix.bytesperline * + vid.fmt.pix.height); + + + n = read (fd, b, vid.fmt.pix.bytesperline*vid.fmt.pix.height); + if (n < 0) { + perror ("Error reading capture buffer"); + if (!buf) free (b); + return (u_char *)NULL; + } + + return b; + } + + return (u_char *) NULL; + + +#else + + u_char *b; + int stride; + int n; + + if (fd >= 0) { + stride = capture_start(fd); + + b = (buf != NULL) + ? buf + : (u_char *) malloc (stride * out_h); + + n = read(fd, b, stride * out_h); + capture_stop(fd); + if (n < 0) { + perror ("Error reading capture buffer"); + if (!buf) free (b); + return (u_char *)NULL; + } + + + return b; + } + + return (u_char *) NULL; + +#endif +} + + + + + + + + + + diff --git a/src/driver/capture.h b/src/driver/capture.h new file mode 100644 index 000000000..53775739e --- /dev/null +++ b/src/driver/capture.h @@ -0,0 +1,81 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __CAPTURE_CONTROL__ +#define __CAPTURE_CONTROL__ + + +#define __v4l_capture + + +using namespace std; + + +// +// -- Picture Capture Control +// -- 2003-12 rasc +// + +#ifdef __v4l_capture + +#include +#define CAPTURE_DEV "/dev/v4l/video" // CaptureNr will be appended! + +#else + +#include +#define CAPTURE_DEV "/dev/dbox/capture" // CaptureNr will be appended! + +#endif + + +class CCAPTURE +{ + public: + CCAPTURE (); + CCAPTURE (int capture_nr); // incl. open + CCAPTURE (int capture_nr, int x, int y, int w, int h); // open + set_coord + ~CCAPTURE (); + + int captureopen (int capture_nr); + void captureclose (void); + void set_coord (int x, int y, int w, int h); + void set_xy (int x, int y); + void set_size (int w, int h); + void set_output_size (int w, int h); + u_char *readframe (u_char *buf); + + private: + void _set_window (int x, int y, int w, int h); + + int fd; // io descriptor + int cx, cy, cw, ch; // capture size + int out_w, out_h; // capture output size + int stride; + +}; + + + +#endif + + diff --git a/src/driver/encoding.cpp b/src/driver/encoding.cpp new file mode 100644 index 000000000..519b10d89 --- /dev/null +++ b/src/driver/encoding.cpp @@ -0,0 +1,44 @@ +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/encoding.cpp,v 1.2 2003/09/27 11:48:09 thegoodguy Exp $ + * + * conversion of character encodings - d-box2 linux project + * + * (C) 2003 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +std::string Latin1_to_UTF8(const std::string & s) +{ + std::string r; + + for (std::string::const_iterator it = s.begin(); it != s.end(); it++) + { + unsigned char c = *it; + if (c < 0x80) + r += c; + else + { + unsigned char d = 0xc0 | (c >> 6); + r += d; + d = 0x80 | (c & 0x3f); + r += d; + } + } + return r; +} diff --git a/src/driver/encoding.h b/src/driver/encoding.h new file mode 100644 index 000000000..9564a8733 --- /dev/null +++ b/src/driver/encoding.h @@ -0,0 +1,31 @@ +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/encoding.h,v 1.2 2003/09/27 11:48:09 thegoodguy Exp $ + * + * conversion of character encodings - d-box2 linux project + * + * (C) 2003 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __neutrino__encoding_h__ +#define __neutrino__encoding_h__ + +#include + +std::string Latin1_to_UTF8(const std::string & s); + +#endif /* __neutrino__encoding_h__ */ diff --git a/src/driver/fb_window.cpp b/src/driver/fb_window.cpp new file mode 100644 index 000000000..d0d47afd5 --- /dev/null +++ b/src/driver/fb_window.cpp @@ -0,0 +1,82 @@ +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/fb_window.cpp,v 1.6 2004/03/14 22:28:13 thegoodguy Exp $ + * + * abstract fb_window class - d-box2 linux project + * + * (C) 2003 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +class CPrivateData +{ + public: + CFrameBuffer * frameBuffer; + fb_pixel_t * Background; +}; + +CFBWindow::CFBWindow(const int _x, const int _y, const int _dx, const int _dy) +{ + x = _x ; + y = _y ; + dx = _dx; + dy = _dy; + + private_data = (void *) new CPrivateData; + ((CPrivateData *)private_data)->frameBuffer = CFrameBuffer::getInstance(); + ((CPrivateData *)private_data)->Background = new fb_pixel_t [_dx * _dy]; + if (((CPrivateData *)private_data)->Background != NULL) + ((CPrivateData *)private_data)->frameBuffer->SaveScreen(_x, _y, _dx, _dy, (fb_pixel_t *)((CPrivateData *)private_data)->Background); + +} + +CFBWindow::~CFBWindow(void) +{ + if (private_data != NULL) + { + if (((CPrivateData *)private_data)->Background != NULL) + ((CPrivateData *)private_data)->frameBuffer->RestoreScreen(x, y, dx, dy, (fb_pixel_t *)((CPrivateData *)private_data)->Background); + + delete ((CPrivateData *)private_data)->Background; + delete ((CPrivateData *)private_data); + private_data = NULL; + } +} + +void CFBWindow::paintBoxRel(const int _x, const int _y, const int _dx, const int _dy, const color_t _col, int radius, int type) +{ + ((CPrivateData *)private_data)->frameBuffer->paintBoxRel(x + _x, y + _y, _dx, _dy, _col, radius, type); +} + +bool CFBWindow::paintIcon(const char * const _filename, const int _x, const int _y, const color_t _offset) +{ + ((CPrivateData *)private_data)->frameBuffer->paintIcon(_filename, x + _x, y + _y, _offset); + return 0; +} + +void CFBWindow::RenderString(const font_t _font, const int _x, const int _y, const int _width, const char * const _text, const color_t _color, const int _boxheight, const bool _utf8_encoded) +{ + ((Font *)_font)->RenderString(x + _x, y + _y, _width, _text, _color, _boxheight, _utf8_encoded); +} diff --git a/src/driver/fb_window.h b/src/driver/fb_window.h new file mode 100644 index 000000000..36110386d --- /dev/null +++ b/src/driver/fb_window.h @@ -0,0 +1,52 @@ +#ifndef __fb_window_h__ +#define __fb_window_h__ +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/fb_window.h,v 1.3 2004/03/13 12:45:41 thegoodguy Exp $ + * + * abstract fb_window class - d-box2 linux project + * + * (C) 2003 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +class CFBWindow +{ + public: +#ifdef FB_USE_PALETTE + typedef unsigned short color_t; +#else + typedef unsigned int color_t; +#endif + typedef void * font_t; + typedef void * private_data_t; + + private: + private_data_t private_data; + + public: + int x, y; /* upper left corner */ + int dx, dy; /* dimension */ + + CFBWindow(const int _x, const int _y, const int _dx, const int _dy); + ~CFBWindow(); + + void paintBoxRel(const int _x, const int _y, const int _dx, const int _dy, const color_t _col, int radius = 0, int type = 0); + bool paintIcon(const char * const _filename, const int _x, const int _y, const color_t _offset = 1); + void RenderString(const font_t _font, const int _x, const int _y, const int _width, const char * const _text, const color_t _color, const int _boxheight = 0, const bool _utf8_encoded = false); +}; + +#endif /* __fb_window_h__ */ diff --git a/src/driver/file.cpp b/src/driver/file.cpp new file mode 100644 index 000000000..01723fe7c --- /dev/null +++ b/src/driver/file.cpp @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: non-nil; c-basic-offset: 4 -*- */ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/* ATTENTION: the array file_extension_list MUST BE SORTED ASCENDING (cf. sort, man bsearch) - otherwise bsearch will not work correctly! */ +const char * const file_extension_list[] = +{ + "asf", "avi", "bmp", "cdr", "crw", + "flac", "gif", "imu", "jpeg", "jpg", + "m2a", "m3u", "mkv", "mp2", "mp3", + "mpa", "ogg", "png", "sh", "txt", + "url", "wav", "xml" +}; +/* ATTENTION: the array file_extension_list MUST BE SORTED ASCENDING (cf. sort, man bsearch) - otherwise bsearch will not work correctly! */ + +const CFile::FileType file_type_list[] = +{ + CFile::FILE_ASF , CFile::FILE_AVI , CFile::FILE_PICTURE , CFile::FILE_CDR , CFile::FILE_PICTURE , + CFile::FILE_FLAC , CFile::FILE_PICTURE , CFile::STREAM_PICTURE, CFile::FILE_PICTURE , CFile::FILE_PICTURE , + CFile::FILE_MP3 , CFile::FILE_PLAYLIST , CFile::FILE_MKV , CFile::FILE_MP3 , CFile::FILE_MP3 , + CFile::FILE_MP3 , CFile::FILE_OGG , CFile::FILE_PICTURE , CFile::FILE_TEXT , CFile::FILE_TEXT , + CFile::STREAM_AUDIO , CFile::FILE_WAV , CFile::FILE_XML +}; + +int mycasecmp(const void * a, const void * b) +{ + return strcasecmp(*(const char * *)a, *(const char * *)b); +} + +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ + +CFile::CFile() + : Size( 0 ), Mode( 0 ), Marked( false ), Time( 0 ) +{ +} + +CFile::FileType CFile::getType(void) const +{ + if(S_ISDIR(Mode)) + return FILE_DIR; + + std::string::size_type ext_pos = Name.rfind('.'); + + if (ext_pos != std::string::npos) + { + const char * key = &(Name.c_str()[ext_pos + 1]); + + void * result = ::bsearch(&key, file_extension_list, sizeof(file_extension_list) / sizeof(const char *), sizeof(const char *), mycasecmp); + + if (result != NULL) + return file_type_list[(const char * *)result - (const char * *)&file_extension_list]; + } + return FILE_UNKNOWN; +} + +//------------------------------------------------------------------------ + +std::string CFile::getFileName(void) const // return name.extension or folder name without trailing / +{ + std::string::size_type namepos = Name.rfind('/'); + + return (namepos == std::string::npos) ? Name : Name.substr(namepos + 1); +} + +//------------------------------------------------------------------------ + +std::string CFile::getPath(void) const // return complete path including trailing / +{ + int pos = 0; + + return ((pos = Name.rfind('/')) > 1) ? Name.substr(0, pos + 1) : "/"; +} diff --git a/src/driver/file.h b/src/driver/file.h new file mode 100644 index 000000000..6d62e8e46 --- /dev/null +++ b/src/driver/file.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: non-nil; c-basic-offset: 4 -*- */ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __FILE_H__ +#define __FILE_H__ + +#include /* make sure off_t has size 8 + in __USE_FILE_OFFSET64 mode */ + +#ifndef __USE_FILE_OFFSET64 +#error not using 64 bit file offsets +#endif /* __USE_FILE__OFFSET64 */ + +#include + + +#include +#include + +class CFile +{ +public: + enum FileType + { + FILE_UNKNOWN = 0, + FILE_AVI, + FILE_ASF, + FILE_DIR, + FILE_TEXT, + FILE_CDR, + FILE_MP3, + FILE_MKV, + FILE_OGG, + FILE_WAV, + FILE_FLAC, + FILE_XML, + FILE_PLAYLIST, + STREAM_AUDIO, + FILE_PICTURE, + STREAM_PICTURE + }; + + FileType getType(void) const; + std::string getFileName(void) const; + std::string getPath(void) const; + + CFile(); + off_t Size; + std::string Name; + std::string Url; + mode_t Mode; + bool Marked; + time_t Time; +}; + +typedef std::vector CFileList; + +#endif /* __FILE_H__ */ diff --git a/src/driver/fontrenderer.cpp b/src/driver/fontrenderer.cpp new file mode 100644 index 000000000..f79f78349 --- /dev/null +++ b/src/driver/fontrenderer.cpp @@ -0,0 +1,630 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Copyright (C) 2003 thegoodguy + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +// this method is recommended for FreeType >2.0.x: +#include +#include FT_FREETYPE_H + +#include + +#include + +//#undef USE_NEVIS_GXA // since OSD problem gone with new driver, until GXA will be faster//reenabled GXA-luc + +FT_Error FBFontRenderClass::myFTC_Face_Requester(FTC_FaceID face_id, + FT_Library library, + FT_Pointer request_data, + FT_Face* aface) +{ + return ((FBFontRenderClass*)request_data)->FTC_Face_Requester(face_id, aface); +} + + +FBFontRenderClass::FBFontRenderClass(const int xr, const int yr) +{ + dprintf(DEBUG_DEBUG, "[FONT] initializing core...\n"); + if (FT_Init_FreeType(&library)) + { + dprintf(DEBUG_NORMAL, "[FONT] initializing core failed.\n"); + return; + } + + font = NULL; + + xres = xr; + yres = yr; + + int maxbytes= 4 *1024*1024; + dprintf(DEBUG_INFO, "[FONT] Intializing font cache, using max. %dMB...\n", maxbytes/1024/1024); + fflush(stdout); + if (FTC_Manager_New(library, 10, 20, maxbytes, myFTC_Face_Requester, this, &cacheManager)) + { + dprintf(DEBUG_NORMAL, "[FONT] manager failed!\n"); + return; + } + if (!cacheManager) + { + dprintf(DEBUG_NORMAL, "[FONT] error.\n"); + return; + } + if (FTC_SBitCache_New(cacheManager, &sbitsCache)) + { + dprintf(DEBUG_NORMAL, "[FONT] sbit failed!\n"); + return; + } +/* if (FTC_ImageCache_New(cacheManager, &imageCache)) + { + printf(" imagecache failed!\n"); + } +*/ + pthread_mutex_init( &render_mutex, NULL ); +} + +FBFontRenderClass::~FBFontRenderClass() +{ + fontListEntry * g; + + for (fontListEntry * f = font; f; f = g) + { + g = f->next; + delete f; + } + + FTC_Manager_Done(cacheManager); + FT_Done_FreeType(library); +} + +FT_Error FBFontRenderClass::FTC_Face_Requester(FTC_FaceID face_id, FT_Face* aface) +{ + fontListEntry *font=(fontListEntry *)face_id; + if (!font) + return -1; + dprintf(DEBUG_DEBUG, "[FONT] FTC_Face_Requester (%s/%s)\n", font->family, font->style); + + int error; + if ((error=FT_New_Face(library, font->filename, 0, aface))) + { + dprintf(DEBUG_NORMAL, "[FONT] FTC_Face_Requester (%s/%s) failed: %i\n", font->family, font->style, error); + return error; + } + + if (strcmp(font->style, (*aface)->style_name) != 0) + { + FT_Matrix matrix; // Italics + + matrix.xx = 1 * 0x10000; + matrix.xy = (0x10000 >> 3); + matrix.yx = 0 * 0x10000; + matrix.yy = 1 * 0x10000; + + FT_Set_Transform(*aface, &matrix, NULL); + } + return 0; +} + +FTC_FaceID FBFontRenderClass::getFaceID(const char * const family, const char * const style) +{ + for (fontListEntry *f=font; f; f=f->next) + { + if ((!strcmp(f->family, family)) && (!strcmp(f->style, style))) + return (FTC_FaceID)f; + } + if (strncmp(style, "Bold ", 5) == 0) + { + for (fontListEntry *f=font; f; f=f->next) + { + if ((!strcmp(f->family, family)) && (!strcmp(f->style, &(style[5])))) + return (FTC_FaceID)f; + } + } + for (fontListEntry *f=font; f; f=f->next) + { + if (!strcmp(f->family, family)) + { + if (f->next) // the first font always seems to be italic, skip if possible + continue; + return (FTC_FaceID)f; + } + } + return 0; +} + +FT_Error FBFontRenderClass::getGlyphBitmap(FTC_ImageTypeRec *font, FT_ULong glyph_index, FTC_SBit *sbit) +{ + return FTC_SBitCache_Lookup(sbitsCache, font, glyph_index, sbit, NULL); +} + +FT_Error FBFontRenderClass::getGlyphBitmap(FTC_ScalerRec *sc, FT_ULong glyph_index, FTC_SBit *sbit) +{ + return FTC_SBitCache_LookupScaler(sbitsCache, sc, FT_LOAD_DEFAULT, glyph_index, sbit, NULL); +} + +const char * const FBFontRenderClass::AddFont(const char * const filename, const bool make_italics) +{ + fflush(stdout); + int error; + fontListEntry *n=new fontListEntry; + + FT_Face face; + if ((error=FT_New_Face(library, filename, 0, &face))) + { + dprintf(DEBUG_NORMAL, "[FONT] adding font %s, failed: %i\n", filename, error); + delete n;//Memory leak: n + return NULL; + } + n->filename = strdup(filename); + n->family = strdup(face->family_name); + n->style = strdup(make_italics ? "Italic" : face->style_name); + FT_Done_Face(face); + n->next=font; + dprintf(DEBUG_DEBUG, "[FONT] adding font %s... family %s, style %s ok\n", filename, n->family, n->style); + font=n; + return n->style; +} + +FBFontRenderClass::fontListEntry::~fontListEntry() +{ + delete[] filename; + delete[] family; + delete[] style; +} + +Font *FBFontRenderClass::getFont(const char * const family, const char * const style, int size) +{ + FTC_FaceID id = getFaceID(family, style); + if (!id) { + dprintf(DEBUG_DEBUG, "[FONT] getFont: family %s, style %s failed!\n", family, style); + return 0; + } + dprintf(DEBUG_DEBUG, "[FONT] getFont: family %s, style %s ok\n", family, style); + return new Font(this, id, size, (strcmp(((fontListEntry *)id)->style, style) == 0) ? Font::Regular : Font::Embolden); +} + +std::string FBFontRenderClass::getFamily(const char * const filename) const +{ + for (fontListEntry *f=font; f; f=f->next) + { + if (!strcmp(f->filename, filename)) + return f->family; + } + + return ""; +} + +Font::Font(FBFontRenderClass *render, FTC_FaceID faceid, const int isize, const fontmodifier _stylemodifier) +{ + stylemodifier = _stylemodifier; + + frameBuffer = CFrameBuffer::getInstance(); + renderer = render; + font.face_id = faceid; + font.width = isize; + font.height = isize; + //font.image_type = ftc_image_grays; + //font.image_type |= ftc_image_flag_autohinted; + font.flags = FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT; + + scaler.face_id = font.face_id; + scaler.width = isize * 64; + scaler.height = isize * 64; + scaler.pixel = false; + scaler.x_res = render->xres; + scaler.y_res = render->yres; + + setSize(isize); +} + +FT_Error Font::getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit) +{ + return renderer->getGlyphBitmap(&scaler, glyph_index, sbit); +} + +int Font::setSize(int isize) +{ + int temp = font.width; + font.width = font.height = isize; + scaler.width = isize * 64; + scaler.height = isize * 64; + + if (FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size)<0) + { + dprintf(DEBUG_NORMAL, "FTC_Manager_Lookup_Size failed!\n"); + return 0; + } + face = size->face; +#if 0 +//FIXME test + + ascender = face->ascender; + descender = face->descender; + height = face->height; + lower = -descender+(-(descender>>1))+1; +return 0; +#endif + // hack begin (this is a hack to get correct font metrics, didn't find any other way which gave correct values) + FTC_SBit glyph; + int index; + + index=FT_Get_Char_Index(face, 'M'); // "M" gives us ascender + getGlyphBitmap(index, &glyph); + int tM=glyph->top; + fontwidth = glyph->width; + + index=FT_Get_Char_Index(face, 'g'); // "g" gives us descender + getGlyphBitmap(index, &glyph); + int hg=glyph->height; + int tg=glyph->top; + + ascender=tM; + descender=tg-hg; //this is a negative value! + int halflinegap= -(descender>>1); // |descender/2| - we use descender as linegap, half at top, half at bottom + upper = halflinegap+ascender+3; // we add 3 at top + lower = -descender+halflinegap+1; // we add 1 at bottom + height=upper+lower; // this is total height == distance of lines + // hack end + + //printf("glyph: hM=%d tM=%d hg=%d tg=%d ascender=%d descender=%d height=%d linegap/2=%d upper=%d lower=%d\n", + // hM,tM,hg,tg,ascender,descender,height,halflinegap,upper,lower); + //printf("font metrics: height=%ld\n", (size->metrics.height+32) >> 6); + return temp; +} + +int Font::getHeight(void) +{ + return height; +} + +int UTF8ToUnicode(const char * &text, const bool utf8_encoded) // returns -1 on error +{ + int unicode_value; +//printf("%c ", (unsigned char)(*text)); + if (utf8_encoded && ((((unsigned char)(*text)) & 0x80) != 0)) + { + int remaining_unicode_length; + if ((((unsigned char)(*text)) & 0xf8) == 0xf0) + { + unicode_value = ((unsigned char)(*text)) & 0x07; + remaining_unicode_length = 3; + } + else if ((((unsigned char)(*text)) & 0xf0) == 0xe0) + { + unicode_value = ((unsigned char)(*text)) & 0x0f; + remaining_unicode_length = 2; + } + else if ((((unsigned char)(*text)) & 0xe0) == 0xc0) + { + unicode_value = ((unsigned char)(*text)) & 0x1f; + remaining_unicode_length = 1; + } + else // cf.: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return -1; // corrupted character or a character with > 4 bytes utf-8 representation + + for (int i = 0; i < remaining_unicode_length; i++) + { + text++; + if (((*text) & 0xc0) != 0x80) + { + remaining_unicode_length = -1; + return -1; // incomplete or corrupted character + } + unicode_value <<= 6; + unicode_value |= ((unsigned char)(*text)) & 0x3f; + } + if (remaining_unicode_length == -1) + return -1; // incomplete or corrupted character + } + else + unicode_value = (unsigned char)(*text); + + return unicode_value; +} + +void Font::RenderString(int x, int y, const int width, const char *text, const unsigned char color, const int boxheight, const bool utf8_encoded) +{ + if (!frameBuffer->getActive()) + return; + + pthread_mutex_lock( &renderer->render_mutex ); + + if (FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size)<0) + { + dprintf(DEBUG_NORMAL, "FTC_Manager_Lookup_Size failed!\n"); + return; + } + face = size->face; + + int use_kerning=FT_HAS_KERNING(face); + + int left=x; + int step_y=height; + + // ----------------------------------- box upper end (this is NOT a font metric, this is our method for y centering) + // + // ** -------------------------------- y=baseline-upper + // || + // |u --------------------*----------- y=baseline+ascender + // |p * * + // hp * * + // ee * * * * + // ir * * ******* + // g| * * * * + // h| * * * * + // t* -------**--------*-----*-------- y=baseline + // |l * + // |o * + // |w -----**------------------------- y=baseline+descender // descender is a NEGATIVE value + // |r + // ** -------------------------------- y=baseline+lower == YCALLER + // + // ----------------------------------- box lower end (this is NOT a font metric, this is our method for y centering) + + // height = ascender + -1*descender + linegap // descender is negative! + + // now we adjust the given y value (which is the line marked as YCALLER) to be the baseline after adjustment: + y -= lower; + // y coordinate now gives font baseline which is used for drawing + + // caution: this only works if we print a single line of text + // if we have multiple lines, don't use boxheight or specify boxheight==0. + // if boxheight is !=0, we further adjust y, so that text is y-centered in the box + if(boxheight) + { + if(boxheight>step_y) // this is a real box (bigger than text) + y -= ((boxheight-step_y)>>1); + else if(boxheight<0) // this normally would be wrong, so we just use it to define a "border" + y += (boxheight>>1); // half of border value at lower end, half at upper end + } + + int lastindex=0; // 0 == missing glyph (never has kerning values) + FT_Vector kerning; + int pen1=-1; // "pen" positions for kerning, pen2 is "x" + + static fb_pixel_t oldbgcolor = 0, oldfgcolor = 0; + static fb_pixel_t colors[256]; + + fb_pixel_t bgcolor = frameBuffer->realcolor[color]; + fb_pixel_t fgcolor = frameBuffer->realcolor[(((((int)color) + 2) | 7) - 2)]; + + if((oldbgcolor != bgcolor) || (oldfgcolor != fgcolor)) { + + oldbgcolor = bgcolor; + oldfgcolor = fgcolor; + t_fb_var_screeninfo * screeninfo = frameBuffer->getScreenInfo(); + int rl = screeninfo->red.length; + int ro = screeninfo->red.offset; + int gl = screeninfo->green.length; + int go = screeninfo->green.offset; + int bl = screeninfo->blue.length; + int bo = screeninfo->blue.offset; + int tl = screeninfo->transp.length; + int to = screeninfo->transp.offset; + int fgr = (((int)fgcolor >> ro) & ((1 << rl) - 1)); + int fgg = (((int)fgcolor >> go) & ((1 << gl) - 1)); + int fgb = (((int)fgcolor >> bo) & ((1 << bl) - 1)); + int fgt = (((int)fgcolor >> to) & ((1 << tl) - 1)); + int deltar = (((int)bgcolor >> ro) & ((1 << rl) - 1)) - fgr; + int deltag = (((int)bgcolor >> go) & ((1 << gl) - 1)) - fgg; + int deltab = (((int)bgcolor >> bo) & ((1 << bl) - 1)) - fgb; + int deltat = (((int)bgcolor >> to) & ((1 << tl) - 1)) - fgt; + + + for (int i = 0; i < 256; i++) { + colors[255 - i] = + ((((fgr + deltar * i / 255) & ((1 << rl) - 1)) << ro) | + (((fgg + deltag * i / 255) & ((1 << gl) - 1)) << go) | + (((fgb + deltab * i / 255) & ((1 << bl) - 1)) << bo) | + (((fgt + deltat * i / 255) & ((1 << tl) - 1)) << to)); + } + } + + int spread_by = 0; + if (stylemodifier == Font::Embolden) + { + spread_by = (fontwidth / 6) - 1; + if (spread_by < 1) + spread_by = 1; + } + + for (; *text; text++) + { + FTC_SBit glyph; + if (*text=='\n') + { + x = left; + y += step_y; + } + + int unicode_value = UTF8ToUnicode(text, utf8_encoded); + + if (unicode_value == -1) + break; + + int index = FT_Get_Char_Index(face, unicode_value); + + if (!index) + continue; + if (getGlyphBitmap(index, &glyph)) + { + dprintf(DEBUG_NORMAL, "failed to get glyph bitmap.\n"); + continue; + } + + // width clip + if (x + glyph->xadvance + spread_by > left + width) + break; + + //kerning + if(use_kerning) + { + FT_Get_Kerning(face,lastindex,index,0,&kerning); + //x+=(kerning.x+32)>>6; // kerning! + x+=(kerning.x)>>6; // kerning! + } + + #ifndef USE_NEVIS_GXA + int stride = frameBuffer->getStride(); + uint8_t * d = ((uint8_t *)frameBuffer->getFrameBufferPointer()) + (x + glyph->left) * sizeof(fb_pixel_t) + stride * (y - glyph->top); + #endif + uint8_t * s = glyph->buffer; + int w = glyph->width; + int h = glyph->height; + int pitch = glyph->pitch; + + for (int ay=0; aypaintPixel(x + glyph->left + ax, y - glyph->top + ay, colors[*s++]); + #else + *td++= colors[*s++]; + #endif + } + else + { + int start, end; + int color = -1; + + if (ax < w) + start = 0; + else + start = ax - w + 1; + + if (ax < spread_by) + end = ax + 1; + else + end = spread_by + 1; + + for (int i = start; i < end; i++) + if (color < *(s - i)) + color = *(s - i); + #ifdef USE_NEVIS_GXA + frameBuffer->paintPixel(x + glyph->left + ax, y - glyph->top + ay, colors[color]); + #else + *td++= colors[color]; + #endif + s++; + } + } + s += pitch- ax; + #ifndef USE_NEVIS_GXA + d += stride; + #endif + } + x+=glyph->xadvance+1; + //x+=glyph->xadvance; + if(pen1>x) + x=pen1; + pen1=x; + lastindex=index; + } +//printf("RenderStat: %d %d %d \n", renderer->cacheManager->num_nodes, renderer->cacheManager->num_bytes, renderer->cacheManager->max_bytes); + pthread_mutex_unlock( &renderer->render_mutex ); +} + +void Font::RenderString(int x, int y, const int width, const std::string & text, const unsigned char color, const int boxheight, const bool utf8_encoded) +{ + RenderString(x, y, width, text.c_str(), color, boxheight, utf8_encoded); +} + +int Font::getRenderWidth(const char *text, const bool utf8_encoded) +{ + pthread_mutex_lock( &renderer->render_mutex ); + + if (FTC_Manager_LookupSize(renderer->cacheManager, &scaler, &size)<0) + { + dprintf(DEBUG_NORMAL, "FTC_Manager_Lookup_Size failed!\n"); + return -1; + } + face = size->face; + + int use_kerning=FT_HAS_KERNING(face); + int x=0; + int lastindex=0; // 0==missing glyph (never has kerning) + FT_Vector kerning; + int pen1=-1; // "pen" positions for kerning, pen2 is "x" + for (; *text; text++) + { + FTC_SBit glyph; + + int unicode_value = UTF8ToUnicode(text, utf8_encoded); + + if (unicode_value == -1) + break; + + int index=FT_Get_Char_Index(face, unicode_value); + + if (!index) + continue; + if (getGlyphBitmap(index, &glyph)) + { + dprintf(DEBUG_NORMAL, "failed to get glyph bitmap.\n"); + continue; + } + //kerning + if(use_kerning) + { + FT_Get_Kerning(face,lastindex,index,0,&kerning); + x+=(kerning.x+32)>>6; // kerning! + } + + x+=glyph->xadvance+1; + if(pen1>x) + x=pen1; + pen1=x; + lastindex=index; + } + + if (stylemodifier == Font::Embolden) + { + int spread_by = (fontwidth / 6) - 1; + if (spread_by < 1) + spread_by = 1; + + x += spread_by; + } + + pthread_mutex_unlock( &renderer->render_mutex ); + + return x; +} + +int Font::getRenderWidth(const std::string & text, const bool utf8_encoded) +{ + return getRenderWidth(text.c_str(), utf8_encoded); +} diff --git a/src/driver/fontrenderer.h b/src/driver/fontrenderer.h new file mode 100644 index 000000000..17c225f87 --- /dev/null +++ b/src/driver/fontrenderer.h @@ -0,0 +1,124 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Copyright (C) 2003 thegoodguy + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __FONTRENDERER__ +#define __FONTRENDERER__ + +#include +#include + +#include +#include FT_FREETYPE_H +#include FT_CACHE_H + +#include FT_CACHE_IMAGE_H +#include FT_CACHE_SMALL_BITMAPS_H + +#include "framebuffer.h" + + +class FBFontRenderClass; +class Font +{ + CFrameBuffer *frameBuffer; + FTC_ImageTypeRec font; + FBFontRenderClass *renderer; + FT_Face face; + FT_Size size; + FTC_ScalerRec scaler; + + FT_Error getGlyphBitmap(FT_ULong glyph_index, FTC_SBit *sbit); + + // these are HACKED values, because the font metrics were unusable. + int height,ascender,descender,upper,lower; + int fontwidth; + + public: + enum fontmodifier + { + Regular, + Embolden + }; + fontmodifier stylemodifier; + + void RenderString(int x, int y, const int width, const char * text, const unsigned char color, const int boxheight = 0, const bool utf8_encoded = false); + void RenderString(int x, int y, const int width, const std::string & text, const unsigned char color, const int boxheight = 0, const bool utf8_encoded = false); + + int getRenderWidth(const char * text, const bool utf8_encoded = false); + int getRenderWidth(const std::string & text, const bool utf8_encoded = false); + int getHeight(void); + int getSize(){return font.width;} + int setSize(int isize); + + Font(FBFontRenderClass *render, FTC_FaceID faceid, const int isize, const fontmodifier _stylemodifier); + ~Font(){} +}; + +class FBFontRenderClass +{ + struct fontListEntry + { + char *filename, *style, *family; + fontListEntry *next; + ~fontListEntry(); + } + *font; + + FT_Library library; + FTC_Manager cacheManager; /* the cache manager */ + FTC_ImageCache imageCache; /* the glyph image cache */ + FTC_SBitCache sbitsCache; /* the glyph small bitmaps cache */ + + FTC_FaceID getFaceID(const char * const family, const char * const style); + FT_Error getGlyphBitmap(FTC_ImageTypeRec *font, FT_ULong glyph_index, FTC_SBit *sbit); + FT_Error getGlyphBitmap(FTC_ScalerRec *sc, FT_ULong glyph_index, FTC_SBit *sbit); + + int xres; /* the screen resolution in dpi */ + int yres; /* defaults to 72 dpi */ + + public: + pthread_mutex_t render_mutex; + + FT_Error FTC_Face_Requester(FTC_FaceID face_id, FT_Face* aface); + + + static FT_Error myFTC_Face_Requester(FTC_FaceID face_id, + FT_Library library, + FT_Pointer request_data, + FT_Face* aface); + + //FT_Face getFace(const char *family, const char *style); + Font *getFont(const char * const family, const char * const style, int size); + + std::string getFamily(const char * const filename) const; + + const char * const AddFont(const char * const filename, const bool make_italics = false); + + FBFontRenderClass(const int xres = 72, const int yres = 72); + ~FBFontRenderClass(); + + friend class Font; +}; + +#endif diff --git a/src/driver/framebuffer.cpp b/src/driver/framebuffer.cpp new file mode 100644 index 000000000..b57ec4723 --- /dev/null +++ b/src/driver/framebuffer.cpp @@ -0,0 +1,1409 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + 2003 thegoodguy + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +//#include +#include +extern cVideo * videoDecoder; + +extern CPictureViewer * g_PicViewer; +#define BACKGROUNDIMAGEWIDTH 720 + +//#undef USE_NEVIS_GXA //FIXME +/*******************************************************************************/ +#ifdef USE_NEVIS_GXA + +#ifdef GXA_FG_COLOR_REG +#undef GXA_FG_COLOR_REG +#endif +#ifdef GXA_BG_COLOR_REG +#undef GXA_BG_COLOR_REG +#endif +#ifdef GXA_LINE_CONTROL_REG +#undef GXA_LINE_CONTROL_REG +#endif +#ifdef GXA_DEPTH_REG +#undef GXA_DEPTH_REG +#endif +#ifdef GXA_CONTENT_ID_REG +#undef GXA_CONTENT_ID_REG +#endif + +#define GXA_POINT(x, y) (((y) & 0x0FFF) << 16) | ((x) & 0x0FFF) +#define GXA_SRC_BMP_SEL(x) (x << 8) +#define GXA_DST_BMP_SEL(x) (x << 5) +#define GXA_PARAM_COUNT(x) (x << 2) + +#define GXA_FG_COLOR_REG 0x0020 +#define GXA_BG_COLOR_REG 0x0024 +#define GXA_LINE_CONTROL_REG 0x0038 +#define GXA_BMP2_TYPE_REG 0x0050 +#define GXA_BMP2_ADDR_REG 0x0054 +#define GXA_DEPTH_REG 0x00F4 +#define GXA_CONTENT_ID_REG 0x0144 + +#define GXA_CMD_BLT 0x00010800 +#define GXA_CMD_NOT_ALPHA 0x00011000 +#define GXA_CMD_NOT_TEXT 0x00018000 + +/* +static unsigned int _read_gxa(volatile unsigned char *base_addr, unsigned int offset) +{ + return *(volatile unsigned int *)(base_addr + offset); +} +*/ +static void _write_gxa(volatile unsigned char *base_addr, unsigned int offset, unsigned int value) +{ + while( (*(volatile unsigned int *)(base_addr + GXA_DEPTH_REG)) & 0x40000000); + *(volatile unsigned int *)(base_addr + offset) = value; +} + +#endif /* USE_NEVIS_GXA */ + +/*******************************************************************************/ + +static uint8_t * virtual_fb = NULL; +inline unsigned int make16color(uint16_t r, uint16_t g, uint16_t b, uint16_t t, + uint32_t rl = 0, uint32_t ro = 0, + uint32_t gl = 0, uint32_t go = 0, + uint32_t bl = 0, uint32_t bo = 0, + uint32_t tl = 0, uint32_t to = 0) +{ + return ((t << 24) & 0xFF000000) | ((r << 8) & 0xFF0000) | ((g << 0) & 0xFF00) | (b >> 8 & 0xFF); +} + +CFrameBuffer::CFrameBuffer() +: active ( true ) +{ + iconBasePath = ""; + available = 0; + cmap.start = 0; + cmap.len = 256; + cmap.red = red; + cmap.green = green; + cmap.blue = blue; + cmap.transp = trans; + backgroundColor = 0; + useBackgroundPaint = false; + background = NULL; + backupBackground = NULL; + backgroundFilename = ""; + fd = 0; + tty = 0; +//FIXME: test + memset(red, 0, 256*sizeof(__u16)); + memset(green, 0, 256*sizeof(__u16)); + memset(blue, 0, 256*sizeof(__u16)); + memset(trans, 0, 256*sizeof(__u16)); +} + +CFrameBuffer* CFrameBuffer::getInstance() +{ + static CFrameBuffer* frameBuffer = NULL; + + if(!frameBuffer) { + frameBuffer = new CFrameBuffer(); + printf("[neutrino] frameBuffer Instance created\n"); + } else { + //printf("[neutrino] frameBuffer Instace requested\n"); + } + return frameBuffer; +} + +void CFrameBuffer::init(const char * const fbDevice) +{ + fd = open(fbDevice, O_RDWR); + if(!fd) fd = open(fbDevice, O_RDWR); + + if (fd<0) { + perror(fbDevice); + goto nolfb; + } + + if (ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo)<0) { + perror("FBIOGET_VSCREENINFO"); + goto nolfb; + } + + memcpy(&oldscreen, &screeninfo, sizeof(screeninfo)); + + fb_fix_screeninfo fix; + if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)<0) { + perror("FBIOGET_FSCREENINFO"); + goto nolfb; + } + + available=fix.smem_len; + printf("%dk video mem\n", available/1024); + lfb=(fb_pixel_t*)mmap(0, available, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); + + if (!lfb) { + perror("mmap"); + goto nolfb; + } + +#ifdef USE_NEVIS_GXA + /* Open 7dev/mem for HW-register access */ + devmem_fd = open("/dev/mem", O_RDWR | O_SYNC); + if (devmem_fd < 0) { + perror("Unable to open /dev/mem"); + goto nolfb; + } + + /* mmap the GXA's base address */ + gxa_base = (volatile unsigned char*) mmap(0, 0x00040000, PROT_READ | PROT_WRITE, MAP_SHARED, devmem_fd, 0xE0600000); + if (gxa_base == (void*) -1){ + perror("Unable to mmap /dev/mem"); + goto nolfb; + } + + /* tell the GXA where the framebuffer to draw on starts */ + smem_start = (unsigned int) fix.smem_start; + _write_gxa(gxa_base, GXA_BMP2_TYPE_REG, (3 << 16) | screeninfo.xres); + _write_gxa(gxa_base, GXA_BMP2_ADDR_REG, (unsigned int) fix.smem_start); + _write_gxa(gxa_base, GXA_CONTENT_ID_REG, 0); +#endif + +#if 0 + if ((tty=open("/dev/vc/0", O_RDWR))<0) { + perror("open (tty)"); + goto nolfb; + } + + struct sigaction act; + + memset(&act,0,sizeof(act)); + act.sa_handler = switch_signal; + sigemptyset(&act.sa_mask); + sigaction(SIGUSR1,&act,NULL); + sigaction(SIGUSR2,&act,NULL); + + struct vt_mode mode; + + if (-1 == ioctl(tty,KDGETMODE, &kd_mode)) { + perror("ioctl KDGETMODE"); + goto nolfb; + } + + if (-1 == ioctl(tty,VT_GETMODE, &vt_mode)) { + perror("ioctl VT_GETMODE"); + goto nolfb; + } + + if (-1 == ioctl(tty,VT_GETMODE, &mode)) { + perror("ioctl VT_GETMODE"); + goto nolfb; + } + + mode.mode = VT_PROCESS; + mode.waitv = 0; + mode.relsig = SIGUSR1; + mode.acqsig = SIGUSR2; + + if (-1 == ioctl(tty,VT_SETMODE, &mode)) { + perror("ioctl VT_SETMODE"); + goto nolfb; + } + + if (-1 == ioctl(tty,KDSETMODE, KD_GRAPHICS)) { + perror("ioctl KDSETMODE"); + goto nolfb; + } +#endif + + return; + +nolfb: + printf("framebuffer not available.\n"); + lfb=0; +} + + +CFrameBuffer::~CFrameBuffer() +{ + if (background) { + delete[] background; + } + + if (backupBackground) { + delete[] backupBackground; + } + +#if 0 +#ifdef RETURN_FROM_GRAPHICS_MODE + if (-1 == ioctl(tty,KDSETMODE, kd_mode)) + perror("ioctl KDSETMODE"); +#endif + + if (-1 == ioctl(tty,VT_SETMODE, &vt_mode)) + perror("ioctl VT_SETMODE"); + + if (available) + ioctl(fd, FBIOPUT_VSCREENINFO, &oldscreen); +#endif + if (lfb) + munmap(lfb, available); + + if (virtual_fb) + delete[] virtual_fb; + close(fd); + close(tty); +} + +int CFrameBuffer::getFileHandle() const +{ + return fd; +} + +unsigned int CFrameBuffer::getStride() const +{ + return stride; +} + +unsigned int CFrameBuffer::getScreenWidth(bool real) +{ + if(real) + return xRes; + else + return g_settings.screen_EndX - g_settings.screen_StartX; +} + +unsigned int CFrameBuffer::getScreenHeight(bool real) +{ + if(real) + return yRes; + else + return g_settings.screen_EndY - g_settings.screen_StartY; +} + +unsigned int CFrameBuffer::getScreenX() +{ + return g_settings.screen_StartX; +} + +unsigned int CFrameBuffer::getScreenY() +{ + return g_settings.screen_StartY; +} + +fb_pixel_t * CFrameBuffer::getFrameBufferPointer() const +{ + if (active || (virtual_fb == NULL)) + return lfb; + else + return (fb_pixel_t *) virtual_fb; +} + +bool CFrameBuffer::getActive() const +{ + return (active || (virtual_fb != NULL)); +} + +void CFrameBuffer::setActive(bool enable) +{ + active = enable; +} + +t_fb_var_screeninfo *CFrameBuffer::getScreenInfo() +{ + return &screeninfo; +} + +int CFrameBuffer::setMode(unsigned int nxRes, unsigned int nyRes, unsigned int nbpp) +{ + if (!available&&!active) + return -1; + +#if 0 + screeninfo.xres_virtual=screeninfo.xres=nxRes; + screeninfo.yres_virtual=screeninfo.yres=nyRes; + screeninfo.height=0; + screeninfo.width=0; + screeninfo.xoffset=screeninfo.yoffset=0; + screeninfo.bits_per_pixel=nbpp; + + if (ioctl(fd, FBIOPUT_VSCREENINFO, &screeninfo)<0) { + perror("FBIOPUT_VSCREENINFO"); + } + + if(1) { + printf("SetMode: %dbits, red %d:%d green %d:%d blue %d:%d transp %d:%d\n", + screeninfo.bits_per_pixel, screeninfo.red.length, screeninfo.red.offset, screeninfo.green.length, screeninfo.green.offset, screeninfo.blue.length, screeninfo.blue.offset, screeninfo.transp.length, screeninfo.transp.offset); + } + if ((screeninfo.xres!=nxRes) && (screeninfo.yres!=nyRes) && (screeninfo.bits_per_pixel!=nbpp)) + { + printf("SetMode failed: wanted: %dx%dx%d, got %dx%dx%d\n", + nxRes, nyRes, nbpp, + screeninfo.xres, screeninfo.yres, screeninfo.bits_per_pixel); + return -1; + } +#endif + + xRes = screeninfo.xres; + yRes = screeninfo.yres; + bpp = screeninfo.bits_per_pixel; + fb_fix_screeninfo fix; + + if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)<0) { + perror("FBIOGET_FSCREENINFO"); + return -1; + } + + stride = fix.line_length; +printf("FB: %dx%dx%d line lenght %d\n", xRes, yRes, bpp, stride); + + memset(getFrameBufferPointer(), 0, stride * yRes); + if (ioctl(fd, FBIOBLANK, FB_BLANK_UNBLANK) < 0) { + printf("screen unblanking failed\n"); + } + return 0; +} + +void CFrameBuffer::setTransparency( int tr ) +{ +} + +void CFrameBuffer::setBlendLevel(int blev1, int blev2) +{ + unsigned short value = blev1; +#if 0 + if (ioctl(fd, FBIO_CHANGEOPACITY, &value) < 0) + printf("FBIO_CHANGEOPACITY failed.\n"); +#endif +} + +void CFrameBuffer::setAlphaFade(int in, int num, int tr) +{ + for (int i=0; i>16)*level; + *g= ((rgb2&0x00FF00)>>8 )*level; + *b= ((rgb2&0x0000FF) )*level; + *r+=((rgb1&0xFF0000)>>16)*(255-level); + *g+=((rgb1&0x00FF00)>>8 )*(255-level); + *b+=((rgb1&0x0000FF) )*(255-level); +} + +void CFrameBuffer::paletteGenFade(int in, __u32 rgb1, __u32 rgb2, int num, int tr) +{ + for (int i=0; i>8; + cmap.green[i] =(rgb&0x00FF00) ; + cmap.blue[i] =(rgb&0x0000FF)<<8; + cmap.transp[i] = tr; +} + +void CFrameBuffer::paletteSet(struct fb_cmap *map) +{ + if (!active) + return; + + if(map == NULL) + map = &cmap; + + if(bpp == 8) { +//printf("Set palette for %dbit\n", bpp); + ioctl(fd, FBIOPUTCMAP, map); + } + uint32_t rl, ro, gl, go, bl, bo, tl, to; + rl = screeninfo.red.length; + ro = screeninfo.red.offset; + gl = screeninfo.green.length; + go = screeninfo.green.offset; + bl = screeninfo.blue.length; + bo = screeninfo.blue.offset; + tl = screeninfo.transp.length; + to = screeninfo.transp.offset; + for (int i = 0; i < 256; i++) { + realcolor[i] = make16color(cmap.red[i], cmap.green[i], cmap.blue[i], cmap.transp[i], + rl, ro, gl, go, bl, bo, tl, to); + } +} + +#if 0 +void CFrameBuffer::paintBoxRel(const int x, const int y, const int dx, const int dy, const fb_pixel_t col) +{ + if (!getActive()) + return; + + uint8_t * pos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; + for (int count = 0; count < dy; count++) { + fb_pixel_t * dest = (fb_pixel_t *)pos; + for (int i = 0; i < dx; i++) + *(dest++) = col; + pos += stride; + } +} +#endif + +void CFrameBuffer::paintBoxRel(const int x, const int y, const int dx, const int dy, const fb_pixel_t col, int radius, int type) +{ + /* draw a filled rectangle (with additional round corners) */ + + if (!getActive()) + return; + +#ifdef USE_NEVIS_GXA + /* this table contains the x coordinates for a quarter circle (the bottom right quarter) with fixed + radius of 540 px which is the half of the max HD graphics size of 1080 px. So with that table we + ca draw boxes with round corners and als circles by just setting dx = dy = radius (max 540). */ + int q_circle[541] = { + 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, + 540, 540, 540, 540, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, + 539, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 537, 537, 537, 537, 537, 537, 537, + 537, 537, 536, 536, 536, 536, 536, 536, 536, 536, 535, 535, 535, 535, 535, 535, 535, 535, 534, 534, + 534, 534, 534, 534, 533, 533, 533, 533, 533, 533, 532, 532, 532, 532, 532, 532, 531, 531, 531, 531, + 531, 531, 530, 530, 530, 530, 529, 529, 529, 529, 529, 529, 528, 528, 528, 528, 527, 527, 527, 527, + 527, 526, 526, 526, 526, 525, 525, 525, 525, 524, 524, 524, 524, 523, 523, 523, 523, 522, 522, 522, + 522, 521, 521, 521, 521, 520, 520, 520, 519, 519, 519, 518, 518, 518, 518, 517, 517, 517, 516, 516, + 516, 515, 515, 515, 515, 514, 514, 514, 513, 513, 513, 512, 512, 512, 511, 511, 511, 510, 510, 510, + 509, 509, 508, 508, 508, 507, 507, 507, 506, 506, 506, 505, 505, 504, 504, 504, 503, 503, 502, 502, + 502, 501, 501, 500, 500, 499, 499, 499, 498, 498, 498, 497, 497, 496, 496, 496, 495, 495, 494, 494, + 493, 493, 492, 492, 491, 491, 490, 490, 490, 489, 489, 488, 488, 487, 487, 486, 486, 485, 485, 484, + 484, 483, 483, 482, 482, 481, 481, 480, 480, 479, 479, 478, 478, 477, 477, 476, 476, 475, 475, 474, + 473, 473, 472, 472, 471, 471, 470, 470, 469, 468, 468, 467, 466, 466, 465, 465, 464, 464, 463, 462, + 462, 461, 460, 460, 459, 459, 458, 458, 457, 456, 455, 455, 454, 454, 453, 452, 452, 451, 450, 450, + 449, 449, 448, 447, 446, 446, 445, 445, 444, 443, 442, 441, 441, 440, 440, 439, 438, 437, 436, 436, + 435, 435, 434, 433, 432, 431, 431, 430, 429, 428, 427, 427, 426, 425, 425, 424, 423, 422, 421, 421, + 420, 419, 418, 417, 416, 416, 415, 414, 413, 412, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, + 403, 402, 401, 400, 399, 398, 397, 397, 395, 394, 393, 393, 392, 391, 390, 389, 388, 387, 386, 385, + 384, 383, 382, 381, 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, 369, 368, 367, 367, 365, 364, + 363, 362, 361, 360, 358, 357, 356, 355, 354, 353, 352, 351, 350, 348, 347, 346, 345, 343, 342, 341, + 340, 339, 337, 336, 335, 334, 332, 331, 329, 328, 327, 326, 324, 323, 322, 321, 319, 317, 316, 315, + 314, 312, 310, 309, 308, 307, 305, 303, 302, 301, 299, 297, 296, 294, 293, 291, 289, 288, 287, 285, + 283, 281, 280, 278, 277, 275, 273, 271, 270, 268, 267, 265, 263, 261, 259, 258, 256, 254, 252, 250, + 248, 246, 244, 242, 240, 238, 236, 234, 232, 230, 228, 225, 223, 221, 219, 217, 215, 212, 210, 207, + 204, 202, 200, 197, 195, 192, 190, 187, 184, 181, 179, 176, 173, 170, 167, 164, 160, 157, 154, 150, + 147, 144, 140, 136, 132, 128, 124, 120, 115, 111, 105, 101, 95, 89, 83, 77, 69, 61, 52, 40, + 23}; + + int line = 0; + unsigned int cmd = GXA_CMD_NOT_TEXT | GXA_SRC_BMP_SEL(2) | GXA_DST_BMP_SEL(2) | GXA_PARAM_COUNT(2) | GXA_CMD_NOT_ALPHA; + + _write_gxa(gxa_base, GXA_FG_COLOR_REG, (unsigned int) col); /* setup the drawing color */ + _write_gxa(gxa_base, GXA_LINE_CONTROL_REG, 0x00000404); /* X is major axis, skip last pixel */ + + if ((type) && (radius)) + { + #define MUL 32768 /* just an multiplicator for all math to reduce rounding errors */ + int ofs, scf, scl; + + /* limit the radius */ + if (radius > dx) + radius = dx; + if (radius > dy) + radius = dy; + if (radius > 540) + radius = 540; + + scf = (540 * MUL) / radius; + + while (line < dy) + { + ofs = 0; + + if ((line < radius) && (type & 1)) + { + /* uper round corners */ + scl = scf * (radius - line) / MUL; + if ((scf * (radius - line) % MUL) >= (MUL / 2)) /* round up */ + scl++; + ofs = radius - (q_circle[scl] * MUL / scf); + } + else if ((line >= (dy - radius)) && (type & 2)) + { + /* lower round corners */ + scl = scf * (radius - (dy - (line + 1))) / MUL; + if ((scf * (radius - (dy - (line + 1))) % MUL) >= (MUL / 2)) /* round up */ + scl++; + ofs = radius - (q_circle[scl] * MUL / scf); + } + _write_gxa(gxa_base, cmd, GXA_POINT(x + dx - ofs, y + line)); /* endig point */ + _write_gxa(gxa_base, cmd, GXA_POINT(x + ofs, y + line)); /* start point */ + + line++; + } + } + else + { + while (line < dy) + { + _write_gxa(gxa_base, cmd, GXA_POINT(x + dx, y + line)); /* endig point */ + _write_gxa(gxa_base, cmd, GXA_POINT(x, y + line)); /* start point */ + line++; + } + } + +#else + int F,R=radius,sx,sy,dxx=dx,dyy=dy,rx,ry,wx,wy; + + if (!getActive()) + return; + + uint8_t *pos = ((uint8_t *)getFrameBufferPointer()) + x*sizeof(fb_pixel_t) + stride*y; + uint8_t *pos0 = 0, *pos1 = 0, *pos2 = 0, *pos3 = 0; + + fb_pixel_t *dest0, *dest1; + + if(R) { + if(--dyy<=0) { + //if(dyy <= 0) + dyy=1; + } + + if(R==1 || R>(dxx/2) || R>(dyy/2)) { + R=dxx/10; + F=dyy/10; + if(R>F) { + if(R>(dyy/3)) { + R=dyy/3; + } + } else { + R=F; + if(R>(dxx/3)) { + R=dxx/3; + } + } + } + sx=0; + sy=R; + F=1-R; + + rx=R-sx; + ry=R-sy; + + if(type & 1) { + pos1=pos+(ry*stride); // top 1 + pos2=pos+(rx*stride); // top 2 + } + if(type & 2) { + pos0=pos+((dyy-ry)*stride); // bottom 1 + pos3=pos+((dyy-rx)*stride); // bottom 2 + } + while (sx <= sy) { + rx=R-sx; + ry=R-sy; + wx=rx<<1; + wy=ry<<1; + dest0=(fb_pixel_t *)(pos0+rx*sizeof(fb_pixel_t)); + dest1=(fb_pixel_t *)(pos1+rx*sizeof(fb_pixel_t)); + for (int i=0; i<(dxx-wx); i++) { + if(type & 2) + *(dest0++)=col; //bottom 1 + if(type & 1) + *(dest1++)=col; // top 1 + } + dest0=(fb_pixel_t *)(pos2+ry*sizeof(fb_pixel_t)); + dest1=(fb_pixel_t *)(pos3+ry*sizeof(fb_pixel_t)); + for (int i=0; i<(dxx-wy); i++) { + if(type & 1) + *(dest0++)=col; // top 2 + if(type & 2) + *(dest1++)=col; //bottom 2 + } + sx++; + pos2-=stride; + pos3+=stride; + if (F<0) { + F+=(sx<<1)-1; + } else { + F+=((sx-sy)<<1); + sy--; + pos0-=stride; + pos1+=stride; + } + } + if(type & 1) + pos+=R*stride; + } + + int start = R; + int end = dyy - R; + if(!(type & 1)) + start = 0; + if(!(type & 2)) + end = dyy+ (R ? 1 : 0); + +#if 0 + fb_fillrect fillrect; + fillrect.dx = x; + fillrect.dy = y+start; + fillrect.width = dx; + fillrect.height = end; + fillrect.color = col; + fillrect.rop = ROP_COPY; + ioctl(fd, FBIO_FILL_RECT, &fillrect); +#else + for (int count= start; count < end; count++) { + dest0=(fb_pixel_t *)pos; + for (int i=0; iDisplayImage(newname, x, y, 0, 0); + } + struct rawHeader header; + uint16_t width, height; + int fd; +#if 0 // no need if we have whole / as r/w + std::string iconBasePath1 = "/var/share/icons/"; + fd = open((iconBasePath1 + filename).c_str(), O_RDONLY); + if (fd == -1) + fd = open((iconBasePath + filename).c_str(), O_RDONLY); +#endif + fd = open((iconBasePath + filename).c_str(), O_RDONLY); + + if (fd == -1) { + printf("paintIcon: error while loading icon: %s%s\n", iconBasePath.c_str(), filename.c_str()); + return false; + } + + read(fd, &header, sizeof(struct rawHeader)); + + width = (header.width_hi << 8) | header.width_lo; + height = (header.height_hi << 8) | header.height_lo; + + unsigned char pixbuf[768]; + uint8_t * d = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; + fb_pixel_t * d2; + for (int count=0; count> 1 ); + unsigned char *pixpos = &pixbuf[0]; + d2 = (fb_pixel_t *) d; + for (int count2=0; count2> 1; count2 ++ ) { + unsigned char compressed = *pixpos; + unsigned char pix1 = (compressed & 0xf0) >> 4; + unsigned char pix2 = (compressed & 0x0f); + if (pix1 != header.transp) { + paintPixel(d2, pix1 + offset); + } + d2++; + if (pix2 != header.transp) { + paintPixel(d2, pix2 + offset); + } + d2++; + pixpos++; + } + d += stride; + } + + close(fd); + return true; +} + +bool CFrameBuffer::paintIcon(const char * const filename, const int x, const int y, const unsigned char offset) +{ +//printf("%s(%s, %d, %d, %d)\n", __FUNCTION__, filename, x, y, offset); + return paintIcon(std::string(filename), x, y, offset); +} + +void CFrameBuffer::loadPal(const std::string & filename, const unsigned char offset, const unsigned char endidx) +{ + if (!getActive()) + return; + +//printf("%s()\n", __FUNCTION__); + + struct rgbData rgbdata; + int fd; + + fd = open((iconBasePath + filename).c_str(), O_RDONLY); + + if (fd == -1) { + printf("error while loading palette: %s%s\n", iconBasePath.c_str(), filename.c_str()); + return; + } + + int pos = 0; + int readb = read(fd, &rgbdata, sizeof(rgbdata) ); + while(readb) { + __u32 rgb = (rgbdata.r<<16) | (rgbdata.g<<8) | (rgbdata.b); + int colpos = offset+pos; + if( colpos>endidx) + break; + + paletteSetColor(colpos, rgb, 0xFF); + readb = read(fd, &rgbdata, sizeof(rgbdata) ); + pos++; + } + paletteSet(&cmap); + close(fd); +} + +void CFrameBuffer::paintPixel(const int x, const int y, const fb_pixel_t col) +{ + if (!getActive()) + return; + + #ifdef USE_NEVIS_GXA + paintHLineRel(x, 1, y, col); + #else + fb_pixel_t * pos = getFrameBufferPointer(); + pos += (stride / sizeof(fb_pixel_t)) * y; + pos += x; + + *pos = col; + #endif +} + +void CFrameBuffer::paintLine(int xa, int ya, int xb, int yb, const fb_pixel_t col) +{ + if (!getActive()) + return; + +//printf("%s(%d, %d, %d, %d, %.8X)\n", __FUNCTION__, xa, ya, xb, yb, col); + + int dx = abs (xa - xb); + int dy = abs (ya - yb); + int x; + int y; + int End; + int step; + + if ( dx > dy ) + { + int p = 2 * dy - dx; + int twoDy = 2 * dy; + int twoDyDx = 2 * (dy-dx); + + if ( xa > xb ) + { + x = xb; + y = yb; + End = xa; + step = ya < yb ? -1 : 1; + } + else + { + x = xa; + y = ya; + End = xb; + step = yb < ya ? -1 : 1; + } + + paintPixel (x, y, col); + + while( x < End ) + { + x++; + if ( p < 0 ) + p += twoDy; + else + { + y += step; + p += twoDyDx; + } + paintPixel (x, y, col); + } + } + else + { + int p = 2 * dx - dy; + int twoDx = 2 * dx; + int twoDxDy = 2 * (dx-dy); + + if ( ya > yb ) + { + x = xb; + y = yb; + End = ya; + step = xa < xb ? -1 : 1; + } + else + { + x = xa; + y = ya; + End = yb; + step = xb < xa ? -1 : 1; + } + + paintPixel (x, y, col); + + while( y < End ) + { + y++; + if ( p < 0 ) + p += twoDx; + else + { + x += step; + p += twoDxDy; + } + paintPixel (x, y, col); + } + } +} + +void CFrameBuffer::setBackgroundColor(const fb_pixel_t color) +{ + backgroundColor = color; +} + +bool CFrameBuffer::loadPictureToMem(const std::string & filename, const uint16_t width, const uint16_t height, const uint16_t stride, fb_pixel_t * memp) +{ + struct rawHeader header; + int fd; + +//printf("%s(%d, %d, memp)\n", __FUNCTION__, width, height); + + fd = open((iconBasePath + filename).c_str(), O_RDONLY ); + + if (fd == -1) + { + printf("error while loading icon: %s%s\n", iconBasePath.c_str(), filename.c_str()); + return false; + } + + read(fd, &header, sizeof(struct rawHeader)); + + if ((width != ((header.width_hi << 8) | header.width_lo)) || + (height != ((header.height_hi << 8) | header.height_lo))) + { + printf("error while loading icon: %s - invalid resolution = %hux%hu\n", filename.c_str(), width, height); + return false; + } + + if ((stride == 0) || (stride == width * sizeof(fb_pixel_t))) + read(fd, memp, height * width * sizeof(fb_pixel_t)); + else + for (int i = 0; i < height; i++) + read(fd, ((uint8_t *)memp) + i * stride, width * sizeof(fb_pixel_t)); + + close(fd); + return true; +} + +bool CFrameBuffer::loadPicture2Mem(const std::string & filename, fb_pixel_t * memp) +{ + return loadPictureToMem(filename, BACKGROUNDIMAGEWIDTH, 576, 0, memp); +} + +bool CFrameBuffer::loadPicture2FrameBuffer(const std::string & filename) +{ + if (!getActive()) + return false; + + return loadPictureToMem(filename, BACKGROUNDIMAGEWIDTH, 576, getStride(), getFrameBufferPointer()); +} + +bool CFrameBuffer::savePictureFromMem(const std::string & filename, const fb_pixel_t * const memp) +{ + struct rawHeader header; + uint16_t width, height; + int fd; + + width = BACKGROUNDIMAGEWIDTH; + height = 576; + + header.width_lo = width & 0xFF; + header.width_hi = width >> 8; + header.height_lo = height & 0xFF; + header.height_hi = height >> 8; + header.transp = 0; + + fd = open((iconBasePath + filename).c_str(), O_WRONLY | O_CREAT); + + if (fd==-1) + { + printf("error while saving icon: %s%s", iconBasePath.c_str(), filename.c_str() ); + return false; + } + + write(fd, &header, sizeof(struct rawHeader)); + + write(fd, memp, width * height * sizeof(fb_pixel_t)); + + close(fd); + return true; +} + +bool CFrameBuffer::loadBackground(const std::string & filename, const unsigned char offset) +{ + if ((backgroundFilename == filename) && (background)) + return true; + + if (background) + delete[] background; + + background = new fb_pixel_t[BACKGROUNDIMAGEWIDTH * 576]; + + if (!loadPictureToMem(filename, BACKGROUNDIMAGEWIDTH, 576, 0, background)) + { + delete[] background; + background=0; + return false; + } + + if (offset != 0)//pic-offset + { + fb_pixel_t * bpos = background; + int pos = BACKGROUNDIMAGEWIDTH * 576; + while (pos > 0) + { + *bpos += offset; + bpos++; + pos--; + } + } + + fb_pixel_t * dest = background + BACKGROUNDIMAGEWIDTH * 576; + uint8_t * src = ((uint8_t * )background)+ BACKGROUNDIMAGEWIDTH * 576; + for (int i = 576 - 1; i >= 0; i--) + for (int j = BACKGROUNDIMAGEWIDTH - 1; j >= 0; j--) + { + dest--; + src--; + paintPixel(dest, *src); + } + backgroundFilename = filename; + + return true; +} + +bool CFrameBuffer::loadBackgroundPic(const std::string & filename, bool show) +{ + if ((backgroundFilename == filename) && (background)) + return true; + +//printf("loadBackgroundPic: %s\n", filename.c_str()); + if (background) + delete[] background; + + background = g_PicViewer->getImage(iconBasePath + filename, BACKGROUNDIMAGEWIDTH, 576); + + if (background == NULL) { + background=0; + return false; + } + + backgroundFilename = filename; + if(show) { + useBackgroundPaint = true; + paintBackground(); + } + return true; +} + +void CFrameBuffer::useBackground(bool ub) +{ + useBackgroundPaint = ub; + if(!useBackgroundPaint) { + delete[] background; + background=0; + } +} + +bool CFrameBuffer::getuseBackground(void) +{ + return useBackgroundPaint; +} + +void CFrameBuffer::saveBackgroundImage(void) +{ + if (backupBackground != NULL) + delete[] backupBackground; + + backupBackground = background; + //useBackground(false); // <- necessary since no background is available + useBackgroundPaint = false; + background = NULL; +} + +void CFrameBuffer::restoreBackgroundImage(void) +{ + fb_pixel_t * tmp = background; + + if (backupBackground != NULL) + { + background = backupBackground; + backupBackground = NULL; + } + else + useBackground(false); // <- necessary since no background is available + + if (tmp != NULL) + delete[] tmp; +} + +void CFrameBuffer::paintBackgroundBoxRel(int x, int y, int dx, int dy) +{ + if (!getActive()) + return; + + if(!useBackgroundPaint) + { + paintBoxRel(x, y, dx, dy, backgroundColor); + } + else + { + uint8_t * fbpos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; + fb_pixel_t * bkpos = background + x + BACKGROUNDIMAGEWIDTH * y; + for(int count = 0;count < dy; count++) + { + memcpy(fbpos, bkpos, dx * sizeof(fb_pixel_t)); + fbpos += stride; + bkpos += BACKGROUNDIMAGEWIDTH; + } + } +} + +void CFrameBuffer::paintBackground() +{ + if (!getActive()) + return; + + if (useBackgroundPaint && (background != NULL)) + { + for (int i = 0; i < 576; i++) + memcpy(((uint8_t *)getFrameBufferPointer()) + i * stride, (background + i * BACKGROUNDIMAGEWIDTH), BACKGROUNDIMAGEWIDTH * sizeof(fb_pixel_t)); + } + else + { + paintBoxRel(0, 0, xRes, yRes, backgroundColor); + } +} + +void CFrameBuffer::SaveScreen(int x, int y, int dx, int dy, fb_pixel_t * const memp) +{ + if (!getActive()) + return; + + uint8_t * pos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; + fb_pixel_t * bkpos = memp; + for (int count = 0; count < dy; count++) { + fb_pixel_t * dest = (fb_pixel_t *)pos; + for (int i = 0; i < dx; i++) + //*(dest++) = col; + *(bkpos++) = *(dest++); + pos += stride; + } +#if 0 //FIXME test to flush cache + if (ioctl(fd, 1, FB_BLANK_UNBLANK) < 0); +#endif + //RestoreScreen(x, y, dx, dy, memp); //FIXME +#if 0 + uint8_t * fbpos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; + fb_pixel_t * bkpos = memp; + for (int count = 0; count < dy; count++) + { + memcpy(bkpos, fbpos, dx * sizeof(fb_pixel_t)); + fbpos += stride; + bkpos += dx; + } +#endif + +} + +void CFrameBuffer::RestoreScreen(int x, int y, int dx, int dy, fb_pixel_t * const memp) +{ + if (!getActive()) + return; + + uint8_t * fbpos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; + fb_pixel_t * bkpos = memp; + for (int count = 0; count < dy; count++) + { + memcpy(fbpos, bkpos, dx * sizeof(fb_pixel_t)); + fbpos += stride; + bkpos += dx; + } +} + +void CFrameBuffer::switch_signal (int signal) +{ + CFrameBuffer * thiz = CFrameBuffer::getInstance(); + if (signal == SIGUSR1) { + if (virtual_fb != NULL) + delete[] virtual_fb; + virtual_fb = new uint8_t[thiz->stride * thiz->yRes]; + thiz->active = false; + if (virtual_fb != NULL) + memcpy(virtual_fb, thiz->lfb, thiz->stride * thiz->yRes); + ioctl(thiz->tty, VT_RELDISP, 1); + printf ("release display\n"); + } + else if (signal == SIGUSR2) { + ioctl(thiz->tty, VT_RELDISP, VT_ACKACQ); + thiz->active = true; + printf ("acquire display\n"); + thiz->paletteSet(NULL); + if (virtual_fb != NULL) + memcpy(thiz->lfb, virtual_fb, thiz->stride * thiz->yRes); + else + memset(thiz->lfb, 0, thiz->stride * thiz->yRes); + } +} + +void CFrameBuffer::ClearFrameBuffer() +{ + int tr; + + tr = 0xFF; + //paletteSetColor(0, 0xFFFFFF, 0xFF); + //Windows Colors + paletteSetColor(0x1, 0x010101, tr); + paletteSetColor(0x2, 0x800000, tr); + paletteSetColor(0x3, 0x008000, tr); + paletteSetColor(0x4, 0x808000, tr); + paletteSetColor(0x5, 0x000080, tr); + paletteSetColor(0x6, 0x800080, tr); + paletteSetColor(0x7, 0x008080, tr); + paletteSetColor(0x8, 0xA0A0A0, tr); + paletteSetColor(0x9, 0x505050, tr); + paletteSetColor(0xA, 0xFF0000, tr); + paletteSetColor(0xB, 0x00FF00, tr); + paletteSetColor(0xC, 0xFFFF00, tr); + paletteSetColor(0xD, 0x0000FF, tr); + paletteSetColor(0xE, 0xFF00FF, tr); + paletteSetColor(0xF, 0x00FFFF, tr); + paletteSetColor(0x10, 0xFFFFFF, tr); + paletteSetColor(0x11, 0x000000, tr); + useBackground(false); + + paintBackground(); + + //background + paletteSetColor(COL_BACKGROUND, 0x000000, 0xffff); + + paletteSet(); +} + +void CFrameBuffer::showFrame(const std::string & filename) +{ + std::string varpath = "/var/tuxbox/config/neutrino/icons/"; + if(!access((varpath + filename).c_str(), F_OK)) + videoDecoder->ShowPicture((varpath + filename).c_str()); + else + videoDecoder->ShowPicture((iconBasePath + filename).c_str()); +} diff --git a/src/driver/framebuffer.h b/src/driver/framebuffer.h new file mode 100644 index 000000000..e76f75f12 --- /dev/null +++ b/src/driver/framebuffer.h @@ -0,0 +1,198 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __framebuffer__ +#define __framebuffer__ +#include + +#include +#include + +#include +#include + +#define fb_pixel_t uint32_t + +typedef struct fb_var_screeninfo t_fb_var_screeninfo; + +#if 0 +#define CORNER_TOP_LEFT 0x1 +#define CORNER_TOP_RIGHT 0x2 +#define CORNER_TOP 0x3 +#define CORNER_BOTTOM_RIGHT 0x4 +#define CORNER_RIGHT 0x6 +#define CORNER_BOTTOM_LEFT 0x8 +#define CORNER_LEFT 0x9 +#define CORNER_BOTTOM 0xC +#endif + +#define CORNER_TOP 0x1 +#define CORNER_BOTTOM 0x2 +#define CORNER_BOTH 0x3 + +/** Ausführung als Singleton */ +class CFrameBuffer +{ + private: + + CFrameBuffer(); + + struct rgbData + { + uint8_t r; + uint8_t g; + uint8_t b; + } __attribute__ ((packed)); + + struct rawHeader + { + uint8_t width_lo; + uint8_t width_hi; + uint8_t height_lo; + uint8_t height_hi; + uint8_t transp; + } __attribute__ ((packed)); + + std::string iconBasePath; + + int fd, tty; + fb_pixel_t * lfb; + int available; + fb_pixel_t * background; + fb_pixel_t * backupBackground; + fb_pixel_t backgroundColor; + std::string backgroundFilename; + bool useBackgroundPaint; + unsigned int xRes, yRes, stride, bpp; + t_fb_var_screeninfo screeninfo, oldscreen; + fb_cmap cmap; + __u16 red[256], green[256], blue[256], trans[256]; + + void paletteFade(int i, __u32 rgb1, __u32 rgb2, int level); + + int kd_mode; + struct vt_mode vt_mode; + bool active; + static void switch_signal (int); + + #ifdef USE_NEVIS_GXA + int devmem_fd; /* to access the GXA register we use /dev/mem */ + unsigned int smem_start; /* as aquired from the fbdev, the framebuffers physical start address */ + volatile uint8_t *gxa_base; /* base address for the GXA's register access */ + #endif /* USE_NEVIS_GXA */ + public: +#ifndef FB_USE_PALETTE + fb_pixel_t realcolor[256]; +#endif + + ~CFrameBuffer(); + + static CFrameBuffer* getInstance(); + + void init(const char * const fbDevice = "/dev/fb/0"); + int setMode(unsigned int xRes, unsigned int yRes, unsigned int bpp); + + + int getFileHandle() const; //only used for plugins (games) !! + t_fb_var_screeninfo *getScreenInfo(); + + fb_pixel_t * getFrameBufferPointer() const; // pointer to framebuffer + unsigned int getStride() const; // size of a single line in the framebuffer (in bytes) + unsigned int getScreenWidth(bool real = false); + unsigned int getScreenHeight(bool real = false); + unsigned int getScreenX(); + unsigned int getScreenY(); + + bool getActive() const; // is framebuffer active? + void setActive(bool enable); // is framebuffer active? + + void setTransparency( int tr = 0 ); + void setBlendLevel(int blev1, int blev2); + + //Palette stuff + void setAlphaFade(int in, int num, int tr); + void paletteGenFade(int in, __u32 rgb1, __u32 rgb2, int num, int tr=0); + void paletteSetColor(int i, __u32 rgb, int tr); + void paletteSet(struct fb_cmap *map = NULL); + + //paint functions + inline void paintPixel(fb_pixel_t * const dest, const uint8_t color) const + { +#ifdef FB_USE_PALETTE + *dest = color; +#else + *dest = realcolor[color]; +#endif + }; + void paintPixel(int x, int y, const fb_pixel_t col); + + void paintBoxRel(const int x, const int y, const int dx, const int dy, const fb_pixel_t col, int radius = 0, int type = 0); + inline void paintBox(int xa, int ya, int xb, int yb, const fb_pixel_t col) { paintBoxRel(xa, ya, xb - xa, yb - ya, col); } + inline void paintBox(int xa, int ya, int xb, int yb, const fb_pixel_t col, int radius, int type) { paintBoxRel(xa, ya, xb - xa, yb - ya, col, radius, type); } + + void paintLine(int xa, int ya, int xb, int yb, const fb_pixel_t col); + + void paintVLine(int x, int ya, int yb, const fb_pixel_t col); + void paintVLineRel(int x, int y, int dy, const fb_pixel_t col); + + void paintHLine(int xa, int xb, int y, const fb_pixel_t col); + void paintHLineRel(int x, int dx, int y, const fb_pixel_t col); + + + void setIconBasePath(const std::string & iconPath); + + bool paintIcon (const char * const filename, const int x, const int y, const unsigned char offset = 1); + bool paintIcon (const std::string & filename, const int x, const int y, const unsigned char offset = 1); + bool paintIcon8(const std::string & filename, const int x, const int y, const unsigned char offset = 0); + void loadPal (const std::string & filename, const unsigned char offset = 0, const unsigned char endidx = 255); + + bool loadPicture2Mem (const std::string & filename, fb_pixel_t * const memp); + bool loadPicture2FrameBuffer(const std::string & filename); + bool loadPictureToMem (const std::string & filename, const uint16_t width, const uint16_t height, const uint16_t stride, fb_pixel_t * const memp); + bool savePictureFromMem (const std::string & filename, const fb_pixel_t * const memp); + + int getBackgroundColor() { return backgroundColor;} + void setBackgroundColor(const fb_pixel_t color); + bool loadBackground(const std::string & filename, const unsigned char col = 0); + void useBackground(bool); + bool getuseBackground(void); + + void saveBackgroundImage(void); // <- implies useBackground(false); + void restoreBackgroundImage(void); + + void paintBackgroundBoxRel(int x, int y, int dx, int dy); + inline void paintBackgroundBox(int xa, int ya, int xb, int yb) { paintBackgroundBoxRel(xa, ya, xb - xa, yb - ya); } + + void paintBackground(); + + void SaveScreen(int x, int y, int dx, int dy, fb_pixel_t * const memp); + void RestoreScreen(int x, int y, int dx, int dy, fb_pixel_t * const memp); + + void ClearFrameBuffer(); + void showFrame(const std::string & filename); + bool loadBackgroundPic(const std::string & filename, bool show = true); +}; + + +#endif diff --git a/src/driver/genpsi.c b/src/driver/genpsi.c new file mode 100644 index 000000000..0a0ee923d --- /dev/null +++ b/src/driver/genpsi.c @@ -0,0 +1,282 @@ +/* +$Id: genpsi.c,v 1.2 2006/01/16 12:45:54 sat_man Exp $ + + Copyright (c) 2004 gmo18t, Germany. All rights reserved. + + aktuelle Versionen gibt es hier: + $Source: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/genpsi.c,v $ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 675 Mass Ave, Cambridge MA 02139, USA. + + Mit diesem Programm koennen Neutrino TS Streams für das Abspielen unter Enigma gepatched werden + */ +//#include +#include +#include +#include + +#define SIZE_TS_PKT 188 +#define OFS_HDR_2 5 +#define OFS_PMT_DATA 13 +#define OFS_STREAM_TAB 17 +#define SIZE_STREAM_TAB_ROW 5 +#define OFS_ENIGMA_TAB 31 +#define SIZE_ENIGMA_TAB_ROW 4 + +#define ES_TYPE_MPEG12 0x02 +#define ES_TYPE_AVC 0x1b +#define ES_TYPE_MPA 0x03 +#define ES_TYPE_AC3 0x81 + +typedef struct +{ + short nba; + uint16_t vpid; + uint8_t vtype; + uint16_t apid[10]; + short isAC3[10]; +} T_AV_PIDS; + +T_AV_PIDS avPids; + +static const uint32_t crc_table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +uint32_t calc_crc32psi(uint8_t *dst, const uint8_t *src, uint32_t len) +{ + uint32_t i; + uint32_t crc = 0xffffffff; + + for (i=0; i> 24) ^ *src++) & 0xff]; + + if (dst) + { + dst[0] = (crc >> 24) & 0xff; + dst[1] = (crc >> 16) & 0xff; + dst[2] = (crc >> 8) & 0xff; + dst[3] = (crc) & 0xff; + } + + return crc; +} + +void transfer_pids(uint16_t pid,uint16_t pidart,short isAC3) +{ + switch(pidart) + { + case EN_TYPE_VIDEO: + avPids.vpid=pid; + avPids.vtype = ES_TYPE_MPEG12; + break; + case EN_TYPE_AVC: + avPids.vpid=pid; + avPids.vtype = ES_TYPE_AVC; + break; + case EN_TYPE_AUDIO: + avPids.apid[avPids.nba]=pid; + avPids.isAC3[avPids.nba]=isAC3; + avPids.nba++; + break; + case EN_TYPE_TELTEX: + break; + + default: + break; + } +} +//-- special enigma stream description packet for -- +//-- at least 1 video, 1 audo and 1 PCR-Pid stream -- +//------------------------------------------------------------------------------------ +static uint8_t pkt_enigma[] = +{ + 0x47, 0x40, 0x1F, 0x10, 0x00, + 0x7F, 0x80, 0x24, + 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x6D, 0x66, 0x30, 0x19, + 0x80, 0x13, 'N','E','U','T','R','I','N','O','N','G', // tag(8), len(8), text(10) -> NG hihi ;) + 0x00, 0x02, 0x00, 0x6e, // cVPID(8), len(8), PID(16) + 0x01, 0x03, 0x00, 0x78, 0x00, // cAPID(8), len(8), PID(16), ac3flag(8) +// 0x02, 0x02, 0x00, 0x82,// cTPID(8), len(8), ... + 0x03, 0x02, 0x00, 0x6e // cPCRPID(8), ... +}; +//-- PAT packet for at least 1 PMT -- +//---------------------------------------------------------- +static uint8_t pkt_pat[] = +{ + 0x47, 0x40, 0x00, 0x10, 0x00, // HEADER-1 + 0x00, 0xB0, 0x0D, // HEADER-2 + 0x04, 0x37, 0xE9, 0x00, 0x00, // HEADER-3 sid + 0x6D, 0x66, 0xEF, 0xFF, // PAT-DATA - PMT (PID=0xFFF) entry +}; + +//-- PMT packet for at least 1 video and 1 audio stream -- +//-------------------------------------------------------- +static uint8_t pkt_pmt[] = +{ + 0x47, 0x4F, 0xFF, 0x10, 0x00, // HEADER-1 + 0x02, 0xB0, 0x17, // HEADER-2 + 0x6D, 0x66, 0xE9, 0x00, 0x00, // HEADER-3 + 0xE0, 0x00, 0xF0, 0x00, // PMT-DATA + 0x02, 0xE0, 0x00, 0xF0, 0x00, // (video stream 1) + 0x03, 0xE0, 0x00, 0xF0, 0x00 // (audio stream 1) +}; + + +//== setup a new TS packet with format == +//== predefined with a template == +//======================================= +#define COPY_TEMPLATE(dst, src) copy_template(dst, src, sizeof(src)) + +static int copy_template(uint8_t *dst, uint8_t *src, int len) +{ +//-- reset buffer -- + memset(dst, 0xFF, SIZE_TS_PKT); +//-- copy PMT template -- + memcpy(dst, src, len); + + return len; +} +int genpsi(int fd2) +{ + int bytes = 0; + uint8_t pkt[SIZE_TS_PKT]; + int i, data_len, patch_len, ofs; + +//-- copy "Enigma"-template -- + data_len = COPY_TEMPLATE(pkt, pkt_enigma); + +//-- adjust len dependent to number of audio streams -- + data_len += ((SIZE_ENIGMA_TAB_ROW+1) * (avPids.nba-1)); + + patch_len = data_len - OFS_HDR_2 + 1; + pkt[OFS_HDR_2+1] |= (patch_len>>8); + pkt[OFS_HDR_2+2] = (patch_len & 0xFF); +//-- write row with desc. for video stream -- + ofs = OFS_ENIGMA_TAB; + pkt[ofs] = EN_TYPE_VIDEO; + pkt[ofs+1] = 0x02; + pkt[ofs+2] = (avPids.vpid>>8); + pkt[ofs+3] = (avPids.vpid & 0xFF); +//-- for each audio stream, write row with desc. -- + ofs += SIZE_ENIGMA_TAB_ROW; + for (i=0; i>8); + pkt[ofs+3] = (avPids.apid[i] & 0xFF); + pkt[ofs+4] = (avPids.isAC3[i]==1)? 0x01 : 0x00; + + ofs += (SIZE_ENIGMA_TAB_ROW + 1); + } +//-- write row with desc. for pcr stream (eq. video) -- + pkt[ofs] = EN_TYPE_PCR; + pkt[ofs+1] = 0x02; + pkt[ofs+2] = (avPids.vpid>>8); + pkt[ofs+3] = (avPids.vpid & 0xFF); + +//-- calculate CRC -- + calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 ); +//-- write TS packet -- + bytes += write(fd2, pkt, SIZE_TS_PKT); +//-- (II) build PAT -- + data_len = COPY_TEMPLATE(pkt, pkt_pat); +//-- calculate CRC -- + calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 ); +//-- write TS packet -- + bytes += write(fd2, pkt, SIZE_TS_PKT); + +//-- (III) build PMT -- + data_len = COPY_TEMPLATE(pkt, pkt_pmt); +//-- adjust len dependent to count of audio streams -- + data_len += (SIZE_STREAM_TAB_ROW * (avPids.nba-1)); + patch_len = data_len - OFS_HDR_2 + 1; + pkt[OFS_HDR_2+1] |= (patch_len>>8); + pkt[OFS_HDR_2+2] = (patch_len & 0xFF); +//-- patch pcr PID -- + ofs = OFS_PMT_DATA; + pkt[ofs] |= (avPids.vpid>>8); + pkt[ofs+1] = (avPids.vpid & 0xFF); +//-- write row with desc. for ES video stream -- + ofs = OFS_STREAM_TAB; + pkt[ofs] = avPids.vtype; + pkt[ofs+1] = 0xE0 | (avPids.vpid>>8); + pkt[ofs+2] = (avPids.vpid & 0xFF); + pkt[ofs+3] = 0xF0; + pkt[ofs+4] = 0x00; + +//-- for each ES audio stream, write row with desc. -- + for (i=0; i>8); + pkt[ofs+2] = (avPids.apid[i] & 0xFF); + pkt[ofs+3] = 0xF0; + pkt[ofs+4] = 0x00; + } +//-- calculate CRC -- + calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 ); +//-- write TS packet -- + bytes += write(fd2, pkt, SIZE_TS_PKT); +//-- finish -- + avPids.vpid=0; + avPids.nba=0; + return 1; +} diff --git a/src/driver/genpsi.h b/src/driver/genpsi.h new file mode 100644 index 000000000..113eb883b --- /dev/null +++ b/src/driver/genpsi.h @@ -0,0 +1,38 @@ +/* +$Id: genpsi.h,v 1.1 2005/08/15 14:47:52 metallica Exp $ + + Copyright (c) 2004 gmo18t, Germany. All rights reserved. + + aktuelle Versionen gibt es hier: + $Source: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/genpsi.h,v $ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 675 Mass Ave, Cambridge MA 02139, USA. + + Mit diesem Programm koennen Neutrino TS Streams für das Abspielen unter Enigma gepatched werden + */ +#ifndef __genpsi_h__ +#define __genpsi_h__ +#include + +int genpsi(int fd2); +void transfer_pids(uint16_t pid,uint16_t pidart,short isAC3); + +#define EN_TYPE_VIDEO 0x00 +#define EN_TYPE_AUDIO 0x01 +#define EN_TYPE_TELTEX 0x02 +#define EN_TYPE_PCR 0x03 +#define EN_TYPE_AVC 0x04 + +#endif diff --git a/src/driver/netfile.cpp b/src/driver/netfile.cpp new file mode 100644 index 000000000..dde135483 --- /dev/null +++ b/src/driver/netfile.cpp @@ -0,0 +1,2023 @@ +/******************************************************************************\ +| Neutrino-GUI - DBoxII-Project +| +| Copyright (C) 2004 by Sanaia +| netfile - remote file access mapper +| +| +| description: +| netfile - a URL capable wrapper for the fopen() call +| +| usage: +| include 'netfile.h' in your code as *LAST* file after all other +| include files and add netfile.c to your sources. That's it. The +| include file maps the common fopen() call onto a URL capable +| version that handles files hosted on http servers like local ones. +| +| +| examples: +| +| automatic redirection example: +| +| fd = fopen("remotefile.url", "r"); +| +| This is a pretty straight forward implementation that should +| even work with applications which refuse to accept filenames +| starting with protocol headers (i.e. 'http://'). If the +| given file ends with '.url', then the file is opened and read +| and its content is assumed to be a valid URL which opened then. +| This works for all protocols provided by this code, e.g. 'http://', +| 'icy://' and 'scast://' +| All restrictions apply for the protocols themself as follows. +| +| +| http example: +| +| fd = fopen("http://find.me:666/somewhere/foo.bar", "r"); +| +| This opens the specified file on a webserver (read only). +| NOTE: the stream itself is bidirectional, you can write +| into it (e.g. commands for communication with the server), +| but this is neither supported nor recommended. The result +| of such an action is rather undefined. You *CAN NOT* make +| any changes to the file of the webserver ! +| +| +| shoutcast example: +| +| fd = fopen("scast://666", "r"); +| +| This opens a shoutcast sation; all you need to know is the +| station number. The query of the shoutcast directory and the +| lookup of a working server is done automatically. The stream +| is opened read-only. +| I recommend this for official shoutcast stations. +| +| shoutcast example: +| +| fd = fopen("icy://find.me:666/funky/station/", "r"); +| or +| fd = fopen("icy://username:password@find.me:666/station", "r"); +| +| This is a low level mechanism that can be used for all +| shoutcast servers, but it mainly is intended to be used for +| private radio stations which are not listed in the official +| shoutcast directory. The stream is opened read-only. +| The second format contains a basic authentication string before '@' +| of username:passwort to be sent to the server. +| +| file access modes, selectable by the fopen 'access type': +| +| "r" read only, stream caching enabled +| "rc" read only, stream caching disabled (compatibility mode) +| +| NOTE: All network accesses are only possible read only. Although some +| protocols could allow write access to the remote resource, this +| is not (and rather unlikely to be anytime) implemented here. +| All remote accesses are made through a FIFO caching mechanism that +| uses read-ahead caching (as far as possible). The fopen() call starts +| a background fetching thread that fills the cache up to the ceiling. +| +| +| License: GPL +| +| This program is free software; you can redistribute it and/or modify +| it under the terms of the GNU General Public License as published by +| the Free Software Foundation; either version 2 of the License, or +| (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with this program; if not, write to the Free Software +| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +| +\******************************************************************************/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "netfile.h" +#include "global.h" +#include +#include +#include +/* +TODO: + - ICECAST support + - follow redirection errors (server error codes 302, 301) (done for HTTP, 2005-05-16 ChakaZulu) + - support for automatic playlist processing (shoutcast pls files) + +known bugs: + - HTTP POST requests - are implemented, but don't work with shoutcast.com !? +*/ + +#define STATIC /**/ + +#ifdef fopen + #undef fopen +#endif +#ifdef fclose + #undef fclose +#endif +#ifdef fread + #undef fread +#endif +#ifdef ftell + #undef ftell +#endif +#ifdef rewind + #undef rewind +#endif +#ifdef fseek + #undef fseek +#endif + + + + +typedef struct +{ + const unsigned char mask[4]; + const unsigned char mode[4]; + const char *type; +} magic_t; + +magic_t known_magic[] = +{ + {{0xFF, 0xFF, 0xFF, 0x00}, {'I' , 'D' , '3' , 0x00}, "audio/mpeg"}, + {{0xFF, 0xFF, 0xFF, 0x00}, {'O' , 'g' , 'g' , 0x00}, "audio/ogg" }, + {{0xFF, 0xFE, 0x00, 0x00}, {0xFF, 0xFA, 0x00, 0x00}, "audio/mpeg"} +}; + +#if 0 +#warning if a magic is contained in a file (for instance in .cdr) there is no way to play it correctly with neutrino +#warning the third magic is pretty short - hence disabled by default +/* 1111 1111 1111 1010 0000 0000 0000 0000 + AAAA AAAA AAAB BCC + where A: frame sync + B: MPEG audio ID (11 = MPEG Version 1) + C: Layer description (01 = Layer III) + see http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm */ + +#define known_magic_count (sizeof(known_magic) / sizeof(magic_t)) +#else +#define known_magic_count 2 +#endif + +#define is_redirect(a) ((a == 301) || (a == 302)) + +char err_txt[2048]; /* human readable error message */ +char redirect_url[2048]; /* new url if we've been redirected (HTTP 301/302) */ +static int debug = 0; /* print debugging output or not */ +static char logfile[255]; /* redirect errors from stderr */ +static int retry_num = 2 /*10*/; /* number of retries for failed connections */ +static int enable_metadata = 0; /* allow shoutcast meta data streaming */ +static int got_opts = 0; /* is set to 1 if getOpts() was executed */ +static int cache_size = 196608; /* default cache size; can be overridden at */ + /* runtime with an option in the options file */ + +STATIC STREAM_CACHE cache[CACHEENTMAX]; +STATIC STREAM_TYPE stream_type[CACHEENTMAX]; + +static int ConnectToServer(char *hostname, int port); +static int parse_response(URL *url, void *, CSTATE*); +static int request_file(URL *url); +static void readln(int, char *); +static int getCacheSlot(FILE *fd); +static int push(FILE *fd, char *buf, long len); +static int pop(FILE *fd, char *buf, long len); +static void CacheFillThread(void *url); +static void ShoutCAST_MetaFilter(STREAM_FILTER *); +static void ShoutCAST_DestroyFilter(void *a); +static STREAM_FILTER *ShoutCAST_InitFilter(int); +static void ShoutCAST_ParseMetaData(char *, CSTATE *); + +static void getOpts(void); + +static void parseURL_url(URL& url); + +static int base64_encode(char *dest, const char *src); + +/***************************************/ +/* this is a simple options parser */ + +void getOpts() +{ + char *dirs[] = { (char *) "/var/etc", (char *) ".", NULL }; + char buf[4096], *ptr; + int i; + FILE *fd = NULL; + +#ifndef RADIOBOX //a not generic thing in a generic library + /* options which can be set from within neutrino */ + enable_metadata = g_settings.audioplayer_enable_sc_metadata; +#endif /* RADIOBOX */ + + if (got_opts) /* prevent reading in options multiple times */ + return; + else + got_opts = 1; + + for(i=0; dirs[i] != NULL; i++) + { + sprintf(buf, "%s/.netfile", dirs[i]); + fd = fopen(buf, "r"); + if(fd) break; + } + + if(!fd) + return; + fread(buf, sizeof(char), 4095, fd); + fclose(fd); + + if(strstr(buf, "debug=1")) + debug = 1; + + if((ptr = strstr(buf, "cachesize="))) + cache_size = atoi(strchr(ptr, '=') + 1); + + if((ptr = strstr(buf, "retries="))) + retry_num = atoi(strchr(ptr, '=') + 1); + + if((ptr = strstr(buf, "logfile="))) + { + strcpy(logfile, strchr(ptr, '=') + 1); + CRLFCut(logfile); + freopen(logfile, "w", stderr); + } +} + +/***************************************/ +/* networking functions */ + +int ConnectToServer(char *hostname, int port) +{ + struct hostent *host; + struct sockaddr_in sock; + int fd, addr; + struct pollfd pfd; + + dprintf(stderr, "looking up hostname: %s\n", hostname); + + host = gethostbyname(hostname); + + if(host == NULL) + { + herror(err_txt); + return -1; + } + + addr = htonl(*(int *)host->h_addr); + + dprintf(stderr, "connecting to %s [%d.%d.%d.%d], port %d\n", host->h_name, + (addr & 0xff000000) >> 24, + (addr & 0x00ff0000) >> 16, + (addr & 0x0000ff00) >> 8, + (addr & 0x000000ff), port); + + fd = socket(AF_INET, SOCK_STREAM, 0); + + if(fd == -1) + { + strcpy(err_txt, strerror(errno)); + return -1; + } + + memset(&sock, 0, sizeof(sock)); + memmove((char*)&sock.sin_addr, host->h_addr, host->h_length); + + sock.sin_family = AF_INET; + sock.sin_port = htons(port); + + int flgs = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flgs | O_NONBLOCK); + + if( connect(fd, (struct sockaddr *)&sock, sizeof(sock)) == -1 ) + { + if(errno != EINPROGRESS) { + close(fd); + strcpy(err_txt, strerror(errno)); + dprintf(stderr, "error connecting to %s: %s\n", hostname, err_txt); + return -1; + } + } + dprintf(stderr, "connected to %s\n", hostname); + pfd.fd = fd; + //pfd.events = POLLIN | POLLPRI; + pfd.events = POLLOUT | POLLERR | POLLHUP; + pfd.revents = 0; + + int ret = poll(&pfd, 1, 5000); + if(ret != 1) { + strcpy(err_txt, strerror(errno)); + dprintf(stderr, "error connecting to %s: %s\n", hostname, err_txt); + close(fd); + return -1; + } + if ((pfd.revents & POLLOUT) == POLLOUT) { + fcntl(fd, F_SETFL, flgs &~ O_NONBLOCK); + return fd; + } + + return fd; +} + +/*********************************************/ +/* request a file from the HTTP server */ +/* the network stream must be opened already */ +/* and the URL structure be initialized */ +/* properly ! */ + +int request_file(URL *url) +{ + char str[255], *ptr; + int slot; + ID3 id3; + + /* get the cache slot for this stream. A negative return value */ + /* indicates that no cache has been set up for this stream */ + slot = getCacheSlot(url->stream); + + /* if the filename contains a line break, then use everything */ + /* up to the line break as file name and everything beyond as */ + /* entity to be sent with the request */ + ptr = strchr(url->file, '\n'); + if(ptr) + { + strcpy(url->entity, ptr + 1); + *ptr = 0; + } + switch(url->proto_version) + { + /* send a HTTP/1.0 request */ + case HTTP10: { + snprintf(str, sizeof(str)-1, "GET http://%s:%d%s\n", url->host, url->port, url->file); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + } + break; + + /* send a HTTP/1.1 request */ + case HTTP11: { + int meta_int; + CSTATE tmp; + + snprintf(str, sizeof(str)-1, "%s %s HTTP/1.1\r\n", (url->entity[0]) ? "POST" : "GET", url->file); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + + snprintf(str, sizeof(str)-1, "Host: %s:%d\r\n", url->host, url->port); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + + snprintf(str, sizeof(str)-1, "User-Agent: WinampMPEG/5.52\r\n"); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + + if (url->logindata[0]) + { + sprintf(str, "Authorization: Basic %s\r\n", url->logindata); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + } + + snprintf(str, sizeof(str)-1, "Accept: */*\r\n"); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + + if(enable_metadata) + { + snprintf(str, sizeof(str)-1, "Icy-MetaData: 1\r\n"); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + } + + /* if we have a entity, announce it to the server */ + if(url->entity[0]) + { + snprintf(str, sizeof(str)-1, "Content-Length: %d\r\n", strlen(url->entity)); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + } + + snprintf(str, sizeof(str)-1, "Connection: close\r\n"); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + + // empty line -> end of HTTP request + snprintf(str, sizeof(str)-1, "\r\n"); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + + if( (meta_int = parse_response(url, &id3, &tmp)) < 0) + return -1; + + if(meta_int) + { + /* hook in the filter function if there is meta */ + /* data present in the stream */ + cache[slot].filter_arg = ShoutCAST_InitFilter(meta_int); + cache[slot].filter = ShoutCAST_MetaFilter; + + /* this is a *really bad* way to pass along the argument, */ + /* since we convert the integer into a pointer instead of */ + /* passing along a pointer/reference !*/ + if(cache[slot].filter_arg->state) + memmove(cache[slot].filter_arg->state, &tmp, sizeof(CSTATE)); + } + + /* push the created ID3 header into the stream cache */ + push(url->stream, (char*)&id3, id3.len); +#if 0 + rval = parse_response(url, NULL, NULL); + dprintf(stderr, "server response parser: return value = %d\n", rval); + + /* if the header indicated a zero length document or an */ + /* error, then close the cache, if there is any */ + /* 25.04.05 ChakaZulu: zero length can be a stream so let's try playing */ + if((slot >= 0) && (rval < 0)) + cache[slot].closed = 1; + + /* return on error */ + if( rval < 0 ) + return rval; +#endif + } + break; + + /* send a SHOUTCAST request */ + case SHOUTCAST:{ + int meta_int; + CSTATE tmp; + + sprintf(str, "GET %s HTTP/1.0\r\n", url->file); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + sprintf(str, "Host: %s\r\n", url->host); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + + if(enable_metadata) + { + sprintf(str, "icy-metadata: 1\r\n"); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + } + + sprintf(str, "User-Agent: %s\r\n", "RealPlayer/4.0"); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + + if (url->logindata[0]) + { + sprintf(str, "Authorization: Basic %s\r\n", url->logindata); + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + } + + sprintf(str, "\r\n"); /* end of headers to send */ + dprintf(stderr, "> %s", str); + send(url->fd, str, strlen(str), 0); + + if( (meta_int = parse_response(url, &id3, &tmp)) < 0) + return -1; + + if(meta_int) + { + /* hook in the filter function if there is meta */ + /* data present in the stream */ + cache[slot].filter_arg = ShoutCAST_InitFilter(meta_int); + cache[slot].filter = ShoutCAST_MetaFilter; + + /* this is a *really bad* way to pass along the argument, */ + /* since we convert the integer into a pointer instead of */ + /* passing along a pointer/reference !*/ + if(cache[slot].filter_arg->state) + memmove(cache[slot].filter_arg->state, &tmp, sizeof(CSTATE)); + } + + /* push the created ID3 header into the stream cache */ + push(url->stream, (char*)&id3, id3.len); + } + break; + } /* end switch(url->proto_version) */ + + /* now it get's nasty ;) */ + /* create a thread that continously feeds the cache */ + /* with the data it fetches from the network stream */ + /* but *ONLY* if there is a cache slot for this stream at all ! */ + /* HINT: in compatibility mode no cache is configured */ + + if(slot >= 0) + { + pthread_attr_init(&cache[slot].attr); + pthread_create( + &cache[slot].fill_thread, + &cache[slot].attr, + (void *(*)(void*))&CacheFillThread, (void*)&cache[slot]); + dprintf(stderr, "request_file: slot %d fill_thread 0x%x\n", slot, (int)cache[slot].fill_thread); + } + + /* now we do not care any longer about fetching new data,*/ + /* but we can not be shure that the cache is filled with */ + /* enough stuff ! */ + return 0; +} + +/***************************************/ +/* parse the server response (header) */ +/* and translate possible errors into */ +/* local syserror numbers */ + +#define getHeaderVal(a,b) { \ + char *_ptr; \ + _ptr = strstr(header, a); \ + if(_ptr) \ + { \ + _ptr = strchr(_ptr, ':'); \ + for(; !isalnum(*_ptr); _ptr++); \ + b = atoi(_ptr); \ + } else b = -1; } + +#define getHeaderStr(a,b) { \ + char *_ptr; \ + _ptr = strstr(header, a); \ + if(_ptr) \ + { \ + unsigned int i; \ + _ptr = strchr(_ptr, ':'); \ + for(_ptr++; isspace(*_ptr); _ptr++); \ + for (i=0; (_ptr[i]!='\n') && (_ptr[i]!='\r') && (_ptr[i]!='\0') && (ifd; + ID3 *id3 = (ID3*)opt; + + memset(header, 0, 2048); + ptr = header; + + /* extract the http header from the stream */ + do + { + recv(fd, ptr, 1, 0); + + /* skip all 'CR' symbols */ + if(*ptr != 13) + { + lastchr = chr; chr = *ptr++; hlen++; + } + + } while((hlen < 2048) && ( ! ((chr == 10) && (lastchr == 10)))); + + *ptr = 0; + + dprintf(stderr, "----------\n%s----------\n", header); + + /* parse the header fields */ + ptr = strstr(header, "HTTP/1.1"); + + if(!ptr) + ptr = strstr(header, "HTTP/1.0"); + + if(!ptr) + ptr = strstr(header, "ICY"); + + /* no valid HTTP/1.1 or SHOUTCAST response */ + if(!ptr) + return -1; + + response = atoi(strchr(ptr, ' ') + 1); + + switch(response) + { + case 200: errno = 0; + break; + + case 301: /* 'file moved' error */ + case 302: /* 'file not found' error */ + errno = ENOENT; + strcpy(err_txt, ptr); + getHeaderStr("Location", redirect_url); + return -1 * response; + break; + + case 404: /* 'file not found' error */ + errno = ENOENT; + strcpy(err_txt, ptr); + return -1; + break; + + default: errno = ENOPROTOOPT; + dprintf(stderr, "unknown server response code: %d\n", response); + return -1; + } + + /* use 'audio/mpeg' as default type, in case we are not told otherwise */ + strcpy(str, "audio/mpeg"); + getHeaderStr("Content-Type:", str); + f_type(url->stream, str); + dprintf(stderr, "type %s\n", str); + + /* if we got a content length from the server, i.e. rval >= 0 */ + /* then return now with the content length as return value */ + getHeaderVal("Content-Length:", rval); + // dprintf(stderr, "file size: %d\n", rval); + if(rval >= 0) + return rval; + + /* yet another hack: this is only implemented to be able to fetch */ + /* the playlists from shoutcast */ + if(strstr(header, "Transfer-Encoding: chunked")) + { + readln(fd, str); + sscanf(str, "%x", &rval); + return rval; + } + + /* no content length indication from the server ? Then treat it as stream */ + getHeaderVal("icy-metaint:", meta_interval); + if(meta_interval < 0) + meta_interval = 0; + + if (state != NULL) { + getHeaderStr("icy-genre:", state->genre); + getHeaderStr("icy-name:", state->station); + getHeaderStr("icy-url:", state->station_url); + getHeaderVal("icy-br:", state->bitrate); + } + /********************* dirty hack **********************/ + /* we parse the stream header sent by the server and */ + /* build based on this information an arteficial id3 */ + /* header that is pushed into the streamcache before */ + /* any data from the stream is fed into the cache. This */ + /* makes the stream look like an MP3 and we have the */ + /* station information in the display of the player :)) */ + +#define SSIZE(a) (\ + (((a) & 0x0000007f) << 0) | (((a) & 0x00003f80) << 1) | \ + (((a) & 0x001fc000) << 2) | (((a) & 0xfe000000) << 3)) + +#define FRAME(b,c) {\ + strcpy(id3frame.id, (b)); \ + strcpy(id3frame.base, (c)); \ + id3frame.size = strlen(id3frame.base); \ + fcnt = 11 + id3frame.size; } + + if(id3) + { + int cnt = 0, fcnt = 0; + ID3_frame id3frame; + uint32_t sz; + char station[2048], desc[2048]; + + memmove(id3->magic, "ID3", 3); + id3->version[0] = 3; + id3->version[1] = 0; + + ptr = strstr(header, "icy-name:"); + if(ptr) + { + ptr = strchr(ptr, ':') + 1; + for(; ((*ptr == '-') || (*ptr == ' ')); ptr++){}; + strcpy(station, ptr); + *strchr(station, '\n') = 0; + + ptr = strchr(station, '-'); + if(ptr) + { + *ptr = 0; + for(ptr++; ((*ptr == '-') || (*ptr == ' ')); ptr++){}; + strcpy(desc, ptr); + } + + FRAME("TPE1", station); + id3frame.size = SSIZE(id3frame.size + 1); + memmove(id3->base + cnt, &id3frame, fcnt); + cnt += fcnt; + + FRAME("TALB", desc); + id3frame.size = SSIZE(id3frame.size + 1); + memmove(id3->base + cnt, &id3frame, fcnt); + cnt += fcnt; + } + + ptr = strstr(header, "icy-genre:"); + if(ptr) + { + ptr = strchr(ptr, ':') + 1; + for(; ((*ptr == '-') || (*ptr == ' ')); ptr++){}; + strcpy(str, ptr); + *strchr(str, '\n') = 0; + + FRAME("TIT2", str); + id3frame.size = SSIZE(id3frame.size + 1); + memmove(id3->base + cnt, &id3frame, fcnt); + cnt += fcnt; + } + + FRAME("COMM", "dbox streamconverter"); + id3frame.size = SSIZE(id3frame.size + 1); + memmove(id3->base + cnt, &id3frame, fcnt); + cnt += fcnt; + + sz = 14 + cnt - 10; + + id3->size[0] = (sz & 0xfe000000) >> 21; + id3->size[1] = (sz & 0x001fc000) >> 14; + id3->size[2] = (sz & 0x00003f80) >> 7; + id3->size[3] = (sz & 0x0000007f) >> 0; + + id3->len = 14 + cnt; + } + + return meta_interval; +} + +/******* wrapper functions for the f*() calls ************************/ + +#define transport(a,b,c) \ + if(strstr(url.url, a)) \ + { \ + url.access_mode = b; \ + url.proto_version = c; \ + } + +FILE *f_open(const char *filename, const char *acctype) +{ + URL url; + FILE *fd; + int /*i,*/ compatibility_mode = 0; + char *ptr = NULL, buf[4096], type[10]; + + if(acctype) + strcpy(type, acctype); + + /* read some options from the options-file */ + getOpts(); + + /* test if compatibility mode has been requested. */ + /* e.g. "rbc" = read, binary, without stream caching */ + if(strchr(type, 'c')) + { + compatibility_mode = 1; + *strchr(type, 'c') = 0; + } + + dprintf(stderr, "f_open: %s %s\n", (compatibility_mode) ? "(compatibility mode)" : "", filename); + + /* set default protocol and port */ + memset(&url, 0, sizeof(URL)); + url.proto_version = HTTP11; + url.port = 80; + strcpy(url.url, filename); + + /* remove leading spaces */ + for (ptr = url.url; (ptr != NULL) && ((*ptr == ' ') || (*ptr == ' ')); ptr++){} ; + + if(ptr != url.url) + strcpy(url.url, ptr); + + /* did we get an URL file as argument ? If so, then open */ + /* this file, read out the url and open the url instead */ +#ifndef DISABLE_URLFILES + if( strstr(filename, ".url") || strstr(filename, ".imu")) + { + fd = fopen(filename, "r"); + + if(fd) + { + fread(buf, sizeof(char), 4095, fd); + fclose(fd); + + ptr = strstr(buf, "://"); + + if(!ptr) + { + dprintf(stderr, "Ups! File doesn't seem to contain any URL !\nbuffer:%s\n", buf); + return NULL; + } + + ptr = strchr(buf, '\n'); + if(ptr) + *ptr = 0; + + sprintf(url.url, "%s", buf); + } + else + return NULL; + } +#endif + + /* now lets see what we have ... */ + parseURL_url(url); + + dprintf(stderr, "URL to open: %s, access mode %s%s\n", + url.url, + (url.access_mode == MODE_HTTP) ? "HTTP" : + (url.access_mode == MODE_SCAST) ? "SHOUTCAST" : + (url.access_mode == MODE_ICAST) ? "ICECAST" : + (url.access_mode == MODE_PLS) ? "PLAYLIST" : + "FILE", + (url.access_mode != MODE_FILE) ? ( + (url.proto_version == HTTP10) ? "/1.0" : + (url.proto_version == HTTP11) ? "/1.1" : + (url.proto_version == SHOUTCAST) ? "/SHOUTCAST" : + "") : "" ); + + dprintf(stderr, "FILE to open: %s, access mode: %d\n", url.file, url.access_mode); + + switch(url.access_mode) + { + case MODE_HTTP: { + int follow_url = 1; // used for redirects + int redirects = 0; + *redirect_url = '\0'; + while (follow_url) + { + + int retries = retry_num; + + do + { + url.fd = ConnectToServer(url.host, url.port); + retries--; + } while( url.fd < 0 && retries > 0); + + /* if the stream could not be opened, then indicate */ + /* an 'No such device or address' error */ + if(url.fd < 0) + { + fd = NULL; + errno = ENXIO; + printf("netfile: could not connect to server %s:%d\n",url.host, url.port); + return fd; + } + else + { + fd = fdopen(url.fd, "r+"); + url.stream = fd; + + if(!fd) + { + perror(err_txt); + } + else + { + /* in compatibility mode we must not use our own stream cache */ + /* because the application makes use of their own f*() calls */ + /* which we can not replace by our own functions and thus they'll */ + /* interfere with each other. All we can do is to open the stream */ + /* and return a valid stream descriptor */ + if(!compatibility_mode) + { + int i; + /* look for a free cache slot */ + for(i=0; ((i 0); + + + /* extract the servers from the received playlist */ + if(!ptr) + { + dprintf(stderr, "Ups! Playlist doesn't seem to contain any URL !\nbuffer:%s\n", buf); + sprintf(err_txt, "Ups! Playlist doesn't seem to contain any URL !"); + return NULL; + } + + for(int i=0; ((ptr != NULL) && (i<25)); ptr = strstr(ptr, "http://") ) + { + strncpy(servers[i], ptr, 1023); + ptr2 = strchr(servers[i], '\n'); + if(ptr2) *ptr2 = 0; + // change ptr so that next strstr searches in buf and not in servers[i] + ptr = strchr(ptr,'\n'); + if (ptr != NULL) + ptr++; + dprintf(stderr, "server[%d]: %s\n", i, servers[i]); + i++; + } + + /* try to connect to all servers until we find one that */ + /* is willing to serve us */ + { + int i; + for(i=0, fd = NULL; ((fd == NULL) && (i<25)); i++) + { + const char* const chptr = strstr(servers[i], "://"); + if(chptr) + { + sprintf(url.url, "icy%s", chptr); + fd = f_open(url.url, "r"); + } + } + } + } + break; + + case MODE_FILE: + default: + { + unsigned char magic[4] = {0, 0, 0, 0}; + + fd = fopen(url.file, type); + if (fd == NULL) + return NULL; + fread(&magic, 4, 1, fd); + rewind(fd); + + /* first stage: try to determine the filetype from the file */ + /* magic, if there is any */ + for (int i = 0; i < known_magic_count; i++) + { + if (((*(uint32_t *)&(magic[0])) & *(uint32_t *)&(known_magic[i].mask[0])) == *(uint32_t *)&(known_magic[i].mode[0])) + { + f_type(fd, (char *)known_magic[i].type); + goto magic_found; + } + } + + /* stage two: try to determine the filetype from the file name */ + /* a smarter solution would be to get this info from /etc/mime.types */ + + ptr = strrchr(url.file , '.'); +#warning what about filenames without dots? + + if (ptr++) + { + if( strcasecmp(ptr, "cdr") == 0) f_type(fd, (char *) "audio/cdr"); + if( strcasecmp(ptr, "wav") == 0) f_type(fd, (char *) "audio/wave"); + if( strcasecmp(ptr, "aif") == 0) f_type(fd, (char *) "audio/aifc"); + if( strcasecmp(ptr, "snd") == 0) f_type(fd, (char *) "audio/snd"); + + /* they should be obsolete now due to the file magic detection */ + if( strcasecmp(ptr, "ogg") == 0) f_type(fd, (char *) "audio/ogg"); + if( strcasecmp(ptr, "mp3") == 0) f_type(fd, (char *) "audio/mpeg"); + if( strcasecmp(ptr, "mp2") == 0) f_type(fd, (char *) "audio/mpeg"); + if( strcasecmp(ptr, "mpa") == 0) f_type(fd, (char *) "audio/mpeg"); + } +magic_found: + ; + } + break; + } /* endswitch */ + + return fd; +} + +int f_close(FILE *stream) +{ + int i, rval; + + dprintf(stderr, "f_close: stream 0x%x\n", stream); + /* at first, lookup the stream in the stream type table and remove it */ + for(i=0 ; (idestructor) + { + dprintf(stderr, "f_close: calling stream filter destructor\n"); + cache[i].filter_arg->destructor(cache[i].filter_arg); + free(cache[i].filter_arg); + } + + dprintf(stderr, "f_close: destroying mutexes\n"); + pthread_mutex_destroy(&cache[i].cache_lock); + pthread_mutex_destroy(&cache[i].readable); + pthread_mutex_destroy(&cache[i].writeable); + + /* completely blank out all data */ + memset(&cache[i], 0, sizeof(STREAM_CACHE)); + } + else + rval = fclose(stream); + + return rval; +} + +long f_tell(FILE *stream) +{ + int i; + long rval; + + /* lookup the stream ID in the cache table */ + i = getCacheSlot(stream); + + if(i < 0) + return( ftell(stream) ); + + if(cache[i].fd == stream) + rval = cache[i].total_bytes_delivered; + else + rval = ftell(stream); + + return rval; +} + +void f_rewind(FILE *stream) +{ + int i; + + /* lookup the stream ID in the cache table */ + i = getCacheSlot(stream); + + if(i < 0) + { + rewind(stream); + return; + } + + if(cache[i].fd == stream) + { + /* nothing to do */ + } + else + rewind(stream); +} + +int f_seek(FILE *stream, long offset, int whence) +{ + int i, rval; + + /* lookup the stream ID in the cache table */ + i = getCacheSlot(stream); + + if(i < 0) + return( fseek(stream, offset, whence) ); + + if(cache[i].fd == stream) + { + dprintf(stderr, "WARNING: program tries to seek on a stream !! offset %d whence %d\n", (int) offset, whence); + rval = -1; + } + else + rval = fseek(stream, offset, whence); + + return rval; +} + +size_t f_read (void *ptr, size_t size, size_t nitems, FILE *stream) +{ + int i, rval; + + /* lookup the stream ID in the cache table */ + i = getCacheSlot(stream); + + if(i < 0) + return( fread(ptr, size, nitems, stream) ); + + if(cache[i].fd == stream) { + rval = pop(stream, (char*)ptr, size * nitems); + } + else + rval = fread(ptr, size, nitems, stream); + + return rval; +} + +char *f_type(FILE *stream, char *type) +{ + int i; + + /* lookup the stream in the stream type table */ + for(i=0 ; (i (cache[i].csize - cache[i].filled)) ? (cache[i].csize - cache[i].filled) : (len - rval); + + if(cache[i].wptr < cache[i].rptr) + { + amt[0] = cache[i].rptr - cache[i].wptr; + amt[1] = 0; + } + else + { + amt[0] = cache[i].ceiling - cache[i].wptr; + amt[1] = cache[i].rptr - cache[i].cache; + } + + for(j=0; j<2; j++) + { + if(amt[j] > blen) + amt[j] = blen; + + if(amt[j]) + { + memmove(cache[i].wptr, buf, amt[j]); + cache[i].wptr = cache[i].cache + + (((int)(cache[i].wptr - cache[i].cache) + amt[j]) % cache[i].csize); + + buf += amt[j]; /* adjust the target buffer pointer */ + rval += amt[j]; /* increase the 'total bytes' counter */ + blen -= amt[j]; /* decrease the block length counter */ + cache[i].filled += amt[j]; + } + } + + // dprintf(stderr, "push: %d/%d bytes written [filled: %d of %d], stream: %x\n", amt[0] + amt[1], rval, cache[i].filled, CACHESIZE, fd); + + pthread_mutex_unlock( &cache[i].cache_lock ); + + /* unlock the cache for read access, if it */ + /* contains some data */ + if(cache[i].filled){ + pthread_mutex_unlock( &cache[i].readable ); + } + } + + /* if there is still space in the cache, unlock */ + /* it again for further writing by anyone */ + if(cache[i].csize - cache[i].filled){ + pthread_mutex_unlock( & cache[i].writeable ); + } + else + dprintf(stderr, "push: buffer overrun; cache full - leaving cache locked\n"); + + } while(rval < len); + + dprintf(stderr, "push: exitstate: [filled: %3.1f %%], stream: %x\r", 100.0 * (float)cache[i].filled / (float)cache[i].csize, (int) fd); + + return rval; +} + +int pop(FILE *fd, char *buf, long len) +{ + int rval = 0, i, j; + int blen = 0; + + i = getCacheSlot(fd); + + if(i < 0) + return -1; + + dprintf(stderr, "pop: %d bytes requested [filled: %d of %d], stream: %x buf 0x%x\n", + (int) len, (int) cache[i].filled, (int) CACHESIZE, (int)fd, (int) buf); + + if(cache[i].fd == fd) + { + do + { + if(cache[i].closed && (!cache[i].filled) ) + return 0; + + if((!cache[i].filled) && feof(fd)){ + return 0; + } + + /* try to obtain read permissions for the cache */ + /* this will block if the cache is empty */ +#if 0 //FIXME no way to stop if connection dead ? + pthread_mutex_lock( & cache[i].readable ); +#else + while(true) { + int lret = pthread_mutex_trylock(&cache[i].readable); + if((lret == 0) || (CAudioPlayer::getInstance()->getState() == CBaseDec::STOP_REQ)) + break; + usleep(100); + } +#endif + if(cache[i].filled) + { + int amt[2]; + + /* prevent any modification to the cache by other threads, */ + /* mainly by the push() function, while we read data from it */ + pthread_mutex_lock( &cache[i].cache_lock ); + + /* block transfer length: get either what's there or */ + /* only as much as we need */ + blen = ((len - rval) > cache[i].filled) ? cache[i].filled : (len - rval); + + if(cache[i].rptr < cache[i].wptr) + { + amt[0] = cache[i].wptr - cache[i].rptr; + amt[1] = 0; + } + else + { + amt[0] = cache[i].ceiling - cache[i].rptr; + amt[1] = cache[i].wptr - cache[i].cache; + } + + for(j=0; j<2; j++) + { + if(amt[j] > blen) amt[j] = blen; + + if(amt[j]) + { + dprintf(stderr, "pop(): rptr: 0x%08x, buf: 0x%08x, amt[%d]=%d, blen=%d, len=%d, rval=%d\n", + (int) cache[i].rptr, (int) buf, j, amt[j], blen, (int) len, rval); + + memmove(buf, cache[i].rptr, amt[j]); + + cache[i].rptr = cache[i].cache + + (((int)(cache[i].rptr - cache[i].cache) + amt[j]) % cache[i].csize); + + buf += amt[j]; /* adjust the target buffer pointer */ + rval += amt[j]; /* increase the 'total bytes' counter */ + blen -= amt[j]; /* decrease the block length counter */ + cache[i].filled -= amt[j]; + } + } + + dprintf(stderr, "pop: %d/%d/%d bytes read [filled: %d of %d], stream: %x\n", amt[0] + amt[1], rval, (int) len, (int) cache[i].filled, (int) CACHESIZE, (int) fd); + + /* if the cache is closed and empty, then */ + /* force the end condition to be met */ + if(cache[i].closed && (! cache[i].filled)) + break;//len = rval; + + /* allow write access again */ + pthread_mutex_unlock( &cache[i].cache_lock ); + + /* unlock the cache for write access, if it */ + /* has some free space */ + if(cache[i].csize - cache[i].filled){ + pthread_mutex_unlock( &cache[i].writeable ); + } + } + + /* if there is still data in the cache, unlock */ + /* it again for further reading by anyone */ + if(cache[i].filled) + { + pthread_mutex_unlock( & cache[i].readable ); + } + else + dprintf(stderr, "pop: buffer underrun; cache empty - leaving cache locked\n"); + } while((rval < len) && (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP_REQ)); + } + else + { + dprintf(stderr, "pop: no cache present for stream %0x\n", (int) fd); + rval = -1; + } + +// dprintf(stderr, "pop: exitstate: [filled: %3.1f %%], stream: %x\n", 100.0 * (float)cache[i].filled / (float)cache[i].csize, fd); + + cache[i].total_bytes_delivered += rval; + + if(cache[i].filter_arg) + if(cache[i].filter_arg->state) + cache[i].filter_arg->state->buffered = 65536L * (long long)cache[i].filled / (long long)CACHESIZE; + + return rval; +} + +void CacheFillThread(void *c) +{ + char *buf; + STREAM_CACHE *scache = (STREAM_CACHE*)c; + int rval, datalen; + + if(scache->closed) + return; + + dprintf(stderr, "CacheFillThread: thread started, using stream %8x\n", (int) scache->fd); + + buf = (char*)malloc(CACHEBTRANS); + + if(!buf) + { + dprintf(stderr, "CacheFillThread: fatal error ! Could not allocate memory. Terminating.\n"); + exit(-1); + } + + /* endless loop; read a block of data from the stream */ + /* and push it into the cache */ + do + { + struct pollfd pfd; + + /* has a f_close() call in an other thread already closed the cache ? */ + datalen = CACHEBTRANS; + + pfd.fd = fileno(scache->fd); + pfd.events = POLLIN | POLLPRI; + pfd.revents = 0; + + int ret = poll(&pfd, 1, 1000); + + if (ret > 0 && (pfd.revents & POLLIN) == POLLIN) { +#if 0 //FIXME: fread blocks i/o on dead connection + rval = fread(buf, 1, datalen, scache->fd); + if ((rval == 0) && feof(scache->fd)) + break; /* exit cache fill thread if eof and nothing to push */ +#else + rval = read(fileno(scache->fd), buf, datalen); + if (rval == 0) + break; /* exit cache fill thread if eof and nothing to push */ +#endif + /* if there is a filter function set up for this stream, then */ + /* we need to call it with the propper arguments */ + if(scache->filter) + { + scache->filter_arg->buf = buf; + scache->filter_arg->len = &rval; + scache->filter(scache->filter_arg); + datalen = rval; + } + + if( push(scache->fd, buf, rval) < 0) + break; + } + } + while(!scache->closed); + //while( (rval == datalen) && (!scache->closed) ); + + /* close the cache if the stream disrupted */ + scache->closed = 1; + pthread_mutex_unlock( &scache->writeable ); + pthread_mutex_unlock( &scache->readable ); + + /* ... and exit this thread. */ + dprintf(stderr, "CacheFillThread: thread exited, stream %8x \n", (int) scache->fd); + + free(buf); + pthread_exit(0); +} + +/**************************** stream filter ******************************/ + +int f_status(FILE *stream, void (*cb)(void*)) +{ + int i, rval = -1; + + if(!stream) + { + strcpy(err_txt, "NULL pointer as stream id\n"); + return -1; + } + + /* lookup the stream ID in the cache table */ + i = getCacheSlot(stream); + + if(cache[i].fd == stream) + { + /* hook the users function into the steam filter */ + if(cache[i].filter_arg) + { + if(cache[i].filter_arg->state) + { + cache[i].filter_arg->state->cb = cb; + rval = 0; + } + else + strcpy(err_txt, "no cache[].filter_arg->state hook\n"); + } + else + strcpy(err_txt, "no cache[].filter_arg hook\n"); + } + + return rval; +} + +/* parse the meta data block and copy all relevant */ +/* information into the CSTATE structure */ +void ShoutCAST_ParseMetaData(char *md, CSTATE *state) +{ + #define SKIP(a) for(;(a && !isalnum(*a)); ++a); + char *ptr; + + /* abort if we were submitted a NULL pointer */ + if((!md) || (!state)) + return; + + dprintf(stderr, "ShoutCAST_ParseMetaData(%x : %s, %x)\n", (int) md, md, (int) state); + + ptr = strstr(md, "StreamTitle="); + + if(ptr) + { + /* look if there is a dash or a comma that separates artist and title */ + ptr = strstr(md, " - "); + + if(!ptr) + ptr = strstr(md, ", "); + + + /* no separator, simply copy everything into the 'title' field */ + if(!ptr) + { + ptr = strchr(md, '='); + strncpy(state->title, ptr + 2, 4096); + ptr = strchr(state->title, ';'); + if(ptr) + *(ptr - 1) = 0; + state->artist[0] = 0; + } + else + { + SKIP(ptr); + strcpy(state->title, ptr); + ptr = strchr(state->title, ';'); + if(ptr) + *(ptr - 1) = 0; + + ptr = strstr(md, "StreamTitle="); + ptr = strchr(ptr, '\''); + strncpy(state->artist, ptr + 1, 4096); + ptr = strstr(state->artist, " - "); + if(!ptr) + ptr = strstr(state->artist, ", "); + + if(ptr) + *ptr = 0; + } + state->state = RUNNING; + } +} + +void ShoutCAST_DestroyFilter(void *a) +{ + STREAM_FILTER *arg = (STREAM_FILTER*)a; + + if(arg->state) + free(arg->state), arg->state = NULL; + if(arg->user) + free(arg->user), arg->user = NULL; +} + +STREAM_FILTER *ShoutCAST_InitFilter(int meta_int) +{ + STREAM_FILTER *arg; + + arg = (STREAM_FILTER*)calloc(1, sizeof(STREAM_FILTER)); + + /* allocate our private data space, hook it into the */ + /* stream filter structure and initialize the variables */ + if(!arg->user) + { + arg->user = calloc(1, sizeof(FILTERDATA)); + arg->state = (CSTATE*)calloc(1, sizeof(CSTATE)); + ((FILTERDATA*)arg->user)->meta_int = meta_int; + arg->destructor = ShoutCAST_DestroyFilter; + } + + return arg; +} + +void ShoutCAST_MetaFilter(STREAM_FILTER *arg) +{ + FILTERDATA *filterdata = (FILTERDATA*)arg->user; + int meta_int = filterdata->meta_int; + int len = *arg->len; + char*buf = (char*)arg->buf; + int meta_start; + + /* bug trap */ + if(!arg) + return; + +#if 0 + dprintf(stderr, "filter : cnt : %d\n", filterdata->cnt); + dprintf(stderr, "filter : len : %d\n", filterdata->len); + dprintf(stderr, "filter : stored : %d\n", filterdata->stored); + dprintf(stderr, "filter : cnt + len: %d\n", filterdata->cnt + len); + dprintf(stderr, "filter : meta_int : %d\n", filterdata->meta_int); +#endif + /* not yet all meta data has been processed */ + if(filterdata->stored < filterdata->len) + { + int bsize = (filterdata->len + 1) - filterdata->stored; + + /* if there is some meta data, extract it */ + /* there can be zero size blocks too */ + if(filterdata->len) + { + dprintf(stderr, "filter : ********* partitioned metadata block part 2 ******\n"); + + memmove(filterdata->meta_data + filterdata->stored, buf, bsize); + + ShoutCAST_ParseMetaData(filterdata->meta_data, arg->state); + + /* call the users callback function */ + if(arg->state->cb) + arg->state->cb(arg->state); + + //dprintf(stderr, "filter : metadata : \n\n\n----------\n%s\n----------\n\n\n", filterdata->meta_data); + + /* remove the metadata and it's size indicator from the buffer */ + memmove(buf, buf + bsize, len - bsize); + + *arg->len -= bsize; + filterdata->cnt = len - bsize; + filterdata->stored = 0; + filterdata->len = 0; + } + return; + } + + if((filterdata->cnt < meta_int) && ((filterdata->cnt + len) <= meta_int)) + { + /* do nothing; leave the data block and the length variable */ + /* untouched, update our private counter and return */ + filterdata->cnt += len; + return; + } + + /* does a meta data block start in the current block ? */ + if((filterdata->cnt <= meta_int) && ((filterdata->cnt + len) > meta_int)) + { + meta_start = meta_int - filterdata->cnt; + + /* the first byte of the meta data block tells us how long it is */ + filterdata->len = 16 * (int)buf[meta_start]; + + dprintf(stderr, "filter : ---> metadata %d bytes @ %d\n", filterdata->len, meta_start); + + /****************************************************************/ + /* case A: the meta data is completely within the current block */ + /****************************************************************/ + if((meta_start + filterdata->len) <= len) + { + int b = meta_start + filterdata->len + 1; + + /* if there is some meta data, extract it; */ + /* there can be zero size blocks too */ + if(filterdata->len) + { + memset(filterdata->meta_data, 0, 4096); + memmove(filterdata->meta_data, buf + meta_start, filterdata->len); + + ShoutCAST_ParseMetaData(filterdata->meta_data, arg->state); + + /* call the users callback function */ + if(arg->state->cb) + arg->state->cb(arg->state); + + //dprintf(stderr, "filter : metadata : \n\n\n----------\n%s\n----------\n\n\n", filterdata->meta_data); + } + + /* remove the metadata and it's size indicator from the buffer */ + memmove(buf + meta_start, buf + b, len - b ); + + /* adjust the buffersize */ + *arg->len -= filterdata->len + 1; + filterdata->cnt = len - b; + filterdata->stored = 0; + filterdata->len = 0; + } + + /************************************************************************/ + /* case B: the meta data is partitioned and continues in the next block */ + /************************************************************************/ + else + { + dprintf(stderr, "filter : ********* partitioned metadata block part 1 ******\n"); + + /* if there is some meta data, extract it */ + /* there can be zero size blocks too */ + if(filterdata->len) + { + memset(filterdata->meta_data, 0, 4096); + filterdata->stored = len - meta_start; + memmove(filterdata->meta_data, buf + meta_start, filterdata->stored); + } + + *arg->len = meta_start; + filterdata->cnt = 0; + } + } +} + +/**************************** utility functions ******************************/ +void parseURL_url(URL& url) { + /* now lets see what we have ... */ + char buffer[2048]; +// printf("parseURL_url: %s\n", url.url); + char *ptr = strstr(url.url, "://"); + if (!ptr) + { + url.access_mode = MODE_FILE; + strcpy(url.file, url.url); + url.host[0] = 0; + url.port = 0; + url.logindata[0] = 0; + } + else + { + strcpy(url.host, ptr + 3); + + /* select the appropriate transport modes */ + transport("http", MODE_HTTP, HTTP11); + transport("icy", MODE_HTTP, SHOUTCAST); + transport("scast", MODE_SCAST, SHOUTCAST); + //findme + transport("icast", MODE_ICAST, SHOUTCAST); + + /* if we fetch a playlist file, then set the access mode */ + /* that it will be parsed and processed automatically. If */ + /* it does not fail, then the call returns with an opened stream */ + +/* this currently results in an endless loop due to recursive calls of f_open() + if((url.access_mode == HTTP11) && (strstr(url.url, ".pls"))) + { + url.access_mode = MODE_PLS; + url.proto_version = SHOUTCAST; + } +*/ + + /* extract the file path from the url */ + ptr = strchr(ptr + 3, '/'); + if(ptr) + strcpy(url.file, ptr); + else + strcpy(url.file, "/"); + + /* extract the host part from the url */ + ptr = strchr(url.host, '/'); + if(ptr) + *ptr = 0; + + if ((ptr = strchr(url.host, '@'))) + { + *ptr = 0; + base64_encode(buffer, url.host); + strcpy(url.logindata, buffer); + + strcpy(buffer, ptr + 1); + strcpy(url.host, buffer); + } + else + url.logindata[0] = 0; + + ptr = strrchr(url.host, ':'); + + if(ptr) + { + url.port = atoi(ptr + 1); + *ptr = 0; + } + } +} + +int base64_encode(char *dest, const char *src) +{ + int retval = 1; + int src_len, src_pos; + char symbols[65]; + char mypart[3]; + char mybits[24]; + int part_pos; + int null_bytes = 0; + + if (dest != NULL && src != NULL && (src_len = strlen(src)) > 0) + { + strcpy(symbols,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); + char buffer[src_len*2]; + char *buf_ptr = buffer; + + for (src_pos = 0; src_pos < src_len; src_pos +=3) + { + for (part_pos = 0; part_pos < 3; part_pos++) + { + if (src[src_pos+part_pos] != 0) + mypart[part_pos] = src[src_pos+part_pos]; + else + { + null_bytes = 3 - part_pos; + mypart[part_pos] = 0; + if (part_pos < 2) /* here: part_pos == 1, cannot be 0 */ + mypart[part_pos+1] = 0; + break; + } + } + for (part_pos = 0; part_pos < 24; part_pos++) + mybits[part_pos] = ( mypart[part_pos/8] >> (7 - (part_pos%8)) ) & 0x1; + for (part_pos = 0; part_pos < 24; part_pos+=6) + { + *buf_ptr = (mybits[part_pos] << 5) | + (mybits[part_pos+1] << 4) | (mybits[part_pos+2] << 3) | (mybits[part_pos+3] << 2) | + (mybits[part_pos+4] << 1) | mybits[part_pos+5]; + buf_ptr++; + } + } + for (part_pos = 0 ; part_pos < buf_ptr - buffer - null_bytes; part_pos++) + dest[part_pos] = symbols[(int)buffer[part_pos]]; + for (part_pos = buf_ptr - buffer - null_bytes ; part_pos < buf_ptr - buffer; part_pos++) + dest[part_pos] = '='; + } + else + retval = 0; + + return retval; +} + diff --git a/src/driver/netfile.h b/src/driver/netfile.h new file mode 100644 index 000000000..97a89e1d5 --- /dev/null +++ b/src/driver/netfile.h @@ -0,0 +1,214 @@ +/******************************************************************/ +/* netfile - a URL capable wrapper for the fopen() call */ +/* */ +/* usage: include 'netfile.h' in your code as *LAST* file */ +/* after all other include files and add netfile.c to your */ +/* sources. That's it. The include file maps the common */ +/* fopen() call onto a URL capable version that handles */ +/* files hosted on http servers like local ones. */ +/* */ +/* http example: */ +/* fd = fopen("http://find.me:666/somewhere/foo.bar", "r"); */ +/* */ +/* shoutcast example: */ +/* fd = fopen("icy://find.me:666/funky/station/", "r"); */ +/* */ +/* shoutcast example: (opens the shoutcast station 666 directly) */ +/* fd = fopen("scast://666", "r"); */ +/* */ +/* NOTE: only read access is implemented ! */ +/******************************************************************/ +#ifndef NETFILE_H +#define NETFILE_H 1 + +/* whether we should open an *.url file as plain file or the url */ +/* contained in it instead */ +//#define DISABLE_URLFILES 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define dprintf if(debug) fprintf + +/* file access modes */ +#define ACC_RO 0 +#define ACC_RW 1 +#define ACC_UD 2 /* -> this is used for the 'r+' mode */ +#define ACC_WO 3 + +#define MODE_FILE 0 +#define MODE_HTTP 1 +#define MODE_SCAST 2 /* pseudo transfer mode; is actually HTTP/SHOUTCAST */ +#define MODE_ICAST 3 /* pseudo transfer mode; is actually HTTP/SHOUTCAST */ +#define MODE_PLS 4 /* pseudo transfer mode; is actually HTTP/SHOUTCAST */ + +#define HTTP10 0 +#define HTTP11 1 +#define SHOUTCAST 2 + +#define MAX_REDIRECTS 5 /* follow this amount of redirects */ + +#define CONNECTING 1 /* not used */ +#define BUFFERING 2 /* not used */ +#define RUNNING 3 + +/* map all fopen() calls onto out f_open() function */ +#define fopen f_open +#define fclose f_close +#define fread f_read +#define ftell f_tell +#define rewind f_rewind +#define fseek f_seek +#define fstatus f_status +#define ftype f_type + +extern FILE *f_open(const char *, const char *); +extern int f_close(FILE *); +extern size_t f_read (void *, size_t, size_t, FILE *); +extern long f_tell(FILE *); +extern void f_rewind(FILE *); +extern int f_seek(FILE *, long, int); +extern int f_status(FILE *, void (*)(void*)); +extern char *f_type(FILE*, char*); + +extern char err_txt[2048]; + +#define CACHESIZE cache_size +#define CACHEENTMAX 20 /* at most 20 caches are available */ +#define CACHEBTRANS 1024 /* blocksize for the stream-to-cache transfer */ + +typedef struct +{ + int access_mode; /* access mode; FILE or HTTP */ + int proto_version; /* 0= 1.0; 1 = 1.1; 2 = shoutcast */ + char url[2048]; /* universal resource locator */ + char host[2048]; + int port; + char file[2048]; + char entity[2048]; /* data to send on POST requests */ + int fd; /* filedescriptor of the file*/ + FILE *stream; /* streamdescriptor */ + char logindata[2048]; /* base64 encoded auhtentication string of "username:password" */ +} URL; + +typedef struct +{ + void (*cb)(void *); /* user provided callback function */ + void *user; /* user date hook point */ + int state; /* CONNECTING, BUFFERING, RUNNING */ + int bitrate; + int buffered; /* "waterlevel" in the cache; 0 ... 65535 */ + char station_url[1024]; /*station url */ + char station[1024]; /* station name */ + char genre[4096]; /* station genre */ + char artist[4096]; /* artist currently playing */ + char title[4096]; /* title currently playing */ +} CSTATE; + +typedef struct +{ + void *buf; /* start of the buffer */ + int *len; /* pointer to a variable containing the length of the buffer */ + void *arg; /* pointer to some arguments for the filter function */ + void *user; /* here the filter function can hook in */ + /* some private data */ + void (*destructor)(void*); /* stream filter destructor */ + + CSTATE *state; +} STREAM_FILTER; + +typedef struct +{ + int cnt; /* counter */ + int len; /* meta block length */ + int stored; /* number of bytes already stored */ + int meta_int; /* meta data intervall */ + char meta_data[4096]; /* meta blocks cam be at most 4096 bytes */ +} FILTERDATA; + +typedef struct +{ + FILE *fd; /* stream ID */ + + int acc_mode; /* ACC_RO, ACC_RW, ACC_UD (unused yet) */ + + char *cache; /* cache buffer */ + char *ceiling; /* cache ceiling */ + int csize; /* cache size */ + char *wptr; /* next write position */ + char *rptr; /* next read position */ + long filled; + int closed; /* flag; closed = 1 if supply thread */ + /* has been terminated due to a */ + /* disrupted incoming stream or an EOF */ + long total_bytes_delivered; + + pthread_t fill_thread; + pthread_attr_t attr; + pthread_mutex_t cache_lock; + pthread_mutexattr_t cache_lock_attr; + + pthread_mutex_t readable; + pthread_mutexattr_t readable_attr; + + pthread_mutex_t writeable; + pthread_mutexattr_t writeable_attr; + + void (*filter)(STREAM_FILTER*); /* stream filter function */ + + STREAM_FILTER *filter_arg; /* place to hook in a pointer to the arguments */ +} STREAM_CACHE; + +typedef struct +{ + FILE *stream; + char type[65]; +} STREAM_TYPE; + +typedef struct +{ + char magic[3]; /* "ID3" */ + char version[2]; /* version of the tag */ + char flags; + char size[4]; + char base[1024]; + int len; +} ID3; + +typedef struct +{ + char id[4]; + uint32_t size; + char flags[3]; + char base[1024]; +} ID3_frame; + +#define CRLFCut(a) \ +{ \ + char *_ptr; \ + _ptr = strchr(a, '\r'); \ + if(_ptr) *_ptr = 0; \ + else { \ + _ptr = strchr(a, '\n'); \ + if(_ptr) *_ptr = 0; } \ +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/driver/pictureviewer/Makefile.am b/src/driver/pictureviewer/Makefile.am new file mode 100644 index 000000000..5c28f9a4f --- /dev/null +++ b/src/driver/pictureviewer/Makefile.am @@ -0,0 +1,15 @@ +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +INCLUDES = \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/libconfigfile \ + @FREETYPE_CFLAGS@ \ + -I$(top_srcdir)/lib + +noinst_LIBRARIES = libneutrino_pictureviewer.a + +libneutrino_pictureviewer_a_SOURCES = \ + pictureviewer.cpp fb_display.cpp \ + png.cpp bmp.cpp resize.cpp jpeg.cpp \ + gif.cpp crw.cpp make15color_errdiff.cpp diff --git a/src/driver/pictureviewer/bmp.cpp b/src/driver/pictureviewer/bmp.cpp new file mode 100644 index 000000000..84ba4be2a --- /dev/null +++ b/src/driver/pictureviewer/bmp.cpp @@ -0,0 +1,263 @@ +#include "config.h" +#ifdef FBV_SUPPORT_BMP +#include "pictureviewer.h" +#include + +#include +#include +#include +#include + +#define BMP_TORASTER_OFFSET 10 +#define BMP_SIZE_OFFSET 18 +#define BMP_BPP_OFFSET 28 +#define BMP_RLE_OFFSET 30 +#define BMP_COLOR_OFFSET 54 + +#define fill4B(a) ( ( 4 - ( (a) % 4 ) ) & 0x03) + +struct color { + unsigned char red; + unsigned char green; + unsigned char blue; +}; + +int fh_bmp_id(const char *name) +{ + int fd; + char id[2]; + + fd = open(name, O_RDONLY); + if (fd == -1) { +// dbout("fh_bmp_id {\n"); + return(0); + } + + read(fd, id, 2); + close(fd); + if ( id[0]=='B' && id[1]=='M' ) { + return(1); + } + return(0); +} + +void fetch_pallete(int fd, struct color pallete[], int count) +{ +// dbout("fetch_palette {\n"); + unsigned char buff[4]; + int i; + + lseek(fd, BMP_COLOR_OFFSET, SEEK_SET); + for (i=0; i0) + bytes++; + unsigned char* tbuffer = (unsigned char*) malloc(bytes); + if(tbuffer==NULL) + { + printf("Error: malloc\n"); + return (FH_ERROR_MALLOC); + } + for (i=0; i>4; + c2 = tbuffer[j] & 0x0f; + *wr_buffer++ = pallete[c1].red; + *wr_buffer++ = pallete[c1].green; + *wr_buffer++ = pallete[c1].blue; + *wr_buffer++ = pallete[c2].red; + *wr_buffer++ = pallete[c2].green; + *wr_buffer++ = pallete[c2].blue; + } + if (x%2) { + c1 = tbuffer[j]>>4; + *wr_buffer++ = pallete[c1].red; + *wr_buffer++ = pallete[c1].green; + *wr_buffer++ = pallete[c1].blue; + } + if (skip) { + read(fd, buff, skip); + } + wr_buffer -= x*6; /* backoff 2 lines - x*2 *3 */ + } + free(tbuffer); + } + break; + case 8: /* 8bit palletized */ + { + skip = fill4B(x); + fetch_pallete(fd, pallete, 256); + lseek(fd, raster, SEEK_SET); + unsigned char* tbuffer = (unsigned char*) malloc(x); + if(tbuffer==NULL) + { + printf("Error: malloc\n"); + return (FH_ERROR_MALLOC); + } + for (i=0; i +#include +#ifdef FBV_SUPPORT_CRW + #include + #include + #include +#include +#include + +extern "C" { +#include +} + #include + #include "pictureviewer.h" + +/* + Get a 2-byte integer, making no assumptions about CPU byte order. + Nor should we assume that the compiler evaluates left-to-right. + */ +unsigned short fget2 (FILE *f,int order) +{ + unsigned char a, b; + + a = fgetc(f); + b = fgetc(f); + if (order == 0x4949) /* "II" means little-endian */ + return a + (b << 8); + else /* "MM" means big-endian */ + return (a << 8) + b; +} + +/* + Same for a 4-byte integer. + */ +int fget4 (FILE *f,int order) +{ + unsigned char a, b, c, d; + + a = fgetc(f); + b = fgetc(f); + c = fgetc(f); + d = fgetc(f); + if (order == 0x4949) + return a + (b << 8) + (c << 16) + (d << 24); + else + return (a << 24) + (b << 16) + (c << 8) + d; +} + +int fh_crw_parsedirs(FILE *fh, int pos, int length, int order) +{ + fseek(fh,pos+length-4,SEEK_SET); + int off=pos+fget4(fh,order); + fseek(fh,off,SEEK_SET); + int nEntrys=fget2(fh,order); + + for (int i = 0; i < nEntrys; i++) + { + int type = fget2(fh,order); + int len = fget4(fh,order); + int roff = fget4(fh,order); + + switch(type) + { + case 0x2005: // Image + break; + case 0x2007: // Thumbnail + fseek(fh,pos+roff,SEEK_SET); + return 1; + break; + case 0x0810: // Owner + break; + case 0x0816: // Filename + break; + case 0x0817: // Thumbname + break; + case 0x580b: // SerNo. + break; + case 0x0805: // comment, if subdir 0x300a. "EOS 300D DIGITAL CMOS RAW" if subdir 0x2804 + break; + case 0x080a: // vendor \0 name of the camera + break; + case 0x080b: // firmware + break; + case 0x0815: + break; + case 0x180e: // time + break; + case 0x102a: // White balance + break; + case 0x1031: // size of the image + break; + case 0x1835: // decoder table + break; + default: + if (type >> 8 == 0x28 || type >> 8 == 0x30) // Subdirs + { + if (fh_crw_parsedirs(fh,pos+roff,len,order)==1) + { + return 1; + } + } + } + } + return 0; +} + +void fh_crw_find_jpeg_thumbnail(FILE *fh) +{ + char header[26]; + int order=0; + long fsize=0; + long hlength=0; + + fseek (fh, 0, SEEK_SET); + fread (header, 1, 26, fh); + fseek (fh, 0, SEEK_END); + fsize = ftell(fh); + fseek (fh, 0, SEEK_SET); + + order=*((unsigned short*)header); + + if (order == 0x4949) + hlength = header[2] + (header[3] << 8) + (header[4] << 16) + (header[5] << 24); + else + hlength = (header[2] << 24) + (header[3] << 16) + (header[4] << 8) + header[5]; + + fh_crw_parsedirs(fh,hlength,fsize-hlength,order); +} + +struct r_crw_jpeg_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf envbuffer; +}; + +int fh_crw_id(const char *name) +{ +// dbout("fh_crw_id {\n"); + int fd; + unsigned char id[14]; + fd=open(name,O_RDONLY); if(fd==-1) return(0); + read(fd,id,14); + close(fd); +// dbout("fh_crw_id }\n"); + if(id[6]=='H' && id[7]=='E' && id[8]=='A' && id[9]=='P' && + id[10]=='C' && id[11]=='C' && id[12]=='D' && id[13]=='R') return(1); + + return(0); +} + + +void crw_cb_error_exit(j_common_ptr cinfo) +{ +// dbout("crw_cb_error_exit {\n"); + struct r_crw_jpeg_error_mgr *mptr; + mptr=(struct r_crw_jpeg_error_mgr*) cinfo->err; + (*cinfo->err->output_message) (cinfo); + longjmp(mptr->envbuffer,1); +// dbout("crw_cb_error_exit }\n"); +} + +int fh_crw_load(const char *filename,unsigned char **buffer,int* xp,int* yp) +{ +// dbout("fh_crw_load (%d/%d) {\n",x,y); + struct jpeg_decompress_struct cinfo; + struct jpeg_decompress_struct *ciptr; + struct r_crw_jpeg_error_mgr emgr; + unsigned char *bp; + int px,py,c,x=*xp; + FILE *fh; + JSAMPLE *lb; + + ciptr=&cinfo; + if(!(fh=fopen(filename,"rb"))) return(FH_ERROR_FILE); + ciptr->err=jpeg_std_error(&emgr.pub); + emgr.pub.error_exit=crw_cb_error_exit; + if(setjmp(emgr.envbuffer)==1) + { + // FATAL ERROR - Free the object and return... + jpeg_destroy_decompress(ciptr); + fclose(fh); +// dbout("fh_crw_load } - FATAL ERROR\n"); + return(FH_ERROR_FORMAT); + } + + jpeg_create_decompress(ciptr); + fh_crw_find_jpeg_thumbnail(fh); + jpeg_stdio_src(ciptr,fh); + jpeg_read_header(ciptr,TRUE); + ciptr->out_color_space=JCS_RGB; + if(x==(int)ciptr->image_width) + ciptr->scale_denom=1; + else if(abs(x*2 - ciptr->image_width) < 2) + ciptr->scale_denom=2; + else if(abs(x*4 - ciptr->image_width) < 4) + ciptr->scale_denom=4; + else if(abs(x*8 - ciptr->image_width) < 8) + ciptr->scale_denom=8; + else + ciptr->scale_denom=1; + + jpeg_start_decompress(ciptr); + + px=ciptr->output_width; py=ciptr->output_height; + c=ciptr->output_components; + + + if(c==3) + { + lb=(JSAMPLE*)(*ciptr->mem->alloc_small)((j_common_ptr) ciptr,JPOOL_PERMANENT,c*px); + bp=*buffer; + while(ciptr->output_scanline < ciptr->output_height) + { + jpeg_read_scanlines(ciptr, &lb, 1); + memcpy(bp,lb,px*c); + bp+=px*c; + } + + } + jpeg_finish_decompress(ciptr); + jpeg_destroy_decompress(ciptr); + fclose(fh); +// dbout("fh_crw_load }\n"); + return(FH_ERROR_OK); +} + +int fh_crw_getsize(const char *filename,int *x,int *y, int wanted_width, int wanted_height) +{ +// dbout("fh_crw_getsize {\n"); + struct jpeg_decompress_struct cinfo; + struct jpeg_decompress_struct *ciptr; + struct r_crw_jpeg_error_mgr emgr; + + int px,py,c; + FILE *fh; + + ciptr=&cinfo; + if(!(fh=fopen(filename,"rb"))) return(FH_ERROR_FILE); + + ciptr->err=jpeg_std_error(&emgr.pub); + emgr.pub.error_exit=crw_cb_error_exit; + if(setjmp(emgr.envbuffer)==1) + { + // FATAL ERROR - Free the object and return... + jpeg_destroy_decompress(ciptr); + fclose(fh); +// dbout("fh_crw_getsize } - FATAL ERROR\n"); + return(FH_ERROR_FORMAT); + } + + jpeg_create_decompress(ciptr); + fh_crw_find_jpeg_thumbnail(fh); + jpeg_stdio_src(ciptr,fh); + jpeg_read_header(ciptr,TRUE); + ciptr->out_color_space=JCS_RGB; + // should be more flexible... + if((int)ciptr->image_width/8 >= wanted_width || + (int)ciptr->image_height/8 >= wanted_height) + ciptr->scale_denom=8; + else if((int)ciptr->image_width/4 >= wanted_width || + (int)ciptr->image_height/4 >= wanted_height) + ciptr->scale_denom=4; + else if((int)ciptr->image_width/2 >= wanted_width || + (int)ciptr->image_height/2 >= wanted_height) + ciptr->scale_denom=2; + else + ciptr->scale_denom=1; + + jpeg_start_decompress(ciptr); + px=ciptr->output_width; py=ciptr->output_height; + c=ciptr->output_components; + *x=px; *y=py; +// jpeg_finish_decompress(ciptr); + jpeg_destroy_decompress(ciptr); + fclose(fh); +// dbout("fh_crw_getsize }\n"); + return(FH_ERROR_OK); +} + +#endif diff --git a/src/driver/pictureviewer/fb_display.cpp b/src/driver/pictureviewer/fb_display.cpp new file mode 100644 index 000000000..0022c2be7 --- /dev/null +++ b/src/driver/pictureviewer/fb_display.cpp @@ -0,0 +1,349 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fb_display.h" +#include "pictureviewer.h" +#include "driver/framebuffer.h" +/* + * FrameBuffer Image Display Function + * (c) smoku/2000 + * + */ + +/* Public Use Functions: + * + * extern void fb_display(unsigned char *rgbbuff, + * int x_size, int y_size, + * int x_pan, int y_pan, + * int x_offs, int y_offs); + * + * extern void getCurrentRes(int *x,int *y); + * + */ + +static unsigned short red[256], green[256], blue[256]; +static struct fb_cmap map332 = {0, 256, red, green, blue, NULL}; +static unsigned short red_b[256], green_b[256], blue_b[256]; +static struct fb_cmap map_back = {0, 256, red_b, green_b, blue_b, NULL}; + +static unsigned char *lfb = 0; + +int openFB(const char *name); +//void closeFB(int fh); +//void getVarScreenInfo(int fh, struct fb_var_screeninfo *var); +//void setVarScreenInfo(int fh, struct fb_var_screeninfo *var); +void getFixScreenInfo(struct fb_fix_screeninfo *fix); +void set332map(); +void blit2FB(void *fbbuff, + unsigned int pic_xs, unsigned int pic_ys, + unsigned int scr_xs, unsigned int scr_ys, + unsigned int xp, unsigned int yp, + unsigned int xoffs, unsigned int yoffs, + int cpp); +void clearFB(int bpp,int cpp); +inline unsigned short make16color(uint32_t r, uint32_t g, + uint32_t b, uint32_t rl, + uint32_t ro, uint32_t gl, + uint32_t go, uint32_t bl, + uint32_t bo, uint32_t tl, + uint32_t to); + +void fb_display(unsigned char *rgbbuff, int x_size, int y_size, int x_pan, int y_pan, int x_offs, int y_offs, bool clearfb, int transp) +{ + struct fb_var_screeninfo *var; + unsigned short *fbbuff = NULL; + int bp = 0; + if(rgbbuff==NULL) + return; + /* read current video mode */ + var = CFrameBuffer::getInstance()->getScreenInfo(); + lfb = (unsigned char *)CFrameBuffer::getInstance()->getFrameBufferPointer(); + + /* correct panning */ + if(x_pan > x_size - (int)var->xres) x_pan = 0; + if(y_pan > y_size - (int)var->yres) y_pan = 0; + /* correct offset */ + if(x_offs + x_size > (int)var->xres) x_offs = 0; + if(y_offs + y_size > (int)var->yres) y_offs = 0; + +//printf("fb_display: bits_per_pixel: %d\n", var->bits_per_pixel); +//printf("fb_display: var->xres %d var->yres %d x_size %d y_size %d\n", var->xres, var->yres, x_size, y_size); + /* blit buffer 2 fb */ + fbbuff = (unsigned short *) convertRGB2FB(rgbbuff, x_size, y_size, var->bits_per_pixel, &bp, transp); + if(fbbuff==NULL) + return; + /* ClearFB if image is smaller */ + //if(x_size < (int)var->xres || y_size < (int)var->yres) + if(clearfb) + clearFB(var->bits_per_pixel, bp); + blit2FB(fbbuff, x_size, y_size, var->xres, var->yres, x_pan, y_pan, x_offs, y_offs, bp); + free(fbbuff); +} + +void getCurrentRes(int *x, int *y) +{ + struct fb_var_screeninfo *var; + var = CFrameBuffer::getInstance()->getScreenInfo(); + *x = var->xres; + *y = var->yres; +//printf("getCurrentRes: %dx%d\n", var->xres, var->yres); +} + +void make332map(struct fb_cmap *map) +{ + int rs, gs, bs, i; + int r = 8, g = 8, b = 4; + + map->red = red; + map->green = green; + map->blue = blue; + + rs = 256 / (r - 1); + gs = 256 / (g - 1); + bs = 256 / (b - 1); + + for (i = 0; i < 256; i++) { + map->red[i] = (rs * ((i / (g * b)) % r)) * 255; + map->green[i] = (gs * ((i / b) % g)) * 255; + map->blue[i] = (bs * ((i) % b)) * 255; + } +} +/* +void set8map(int fh, struct fb_cmap *map) +{ + if (ioctl(fh, FBIOPUTCMAP, map) < 0) { + fprintf(stderr, "Error putting colormap"); + exit(1); + } +} + +void get8map(int fh, struct fb_cmap *map) +{ + if (ioctl(fh, FBIOGETCMAP, map) < 0) { + fprintf(stderr, "Error getting colormap"); + exit(1); + } +} +*/ +void set332map() +{ + make332map(&map332); + CFrameBuffer::getInstance()->paletteSet(&map332); +} + +void blit2FB(void *fbbuff, + unsigned int pic_xs, unsigned int pic_ys, + unsigned int scr_xs, unsigned int scr_ys, + unsigned int xp, unsigned int yp, + unsigned int xoffs, unsigned int yoffs, + int cpp) +{ + int i, xc, yc; + unsigned char *cp; unsigned short *sp; unsigned int *ip; + ip = (unsigned int *) fbbuff; + sp = (unsigned short *) ip; + cp = (unsigned char *) sp; + + xc = (pic_xs > scr_xs) ? scr_xs : pic_xs; + yc = (pic_ys > scr_ys) ? scr_ys : pic_ys; + + unsigned int stride = CFrameBuffer::getInstance()->getStride(); + + switch(cpp){ + case 1: + set332map(); + for(i = 0; i < yc; i++){ + memcpy(lfb+(i+yoffs)*stride+xoffs*cpp, cp + (i+yp)*pic_xs+xp,xc*cpp); + } + break; + case 2: + for(i = 0; i < yc; i++){ + memcpy(lfb+(i+yoffs)*stride+xoffs*cpp, sp + (i+yp)*pic_xs+xp, xc*cpp); + } + break; + case 4: + for(i = 0; i < yc; i++){ + memcpy(lfb+(i+yoffs)*stride+xoffs*cpp, ip + (i+yp)*pic_xs+xp, xc*cpp); + } + break; + } +} + +void clearFB(int bpp, int cpp) +{ + int x,y; + getCurrentRes(&x,&y); + unsigned int stride = CFrameBuffer::getInstance()->getStride(); + +//printf("clearFB: stride %d y %d cpp %d bpp %d total %d\n", stride, y, cpp, bpp, stride*y*cpp); + switch(cpp){ + case 2: + { + uint32_t rl, ro, gl, go, bl, bo, tl, to; + unsigned int i; + struct fb_var_screeninfo *var; + var = CFrameBuffer::getInstance()->getScreenInfo(); + rl = (var->red).length; + ro = (var->red).offset; + gl = (var->green).length; + go = (var->green).offset; + bl = (var->blue).length; + bo = (var->blue).offset; + tl = (var->transp).length; + to = (var->transp).offset; + short black=make16color(0,0,0, rl, ro, gl, go, bl, bo, tl, to); + unsigned short *s_fbbuff = (unsigned short *) malloc(y*stride/2 * sizeof(unsigned short)); + if(s_fbbuff==NULL) + { + printf("Error: malloc\n"); + return; + } + + for(i = 0; i < y*stride/2; i++) + s_fbbuff[i] = black; + memcpy(lfb, s_fbbuff, y*stride); + free(s_fbbuff); + } + break; + case 4: + { + uint32_t col = 0xFF000000; + uint32_t * dest = (uint32_t *) lfb; + for(unsigned int i = 0; i < stride*y/4; i ++) + dest[i] = col; + } + break; + default: + //memset(lfb, 0xFF, stride*y); + memset(lfb, 0, stride*y); + break; + } +} + +inline unsigned char make8color(unsigned char r, unsigned char g, unsigned char b) +{ + return ( + (((r >> 5) & 7) << 5) | + (((g >> 5) & 7) << 2) | + ((b >> 6) & 3) ); +} + +inline unsigned short make15color(unsigned char r, unsigned char g, unsigned char b) +{ + return ( + (((b >> 3) & 31) << 10) | + (((g >> 3) & 31) << 5) | + ((r >> 3) & 31) ); +} + +inline unsigned short make16color(uint32_t r, uint32_t g, uint32_t b, + uint32_t rl, uint32_t ro, + uint32_t gl, uint32_t go, + uint32_t bl, uint32_t bo, + uint32_t tl, uint32_t to) +{ + return ( + // ((0xFF >> (8 - tl)) << to) | + ((r >> (8 - rl)) << ro) | + ((g >> (8 - gl)) << go) | + ((b >> (8 - bl)) << bo)); +} + +void* convertRGB2FB(unsigned char *rgbbuff, unsigned long x, unsigned long y, int bpp, int *cpp, int transp) +{ + unsigned long i; + void *fbbuff = NULL; + unsigned char *c_fbbuff; + unsigned short *s_fbbuff; + unsigned int *i_fbbuff; + unsigned long count = x*y; + uint32_t rl, ro, gl, go, bl, bo, tl, to; + + struct fb_var_screeninfo *var; + var = CFrameBuffer::getInstance()->getScreenInfo(); + rl = (var->red).length; + ro = (var->red).offset; + gl = (var->green).length; + go = (var->green).offset; + bl = (var->blue).length; + bo = (var->blue).offset; + tl = (var->transp).length; + to = (var->transp).offset; + + switch(bpp) + { + case 8: + *cpp = 1; + c_fbbuff = (unsigned char *) malloc(count * sizeof(unsigned char)); + if(c_fbbuff==NULL) + { + printf("Error: malloc\n"); + return NULL; + } + for(i = 0; i < count; i++) + c_fbbuff[i] = make8color(rgbbuff[i*3], rgbbuff[i*3+1], rgbbuff[i*3+2]); + fbbuff = (void *) c_fbbuff; + break; + case 15: + *cpp = 2; +#if HAVE_DVB_API_VERSION < 3 + s_fbbuff = (unsigned short *) malloc(count * sizeof(unsigned short)); + if(s_fbbuff==NULL) + { + printf("Error: malloc\n"); + return NULL; + } + for(i = 0; i < count ; i++) + s_fbbuff[i] = make15color(rgbbuff[i*3], rgbbuff[i*3+1], rgbbuff[i*3+2]); +#else + s_fbbuff = (unsigned short*) make15color_errdiff(rgbbuff, x, y); +#endif + fbbuff = (void *) s_fbbuff; + break; + case 16: + *cpp = 2; +#if HAVE_DVB_API_VERSION < 3 + s_fbbuff = (unsigned short *) malloc(count * sizeof(unsigned short)); + if(s_fbbuff==NULL) + { + printf("Error: malloc\n"); + return NULL; + } + for(i = 0; i < count ; i++) + s_fbbuff[i]=make16color(rgbbuff[i*3], rgbbuff[i*3+1], rgbbuff[i*3+2], rl, ro, gl, go, bl, bo, tl, to); +#else + s_fbbuff = (unsigned short*) make15color_errdiff(rgbbuff, x, y); +#endif + fbbuff = (void *) s_fbbuff; + break; + case 24: + case 32: + *cpp = 4; + i_fbbuff = (unsigned int *) malloc(count * sizeof(unsigned int)); + if(i_fbbuff==NULL) + { + printf("Error: malloc\n"); + return NULL; + } + // red rgbbuff[i*3] green rgbbuff[i*3+1] blue rgbbuff[i*3+2] + for(i = 0; i < count ; i++) + i_fbbuff[i] = (transp << 24) | ((rgbbuff[i*3] << 16) & 0xFF0000) | ((rgbbuff[i*3+1] << 8) & 0xFF00) | (rgbbuff[i*3+2] & 0xFF); + //i_fbbuff[i] = (transp << 24) | ((rgbbuff[i*3+2] << 16) & 0xFF0000) | ((rgbbuff[i*3+1] << 8) & 0xFF00) | (rgbbuff[i*3] & 0xFF); + fbbuff = (void *) i_fbbuff; + break; + default: + fprintf(stderr, "Unsupported video mode! You've got: %dbpp\n", bpp); + exit(1); + } + return fbbuff; +} diff --git a/src/driver/pictureviewer/fb_display.h b/src/driver/pictureviewer/fb_display.h new file mode 100644 index 000000000..914f08e4b --- /dev/null +++ b/src/driver/pictureviewer/fb_display.h @@ -0,0 +1,8 @@ +#ifndef __pictureviewer_fbdisplay__ +#define __pictureviewer_fbdisplay__ +void* convertRGB2FB(unsigned char *rgbbuff, unsigned long x, unsigned long y, int bpp, int *cpp, int transp = 0xFF); +extern void fb_display(unsigned char *rgbbuff, int x_size, int y_size, int x_pan, int y_pan, int x_offs, int y_offs, bool clearfb = true, int transp = 0xFF); +extern void getCurrentRes(int *x,int *y); +unsigned char * make15color_errdiff(unsigned char * orgin,int x, int y); +#endif + diff --git a/src/driver/pictureviewer/gif.cpp b/src/driver/pictureviewer/gif.cpp new file mode 100644 index 000000000..9d3d5cc94 --- /dev/null +++ b/src/driver/pictureviewer/gif.cpp @@ -0,0 +1,160 @@ +#include "config.h" + +#include +#include + +#ifdef FBV_SUPPORT_GIF + #include "pictureviewer.h" + #include + #include + #include + #include + #include +extern "C" { +#include +} + #include + #define min(a,b) ((a) < (b) ? (a) : (b)) + #define gflush return(FH_ERROR_FILE); + #define grflush { DGifCloseFile(gft); return(FH_ERROR_FORMAT); } + #define mgrflush { free(lb); free(slb); DGifCloseFile(gft); return(FH_ERROR_FORMAT); } + #define agflush return(FH_ERROR_FORMAT); + #define agrflush { DGifCloseFile(gft); return(FH_ERROR_FORMAT); } + + +int fh_gif_id(const char *name) +{ + int fd; + char id[4]; + fd=open(name,O_RDONLY); if(fd==-1) return(0); + read(fd,id,4); + close(fd); + if(id[0]=='G' && id[1]=='I' && id[2]=='F') return(1); + return(0); +} + +inline void m_rend_gif_decodecolormap(unsigned char *cmb,unsigned char *rgbb,ColorMapObject *cm,int s,int l) +{ + GifColorType *cmentry; + int i; + for(i=0;iColors[cmb[i]]; + *(rgbb++)=cmentry->Red; + *(rgbb++)=cmentry->Green; + *(rgbb++)=cmentry->Blue; + } +} +int fh_gif_load(const char *name,unsigned char **buffer,int* xp,int* yp) +{ + int px,py,i,ibxs; + int j; + unsigned char *fbptr; + unsigned char *lb; + unsigned char *slb; + GifFileType *gft; + GifByteType *extension; + int extcode; + GifRecordType rt; + ColorMapObject *cmap; + int cmaps; + + gft=DGifOpenFileName(name); + if(gft==NULL) gflush; + do + { + if(DGifGetRecordType(gft,&rt) == GIF_ERROR) grflush; + switch(rt) + { + case IMAGE_DESC_RECORD_TYPE: + + if(DGifGetImageDesc(gft)==GIF_ERROR) grflush; + px=gft->Image.Width; + py=gft->Image.Height; + lb=(unsigned char*)malloc(px*3); + slb=(unsigned char*) malloc(px); +// printf("reading...\n"); + if(lb!=NULL && slb!=NULL) + { + cmap=(gft->Image.ColorMap ? gft->Image.ColorMap : gft->SColorMap); + cmaps=cmap->ColorCount; + + ibxs=ibxs*3; + fbptr=*buffer; + if(!(gft->Image.Interlace)) + { + for(i=0;iImage.Width; + py=gft->Image.Height; + *x=px; *y=py; + DGifCloseFile(gft); + return(FH_ERROR_OK); + break; + case EXTENSION_RECORD_TYPE: + if(DGifGetExtension(gft,&extcode,&extension)==GIF_ERROR) grflush; + while(extension!=NULL) + if(DGifGetExtensionNext(gft,&extension)==GIF_ERROR) grflush; + break; + default: + break; + } + } + while( rt!= TERMINATE_RECORD_TYPE ); + DGifCloseFile(gft); + return(FH_ERROR_FORMAT); +} +#endif diff --git a/src/driver/pictureviewer/jpeg.cpp b/src/driver/pictureviewer/jpeg.cpp new file mode 100644 index 000000000..52a1badaf --- /dev/null +++ b/src/driver/pictureviewer/jpeg.cpp @@ -0,0 +1,310 @@ +#include "../../../config.h" +#include "config.h" +#ifdef FBV_SUPPORT_JPEG + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +#include + +#include +#include "pictureviewer.h" +#include "picv_client_server.h" + +#define MIN(a,b) ((a)>(b)?(b):(a)) + +struct r_jpeg_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf envbuffer; +}; + + +int fh_jpeg_id(const char *name) +{ +// dbout("fh_jpeg_id {\n"); + int fd; + unsigned char id[10]; + fd=open(name,O_RDONLY); if(fd==-1) return(0); + read(fd,id,10); + close(fd); +// dbout("fh_jpeg_id }\n"); + if(id[6]=='J' && id[7]=='F' && id[8]=='I' && id[9]=='F') return(1); + if(id[0]==0xff && id[1]==0xd8 && id[2]==0xff) return(1); + return(0); +} + + +void jpeg_cb_error_exit(j_common_ptr cinfo) +{ +// dbout("jpeg_cd_error_exit {\n"); + struct r_jpeg_error_mgr *mptr; + mptr=(struct r_jpeg_error_mgr*) cinfo->err; + (*cinfo->err->output_message) (cinfo); + longjmp(mptr->envbuffer,1); +// dbout("jpeg_cd_error_exit }\n"); +} + +#define BUFFERLEN 8192 +int fh_jpeg_load_via_server(const char *filename,unsigned char *buffer,int x,int y) +{ + struct sockaddr_in si_other; + int s, slen=sizeof(si_other); + int bytes, port; + char path[PICV_CLIENT_SERVER_PATHLEN]; + struct pic_data pd; + + strncpy(path, filename, PICV_CLIENT_SERVER_PATHLEN-1); + path[PICV_CLIENT_SERVER_PATHLEN - 1] = 0; + + dbout("fh_jpeg_load_via_server (%s/%d/%d) {\n",basename(filename),x,y); + if ((s=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==-1) + { + perror("socket:"); + return(FH_ERROR_FILE); + } + port=atoi(g_settings.picviewer_decode_server_port); + printf("Server %s [%d]\n",g_settings.picviewer_decode_server_ip.c_str(),port); + + memset((char *) &si_other, sizeof(si_other), 0); + si_other.sin_family = AF_INET; + si_other.sin_port = htons(port); + if (inet_aton(g_settings.picviewer_decode_server_ip.c_str(), + &si_other.sin_addr)==0) + { + fprintf(stderr, "inet_aton() failed\n"); + return(FH_ERROR_FILE); + } + if (connect(s, (struct sockaddr *) &si_other, slen)==-1) + { + perror("connect()"); + return(FH_ERROR_FILE); + } + if (send(s, path, PICV_CLIENT_SERVER_PATHLEN, 0)==-1) + { + perror("send()"); + return(FH_ERROR_FILE); + } + pd.width=htonl(x); + pd.height=htonl(y); + if (send(s, &pd, sizeof(pd), 0)==-1) + { + perror("send()"); + return(FH_ERROR_FILE); + } + if (recv(s, &pd, sizeof(pd), 0) < (int)sizeof(pd)) + { + perror("recv pic desc"); + return(FH_ERROR_FILE); + } + if ((int)ntohl(pd.width) != x || (int)ntohl(pd.height) != y) + { + fprintf(stderr,"ugh, decoded pic has wrong size [%d/%d]<>[%d/%d]\n", ntohl(pd.width), ntohl(pd.height), x, y); + return(FH_ERROR_FILE); + } + unsigned char buf2[BUFFERLEN]; + unsigned char* workptr=buffer; + int rest = x*y*2; + while (rest > 0) + { + bytes=recv(s, buf2, MIN(BUFFERLEN,rest), 0); + if(bytes % 2 ==1) + bytes+=recv(s, buf2+bytes, 1, 0); + + for(int i=0 ; i < bytes ; i+=2) + { + *workptr = (buf2[i] >> 2) << 3; + workptr++; + *workptr = (buf2[i] << 6) | ((buf2[i+1] >> 5) << 3); + workptr++; + *workptr = (buf2[i+1] << 3); + workptr++; + } + rest-=bytes; + } + dbout("fh_jpeg_load_via_server }\n"); + return(FH_ERROR_OK); +} +int fh_jpeg_load_local(const char *filename,unsigned char **buffer,int* x,int* y) +{ + //dbout("fh_jpeg_load_local (%s/%d/%d) {\n",basename(filename),*x,*y); + struct jpeg_decompress_struct cinfo; + struct jpeg_decompress_struct *ciptr; + struct r_jpeg_error_mgr emgr; + unsigned char *bp; + int px,py,c; + FILE *fh; + JSAMPLE *lb; + + ciptr=&cinfo; + if(!(fh=fopen(filename,"rb"))) return(FH_ERROR_FILE); + ciptr->err=jpeg_std_error(&emgr.pub); + emgr.pub.error_exit=jpeg_cb_error_exit; + if(setjmp(emgr.envbuffer)==1) + { + // FATAL ERROR - Free the object and return... + jpeg_destroy_decompress(ciptr); + fclose(fh); +// dbout("fh_jpeg_load } - FATAL ERROR\n"); + return(FH_ERROR_FORMAT); + } + + jpeg_create_decompress(ciptr); + jpeg_stdio_src(ciptr,fh); + jpeg_read_header(ciptr,TRUE); + ciptr->out_color_space=JCS_RGB; + ciptr->dct_method=JDCT_FASTEST; + if(*x==(int)ciptr->image_width) + ciptr->scale_denom=1; + else if(abs(*x*2 - ciptr->image_width) < 2) + ciptr->scale_denom=2; + else if(abs(*x*4 - ciptr->image_width) < 4) + ciptr->scale_denom=4; + else if(abs(*x*8 - ciptr->image_width) < 8) + ciptr->scale_denom=8; + else + ciptr->scale_denom=1; + + jpeg_start_decompress(ciptr); + + px=ciptr->output_width; py=ciptr->output_height; + c=ciptr->output_components; + if(px > *x || py > *y) + { + // pic act larger, e.g. because of not responding jpeg server + free(*buffer); + *buffer = (unsigned char*) malloc(px*py*3); + *x = px; + *y = py; + } + + if(c==3) + { + lb=(JSAMPLE*)(*ciptr->mem->alloc_small)((j_common_ptr) ciptr,JPOOL_PERMANENT,c*px); + bp=*buffer; + while(ciptr->output_scanline < ciptr->output_height) + { + jpeg_read_scanlines(ciptr, &lb, 1); + memcpy(bp,lb,px*c); + bp+=px*c; + } + + } + jpeg_finish_decompress(ciptr); + jpeg_destroy_decompress(ciptr); + fclose(fh); + //dbout("fh_jpeg_load_local }\n"); + return(FH_ERROR_OK); +} + +int fh_jpeg_load(const char *filename,unsigned char **buffer,int* x,int* y) +{ + int ret=FH_ERROR_FILE; +#if HAVE_DVB_API_VERSION >= 3 + if(!g_settings.picviewer_decode_server_ip.empty()) + ret=fh_jpeg_load_via_server(filename, *buffer, *x, *y); + if(ret!=FH_ERROR_OK) +#endif + ret=fh_jpeg_load_local(filename, buffer, x, y); + return ret; +} + +int fh_jpeg_getsize(const char *filename,int *x,int *y, int wanted_width, int wanted_height) +{ +// dbout("fh_jpeg_getsize {\n"); + struct jpeg_decompress_struct cinfo; + struct jpeg_decompress_struct *ciptr; + struct r_jpeg_error_mgr emgr; + + int px,py,c; + FILE *fh; + ciptr=&cinfo; + if(!(fh=fopen(filename,"rb"))) return(FH_ERROR_FILE); + + ciptr->err=jpeg_std_error(&emgr.pub); + emgr.pub.error_exit=jpeg_cb_error_exit; + if(setjmp(emgr.envbuffer)==1) + { + // FATAL ERROR - Free the object and return... + jpeg_destroy_decompress(ciptr); + fclose(fh); +// dbout("fh_jpeg_getsize } - FATAL ERROR\n"); + return(FH_ERROR_FORMAT); + } + + jpeg_create_decompress(ciptr); + jpeg_stdio_src(ciptr,fh); + jpeg_read_header(ciptr,TRUE); + ciptr->out_color_space=JCS_RGB; + // should be more flexible... + if((int)ciptr->image_width/8 >= wanted_width || + (int)ciptr->image_height/8 >= wanted_height) + ciptr->scale_denom=8; + else if((int)ciptr->image_width/4 >= wanted_width || + (int)ciptr->image_height/4 >= wanted_height) + ciptr->scale_denom=4; + else if((int)ciptr->image_width/2 >= wanted_width || + (int)ciptr->image_height/2 >= wanted_height) + ciptr->scale_denom=2; + else + ciptr->scale_denom=1; + + jpeg_start_decompress(ciptr); + px=ciptr->output_width; py=ciptr->output_height; + c=ciptr->output_components; +#if HAVE_DVB_API_VERSION >= 3 + if(!g_settings.picviewer_decode_server_ip.empty()) + { + // jpeg server resizes pic to desired size + if( px > wanted_width || py > wanted_height) + { + if( (CPictureViewer::m_aspect_ratio_correction*py*wanted_width/px) <= wanted_height) + { + *x=wanted_width; + *y=(int)(CPictureViewer::m_aspect_ratio_correction*py*wanted_width/px); + } + else + { + *x=(int)((1.0/CPictureViewer::m_aspect_ratio_correction)*px*wanted_height/py); + *y=wanted_height; + } + } + else if(CPictureViewer::m_aspect_ratio_correction >=1) + { + *x=px; + *y=(int)(py/CPictureViewer::m_aspect_ratio_correction); + } + else + { + *x=(int)(px/CPictureViewer::m_aspect_ratio_correction); + *y=py; + } + + } + else +#endif + { + *x=px; + *y=py; + } +// jpeg_finish_decompress(ciptr); + jpeg_destroy_decompress(ciptr); + fclose(fh); +// dbout("fh_jpeg_getsize }\n"); + return(FH_ERROR_OK); +} +#endif diff --git a/src/driver/pictureviewer/make15color_errdiff.cpp b/src/driver/pictureviewer/make15color_errdiff.cpp new file mode 100644 index 000000000..e00ae47ee --- /dev/null +++ b/src/driver/pictureviewer/make15color_errdiff.cpp @@ -0,0 +1,155 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2005 Zwen + + Kommentar: + This is an implementation of the floyd steinberg error diffusion algorithm + adapted for 24bit to 15bit color reduction. + + For a description of the base alorithm see e.g.: + http://www.informatik.fh-muenchen.de/~schieder/graphik-01-02/slide0264.html + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "pictureviewer.h" + +void c32_15(unsigned char r, unsigned char g , unsigned char b , unsigned char* d) +{ + *d = ((r >> 1) & 0x7C) | (g >> 6); + *(d+1) = ((g << 2) & 0xE0) | (b >> 3); +} + +#define FS_CALC_ERROR_COMMON(color, index) \ + p1 = p2 = (p_src[index] + (this_line_error_##color[ix]>>4)); \ + if(p1>255)p1=255; if(p1<0)p1=0; \ + color = (p1 & 0xF8) | 0x4; \ + error = p2 - color; \ + +#define FS_CALC_ERROR_RIGHT(color, index) \ + FS_CALC_ERROR_COMMON(color,index) \ + this_line_error_##color[ix+1] += (error * 7); \ + next_line_error_##color[ix-1] += (error * 3); \ + next_line_error_##color[ix] += (error * 5); \ + next_line_error_##color[ix+1] += error; + +#define FS_CALC_ERROR_LEFT(color, index) \ + FS_CALC_ERROR_COMMON(color,index) \ + this_line_error_##color[ix-1] += (error * 7); \ + next_line_error_##color[ix+1] += (error * 3); \ + next_line_error_##color[ix] += (error * 5); \ + next_line_error_##color[ix-1] += error; + +unsigned char * make15color_errdiff(unsigned char * src,int width, int height) +{ + int odd_line=1; + int ix,iy, error, p1, p2; + unsigned char r,g,b; + unsigned char *p_src, *p_dst; + unsigned char *dst = (unsigned char*) malloc(width*height*2); + int *this_line_error_r; + int *this_line_error_g; + int *this_line_error_b; + int *next_line_error_r; + int *next_line_error_g; + int *next_line_error_b; + int *save_error; + int *error1_r = (int*) malloc((width+2)*sizeof(int)); + int *error1_g = (int*) malloc((width+2)*sizeof(int)); + int *error1_b = (int*) malloc((width+2)*sizeof(int)); + int *error2_r = (int*) malloc((width+2)*sizeof(int)); + int *error2_g = (int*) malloc((width+2)*sizeof(int)); + int *error2_b = (int*) malloc((width+2)*sizeof(int)); + + dbout("Start error diffusion\n"); + + this_line_error_r = error1_r; + this_line_error_g = error1_g; + this_line_error_b = error1_b; + next_line_error_r = error2_r; + next_line_error_g = error2_g; + next_line_error_b = error2_b; + memset (this_line_error_r, 0 , (width+2) * sizeof(int)); + memset (this_line_error_g, 0 , (width+2) * sizeof(int)); + memset (this_line_error_b, 0 , (width+2) * sizeof(int)); + memset (next_line_error_r, 0 , (width+2) * sizeof(int)); + memset (next_line_error_g, 0 , (width+2) * sizeof(int)); + memset (next_line_error_b, 0 , (width+2) * sizeof(int)); + p_src = src; + p_dst = dst; + + for(iy=0 ; iy < height ; iy++) + { + save_error = this_line_error_r; + this_line_error_r = next_line_error_r; + next_line_error_r = save_error; + save_error = this_line_error_g; + this_line_error_g = next_line_error_g; + next_line_error_g = save_error; + save_error = this_line_error_b; + this_line_error_b = next_line_error_b; + next_line_error_b = save_error; + memset (next_line_error_r, 0 , (width+2) * sizeof(int)); + memset (next_line_error_g, 0 , (width+2) * sizeof(int)); + memset (next_line_error_b, 0 , (width+2) * sizeof(int)); + + if(odd_line) + { + for(ix=1 ; ix <= width ; ix++) + { + FS_CALC_ERROR_RIGHT(r,0); + FS_CALC_ERROR_RIGHT(g,1); + FS_CALC_ERROR_RIGHT(b,2); + c32_15(r,g,b,p_dst); + p_src+=3; + p_dst+=2; + } + odd_line=0; + } + else + { + p_src+=(width-1)*3; + p_dst+=(width-1)*2; + for(ix=width ; ix >= 1 ; ix--) + { + FS_CALC_ERROR_LEFT(r,0); + FS_CALC_ERROR_LEFT(g,1); + FS_CALC_ERROR_LEFT(b,2); + c32_15(r,g,b,p_dst); + p_src-=3; + p_dst-=2; + } + p_src+=width*3; + p_dst+=width*2; + odd_line=1; + } + } + free(error1_r); + free(error1_g); + free(error1_b); + free(error2_r); + free(error2_g); + free(error2_b); + dbout("End error diffusion\n"); + return dst; +} + diff --git a/src/driver/pictureviewer/pictureviewer.cpp b/src/driver/pictureviewer/pictureviewer.cpp new file mode 100644 index 000000000..e7069ba11 --- /dev/null +++ b/src/driver/pictureviewer/pictureviewer.cpp @@ -0,0 +1,540 @@ +#include +#include +#include "pictureviewer.h" +#include "config.h" +#include "fb_display.h" +#include "driver/framebuffer.h" + + +#include +#include +#include + +/* resize.cpp */ +extern unsigned char *simple_resize (unsigned char *orgin, int ox, int oy, int dx, int dy); +extern unsigned char *color_average_resize (unsigned char *orgin, int ox, int oy, int dx, int dy); + + +#ifdef FBV_SUPPORT_GIF +extern int fh_gif_getsize (const char *, int *, int *, int, int); +extern int fh_gif_load (const char *, unsigned char **, int *, int *); +extern int fh_gif_id (const char *); +#endif +#ifdef FBV_SUPPORT_JPEG +extern int fh_jpeg_getsize (const char *, int *, int *, int, int); +extern int fh_jpeg_load (const char *, unsigned char **, int *, int *); +extern int fh_jpeg_id (const char *); +#endif +#ifdef FBV_SUPPORT_PNG +extern int fh_png_getsize (const char *, int *, int *, int, int); +extern int fh_png_load (const char *, unsigned char **, int *, int *); +extern int fh_png_id (const char *); +#endif +#ifdef FBV_SUPPORT_BMP +extern int fh_bmp_getsize (const char *, int *, int *, int, int); +extern int fh_bmp_load (const char *, unsigned char **, int *, int *); +extern int fh_bmp_id (const char *); +#endif +#ifdef FBV_SUPPORT_CRW +extern int fh_crw_getsize (const char *, int *, int *, int, int); +extern int fh_crw_load (const char *, unsigned char **, int *, int *); +extern int fh_crw_id (const char *); +#endif + +double CPictureViewer::m_aspect_ratio_correction; + +void CPictureViewer::add_format (int (*picsize) (const char *, int *, int *, int, int), int (*picread) (const char *, unsigned char **, int *, int *), int (*id) (const char *)) +{ + CFormathandler *fhn; + fhn = (CFormathandler *) malloc (sizeof (CFormathandler)); + fhn->get_size = picsize; + fhn->get_pic = picread; + fhn->id_pic = id; + fhn->next = fh_root; + fh_root = fhn; +} + +void CPictureViewer::init_handlers (void) +{ +#ifdef FBV_SUPPORT_GIF + add_format (fh_gif_getsize, fh_gif_load, fh_gif_id); +#endif +#ifdef FBV_SUPPORT_JPEG + add_format (fh_jpeg_getsize, fh_jpeg_load, fh_jpeg_id); +#endif +#ifdef FBV_SUPPORT_PNG + add_format (fh_png_getsize, fh_png_load, fh_png_id); +#endif +#ifdef FBV_SUPPORT_BMP + add_format (fh_bmp_getsize, fh_bmp_load, fh_bmp_id); +#endif +#ifdef FBV_SUPPORT_CRW + add_format (fh_crw_getsize, fh_crw_load, fh_crw_id); +#endif +} + +CPictureViewer::CFormathandler * CPictureViewer::fh_getsize (const char *name, int *x, int *y, int width_wanted, int height_wanted) +{ + CFormathandler *fh; + for (fh = fh_root; fh != NULL; fh = fh->next) { + if (fh->id_pic (name)) + if (fh->get_size (name, x, y, width_wanted, height_wanted) == FH_ERROR_OK) + return (fh); + } + return (NULL); +} + +bool CPictureViewer::DecodeImage (const std::string & name, bool showBusySign, bool unscaled) +{ +// dbout("DecodeImage {\n"); + if (name == m_NextPic_Name) { +// dbout("DecodeImage }\n"); + return true; + } + + int x, y, xs, ys, imx, imy; + getCurrentRes (&xs, &ys); + + // Show red block for "next ready" in view state + if (showBusySign) + showBusy (m_startx + 3, m_starty + 3, 10, 0xff, 00, 00); + + CFormathandler *fh; + if (unscaled) + fh = fh_getsize (name.c_str (), &x, &y, INT_MAX, INT_MAX); + else + fh = fh_getsize (name.c_str (), &x, &y, m_endx - m_startx, m_endy - m_starty); + if (fh) { + if (m_NextPic_Buffer != NULL) { + free (m_NextPic_Buffer); + } + m_NextPic_Buffer = (unsigned char *) malloc (x * y * 3); + if (m_NextPic_Buffer == NULL) { + printf ("Error: malloc\n"); + return false; + } +// dbout("---Decoding Start(%d/%d)\n",x,y); + if (fh->get_pic (name.c_str (), &m_NextPic_Buffer, &x, &y) == FH_ERROR_OK) { +// dbout("---Decoding Done\n"); + if ((x > (m_endx - m_startx) || y > (m_endy - m_starty)) && m_scaling != NONE && !unscaled) { + if ((m_aspect_ratio_correction * y * (m_endx - m_startx) / x) <= (m_endy - m_starty)) { + imx = (m_endx - m_startx); + imy = (int) (m_aspect_ratio_correction * y * (m_endx - m_startx) / x); + } else { + imx = (int) ((1.0 / m_aspect_ratio_correction) * x * (m_endy - m_starty) / y); + imy = (m_endy - m_starty); + } + if (m_scaling == SIMPLE) + m_NextPic_Buffer = simple_resize (m_NextPic_Buffer, x, y, imx, imy); + else + m_NextPic_Buffer = color_average_resize (m_NextPic_Buffer, x, y, imx, imy); + x = imx; + y = imy; + } + m_NextPic_X = x; + m_NextPic_Y = y; + if (x < (m_endx - m_startx)) + m_NextPic_XPos = (m_endx - m_startx - x) / 2 + m_startx; + else + m_NextPic_XPos = m_startx; + if (y < (m_endy - m_starty)) + m_NextPic_YPos = (m_endy - m_starty - y) / 2 + m_starty; + else + m_NextPic_YPos = m_starty; + if (x > (m_endx - m_startx)) + m_NextPic_XPan = (x - (m_endx - m_startx)) / 2; + else + m_NextPic_XPan = 0; + if (y > (m_endy - m_starty)) + m_NextPic_YPan = (y - (m_endy - m_starty)) / 2; + else + m_NextPic_YPan = 0; + } else { + printf ("Unable to read file !\n"); + free (m_NextPic_Buffer); + m_NextPic_Buffer = (unsigned char *) malloc (3); + if (m_NextPic_Buffer == NULL) { + printf ("Error: malloc\n"); + return false; + } + memset (m_NextPic_Buffer, 0, 3); + m_NextPic_X = 1; + m_NextPic_Y = 1; + m_NextPic_XPos = 0; + m_NextPic_YPos = 0; + m_NextPic_XPan = 0; + m_NextPic_YPan = 0; + } + } else { + printf ("Unable to read file or format not recognized!\n"); + if (m_NextPic_Buffer != NULL) { + free (m_NextPic_Buffer); + } + m_NextPic_Buffer = (unsigned char *) malloc (3); + if (m_NextPic_Buffer == NULL) { + printf ("Error: malloc\n"); + return false; + } + memset (m_NextPic_Buffer, 0, 3); + m_NextPic_X = 1; + m_NextPic_Y = 1; + m_NextPic_XPos = 0; + m_NextPic_YPos = 0; + m_NextPic_XPan = 0; + m_NextPic_YPan = 0; + } + m_NextPic_Name = name; + hideBusy (); +// dbout("DecodeImage }\n"); + return (m_NextPic_Buffer != NULL); +} + +void CPictureViewer::SetVisible (int startx, int endx, int starty, int endy) +{ + m_startx = startx; + m_endx = endx; + m_starty = starty; + m_endy = endy; +} + + +bool CPictureViewer::ShowImage (const std::string & filename, bool unscaled) +{ +// dbout("Show Image {\n"); + // Wird eh ueberschrieben ,also schonmal freigeben... (wenig speicher) + if (m_CurrentPic_Buffer != NULL) { + free (m_CurrentPic_Buffer); + m_CurrentPic_Buffer = NULL; + } + DecodeImage (filename, true, unscaled); + DisplayNextImage (); +// dbout("Show Image }\n"); + return true; +} + +bool CPictureViewer::DisplayNextImage () +{ +// dbout("DisplayNextImage {\n"); + if (m_CurrentPic_Buffer != NULL) { + free (m_CurrentPic_Buffer); + m_CurrentPic_Buffer = NULL; + } + if (m_NextPic_Buffer != NULL) + fb_display (m_NextPic_Buffer, m_NextPic_X, m_NextPic_Y, m_NextPic_XPan, m_NextPic_YPan, m_NextPic_XPos, m_NextPic_YPos); +// dbout("DisplayNextImage fb_disp done\n"); + m_CurrentPic_Buffer = m_NextPic_Buffer; + m_NextPic_Buffer = NULL; + m_CurrentPic_Name = m_NextPic_Name; + m_CurrentPic_X = m_NextPic_X; + m_CurrentPic_Y = m_NextPic_Y; + m_CurrentPic_XPos = m_NextPic_XPos; + m_CurrentPic_YPos = m_NextPic_YPos; + m_CurrentPic_XPan = m_NextPic_XPan; + m_CurrentPic_YPan = m_NextPic_YPan; +// dbout("DisplayNextImage }\n"); + return true; +} + +void CPictureViewer::Zoom (float factor) +{ +// dbout("Zoom %f\n",factor); + showBusy (m_startx + 3, m_starty + 3, 10, 0xff, 0xff, 00); + + int oldx = m_CurrentPic_X; + int oldy = m_CurrentPic_Y; + unsigned char *oldBuf = m_CurrentPic_Buffer; + m_CurrentPic_X = (int) (factor * m_CurrentPic_X); + m_CurrentPic_Y = (int) (factor * m_CurrentPic_Y); + + if (m_scaling == COLOR) + m_CurrentPic_Buffer = color_average_resize (m_CurrentPic_Buffer, oldx, oldy, m_CurrentPic_X, m_CurrentPic_Y); + else + m_CurrentPic_Buffer = simple_resize (m_CurrentPic_Buffer, oldx, oldy, m_CurrentPic_X, m_CurrentPic_Y); + + if (m_CurrentPic_Buffer == oldBuf) { + // resize failed + hideBusy (); + return; + } + + if (m_CurrentPic_X < (m_endx - m_startx)) + m_CurrentPic_XPos = (m_endx - m_startx - m_CurrentPic_X) / 2 + m_startx; + else + m_CurrentPic_XPos = m_startx; + if (m_CurrentPic_Y < (m_endy - m_starty)) + m_CurrentPic_YPos = (m_endy - m_starty - m_CurrentPic_Y) / 2 + m_starty; + else + m_CurrentPic_YPos = m_starty; + if (m_CurrentPic_X > (m_endx - m_startx)) + m_CurrentPic_XPan = (m_CurrentPic_X - (m_endx - m_startx)) / 2; + else + m_CurrentPic_XPan = 0; + if (m_CurrentPic_Y > (m_endy - m_starty)) + m_CurrentPic_YPan = (m_CurrentPic_Y - (m_endy - m_starty)) / 2; + else + m_CurrentPic_YPan = 0; + fb_display (m_CurrentPic_Buffer, m_CurrentPic_X, m_CurrentPic_Y, m_CurrentPic_XPan, m_CurrentPic_YPan, m_CurrentPic_XPos, m_CurrentPic_YPos); +} + +void CPictureViewer::Move (int dx, int dy) +{ +// dbout("Move %d %d\n",dx,dy); + showBusy (m_startx + 3, m_starty + 3, 10, 0x00, 0xff, 00); + + int xs, ys; + getCurrentRes (&xs, &ys); + m_CurrentPic_XPan += dx; + if (m_CurrentPic_XPan + xs >= m_CurrentPic_X) + m_CurrentPic_XPan = m_CurrentPic_X - xs - 1; + if (m_CurrentPic_XPan < 0) + m_CurrentPic_XPan = 0; + + m_CurrentPic_YPan += dy; + if (m_CurrentPic_YPan + ys >= m_CurrentPic_Y) + m_CurrentPic_YPan = m_CurrentPic_Y - ys - 1; + if (m_CurrentPic_YPan < 0) + m_CurrentPic_YPan = 0; + + if (m_CurrentPic_X < (m_endx - m_startx)) + m_CurrentPic_XPos = (m_endx - m_startx - m_CurrentPic_X) / 2 + m_startx; + else + m_CurrentPic_XPos = m_startx; + if (m_CurrentPic_Y < (m_endy - m_starty)) + m_CurrentPic_YPos = (m_endy - m_starty - m_CurrentPic_Y) / 2 + m_starty; + else + m_CurrentPic_YPos = m_starty; +// dbout("Display x(%d) y(%d) xpan(%d) ypan(%d) xpos(%d) ypos(%d)\n",m_CurrentPic_X, m_CurrentPic_Y, +// m_CurrentPic_XPan, m_CurrentPic_YPan, m_CurrentPic_XPos, m_CurrentPic_YPos); + + fb_display (m_CurrentPic_Buffer, m_CurrentPic_X, m_CurrentPic_Y, m_CurrentPic_XPan, m_CurrentPic_YPan, m_CurrentPic_XPos, m_CurrentPic_YPos); +} + +CPictureViewer::CPictureViewer () +{ + fh_root = NULL; + m_scaling = COLOR; + //m_aspect = 4.0 / 3; + m_aspect = 16.0 / 9; + m_CurrentPic_Name = ""; + m_CurrentPic_Buffer = NULL; + m_CurrentPic_X = 0; + m_CurrentPic_Y = 0; + m_CurrentPic_XPos = 0; + m_CurrentPic_YPos = 0; + m_CurrentPic_XPan = 0; + m_CurrentPic_YPan = 0; + m_NextPic_Name = ""; + m_NextPic_Buffer = NULL; + m_NextPic_X = 0; + m_NextPic_Y = 0; + m_NextPic_XPos = 0; + m_NextPic_YPos = 0; + m_NextPic_XPan = 0; + m_NextPic_YPan = 0; + int xs, ys; + getCurrentRes (&xs, &ys); + m_startx = 0; + m_endx = xs - 1; + m_starty = 0; + m_endy = ys - 1; + m_aspect_ratio_correction = m_aspect / ((double) xs / ys); + + m_busy_buffer = NULL; + + init_handlers (); +} + +void CPictureViewer::showBusy (int sx, int sy, int width, char r, char g, char b) +{ +// dbout("Show Busy{\n"); + unsigned char rgb_buffer[3]; + unsigned char *fb_buffer; + unsigned char *busy_buffer_wrk; + int cpp; + struct fb_var_screeninfo *var; + var = CFrameBuffer::getInstance ()->getScreenInfo (); + + rgb_buffer[0] = r; + rgb_buffer[1] = g; + rgb_buffer[2] = b; + + fb_buffer = (unsigned char *) convertRGB2FB (rgb_buffer, 1, 1, var->bits_per_pixel, &cpp); + if (fb_buffer == NULL) { + printf ("Error: malloc\n"); + return; + } + if (m_busy_buffer != NULL) { + free (m_busy_buffer); + m_busy_buffer = NULL; + } + m_busy_buffer = (unsigned char *) malloc (width * width * cpp); + if (m_busy_buffer == NULL) { + printf ("Error: malloc\n"); + return; + } + busy_buffer_wrk = m_busy_buffer; + unsigned char *fb = (unsigned char *) CFrameBuffer::getInstance ()->getFrameBufferPointer (); + unsigned int stride = CFrameBuffer::getInstance ()->getStride (); + + for (int y = sy; y < sy + width; y++) { + for (int x = sx; x < sx + width; x++) { + memcpy (busy_buffer_wrk, fb + y * stride + x * cpp, cpp); + busy_buffer_wrk += cpp; + memcpy (fb + y * stride + x * cpp, fb_buffer, cpp); + } + } + m_busy_x = sx; + m_busy_y = sy; + m_busy_width = width; + m_busy_cpp = cpp; + free (fb_buffer); +// dbout("Show Busy}\n"); +} + +void CPictureViewer::hideBusy () +{ +// dbout("Hide Busy{\n"); + if (m_busy_buffer != NULL) { + unsigned char *fb = (unsigned char *) CFrameBuffer::getInstance ()->getFrameBufferPointer (); + unsigned int stride = CFrameBuffer::getInstance ()->getStride (); + unsigned char *busy_buffer_wrk = m_busy_buffer; + + for (int y = m_busy_y; y < m_busy_y + m_busy_width; y++) { + for (int x = m_busy_x; x < m_busy_x + m_busy_width; x++) { + memcpy (fb + y * stride + x * m_busy_cpp, busy_buffer_wrk, m_busy_cpp); + busy_buffer_wrk += m_busy_cpp; + } + } + free (m_busy_buffer); + m_busy_buffer = NULL; + } +// dbout("Hide Busy}\n"); +} +void CPictureViewer::Cleanup () +{ + if (m_busy_buffer != NULL) { + free (m_busy_buffer); + m_busy_buffer = NULL; + } + if (m_NextPic_Buffer != NULL) { + free (m_NextPic_Buffer); + m_NextPic_Buffer = NULL; + } + if (m_CurrentPic_Buffer != NULL) { + free (m_CurrentPic_Buffer); + m_CurrentPic_Buffer = NULL; + } +} +#define LOGO_DIR1 "/share/tuxbox/neutrino/icons/logo" +#define LOGO_DIR2 "/var/share/icons/logo" +#define LOGO_FMT ".jpg" + +bool CPictureViewer::DisplayLogo (uint64_t channel_id, int posx, int posy, int width, int height) +{ + char fname[255]; + bool ret = false; + sprintf(fname, "%s/%llx.jpg", LOGO_DIR2, channel_id & 0xFFFFFFFFFFFFULL); +printf("logo file: %s\n", fname); + if(access(fname, F_OK)) + sprintf(fname, "%s/%llx.gif", LOGO_DIR2, channel_id & 0xFFFFFFFFFFFFULL); + if(!access(fname, F_OK)) { + ret = DisplayImage(fname, posx, posy, width, height); + } + return ret; +} + +bool CPictureViewer::DisplayImage (const std::string & name, int posx, int posy, int width, int height) +{ + int x, y; + CFormathandler *fh; + bool ret = false; + + if (m_NextPic_Name != name || m_NextPic_X != width || m_NextPic_Y != height) { + + //getCurrentRes (&xs, &ys); + + fh = fh_getsize (name.c_str (), &x, &y, INT_MAX, INT_MAX); + if (fh) { + if (m_NextPic_Buffer != NULL) + free (m_NextPic_Buffer); + + m_NextPic_Buffer = (unsigned char *) malloc (x * y * 3); + if (m_NextPic_Buffer == NULL) { + printf ("Error: malloc\n"); + return false; + } + if (fh->get_pic (name.c_str (), &m_NextPic_Buffer, &x, &y) == FH_ERROR_OK) { +//printf("DisplayImage: decoded %s, %d x %d to x=%d y=%d\n", name.c_str (), x, y, posx, posy); + //FIXME m_aspect_ratio_correction ? + if(width && height) { + if(x != width || y != height) { + //m_NextPic_Buffer = simple_resize (m_NextPic_Buffer, x, y, imx, imy); + m_NextPic_Buffer = color_average_resize (m_NextPic_Buffer, x, y, width, height); + x = width; + y = height; + } + posx += (width-x)/2; + posy += (height-y)/2; + } +//printf("DisplayImage: display %s, %d x %d to x=%d y=%d\n", name.c_str (), x, y, posx, posy); + fb_display (m_NextPic_Buffer, x, y, 0, 0, posx, posy, false, convertSetupAlpha2Alpha(g_settings.infobar_alpha)); + m_NextPic_X = x; + m_NextPic_Y = y; + m_NextPic_Name = name; + ret = true; + } else { + printf ("Error decoding file %s\n", name.c_str ()); + free (m_NextPic_Buffer); + m_NextPic_Buffer = NULL; + m_NextPic_Name = ""; + } + } else { + printf("Error open file %s\n", name.c_str ()); + } + } else if(m_NextPic_Buffer) { + m_NextPic_XPos = posx; + m_NextPic_YPos = posy; + fb_display (m_NextPic_Buffer, m_NextPic_X, m_NextPic_Y, 0, 0, m_NextPic_XPos, m_NextPic_YPos, false, convertSetupAlpha2Alpha(g_settings.infobar_alpha)); + ret = true; + } + return ret; +} + +fb_pixel_t * CPictureViewer::getImage (const std::string & name, int width, int height) +{ + int x, y; + CFormathandler *fh; + unsigned char * buffer; + fb_pixel_t * ret = NULL; + + fh = fh_getsize (name.c_str (), &x, &y, INT_MAX, INT_MAX); + if (fh) { + + buffer = (unsigned char *) malloc (x * y * 3); + if (buffer == NULL) { + printf ("Error: malloc\n"); + return false; + } + if (fh->get_pic (name.c_str (), &buffer, &x, &y) == FH_ERROR_OK) { +printf("getImage: decoded %s, %d x %d \n", name.c_str (), x, y); + if(x != width || y != height) + { + buffer = color_average_resize (buffer, x, y, width, height); + x = width; + y = height; + } + struct fb_var_screeninfo *var = CFrameBuffer::getInstance()->getScreenInfo(); + int bp; + ret = (fb_pixel_t *) convertRGB2FB(buffer, x, y, var->bits_per_pixel, &bp, 0); + free(buffer); + //fb_display (buffer, x, y, 0, 0, posx, posy, false, convertSetupAlpha2Alpha(g_settings.infobar_alpha)); + } else { + printf ("Error decoding file %s\n", name.c_str ()); + free (buffer); + buffer = NULL; + } + } else + printf("Error open file %s\n", name.c_str ()); + + return ret; +} diff --git a/src/driver/pictureviewer/pictureviewer.h b/src/driver/pictureviewer/pictureviewer.h new file mode 100644 index 000000000..03c1c0673 --- /dev/null +++ b/src/driver/pictureviewer/pictureviewer.h @@ -0,0 +1,114 @@ +#ifndef __pictureviewer__ +#define __pictureviewer__ + +/* + pictureviewer - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include /* printf */ +#include /* gettimeofday */ +#include "driver/framebuffer.h" +class CPictureViewer +{ + struct cformathandler + { + struct cformathandler *next; + int (*get_size)(const char *,int *,int*, int, int); + int (*get_pic)(const char *,unsigned char **,int* ,int*); + int (*id_pic)(const char *); + }; + typedef struct cformathandler CFormathandler; + + public: + enum ScalingMode + { + NONE=0, + SIMPLE=1, + COLOR=2 + }; + CPictureViewer(); + ~CPictureViewer(){Cleanup();}; + bool ShowImage(const std::string & filename, bool unscaled=false); + bool DecodeImage(const std::string & name, bool showBusySign=false, bool unscaled=false); + bool DisplayNextImage(); + void SetScaling(ScalingMode s){m_scaling=s;} + void SetAspectRatio(float aspect_ratio) {m_aspect=aspect_ratio;} + void showBusy(int sx, int sy, int width, char r, char g, char b); + void hideBusy(); + void Zoom(float factor); + void Move(int dx, int dy); + void Cleanup(); + void SetVisible(int startx, int endx, int starty, int endy); + static double m_aspect_ratio_correction; + bool DisplayImage (const std::string & name, int posx, int posy, int width, int height); + bool DisplayLogo (uint64_t channel_id, int posx, int posy, int width, int height); + fb_pixel_t * getImage (const std::string & name, int width, int height); + + private: + CFormathandler *fh_root; + ScalingMode m_scaling; + float m_aspect; + std::string m_NextPic_Name; + unsigned char* m_NextPic_Buffer; + int m_NextPic_X; + int m_NextPic_Y; + int m_NextPic_XPos; + int m_NextPic_YPos; + int m_NextPic_XPan; + int m_NextPic_YPan; + std::string m_CurrentPic_Name; + unsigned char* m_CurrentPic_Buffer; + int m_CurrentPic_X; + int m_CurrentPic_Y; + int m_CurrentPic_XPos; + int m_CurrentPic_YPos; + int m_CurrentPic_XPan; + int m_CurrentPic_YPan; + + unsigned char* m_busy_buffer; + int m_busy_x; + int m_busy_y; + int m_busy_width; + int m_busy_cpp; + + int m_startx; + int m_starty; + int m_endx; + int m_endy; + + CFormathandler * fh_getsize(const char *name,int *x,int *y, int width_wanted, int height_wanted); + void init_handlers(void); + void add_format(int (*picsize)(const char *,int *,int*,int,int),int (*picread)(const char *,unsigned char **,int*,int*), int (*id)(const char*)); +}; + + +#define FH_ERROR_OK 0 +#define FH_ERROR_FILE 1 /* read/access error */ +#define FH_ERROR_FORMAT 2 /* file format error */ +#define FH_ERROR_MALLOC 3 /* error during malloc */ + +#define dbout(fmt, args...) {struct timeval tv; gettimeofday(&tv,NULL); \ + printf( "PV[%ld|%02ld] " fmt, (long)tv.tv_sec, (long)tv.tv_usec/10000, ## args);} +#endif diff --git a/src/driver/pictureviewer/picv_client_server.h b/src/driver/pictureviewer/picv_client_server.h new file mode 100644 index 000000000..c23cfee42 --- /dev/null +++ b/src/driver/pictureviewer/picv_client_server.h @@ -0,0 +1,37 @@ +/* + + structs/defines for client server communication + between neutrino picviewer and jpeg decode server + + (c) Zwen@tuxbox.org + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef picv_client_server__ +#define picv_client_server__ + +#define PICV_CLIENT_SERVER_PATHLEN 1000 + +struct pic_data +{ + uint32_t width; + uint32_t height; + uint32_t bpp; /* unused atm */ +}; + +#endif diff --git a/src/driver/pictureviewer/png.cpp b/src/driver/pictureviewer/png.cpp new file mode 100644 index 000000000..539b0b7b7 --- /dev/null +++ b/src/driver/pictureviewer/png.cpp @@ -0,0 +1,158 @@ +#include "config.h" + +#ifdef FBV_SUPPORT_PNG + #include + #include + #include +#include +#include + + #include "pictureviewer.h" + + #define PNG_BYTES_TO_CHECK 4 + #define min(x,y) ((x) < (y) ? (x) : (y)) + +int fh_png_id(const char *name) +{ + int fd; + char id[4]; + fd=open(name,O_RDONLY); if(fd==-1) return(0); + read(fd,id,4); + close(fd); + if(id[1]=='P' && id[2]=='N' && id[3]=='G') return(1); + return(0); +} + + +int fh_png_load(const char *name,unsigned char **buffer,int* xp,int* yp) +{ + static const png_color_16 my_background = {0, 0, 0, 0, 0}; + + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + unsigned int i; + int bit_depth, color_type, interlace_type; + int number_passes,pass; + png_byte * fbptr; + FILE * fh; + + if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); + if(png_ptr == NULL) { + fclose(fh); + return(FH_ERROR_FORMAT); + } + info_ptr = png_create_info_struct(png_ptr); + if(info_ptr == NULL) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + fclose(fh); + return(FH_ERROR_FORMAT); + } + + if(setjmp(png_ptr->jmpbuf)) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fh); + return(FH_ERROR_FORMAT); + } + + png_init_io(png_ptr,fh); + + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_set_palette_to_rgb(png_ptr); + png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + /* other possibility for png_set_background: use png_get_bKGD */ + } + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + png_set_gray_to_rgb(png_ptr); + png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + + if (bit_depth < 8) + png_set_packing(png_ptr); + + if (bit_depth == 16) + png_set_strip_16(png_ptr); + + /* on Intel PC ?: + if (bit_depth == 16) + png_set_swap(png_ptr); + */ + + number_passes = png_set_interlace_handling(png_ptr); + png_read_update_info(png_ptr,info_ptr); + + if (width * 3 != png_get_rowbytes(png_ptr, info_ptr)) + { + printf("[png.cpp]: Error processing %s - please report (including image).\n", name); + fclose(fh); + return(FH_ERROR_FORMAT); + } + + for(pass = 0; pass < number_passes; pass++) + { + fbptr = (png_byte *)(*buffer); + for (i = 0; i < height; i++, fbptr += width * 3) + { + png_read_row(png_ptr, fbptr, NULL); + } + } + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fh); + return(FH_ERROR_OK); +} + +int fh_png_getsize(const char *name,int *x,int *y, int wanted_width, int wanted_height) +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + FILE *fh; + + if(!(fh=fopen(name,"rb"))) return(FH_ERROR_FILE); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); + if(png_ptr == NULL) { + fclose(fh); + return(FH_ERROR_FORMAT); + } + info_ptr = png_create_info_struct(png_ptr); + if(info_ptr == NULL) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + fclose(fh); + return(FH_ERROR_FORMAT); + } + + if(setjmp(png_ptr->jmpbuf)) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fh); + return(FH_ERROR_FORMAT); + } + + png_init_io(png_ptr,fh); + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + *x=width; + *y=height; + fclose(fh); + return(FH_ERROR_OK); +} +#endif diff --git a/src/driver/pictureviewer/resize.cpp b/src/driver/pictureviewer/resize.cpp new file mode 100644 index 000000000..662385564 --- /dev/null +++ b/src/driver/pictureviewer/resize.cpp @@ -0,0 +1,80 @@ +#include +#include + +#include "pictureviewer.h" + +unsigned char * simple_resize(unsigned char * orgin,int ox,int oy,int dx,int dy) +{ +// dbout("simple_resize{\n"); + unsigned char *cr,*p,*l; + int i,j,k,ip; + cr=(unsigned char*) malloc(dx*dy*3); + if(cr==NULL) + { + printf("Error: malloc\n"); +// dbout("simple_resize}\n"); + return(orgin); + } + l=cr; + + for(j=0;j=ox) + xb_v[i]=ox-1; + } + for(j=0;j=oy) yb=oy-1; + for(i=0;i +#include +#include +#include +#include +#include +#include + +#include "pig.h" + + + + +// Video4Linux API for PIG +// + +// +// -- Picture in Graphics Control +// -- This module is a Class to provide a PIG abstraction layer +// -- +// -- 2002-11 rasc +// -- 2003-06 rasc V4L Api +// + + + +// +// -- Constructor +// + +CPIG::CPIG() +{ + fd = -1; + status = CLOSED; +} + + +CPIG::CPIG(int pig_nr) +{ + fd = -1; + status = CLOSED; + fd = pigopen (pig_nr); +} + + +CPIG::CPIG(int pig_nr, int x, int y, int w, int h) +{ + fd = -1; + status = CLOSED; + fd = pigopen (pig_nr); + set_coord (x,y, w,h); + +} + +CPIG::~CPIG() +{ + pigclose (); // cleanup anyway!! + +} + + +// +// -- open PIG #nr +// -- return >=0: ok +// + +int CPIG::pigopen (int pig_nr) +{ + + char *pigdevs[] = { + PIG_DEV "0" // PIG device 0 + // PIG_DEV "1", // PIG device 1 + // PIG_DEV "2", // PIG device ... + // PIG_DEV "3" + }; + + + if ( (pig_nr>0) || (pig_nr < (int)(sizeof (pigdevs)/sizeof(char *))) ) { + + if (fd < 0) { + fd = open( pigdevs[pig_nr], O_RDWR ); + if (fd >= 0) { + status = HIDE; + px = py = pw = ph = 0; + } + return fd; + } + + } + + return -1; +} + + +// +// -- close PIG +// + +void CPIG::pigclose () +{ + if (fd >=0 ) { + close (fd); + fd = -1; + status = CLOSED; + px = py = pw = ph = 0; + } + return; +} + + +// +// -- set PIG Position +// -- routines should be self explaining +// + +void CPIG::_set_window (int x, int y, int w, int h) +{ +#if HAVE_DVB_API_VERSION >= 3 + // -- Modul interne Routine + struct v4l2_crop crop; + struct v4l2_format coord; + int err; + + crop.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + err = ioctl(fd, VIDIOC_G_CROP, &crop); + + // take whole input frame + crop.c.left = 0; + crop.c.top = 0; + crop.c.width = 720; + crop.c.height = 576; + err = ioctl(fd, VIDIOC_S_CROP, &crop); + + coord.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + err = ioctl(fd, VIDIOC_G_FMT, &coord); + + // fit into small window + coord.fmt.win.w.left = x; + coord.fmt.win.w.top = y; + coord.fmt.win.w.width = w; + coord.fmt.win.w.height = h; + + err = ioctl(fd, VIDIOC_S_FMT, &coord); +#if 0 // old + struct v4l2_format coord; + int err; + + ioctl(fd, VIDIOC_G_FMT, &coord); + coord.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + + coord.fmt.win.w.left = x; + coord.fmt.win.w.top = y; + coord.fmt.win.w.width = w; + coord.fmt.win.w.height = h; + + int pigmode = 0; + err = ioctl(fd, VIDIOC_OVERLAY, &pigmode); +printf("pig::window VIDIOC_OVERLAY %d\n", err); + + err = ioctl(fd, VIDIOC_S_FMT, &coord); +printf("pig::window VIDIOC_S_FMT %d\n", err); +#endif +#else + avia_pig_set_pos(fd,x,y); + avia_pig_set_size(fd, w, h); + avia_pig_set_stack(fd,2); +#endif +} + + +void CPIG::set_coord (int x, int y, int w, int h) +{ + + if (( x != px ) || ( y != py )) { + px = x; + py = y; + pw = w; + ph = h; + _set_window (px,py,pw,ph); + } + +} + + +void CPIG::set_xy (int x, int y) +{ + + if (( x != px ) || ( y != py )) { + px = x; + py = y; + _set_window (px,py,pw,ph); + } + +} + + +void CPIG::set_size (int w, int h) +{ + + if (( w != pw ) || ( h != ph )) { + pw = w; + ph = h; + _set_window (px,py,pw,ph); + } + +} + + +// $$$ ???? what this for? + +//void CPIG::set_source (int x, int y) +//{ +// +// if (fd >= 0) { +// +// if (( x != px ) || ( y != py )) { +// // avia_pig_set_source(fd,x,y); +// } +// +// } +// +//} + + +// +// -- routine set's stack position of PIG on display +// + +//void CPIG::set_stackpos (int pos) +// +//{ +// if (fd >= 0) { +// avia_pig_set_stack(fd,pos); +// stackpos = pos; +// } +//} + + +// +// -- Show PIG or hide PIG +// + +void CPIG::show (int x, int y, int w, int h) +{ + set_coord (x,y, w,h); + show (); +} + +void CPIG::show (void) +{ + if ( fd >= 0 ) { +#if HAVE_DVB_API_VERSION >= 3 + int pigmode = 1; + int err; + err = ioctl(fd, VIDIOC_OVERLAY, &pigmode); +//printf("pig::show err %d\n", err); +#else + avia_pig_show(fd); +#endif + status = SHOW; + } +} + +void CPIG::hide (void) +{ + if ( fd >= 0 ) { +#if HAVE_DVB_API_VERSION >= 3 + int pigmode = 0; + int err; + err = ioctl(fd, VIDIOC_OVERLAY, &pigmode); +#else + avia_pig_hide(fd); +#endif + status = HIDE; + } +} + + +CPIG::PigStatus CPIG::getStatus(void) +{ + return status; + +} + + + + + +// +// ToDo's: +// -- Capability unavail check/status +// -- Cropping for resizing (possible zoom/scaling?) +// -- Capturing +// + diff --git a/src/driver/pig.h b/src/driver/pig.h new file mode 100644 index 000000000..48f044420 --- /dev/null +++ b/src/driver/pig.h @@ -0,0 +1,83 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __PIG_CONTROL__ +#define __PIG_CONTROL__ +#include +using namespace std; + + +// +// -- Picture in Graphics Control +// -- 2002-11 rasc +// -- 2003-06 rasc V4L API +// + + + +#if HAVE_DVB_API_VERSION >= 3 +#include + +#define PIG_DEV "/dev/v4l/video" // PigNr will be appended! +#else +#include +#define PIG_DEV "/dev/dbox/pig" +#endif + + +class CPIG +{ + public: + CPIG (); + CPIG (int pig_nr); // incl. open + CPIG (int pig_nr, int x, int y, int w, int h); // open + set_coord + ~CPIG (); + + int pigopen (int pig_nr); + void pigclose (void); + void set_coord (int x, int y, int w, int h); + void set_xy (int x, int y); + void set_size (int w, int h); +// void set_source(int x, int y); +// void set_stackpos (int pos); + void show (void); + void show (int x, int y, int w, int h); + void hide (void); + + enum PigStatus { CLOSED, HIDE, SHOW }; + PigStatus getStatus(void); + + private: + void _set_window (int x, int y, int w, int h); + + int fd; // io descriptor + int px, py, pw, ph; // pig frame + int stackpos; // Order (Framebuffer, PIGs) + PigStatus status; // on display? + + +}; + + +#endif + + diff --git a/src/driver/rcinput.cpp b/src/driver/rcinput.cpp new file mode 100644 index 000000000..b05893e3e --- /dev/null +++ b/src/driver/rcinput.cpp @@ -0,0 +1,1487 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + 2003 thegoodguy + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +//#define RCDEBUG +#include +#include +#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL +#include +#endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ +#include +#include + +#include +#include +#include + +#include + +#include +#include + +//const char * const RC_EVENT_DEVICE[NUMBER_OF_EVENT_DEVICES] = {"/dev/input/nevis_ir", "/dev/input/event0"}; +const char * const RC_EVENT_DEVICE[NUMBER_OF_EVENT_DEVICES] = {"/dev/input/nevis_ir"}; +typedef struct input_event t_input_event; + +#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL +static struct termio orig_termio; +static bool saved_orig_termio = false; +#endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ + +/************************************************************************** +* Constructor - opens rc-input device and starts threads +* +**************************************************************************/ +CRCInput::CRCInput() +{ + timerid= 1; + + // pipe for internal event-queue + // ----------------------------- + if (pipe(fd_pipe_high_priority) < 0) + { + perror("fd_pipe_high_priority"); + exit(-1); + } + + fcntl(fd_pipe_high_priority[0], F_SETFL, O_NONBLOCK ); + fcntl(fd_pipe_high_priority[1], F_SETFL, O_NONBLOCK ); + + if (pipe(fd_pipe_low_priority) < 0) + { + perror("fd_pipe_low_priority"); + exit(-1); + } + + fcntl(fd_pipe_low_priority[0], F_SETFL, O_NONBLOCK ); + fcntl(fd_pipe_low_priority[1], F_SETFL, O_NONBLOCK ); + + + // open event-library + // ----------------------------- + fd_event = 0; + + //network-setup + struct sockaddr_un servaddr; + int clilen; + memset(&servaddr, 0, sizeof(struct sockaddr_un)); + servaddr.sun_family = AF_UNIX; + strcpy(servaddr.sun_path, NEUTRINO_UDS_NAME); + clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path); + unlink(NEUTRINO_UDS_NAME); + + //network-setup + if ((fd_event = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + perror("[neutrino] socket\n"); + } + + if ( bind(fd_event, (struct sockaddr*) &servaddr, clilen) <0 ) + { + perror("[neutrino] bind failed...\n"); + exit(-1); + } + + + if (listen(fd_event, 15) !=0) + { + perror("[neutrino] listen failed...\n"); + exit( -1 ); + } + + for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) + { + fd_rc[i] = -1; + } + clickfd = -1; + repeat_block = repeat_block_generic = 0; + open(); + rc_last_key = KEY_MAX; +} + +void CRCInput::open() +{ + close(); + + for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) + { + if ((fd_rc[i] = ::open(RC_EVENT_DEVICE[i], O_RDONLY)) == -1) + perror(RC_EVENT_DEVICE[i]); + else + { + fcntl(fd_rc[i], F_SETFL, O_NONBLOCK); + } +printf("CRCInput::open: %s fd %d\n", RC_EVENT_DEVICE[i], fd_rc[i]); + } + + //+++++++++++++++++++++++++++++++++++++++ +#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL + fd_keyb = STDIN_FILENO; +#else + fd_keyb = 0; +#endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ + /* + ::open("/dev/dbox/rc0", O_RDONLY); + if (fd_keyb<0) + { + perror("/dev/stdin"); + exit(-1); + } + */ +#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL + ::fcntl(fd_keyb, F_SETFL, O_NONBLOCK); + + struct termio new_termio; + + ::ioctl(STDIN_FILENO, TCGETA, &orig_termio); + + saved_orig_termio = true; + + new_termio = orig_termio; + new_termio.c_lflag &= ~ICANON; + // new_termio.c_lflag &= ~(ICANON|ECHO); + new_termio.c_cc[VMIN ] = 1; + new_termio.c_cc[VTIME] = 0; + + ::ioctl(STDIN_FILENO, TCSETA, &new_termio); + +#else + //fcntl(fd_keyb, F_SETFL, O_NONBLOCK ); + + //+++++++++++++++++++++++++++++++++++++++ +#endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ + + open_click(); + calculateMaxFd(); +} + +void CRCInput::close() +{ + for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) { + if (fd_rc[i] != -1) { + ::close(fd_rc[i]); + fd_rc[i] = -1; + } + } +#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL + if (saved_orig_termio) + { + ::ioctl(STDIN_FILENO, TCSETA, &orig_termio); + printf("Original terminal settings restored.\n"); + } +#else +/* + if(fd_keyb) + { + ::close(fd_keyb); + } +*/ +#endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ + calculateMaxFd(); +} + +void CRCInput::calculateMaxFd() +{ + fd_max = fd_event; + + for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) + if (fd_rc[i] > fd_max) + fd_max = fd_rc[i]; + + if(fd_pipe_high_priority[0] > fd_max) + fd_max = fd_pipe_high_priority[0]; + if(fd_pipe_low_priority[0] > fd_max) + fd_max = fd_pipe_low_priority[0]; +} + +/************************************************************************** +* Destructor - close the input-device +* +**************************************************************************/ +CRCInput::~CRCInput() +{ + close(); + + if(fd_pipe_high_priority[0]) + ::close(fd_pipe_high_priority[0]); + if(fd_pipe_high_priority[1]) + ::close(fd_pipe_high_priority[1]); + + if(fd_pipe_low_priority[0]) + ::close(fd_pipe_low_priority[0]); + if(fd_pipe_low_priority[1]) + ::close(fd_pipe_low_priority[1]); + + if(fd_event) + ::close(fd_event); + close_click(); +} + +/************************************************************************** +* stopInput - stop reading rcin for plugins +* +**************************************************************************/ +void CRCInput::stopInput() +{ + close(); +} + +/************************************************************************** +* restartInput - restart reading rcin after calling plugins +* +**************************************************************************/ +void CRCInput::restartInput() +{ + close(); + open(); +} + +int CRCInput::messageLoop( bool anyKeyCancels, int timeout ) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = menu_return::RETURN_REPAINT; + + bool doLoop = true; + + if ( timeout == -1 ) + timeout = g_settings.timing[SNeutrinoSettings::TIMING_MENU]; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd( timeout == 0 ? 0xFFFF : timeout); + + while (doLoop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if ( ( msg == CRCInput::RC_timeout ) || + ( msg == CRCInput::RC_home ) || + ( msg == CRCInput::RC_ok ) ) + doLoop = false; + else if((msg == CRCInput::RC_sat) || (msg == CRCInput::RC_favorites)) { + } + else + { + int mr = CNeutrinoApp::getInstance()->handleMsg( msg, data ); + + if ( mr & messages_return::cancel_all ) + { + res = menu_return::RETURN_EXIT_ALL; + doLoop = false; + } + else if ( mr & messages_return::unhandled ) + { + if ((msg <= CRCInput::RC_MaxRC) && + (data == 0)) /* <- button pressed */ + { + if ( anyKeyCancels ) + doLoop = false; + else + timeoutEnd = CRCInput::calcTimeoutEnd( timeout ); + } + } + } + + + } + return res; +} + + +int CRCInput::addTimer(unsigned long long Interval, bool oneshot, bool correct_time ) +{ + struct timeval tv; + + gettimeofday( &tv, NULL ); + unsigned long long timeNow = (unsigned long long) tv.tv_usec + (unsigned long long)((unsigned long long) tv.tv_sec * (unsigned long long) 1000000); + + timer _newtimer; + if (!oneshot) + _newtimer.interval = Interval; + else + _newtimer.interval = 0; + + _newtimer.id = timerid++; + if ( correct_time ) + _newtimer.times_out = timeNow+ Interval; + else + _newtimer.times_out = Interval; + + _newtimer.correct_time = correct_time; + +//printf("adding timer %d (0x%llx, 0x%llx)\n", _newtimer.id, _newtimer.times_out, Interval); + + std::vector::iterator e; + for ( e= timers.begin(); e!= timers.end(); ++e ) + if ( e->times_out> _newtimer.times_out ) + break; + + timers.insert(e, _newtimer); + return _newtimer.id; +} + +int CRCInput::addTimer(struct timeval Timeout) +{ + unsigned long long timesout = (unsigned long long) Timeout.tv_usec + (unsigned long long)((unsigned long long) Timeout.tv_sec * (unsigned long long) 1000000); + return addTimer( timesout, true, false ); +} + +int CRCInput::addTimer(const time_t *Timeout) +{ + return addTimer( (unsigned long long)*Timeout* (unsigned long long) 1000000, true, false ); +} + +void CRCInput::killTimer(uint32_t id) +{ +//printf("killing timer %d\n", id); + std::vector::iterator e; + for ( e= timers.begin(); e!= timers.end(); ++e ) + if ( e->id == id ) + { + timers.erase(e); + break; + } +} + +int CRCInput::checkTimers() +{ + struct timeval tv; + int _id = 0; + + gettimeofday( &tv, NULL ); + unsigned long long timeNow = (unsigned long long) tv.tv_usec + (unsigned long long)((unsigned long long) tv.tv_sec * (unsigned long long) 1000000); + + + std::vector::iterator e; + for ( e= timers.begin(); e!= timers.end(); ++e ) + if ( e->times_out< timeNow+ 2000 ) + { +//printf("timeout timer %d %llx %llx\n",e->id,e->times_out,timeNow ); + _id = e->id; + if ( e->interval != 0 ) + { + timer _newtimer; + _newtimer.id = e->id; + _newtimer.interval = e->interval; + _newtimer.correct_time = e->correct_time; + if ( _newtimer.correct_time ) + _newtimer.times_out = timeNow + e->interval; + else + _newtimer.times_out = e->times_out + e->interval; + + timers.erase(e); + for ( e= timers.begin(); e!= timers.end(); ++e ) + if ( e->times_out> _newtimer.times_out ) + break; + + timers.insert(e, _newtimer); + } + else + timers.erase(e); + + break; + } +// else +// printf("skipped timer %d %llx %llx\n",e->id,e->times_out, timeNow ); +//printf("checkTimers: return %d\n", _id); + return _id; +} + + + +long long CRCInput::calcTimeoutEnd(const int timeout_in_seconds) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + return (unsigned long long) tv.tv_usec + (unsigned long long)((unsigned long long) tv.tv_sec + (unsigned long long)timeout_in_seconds) * (unsigned long long) 1000000; +} + +long long CRCInput::calcTimeoutEnd_MS(const int timeout_in_milliseconds) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + unsigned long long timeNow = (unsigned long long) tv.tv_usec + (unsigned long long)((unsigned long long) tv.tv_sec * (unsigned long long) 1000000); + + return ( timeNow + timeout_in_milliseconds * 1000 ); +} + + +void CRCInput::getMsgAbsoluteTimeout(neutrino_msg_t * msg, neutrino_msg_data_t * data, unsigned long long *TimeoutEnd, bool bAllowRepeatLR) +{ + struct timeval tv; + + gettimeofday( &tv, NULL ); + unsigned long long timeNow = (unsigned long long) tv.tv_usec + (unsigned long long)((unsigned long long) tv.tv_sec * (unsigned long long) 1000000); + + unsigned long long diff; + + if ( *TimeoutEnd < timeNow+ 100 ) + diff = 100; // Minimum Differenz... + else + diff = ( *TimeoutEnd - timeNow ); +//printf("CRCInput::getMsgAbsoluteTimeout diff %llx TimeoutEnd %llx now %llx\n", diff, *TimeoutEnd, timeNow); + getMsg_us( msg, data, diff, bAllowRepeatLR ); + + if ( *msg == NeutrinoMessages::EVT_TIMESET ) + { + // recalculate timeout.... + //unsigned long long ta= *TimeoutEnd; + *TimeoutEnd= *TimeoutEnd + *(long long*) *data; + + //printf("[getMsgAbsoluteTimeout]: EVT_TIMESET - recalculate timeout\n%llx/%llx - %llx/%llx\n", timeNow, *(long long*) *data, *TimeoutEnd, ta ); + } +} + +void CRCInput::getMsg(neutrino_msg_t * msg, neutrino_msg_data_t * data, int Timeout, bool bAllowRepeatLR) +{ + getMsg_us(msg, data, (unsigned long long) Timeout * 100 * 1000, bAllowRepeatLR); +} + +void CRCInput::getMsg_ms(neutrino_msg_t * msg, neutrino_msg_data_t * data, int Timeout, bool bAllowRepeatLR) +{ + getMsg_us(msg, data, (unsigned long long) Timeout * 1000, bAllowRepeatLR); +} + +#define ENABLE_REPEAT_CHECK +void CRCInput::getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, unsigned long long Timeout, bool bAllowRepeatLR) +{ + static unsigned long long last_keypress = 0ULL; + unsigned long long getKeyBegin; + + //static __u16 rc_last_key = KEY_MAX; + static __u16 rc_last_repeat_key = KEY_MAX; + + struct timeval tv, tvselect; + unsigned long long InitialTimeout = Timeout; + long long targetTimeout; + + int timer_id; + fd_set rfds; + t_input_event ev; + + *data = 0; + + // wiederholung reinmachen - dass wirklich die ganze zeit bis timeout gewartet wird! + gettimeofday( &tv, NULL ); + getKeyBegin = (unsigned long long) tv.tv_usec + (unsigned long long)((unsigned long long) tv.tv_sec * (unsigned long long) 1000000); + + while(1) { + timer_id = 0; + if ( timers.size()> 0 ) + { + gettimeofday( &tv, NULL ); + unsigned long long t_n= (unsigned long long) tv.tv_usec + (unsigned long long)((unsigned long long) tv.tv_sec * (unsigned long long) 1000000); + if ( timers[0].times_out< t_n ) + { + timer_id = checkTimers(); + *msg = NeutrinoMessages::EVT_TIMER; + *data = timer_id; + return; + } + else + { + targetTimeout = timers[0].times_out - t_n; + if ( (unsigned long long) targetTimeout> Timeout) + targetTimeout= Timeout; + else + timer_id = timers[0].id; + } + } + else + targetTimeout= Timeout; + + tvselect.tv_sec = targetTimeout/1000000; + tvselect.tv_usec = targetTimeout%1000000; + + FD_ZERO(&rfds); + for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) + { + if (fd_rc[i] != -1) + FD_SET(fd_rc[i], &rfds); + } +#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL + if (true) +#else + if (fd_keyb> 0) +#endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ + FD_SET(fd_keyb, &rfds); + + FD_SET(fd_event, &rfds); + FD_SET(fd_pipe_high_priority[0], &rfds); + FD_SET(fd_pipe_low_priority[0], &rfds); + + int status = select(fd_max+1, &rfds, NULL, NULL, &tvselect); + + if ( status == -1 ) + { + perror("[neutrino - getMsg_us]: select returned "); + // in case of an error return timeout...?! + *msg = RC_timeout; + *data = 0; + return; + } + else if ( status == 0 ) // Timeout! + { + if ( timer_id != 0 ) + { + timer_id = checkTimers(); + if ( timer_id != 0 ) + { + *msg = NeutrinoMessages::EVT_TIMER; + *data = timer_id; + return; + } + else + continue; + } + else + { + *msg = RC_timeout; + *data = 0; + return; + } + } + + if(FD_ISSET(fd_pipe_high_priority[0], &rfds)) + { + struct event buf; + + read(fd_pipe_high_priority[0], &buf, sizeof(buf)); + + *msg = buf.msg; + *data = buf.data; + + // printf("got event from high-pri pipe %x %x\n", *msg, *data ); + + return; + } + + +#ifdef KEYBOARD_INSTEAD_OF_REMOTE_CONTROL + if (FD_ISSET(fd_keyb, &rfds)) + { + int trkey; + char key = 0; + read(fd_keyb, &key, sizeof(key)); + + switch(key) + { + case 27: // <- Esc + trkey = KEY_HOME; + break; + case 10: // <- Return + case 'o': + trkey = KEY_OK; + break; + case 'p': + trkey = KEY_POWER; + break; + case 's': + trkey = KEY_SETUP; + break; + case 'h': + trkey = KEY_HELP; + break; + case 'i': + trkey = KEY_UP; + break; + case 'm': + trkey = KEY_DOWN; + break; + case 'j': + trkey = KEY_LEFT; + break; + case 'k': + trkey = KEY_RIGHT; + break; + case 'r': + trkey = KEY_RED; + break; + case 'g': + trkey = KEY_GREEN; + break; + case 'y': + trkey = KEY_YELLOW; + break; + case 'b': + trkey = KEY_BLUE; + break; + case '0': + trkey = RC_0; + break; + case '1': + trkey = RC_1; + break; + case '2': + trkey = RC_2; + break; + case '3': + trkey = RC_3; + break; + case '4': + trkey = RC_4; + break; + case '5': + trkey = RC_5; + break; + case '6': + trkey = RC_6; + break; + case '7': + trkey = RC_7; + break; + case '8': + trkey = RC_8; + break; + case '9': + trkey = RC_9; + break; + case '+': + trkey = RC_plus; + break; + case '-': + trkey = RC_minus; + break; + case 'a': + trkey = KEY_A; + break; + case 'u': + trkey = KEY_U; + break; + case '/': + trkey = KEY_SLASH; + break; + case '\\': + trkey = KEY_BACKSLASH; + break; + default: + trkey = RC_nokey; + } + if (trkey != RC_nokey) + { + *msg = trkey; + *data = 0; /* <- button pressed */ + return; + } + } +#else + /* + if(FD_ISSET(fd_keyb, &rfds)) + { + char key = 0; + read(fd_keyb, &key, sizeof(key)); + printf("keyboard: %d\n", rc_key); + } + */ +#endif /* KEYBOARD_INSTEAD_OF_REMOTE_CONTROL */ + + if(FD_ISSET(fd_event, &rfds)) { + //printf("[neutrino] event - accept!\n"); + socklen_t clilen; + struct sockaddr_in cliaddr; + clilen = sizeof(cliaddr); + int fd_eventclient = accept(fd_event, (struct sockaddr *) &cliaddr, &clilen); + + *msg = RC_nokey; + //printf("[neutrino] network event - read!\n"); + CEventServer::eventHead emsg; + int read_bytes= recv(fd_eventclient, &emsg, sizeof(emsg), MSG_WAITALL); + //printf("[neutrino] event read %d bytes - following %d bytes\n", read_bytes, emsg.dataSize ); + if ( read_bytes == sizeof(emsg) ) { + bool dont_delete_p = false; + + unsigned char* p; + p= new unsigned char[ emsg.dataSize + 1 ]; + if ( p!=NULL ) + { + read_bytes= recv(fd_eventclient, p, emsg.dataSize, MSG_WAITALL); + //printf("[neutrino] eventbody read %d bytes - initiator %x\n", read_bytes, emsg.initiatorID ); + + if ( emsg.initiatorID == CEventServer::INITID_CONTROLD ) + { + switch(emsg.eventID) + { + case CControldClient::EVT_VOLUMECHANGED : + *msg = NeutrinoMessages::EVT_VOLCHANGED; + *data = 0; + break; + case CControldClient::EVT_MUTECHANGED : + *msg = NeutrinoMessages::EVT_MUTECHANGED; + *data = (unsigned) p; + dont_delete_p = true; + break; + case CControldClient::EVT_VCRCHANGED : + *msg = NeutrinoMessages::EVT_VCRCHANGED; + *data = *(int*) p; + break; + case CControldClient::EVT_MODECHANGED : + *msg = NeutrinoMessages::EVT_MODECHANGED; + *data = *(int*) p; + break; + default: + printf("[neutrino] event INITID_CONTROLD - unknown eventID 0x%x\n", emsg.eventID ); + } + } + else if ( emsg.initiatorID == CEventServer::INITID_HTTPD ) + { + switch(emsg.eventID) + { + case NeutrinoMessages::SHUTDOWN : + *msg = NeutrinoMessages::SHUTDOWN; + *data = 0; + break; + case NeutrinoMessages::EVT_POPUP : + *msg = NeutrinoMessages::EVT_POPUP; + *data = (unsigned) p; + dont_delete_p = true; + break; + case NeutrinoMessages::EVT_EXTMSG : + *msg = NeutrinoMessages::EVT_EXTMSG; + *data = (unsigned) p; + dont_delete_p = true; + break; + case NeutrinoMessages::CHANGEMODE : // Change + *msg = NeutrinoMessages::CHANGEMODE; + *data = *(unsigned*) p; + break; + case NeutrinoMessages::STANDBY_TOGGLE : + *msg = NeutrinoMessages::STANDBY_TOGGLE; + *data = 0; + break; + case NeutrinoMessages::STANDBY_ON : + *msg = NeutrinoMessages::STANDBY_ON; + *data = 0; + break; + case NeutrinoMessages::STANDBY_OFF : + *msg = NeutrinoMessages::STANDBY_OFF; + *data = 0; + break; + case NeutrinoMessages::EVT_START_PLUGIN : + *msg = NeutrinoMessages::EVT_START_PLUGIN; + *data = (unsigned) p; + dont_delete_p = true; + break; + case NeutrinoMessages::LOCK_RC : + *msg = NeutrinoMessages::LOCK_RC; + *data = 0; + break; + case NeutrinoMessages::UNLOCK_RC : + *msg = NeutrinoMessages::UNLOCK_RC; + *data = 0; + break; + default: + printf("[neutrino] event INITID_HTTPD - unknown eventID 0x%x\n", emsg.eventID ); + } + } + else if ( emsg.initiatorID == CEventServer::INITID_SECTIONSD ) + { + //printf("[neutrino] event - from SECTIONSD %x %x\n", emsg.eventID, *(unsigned*) p); + switch(emsg.eventID) + { + case CSectionsdClient::EVT_TIMESET: + { + struct timeval tv; + gettimeofday( &tv, NULL ); + long long timeOld = (long long) tv.tv_usec + (long long)((long long) tv.tv_sec * (long long) 1000000); + + //printf("[neutrino] event TIMESET from SECTIONSD %x %x\n", emsg.eventID, *(unsigned*) p); + //g_Sectionsd->registerEvent(CSectionsdClient::EVT_TIMESET, 222, NEUTRINO_UDS_NAME); + stime((time_t*) p); + + gettimeofday( &tv, NULL ); + long long timeNew = (long long) tv.tv_usec + (long long)((long long) tv.tv_sec * (long long) 1000000); + + delete[] p;//new [] delete [] + p= new unsigned char[ sizeof(long long) ]; + *(long long*) p = timeNew - timeOld; + + if ((long long)last_keypress > *(long long*)p) + last_keypress += *(long long *)p; + + // Timer anpassen + for(std::vector::iterator e = timers.begin(); e != timers.end(); ++e) + if (e->correct_time) + e->times_out+= *(long long*) p; + + *msg = NeutrinoMessages::EVT_TIMESET; + *data = (neutrino_msg_data_t) p; + dont_delete_p = true; + } + break; + case CSectionsdClient::EVT_GOT_CN_EPG: +printf("[neutrino] CSectionsdClient::EVT_GOT_CN_EPG\n"); + *msg = NeutrinoMessages::EVT_CURRENTNEXT_EPG; + *data = (neutrino_msg_data_t) p; + dont_delete_p = true; + break; + case CSectionsdClient::EVT_SERVICES_UPDATE: + *msg = NeutrinoMessages::EVT_SERVICES_UPD; + *data = 0; + break; + case CSectionsdClient::EVT_BOUQUETS_UPDATE: + break; + case CSectionsdClient::EVT_WRITE_SI_FINISHED: + *msg = NeutrinoMessages::EVT_SI_FINISHED; + *data = 0; + break; + default: + printf("[neutrino] event INITID_SECTIONSD - unknown eventID 0x%x\n", emsg.eventID ); + } + } + else if ( emsg.initiatorID == CEventServer::INITID_ZAPIT ) + { + //printf("[neutrino] event - from ZAPIT %x %x\n", emsg.eventID, *(unsigned*) p); + switch(emsg.eventID) + { + case CZapitClient::EVT_RECORDMODE_ACTIVATED: + *msg = NeutrinoMessages::EVT_RECORDMODE; + *data = true; + break; + case CZapitClient::EVT_RECORDMODE_DEACTIVATED: + *msg = NeutrinoMessages::EVT_RECORDMODE; + *data = false; + break; + case CZapitClient::EVT_ZAP_COMPLETE: + *msg = NeutrinoMessages::EVT_ZAP_COMPLETE; + break; + case CZapitClient::EVT_ZAP_FAILED: + *msg = NeutrinoMessages::EVT_ZAP_FAILED; + break; + case CZapitClient::EVT_ZAP_SUB_FAILED: + *msg = NeutrinoMessages::EVT_ZAP_SUB_FAILED; + break; + case CZapitClient::EVT_ZAP_COMPLETE_IS_NVOD: + *msg = NeutrinoMessages::EVT_ZAP_ISNVOD; + break; + case CZapitClient::EVT_ZAP_SUB_COMPLETE: + *msg = NeutrinoMessages::EVT_ZAP_SUB_COMPLETE; + break; + case CZapitClient::EVT_SCAN_COMPLETE: + *msg = NeutrinoMessages::EVT_SCAN_COMPLETE; + *data = 0; + break; + case CZapitClient::EVT_SCAN_NUM_TRANSPONDERS: + *msg = NeutrinoMessages::EVT_SCAN_NUM_TRANSPONDERS; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_SCAN_REPORT_NUM_SCANNED_TRANSPONDERS: + *msg = NeutrinoMessages::EVT_SCAN_REPORT_NUM_SCANNED_TRANSPONDERS; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_SCAN_REPORT_FREQUENCY: + *msg = NeutrinoMessages::EVT_SCAN_REPORT_FREQUENCY; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_SCAN_FOUND_A_CHAN: + *msg = NeutrinoMessages::EVT_SCAN_FOUND_A_CHAN; + break; + case CZapitClient::EVT_SCAN_SERVICENAME: + *msg = NeutrinoMessages::EVT_SCAN_SERVICENAME; + break; + case CZapitClient::EVT_SCAN_FOUND_TV_CHAN: + *msg = NeutrinoMessages::EVT_SCAN_FOUND_TV_CHAN; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_SCAN_FOUND_RADIO_CHAN: + *msg = NeutrinoMessages::EVT_SCAN_FOUND_RADIO_CHAN; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_SCAN_FOUND_DATA_CHAN: + *msg = NeutrinoMessages::EVT_SCAN_FOUND_DATA_CHAN; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_SCAN_REPORT_FREQUENCYP: + *msg = NeutrinoMessages::EVT_SCAN_REPORT_FREQUENCYP; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_SCAN_NUM_CHANNELS: + *msg = NeutrinoMessages::EVT_SCAN_NUM_CHANNELS; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_SCAN_PROVIDER: + *msg = NeutrinoMessages::EVT_SCAN_PROVIDER; + break; + case CZapitClient::EVT_SCAN_SATELLITE: + *msg = NeutrinoMessages::EVT_SCAN_SATELLITE; + break; + case CZapitClient::EVT_BOUQUETS_CHANGED: + *msg = NeutrinoMessages::EVT_BOUQUETSCHANGED; + *data = 0; + break; + case CZapitClient::EVT_SERVICES_CHANGED: + *msg = NeutrinoMessages::EVT_SERVICESCHANGED; + *data = 0; + break; + case CZapitClient::EVT_ZAP_CA_CLEAR: + *msg = NeutrinoMessages::EVT_ZAP_CA_CLEAR; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_ZAP_CA_LOCK: + *msg = NeutrinoMessages::EVT_ZAP_CA_LOCK; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_ZAP_CA_FTA: + *msg = NeutrinoMessages::EVT_ZAP_CA_FTA; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_ZAP_CA_ID : + *msg = NeutrinoMessages::EVT_ZAP_CA_ID; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_SCAN_FAILED: + *msg = NeutrinoMessages::EVT_SCAN_FAILED; + *data = 0; + break; + case CZapitClient::EVT_ZAP_MOTOR: + *msg = NeutrinoMessages::EVT_ZAP_MOTOR; + *data = *(unsigned*) p; + break; + case CZapitClient::EVT_SDT_CHANGED: + *msg = NeutrinoMessages::EVT_SERVICES_UPD; + *data = 0; + break; + default: + printf("[neutrino] event INITID_ZAPIT - unknown eventID 0x%x\n", emsg.eventID ); + } + if (((*msg) >= CRCInput::RC_WithData) && ((*msg) < CRCInput::RC_WithData + 0x10000000)) + { + *data = (neutrino_msg_data_t) p; + dont_delete_p = true; + } + } + else if ( emsg.initiatorID == CEventServer::INITID_TIMERD ) + { + /* + if (emsg.eventID==CTimerdClient::EVT_ANNOUNCE_NEXTPROGRAM) + { + } + + if (emsg.eventID==CTimerdClient::EVT_NEXTPROGRAM) + { + *msg = NeutrinoMessages::EVT_NEXTPROGRAM; + *data = (neutrino_msg_data_t) p; + dont_delete_p = true; + } + */ + switch(emsg.eventID) + { + case CTimerdClient::EVT_ANNOUNCE_RECORD : + *msg = NeutrinoMessages::ANNOUNCE_RECORD; + *data = (unsigned) p; + dont_delete_p = true; + break; + case CTimerdClient::EVT_ANNOUNCE_ZAPTO : + *msg = NeutrinoMessages::ANNOUNCE_ZAPTO; + *data = 0; + break; + case CTimerdClient::EVT_ANNOUNCE_SHUTDOWN : + *msg = NeutrinoMessages::ANNOUNCE_SHUTDOWN; + *data = 0; + break; + case CTimerdClient::EVT_ANNOUNCE_SLEEPTIMER : + *msg = NeutrinoMessages::ANNOUNCE_SLEEPTIMER; + *data = 0; + break; + case CTimerdClient::EVT_SLEEPTIMER : + *msg = NeutrinoMessages::SLEEPTIMER; + *data = 0; + break; + case CTimerdClient::EVT_RECORD_START : + *msg = NeutrinoMessages::RECORD_START; + *data = (unsigned) p; + dont_delete_p = true; + break; + case CTimerdClient::EVT_RECORD_STOP : + *msg = NeutrinoMessages::RECORD_STOP; + *data = (unsigned) p; + dont_delete_p = true; + break; + case CTimerdClient::EVT_ZAPTO : + *msg = NeutrinoMessages::ZAPTO; + *data = (unsigned) p; + dont_delete_p = true; + break; + case CTimerdClient::EVT_SHUTDOWN : + *msg = NeutrinoMessages::SHUTDOWN; + *data = 0; + break; + case CTimerdClient::EVT_STANDBY_ON : + *msg = NeutrinoMessages::STANDBY_ON; + *data = 0; + break; + case CTimerdClient::EVT_STANDBY_OFF : + *msg = NeutrinoMessages::STANDBY_OFF; + *data = 0; + break; + case CTimerdClient::EVT_REMIND : + *msg = NeutrinoMessages::REMIND; + *data = (unsigned) p; + dont_delete_p = true; + break; + case CTimerdClient::EVT_EXEC_PLUGIN : + *msg = NeutrinoMessages::EVT_START_PLUGIN; + *data = (unsigned) p; + dont_delete_p = true; + break; + + default : + printf("[neutrino] event INITID_TIMERD - unknown eventID 0x%x\n", emsg.eventID ); + + } + } + else if (emsg.initiatorID == CEventServer::INITID_NEUTRINO) + { + if ((emsg.eventID == NeutrinoMessages::EVT_RECORDING_ENDED) && + (read_bytes == sizeof(stream2file_status2_t))) + { + *msg = NeutrinoMessages::EVT_RECORDING_ENDED; + *data = (neutrino_msg_data_t) p; + dont_delete_p = true; + } + } + else if (emsg.initiatorID == CEventServer::INITID_GENERIC_INPUT_EVENT_PROVIDER) + { + if (read_bytes == sizeof(int)) + { + *msg = *(int *)p; + *data = emsg.eventID; + } + } + else + printf("[neutrino] event - unknown initiatorID 0x%x\n", emsg.initiatorID); + if ( !dont_delete_p ) + { + delete[] p;//new [] delete [] + p= NULL; + } + } + } + else + { + printf("[neutrino] event - read failed!\n"); + } + + ::close(fd_eventclient); + + if ( *msg != RC_nokey ) + { + // raus hier :) + //printf("[neutrino] event 0x%x\n", *msg); + return; + } + } + + for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) { + if ((fd_rc[i] != -1) && (FD_ISSET(fd_rc[i], &rfds))) { + int ret; + ret = read(fd_rc[i], &ev, sizeof(t_input_event)); + + if(ret != sizeof(t_input_event)) + continue; + printf("key: %04x value %d, translate: %04x -%s-\n", ev.code, ev.value, translate(ev.code, i), getKeyName(translate(ev.code, i)).c_str()); + uint32_t trkey = translate(ev.code, i); + + if (trkey == RC_nokey) + continue; + if (ev.value) { +#ifdef RCDEBUG + printf("got keydown native key: %04x %04x, translate: %04x -%s-\n", ev.code, ev.code&0x1f, translate(ev.code, 0), getKeyName(translate(ev.code, 0)).c_str()); + printf("rc_last_key %04x rc_last_repeat_key %04x\n\n", rc_last_key, rc_last_repeat_key); +#endif + unsigned long long now_pressed; + bool keyok = true; + + tv = ev.time; + now_pressed = (unsigned long long) tv.tv_usec + (unsigned long long)((unsigned long long) tv.tv_sec * (unsigned long long) 1000000); + if (ev.code == rc_last_key) { + /* only allow selected keys to be repeated */ + /* (why?) */ + if((trkey == RC_up) || (trkey == RC_down ) || + (trkey == RC_plus ) || (trkey == RC_minus ) || + (trkey == RC_page_down ) || (trkey == RC_page_up ) || + //(trkey == RC_standby) || + ((bAllowRepeatLR) && ((trkey == RC_left ) || + (trkey == RC_right)))) + { +#ifdef ENABLE_REPEAT_CHECK + if (rc_last_repeat_key != ev.code) { + if ((now_pressed > last_keypress + repeat_block) || + /* accept all keys after time discontinuity: */ + (now_pressed < last_keypress)) + rc_last_repeat_key = ev.code; + else + keyok = false; + } +#endif + } + else + keyok = false; + } + else + rc_last_repeat_key = KEY_MAX; + + rc_last_key = ev.code; + + if (keyok) { +#ifdef ENABLE_REPEAT_CHECK + if ((now_pressed > last_keypress + repeat_block_generic) || + /* accept all keys after time discontinuity: */ + (now_pressed < last_keypress)) +#endif + { + last_keypress = now_pressed; + + *msg = trkey; + *data = 0; /* <- button pressed */ + if(g_settings.key_click) + play_click(); + return; + } + } /*if keyok */ + } /* if (ev.value) */ + else { + // clear rc_last_key on keyup event +#ifdef RCDEBUG + printf("got keyup native key: %04x %04x, translate: %04x -%s-\n", ev.code, ev.code&0x1f, translate(ev.code, 0), getKeyName(translate(ev.code, 0)).c_str() ); +#endif + rc_last_key = KEY_MAX; + if (trkey == RC_standby) { + *msg = RC_standby; + *data = 1; /* <- button released */ + return; + } + } + }/* if FDSET */ + } /* for NUMBER_OF_EVENT_DEVICES */ + + if(FD_ISSET(fd_pipe_low_priority[0], &rfds)) + { + struct event buf; + + read(fd_pipe_low_priority[0], &buf, sizeof(buf)); + + *msg = buf.msg; + *data = buf.data; + + // printf("got event from low-pri pipe %x %x\n", *msg, *data ); + + return; + } + + if ( InitialTimeout == 0 ) + { + //nicht warten wenn kein key da ist + *msg = RC_timeout; + *data = 0; + return; + } + else + { + //timeout neu kalkulieren + gettimeofday( &tv, NULL ); + long long getKeyNow = (long long) tv.tv_usec + (long long)((long long) tv.tv_sec * (long long) 1000000); + long long diff = (getKeyNow - getKeyBegin); + if( Timeout <= (unsigned long long) diff ) + { + *msg = RC_timeout; + *data = 0; + return; + } + else + Timeout -= diff; + } + } +} + +void CRCInput::postMsg(const neutrino_msg_t msg, const neutrino_msg_data_t data, const bool Priority) +{ +// printf("postMsg %x %x %d\n", msg, data, Priority ); + + struct event buf; + buf.msg = msg; + buf.data = data; + + if (Priority) + write(fd_pipe_high_priority[1], &buf, sizeof(buf)); + else + write(fd_pipe_low_priority[1], &buf, sizeof(buf)); +} + + +void CRCInput::clearRCMsg() +{ + t_input_event ev; + + for (int i = 0; i < NUMBER_OF_EVENT_DEVICES; i++) + { + if (fd_rc[i] != -1) + { + while (read(fd_rc[i], &ev, sizeof(t_input_event)) == sizeof(t_input_event)) + ; + } + } + rc_last_key = KEY_MAX; +} + +/************************************************************************** +* isNumeric - test if key is 0..9 +* +**************************************************************************/ +bool CRCInput::isNumeric(const neutrino_msg_t key) +{ + return ((key == RC_0) || ((key >= RC_1) && (key <= RC_9))); +} + +/************************************************************************** +* getNumericValue - return numeric value of the key or -1 +* +**************************************************************************/ +int CRCInput::getNumericValue(const neutrino_msg_t key) +{ + return ((key == RC_0) ? (int)0 : (((key >= RC_1) && (key <= RC_9)) ? (int)(key - RC_1 + 1) : (int)-1)); +} + +/************************************************************************** +* convertDigitToKey - return key representing digit or RC_nokey +* +**************************************************************************/ +static const unsigned int digit_to_key[10] = {CRCInput::RC_0, CRCInput::RC_1, CRCInput::RC_2, CRCInput::RC_3, CRCInput::RC_4, CRCInput::RC_5, CRCInput::RC_6, CRCInput::RC_7, CRCInput::RC_8, CRCInput::RC_9}; + +unsigned int CRCInput::convertDigitToKey(const unsigned int digit) +{ + return (digit < 10) ? digit_to_key[digit] : RC_nokey; +} + +/************************************************************************** +* getUnicodeValue - return unicode value of the key or -1 +* +**************************************************************************/ +#define UNICODE_VALUE_SIZE 58 +static const int unicode_value[UNICODE_VALUE_SIZE] = {-1 , -1 , '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', -1 , -1 , + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', -1 , -1 , 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', -1 /* FIXME */, -1 /* FIXME */, -1 , '\\', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', ',', '.', '/', -1, -1, -1, ' '}; + +int CRCInput::getUnicodeValue(const neutrino_msg_t key) +{ + if (key < UNICODE_VALUE_SIZE) + return unicode_value[key]; + else + return -1; +} + +/************************************************************************** +* transforms the rc-key to const char * +* +**************************************************************************/ +const char * CRCInput::getSpecialKeyName(const unsigned int key) +{ + switch(key) + { + case RC_standby: + return "standby"; + case RC_home: +#if HAVE_DVB_API_VERSION == 1 + return "lame"; +#else + return "home"; +#endif + case RC_setup: +#if HAVE_DVB_API_VERSION == 1 + return "dream"; +#else + return "setup"; +#endif + case RC_red: + return "red button"; + case RC_green: + return "green button"; + case RC_yellow: + return "yellow button"; + case RC_blue: + return "blue button"; + case RC_page_up: + return "page up"; + case RC_page_down: + return "page down"; + case RC_up: + return "cursor up"; + case RC_down: + return "cursor down"; + case RC_left: + return "cursor left"; + case RC_right: + return "cursor right"; + case RC_ok: + return "ok"; + case RC_plus: + return "vol. inc"; + case RC_minus: + return "vol. dec"; + case RC_spkr: + return "mute"; + case RC_help: + return "help"; + case RC_info: + return "info"; + case RC_topleft: + return "topleft"; + case RC_topright: + return "topright"; + case RC_audio: + return "audio"; + case RC_video: + return "video"; + case RC_tv: + return "tv"; + case RC_radio: + return "radio"; + case RC_text: + return "text"; +#if 0 + case RC_shift_red: + return "shift-red"; + case RC_shift_green: + return "shift-green"; + case RC_shift_yellow: + return "shift-yellow"; + case RC_shift_blue: + return "shift-blue"; + case RC_shift_tv: + return "shift-tv"; + case RC_shift_radio: + return "shift-radio"; +#endif + case RC_epg: + return "epg"; + case RC_recall: + return "recall"; + case RC_favorites: + return "favorites"; + case RC_sat: + return "sat"; + case RC_sat2: + return "sat2"; + case RC_timeout: + return "timeout"; + case RC_play: + return "play"; + case RC_stop: + return "stop"; + case RC_forward: + return "forward"; + case RC_rewind: + return "rewind"; + case RC_timeshift: + return "timeshift"; + case RC_mode: + return "mode"; + case RC_record: + return "record"; + case RC_pause: + return "pause"; + case RC_games: + return "games"; + case RC_next: + return "next"; + case RC_prev: + return "prev"; + case RC_nokey: + return "none"; + default: + printf("unknown key: %d (0x%x) \n", key, key); + return "unknown"; + } +} + +std::string CRCInput::getKeyName(const unsigned int key) +{ + int unicode_value = getUnicodeValue(key); + if (unicode_value == -1) + return getSpecialKeyName(key); + else + { + char tmp[2]; + tmp[0] = unicode_value; + tmp[1] = 0; + return std::string(tmp); + } +} + +/************************************************************************** +* transforms the rc-key to generic - internal use only! +* +**************************************************************************/ +int CRCInput::translate(int code, int num) +{ + if(code == 0x100) code = RC_up; + else if(code == 0x101) code = RC_down; + if ((code >= 0) && (code <= KEY_MAX)) + return code; + else + return RC_nokey; +} + +void CRCInput::close_click() +{ +} + +void CRCInput::open_click() +{ +} + +void CRCInput::reset_dsp(int rate) +{ +} + +void CRCInput::set_dsp() +{ +} + +void CRCInput::play_click() +{ +} diff --git a/src/driver/rcinput.h b/src/driver/rcinput.h new file mode 100644 index 000000000..e0d830b0a --- /dev/null +++ b/src/driver/rcinput.h @@ -0,0 +1,247 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __MOD_rcinput__ +#define __MOD_rcinput__ + +#include +#include +#include + +#ifndef KEY_OK +#define KEY_OK 0x160 +#endif + +#ifndef KEY_RED +#define KEY_RED 0x18e +#endif + +#ifndef KEY_GREEN +#define KEY_GREEN 0x18f +#endif + +#ifndef KEY_YELLOW +#define KEY_YELLOW 0x190 +#endif + +#ifndef KEY_BLUE +#define KEY_BLUE 0x191 +#endif + +/* SAGEM remote controls have the following additional keys */ + +#ifndef KEY_TOPLEFT +#define KEY_TOPLEFT 0x1a2 +#endif + +#ifndef KEY_TOPRIGHT +#define KEY_TOPRIGHT 0x1a3 +#endif + +#ifndef KEY_BOTTOMLEFT +#define KEY_BOTTOMLEFT 0x1a4 +#endif + +#ifndef KEY_BOTTOMRIGHT +#define KEY_BOTTOMRIGHT 0x1a5 +#endif + +typedef uint32_t neutrino_msg_t; +typedef uint32_t neutrino_msg_data_t; + +#define NEUTRINO_UDS_NAME "/tmp/neutrino.sock" + + +class CRCInput +{ + private: + struct event + { + neutrino_msg_t msg; + neutrino_msg_data_t data; + }; + + struct timer + { + uint id; + unsigned long long interval; + unsigned long long times_out; + bool correct_time; + }; + + uint32_t timerid; + std::vector timers; + + int fd_pipe_high_priority[2]; + int fd_pipe_low_priority[2]; + int fd_gamerc; +#define NUMBER_OF_EVENT_DEVICES 1 + int fd_rc[NUMBER_OF_EVENT_DEVICES]; + int fd_keyb; + int fd_event; + + int fd_max; + int clickfd; + __u16 rc_last_key; + void set_dsp(); + + void open(); + void close(); + int translate(int code, int num); + + void calculateMaxFd(void); + + int checkTimers(); + + public: + //rc-code definitions + static const neutrino_msg_t RC_Repeat = 0x0400; + static const neutrino_msg_t RC_Release = 0x0800; + static const neutrino_msg_t RC_MaxRC = KEY_MAX | RC_Repeat | RC_Release; /* /include/linux/input.h: #define KEY_MAX 0x1ff */ + static const neutrino_msg_t RC_KeyBoard = 0x4000; + static const neutrino_msg_t RC_Events = 0x80000000; + static const neutrino_msg_t RC_Messages = 0x90000000; + static const neutrino_msg_t RC_WithData = 0xA0000000; + enum + { + RC_0 = KEY_0, /* /include/linux/input.h: #define KEY_0 11 */ + RC_1 = KEY_1, /* /include/linux/input.h: #define KEY_1 2 */ + RC_2 = KEY_2, /* /include/linux/input.h: #define KEY_2 3 */ + RC_3 = KEY_3, /* /include/linux/input.h: #define KEY_3 4 */ + RC_4 = KEY_4, /* /include/linux/input.h: #define KEY_4 5 */ + RC_5 = KEY_5, /* /include/linux/input.h: #define KEY_5 6 */ + RC_6 = KEY_6, /* /include/linux/input.h: #define KEY_6 7 */ + RC_7 = KEY_7, /* /include/linux/input.h: #define KEY_7 8 */ + RC_8 = KEY_8, /* /include/linux/input.h: #define KEY_8 9 */ + RC_9 = KEY_9, /* /include/linux/input.h: #define KEY_9 10 */ + RC_backspace = KEY_BACKSPACE, /* /include/linux/input.h: #define KEY_BACKSPACE 14 */ + RC_up = KEY_UP, /* /include/linux/input.h: #define KEY_UP 103 */ + RC_left = KEY_LEFT, /* /include/linux/input.h: #define KEY_LEFT 105 */ + RC_right = KEY_RIGHT, /* /include/linux/input.h: #define KEY_RIGHT 106 */ + RC_down = KEY_DOWN, /* /include/linux/input.h: #define KEY_DOWN 108 */ + RC_spkr = KEY_MUTE, /* /include/linux/input.h: #define KEY_MUTE 113 */ + RC_minus = KEY_VOLUMEDOWN, /* /include/linux/input.h: #define KEY_VOLUMEDOWN 114 */ + RC_plus = KEY_VOLUMEUP, /* /include/linux/input.h: #define KEY_VOLUMEUP 115 */ + RC_standby = KEY_POWER, /* /include/linux/input.h: #define KEY_POWER 116 */ + RC_help = KEY_HELP, /* /include/linux/input.h: #define KEY_HELP 138 */ + RC_home = KEY_EXIT, /* /include/linux/input.h: #define KEY_HOME 102 */ + RC_setup = KEY_MENU, /* /include/linux/input.h: #define KEY_SETUP 141 */ + RC_topleft = KEY_TOPLEFT, + RC_topright = KEY_TOPRIGHT, + RC_page_up = KEY_PAGEUP, /* /include/linux/input.h: #define KEY_PAGEUP 104 */ + RC_page_down = KEY_PAGEDOWN, /* /include/linux/input.h: #define KEY_PAGEDOWN 109 */ + RC_ok = KEY_OK, /* /include/linux/input.h: #define KEY_OK 0x160 */ /* in patched input.h */ + RC_red = KEY_RED, /* /include/linux/input.h: #define KEY_RED 0x18e */ /* in patched input.h */ + RC_green = KEY_GREEN, /* /include/linux/input.h: #define KEY_GREEN 0x18f */ /* in patched input.h */ + RC_yellow = KEY_YELLOW, /* /include/linux/input.h: #define KEY_YELLOW 0x190 */ /* in patched input.h */ + RC_blue = KEY_BLUE, /* /include/linux/input.h: #define KEY_BLUE 0x191 */ /* in patched input.h */ + RC_top_left = KEY_TOPLEFT, /* /include/linux/input.h: #define KEY_TOPLEFT 0x1a2 */ /* in patched input.h */ + RC_top_right = KEY_TOPRIGHT, /* /include/linux/input.h: #define KEY_TOPRIGHT 0x1a3 */ /* in patched input.h */ + RC_bottom_left = KEY_BOTTOMLEFT, /* /include/linux/input.h: #define KEY_BOTTOMLEFT 0x1a4 */ /* in patched input.h */ + RC_bottom_right = KEY_BOTTOMRIGHT, /* /include/linux/input.h: #define KEY_BOTTOMRIGHT 0x1a5 */ /* in patched input.h */ + + RC_audio = KEY_AUDIO, + RC_video = KEY_VIDEO, + RC_tv = KEY_TV, + RC_radio = KEY_RADIO, + RC_text = KEY_TEXT, + RC_info = KEY_INFO, + RC_epg = KEY_EPG, + RC_recall = KEY_LAST, + RC_favorites = KEY_FAVORITES, + RC_sat = KEY_SAT, + RC_sat2 = KEY_SAT2, + RC_record = KEY_RECORD, + RC_play = KEY_PLAY, + RC_pause = KEY_PAUSE, + RC_forward = KEY_FORWARD, + RC_rewind = KEY_REWIND, + RC_stop = KEY_STOP, + RC_timeshift = KEY_TIME, + RC_mode = KEY_MODE, + RC_games = KEY_GAMES, + RC_next = KEY_NEXT, + RC_prev = KEY_PREVIOUS, + + RC_timeout = 0xFFFFFFFF, + RC_nokey = 0xFFFFFFFE + }; + + inline int getFileHandle(void) /* used for plugins (i.e. games) only */ + { +#if HAVE_DVB_API_VERSION == 1 + return fd_gamerc; +#else + return fd_rc[0]; +#endif + } + void stopInput(); + void restartInput(); + + unsigned long long repeat_block; + unsigned long long repeat_block_generic; + CRCInput(); //constructor - opens rc-device and starts needed threads + ~CRCInput(); //destructor - closes rc-device + + + static bool isNumeric(const neutrino_msg_t key); + static int getNumericValue(const neutrino_msg_t key); + static unsigned int convertDigitToKey(const unsigned int digit); + static int getUnicodeValue(const neutrino_msg_t key); + + static const char * getSpecialKeyName(const unsigned int key); + static std::string getKeyName(const unsigned int key); + + int addTimer(unsigned long long Interval, bool oneshot= true, bool correct_time= true ); + int addTimer(struct timeval Timeout); + int addTimer(const time_t *Timeout); + + void killTimer(uint32_t id); + + static long long calcTimeoutEnd_MS(const int timeout_in_milliseconds); + static long long calcTimeoutEnd(const int timeout_in_seconds); + + void getMsgAbsoluteTimeout(neutrino_msg_t * msg, neutrino_msg_data_t * data, unsigned long long *TimeoutEnd, bool bAllowRepeatLR= false); + void getMsg(neutrino_msg_t * msg, neutrino_msg_data_t * data, int Timeout, bool bAllowRepeatLR= false); //get message, timeout in 1/10 secs :) + void getMsg_ms(neutrino_msg_t * msg, neutrino_msg_data_t * data, int Timeout, bool bAllowRepeatLR= false); //get message, timeout in msecs :) + void getMsg_us(neutrino_msg_t * msg, neutrino_msg_data_t * data, unsigned long long Timeout, bool bAllowRepeatLR= false);//get message, timeout in µsecs :) + void postMsg(const neutrino_msg_t msg, const neutrino_msg_data_t data, const bool Priority = true); // push message back into buffer + void clearRCMsg(); + + int messageLoop( bool anyKeyCancels = false, int timeout= -1 ); + void open_click(); + void close_click(); + void play_click(); + void reset_dsp(int rate); +}; + + +#endif diff --git a/src/driver/rfmod.cpp b/src/driver/rfmod.cpp new file mode 100644 index 000000000..5cbe6f071 --- /dev/null +++ b/src/driver/rfmod.cpp @@ -0,0 +1,134 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#define RFMOD_DEV "/dev/rfmod0" +#define IOCTL_SET_CHANNEL 0 +#define IOCTL_SET_TESTMODE 1 +#define IOCTL_SET_SOUNDENABLE 2 +#define IOCTL_SET_SOUNDSUBCARRIER 3 +#define IOCTL_SET_FINETUNE 4 +#define IOCTL_SET_STANDBY 5 + +#define C0 3 +#define C1 2 +#define FL 1 +#define FM 0 + +RFmod::RFmod() +{ + rfmodfd=open(RFMOD_DEV, O_RDWR); +} + +void RFmod::init() +{ + soundsubcarrier=g_settings.rf_subcarrier; + soundenable=g_settings.rf_soundenable; + channel = g_settings.rf_channel; + finetune = g_settings.rf_finetune; + standby = g_settings.rf_standby; + + setSoundSubCarrier(soundsubcarrier); + setSoundEnable(soundenable); + setChannel(channel); + setFinetune(finetune); + setStandby(standby); + setTestPattern(0); +} + +RFmod::~RFmod() +{ + if (rfmodfd>=0) + close(rfmodfd); +} + +int RFmod::setSoundEnable(int val) +{ + soundenable = val; +//printf("RF sound: %d\n", val); + if(rfmodfd > 0) + ioctl(rfmodfd,IOCTL_SET_SOUNDENABLE,&soundenable); + + return 0; +} + +int RFmod::setStandby(int val) +{ + standby = val; +//printf("RF standby: %d\n", val); + + if(rfmodfd > 0) + ioctl(rfmodfd,IOCTL_SET_STANDBY,&standby); + + return 0; +} + +int RFmod::setChannel(int val) +{ + channel = val; +//printf("RF channel: %d\n", val); + + if(rfmodfd > 0) + ioctl(rfmodfd,IOCTL_SET_CHANNEL,&channel); + + return 0; +} + +int RFmod::setFinetune(int val) +{ + finetune = val; +//printf("RF finetune: %d\n", val); + + if(rfmodfd > 0) + ioctl(rfmodfd,IOCTL_SET_FINETUNE,&finetune); + + return 0; +} + +int RFmod::setTestPattern(int val) +{ +//printf("RF test: %d\n", val); + if(rfmodfd > 0) + ioctl(rfmodfd,IOCTL_SET_TESTMODE,&val); + + return 0; +} + + +int RFmod::setSoundSubCarrier(int freq) //freq in KHz +{ +//printf("RF carrier: %d\n", freq); + soundsubcarrier=freq; +/* + switch(freq) + { + case 4500: + sfd=0; + break; + case 5500: + sfd=1; + break; + case 6000: + sfd=2; + break; + case 6500: + sfd=3; + break; + default: + return -1; + } +*/ + if(rfmodfd > 0) + ioctl(rfmodfd,IOCTL_SET_SOUNDSUBCARRIER,&soundsubcarrier); + + return 0; +} diff --git a/src/driver/rfmod.h b/src/driver/rfmod.h new file mode 100644 index 000000000..31b669077 --- /dev/null +++ b/src/driver/rfmod.h @@ -0,0 +1,23 @@ +#ifndef __erfmod_h +#define __erfmod_h + + +class RFmod +{ + int channel,soundsubcarrier,soundenable,finetune,standby; + +public: + RFmod(); + ~RFmod(); + + int rfmodfd; + void init(); + + int setChannel(int channel); + int setSoundSubCarrier(int val); + int setSoundEnable(int val); + int setStandby(int val); + int setFinetune(int val); + int setTestPattern(int val); +}; +#endif diff --git a/src/driver/ringbuffer.c b/src/driver/ringbuffer.c new file mode 100755 index 000000000..b15120c49 --- /dev/null +++ b/src/driver/ringbuffer.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2000 Paul Davis + * Copyright (C) 2003 Rohan Drape + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * ISO/POSIX C version of Paul Davis's lock free ringbuffer C++ code. + * This is safe for the case of one read thread and one write thread. + */ + +#include +#include +#include +#include +#include "ringbuffer.h" + + +/* Create a new ringbuffer to hold at least `sz' bytes of data. The + * actual buffer size is rounded up to the next power of two. + */ +ringbuffer_t * ringbuffer_create (int sz) +{ + int power_of_two; + ringbuffer_t *rb; + + rb = malloc (sizeof (ringbuffer_t)); + + for(power_of_two = 1; 1 << power_of_two < sz; power_of_two++) + ; + + rb->size = 1 << power_of_two; + rb->size_mask = rb->size-1; + rb->write_ptr = 0; + rb->read_ptr = 0; + rb->buf = malloc (rb->size); + rb->mlocked = 0; +printf("RING buffer size %d\n", rb->size); fflush(stdout); + return rb; +} + + +/* Free all data associated with the ringbuffer `rb'. + */ +void ringbuffer_free (ringbuffer_t * rb) +{ + if (rb->mlocked) + munlock (rb->buf, rb->size); + + free (rb->buf); +} + +/* Lock the data block of `rb' using the system call 'mlock'. */ +int ringbuffer_mlock (ringbuffer_t * rb) +{ + if (mlock (rb->buf, rb->size)) + return -1; + + rb->mlocked = 1; + return 0; +} + +/* Reset the read and write pointers to zero. This is not thread + * safe. + */ +void ringbuffer_reset (ringbuffer_t * rb) +{ + rb->read_ptr = 0; + rb->write_ptr = 0; +} + +/* Return the number of bytes available for reading. This is the + * number of bytes in front of the read pointer and behind the write + * pointer. + */ +size_t ringbuffer_read_space (ringbuffer_t * rb) +{ + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) + return w - r; + else + return (w - r + rb->size) & rb->size_mask; +} + +/* Return the number of bytes available for writing. This is the + * number of bytes in front of the write pointer and behind the read + * pointer. + */ +size_t ringbuffer_write_space (ringbuffer_t * rb) +{ + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) + return ((r - w + rb->size) & rb->size_mask) - 1; + else if (w < r) + return (r - w) - 1; + else + return rb->size - 1; +} + +/* The copying data reader. Copy at most `cnt' bytes from `rb' to + * `dest'. Returns the actual number of bytes copied. + */ +size_t ringbuffer_read (ringbuffer_t * rb, char *dest, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + + if ((free_cnt = ringbuffer_read_space (rb)) == 0) + return 0; + + to_read = cnt > free_cnt ? free_cnt : cnt; + + cnt2 = rb->read_ptr + to_read; + + if (cnt2 > rb->size) + { + n1 = rb->size - rb->read_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_read; + n2 = 0; + } + + memcpy (dest, &(rb->buf[rb->read_ptr]), n1); + rb->read_ptr += n1; + rb->read_ptr &= rb->size_mask; + + if (n2) + { + memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2); + rb->read_ptr += n2; + rb->read_ptr &= rb->size_mask; + } + + return to_read; +} + +/* The copying data writer. Copy at most `cnt' bytes to `rb' from + * `src'. Returns the actual number of bytes copied. + */ +size_t ringbuffer_write (ringbuffer_t * rb, char *src, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_write; + size_t n1, n2; + + if ((free_cnt = ringbuffer_write_space (rb)) == 0) + return 0; + + to_write = cnt > free_cnt ? free_cnt : cnt; + + cnt2 = rb->write_ptr + to_write; + + if (cnt2 > rb->size) { + n1 = rb->size - rb->write_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_write; + n2 = 0; + } + + memcpy (&(rb->buf[rb->write_ptr]), src, n1); + rb->write_ptr += n1; + rb->write_ptr &= rb->size_mask; + + if (n2) + { + memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2); + rb->write_ptr += n2; + rb->write_ptr &= rb->size_mask; + } + + return to_write; +} + +/* Advance the read pointer `cnt' places. + */ +void ringbuffer_read_advance (ringbuffer_t * rb, size_t cnt) +{ + rb->read_ptr += cnt; + rb->read_ptr &= rb->size_mask; +} + +/* Advance the write pointer `cnt' places. + */ +void ringbuffer_write_advance (ringbuffer_t * rb, size_t cnt) +{ + rb->write_ptr += cnt; + rb->write_ptr &= rb->size_mask; +} + +/* The non-copying data reader. `vec' is an array of two places. Set + * the values at `vec' to hold the current readable data at `rb'. If + * the readable data is in one segment the second segment has zero + * length. + */ +void ringbuffer_get_read_vector (ringbuffer_t * rb, ringbuffer_data_t * vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) + free_cnt = w - r; + else + free_cnt = (w - r + rb->size) & rb->size_mask; + + cnt2 = r + free_cnt; + + if (cnt2 > rb->size) + { + /* Two part vector: the rest of the buffer after the current write + * ptr, plus some from the start of the buffer. + */ + vec[0].buf = &(rb->buf[r]); + vec[0].len = rb->size - r; + vec[1].buf = rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } + else + { + /* Single part vector: just the rest of the buffer */ + vec[0].buf = &(rb->buf[r]); + vec[0].len = free_cnt; + vec[1].len = 0; + } +} + +/* The non-copying data writer. `vec' is an array of two places. Set + * the values at `vec' to hold the current writeable data at `rb'. If + * the writeable data is in one segment the second segment has zero + * length. + */ +void ringbuffer_get_write_vector (ringbuffer_t * rb, ringbuffer_data_t * vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) + free_cnt = ((r - w + rb->size) & rb->size_mask) - 1; + else if (w < r) + free_cnt = (r - w) - 1; + else + free_cnt = rb->size - 1; +//free_cnt = free_cnt / 188 * 188; + cnt2 = w + free_cnt; + + if (cnt2 > rb->size) + { + /* Two part vector: the rest of the buffer after the current write + * ptr, plus some from the start of the buffer. + */ + vec[0].buf = &(rb->buf[w]); + vec[0].len = rb->size - w; + vec[1].buf = rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } + else + { + vec[0].buf = &(rb->buf[w]); + vec[0].len = free_cnt; + vec[1].len = 0; + } +} diff --git a/src/driver/ringbuffer.h b/src/driver/ringbuffer.h new file mode 100755 index 000000000..f86b0eb08 --- /dev/null +++ b/src/driver/ringbuffer.h @@ -0,0 +1,40 @@ +#ifndef _RINGBUFFER_H +#define _RINGBUFFER_H + +#include + +typedef struct +{ + char *buf; + size_t len; +} ringbuffer_data_t; + +typedef struct +{ + char *buf; + volatile size_t write_ptr; + volatile size_t read_ptr; + size_t size; + size_t size_mask; + int mlocked; +} ringbuffer_t; + +ringbuffer_t *ringbuffer_create(int sz); +void ringbuffer_free(ringbuffer_t *rb); + +int ringbuffer_mlock(ringbuffer_t *rb); +void ringbuffer_reset(ringbuffer_t *rb); + +void ringbuffer_write_advance(ringbuffer_t *rb, size_t cnt); +void ringbuffer_read_advance(ringbuffer_t *rb, size_t cnt); + +size_t ringbuffer_write_space(ringbuffer_t *rb); +size_t ringbuffer_read_space(ringbuffer_t *rb); + +size_t ringbuffer_read(ringbuffer_t *rb, char *dest, size_t cnt); +size_t ringbuffer_write(ringbuffer_t *rb, char *src, size_t cnt); + +void ringbuffer_get_read_vector(ringbuffer_t *rb, ringbuffer_data_t *vec); +void ringbuffer_get_write_vector(ringbuffer_t *rb, ringbuffer_data_t *vec); + +#endif diff --git a/src/driver/screen_max.cpp b/src/driver/screen_max.cpp new file mode 100644 index 000000000..80dbb0060 --- /dev/null +++ b/src/driver/screen_max.cpp @@ -0,0 +1,51 @@ +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/screen_max.cpp,v 1.3 2004/03/17 22:56:08 rasc Exp $ + * + * -- some odd module to calc max. screen usage of an menue + * -- this should be somewhere else (neutrino needs redesign) + * + * (C) 2004 by rasc + */ + +#include +#include "global.h" +#include "driver/screen_max.h" + +// -- this is a simple odd class provided for 'static' usage +// -- to calculate max. usage of a preferred menue size (x,y) +// -- this is due to 16:9 TV zoom functions, which are cutting menues. +// -- so using this function will make menues to obey max. screen settings. +// +// usage: e.g. try to paint menue h: 500 w, 400 (but screen is limited +// to (450 x 420)), functions will return 450 and 400 +// the _add factor is for boundary... +// +// 16:9 Zoom-Mode on a Thomson TV set will e.g. be 625x415 +// +// 2004-03-17 rasc + +int w_max (int w_size, int w_add) +{ + int dw; + int ret; + + dw = (g_settings.screen_EndX - g_settings.screen_StartX); + + ret = w_size; + if (dw <= (w_size + w_add) ) ret = dw - w_add; + + return ret; +} + +int h_max (int h_size, int h_add) +{ + int dh; + int ret; + + dh = (g_settings.screen_EndY - g_settings.screen_StartY); + + ret = h_size; + if (dh <= (h_size + h_add) ) ret = dh - h_add; + + return ret; +} diff --git a/src/driver/screen_max.h b/src/driver/screen_max.h new file mode 100644 index 000000000..8b60d0570 --- /dev/null +++ b/src/driver/screen_max.h @@ -0,0 +1,33 @@ +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/screen_max.h,v 1.1 2004/03/17 21:30:51 rasc Exp $ + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef __SCREEN_MAX__ +#define __SCREEN_MAX__ + + +int w_max (int w_size, int w_add); +int h_max (int h_size, int h_add); + + + +#endif + + diff --git a/src/driver/showframe.c b/src/driver/showframe.c new file mode 100644 index 000000000..a00afd1b0 --- /dev/null +++ b/src/driver/showframe.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VIDEO_DEV "/dev/dvb/card0/video0" +#define VIDEO_SET_AUTOFLUSH _IOW('o', 2, int) + +void showframe(char * fname) +{ + int file, size; + char *buffer; + + file=open(fname, O_RDONLY); + if (file < 0) + return; + size=lseek(file, 0, SEEK_END); + lseek(file, 0, SEEK_SET); + if (size < 0) + { + close(file); + return; + } + buffer = malloc(size); + read(file, buffer, size); + close(file); + displayIFrame(buffer, size); + free(buffer); + return; +} +static int displayIFrame(const char *frame, int len) +{ + int fdv, fdvideo, i; + fdv=open("/dev/video", O_WRONLY); + if (fdv < 0) { + printf("cant open /dev/video\n"); + return -1; + } + + fdvideo = open(VIDEO_DEV, O_RDWR); + if (fdvideo < 0) { + colose(fdv);//Resource leak: fdv + printf("cant open %s\n", VIDEO_DEV); + return -1; + } + if (ioctl(fdvideo, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY ) <0) + printf("VIDEO_SELECT_SOURCE failed \n"); + if (ioctl(fdvideo, VIDEO_CLEAR_BUFFER) <0 ) + printf("VIDEO_CLEAR_BUFFER failed \n"); + if (ioctl(fdvideo, VIDEO_PLAY) < 0 ) + printf("VIDEO_PLAY failed\n"); + + for (i=0; i < 2; i++ ) + write(fdv, frame, len); + + unsigned char buf[128]; + memset(&buf, 0, 128); + write(fdv, buf, 128); + + if ( ioctl(fdv, VIDEO_SET_AUTOFLUSH, 0) < 0 ) + printf("VIDEO_SET_AUTOFLUSH off failed\n"); + + if (ioctl(fdvideo, VIDEO_SET_BLANK, 0) < 0 ) + printf("VIDEO_SET_BLANK failed\n"); + + close(fdvideo); + if ( ioctl(fdv, VIDEO_SET_AUTOFLUSH, 1) < 0 ) + printf("VIDEO_SET_AUTOFLUSH on failed\n"); + + close(fdv); + return 0; +} + diff --git a/src/driver/shutdown_count.cpp b/src/driver/shutdown_count.cpp new file mode 100644 index 000000000..c6fd2e398 --- /dev/null +++ b/src/driver/shutdown_count.cpp @@ -0,0 +1,97 @@ +/* + Shutdown Counter - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include +#include + + +SHTDCNT::SHTDCNT() + : configfile('\t') +{ +} + +SHTDCNT* SHTDCNT::getInstance() +{ + static SHTDCNT* shtdcnt = NULL; + if(shtdcnt == NULL) + { + shtdcnt = new SHTDCNT(); + } + return shtdcnt; +} + +void* SHTDCNT::TimeThread(void *) +{ + while(1) + { + sleep(1); + SHTDCNT::getInstance()->shutdown_counter(); + } + return NULL; +} + +void SHTDCNT::init() +{ + if (pthread_create (&thrTime, NULL, TimeThread, NULL) != 0 ) + { + perror("[SHTDCNT]: pthread_create(TimeThread)"); + return ; + } +} + +void SHTDCNT::shutdown_counter() +{ + if (atoi(g_settings.shutdown_count) > 0) + { + if ((CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_standby) && (!CNeutrinoApp::getInstance ()->recordingstatus)) + { + if (shutdown_cnt > 0 ) + { + shutdown_cnt = shutdown_cnt - 1; + printf("[SHTDCNT] shutdown counter: %d sec to shutdown\n", shutdown_cnt); + } + else + { + // send shutdown message + printf("[SHTDCNT] shutdown counter send NeutrinoMessages::SHUTDOWN\n"); + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::SHUTDOWN, 0); + } + } + else + { + // reset counter + shutdown_cnt = atoi(g_settings.shutdown_count) * 60; + } + } +} diff --git a/src/driver/shutdown_count.h b/src/driver/shutdown_count.h new file mode 100644 index 000000000..2bf7efee3 --- /dev/null +++ b/src/driver/shutdown_count.h @@ -0,0 +1,53 @@ +/* + Shutdown Counter - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __shutdown_count__ +#define __shutdown_count__ + +#include +#include + +class SHTDCNT +{ + private: + + pthread_t thrTime; + unsigned int shutdown_cnt; + CConfigFile configfile; + + void shutdown_counter(); + SHTDCNT(); + + static void* TimeThread(void*); + + public: + + void setlcdparameter(void); + + static SHTDCNT* getInstance(); + void init(); +}; + +#endif diff --git a/src/driver/slotbuffer.c b/src/driver/slotbuffer.c new file mode 100644 index 000000000..3a59da1b9 --- /dev/null +++ b/src/driver/slotbuffer.c @@ -0,0 +1,107 @@ +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/slotbuffer.c,v 1.1 2004/06/03 09:51:54 thegoodguy Exp $ + * + * (C) 2004 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* Note: this slotbuffer "wastes" one slot */ + +#include "slotbuffer.h" +#include + +slotbuffer_t * slotbuffer_construct(const size_t size) +{ + slotbuffer_t * slotbuffer; + + slotbuffer = malloc(sizeof(slotbuffer_t)); + + slotbuffer->buffer = malloc(size); + slotbuffer->size = size; + slotbuffer->read_pointer = 0; + slotbuffer->write_pointer = 0; + + return slotbuffer; +} + +void slotbuffer_destruct(slotbuffer_t * const slotbuffer) +{ + free(slotbuffer->buffer); + free(slotbuffer); +} + +size_t slotbuffer_remaining_read_space(slotbuffer_t * const slotbuffer) +{ + ssize_t delta; + + delta = slotbuffer->write_pointer; + delta -= slotbuffer->read_pointer; + + return (delta >= 0) ? delta : (delta + slotbuffer->size); +} + +size_t slotbuffer_remaining_write_space(slotbuffer_t * const slotbuffer) +{ + ssize_t delta; + + delta = slotbuffer->read_pointer; + delta -= slotbuffer->write_pointer; + + return ((delta > 0) ? delta : (delta + slotbuffer->size)) - 1; +} + +size_t slotbuffer_remaining_continuous_read_space(slotbuffer_t * const slotbuffer) +{ + ssize_t delta; + size_t read_pointer; + + delta = slotbuffer->write_pointer; + read_pointer = slotbuffer->read_pointer; + delta -= read_pointer; + + return (delta >= 0) ? delta : (slotbuffer->size - read_pointer); +} + +size_t slotbuffer_remaining_continuous_write_space(slotbuffer_t * const slotbuffer) +{ + ssize_t delta; + size_t write_pointer; + + delta = slotbuffer->read_pointer; + + if (delta == 0) + return (slotbuffer->size - slotbuffer->write_pointer - 1); + + write_pointer = slotbuffer->write_pointer; + delta -= write_pointer; + + return (delta > 0) ? (delta - 1) : (slotbuffer->size - write_pointer); +} + +void slotbuffer_advance_read_pointer(slotbuffer_t * const slotbuffer, const size_t delta) +{ + slotbuffer->read_pointer += delta; + if (slotbuffer->read_pointer >= slotbuffer->size) + slotbuffer->read_pointer = 0; +} + +void slotbuffer_advance_write_pointer(slotbuffer_t * const slotbuffer, const size_t delta) +{ + slotbuffer->write_pointer += delta; + if (slotbuffer->write_pointer >= slotbuffer->size) + slotbuffer->write_pointer = 0; +} diff --git a/src/driver/slotbuffer.h b/src/driver/slotbuffer.h new file mode 100644 index 000000000..07266f62d --- /dev/null +++ b/src/driver/slotbuffer.h @@ -0,0 +1,44 @@ +#ifndef __slotbuffer_h__ +#define __slotbuffer_h__ + +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/slotbuffer.h,v 1.1 2004/06/03 09:51:54 thegoodguy Exp $ + * + * (C) 2004 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +typedef struct +{ + unsigned char * buffer; + size_t size; + volatile size_t read_pointer; + volatile size_t write_pointer; +} slotbuffer_t; + +slotbuffer_t * slotbuffer_construct (size_t const size ); +void slotbuffer_destruct (slotbuffer_t * const slotbuffer ); +size_t slotbuffer_remaining_read_space (slotbuffer_t * const slotbuffer ); +size_t slotbuffer_remaining_write_space (slotbuffer_t * const slotbuffer ); +size_t slotbuffer_remaining_continuous_read_space (slotbuffer_t * const slotbuffer ); +size_t slotbuffer_remaining_continuous_write_space(slotbuffer_t * const slotbuffer ); +void slotbuffer_advance_read_pointer (slotbuffer_t * const slotbuffer, size_t const delta); +void slotbuffer_advance_write_pointer (slotbuffer_t * const slotbuffer, size_t const delta); + +#endif diff --git a/src/driver/stream2file.cpp b/src/driver/stream2file.cpp new file mode 100644 index 000000000..75074e962 --- /dev/null +++ b/src/driver/stream2file.cpp @@ -0,0 +1,185 @@ +/* + * $Id: stream2file.cpp,v 1.19 2005/01/12 20:40:22 chakazulu Exp $ + * + * streaming to file/disc + * + * Copyright (C) 2004 Axel Buehning , + * thegoodguy + * + * based on code which is + * Copyright (C) 2001 TripleDES + * Copyright (C) 2000, 2001 Marcus Metzler + * Copyright (C) 2002 Andreas Oberritter + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern "C" { +#include +} + +static cRecord * record = NULL; +extern CZapitChannel *channel; +extern CCam *cam0; + +extern bool autoshift; +extern bool autoshift_delete; + +#define MAXPIDS 64 +#define FILENAMEBUFFERSIZE 1024 + +static stream2file_status_t exit_flag = STREAM2FILE_STATUS_IDLE; + +char rec_filename[FILENAMEBUFFERSIZE]; + +stream2file_error_msg_t start_recording(const char * const filename, + const char * const info, const unsigned short vpid, const unsigned short * const pids, + const unsigned int numpids) +{ + int fd; + char buf[FILENAMEBUFFERSIZE]; + struct statfs s; + + if(autoshift) + sprintf(rec_filename, "%s_temp", filename); + else + sprintf(rec_filename, "%s", filename); + + // write stream information (should wakeup the disk from standby, too) + sprintf(buf, "%s.xml", rec_filename); + + char * dir = strdup(buf); + int ret = statfs(dirname(dir), &s); + free(dir); + if((ret != 0) || (s.f_type == 0x72b6) || (s.f_type == 0x24051905)) { + return STREAM2FILE_INVALID_DIRECTORY; + } + if ((fd = open(buf, O_SYNC | O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) { + write(fd, info, strlen(info)); + fdatasync(fd); + close(fd); + } else { + return STREAM2FILE_INVALID_DIRECTORY; + } + + exit_flag = STREAM2FILE_STATUS_RUNNING; + + sprintf(buf, "%s.ts", rec_filename); + + printf("Record start: file %s vpid %x apid %x\n", buf, vpid, pids[0]); + + fd = open(buf, O_CREAT | O_RDWR | O_LARGEFILE | O_TRUNC , S_IRWXO | S_IRWXG | S_IRWXU); + if(fd < 0) { + perror(buf); + return STREAM2FILE_INVALID_DIRECTORY; + } + genpsi(fd); + + if(!record) + record = new cRecord(2); + + record->Open(numpids); + + if(!record->Start(fd, (unsigned short ) vpid, (unsigned short *) pids, numpids)) { + record->Stop(); + delete record; + record = NULL; + return STREAM2FILE_INVALID_DIRECTORY; + } + + if(channel) + cam0->setCaPmt(channel->getCaPmt(), 0, 5, true); // demux 0 + 2, update + + CVFD::getInstance()->ShowIcon(VFD_ICON_CAM1, true); + + return STREAM2FILE_OK; +} + +stream2file_error_msg_t stop_recording(const char * const info) +{ + char buf[FILENAMEBUFFERSIZE]; + char buf1[FILENAMEBUFFERSIZE]; + int fd; + stream2file_error_msg_t ret; + + //if(!autoshift || autoshift_delete) + { + sprintf(buf, "%s.xml", rec_filename); + if ((fd = open(buf, O_SYNC | O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) { + write(fd, info, strlen(info)); + fdatasync(fd); + close(fd); + } + } + + if(record) { + record->Stop(); + delete record; + record = NULL; + } + + if (exit_flag == STREAM2FILE_STATUS_RUNNING) { + exit_flag = STREAM2FILE_STATUS_IDLE; + ret = STREAM2FILE_OK; + } + else + ret = STREAM2FILE_RECORDING_THREADS_FAILED; + + if((autoshift && g_settings.auto_delete) || autoshift_delete) { + sprintf(buf, "rm -f %s.ts &", rec_filename); + sprintf(buf1, "%s.xml", rec_filename); + autoshift_delete = false; + system(buf); + unlink(buf1); + } + CVFD::getInstance()->ShowIcon(VFD_ICON_CAM1, false); + + rec_filename[0] = 0; + return ret; +} + diff --git a/src/driver/stream2file.h b/src/driver/stream2file.h new file mode 100644 index 000000000..0708a11aa --- /dev/null +++ b/src/driver/stream2file.h @@ -0,0 +1,59 @@ +/* + * $Id: stream2file.h,v 1.10 2005/01/12 20:40:22 chakazulu Exp $ + * + * (C) 2004 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __stream2file_h__ +#define __stream2file_h__ + +enum stream2file_error_msg_t +{ + STREAM2FILE_OK = 0, + STREAM2FILE_BUSY = -1, + STREAM2FILE_INVALID_DIRECTORY = -2, + STREAM2FILE_INVALID_PID = -3, + STREAM2FILE_PES_FILTER_FAILURE = -4, + STREAM2FILE_DVR_OPEN_FAILURE = -5, + STREAM2FILE_RECORDING_THREADS_FAILED = -6, +}; + +enum stream2file_status_t +{ + STREAM2FILE_STATUS_RUNNING = 0, + STREAM2FILE_STATUS_IDLE = 1, + STREAM2FILE_STATUS_BUFFER_OVERFLOW = -1, + STREAM2FILE_STATUS_WRITE_OPEN_FAILURE = -2, + STREAM2FILE_STATUS_WRITE_FAILURE = -3, + STREAM2FILE_STATUS_READ_FAILURE = -4 +}; + +struct stream2file_status2_t +{ + stream2file_status_t status; + char dir[100]; +}; + +stream2file_error_msg_t start_recording(const char * const filename, + const char * const info, + const unsigned short vpid, + const unsigned short * const apids, + const unsigned int numpids); +stream2file_error_msg_t stop_recording(const char * const info); + +#endif diff --git a/src/driver/streamts.cpp b/src/driver/streamts.cpp new file mode 100644 index 000000000..6382e6280 --- /dev/null +++ b/src/driver/streamts.cpp @@ -0,0 +1,487 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif +#include + +#include + +#include +#include +#include + +extern CZapitChannel *channel; +extern CCam *cam0; + +#define TS_SIZE 188 +//#define IN_SIZE (2048 * TS_SIZE) +#define IN_SIZE (TS_SIZE * 362) + +#define DMX_BUFFER_SIZE (3008 * 62) + +/* maximum number of pes pids */ +#define MAXPIDS 64 + +/* tcp packet data size */ +//#define PACKET_SIZE 1448 +#define PACKET_SIZE 7*TS_SIZE + +//unsigned char * buf; + +int demuxfd[MAXPIDS]; + +static unsigned char exit_flag = 0; +static unsigned int writebuf_size = 0; +static unsigned char writebuf[PACKET_SIZE]; + +static int +sync_byte_offset (const unsigned char * buf, const unsigned int len) +{ + + unsigned int i; + + for (i = 0; i < len; i++) + if (buf[i] == 0x47) + return i; + + return -1; +} + +void packet_stdout (int fd, unsigned char * buf, int count, void * p) +{ + + unsigned int size; + unsigned char * bp; + ssize_t written; + +//printf("packet_stdout count %d\n", count); + /* ensure, that there is always at least one complete + * packet inside of the send buffer */ + while (writebuf_size + count >= PACKET_SIZE) { + + /* how many bytes are to be sent from the input buffer? */ + size = PACKET_SIZE - writebuf_size; + + /* send buffer is not empty, so copy from + input buffer to get a complete packet */ + if (writebuf_size) { + memcpy(writebuf + writebuf_size, buf, size); + bp = writebuf; + } + + /* if send buffer is empty, then do not memcopy, + but send directly from input buffer */ + else { + bp = buf; + } + + /* write the packet, count the amount of really written bytes */ + written = write(fd, bp, PACKET_SIZE); + + /* exit on error */ + if (written == -1) { + perror("write"); + exit_flag = 1; + return; + } + + /* if the packet could not be written completely, then + * how many bytes must be stored in the send buffer + * until the next packet is to be sent? */ + writebuf_size = PACKET_SIZE - written; + + /* move all bytes of the packet which were not sent + * to the beginning of the send buffer */ + if (writebuf_size) + memmove(writebuf, bp + written, writebuf_size); + + /* * advance in the input buffer */ + buf += size; + + /* * decrease the todo size */ + count -= size; + } + + /* if there are still some bytes left in the input buffer, + * then store them in the send buffer and increase send + * buffer size */ + if (count) { + memcpy(writebuf + writebuf_size, buf, count); + writebuf_size += count; + } +} + +int open_incoming_port (int port) +{ + struct sockaddr_in socketAddr; + int socketOptActive = 1; + int handle; + + if (!port) + return -1; + + if ((handle = socket (AF_INET, SOCK_STREAM, 0)) < 0) + { + fprintf (stderr, "network port %u open: ", port); + perror ("socket"); + return -1; + } + + if (setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const void *)&socketOptActive, sizeof (int)) < 0) + { + fprintf (stderr, "network port %u open: error setsockopt\n", port); + close (handle); + return -1; + } + + socketAddr.sin_family = AF_INET; + socketAddr.sin_port = htons (port); + socketAddr.sin_addr.s_addr = htonl (INADDR_ANY); + + if (bind (handle, (struct sockaddr *) &socketAddr, sizeof (socketAddr)) < 0) + { + fprintf (stderr, "network port %u open: ", port); + perror ("bind"); + close (handle); + return -1; + } + + if (listen (handle, 5) < 0) + { + fprintf (stderr, "network port %u open: ", port); + perror ("listen"); + close (handle); + return -1; + } + return handle; +} + +void * streamts_live_thread(void *data); +int streamts_stop; + +void streamts_main_thread(void *data) +{ + struct sockaddr_in servaddr; + int clilen; + + struct pollfd pfd[128]; + int poll_cnt, tcnt; + int listenfd; + int connfd = -1; + int pollres; + int i; + pthread_t st = 0; + + printf("Starting STREAM thread keeper, tid %ld\n", syscall(__NR_gettid)); + + listenfd = open_incoming_port(31339); + if(listenfd < 0) { + printf("Open incoming port failed\n"); + return; + } + printf("listenfd %d\n", listenfd); + + clilen = sizeof (servaddr); + pfd[0].fd = listenfd; + pfd[0].events = (POLLIN | POLLPRI); + pfd[0].revents = 0; + tcnt = 1; + streamts_stop = 0; + + while (!streamts_stop) { + poll_cnt = tcnt; +//printf("polling, count= %d\n", poll_cnt); + pollres = poll (pfd, poll_cnt, 1000); + if (pollres < 0) { + perror("poll"); + continue; + } + if(pollres == 0) + continue; + for (i = poll_cnt - 1; i >= 0; i--) { + if (pfd[i].revents & (POLLIN | POLLPRI | POLLHUP | POLLRDHUP)) { + printf("fd %d has events %x\n", pfd[i].fd, pfd[i].revents); + if (pfd[i].fd == listenfd) { + if(connfd >= 0) + close(connfd); + connfd = accept (listenfd, (struct sockaddr *) &servaddr, (socklen_t *) & clilen); + printf("new connection, fd %d\n", connfd); + if(connfd < 0) { + perror("accept"); + continue; + } + if(st != 0) { + printf("New connection, stopping stream thread\n"); + exit_flag = 1; + pthread_join(st, NULL); + tcnt --; + } + pfd[tcnt].fd = connfd; + pfd[tcnt].events = POLLRDHUP | POLLHUP; + pfd[tcnt].revents = 0; + tcnt++; + exit_flag = 0; + pthread_create (&st, NULL, streamts_live_thread, (void *) connfd); + } else { + if (pfd[i].revents & (POLLHUP | POLLRDHUP)) { + connfd = -1; + printf("Client disconnected, stopping stream thread\n"); + exit_flag = 1; + if(st) + pthread_join(st, NULL); + st = 0; + tcnt --; + } + } + } + } + } + printf("Stopping STREAM thread keeper\n"); + close(listenfd); + if(st != 0) { + printf("Stopping stream thread\n"); + exit_flag = 1; + pthread_join(st, NULL); + close(connfd); + } + return; +} + +void * streamts_live_thread(void *data) +{ + unsigned char * buf; + int pid; + int pids[MAXPIDS]; + char cbuf[512]; + char *bp; + int fd = (int) data; + FILE * fp; + unsigned char demuxfd_count = 0; + + printf("Starting LIVE STREAM thread, fd %d\n", fd); + fp = fdopen(fd, "r+"); + if(fp == NULL) { + perror("fdopen"); + return 0; + } + + writebuf_size = 0; + + cbuf[0] = 0; + bp = &cbuf[0]; + + /* read one line */ + while (bp - &cbuf[0] < (int) sizeof(cbuf)) { + unsigned char c; + int res = read(fd, &c, 1); + if(res < 0) { + perror("read"); + return 0; + } + if ((*bp++ = c) == '\n') + break; + } + + *bp++ = 0; + bp = &cbuf[0]; + + printf("stream: got %s\n", cbuf); + + /* send response to http client */ + if (!strncmp(cbuf, "GET /", 5)) { + fprintf(fp, "HTTP/1.1 200 OK\r\nServer: streamts (%s)\r\n\r\n", "ts" /*&argv[1][1]*/); + fflush(fp); + bp += 5; + } else { + printf("Received garbage\n"); + return 0; + } + + /* parse stdin / url path, start dmx filters */ + do { + int res = sscanf(bp, "%x", &pid); + if(res == 1) { + printf("New pid: 0x%x\n", pid); + pids[demuxfd_count++] = pid; + } + } + while ((bp = strchr(bp, ',')) && (bp++) && (demuxfd_count < MAXPIDS)); + + if(demuxfd_count == 0) { + printf("No pids!\n"); + return 0; + } + + buf = (unsigned char *) malloc(IN_SIZE); + if (buf == NULL) { + perror("malloc"); + return 0; + } + + cDemux * dmx = new cDemux(1); + + dmx->Open(DMX_TP_CHANNEL, NULL, DMX_BUFFER_SIZE); + + dmx->pesFilter(pids[0]); + for(int i = 1; i < demuxfd_count; i++) + dmx->addPid(pids[i]); + + dmx->Start(); + + if(channel) + cam0->setCaPmt(channel->getCaPmt(), 0, 3, true); // demux 0 + 1, update + + size_t pos; + ssize_t r; + ssize_t todo; + int offset; + + while (!exit_flag) { + todo = IN_SIZE; + pos = 0; + + while ((!exit_flag) && (todo)) { + r = dmx->Read(buf+pos, todo, 100); + if (r > 0) { +//printf("Read: %d\n", r); + pos += r; + todo -= r; + } else + usleep(1000); + } + if(!exit_flag) { + //packet_stdout(fd, buf, IN_SIZE, NULL); + /* make sure to start with a ts header */ + offset = sync_byte_offset(buf, IN_SIZE); + + if (offset == -1) + continue; + + packet_stdout(fd, buf + offset, IN_SIZE - offset, NULL); + } + } + + printf("Exiting LIVE STREAM thread, fd %d\n", fd); + if(channel) + cam0->setCaPmt(channel->getCaPmt(), 0, 1, true); // demux 0, update + + delete dmx; + free(buf); + close(fd); + return 0; +} + +void streamts_file_thread(void *data) +{ + int dvrfd; + unsigned char * buf; + char cbuf[512]; + char *bp; + unsigned char mode = 0; + char tsfile[IN_SIZE]; + int tsfilelen = 0; + int fileslice = 0; + int i = 0; + int fd = (int) data; + + buf = (unsigned char *) malloc(IN_SIZE); + + if (buf == NULL) { + perror("malloc"); + return; + } + + bp = &cbuf[0]; + + /* read one line */ + while (bp - &cbuf[0] < IN_SIZE) { + unsigned char c; + read(fd, &c, 1); + if ((*bp++ = c) == '\n') + break; + } + + *bp++ = 0; + bp = &cbuf[0]; + + /* send response to http client */ + if (!strncmp(cbuf, "GET /", 5)) { + printf("HTTP/1.1 200 OK\r\nServer: streamts (%s)\r\n\r\n", "ts" /*&argv[1][1]*/); + fflush(stdout); + bp += 5; + } + + /* ts filename */ + int j = 0; + i = 0; + while (i < (int) strlen(bp) - 3) + { + if ((bp[i] == '.') && (bp[i + 1] == 't') && (bp[i + 2] == 's')) + { + tsfile[j] = bp[i]; + tsfile[j + 1] = bp[i + 1]; + tsfile[j + 2] = bp[i + 2]; + tsfile[j + 3] = '\0'; + break; + } + else + if ((bp[i] == '%') && (bp[i + 1] == '2') && (bp[i + 2] == '0')) + { + tsfile[j++] = ' '; + i += 3; + } + else + tsfile[j++] = bp[i++]; + } + tsfilelen = strlen(tsfile); + /* open ts file */ + if ((dvrfd = open(tsfile, O_RDONLY)) < 0) { + free(buf); + return; + } + + size_t pos; + ssize_t r; + + while (!exit_flag) { + /* always read IN_SIZE bytes */ + for (pos = 0; pos < IN_SIZE; pos += r) { + r = read(dvrfd, buf + pos, IN_SIZE - pos); + if (r == -1) { + /* Error */ + exit_flag = 1; + break; + } else if (r == 0) { + /* End of file */ + if (mode == 3) { + close(dvrfd); + sprintf(&tsfile[tsfilelen], ".%03d", ++fileslice); + dvrfd = open(tsfile, O_RDONLY); + } + if ((dvrfd == -1) || (mode != 3)) { + exit_flag = 1; + break; + } + } + } + packet_stdout(fd, buf, pos, NULL); + } + close(dvrfd); + free(buf); + + return; +} diff --git a/src/driver/vcrcontrol.cpp b/src/driver/vcrcontrol.cpp new file mode 100644 index 000000000..e9223bae7 --- /dev/null +++ b/src/driver/vcrcontrol.cpp @@ -0,0 +1,941 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ +int was_record = 0; +extern bool autoshift; +extern bool autoshift_delete; + +#define SA struct sockaddr +#define SAI struct sockaddr_in +extern "C" { +#include +} +CMovieInfo * g_cMovieInfo; +MI_MOVIE_INFO * g_movieInfo; +t_channel_id rec_channel_id; +int safe_mkdir(char * path); + +static CVCRControl vcrControl; + +CVCRControl * CVCRControl::getInstance() +{ + return &vcrControl; +} + +//------------------------------------------------------------------------- +CVCRControl::CVCRControl() +{ + Device = NULL; +} + +//------------------------------------------------------------------------- +CVCRControl::~CVCRControl() +{ + unregisterDevice(); +} + +//------------------------------------------------------------------------- +void CVCRControl::unregisterDevice() +{ + if (Device) + { + delete Device; + Device = NULL; + } +} + +//------------------------------------------------------------------------- +void CVCRControl::registerDevice(CDevice * const device) +{ + unregisterDevice(); + + Device = device; +} + +//------------------------------------------------------------------------- +bool CVCRControl::Record(const CTimerd::RecordingInfo * const eventinfo) +{ + int mode = g_Zapit->isChannelTVChannel(eventinfo->channel_id) ? NeutrinoMessages::mode_tv : NeutrinoMessages::mode_radio; + + return Device->Record(eventinfo->channel_id, mode, eventinfo->epgID, eventinfo->epgTitle, eventinfo->apids, eventinfo->epg_starttime); +} + +//------------------------------------------------------------------------- +void CVCRControl::CDevice::getAPIDs(const unsigned char ap, APIDList & apid_list) +{ +// (strstr(g_RemoteControl->current_PIDs.APIDs[i].desc, "(AC3)") == NULL)) + unsigned char apids=ap; + if (apids == TIMERD_APIDS_CONF) + apids = g_settings.recording_audio_pids_default; + apid_list.clear(); + CZapitClient::responseGetPIDs allpids; + g_Zapit->getPIDS(allpids); + // assume smallest apid ist std apid + if (apids & TIMERD_APIDS_STD) + { + uint32_t apid_min=UINT_MAX; + uint32_t apid_min_idx=0; + for(unsigned int i = 0; i < allpids.APIDs.size(); i++) + { + if (allpids.APIDs[i].pid < apid_min && !allpids.APIDs[i].is_ac3) + { + apid_min = allpids.APIDs[i].pid; + apid_min_idx = i; + } + } + if (apid_min != UINT_MAX) + { + APIDDesc a = {apid_min, apid_min_idx, false}; + apid_list.push_back(a); + } + } + if (apids & TIMERD_APIDS_ALT) + { + uint32_t apid_min=UINT_MAX; + uint32_t apid_min_idx=0; + for(unsigned int i = 0; i < allpids.APIDs.size(); i++) + { + if (allpids.APIDs[i].pid < apid_min && !allpids.APIDs[i].is_ac3) + { + apid_min = allpids.APIDs[i].pid; + apid_min_idx = i; + } + } + for(unsigned int i = 0; i < allpids.APIDs.size(); i++) + { + if (allpids.APIDs[i].pid != apid_min && !allpids.APIDs[i].is_ac3) + { + APIDDesc a = {allpids.APIDs[i].pid, i, false}; + apid_list.push_back(a); + } + } + } + if (apids & TIMERD_APIDS_AC3) + { + bool ac3_found=false; + for(unsigned int i = 0; i < allpids.APIDs.size(); i++) + { + if (allpids.APIDs[i].is_ac3) + { + APIDDesc a = {allpids.APIDs[i].pid, i, true}; + apid_list.push_back(a); + ac3_found=true; + } + } + // add non ac3 apid if ac3 not found + if (!(apids & TIMERD_APIDS_STD) && !ac3_found) + { + uint32_t apid_min=UINT_MAX; + uint32_t apid_min_idx=0; + for(unsigned int i = 0; i < allpids.APIDs.size(); i++) + { + if (allpids.APIDs[i].pid < apid_min && !allpids.APIDs[i].is_ac3) + { + apid_min = allpids.APIDs[i].pid; + apid_min_idx = i; + } + } + if (apid_min != UINT_MAX) + { + APIDDesc a = {apid_min, apid_min_idx, false}; + apid_list.push_back(a); + } + } + } + // no apid selected use standard + if (apid_list.empty() && !allpids.APIDs.empty()) + { + uint32_t apid_min=UINT_MAX; + uint32_t apid_min_idx=0; + for(unsigned int i = 0; i < allpids.APIDs.size(); i++) + { + if (allpids.APIDs[i].pid < apid_min && !allpids.APIDs[i].is_ac3) + { + apid_min = allpids.APIDs[i].pid; + apid_min_idx = i; + } + } + if (apid_min != UINT_MAX) + { + APIDDesc a = {apid_min, apid_min_idx, false}; + apid_list.push_back(a); + } + for(APIDList::iterator it = apid_list.begin(); it != apid_list.end(); it++) + printf("Record APID 0x%X %d\n",it->apid, it->ac3); + + } +} + +//------------------------------------------------------------------------- +bool CVCRControl::CVCRDevice::Stop() +{ + deviceState = CMD_VCR_STOP; + + if(last_mode != NeutrinoMessages::mode_scart) + { + g_RCInput->postMsg( NeutrinoMessages::VCR_OFF, 0 ); + g_RCInput->postMsg( NeutrinoMessages::CHANGEMODE , last_mode); + } + return true; +} + +//------------------------------------------------------------------------- +bool CVCRControl::CVCRDevice::Record(const t_channel_id channel_id, int mode, const event_id_t epgid, const std::string& epgTitle, unsigned char apids, const time_t epg_time) +{ + printf("Record channel_id: " PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS " epg: %llx, apids 0x%X mode \n", + channel_id, epgid, apids); + // leave menu (if in any) + g_RCInput->postMsg( CRCInput::RC_timeout, 0 ); + + last_mode = CNeutrinoApp::getInstance()->getMode(); + if(mode != last_mode) { + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , mode | NeutrinoMessages::norezap ); + } + + if(channel_id != 0) // wenn ein channel angegeben ist + { + if(g_Zapit->getCurrentServiceID() != channel_id) // und momentan noch nicht getuned ist + { + g_Zapit->zapTo_serviceID(channel_id); // dann umschalten + } + } + if(! (apids & TIMERD_APIDS_STD)) // nicht std apid + { + APIDList apid_list; + getAPIDs(apids,apid_list); + if(!apid_list.empty()) + { + if(!apid_list.begin()->ac3) + g_Zapit->setAudioChannel(apid_list.begin()->index); + else + g_Zapit->setAudioChannel(0); //sonst apid 0, also auf jeden fall ac3 aus ! + } + else + g_Zapit->setAudioChannel(0); //sonst apid 0, also auf jeden fall ac3 aus ! + } + else + g_Zapit->setAudioChannel(0); //sonst apid 0, also auf jeden fall ac3 aus ! + + if(SwitchToScart) + { + // Auf Scart schalten + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::VCR_ON, 0 ); + // Das ganze nochmal in die queue, da obiges RC_timeout erst in der naechsten ev. loop ausgeführt wird + // und dann das menu widget das display falsch rücksetzt + g_RCInput->postMsg( NeutrinoMessages::VCR_ON, 0 ); + } + + deviceState = CMD_VCR_RECORD; + // Send IR + return true; +} + +//------------------------------------------------------------------------- +bool CVCRControl::CVCRDevice::Pause() +{ + return true; +} + +//------------------------------------------------------------------------- +bool CVCRControl::CVCRDevice::Resume() +{ + return true; +} + +//------------------------------------------------------------------------- +void CVCRControl::CFileAndServerDevice::RestoreNeutrino(void) +{ +//printf("RestoreNeutrino\n");fflush(stdout); + /* after this zapit send EVT_RECORDMODE_DEACTIVATED, so neutrino getting NeutrinoMessages::EVT_RECORDMODE */ + g_Zapit->setRecordMode( false ); + if (!g_Zapit->isPlayBackActive() && (CNeutrinoApp::getInstance()->getMode() != NeutrinoMessages::mode_standby)) + g_Zapit->startPlayBack(); + // alten mode wieder herstellen (ausser wen zwischenzeitlich auf oder aus sb geschalten wurde) + if(CNeutrinoApp::getInstance()->getMode() != last_mode && + CNeutrinoApp::getInstance()->getMode() != NeutrinoMessages::mode_standby && + last_mode != NeutrinoMessages::mode_standby) + if(!autoshift) g_RCInput->postMsg( NeutrinoMessages::CHANGEMODE , last_mode); + + if(last_mode == NeutrinoMessages::mode_standby && + CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_standby ) + { + //Wenn vorher und jetzt standby, dann die zapit wieder auf sb schalten + //g_Zapit->setStandby(true); + //was_record = 1; + } + if((last_mode != NeutrinoMessages::mode_standby) && StopSectionsd) + g_Sectionsd->setPauseScanning(false); +} + +void CVCRControl::CFileAndServerDevice::CutBackNeutrino(const t_channel_id channel_id, const int mode) +{ + rec_channel_id = channel_id; +//printf("CutBackNeutrino\n");fflush(stdout); + g_Zapit->setStandby(false); + last_mode = CNeutrinoApp::getInstance()->getMode(); + if(last_mode == NeutrinoMessages::mode_standby) + was_record = 1; + if (channel_id != 0) { + if (mode != last_mode && (last_mode != NeutrinoMessages::mode_standby || mode != CNeutrinoApp::getInstance()->getLastMode())) { + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , mode | NeutrinoMessages::norezap ); + // Wenn wir im Standby waren, dann brauchen wir fürs streamen nicht aufwachen... + if(last_mode == NeutrinoMessages::mode_standby) + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , NeutrinoMessages::mode_standby); + } + if(g_Zapit->getCurrentServiceID() != channel_id) { + g_Zapit->zapTo_serviceID(channel_id); + } + } + if(StopSectionsd) // wenn sectionsd gestoppt werden soll + g_Sectionsd->setPauseScanning(true); // sectionsd stoppen + + /* after this zapit send EVT_RECORDMODE_ACTIVATED, so neutrino getting NeutrinoMessages::EVT_RECORDMODE */ + g_Zapit->setRecordMode( true ); + if((last_mode == NeutrinoMessages::mode_standby) || (StopPlayBack && g_Zapit->isPlayBackActive())) + g_Zapit->stopPlayBack(); +} + +bool sectionsd_getEPGidShort(event_id_t epgID, CShortEPGData * epgdata); +bool sectionsd_getEPGid(const event_id_t epgID, const time_t startzeit, CEPGData * epgdata); + +std::string CVCRControl::CFileAndServerDevice::getCommandString(const CVCRCommand command, const t_channel_id channel_id, const event_id_t epgid, const std::string& epgTitle, unsigned char apids) +{ + char tmp[40]; + std::string apids_selected; + const char * extCommand; + std::string info1, info2; + + std::string extMessage = "\n\n\n\t\n" + "\t\t"; + + CZapitClient::responseGetPIDs pids; + g_Zapit->getPIDS (pids); + CZapitClient::CCurrentServiceInfo si = g_Zapit->getCurrentServiceInfo (); + + APIDList apid_list; + getAPIDs(apids,apid_list); + apids_selected=""; + for(APIDList::iterator it = apid_list.begin(); it != apid_list.end(); it++) + { + if(it != apid_list.begin()) + apids_selected += " "; + sprintf(tmp, "%u", it->apid); + apids_selected += tmp; + } + + std::string tmpstring = g_Zapit->getChannelName(channel_id); + if (tmpstring.empty()) + extMessage += "unknown"; + else + extMessage += ZapitTools::UTF8_to_UTF8XML(tmpstring.c_str()); + + extMessage += "\n\t\t"; + + tmpstring = "not available"; + if (epgid != 0) + { + CShortEPGData epgdata; + //if (g_Sectionsd->getEPGidShort(epgid, &epgdata)) { + if(sectionsd_getEPGidShort(epgid, &epgdata)) { +//#warning fixme sectionsd should deliver data in UTF-8 format + tmpstring = epgdata.title; + info1 = epgdata.info1; + info2 = epgdata.info2; + } + } else if (!epgTitle.empty()) { + tmpstring = epgTitle; + } + extMessage += ZapitTools::UTF8_to_UTF8XML(tmpstring.c_str()); + + extMessage += "\n\t\t"; + + sprintf(tmp, PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS, channel_id); + extMessage += tmp; + + extMessage += "\n\t\t"; + extMessage += ZapitTools::UTF8_to_UTF8XML(info1.c_str()); + extMessage += "\n\t\t"; + extMessage += ZapitTools::UTF8_to_UTF8XML(info2.c_str()); + extMessage += "\n\t\t"; + sprintf(tmp, "%llu", epgid); + extMessage += tmp; + extMessage += "\n\t\t"; + sprintf(tmp, "%d", g_Zapit->getMode()); + extMessage += tmp; + extMessage += "\n\t\t"; + sprintf(tmp, "%u", si.vpid); + extMessage += tmp; + extMessage += "\n\t\t\n"; + // super hack :-), der einfachste weg an die apid descriptions ranzukommen + g_RemoteControl->current_PIDs = pids; + g_RemoteControl->processAPIDnames(); + + for(unsigned int i= 0; i< pids.APIDs.size(); i++) + { + extMessage += "\t\t\t\n" + "\t\t"; + sprintf(tmp, "%u", si.vtxtpid); + extMessage += tmp; + extMessage += + "\n" + "\t\n" + "\n"; + + return extMessage; +} + +bool CVCRControl::CFileDevice::Stop() +{ + std::string extMessage = " "; + time_t end_time = time(0); +//printf("[direct] Stop recording, g_movieInfo %lx\n", g_movieInfo); fflush(stdout); +//FIXME why not save info if shift ? + //if(!autoshift || autoshift_delete) + { + // g_movieInfo->length = (end_time - start_time) / 60; + g_movieInfo->length = (int) round((double) (end_time - start_time) / (double) 60); +//printf("[direct] stop recording 1\n"); fflush(stdout); + g_cMovieInfo->encodeMovieInfoXml(&extMessage, g_movieInfo); +//printf("[direct] stop recording 2\n"); fflush(stdout); + } + bool return_value = (::stop_recording(extMessage.c_str()) == STREAM2FILE_OK); +//printf("[direct] stop recording 3\n"); fflush(stdout); + + RestoreNeutrino(); + + deviceState = CMD_VCR_STOP; + + g_movieInfo->audioPids.clear(); + delete g_movieInfo; + g_movieInfo = NULL; + delete g_cMovieInfo; + g_cMovieInfo = NULL; + + return return_value; +} + +std::string ext_channel_name; +bool CVCRControl::CFileDevice::Record(const t_channel_id channel_id, int mode, const event_id_t epgid, const std::string& epgTitle, unsigned char apids, const time_t epg_time) +{ +printf("Record channel_id: " PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS " epg: %llx, apids 0x%X mode %d\n", + channel_id, epgid, apids, mode); + + CutBackNeutrino(channel_id, mode); + +#define MAXPIDS 64 + unsigned short pids[MAXPIDS]; + unsigned int numpids; + unsigned int pos; + + CZapitClient::CCurrentServiceInfo si = g_Zapit->getCurrentServiceInfo(); + numpids = 0; + + if (si.vpid != 0) + transfer_pids(si.vpid, si.vtype ? EN_TYPE_AVC : EN_TYPE_VIDEO, 0); + + APIDList apid_list; + getAPIDs(apids,apid_list); + for(APIDList::iterator it = apid_list.begin(); it != apid_list.end(); it++) { + pids[numpids++] = it->apid; + transfer_pids(it->apid, EN_TYPE_AUDIO, it->ac3 ? 1 : 0); + } +#if 0 // FIXME : why this needed ? + if(!apid_list.empty()) + g_Zapit->setAudioChannel(apid_list.begin()->index); +#endif + CZapitClient::responseGetPIDs allpids; + g_Zapit->getPIDS(allpids); + + if ((StreamVTxtPid) && (si.vtxtpid != 0)) { + pids[numpids++] = si.vtxtpid; + } + if ((StreamPmtPid) && (si.pmtpid != 0)) { + pids[numpids++] = si.pmtpid; + } + char filename[512]; // UTF-8 + + // Create filename for recording + pos = Directory.size(); + strcpy(filename, Directory.c_str()); + + if ((pos == 0) || (filename[pos - 1] != '/')) { + filename[pos] = '/'; + pos++; + filename[pos] = '\0'; + } + pos = strlen(filename); +#if 0 + time_t t = time(NULL); + strftime(&(filename[pos]), sizeof(filename) - pos - 1, "%Y%m%d_%H%M%S", localtime(&t)); + strcat(filename, "_"); + pos = strlen(filename); +#endif + ext_channel_name = g_Zapit->getChannelName(channel_id); + if (!(ext_channel_name.empty())) + { + strcpy(&(filename[pos]), UTF8_TO_FILESYSTEM_ENCODING(ext_channel_name.c_str())); + char * p_act = &(filename[pos]); + do { + p_act += strcspn(p_act, "/ \"%&-\t`'´!,:;"); + if (*p_act) { + *p_act++ = '_'; + } + } while (*p_act); + if (!autoshift && g_settings.recording_save_in_channeldir) { + struct stat statInfo; + int res = stat(filename,&statInfo); + if (res == -1) { + if (errno == ENOENT) { + //res = mkdir(filename,0755); + res = safe_mkdir(filename); + if (res == 0) { + strcat(filename,"/"); + } else { + perror("[vcrcontrol] mkdir"); + } + + } else { + perror("[vcrcontrol] stat"); + } + } else { + // directory exists + strcat(filename,"/"); + } + + } else + strcat(filename, "_"); + } + + pos = strlen(filename); + if (g_settings.recording_epg_for_filename) { + if(epgid != 0) { + CShortEPGData epgdata; + //if (g_Sectionsd->getEPGidShort(epgid, &epgdata)) + if(sectionsd_getEPGidShort(epgid, &epgdata)) + { + if (!(epgdata.title.empty())) + { + strcpy(&(filename[pos]), epgdata.title.c_str()); + char * p_act = &(filename[pos]); + do { + p_act += strcspn(p_act, "/ \"%&-\t`'~<>!,:;?^°$\\=*#@¤|"); + if (*p_act) { + *p_act++ = '_'; + } + } while (*p_act); + } + } + } else if (!epgTitle.empty()) { + strcpy(&(filename[pos]), epgTitle.c_str()); + char * p_act = &(filename[pos]); + do { + p_act += strcspn(p_act, "/ \"%&-\t`'~<>!,:;?^°$\\=*#@¤|"); + if (*p_act) { + *p_act++ = '_'; + } + } while (*p_act); + } + } +#if 1 + pos = strlen(filename); + time_t t = time(NULL); + strftime(&(filename[pos]), sizeof(filename) - pos - 1, "%Y%m%d_%H%M%S", localtime(&t)); + //pos = strlen(filename); +#endif + + start_time = time(0); + stream2file_error_msg_t error_msg = ::start_recording(filename, + getMovieInfoString(CMD_VCR_RECORD, channel_id, epgid, epgTitle, apid_list, epg_time).c_str(), + si.vpid, pids, numpids); + + if (error_msg == STREAM2FILE_OK) { + deviceState = CMD_VCR_RECORD; + return true; + } + else { + RestoreNeutrino(); + + printf("[vcrcontrol] stream2file error code: %d\n", error_msg); +#warning FIXME: Use better error message + DisplayErrorMessage(g_Locale->getText( + error_msg == STREAM2FILE_BUSY ? LOCALE_STREAMING_BUSY : + error_msg == STREAM2FILE_INVALID_DIRECTORY ? LOCALE_STREAMING_DIR_NOT_WRITABLE : + LOCALE_STREAMINGSERVER_NOCONNECT + )); // UTF-8 + + return false; + } +} + +bool sectionsd_getActualEPGServiceKey(const t_channel_id uniqueServiceKey, CEPGData * epgdata); + +void CVCRControl::Screenshot(const t_channel_id channel_id, char * fname) +{ + char filename[512]; // UTF-8 + char cmd[512]; + std::string channel_name; + CEPGData epgData; + event_id_t epgid = 0; + unsigned int pos; + + if(!fname) { + if(safe_mkdir((char *) "/hdd/screenshots/")) + return; + + strcpy(filename, "/hdd/screenshots/"); + + pos = strlen(filename); + channel_name = g_Zapit->getChannelName(channel_id); + if (!(channel_name.empty())) { + strcpy(&(filename[pos]), UTF8_TO_FILESYSTEM_ENCODING(channel_name.c_str())); + char * p_act = &(filename[pos]); + do { + p_act += strcspn(p_act, "/ \"%&-\t`'´!,:;"); + if (*p_act) { + *p_act++ = '_'; + } + } while (*p_act); + strcat(filename, "_"); + } + pos = strlen(filename); + + //if (g_Sectionsd->getActualEPGServiceKey(channel_id&0xFFFFFFFFFFFFULL, &epgData)) + if(sectionsd_getActualEPGServiceKey(channel_id&0xFFFFFFFFFFFFULL, &epgData)); + epgid = epgData.eventID; + if(epgid != 0) { + CShortEPGData epgdata; + //if (g_Sectionsd->getEPGidShort(epgid, &epgdata)) { + if(sectionsd_getEPGidShort(epgid, &epgdata)) { + if (!(epgdata.title.empty())) { + strcpy(&(filename[pos]), epgdata.title.c_str()); + char * p_act = &(filename[pos]); + do { + p_act += strcspn(p_act, "/ \"%&-\t`'~<>!,:;?^°$\\=*#@¤|"); + if (*p_act) { + *p_act++ = '_'; + } + } while (*p_act); + } + } + } + pos = strlen(filename); + time_t t = time(NULL); + strftime(&(filename[pos]), sizeof(filename) - pos - 1, "%Y%m%d_%H%M%S", localtime(&t)); + strcat(filename, ".bmp"); + } else + strcpy(filename, fname); + + sprintf(cmd, "grab -v %s", filename); +printf("Executing %s\n", cmd); + CHintBox * hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, "Saving screenshot.."); + hintBox->paint(); + system(cmd); + hintBox->hide(); + delete hintBox; +} + +//------------------------------------------------------------------------- +bool CVCRControl::CServerDevice::Stop() +{ + printf("Stop\n"); + + bool return_value = sendCommand(CMD_VCR_STOP); + RestoreNeutrino(); + + return return_value; +} + +//------------------------------------------------------------------------- +bool CVCRControl::CServerDevice::Record(const t_channel_id channel_id, int mode, const event_id_t epgid, const std::string& epgTitle, unsigned char apids, const time_t epg_time) +{ + printf("Record channel_id: " + PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS + " epg: %llx, apids 0x%X mode %d\n", + channel_id, + epgid, + apids, + mode); + + CutBackNeutrino(channel_id, mode); + if(!sendCommand(CMD_VCR_RECORD, channel_id, epgid, epgTitle, apids)) + { + RestoreNeutrino(); + + DisplayErrorMessage(g_Locale->getText(LOCALE_STREAMINGSERVER_NOCONNECT)); + + return false; + } + else { + ext_channel_name = g_Zapit->getChannelName(channel_id); + return true; + } +} + + +//------------------------------------------------------------------------- +void CVCRControl::CServerDevice::serverDisconnect() +{ + close(sock_fd); +} + +//------------------------------------------------------------------------- +bool CVCRControl::CServerDevice::sendCommand(CVCRCommand command, const t_channel_id channel_id, const event_id_t epgid, const std::string& epgTitle, unsigned char apids) +{ + printf("Send command: %d channel_id: " + PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS + " epgid: %llx\n", + command, + channel_id, + epgid); + if(serverConnect()) + { + std::string extMessage = getCommandString(command, channel_id, epgid, epgTitle, apids); + + printf("sending to vcr-client:\n\n%s\n", extMessage.c_str()); + write(sock_fd, extMessage.c_str() , extMessage.length() ); + + serverDisconnect(); + + deviceState = command; + return true; + } + else + return false; + +} + +//------------------------------------------------------------------------- +bool CVCRControl::CServerDevice::serverConnect() +{ + + printf("connect to server: %s:%d\n",ServerAddress.c_str(),ServerPort); + + sock_fd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + SAI servaddr; + memset(&servaddr,0,sizeof(SAI)); + servaddr.sin_family=AF_INET; + servaddr.sin_port=htons(ServerPort); + inet_pton(AF_INET, ServerAddress.c_str(), &servaddr.sin_addr); + + + if(connect(sock_fd, (SA *)&servaddr, sizeof(servaddr))==-1) + { + perror("[cvcr] - cannot connect to streamingserver\n"); + return false; + } + + return true; +} + +extern unsigned short g_vpid; +extern unsigned short g_vtype; +extern unsigned short g_apids[10]; +extern unsigned short g_ac3flags[10]; +extern unsigned short g_numpida; +extern unsigned int g_currentapid, g_currentac3; + +//------------------------------------------------------------------------- +std::string CVCRControl::CFileAndServerDevice::getMovieInfoString(const CVCRCommand command, const t_channel_id channel_id, const event_id_t epgid, const std::string& epgTitle, APIDList apid_list, const time_t epg_time) +{ + std::string extMessage; + std::string apids10; + std::string info1, info2; + if(!g_cMovieInfo) + g_cMovieInfo = new CMovieInfo(); + if(!g_movieInfo) + g_movieInfo = new MI_MOVIE_INFO(); + + g_cMovieInfo->clearMovieInfo(g_movieInfo); + + CZapitClient::responseGetPIDs pids; + g_Zapit->getPIDS (pids); + CZapitClient::CCurrentServiceInfo si = g_Zapit->getCurrentServiceInfo (); + + std::string tmpstring = g_Zapit->getChannelName(channel_id); + if (tmpstring.empty()) + g_movieInfo->epgChannel = "unknown"; + else + g_movieInfo->epgChannel = ZapitTools::UTF8_to_UTF8XML(tmpstring.c_str()); + + tmpstring = "not available"; + if (epgid != 0) { + CEPGData epgdata; + //if (g_Sectionsd->getEPGid(epgid, epg_time, &epgdata)) { + if (sectionsd_getEPGid(epgid, epg_time, &epgdata)) { + tmpstring = epgdata.title; + info1 = epgdata.info1; + info2 = epgdata.info2; + + g_movieInfo->parentalLockAge = epgdata.fsk; + if(epgdata.contentClassification.size() > 0 ) + g_movieInfo->genreMajor = epgdata.contentClassification[0]; + + g_movieInfo->length = epgdata.epg_times.dauer / 60; + + printf("fsk:%d, Genre:%d, Dauer: %d\r\n",g_movieInfo->parentalLockAge,g_movieInfo->genreMajor,g_movieInfo->length); + } + } else if (!epgTitle.empty()) { + tmpstring = epgTitle; + } + g_movieInfo->epgTitle = ZapitTools::UTF8_to_UTF8XML(tmpstring.c_str()); + g_movieInfo->epgId = channel_id; + g_movieInfo->epgInfo1 = ZapitTools::UTF8_to_UTF8XML(info1.c_str()); + g_movieInfo->epgInfo2 = ZapitTools::UTF8_to_UTF8XML(info2.c_str()); + g_movieInfo->epgEpgId = epgid ; + g_movieInfo->epgMode = g_Zapit->getMode(); + g_movieInfo->epgVideoPid = si.vpid; + g_movieInfo->VideoType = si.vtype; + + g_vpid = si.vpid; + g_vtype = si.vtype; + g_currentapid = si.apid; + memset(g_apids, 0, sizeof(unsigned short)*10); + memset(g_ac3flags, 0, sizeof(unsigned short)*10); + g_numpida = 0; + + EPG_AUDIO_PIDS audio_pids; + // super hack :-), der einfachste weg an die apid descriptions ranzukommen + g_RemoteControl->current_PIDs = pids; + g_RemoteControl->processAPIDnames(); + + APIDList::iterator it; + for(unsigned int i= 0; i< pids.APIDs.size(); i++) { + for(it = apid_list.begin(); it != apid_list.end(); it++) { + if(pids.APIDs[i].pid == it->apid) { + audio_pids.epgAudioPid = pids.APIDs[i].pid; + audio_pids.epgAudioPidName = ZapitTools::UTF8_to_UTF8XML(g_RemoteControl->current_PIDs.APIDs[i].desc); + audio_pids.atype = pids.APIDs[i].is_ac3; + audio_pids.selected = (audio_pids.epgAudioPid == (int) g_currentapid) ? 1 : 0; + g_movieInfo->audioPids.push_back(audio_pids); + + if(pids.APIDs[i].is_ac3) + g_ac3flags[i] = 1; + + g_apids[i] = pids.APIDs[i].pid; + if(g_apids[i] == g_currentapid) + g_currentac3 = pids.APIDs[i].is_ac3; + g_numpida++; + } + } + } + //FIXME sometimes no apid in xml ?? + if(g_movieInfo->audioPids.empty() && pids.APIDs.size()) { + int i = 0; + audio_pids.epgAudioPid = pids.APIDs[i].pid; + audio_pids.epgAudioPidName = ZapitTools::UTF8_to_UTF8XML(g_RemoteControl->current_PIDs.APIDs[i].desc); + audio_pids.atype = pids.APIDs[i].is_ac3; + audio_pids.selected = 1; + g_movieInfo->audioPids.push_back(audio_pids); + } + g_movieInfo->epgVTXPID = si.vtxtpid; + + g_cMovieInfo->encodeMovieInfoXml(&extMessage, g_movieInfo); + + //g_movieInfo->audioPids.clear(); + + return extMessage; +} diff --git a/src/driver/vcrcontrol.h b/src/driver/vcrcontrol.h new file mode 100644 index 000000000..8b219f70c --- /dev/null +++ b/src/driver/vcrcontrol.h @@ -0,0 +1,221 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifndef __vcrcontrol__ +#define __vcrcontrol__ + +#include +//#include +#include + +#include +#include + +#include + + +class CVCRControl +{ + public: + typedef enum CVCRStates + { + CMD_VCR_UNKNOWN = 0, + CMD_VCR_RECORD = 1, + CMD_VCR_STOP = 2, + CMD_VCR_PAUSE = 3, + CMD_VCR_RESUME = 4, + CMD_VCR_AVAILABLE = 5 + } CVCRCommand; + + enum CVCRDevices + { + DEVICE_VCR, + DEVICE_SERVER, + DEVICE_FILE + }; + + class CDevice // basisklasse für die devices + { + public: + int sock_fd; + int last_mode; + time_t start_time; + virtual CVCRDevices getDeviceType(void) const = 0; + CVCRStates deviceState; + virtual bool Stop() = 0; + virtual bool Record(const t_channel_id channel_id = 0, int mode=1, const event_id_t epgid = 0, const std::string& epgTitle = "", unsigned char apids = 0, const time_t epg_time=0) = 0; // epg_time added for .xml (MovieBrowser) + virtual bool Pause() = 0; + virtual bool Resume() = 0; + virtual bool IsAvailable() = 0; + CDevice() { deviceState = CMD_VCR_STOP; }; + virtual ~CDevice(){}; + typedef struct { + unsigned short apid; + unsigned int index; + bool ac3; + } APIDDesc; + typedef std::list APIDList; + virtual void getAPIDs(const unsigned char apids, APIDList & apid_list); + }; + + class CVCRDevice : public CDevice // VCR per IR + { + public: + bool SwitchToScart; + + virtual CVCRDevices getDeviceType(void) const + { + return DEVICE_VCR; + }; + virtual bool Stop(); + virtual bool Record(const t_channel_id channel_id = 0, int mode=1, const event_id_t epgid = 0, const std::string& epgTitle = "", unsigned char apids = 0, const time_t epg_time=0); // epg_time added for .xml (MovieBrowser) + virtual bool Pause(); + virtual bool Resume(); + virtual bool IsAvailable() { return true; }; + CVCRDevice(bool switchtoscart) { SwitchToScart = switchtoscart; }; + virtual ~CVCRDevice(){}; + }; + + class CFileAndServerDevice : public CDevice + { + protected: + void RestoreNeutrino(void); + void CutBackNeutrino(const t_channel_id channel_id, const int mode); + std::string getCommandString(const CVCRCommand command, const t_channel_id channel_id, const event_id_t epgid, const std::string& epgTitle, unsigned char apids); + std::string getMovieInfoString(const CVCRCommand command, const t_channel_id channel_id,const event_id_t epgid, const std::string& epgTitle, APIDList apid_list, const time_t epg_time); + + public: + bool StopPlayBack; + bool StopSectionsd; + + virtual bool Pause() + { + return false; + }; + + virtual bool Resume() + { + return false; + }; + + virtual bool IsAvailable() + { + return true; + }; + }; + + class CFileDevice : public CFileAndServerDevice + { + public: + std::string Directory; + unsigned int SplitSize; + bool Use_O_Sync; + bool Use_Fdatasync; + bool StreamVTxtPid; + bool StreamPmtPid; + unsigned int RingBuffers; + + virtual CVCRDevices getDeviceType(void) const + { + return DEVICE_FILE; + }; + + virtual bool Stop(); + virtual bool Record(const t_channel_id channel_id = 0, int mode=1, const event_id_t epgid = 0, const std::string& epgTitle = "", unsigned char apids = 0, const time_t epg_time=0); // epg_time added for .xml (MovieBrowser) + + CFileDevice(const bool stopplayback, const bool stopsectionsd, const char * const directory, const unsigned int splitsize, const bool use_o_sync, const bool use_fdatasync, const bool stream_vtxt_pid, const bool stream_pmt_pid, const unsigned int ringbuffers) + { + StopPlayBack = stopplayback; + StopSectionsd = stopsectionsd; + Directory = directory; + SplitSize = splitsize; + Use_O_Sync = use_o_sync; + Use_Fdatasync = use_fdatasync; + StreamVTxtPid = stream_vtxt_pid; + StreamPmtPid = stream_pmt_pid; + RingBuffers = ringbuffers; + }; + virtual ~CFileDevice() + { + }; + }; + + class CServerDevice : public CFileAndServerDevice // externer Streamingserver per tcp + { + private: + bool serverConnect(); + void serverDisconnect(); + + bool sendCommand(CVCRCommand command, const t_channel_id channel_id = 0, const event_id_t epgid = 0, const std::string& epgTitle = "", unsigned char apids = 0); + + public: + std::string ServerAddress; + unsigned int ServerPort; + + virtual CVCRDevices getDeviceType(void) const + { + return DEVICE_SERVER; + }; + + virtual bool Stop(); + virtual bool Record(const t_channel_id channel_id = 0, int mode=1, const event_id_t epgid = 0, const std::string& epgTitle = "", unsigned char apids = 0, const time_t epg_time=0); // epg_time added for .xml (MovieBrowser) + + CServerDevice(const bool stopplayback, const bool stopsectionsd, const char * const serveraddress, const unsigned int serverport) + { + StopPlayBack = stopplayback; + StopSectionsd = stopsectionsd; + ServerAddress = serveraddress; + ServerPort = serverport; + }; + virtual ~CServerDevice(){}; + }; + + public: + CVCRControl(); + ~CVCRControl(); + static CVCRControl * getInstance(); + + CDevice * Device; + + void registerDevice(CDevice * const device); + void unregisterDevice(); + + inline bool isDeviceRegistered(void) const { return (Device != NULL); }; + + inline CVCRStates getDeviceState(void) const { return Device->deviceState; }; + bool Stop(){return Device->Stop();}; + bool Record(const CTimerd::RecordingInfo * const eventinfo); + bool Pause(){return Device->Pause();}; + bool Resume(){return Device->Resume();}; + void Screenshot(const t_channel_id channel_id, char * fname = NULL); +}; + + +#endif diff --git a/src/driver/vfd.cpp b/src/driver/vfd.cpp new file mode 100644 index 000000000..7b73bf61e --- /dev/null +++ b/src/driver/vfd.cpp @@ -0,0 +1,899 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ + +CVFD::CVFD() +{ +#ifdef VFD_UPDATE + m_fileList = NULL; + m_fileListPos = 0; + m_fileListHeader = ""; + m_infoBoxText = ""; + m_infoBoxAutoNewline = 0; + m_progressShowEscape = 0; + m_progressHeaderGlobal = ""; + m_progressHeaderLocal = ""; + m_progressGlobal = 0; + m_progressLocal = 0; +#endif // VFD_UPDATE + + has_lcd = 1; + fd = open("/dev/display", O_RDONLY); + if(fd < 0) { + perror("/dev/display"); + has_lcd = 0; + } + text[0] = 0; + clearClock = 0; +} + +CVFD::~CVFD() +{ + if(fd > 0) + close(fd); +} + +CVFD* CVFD::getInstance() +{ + static CVFD* lcdd = NULL; + if(lcdd == NULL) { + lcdd = new CVFD(); + } + return lcdd; +} + +void CVFD::count_down() { + if (timeout_cnt > 0) { + timeout_cnt--; + if (timeout_cnt == 0) { + if (atoi(g_settings.lcd_setting_dim_brightness) > 0) { + // save lcd brightness, setBrightness() changes global setting + int b = g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS]; + setBrightness(atoi(g_settings.lcd_setting_dim_brightness)); + g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS] = b; + } else { + setPower(0); + } + } + } +} + +void CVFD::wake_up() { + if (atoi(g_settings.lcd_setting_dim_time) > 0) { + timeout_cnt = atoi(g_settings.lcd_setting_dim_time); + atoi(g_settings.lcd_setting_dim_brightness) > 0 ? + setBrightness(g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS]) : setPower(1); + } + else + setPower(1); +} + +void* CVFD::TimeThread(void *) +{ + while(1) { + sleep(1); + struct stat buf; + if (stat("/tmp/vfd.locked", &buf) == -1) { + CVFD::getInstance()->showTime(); + CVFD::getInstance()->count_down(); + } else + CVFD::getInstance()->wake_up(); + } + return NULL; +} + +void CVFD::init(const char * fontfile, const char * fontname) +{ + //InitNewClock(); /FIXME + + brightness = -1; + setMode(MODE_TVRADIO); + + if (pthread_create (&thrTime, NULL, TimeThread, NULL) != 0 ) { + perror("[lcdd]: pthread_create(TimeThread)"); + return ; + } +} + +void CVFD::setlcdparameter(int dimm, const int power) +{ + if(!has_lcd) return; + + if(dimm < 0) + dimm = 0; + else if(dimm > 15) + dimm = 15; + + if(!power) + dimm = 0; + + if(brightness == dimm) + return; + + brightness = dimm; + +printf("CVFD::setlcdparameter dimm %d power %d\n", dimm, power); + int ret = ioctl(fd, IOC_VFD_SET_BRIGHT, dimm); + if(ret < 0) + perror("IOC_VFD_SET_BRIGHT"); +} + +void CVFD::setlcdparameter(void) +{ + if(!has_lcd) return; + last_toggle_state_power = g_settings.lcd_setting[SNeutrinoSettings::LCD_POWER]; + setlcdparameter((mode == MODE_STANDBY) ? g_settings.lcd_setting[SNeutrinoSettings::LCD_STANDBY_BRIGHTNESS] : g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS], + last_toggle_state_power); +} + +void CVFD::showServicename(const std::string & name) // UTF-8 +{ + if(!has_lcd) return; + +printf("CVFD::showServicename: %s\n", name.c_str()); + servicename = name; + if (mode != MODE_TVRADIO) + return; + + ShowText((char *) name.c_str()); + wake_up(); +} + +void CVFD::showTime(bool force) +{ + if(!has_lcd) + return; + + if (showclock) { + if (mode == MODE_STANDBY) { + char timestr[21]; + struct timeb tm; + struct tm * t; + static int hour = 0, minute = 0; + + ftime(&tm); + t = localtime(&tm.time); + if(force || ((hour != t->tm_hour) || (minute != t->tm_min))) { + hour = t->tm_hour; + minute = t->tm_min; + strftime(timestr, 20, "%H:%M", t); + ShowText((char *) timestr); + } + } + } + + if (CNeutrinoApp::getInstance ()->recordingstatus) { + if(clearClock) { + clearClock = 0; + ShowIcon(VFD_ICON_CAM1, false); + } else { + clearClock = 1; + ShowIcon(VFD_ICON_CAM1, true); + } + } else if(clearClock) { // in case icon ON after record stopped + clearClock = 0; + ShowIcon(VFD_ICON_CAM1, false); + } +} + +void CVFD::showRCLock(int duration) +{ +} + +void CVFD::showVolume(const char vol, const bool perform_update) +{ + static int oldpp = 0; + if(!has_lcd) return; + + ShowIcon(VFD_ICON_MUTE, muted); + if(vol == volume) + return; + + volume = vol; + wake_up(); + ShowIcon(VFD_ICON_FRAME, true); + + if ((mode == MODE_TVRADIO) && g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME]) { + int pp = (int) round((double) vol * (double) 8 / (double) 100); + if(pp > 8) pp = 8; + + if(oldpp != pp) { +printf("CVFD::showVolume: %d, bar %d\n", (int) vol, pp); + int i; + int j = 0x00000200; + for(i = 0; i < pp; i++) { + ShowIcon((vfd_icon) j, true); + j /= 2; + } + for(;i < 8; i++) { + ShowIcon((vfd_icon) j, false); + j /= 2; + } + oldpp = pp; + } + } +} + +void CVFD::showPercentOver(const unsigned char perc, const bool perform_update) +{ + if(!has_lcd) return; + + if ((mode == MODE_TVRADIO) && !(g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME])) { + //if (g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME] == 0) + { + ShowIcon(VFD_ICON_FRAME, true); + int pp; + if(perc == 255) + pp = 0; + else + pp = (int) round((double) perc * (double) 8 / (double) 100); +printf("CVFD::showPercentOver: %d, bar %d\n", (int) perc, pp); + if(pp > 8) pp = 8; + if(pp != percentOver) { + int i; + int j = 0x00000200; + for(i = 0; i < pp; i++) { + ShowIcon((vfd_icon) j, true); + j /= 2; + } + for(;i < 8; i++) { + ShowIcon((vfd_icon) j, false); + j /= 2; + } + percentOver = pp; + } + } + } +} + +void CVFD::showMenuText(const int position, const char * text, const int highlight, const bool utf_encoded) +{ + if(!has_lcd) return; + if (mode != MODE_MENU_UTF8) + return; + + ShowText((char *) text); + wake_up(); +} + +void CVFD::showAudioTrack(const std::string & artist, const std::string & title, const std::string & album) +{ + if(!has_lcd) return; + if (mode != MODE_AUDIO) + return; +printf("CVFD::showAudioTrack: %s\n", title.c_str()); + ShowText((char *) title.c_str()); + wake_up(); + +#ifdef HAVE_LCD + fonts.menu->RenderString(0,22, 125, artist.c_str() , CLCDDisplay::PIXEL_ON, 0, true); // UTF-8 + fonts.menu->RenderString(0,35, 125, album.c_str() , CLCDDisplay::PIXEL_ON, 0, true); // UTF-8 + fonts.menu->RenderString(0,48, 125, title.c_str() , CLCDDisplay::PIXEL_ON, 0, true); // UTF-8 +#endif +} + +void CVFD::showAudioPlayMode(AUDIOMODES m) +{ + if(!has_lcd) return; + switch(m) { + case AUDIO_MODE_PLAY: + ShowIcon(VFD_ICON_PLAY, true); + ShowIcon(VFD_ICON_PAUSE, false); + break; + case AUDIO_MODE_STOP: + ShowIcon(VFD_ICON_PLAY, false); + ShowIcon(VFD_ICON_PAUSE, false); + break; + case AUDIO_MODE_PAUSE: + ShowIcon(VFD_ICON_PLAY, false); + ShowIcon(VFD_ICON_PAUSE, true); + break; + case AUDIO_MODE_FF: + break; + case AUDIO_MODE_REV: + break; + } + wake_up(); +} + +void CVFD::showAudioProgress(const char perc, bool isMuted) +{ + if(!has_lcd) return; +#if 0 // what is this ? FIXME + if (mode == MODE_AUDIO) { + int dp = int( perc/100.0*61.0+12.0); + if(isMuted) { + if(dp > 12) { + display.draw_line(12, 56, dp-1, 56, CLCDDisplay::PIXEL_OFF); + display.draw_line(12, 58, dp-1, 58, CLCDDisplay::PIXEL_OFF); + } + else + display.draw_line (12,55,72,59, CLCDDisplay::PIXEL_ON); + } + } +#endif +} + +void CVFD::setMode(const MODES m, const char * const title) +{ + if(!has_lcd) return; + + if(mode == MODE_AUDIO) + ShowIcon(VFD_ICON_MP3, false); +#if 0 + else if(mode == MODE_STANDBY) { + ShowIcon(VFD_ICON_COL1, false); + ShowIcon(VFD_ICON_COL2, false); + } +#endif + + if(strlen(title)) + ShowText((char *) title); + mode = m; + setlcdparameter(); + + switch (m) { + case MODE_TVRADIO: + switch (g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME]) + { + case 0: + showPercentOver(percentOver, false); + break; + case 1: + showVolume(volume, false); + break; +#if 0 + case 2: + showVolume(volume, false); + showPercentOver(percentOver, false); + break; +#endif + } + showServicename(servicename); + showclock = true; + //showTime(); /* "showclock = true;" implies that "showTime();" does a "displayUpdate();" */ + break; + case MODE_AUDIO: + { + ShowIcon(VFD_ICON_MP3, true); + showAudioPlayMode(AUDIO_MODE_STOP); + showVolume(volume, false); + showclock = true; + //showTime(); /* "showclock = true;" implies that "showTime();" does a "displayUpdate();" */ + break; + } + case MODE_SCART: + showVolume(volume, false); + showclock = true; + //showTime(); /* "showclock = true;" implies that "showTime();" does a "displayUpdate();" */ + break; + case MODE_MENU_UTF8: + showclock = false; + //fonts.menutitle->RenderString(0,28, 140, title, CLCDDisplay::PIXEL_ON, 0, true); // UTF-8 + break; + case MODE_SHUTDOWN: + showclock = false; + break; + case MODE_STANDBY: +#if 0 + ShowIcon(VFD_ICON_COL1, true); + ShowIcon(VFD_ICON_COL2, true); +#endif + showclock = true; + showTime(true); /* "showclock = true;" implies that "showTime();" does a "displayUpdate();" */ + /* "showTime()" clears the whole lcd in MODE_STANDBY */ + break; +#ifdef VFD_UPDATE + case MODE_FILEBROWSER: + showclock = true; + display.draw_fill_rect(-1, -1, 120, 64, CLCDDisplay::PIXEL_OFF); // clear lcd + showFilelist(); + break; + case MODE_PROGRESSBAR: + showclock = false; + display.load_screen(&(background[BACKGROUND_SETUP])); + showProgressBar(); + break; + case MODE_PROGRESSBAR2: + showclock = false; + display.load_screen(&(background[BACKGROUND_SETUP])); + showProgressBar2(); + break; + case MODE_INFOBOX: + showclock = false; + showInfoBox(); + break; +#endif // VFD_UPDATE + } + wake_up(); +} + +void CVFD::setBrightness(int bright) +{ + if(!has_lcd) return; + + g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS] = bright; + setlcdparameter(); +} + +int CVFD::getBrightness() +{ + //FIXME for old neutrino.conf + if(g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS] > 15) + g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS] = 15; + + return g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS]; +} + +void CVFD::setBrightnessStandby(int bright) +{ + if(!has_lcd) return; + + g_settings.lcd_setting[SNeutrinoSettings::LCD_STANDBY_BRIGHTNESS] = bright; + setlcdparameter(); +} + +int CVFD::getBrightnessStandby() +{ + //FIXME for old neutrino.conf + if(g_settings.lcd_setting[SNeutrinoSettings::LCD_STANDBY_BRIGHTNESS] > 15) + g_settings.lcd_setting[SNeutrinoSettings::LCD_STANDBY_BRIGHTNESS] = 15; + return g_settings.lcd_setting[SNeutrinoSettings::LCD_STANDBY_BRIGHTNESS]; +} + +void CVFD::setPower(int power) +{ + if(!has_lcd) return; +// old + //g_settings.lcd_setting[SNeutrinoSettings::LCD_POWER] = power; + //setlcdparameter(); +} + +int CVFD::getPower() +{ + return g_settings.lcd_setting[SNeutrinoSettings::LCD_POWER]; +} + +void CVFD::togglePower(void) +{ + if(!has_lcd) return; + + last_toggle_state_power = 1 - last_toggle_state_power; + setlcdparameter((mode == MODE_STANDBY) ? g_settings.lcd_setting[SNeutrinoSettings::LCD_STANDBY_BRIGHTNESS] : g_settings.lcd_setting[SNeutrinoSettings::LCD_BRIGHTNESS], + last_toggle_state_power); +} + +void CVFD::setMuted(bool mu) +{ + if(!has_lcd) return; + muted = mu; + showVolume(volume); +} + +void CVFD::resume() +{ + if(!has_lcd) return; +} + +void CVFD::pause() +{ + if(!has_lcd) return; +} + +void CVFD::Lock() +{ + if(!has_lcd) return; + creat("/tmp/vfd.locked", 0); +} + +void CVFD::Unlock() +{ + if(!has_lcd) return; + unlink("/tmp/vfd.locked"); +} + +void CVFD::Clear() +{ + if(!has_lcd) return; + int ret = ioctl(fd, IOC_VFD_CLEAR_ALL, 0); + if(ret < 0) + perror("IOC_VFD_SET_TEXT"); +} + +void CVFD::ShowIcon(vfd_icon icon, bool show) +{ +//printf("CVFD::ShowIcon %s %x\n", show ? "show" : "hide", (int) icon); + int ret = ioctl(fd, show ? IOC_VFD_SET_ICON : IOC_VFD_CLEAR_ICON, icon); + if(ret < 0) + perror(show ? "IOC_VFD_SET_ICON" : "IOC_VFD_CLEAR_ICON"); +} + +void CVFD::ShowText(char * str) +{ + int len = strlen(str); + int i, ret; + +printf("CVFD::ShowText: [%s]\n", str); + for(i = len-1; i > 0; i--) { + if(str[i] == ' ') + str[i] = 0; + else + break; + } + + if(!strcmp(str, text) || len > 255) + return; + + strcpy(text, str); + +//printf("****************************** CVFD::ShowText: %s\n", str); + //FIXME !! + ret = ioctl(fd, IOC_VFD_SET_TEXT, len ? str : NULL); + if(ret < 0) + perror("IOC_VFD_SET_TEXT"); +} + +#ifdef VFD_UPDATE +/*****************************************************************************************/ +// showInfoBox +/*****************************************************************************************/ +#define LCD_WIDTH 120 +#define LCD_HEIGTH 64 + +#define EPG_INFO_FONT_HEIGHT 9 +#define EPG_INFO_SHADOW_WIDTH 1 +#define EPG_INFO_LINE_WIDTH 1 +#define EPG_INFO_BORDER_WIDTH 2 + +#define EPG_INFO_WINDOW_POS 4 +#define EPG_INFO_LINE_POS EPG_INFO_WINDOW_POS + EPG_INFO_SHADOW_WIDTH +#define EPG_INFO_BORDER_POS EPG_INFO_WINDOW_POS + EPG_INFO_SHADOW_WIDTH + EPG_INFO_LINE_WIDTH +#define EPG_INFO_TEXT_POS EPG_INFO_WINDOW_POS + EPG_INFO_SHADOW_WIDTH + EPG_INFO_LINE_WIDTH + EPG_INFO_BORDER_WIDTH + +#define EPG_INFO_TEXT_WIDTH LCD_WIDTH - (2*EPG_INFO_WINDOW_POS) + +// timer 0: OFF, timer>0 time to show in seconds, timer>=999 endless +void CVFD::showInfoBox(const char * const title, const char * const text ,int autoNewline,int timer) +{ +#ifdef HAVE_LCD + if(!has_lcd) return; + //printf("[lcdd] Info: \n"); + if(text != NULL) + m_infoBoxText = text; + if(text != NULL) + m_infoBoxTitle = title; + if(timer != -1) + m_infoBoxTimer = timer; + if(autoNewline != -1) + m_infoBoxAutoNewline = autoNewline; + + //printf("[lcdd] Info: %s,%s,%d,%d\n",m_infoBoxTitle.c_str(),m_infoBoxText.c_str(),m_infoBoxAutoNewline,m_infoBoxTimer); + if( mode == MODE_INFOBOX && + !m_infoBoxText.empty()) + { + // paint empty box + display.draw_fill_rect (EPG_INFO_WINDOW_POS, EPG_INFO_WINDOW_POS, LCD_WIDTH-EPG_INFO_WINDOW_POS+1, LCD_HEIGTH-EPG_INFO_WINDOW_POS+1, CLCDDisplay::PIXEL_OFF); + display.draw_fill_rect (EPG_INFO_LINE_POS, EPG_INFO_LINE_POS, LCD_WIDTH-EPG_INFO_LINE_POS-1, LCD_HEIGTH-EPG_INFO_LINE_POS-1, CLCDDisplay::PIXEL_ON); + display.draw_fill_rect (EPG_INFO_BORDER_POS, EPG_INFO_BORDER_POS, LCD_WIDTH-EPG_INFO_BORDER_POS-3, LCD_HEIGTH-EPG_INFO_BORDER_POS-3, CLCDDisplay::PIXEL_OFF); + + // paint title + if(!m_infoBoxTitle.empty()) + { + int width = fonts.menu->getRenderWidth(m_infoBoxTitle.c_str(),true); + if(width > 100) + width = 100; + int start_pos = (120-width) /2; + display.draw_fill_rect (start_pos, EPG_INFO_WINDOW_POS-4, start_pos+width+5, EPG_INFO_WINDOW_POS+10, CLCDDisplay::PIXEL_OFF); + fonts.menu->RenderString(start_pos+4,EPG_INFO_WINDOW_POS+5, width+5, m_infoBoxTitle.c_str(), CLCDDisplay::PIXEL_ON, 0, true); // UTF-8 + } + + // paint info + std::string text_line; + int line; + int pos = 0; + int length = m_infoBoxText.size(); + for(line = 0; line < 5; line++) + { + text_line.clear(); + while ( m_infoBoxText[pos] != '\n' && + ((fonts.menu->getRenderWidth(text_line.c_str(), true) < EPG_INFO_TEXT_WIDTH-10) || !m_infoBoxAutoNewline )&& + (pos < length)) // UTF-8 + { + if ( m_infoBoxText[pos] >= ' ' && m_infoBoxText[pos] <= '~' ) // any char between ASCII(32) and ASCII (126) + text_line += m_infoBoxText[pos]; + pos++; + } + //printf("[lcdd] line %d:'%s'\r\n",line,text_line.c_str()); + fonts.menu->RenderString(EPG_INFO_TEXT_POS+1,EPG_INFO_TEXT_POS+(line*EPG_INFO_FONT_HEIGHT)+EPG_INFO_FONT_HEIGHT+3, EPG_INFO_TEXT_WIDTH, text_line.c_str(), CLCDDisplay::PIXEL_ON, 0, true); // UTF-8 + if ( m_infoBoxText[pos] == '\n' ) + pos++; // remove new line + } + displayUpdate(); + } +#endif +} + +/*****************************************************************************************/ +//showFilelist +/*****************************************************************************************/ +#define BAR_POS_X 114 +#define BAR_POS_Y 10 +#define BAR_POS_WIDTH 6 +#define BAR_POS_HEIGTH 40 + +void CVFD::showFilelist(int flist_pos,CFileList* flist,const char * const mainDir) +{ +#ifdef HAVE_LCD + if(!has_lcd) return; + //printf("[lcdd] FileList\n"); + if(flist != NULL) + m_fileList = flist; + if(flist_pos != -1) + m_fileListPos = flist_pos; + if(mainDir != NULL) + m_fileListHeader = mainDir; + + if (mode == MODE_FILEBROWSER && + m_fileList != NULL && + m_fileList->size() > 0) + { + + printf("[lcdd] FileList:OK\n"); + int size = m_fileList->size(); + + display.draw_fill_rect(-1, -1, 120, 52, CLCDDisplay::PIXEL_OFF); // clear lcd + + if(m_fileListPos > size) + m_fileListPos = size-1; + + int width = fonts.menu->getRenderWidth(m_fileListHeader.c_str(), true); + if(width>110) + width=110; + fonts.menu->RenderString((120-width)/2, 11, width+5, m_fileListHeader.c_str(), CLCDDisplay::PIXEL_ON); + + //printf("list%d,%d\r\n",m_fileListPos,(*m_fileList)[m_fileListPos].Marked); + std::string text; + int marked; + if(m_fileListPos > 0) + { + if ( (*m_fileList)[m_fileListPos-1].Marked == false ) + { + text =""; + marked = CLCDDisplay::PIXEL_ON; + } + else + { + text ="*"; + marked = CLCDDisplay::PIXEL_INV; + } + text += (*m_fileList)[m_fileListPos-1].getFileName(); + fonts.menu->RenderString(1, 12+12, BAR_POS_X+5, text.c_str(), marked); + } + if(m_fileListPos < size) + { + if ((*m_fileList)[m_fileListPos-0].Marked == false ) + { + text =""; + marked = CLCDDisplay::PIXEL_ON; + } + else + { + text ="*"; + marked = CLCDDisplay::PIXEL_INV; + } + text += (*m_fileList)[m_fileListPos-0].getFileName(); + fonts.time->RenderString(1, 12+12+14, BAR_POS_X+5, text.c_str(), marked); + } + if(m_fileListPos < size-1) + { + if ((*m_fileList)[m_fileListPos+1].Marked == false ) + { + text =""; + marked = CLCDDisplay::PIXEL_ON; + } + else + { + text ="*"; + marked = CLCDDisplay::PIXEL_INV; + } + text += (*m_fileList)[m_fileListPos+1].getFileName(); + fonts.menu->RenderString(1, 12+12+14+12, BAR_POS_X+5, text.c_str(), marked); + } + // paint marker + int pages = (((size-1)/3 )+1); + int marker_length = (BAR_POS_HEIGTH-2) / pages; + if(marker_length <4) + marker_length=4;// not smaller than 4 pixel + int marker_offset = ((BAR_POS_HEIGTH-2-marker_length) * m_fileListPos) /size ; + //printf("%d,%d,%d\r\n",pages,marker_length,marker_offset); + + display.draw_fill_rect (BAR_POS_X, BAR_POS_Y, BAR_POS_X+BAR_POS_WIDTH, BAR_POS_Y+BAR_POS_HEIGTH, CLCDDisplay::PIXEL_ON); + display.draw_fill_rect (BAR_POS_X+1, BAR_POS_Y+1, BAR_POS_X+BAR_POS_WIDTH-1, BAR_POS_Y+BAR_POS_HEIGTH-1, CLCDDisplay::PIXEL_OFF); + display.draw_fill_rect (BAR_POS_X+1, BAR_POS_Y+1+marker_offset, BAR_POS_X+BAR_POS_WIDTH-1, BAR_POS_Y+1+marker_offset+marker_length, CLCDDisplay::PIXEL_ON); + + displayUpdate(); + } +#endif +} + +/*****************************************************************************************/ +//showProgressBar +/*****************************************************************************************/ +#define PROG_GLOB_POS_X 10 +#define PROG_GLOB_POS_Y 30 +#define PROG_GLOB_POS_WIDTH 100 +#define PROG_GLOB_POS_HEIGTH 20 +void CVFD::showProgressBar(int global, const char * const text,int show_escape,int timer) +{ +#ifdef HAVE_LCD + if(!has_lcd) return; + if(text != NULL) + m_progressHeaderGlobal = text; + + if(timer != -1) + m_infoBoxTimer = timer; + + if(global >= 0) + { + if(global > 100) + m_progressGlobal =100; + else + m_progressGlobal = global; + } + + if(show_escape != -1) + m_progressShowEscape = show_escape; + + if (mode == MODE_PROGRESSBAR) + { + //printf("[lcdd] prog:%s,%d,%d\n",m_progressHeaderGlobal.c_str(),m_progressGlobal,m_progressShowEscape); + // Clear Display + display.draw_fill_rect (0,12,120,64, CLCDDisplay::PIXEL_OFF); + + // paint progress header + int width = fonts.menu->getRenderWidth(m_progressHeaderGlobal.c_str(),true); + if(width > 100) + width = 100; + int start_pos = (120-width) /2; + fonts.menu->RenderString(start_pos, 12+12, width+10, m_progressHeaderGlobal.c_str(), CLCDDisplay::PIXEL_ON,0,true); + + // paint global bar + int marker_length = (PROG_GLOB_POS_WIDTH * m_progressGlobal)/100; + + display.draw_fill_rect (PROG_GLOB_POS_X, PROG_GLOB_POS_Y, PROG_GLOB_POS_X+PROG_GLOB_POS_WIDTH, PROG_GLOB_POS_Y+PROG_GLOB_POS_HEIGTH, CLCDDisplay::PIXEL_ON); + display.draw_fill_rect (PROG_GLOB_POS_X+1+marker_length, PROG_GLOB_POS_Y+1, PROG_GLOB_POS_X+PROG_GLOB_POS_WIDTH-1, PROG_GLOB_POS_Y+PROG_GLOB_POS_HEIGTH-1, CLCDDisplay::PIXEL_OFF); + + // paint foot + if(m_progressShowEscape == true) + { + fonts.menu->RenderString(90, 64, 40, "Home", CLCDDisplay::PIXEL_ON); + } + displayUpdate(); + } +#endif +} + +/*****************************************************************************************/ +// showProgressBar2 +/*****************************************************************************************/ +#define PROG2_GLOB_POS_X 10 +#define PROG2_GLOB_POS_Y 24 +#define PROG2_GLOB_POS_WIDTH 100 +#define PROG2_GLOB_POS_HEIGTH 10 + +#define PROG2_LOCAL_POS_X 10 +#define PROG2_LOCAL_POS_Y 37 +#define PROG2_LOCAL_POS_WIDTH PROG2_GLOB_POS_WIDTH +#define PROG2_LOCAL_POS_HEIGTH PROG2_GLOB_POS_HEIGTH + +void CVFD::showProgressBar2(int local,const char * const text_local ,int global ,const char * const text_global ,int show_escape ) +{ +#ifdef HAVE_LCD + if(!has_lcd) return; + //printf("[lcdd] prog2\n"); + if(text_local != NULL) + m_progressHeaderLocal = text_local; + + if(text_global != NULL) + m_progressHeaderGlobal = text_global; + + if(global >= 0) + { + if(global > 100) + m_progressGlobal =100; + else + m_progressGlobal = global; + } + if(local >= 0) + { + if(local > 100) + m_progressLocal =100; + else + m_progressLocal = local; + } + if(show_escape != -1) + m_progressShowEscape = show_escape; + + if (mode == MODE_PROGRESSBAR2) + { + + //printf("[lcdd] prog2:%s,%d,%d\n",m_progressHeaderGlobal.c_str(),m_progressGlobal,m_progressShowEscape); + // Clear Display + display.draw_fill_rect (0,12,120,64, CLCDDisplay::PIXEL_OFF); + + // paint global header + int width = fonts.menu->getRenderWidth(m_progressHeaderGlobal.c_str(),true); + if(width > 100) + width = 100; + int start_pos = (120-width) /2; + fonts.menu->RenderString(start_pos, PROG2_GLOB_POS_Y-3, width+10, m_progressHeaderGlobal.c_str(), CLCDDisplay::PIXEL_ON,0,true); + + // paint global bar + int marker_length = (PROG2_GLOB_POS_WIDTH * m_progressGlobal)/100; + + display.draw_fill_rect (PROG2_GLOB_POS_X, PROG2_GLOB_POS_Y, PROG2_GLOB_POS_X+PROG2_GLOB_POS_WIDTH, PROG2_GLOB_POS_Y+PROG2_GLOB_POS_HEIGTH, CLCDDisplay::PIXEL_ON); + display.draw_fill_rect (PROG2_GLOB_POS_X+1+marker_length, PROG2_GLOB_POS_Y+1, PROG2_GLOB_POS_X+PROG2_GLOB_POS_WIDTH-1, PROG2_GLOB_POS_Y+PROG2_GLOB_POS_HEIGTH-1, CLCDDisplay::PIXEL_OFF); + + // paint local header + width = fonts.menu->getRenderWidth(m_progressHeaderLocal.c_str(),true); + if(width > 100) + width = 100; + start_pos = (120-width) /2; + fonts.menu->RenderString(start_pos, PROG2_LOCAL_POS_Y + PROG2_LOCAL_POS_HEIGTH +10 , width+10, m_progressHeaderLocal.c_str(), CLCDDisplay::PIXEL_ON,0,true); + // paint local bar + marker_length = (PROG2_LOCAL_POS_WIDTH * m_progressLocal)/100; + + display.draw_fill_rect (PROG2_LOCAL_POS_X, PROG2_LOCAL_POS_Y, PROG2_LOCAL_POS_X+PROG2_LOCAL_POS_WIDTH, PROG2_LOCAL_POS_Y+PROG2_LOCAL_POS_HEIGTH, CLCDDisplay::PIXEL_ON); + display.draw_fill_rect (PROG2_LOCAL_POS_X+1+marker_length, PROG2_LOCAL_POS_Y+1, PROG2_LOCAL_POS_X+PROG2_LOCAL_POS_WIDTH-1, PROG2_LOCAL_POS_Y+PROG2_LOCAL_POS_HEIGTH-1, CLCDDisplay::PIXEL_OFF); + // paint foot + if(m_progressShowEscape == true) + { + fonts.menu->RenderString(90, 64, 40, "Home", CLCDDisplay::PIXEL_ON); + } + displayUpdate(); + } +#endif +} +/*****************************************************************************************/ +#endif // VFD_UPDATE + + diff --git a/src/driver/vfd.h b/src/driver/vfd.h new file mode 100644 index 000000000..91de14913 --- /dev/null +++ b/src/driver/vfd.h @@ -0,0 +1,172 @@ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __vfd__ +#define __vfd__ + +//#define VFD_UPDATE + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef VFD_UPDATE +// TODO Why is USE_FILE_OFFSET64 not defined, if file.h is included here???? +#ifndef __USE_FILE_OFFSET64 +#define __USE_FILE_OFFSET64 1 +#endif +#include "driver/file.h" +#endif // LCD_UPDATE + +#include +#include +#include + +class CVFD +{ + public: + + enum MODES + { + MODE_TVRADIO, + MODE_SCART, + MODE_SHUTDOWN, + MODE_STANDBY, + MODE_MENU_UTF8, + MODE_AUDIO +#ifdef VFD_UPDATE + , MODE_FILEBROWSER, + MODE_PROGRESSBAR, + MODE_PROGRESSBAR2, + MODE_INFOBOX +#endif // LCD_UPDATE + + }; + enum AUDIOMODES + { + AUDIO_MODE_PLAY, + AUDIO_MODE_STOP, + AUDIO_MODE_FF, + AUDIO_MODE_PAUSE, + AUDIO_MODE_REV + }; + + + private: + MODES mode; + + std::string servicename; + char volume; + unsigned char percentOver; + bool muted; + bool showclock; + pthread_t thrTime; + int last_toggle_state_power; + bool clearClock; + unsigned int timeout_cnt; + int fd; + int brightness; + char text[256]; + + void wake_up(); + void count_down(); + + CVFD(); + + static void* TimeThread(void*); + void setlcdparameter(int dimm, int power); + public: + + ~CVFD(); + bool has_lcd; + void setlcdparameter(void); + + static CVFD* getInstance(); + void init(const char * fontfile, const char * fontname); + + void setMode(const MODES m, const char * const title = ""); + + void showServicename(const std::string & name); // UTF-8 + void showTime(bool force = false); + /** blocks for duration seconds */ + void showRCLock(int duration = 2); + void showVolume(const char vol, const bool perform_update = true); + void showPercentOver(const unsigned char perc, const bool perform_update = true); + void showMenuText(const int position, const char * text, const int highlight = -1, const bool utf_encoded = false); + void showAudioTrack(const std::string & artist, const std::string & title, const std::string & album); + void showAudioPlayMode(AUDIOMODES m=AUDIO_MODE_PLAY); + void showAudioProgress(const char perc, bool isMuted); + void setBrightness(int); + int getBrightness(); + + void setBrightnessStandby(int); + int getBrightnessStandby(); + + void setPower(int); + int getPower(); + + void togglePower(void); + + void setInverse(int); + int getInverse(); + + void setMuted(bool); + + void resume(); + void pause(); + void Lock(); + void Unlock(); + void Clear(); + void ShowIcon(vfd_icon icon, bool show); + void ShowText(char * str); +#ifdef LCD_UPDATE + private: + CFileList* m_fileList; + int m_fileListPos; + std::string m_fileListHeader; + + std::string m_infoBoxText; + std::string m_infoBoxTitle; + int m_infoBoxTimer; // for later use + bool m_infoBoxAutoNewline; + + bool m_progressShowEscape; + std::string m_progressHeaderGlobal; + std::string m_progressHeaderLocal; + int m_progressGlobal; + int m_progressLocal; + public: + MODES getMode(void){return mode;}; + + void showFilelist(int flist_pos = -1,CFileList* flist = NULL,const char * const mainDir=NULL); + void showInfoBox(const char * const title = NULL,const char * const text = NULL,int autoNewline = -1,int timer = -1); + void showProgressBar(int global = -1,const char * const text = NULL,int show_escape = -1,int timer = -1); + void showProgressBar2(int local = -1,const char * const text_local = NULL,int global = -1,const char * const text_global = NULL,int show_escape = -1); +#endif // LCD_UPDATE + +}; + + +#endif diff --git a/src/driver/wav.h b/src/driver/wav.h new file mode 100644 index 000000000..1b108b746 --- /dev/null +++ b/src/driver/wav.h @@ -0,0 +1,65 @@ +static unsigned char click[] = { +0xE5, 0xF5, 0xFF, 0xF7, 0x18, 0xFA, 0x7F, 0xFB, 0x98, 0xFD, 0xFF, 0xFE, 0x17, 0x01, 0x31, 0x03, +0x4A, 0x05, 0xB1, 0x06, 0xCA, 0x08, 0xCA, 0x0F, 0xCA, 0x16, 0x97, 0x12, 0x17, 0x0F, 0xFE, 0x13, +0xE4, 0x18, 0x7E, 0x17, 0x17, 0x16, 0x64, 0x15, 0x64, 0x15, 0xE4, 0x18, 0x17, 0x1D, 0xCA, 0x1D, +0x7E, 0x1E, 0xCA, 0x24, 0x17, 0x2B, 0xE4, 0x26, 0x64, 0x23, 0x31, 0x2D, 0xFE, 0x36, 0x7E, 0x33, +0xB1, 0x30, 0x17, 0x32, 0x7E, 0x33, 0x64, 0x2A, 0x4A, 0x21, 0x64, 0x15, 0x7E, 0x09, 0x97, 0x04, +0xB2, 0xFF, 0xB2, 0xF1, 0xB2, 0xE3, 0xFF, 0xE2, 0x4B, 0xE2, 0x32, 0xD9, 0xCB, 0xD0, 0x7F, 0xD1, +0xE5, 0xD2, 0x18, 0xD0, 0x4B, 0xCD, 0x65, 0xC8, 0x7F, 0xC3, 0xCB, 0xC2, 0x18, 0xC2, 0x18, 0xC2, +0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0xCB, 0xC2, +0x7F, 0xC3, 0x18, 0xC9, 0xB2, 0xCE, 0xFF, 0xD4, 0x4B, 0xDB, 0x4B, 0xE2, 0x4B, 0xE9, 0xE5, 0xEE, +0x32, 0xF5, 0x7F, 0xFB, 0xCA, 0x01, 0x17, 0x08, 0x17, 0x0F, 0xFE, 0x13, 0x97, 0x19, 0xCA, 0x1D, +0xB1, 0x22, 0x31, 0x26, 0xB1, 0x29, 0xCA, 0x2B, 0x97, 0x2E, 0x4A, 0x2F, 0xB1, 0x30, 0xFE, 0x2F, +0xFE, 0x2F, 0xE4, 0x2D, 0x7E, 0x2C, 0xFE, 0x28, 0x31, 0x26, 0xFE, 0x21, 0xCA, 0x1D, 0x31, 0x18, +0x4A, 0x13, 0xB1, 0x0D, 0x17, 0x08, 0xCA, 0x01, 0x7F, 0xFB, 0x32, 0xF5, 0x98, 0xEF, 0x4B, 0xE9, +0xB2, 0xE3, 0x18, 0xDE, 0x7F, 0xD8, 0x98, 0xD3, 0x65, 0xCF, 0x32, 0xCB, 0xB2, 0xC7, 0xE5, 0xC4, +0xCB, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x7F, 0xC3, 0x98, 0xC5, 0x65, 0xC8, +0xE5, 0xCB, 0x18, 0xD0, 0xFF, 0xD4, 0x98, 0xDA, 0x32, 0xE0, 0x7F, 0xE6, 0x7F, 0xED, 0x7F, 0xF4, +0x32, 0xFC, 0xE4, 0x03, 0x97, 0x0B, 0xE4, 0x11, 0x31, 0x18, 0x31, 0x1F, 0x31, 0x26, 0x7E, 0x2C, +0x7E, 0x33, 0xB1, 0x37, 0x97, 0x3C, 0x4A, 0x3D, 0xFE, 0x3D, 0xFE, 0x3D, 0xFE, 0x3D, 0xFE, 0x3D, +0xFE, 0x3D, 0xFE, 0x3D, 0xFE, 0x3D, 0xFE, 0x3D, 0xFE, 0x3D, 0xFE, 0x3D, 0xFE, 0x3D, 0xCA, 0x39, +0x97, 0x35, 0xFE, 0x2F, 0x17, 0x2B, 0xCA, 0x24, 0x7E, 0x1E, 0x7E, 0x17, 0x7E, 0x10, 0x7E, 0x09, +0x31, 0x03, 0xE5, 0xFC, 0x4B, 0xF7, 0xFF, 0xF0, 0x65, 0xEB, 0x7F, 0xE6, 0x98, 0xE1, 0xCB, 0xDE, +0xFF, 0xDB, 0x32, 0xD9, 0x65, 0xD6, 0xFF, 0xD4, 0x4B, 0xD4, 0xFF, 0xD4, 0x65, 0xD6, 0x7F, 0xD8, +0x98, 0xDA, 0x65, 0xDD, 0xE5, 0xE0, 0x18, 0xE5, 0x4B, 0xE9, 0xE5, 0xEE, 0x32, 0xF5, 0xCB, 0xFA, +0x64, 0x00, 0xB1, 0x06, 0xFE, 0x0C, 0x4A, 0x13, 0x4A, 0x1A, 0xE4, 0x1F, 0x7E, 0x25, 0xB1, 0x29, +0x97, 0x2E, 0x17, 0x32, 0x4A, 0x36, 0x17, 0x39, 0x97, 0x3C, 0x97, 0x3C, 0x4A, 0x3D, 0x4A, 0x3D, +0x4A, 0x3D, 0x31, 0x3B, 0xCA, 0x39, 0x4A, 0x36, 0x7E, 0x33, 0x97, 0x2E, 0xB1, 0x29, 0x17, 0x24, +0x31, 0x1F, 0x31, 0x18, 0xE4, 0x11, 0xE4, 0x0A, 0xE4, 0x03, 0xE5, 0xFC, 0xE5, 0xF5, 0x98, 0xEF, +0x4B, 0xE9, 0xFF, 0xE2, 0x65, 0xDD, 0xCB, 0xD7, 0xE5, 0xD2, 0xB2, 0xCE, 0x32, 0xCB, 0x65, 0xC8, +0x4B, 0xC6, 0xE5, 0xC4, 0x7F, 0xC3, 0x32, 0xC4, 0xE5, 0xC4, 0xB2, 0xC7, 0x7F, 0xCA, 0xFF, 0xCD, +0x7F, 0xD1, 0x65, 0xD6, 0x4B, 0xDB, 0x98, 0xE1, 0xE5, 0xE7, 0x32, 0xEE, 0x32, 0xF5, 0x7F, 0xFB, +0x7E, 0x02, 0xCA, 0x08, 0xCA, 0x0F, 0x17, 0x16, 0x17, 0x1D, 0xFE, 0x21, 0xE4, 0x26, 0x17, 0x2B, +0x4A, 0x2F, 0x17, 0x32, 0x97, 0x35, 0x4A, 0x36, 0xB1, 0x37, 0xFE, 0x36, 0x4A, 0x36, 0x31, 0x34, +0x17, 0x32, 0x97, 0x2E, 0x17, 0x2B, 0x7E, 0x25, 0x97, 0x20, 0x4A, 0x1A, 0xB1, 0x14, 0x4A, 0x0C, +0x97, 0x04, 0x4B, 0xFE, 0xB2, 0xF8, 0x4B, 0xF0, 0xE5, 0xE7, 0x98, 0xE1, 0xFF, 0xDB, 0x65, 0xD6, +0xCB, 0xD0, 0x4B, 0xCD, 0x7F, 0xCA, 0x65, 0xC8, 0x4B, 0xC6, 0xE5, 0xC4, 0x7F, 0xC3, 0x98, 0xC5, +0x65, 0xC8, 0xCB, 0xC9, 0xE5, 0xCB, 0x18, 0xD0, 0xFF, 0xD4, 0xE5, 0xD9, 0x7F, 0xDF, 0x18, 0xE5, +0x65, 0xEB, 0xB2, 0xF1, 0xB2, 0xF8, 0xFF, 0xFE, 0xFE, 0x05, 0xFE, 0x0C, 0xFE, 0x13, 0x97, 0x19, +0xE4, 0x1F, 0x7E, 0x25, 0x17, 0x2B, 0x97, 0x2E, 0xCA, 0x32, 0x97, 0x35, 0x17, 0x39, 0xCA, 0x39, +0x7E, 0x3A, 0xCA, 0x39, 0x17, 0x39, 0xFE, 0x36, 0xE4, 0x34, 0xFE, 0x2F, 0x17, 0x2B, 0xCA, 0x24, +0x31, 0x1F, 0x7E, 0x17, 0x7E, 0x10, 0x17, 0x08, 0x64, 0x00, 0xFF, 0xF7, 0x98, 0xEF, 0x32, 0xE7, +0x7F, 0xDF, 0xCB, 0xD7, 0x18, 0xD0, 0xCB, 0xC9, 0x32, 0xC4, 0xCB, 0xC2, 0x18, 0xC2, 0x18, 0xC2, +0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x98, 0xC5, 0xCB, 0xC9, 0x18, 0xD0, +0x65, 0xD6, 0x18, 0xDE, 0xCB, 0xE5, 0x7F, 0xED, 0x32, 0xF5, 0xE5, 0xFC, 0x4A, 0x05, 0x97, 0x0B, +0x97, 0x12, 0x31, 0x18, 0x7E, 0x1E, 0xB1, 0x22, 0xE4, 0x26, 0xB1, 0x29, 0x7E, 0x2C, 0x31, 0x2D, +0x97, 0x2E, 0xE4, 0x2D, 0xE4, 0x2D, 0xCA, 0x2B, 0xB1, 0x29, 0x31, 0x26, 0x64, 0x23, 0x7E, 0x1E, +0x4A, 0x1A, 0xB1, 0x14, 0x17, 0x0F, 0xCA, 0x08, 0x7E, 0x02, 0x32, 0xFC, 0x98, 0xF6, 0xE5, 0xEE, +0xE5, 0xE7, 0xE5, 0xE0, 0x98, 0xDA, 0x65, 0xD6, 0x32, 0xD2, 0xFF, 0xCD, 0xCB, 0xC9, 0x98, 0xC5, +0x18, 0xC2, 0x18, 0xC2, 0x18, 0xC2, 0x32, 0xC4, 0xFF, 0xC6, 0xCB, 0xC9, 0x98, 0xCC, 0x32, 0xD2, +0x7F, 0xD8, 0xE5, 0xE0, 0xFF, 0xE9, 0x65, 0xF2, 0xCB, 0xFA, 0x31, 0x03, 0x97, 0x0B, 0xFE, 0x13, +0x64, 0x1C, 0x64, 0x23, 0x17, 0x2B, 0x97, 0x2E, 0x17, 0x32, 0x31, 0x34, 0x4A, 0x36, 0x4A, 0x36, +0x4A, 0x36, 0xCA, 0x32, 0x4A, 0x2F, 0x64, 0x2A, 0x7E, 0x25, 0xE4, 0x1F, 0x4A, 0x1A, 0x4A, 0x13, +0x4A, 0x0C, 0x4A, 0x05, 0x4B, 0xFE, 0xFF, 0xF7, 0x65, 0xF2, 0xCB, 0xEC, 0x32, 0xE7, 0xFF, 0xE2, +0xCB, 0xDE, 0x4B, 0xDB, 0xCB, 0xD7, 0xFF, 0xD4, 0xE5, 0xD2, 0x7F, 0xD1, 0x18, 0xD0, 0x18, 0xD0, +0xCB, 0xD0, 0x32, 0xD2, 0x98, 0xD3, 0x65, 0xD6, 0x32, 0xD9, 0x18, 0xDE, 0xFF, 0xE2, 0x4B, 0xE9, +0x98, 0xEF, 0x98, 0xF6, 0x4B, 0xFE, 0xB1, 0x06, 0x17, 0x0F, 0x7E, 0x17, 0xE4, 0x1F, 0x31, 0x26, +0x31, 0x2D, 0x64, 0x31, 0x4A, 0x36, 0x64, 0x38, 0x7E, 0x3A, 0x17, 0x39, 0x64, 0x38, 0x7E, 0x33, +0x97, 0x2E, 0x97, 0x27, 0x4A, 0x21, 0x97, 0x19, 0xE4, 0x11, 0xCA, 0x08, 0xB2, 0xFF, 0x4B, 0xF7, +0xE5, 0xEE, 0xE5, 0xE7, 0x98, 0xE1, 0xB2, 0xDC, 0xCB, 0xD7, 0xB2, 0xD5, 0x98, 0xD3, 0x98, 0xD3, +0x98, 0xD3, 0xFF, 0xD4, 0x65, 0xD6, 0x32, 0xD9, 0xFF, 0xDB, 0x7F, 0xDF, 0xFF, 0xE2, 0x7F, 0xE6, +0xB2, 0xEA, 0xE5, 0xEE, 0xCB, 0xF3, 0xB2, 0xF8, 0x98, 0xFD, 0x7E, 0x02, 0x17, 0x08, 0xB1, 0x0D, +0xFE, 0x13, 0x4A, 0x1A, 0x97, 0x20, 0x7E, 0x25, 0x17, 0x2B, 0x4A, 0x2F, 0x31, 0x34, 0x4A, 0x36, +0x64, 0x38, 0xFE, 0x36, 0x4A, 0x36, 0x17, 0x32, 0xE4, 0x2D, 0xE4, 0x26, 0xE4, 0x1F, 0x17, 0x16, +0x4A, 0x0C, 0xCA, 0x01, 0xFF, 0xF7, 0x32, 0xEE +}; diff --git a/src/global.h b/src/global.h new file mode 100644 index 000000000..1b510558f --- /dev/null +++ b/src/global.h @@ -0,0 +1,90 @@ +#ifndef __neutrino_global_h__ +#define __neutrino_global_h__ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include + +#include +#include +#include + +#include "driver/fontrenderer.h" +#include "driver/rcinput.h" +#include "driver/vfd.h" +#include "driver/rfmod.h" + +#include "system/localize.h" +#include "system/settings.h" + +#include "gui/epgview.h" +#include "gui/infoviewer.h" +#include "gui/eventlist.h" + +#ifndef NEUTRINO_CPP + #define NEUTRINO_CPP extern +#endif + +#define NEUTRINO_SETTINGS_FILE CONFIGDIR "/neutrino.conf" + +#define NEUTRINO_RECORDING_TIMER_SCRIPT CONFIGDIR "/recording.timer" +#define NEUTRINO_RECORDING_START_SCRIPT CONFIGDIR "/recording.start" +#define NEUTRINO_RECORDING_ENDED_SCRIPT CONFIGDIR "/recording.end" +#define NEUTRINO_ENTER_STANDBY_SCRIPT CONFIGDIR "/standby.on" +#define NEUTRINO_LEAVE_STANDBY_SCRIPT CONFIGDIR "/standby.off" + +#define NEUTRINO_SCAN_SETTINGS_FILE CONFIGDIR "/scan.conf" +#define NEUTRINO_PARENTALLOCKED_FILE DATADIR "/neutrino/.plocked" + +NEUTRINO_CPP SNeutrinoSettings g_settings; +NEUTRINO_CPP SglobalInfo g_info; + +NEUTRINO_CPP CControldClient *g_Controld; +NEUTRINO_CPP CZapitClient *g_Zapit; +NEUTRINO_CPP CSectionsdClient *g_Sectionsd; +NEUTRINO_CPP CTimerdClient *g_Timerd; + +NEUTRINO_CPP FBFontRenderClass *g_fontRenderer; + +NEUTRINO_CPP Font * g_Font[FONT_TYPE_COUNT]; +NEUTRINO_CPP Font * g_SignalFont; + +NEUTRINO_CPP CRCInput *g_RCInput; + +NEUTRINO_CPP CEpgData *g_EpgData; +NEUTRINO_CPP CInfoViewer *g_InfoViewer; +NEUTRINO_CPP EventList *g_EventList; + +NEUTRINO_CPP CLocaleManager *g_Locale; +NEUTRINO_CPP RFmod *g_RFmod; + +#endif /* __neutrino_global_h__ */ diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am new file mode 100644 index 000000000..c41ccff4a --- /dev/null +++ b/src/gui/Makefile.am @@ -0,0 +1,37 @@ +AM_CPPFLAGS = -fno-rtti -fno-exceptions +#AM_CPPFLAGS = -fno-rtti + +SUBDIRS = widget bedit + +INCLUDES = \ + -I$(top_srcdir)/daemons \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/libeventserver \ + -I$(top_srcdir)/lib/libnet \ + -I$(top_srcdir)/lib/libconfigfile \ + -I$(top_srcdir)/lib/xmltree \ + -I$(top_srcdir)/lib/libcoolstream \ + -I$(top_srcdir)/lib/libupnpclient \ + @CURL_CFLAGS@ \ + @FREETYPE_CFLAGS@ \ + -I$(top_srcdir)/lib + +noinst_LIBRARIES = libtimerlist.a libneutrino_gui.a libneutrino_gui2.a + +libneutrino_gui_a_SOURCES = \ + bouquetlist.cpp channellist.cpp eventlist.cpp pluginlist.cpp \ + favorites.cpp sleeptimer.cpp screensetup.cpp \ + epgview.cpp infoviewer.cpp scan.cpp update.cpp \ + filebrowser.cpp audioplayer.cpp nfs.cpp pictureviewer.cpp \ + movieplayer.cpp rc_lock.cpp bookmarkmanager.cpp \ + timeosd.cpp epgplus.cpp epg_menu.cpp \ + streaminfo2.cpp dboxinfo.cpp \ + plugins.cpp imageinfo.cpp audio_select.cpp moviebrowser.cpp movieinfo.cpp + +libneutrino_gui2_a_SOURCES = \ + color.cpp alphasetup.cpp motorcontrol.cpp scale.cpp hdd_menu.cpp cam_menu.cpp infoclock.cpp upnpbrowser.cpp + +libtimerlist_a_SOURCES = \ + timerlist.cpp + diff --git a/src/gui/alphasetup.cpp b/src/gui/alphasetup.cpp new file mode 100644 index 000000000..621cb213a --- /dev/null +++ b/src/gui/alphasetup.cpp @@ -0,0 +1,272 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define ALPHA_SETUP_ICON_DESELECTED "volumeslider2.raw" +#define ALPHA_SETUP_ICON_ALPHA1_SELECTED "volumeslider2red.raw" +#define ALPHA_SETUP_ICON_ALPHA2_SELECTED "volumeslider2green.raw" + + +CAlphaSetup::CAlphaSetup(const neutrino_locale_t Name, unsigned char* Alpha1, unsigned char* Alpha2, CChangeObserver* Observer) +{ + frameBuffer = CFrameBuffer::getInstance(); + observer = Observer; + name = Name; + + + alpha1 = Alpha1; + alpha2 = Alpha2; + //frameBuffer->setBlendLevel(*alpha1, *alpha2); //FIXME until blend works +} + +int CAlphaSetup::exec(CMenuTarget* parent, const std::string &) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + width = w_max(360, 0); + + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + + height = hheight+ mheight*3; + + x = frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth()-width) >> 1); + y = frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight()-height) >> 1); + + int res = menu_return::RETURN_REPAINT; + if (parent) + { + parent->hide(); + } + unsigned char alpha1_alt= *alpha1; + unsigned char alpha2_alt= *alpha2; + + frameBuffer->setBlendLevel(*alpha1, *alpha2); + paint(); + + int selected = 0; + int max = 1; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + bool loop=true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd, true ); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + switch ( msg ) + { +#if 0 + case CRCInput::RC_down: + { + if(selected 0) + { + paintSlider(x + 10, y + hheight , alpha1, LOCALE_GTXALPHA_ALPHA1, ALPHA_SETUP_ICON_DESELECTED , false); + paintSlider(x + 10, y + hheight + mheight, alpha2, LOCALE_GTXALPHA_ALPHA2, ALPHA_SETUP_ICON_DESELECTED , false); + + selected--; + + switch (selected) + { + case 0: + paintSlider(x + 10, y + hheight , alpha1, LOCALE_GTXALPHA_ALPHA1, ALPHA_SETUP_ICON_ALPHA1_SELECTED, true ); + break; + case 1: + paintSlider(x + 10, y + hheight + mheight, alpha2, LOCALE_GTXALPHA_ALPHA2, ALPHA_SETUP_ICON_ALPHA2_SELECTED, true ); + break; + } + } + break; + } +#endif + case CRCInput::RC_right: + { + switch (selected) + { + case 0: + if (*alpha1 < 255) { + *alpha1+= 0x10; + paintSlider(x + 10, y + hheight , alpha1, LOCALE_GTXALPHA_ALPHA1, ALPHA_SETUP_ICON_ALPHA1_SELECTED, true ); + frameBuffer->setBlendLevel(*alpha1, *alpha2); + } + break; + case 1: + if (*alpha2 < 255) { + *alpha2 += 0x10; + paintSlider(x + 10, y + hheight + mheight, alpha2, LOCALE_GTXALPHA_ALPHA2, ALPHA_SETUP_ICON_ALPHA2_SELECTED, true ); + frameBuffer->setBlendLevel(*alpha1, *alpha2); + } + break; + } + break; + } + case CRCInput::RC_left: + { + switch (selected) + { + case 0: + if (*alpha1 >= 0x10) { + *alpha1 -= 0x10; + paintSlider(x + 10, y + hheight , alpha1, LOCALE_GTXALPHA_ALPHA1, ALPHA_SETUP_ICON_ALPHA1_SELECTED, true ); + frameBuffer->setBlendLevel(*alpha1, *alpha2); + } + break; + case 1: + if (*alpha2 >= 0x10) { + *alpha2 -= 0x10; + paintSlider(x + 10, y + hheight + mheight, alpha2, LOCALE_GTXALPHA_ALPHA2, ALPHA_SETUP_ICON_ALPHA2_SELECTED, true ); + frameBuffer->setBlendLevel(*alpha1, *alpha2); + } + break; + } + break; + } + case CRCInput::RC_favorites: + case CRCInput::RC_sat: + break; + case CRCInput::RC_home: + if ((*alpha1 != alpha1_alt) || (*alpha2 != alpha2_alt)) + { + if (ShowLocalizedMessage(name, LOCALE_MESSAGEBOX_DISCARD, CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbCancel) == CMessageBox::mbrCancel) + { + break; + } + } + + // sonst abbruch... + *alpha1 = alpha1_alt; + *alpha2 = alpha2_alt; + + case CRCInput::RC_timeout: + case CRCInput::RC_ok: + loop = false; + break; + + default: + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + + hide(); + + if(observer) + observer->changeNotify(name, NULL); + + return res; +} + +void CAlphaSetup::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height); +} + +void CAlphaSetup::paint() +{ + frameBuffer->paintBoxRel(x,y, width,hheight, COL_MENUHEAD_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10,y+hheight, width, g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + frameBuffer->paintBoxRel(x,y+hheight, width,height-hheight, COL_MENUCONTENT_PLUS_0); + + paintSlider(x + 10, y + hheight , alpha1, LOCALE_GTXALPHA_ALPHA1, ALPHA_SETUP_ICON_ALPHA1_SELECTED, true ); + //paintSlider(x + 10, y + hheight + mheight, alpha2, LOCALE_GTXALPHA_ALPHA2, ALPHA_SETUP_ICON_DESELECTED , false); +} + +void CAlphaSetup::paintSlider(const int x, const int y, const unsigned char * const spos, const neutrino_locale_t text, const char * const iconname, const bool selected) // UTF-8 +{ + if (!spos) + return; + + int sspos = (*spos)*100/255; + + frameBuffer->paintBoxRel(x+70,y,120,mheight, COL_MENUCONTENT_PLUS_0); + + frameBuffer->paintIcon("volumebody.raw", x + 70 , y + 2 + mheight / 4); + frameBuffer->paintIcon(iconname , x + 73 + sspos, y + mheight / 4); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x,y+mheight, width, g_Locale->getText(text), COL_MENUCONTENT, 0, true); // UTF-8 +} diff --git a/src/gui/alphasetup.h b/src/gui/alphasetup.h new file mode 100644 index 000000000..3631dadaa --- /dev/null +++ b/src/gui/alphasetup.h @@ -0,0 +1,78 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __alphasetup__ +#define __alphasetup__ + + +#include "widget/menue.h" + +#include +#include + +#include + + +class CAlphaSetup : public CMenuTarget +{ + private: + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hheight,mheight; // head/menu font height + + unsigned char *alpha1; + unsigned char *alpha2; + + + neutrino_locale_t name; + + CChangeObserver* observer; + + void paint(); + void setAlpha(); + void paintSlider(const int x, const int y, const unsigned char * const spos, const neutrino_locale_t text, const char * const iconname, const bool selected); + + public: + + CAlphaSetup(const neutrino_locale_t Name, unsigned char* Alpha1, unsigned char* Alpha2, CChangeObserver* Observer = NULL); + + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); + +}; + + +#endif + diff --git a/src/gui/audio_select.cpp b/src/gui/audio_select.cpp new file mode 100644 index 000000000..4eef30449 --- /dev/null +++ b/src/gui/audio_select.cpp @@ -0,0 +1,131 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include +#include +#include +#include + +extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ +extern CAPIDChangeExec * APIDChanger; +extern CAudioSetupNotifier * audioSetupNotifier; +int dvbsub_getpid(); + +#include + +// +// -- AUDIO Selector Menue Handler Class +// -- to be used for calls from Menue +// -- (2005-08-31 rasc) +// + +// -- this is a copy from neutrino.cpp!! +#define AUDIOMENU_ANALOGOUT_OPTION_COUNT 3 +const CMenuOptionChooser::keyval AUDIOMENU_ANALOGOUT_OPTIONS[AUDIOMENU_ANALOGOUT_OPTION_COUNT] = +{ + { 0, LOCALE_AUDIOMENU_STEREO }, + { 1, LOCALE_AUDIOMENU_MONOLEFT }, + { 2, LOCALE_AUDIOMENU_MONORIGHT } +}; + +int CAudioSelectMenuHandler::exec(CMenuTarget* parent, const std::string &actionkey) +{ + int res = menu_return::RETURN_EXIT_ALL; + + + if (parent) { + parent->hide(); + } + + doMenu (); + return res; +} + +int CAudioSelectMenuHandler::doMenu () +{ + CMenuWidget AudioSelector(LOCALE_APIDSELECTOR_HEAD, "audio.raw", 360); + unsigned int count; + CSubtitleChangeExec SubtitleChanger; + + for(count=0; count < g_RemoteControl->current_PIDs.APIDs.size(); count++ ) { + char apid[5]; + sprintf(apid, "%d", count); + AudioSelector.addItem(new CMenuForwarderNonLocalized( + g_RemoteControl->current_PIDs.APIDs[count].desc, true, NULL, + APIDChanger, apid, CRCInput::convertDigitToKey(count + 1)), + (count == g_RemoteControl->current_PIDs.PIDs.selected_apid)); + } + + // -- setup menue for to Dual Channel Stereo + AudioSelector.addItem(GenericMenuSeparatorLine); + + CMenuOptionChooser* oj = new CMenuOptionChooser(LOCALE_AUDIOMENU_ANALOGOUT, + &g_settings.audio_AnalogMode, + AUDIOMENU_ANALOGOUT_OPTIONS, AUDIOMENU_ANALOGOUT_OPTION_COUNT, + true, audioSetupNotifier, CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED); + + AudioSelector.addItem( oj ); + + CChannelList *channelList = CNeutrinoApp::getInstance ()->channelList; + int curnum = channelList->getActiveChannelNumber(); + CZapitChannel * cc = channelList->getChannel(curnum); + + bool sep_added = false; + if(cc) { + for (int i = 0 ; i < (int)cc->getSubtitleCount() ; ++i) { + CZapitAbsSub* s = cc->getChannelSub(i); + CZapitDVBSub* sd = reinterpret_cast(s); + CZapitTTXSub* st = reinterpret_cast(s); + printf("[neutrino] adding subtitle %s pid %x\n", sd->ISO639_language_code.c_str(), sd->pId); + if (s->thisSubType == CZapitAbsSub::DVB) { + if(!sep_added) { + sep_added = true; + AudioSelector.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_SUBTITLES_HEAD)); + } + char spid[5]; + sprintf(spid, "%d", sd->pId); + AudioSelector.addItem(new CMenuForwarderNonLocalized(sd->ISO639_language_code.c_str(), + sd->pId != dvbsub_getpid(), NULL, &SubtitleChanger, spid, CRCInput::convertDigitToKey(++count))); + } + } + if(sep_added) { + AudioSelector.addItem(new CMenuForwarder(LOCALE_SUBTITLES_STOP, true, NULL, &SubtitleChanger, "off")); + } + + } + + return AudioSelector.exec(NULL, ""); +} diff --git a/src/gui/audio_select.h b/src/gui/audio_select.h new file mode 100644 index 000000000..f2700a4f6 --- /dev/null +++ b/src/gui/audio_select.h @@ -0,0 +1,47 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __audio_selector__ +#define __audio_selector__ + +// +// -- Audio Channel Selector Menue +// -- 2005-08-31 rasc +// + +#include "widget/menue.h" + + + +using namespace std; + +class CAudioSelectMenuHandler : public CMenuTarget +{ + public: + int exec( CMenuTarget* parent, const std::string &actionkey); + int doMenu(); + +}; + + +#endif + diff --git a/src/gui/audioplayer.cpp b/src/gui/audioplayer.cpp new file mode 100644 index 000000000..f0bdc5721 --- /dev/null +++ b/src/gui/audioplayer.cpp @@ -0,0 +1,2882 @@ +/* + $Id: audioplayer.cpp,v 1.80 2009/10/18 14:38:03 dbt Exp $ + Neutrino-GUI - DBoxII-Project + + AudioPlayer by Dirch,Zwen + + (C) 2002-2008 the tuxbox project contributors + (C) 2008 Novell, Inc. Author: Stefan Seyfried + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#ifdef ENABLE_GUI_MOUNT +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#if 0 +#ifdef ENABLE_LIRC +#include +#endif + +#if HAVE_DVB_API_VERSION >= 3 +#include +#include +#include +#define ADAP "/dev/dvb/adapter0" +#define ADEC ADAP "/audio0" +#define VDEC ADAP "/video0" +#define DMX ADAP "/demux0" +#define DVR ADAP "/dvr0" +#endif +#endif + +#include +extern cVideo * videoDecoder; + +#ifdef ConnectLineBox_Width +#undef ConnectLineBox_Width +#endif +#define ConnectLineBox_Width 16 + +#define AUDIOPLAYERGUI_SMSKEY_TIMEOUT 1000 +#define SHOW_FILE_LOAD_LIMIT 50 + +//#define AUDIOPLAYER_TIME_DEBUG + +// check if files to be added are already in the playlist +#define AUDIOPLAYER_CHECK_FOR_DUPLICATES +#define AUDIOPLAYER_START_SCRIPT CONFIGDIR "/audioplayer.start" +#define AUDIOPLAYER_END_SCRIPT CONFIGDIR "/audioplayer.end" +#define DEFAULT_RADIOSTATIONS_XMLFILE CONFIGDIR "/radio-stations.xml" + +const long int GET_PLAYLIST_TIMEOUT = 10; +const char RADIO_STATION_XML_FILE[] = {DEFAULT_RADIOSTATIONS_XMLFILE}; + +const std::string icecasturl = "http://dir.xiph.org/yp.xml"; +const long int GET_ICECAST_TIMEOUT = 90; // list is about 500kB! + +CAudiofileExt::CAudiofileExt() +: CAudiofile(), firstChar('\0') +{ +} + +CAudiofileExt::CAudiofileExt(std::string name, CFile::FileType type) +: CAudiofile(name, type), firstChar('\0') +{ +} + +CAudiofileExt::CAudiofileExt(const CAudiofileExt& src) +: CAudiofile(src), firstChar(src.firstChar) +{ +} + +void CAudiofileExt::operator=(const CAudiofileExt& src) +{ + if (&src == this) + return; + CAudiofile::operator=(src); + firstChar = src.firstChar; +} + + +//------------------------------------------------------------------------ + + + +#include +#include +#include + +struct MemoryStruct { + char *memory; + size_t size; +}; + +static void *myrealloc(void *ptr, size_t size) +{ + /* There might be a realloc() out there that doesn't like reallocing + NULL pointers, so we take care of it here */ + if(ptr) + return realloc(ptr, size); + else + return malloc(size); +} + +static size_t +WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) +{ + size_t realsize = size * nmemb; + struct MemoryStruct *mem = (struct MemoryStruct *)data; + + mem->memory = (char *)myrealloc(mem->memory, mem->size + realsize + 1); + if (mem->memory) { + memcpy(&(mem->memory[mem->size]), ptr, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + } + return realsize; +} + +// we borrow this from filebrowser +extern size_t CurlWriteToString(void *ptr, size_t size, size_t nmemb, void *data); + +CAudioPlayerGui::CAudioPlayerGui(bool inetmode) +{ + m_frameBuffer = CFrameBuffer::getInstance(); + m_visible = false; + m_inetmode = false; //inetmode;//FIXME + + Init(); +} + +void CAudioPlayerGui::Init(void) +{ + stimer = 0; + m_selected = 0; + m_metainfo.clear(); + + m_select_title_by_name = g_settings.audioplayer_select_title_by_name==1; + + if(strlen(g_settings.network_nfs_audioplayerdir)!=0) + m_Path = g_settings.network_nfs_audioplayerdir; + else + m_Path = "/"; + + audiofilefilter.Clear(); + if (m_inetmode) { + audiofilefilter.addFilter("url"); + audiofilefilter.addFilter("xml"); + audiofilefilter.addFilter("m3u"); + audiofilefilter.addFilter("pls"); + } else { + audiofilefilter.addFilter("cdr"); + audiofilefilter.addFilter("mp3"); + audiofilefilter.addFilter("m2a"); + audiofilefilter.addFilter("mpa"); + audiofilefilter.addFilter("mp2"); + audiofilefilter.addFilter("m3u"); + audiofilefilter.addFilter("ogg"); + audiofilefilter.addFilter("wav"); +#ifdef ENABLE_FLAC + audiofilefilter.addFilter("flac"); +#endif + } + m_SMSKeyInput.setTimeout(AUDIOPLAYERGUI_SMSKEY_TIMEOUT); +} + +//------------------------------------------------------------------------ + +CAudioPlayerGui::~CAudioPlayerGui() +{ + m_playlist.clear(); + m_radiolist.clear(); + m_filelist.clear(); + m_title2Pos.clear(); + g_Zapit->setStandby (false); + g_Sectionsd->setPauseScanning (false); +} + +//------------------------------------------------------------------------ +int CAudioPlayerGui::exec(CMenuTarget* parent, const std::string &) +{ + CAudioPlayer::getInstance()->init(); + m_state = CAudioPlayerGui::STOP; + + m_show_playlist = g_settings.audioplayer_show_playlist==1; + + if (m_select_title_by_name != (g_settings.audioplayer_select_title_by_name==1)) + { + if ((g_settings.audioplayer_select_title_by_name == 1) + && m_playlistHasChanged) + { + buildSearchTree(); + } + m_select_title_by_name = g_settings.audioplayer_select_title_by_name; + } + + if (m_playlist.empty()) + m_current = -1; + else + m_current = 0; + + m_selected = 0; + //m_width = 710; + //if((g_settings.screen_EndX - g_settings.screen_StartX) < m_width+ConnectLineBox_Width) + m_width=(g_settings.screen_EndX - g_settings.screen_StartX) - ConnectLineBox_Width - 5; + //m_height = 570; + //if((g_settings.screen_EndY - g_settings.screen_StartY) < m_height) + m_height = (g_settings.screen_EndY - g_settings.screen_StartY - 5); + m_sheight = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight(); + m_buttonHeight = std::min(25, m_sheight); + m_theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + m_fheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + m_title_height = m_fheight*2 + 20 + m_sheight + 4; + m_info_height = m_fheight*2; + m_listmaxshow = (m_height - m_info_height - m_title_height - m_theight - 2*m_buttonHeight) / (m_fheight); + m_height = m_theight + m_info_height + m_title_height + 2*m_buttonHeight + m_listmaxshow * m_fheight; // recalc height + + m_x = (((g_settings.screen_EndX - g_settings.screen_StartX) - (m_width + ConnectLineBox_Width)) / 2) + + g_settings.screen_StartX + ConnectLineBox_Width; + m_y = (((g_settings.screen_EndY- g_settings.screen_StartY) - m_height)/ 2) + g_settings.screen_StartY; + m_idletime=time(NULL); + m_screensaver=false; + + if(parent) + { + parent->hide(); + } +#if 0 + if(g_settings.video_Format != g_settings.video_backgroundFormat) + g_Controld->setVideoFormat(g_settings.video_backgroundFormat); +#endif + bool usedBackground = m_frameBuffer->getuseBackground(); + if (usedBackground) + m_frameBuffer->saveBackgroundImage(); + + + // set zapit in standby mode + g_Zapit->stopPlayBack(); + + videoDecoder->ShowPicture(DATADIR "/neutrino/icons/mp3.jpg"); + + // tell neutrino we're in audio mode + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , NeutrinoMessages::mode_audio ); +#if 0 + // remember last mode + CZapitClient::responseGetLastChannel firstchannel; + g_Zapit->getLastChannel(firstchannel.channelNumber, firstchannel.mode); + if ((firstchannel.mode == 'r') ? + (CNeutrinoApp::getInstance()->zapto_radio_on_init_done) : + (CNeutrinoApp::getInstance()->zapto_tv_on_init_done)) + m_LastMode=(CNeutrinoApp::getInstance()->getLastMode() | NeutrinoMessages::norezap); + else + m_LastMode=(CNeutrinoApp::getInstance()->getLastMode()); +#endif + m_LastMode=(CNeutrinoApp::getInstance()->getLastMode()); + // Stop sectionsd + g_Sectionsd->setPauseScanning(true); + + puts("[audioplayer.cpp] executing " AUDIOPLAYER_START_SCRIPT "."); + if (system(AUDIOPLAYER_START_SCRIPT) != 0) + perror("Datei " AUDIOPLAYER_START_SCRIPT " fehlt.Bitte erstellen, wenn gebraucht.\nFile " AUDIOPLAYER_START_SCRIPT " not found. Please create if needed.\n"); + + show(); + + // Restore previous background + if (usedBackground) + m_frameBuffer->restoreBackgroundImage(); + m_frameBuffer->useBackground(usedBackground); + m_frameBuffer->paintBackground(); + + // Restore last mode + //t_channel_id channel_id=CNeutrinoApp::getInstance()->channelList->getActiveChannel_ChannelID(); + //g_Zapit->zapTo_serviceID(channel_id); + //g_Zapit->setStandby(false); + + puts("[audioplayer.cpp] executing " AUDIOPLAYER_END_SCRIPT "."); + if (system(AUDIOPLAYER_END_SCRIPT) != 0) + perror("Datei " AUDIOPLAYER_END_SCRIPT " fehlt. Bitte erstellen, wenn gebraucht.\nFile " AUDIOPLAYER_END_SCRIPT " not found. Please create if needed.\n"); + + // Start Sectionsd + g_Sectionsd->setPauseScanning(false); + videoDecoder->StopPicture(); + + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , m_LastMode ); + g_RCInput->postMsg( NeutrinoMessages::SHOW_INFOBAR, 0 ); + + // always exit all + return menu_return::RETURN_EXIT_ALL; +} + +//------------------------------------------------------------------------ + +int CAudioPlayerGui::show() +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int pic_index = 0; + + int ret = -1; + + CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); + paintLCD(); + + bool loop = true; + bool update = true; + bool clear_before_update = false; + m_key_level = 0; + + while(loop) + { + if(!m_screensaver) + { + updateMetaData(); + } + updateTimes(); + + if(CNeutrinoApp::getInstance()->getMode() != NeutrinoMessages::mode_audio) + { + // stop if mode was changed in another thread + loop = false; + } + if ((m_state != CAudioPlayerGui::STOP) && + (CAudioPlayer::getInstance()->getState() == CBaseDec::STOP) && + (!m_playlist.empty())) + { + if(m_curr_audiofile.FileType != CFile::STREAM_AUDIO) + playNext(); + } + + if (update) + { + if(clear_before_update) + { + hide(); + clear_before_update = false; + } + update = false; + paint(); + } + g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display + + if( msg == CRCInput::RC_timeout || msg == NeutrinoMessages::EVT_TIMER) + { + int timeout = time(NULL) - m_idletime; + int screensaver_timeout = atoi(g_settings.audioplayer_screensaver); + if(screensaver_timeout !=0 && timeout > screensaver_timeout*60 && !m_screensaver) + screensaver(true); + + if(msg == NeutrinoMessages::EVT_TIMER && data == stimer) { + if(m_screensaver) { + char fname[255]; + + sprintf(fname, "%s/mp3-%d.jpg", DATADIR "/neutrino/icons", pic_index); + + int ret = access(fname, F_OK); + printf("CAudioPlayerGui::show: new pic %s: %s\n", fname, ret ? "not found" : "found"); + if(ret == 0) { + pic_index++; + videoDecoder->StopPicture(); + videoDecoder->ShowPicture(fname); + } else if(pic_index) { + pic_index = 0; + videoDecoder->StopPicture(); + videoDecoder->ShowPicture(DATADIR "/neutrino/icons/mp3.jpg"); + } + } else + pic_index = 0; + } + + } + else + { + m_idletime = time(NULL); + if(m_screensaver) + { + screensaver(false); + } + } + + if( msg == CRCInput::RC_tv) + { + if(m_inetmode) { + m_inetmode = false; + m_radiolist = m_playlist; + m_playlist = m_filelist; + } else { + m_inetmode = true; + m_filelist = m_playlist; + m_playlist = m_radiolist; + } + Init(); + clear_before_update = true; + update = true; + } + else if (msg == CRCInput::RC_home) + { + if (m_state != CAudioPlayerGui::STOP) + stop(); + else + loop=false; + } + else if (msg == CRCInput::RC_left) + { + if (m_key_level == 1) + { + playPrev(); + } + else + { + if (!m_show_playlist) + { + m_current--; + if (m_current < 0) + m_current = m_playlist.size()-1; + update = true; + } + else if (!m_playlist.empty()) + { + if (m_selected < m_listmaxshow) + { + m_selected = m_playlist.size()-1; + } + else + m_selected -= m_listmaxshow; + m_liststart = (m_selected / m_listmaxshow) * m_listmaxshow; + update = true; + } + } + + } + else if (msg == CRCInput::RC_right) + { + if (m_key_level == 1) + { + playNext(); + } + else + { + if (!m_show_playlist) + { + m_current++; + if (m_current >= (int)m_playlist.size()) + m_current = 0; + update = true; + } + else if (!m_playlist.empty()) + { + m_selected += m_listmaxshow; + if (m_selected >= m_playlist.size()) { + if (((m_playlist.size() / m_listmaxshow) + 1) * m_listmaxshow == m_playlist.size() + m_listmaxshow) + m_selected = 0; + else + m_selected = m_selected < (((m_playlist.size() / m_listmaxshow) + 1) * m_listmaxshow) ? (m_playlist.size()-1) : 0; + } + m_liststart = (m_selected / m_listmaxshow) * m_listmaxshow; + update = true; + } + } + } + else if((msg &~ CRCInput::RC_Repeat) == CRCInput::RC_up || (msg &~ CRCInput::RC_Repeat) == CRCInput::RC_page_up) + { + if(m_show_playlist && !m_playlist.empty() ) + { + int step = 0; + int prevselected = m_selected; + + step = msg == CRCInput::RC_page_up ? m_listmaxshow : 1; + m_selected -= step; + if((prevselected-step) < 0) + m_selected = m_playlist.size()-1; +#if 0 + if(m_selected == 0) + { + m_selected = m_playlist.size()-1; + } + else + { + m_selected--; + } +#endif + paintItem(prevselected - m_liststart); + unsigned int oldliststart = m_liststart; + m_liststart = (m_selected/m_listmaxshow)*m_listmaxshow; + if(oldliststart != m_liststart) + { + update = true; + } + else + { + paintItem(m_selected - m_liststart); + } + } + } + else if((msg &~ CRCInput::RC_Repeat) == CRCInput::RC_down || (msg &~ CRCInput::RC_Repeat) == CRCInput::RC_page_down) + { + if(m_show_playlist && !m_playlist.empty() ) + { + int prevselected = m_selected; + int step = msg == CRCInput::RC_page_down ? m_listmaxshow : 1; + m_selected += step; + + if(m_selected >= m_playlist.size()) { + if (((m_playlist.size() / m_listmaxshow) + 1) * m_listmaxshow == m_playlist.size() + m_listmaxshow) // last page has full entries + m_selected = 0; + else + m_selected = ((step == m_listmaxshow) && (m_selected < (((m_playlist.size() / m_listmaxshow)+1) * m_listmaxshow))) ? (m_playlist.size() - 1) : 0; + } + //m_selected = (m_selected + 1) % m_playlist.size(); + + paintItem(prevselected - m_liststart); + unsigned int oldliststart = m_liststart; + m_liststart = (m_selected/m_listmaxshow)*m_listmaxshow; + if(oldliststart != m_liststart) + { + update = true; + } + else + { + paintItem(m_selected - m_liststart); + } + } + } + else if (msg == CRCInput::RC_ok || msg == CRCInput::RC_play) + { + if (!m_playlist.empty()) { + if (!m_show_playlist) + play(m_current); + else + play(m_selected); + } + } + else if (msg == CRCInput::RC_red) + { + if(m_key_level == 0) + { + if (!m_playlist.empty()) + { + //xx CPlayList::iterator p = m_playlist.begin()+selected; + removeFromPlaylist(m_selected); + if((int)m_selected == m_current) + { + m_current--; + //stop(); // Stop if song is deleted, next song will be startet automat. + } + if(m_selected >= m_playlist.size()) + m_selected = m_playlist.size() == 0 ? m_playlist.size() : m_playlist.size() - 1; + update = true; + } + } + else if(m_key_level == 1) + { + stop(); + } + else + { + // key_level==2 + } + + } + else if (msg == CRCInput::RC_stop) + { + if(m_key_level == 1) + stop(); + } + else if(msg == CRCInput::RC_green) + { + if (m_key_level == 0) + { + openFilebrowser(); + update=true; + } + else if (m_key_level == 1) + { + if(m_curr_audiofile.FileType != CFile::STREAM_AUDIO) + rev(); + } + else + { // key_level == 2 + + if(m_state == CAudioPlayerGui::STOP) + { + if (!m_playlist.empty()) + { + savePlaylist(); + CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); + paintLCD(); + update = true; + } + } + else + { + // keylevel 2 can only be reached if the currently played file + // is no stream, so we do not have to test for this case + int seconds=0; + CIntInput secondsInput(LOCALE_AUDIOPLAYER_JUMP_DIALOG_TITLE, + seconds, + 5, + LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT1, + LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT2); + int res = secondsInput.exec(NULL,""); + if (seconds != 0 && res!= menu_return::RETURN_EXIT_ALL) + rev(seconds); + update=true; + } + } + } + else if(msg == CRCInput::RC_yellow) + { + if(m_key_level == 0) + { + if (!m_playlist.empty()) + { + //stop(); + clearPlaylist(); + clear_before_update = true; + update = true; + } + } + else if(m_key_level == 1) + { + pause(); + } + else + { // key_level==2 + m_select_title_by_name =! m_select_title_by_name; + if (m_select_title_by_name && m_playlistHasChanged) + buildSearchTree(); + paint(); + } + } + else if(msg == CRCInput::RC_blue) + { + if (m_key_level == 0) + { + if (m_inetmode) { + static int old_select = 0; + char cnt[5]; + CMenuWidget InputSelector(LOCALE_AUDIOPLAYER_LOAD_RADIO_STATIONS, "audio.raw", 400); + int count = 0; + int select = -1; + CMenuSelectorTarget *InetRadioInputChanger = new CMenuSelectorTarget(&select); + // -- setup menue for inetradio input + sprintf(cnt, "%d", count); + InputSelector.addItem(new CMenuForwarder( + LOCALE_AUDIOPLAYER_ADD_LOC, true, NULL, InetRadioInputChanger, + cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count); + + sprintf(cnt, "%d", ++count); + InputSelector.addItem(new CMenuForwarder( + LOCALE_AUDIOPLAYER_ADD_SC, true, NULL, InetRadioInputChanger, + cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count); + + sprintf(cnt, "%d", ++count); + InputSelector.addItem(new CMenuForwarder( + LOCALE_AUDIOPLAYER_ADD_IC, true, NULL, InetRadioInputChanger, + cnt, CRCInput::convertDigitToKey(count + 1)), old_select == count); + + //InputSelector.addItem(GenericMenuSeparator); + hide(); + InputSelector.exec(NULL, ""); + if(select >= 0) + old_select = select; + switch (select) { + case 0: scanXmlFile(RADIO_STATION_XML_FILE); + CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); + paintLCD(); + break; + case 1: openSCbrowser(); + break; + case 2: readDir_ic(); + CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); + paintLCD(); + break; + default: break; + } + update=true; + } + else if ( shufflePlaylist() ) + { + update = true; + } + } + else if (m_key_level == 1) + { + if(m_curr_audiofile.FileType != CFile::STREAM_AUDIO) + ff(); + } + else // key_level == 2 + { + if (m_state != CAudioPlayerGui::STOP) + { + // keylevel 2 can only be reached if the currently played file + // is no stream, so we do not have to test for this case + int seconds=0; + CIntInput secondsInput(LOCALE_AUDIOPLAYER_JUMP_DIALOG_TITLE, + seconds, + 5, + LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT1, + LOCALE_AUDIOPLAYER_JUMP_DIALOG_HINT2); + int res = secondsInput.exec(NULL,""); + if (seconds != 0 && res!= menu_return::RETURN_EXIT_ALL) + ff(seconds); + update = true; + } + } + } + else if(msg == CRCInput::RC_help) + { + if (m_key_level == 2) + m_key_level = 0; + else + m_key_level++; + + if (m_state != CAudioPlayerGui::STOP) + { + // jumping in streams not supported + if (m_key_level == 2 && + m_curr_audiofile.FileType == CFile::STREAM_AUDIO) + { + m_key_level = 0; + } + } + // there are only two keylevels in the "STOP"-case + else if(m_key_level == 1) + { + m_key_level = 2; + } + paintFoot(); + } + else if(msg == CRCInput::RC_0) + { + if(m_current >= 0) + { + m_selected = m_current; + update = true; + } + } + else if (CRCInput::isNumeric(msg) && !(m_playlist.empty())) + { //numeric zap or SMS zap + if (m_select_title_by_name) + { + //printf("select by name\n"); + unsigned char smsKey = 0; + do + { + smsKey = m_SMSKeyInput.handleMsg(msg); + //printf(" new key: %c", smsKey); + g_RCInput->getMsg_ms(&msg, &data, AUDIOPLAYERGUI_SMSKEY_TIMEOUT - 200); + + +/* show a hint box with current char (too slow at the moment?)*/ +#if 1 + char selectedKey[1]; + sprintf(selectedKey,"%c",smsKey); + int x1=(g_settings.screen_EndX- g_settings.screen_StartX)/2 + g_settings.screen_StartX-50; + int y1=(g_settings.screen_EndY- g_settings.screen_StartY)/2 + g_settings.screen_StartY; + int h = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getHeight(); + int w = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getRenderWidth(selectedKey); + m_frameBuffer->paintBoxRel(x1 - 7, y1 - h - 5, w + 14, h + 10, COL_MENUCONTENT_PLUS_6); + m_frameBuffer->paintBoxRel(x1 - 4, y1 - h - 3, w + 8, h + 6, COL_MENUCONTENTSELECTED_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP] + ->RenderString(x1,y1,w+1,selectedKey,COL_MENUCONTENTSELECTED,0); +#endif + + } while (CRCInput::isNumeric(msg) && !(m_playlist.empty())); + + if (msg == CRCInput::RC_timeout + || msg == CRCInput::RC_nokey) + { + //printf("selected key: %c\n",smsKey); + selectTitle(smsKey); + update = true; + } + m_SMSKeyInput.resetOldKey(); + } + else + { + //printf("numeric zap\n"); + int val = 0; + if (getNumericInput(msg,val)) + m_selected = std::min((int)m_playlist.size(), val) - 1; + update = true; + } + + } + +#ifdef ENABLE_GUI_MOUNT + else if((msg == CRCInput::RC_setup) && !m_inetmode) + { + CNFSSmallMenu nfsMenu; + nfsMenu.exec(this, ""); + CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); + paintLCD(); + update = true; + //pushback key if... + //g_RCInput->postMsg( msg, data ); + //loop = false; + } +#endif + else if(msg == NeutrinoMessages::CHANGEMODE) + { + if((data & NeutrinoMessages::mode_mask) != NeutrinoMessages::mode_audio) + { + loop = false; + m_LastMode=data; + } + } + else if(msg == NeutrinoMessages::RECORD_START || + msg == NeutrinoMessages::ZAPTO || + msg == NeutrinoMessages::STANDBY_ON || + msg == NeutrinoMessages::SHUTDOWN || + msg == NeutrinoMessages::SLEEPTIMER) + { + // Exit for Record/Zapto Timers + loop = false; + g_RCInput->postMsg(msg, data); + } + else if(msg == NeutrinoMessages::EVT_TIMER) + { + CNeutrinoApp::getInstance()->handleMsg( msg, data ); + } + else + { + if( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + } + // update mute icon + //paintHead(); + //paintLCD(); + } + } + hide(); + + if(m_state != CAudioPlayerGui::STOP) + stop(); + + return ret; +} + +bool CAudioPlayerGui::playNext(bool allow_rotate) +{ + bool result = false; + + if (!(m_playlist.empty())) + { + int next = getNext(); + if(next >= 0) + play(next); + else if(allow_rotate) + play(0); + else + stop(); + result = true; + } + + return(result); +} + +bool CAudioPlayerGui::playPrev(bool allow_rotate) +{ + bool result = false; + + if (!(m_playlist.empty())) + { + if(m_current == -1) + stop(); + else if(m_current-1 > 0) + play(m_current-1); + else if(allow_rotate) + play(m_playlist.size()-1); + else + play(0); + result = true; + } + + return(result); +} + +bool CAudioPlayerGui::clearPlaylist(void) +{ + bool result = false; + + if (!(m_playlist.empty())) + { + m_playlist.clear(); + m_current = -1; + m_selected = 0; + m_title2Pos.clear(); + result = true; + } + return(result); +} + +bool CAudioPlayerGui::shufflePlaylist(void) +{ + RandomNumber rnd; + bool result = false; + if (!(m_playlist.empty())) + { + if (m_current > 0) + { + std::swap(m_playlist[0], m_playlist[m_current]); + m_current = 0; + } + + std::random_shuffle((m_current != 0) ? m_playlist.begin() : m_playlist.begin() + 1, m_playlist.end(), rnd); + if (m_select_title_by_name) + { + buildSearchTree(); + } + m_playlistHasChanged = true; + m_selected = 0; + + result = true; + } + return(result); +} + +void CAudioPlayerGui::addUrl2Playlist(const char *url, const char *name, const time_t bitrate) { + CAudiofileExt mp3( url, CFile::STREAM_AUDIO ); +// tmp = tmp.substr(0,tmp.length()-4); //remove .url +//printf("[addUrl2Playlist], name = %s, url = %s\n", name, url); + if (name != NULL) { + mp3.MetaData.title = name; + } else { + std::string tmp = mp3.Filename.substr(mp3.Filename.rfind('/')+1); + mp3.MetaData.title = tmp; + } + if (bitrate) + mp3.MetaData.total_time = bitrate; + else + mp3.MetaData.total_time = 0; + + if (url[0] != '#') { + addToPlaylist(mp3); + } +} + +void CAudioPlayerGui::processPlaylistUrl(const char *url, const char *name, const time_t tim) { + CURL *curl_handle; + struct MemoryStruct chunk; + +printf("CAudioPlayerGui::processPlaylistUrl (%s, %s)\n", url, name); + chunk.memory=NULL; /* we expect realloc(NULL, size) to work */ + chunk.size = 0; /* no data at this point */ + + curl_global_init(CURL_GLOBAL_ALL); + + /* init the curl session */ + curl_handle = curl_easy_init(); + + /* specify URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, url); + + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); + + /* some servers don't like requests that are made without a user-agent + field, so we provide one */ + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + /* don't use signal for timeout */ + curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, (long)1); + + /* set timeout to 10 seconds */ + curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, GET_PLAYLIST_TIMEOUT); + + /* get it! */ + curl_easy_perform(curl_handle); + + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + + /* + * Now, our chunk.memory points to a memory block that is chunk.size + * bytes big and contains the remote file. + * + * Do something nice with it! + * + * You should be aware of the fact that at this point we might have an + * allocated data block, and nothing has yet deallocated that data. So when + * you're done with it, you should free() it as a nice application. + */ + + long res_code; + if (curl_easy_getinfo(curl_handle, CURLINFO_HTTP_CODE/*CURLINFO_RESPONSE_CODE*/, &res_code ) == CURLE_OK) { + if (200 == res_code) { + //printf("\nchunk = %s\n", chunk.memory); + std::istringstream iss; + iss.str (std::string(chunk.memory, chunk.size)); + char line[512]; + char *ptr; + while (iss.rdstate() == std::ifstream::goodbit) { + iss.getline(line, 512); + if (line[0] != '#') { + //printf("chunk: line = %s\n", line); + ptr = strstr(line, "http://"); + if (ptr != NULL) { + char *tmp; + // strip \n and \r characters from url + tmp = strchr(line, '\r'); + if (tmp != NULL) + *tmp = '\0'; + tmp = strchr(line, '\n'); + if (tmp != NULL) + *tmp = '\0'; + addUrl2Playlist(ptr, name, tim); + } + } + } + } + } + + if(chunk.memory) + free(chunk.memory); + + /* we're done with libcurl, so clean it up */ + curl_global_cleanup(); +} + + +void CAudioPlayerGui::readDir_ic(void) +{ + std::string answer=""; + std::cout << "[readDir_ic] IC URL: " << icecasturl << std::endl; + CURL *curl_handle; + CURLcode httpres; + /* init the curl session */ + curl_handle = curl_easy_init(); + /* specify URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, icecasturl.c_str()); + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, CurlWriteToString); + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl_handle, CURLOPT_FILE, (void *)&answer); + /* Generate error if http error >= 400 occurs */ + curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1); + /* set timeout to 30 seconds */ + curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, GET_ICECAST_TIMEOUT); + + /* error handling */ + char error[CURL_ERROR_SIZE]; + curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error); + /* get it! */ + CHintBox *scanBox = new CHintBox(LOCALE_AUDIOPLAYER_ADD_IC, g_Locale->getText(LOCALE_AUDIOPLAYER_RECEIVING_LIST)); // UTF-8 + scanBox->paint(); + + httpres = curl_easy_perform(curl_handle); + + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + + //std::cout << "Answer:" << std::endl << "----------------" << std::endl << answer << std::endl; + + if (!answer.empty() && httpres == 0) + { + xmlDocPtr answer_parser = parseXml(answer.c_str()); + scanBox->hide(); + scanXmlData(answer_parser, "server_name", "listen_url", "bitrate", true); + } + else + scanBox->hide(); + + delete scanBox; +} + +void CAudioPlayerGui::scanXmlFile(std::string filename) +{ + xmlDocPtr answer_parser = parseXmlFile(filename.c_str()); + scanXmlData(answer_parser, "name", "url"); +} + +void CAudioPlayerGui::scanXmlData(xmlDocPtr answer_parser, const char *nametag, const char *urltag, + const char *bitratetag, bool usechild) +{ +#define IC_typetag "server_type" + + if (answer_parser != NULL) { + xmlNodePtr element = xmlDocGetRootElement(answer_parser); + element = element->xmlChildrenNode; + xmlNodePtr element_tmp = element; + if (element == NULL) { + printf("[openFilebrowser] No valid XML File.\n"); + } else { + CProgressWindow progress; + long maxProgress = 1; + // count # of entries + while (element) { + maxProgress++; + element = element->xmlNextNode; + } + element = element_tmp; + long listPos = -1; + progress.setTitle(LOCALE_AUDIOPLAYER_LOAD_RADIO_STATIONS); + progress.exec(this, ""); + neutrino_msg_t msg; + neutrino_msg_data_t data; + g_RCInput->getMsg(&msg, &data, 0); + while (element && msg != CRCInput::RC_home) { + char *ptr = NULL; + char *name = NULL; + char *url = NULL; + char *type = NULL; + time_t bitrate = 0; + bool skip = true; + listPos++; + // show status + int global = 100*listPos / maxProgress; + progress.showGlobalStatus(global); + #ifdef LCD_UPDATE + CVFD::getInstance()->showProgressBar(global, "read xmldata..."); + CVFD::getInstance()->setMode(CVFD::MODE_PROGRESSBAR); + #endif // LCD_UPDATE + + if (usechild) { + xmlNodePtr child = element->xmlChildrenNode; + while (child) { + if (strcmp(xmlGetName(child), nametag) == 0) + name = xmlGetData(child); + else if (strcmp(xmlGetName(child), urltag) == 0) + url = xmlGetData(child); + else if (strcmp(xmlGetName(child), IC_typetag) == 0) + type = xmlGetData(child); + else if (bitratetag && strcmp(xmlGetName(child), bitratetag) == 0) { + ptr = xmlGetData(child); + if (ptr) + bitrate = atoi(ptr); + } + child = child->xmlNextNode; + } + if (strcmp("audio/mpeg", type) == 0) skip = false; + else if (strcmp("application/ogg", type) == 0) skip = false; + else if (strcmp("mp3", type) == 0) skip = false; + else if (strcmp("application/mp3", type) == 0) skip = false; + } else { + url = xmlGetAttribute(element, (char *) urltag); + name = xmlGetAttribute(element, (char *) nametag); + if (bitratetag) { + ptr = xmlGetAttribute(element, (char *) bitratetag); + if (ptr) + bitrate = atoi(ptr); + } + skip = false; + } + + if ((url != NULL) && !skip) { + progress.showStatusMessageUTF(url); + //printf("Processing %s, %s\n", url, name); + if (strstr(url, ".m3u") || strstr(url, ".pls")) + processPlaylistUrl(url, name); + else + addUrl2Playlist(url, name, bitrate); + } + element = element->xmlNextNode; + g_RCInput->getMsg(&msg, &data, 0); + + } + progress.hide(); + } + xmlFreeDoc(answer_parser); + } + else + printf("[scanXmlData] answer_parser == NULL"); +} + +bool CAudioPlayerGui::openFilebrowser(void) +{ + bool result = false; + CFileBrowser filebrowser((g_settings.filebrowser_denydirectoryleave) + ? g_settings.network_nfs_audioplayerdir : ""); + + filebrowser.Multi_Select = true; + filebrowser.Dirs_Selectable = true; + filebrowser.Filter = &audiofilefilter; + + hide(); + + if (filebrowser.exec(m_Path.c_str())) + { +#ifdef AUDIOPLAYER_TIME_DEBUG + timeval start; + gettimeofday(&start,NULL); +#endif + CProgressWindow progress; + long maxProgress = (filebrowser.getSelectedFiles().size() > 1) ? filebrowser.getSelectedFiles().size() - 1 : 1; + long currentProgress = -1; + if (maxProgress > SHOW_FILE_LOAD_LIMIT) + { + progress.setTitle(LOCALE_AUDIOPLAYER_READING_FILES); + progress.exec(this,""); + } + + m_Path = filebrowser.getCurrentDir(); + CFileList::const_iterator files = filebrowser.getSelectedFiles().begin(); + for(; files != filebrowser.getSelectedFiles().end();files++) + { + if (maxProgress > SHOW_FILE_LOAD_LIMIT) + { + currentProgress++; + // show status + int global = 100*currentProgress/maxProgress; + progress.showGlobalStatus(global); + progress.showStatusMessageUTF(files->Name); + #ifdef LCD_UPDATE + CVFD::getInstance()->showProgressBar(global, "read metadata..."); + CVFD::getInstance()->setMode(CVFD::MODE_PROGRESSBAR); + #endif // LCD_UPDATE + } + if ((files->getType() == CFile::FILE_CDR) + || (files->getType() == CFile::FILE_OGG) + || (files->getType() == CFile::FILE_MP3) + || (files->getType() == CFile::FILE_WAV) +#ifdef ENABLE_FLAC + || (files->getType() == CFile::FILE_FLAC) +#endif + ) + { + CAudiofileExt audiofile(files->Name, + files->getType()); + addToPlaylist(audiofile); + } + if(files->getType() == CFile::STREAM_AUDIO) + { + std::string filename = files->Name; + FILE *fd = fopen(filename.c_str(), "r"); + if(fd) + { + char buf[512]; + unsigned int len = fread(buf, sizeof(char), 512, fd); + fclose(fd); + + if (len && (strstr(buf, ".m3u") || strstr(buf, ".pls"))) + { + printf("m3u/pls Playlist found: %s\n", buf); + filename = buf; + processPlaylistUrl(buf); + } + else + { + addUrl2Playlist(filename.c_str()); + } + } + } + else if(files->getType() == CFile::FILE_PLAYLIST) + { + std::string sPath = files->Name.substr(0, files->Name.rfind('/')); + std::ifstream infile; + char cLine[256]; + infile.open(files->Name.c_str(), std::ifstream::in); + while (infile.good()) + { + infile.getline(cLine, 255); + // remove CR + if(cLine[strlen(cLine)-1]=='\r') + cLine[strlen(cLine)-1]=0; + if(strlen(cLine) > 0 && cLine[0]!='#') + { + char *url = strstr(cLine, "http://"); + if (url != NULL) { + if (strstr(url, ".m3u") || strstr(url, ".pls")) + processPlaylistUrl(url); + } else if ((url = strstr(cLine, "icy://")) != NULL) { + addUrl2Playlist(url); + } else if ((url = strstr(cLine, "scast:://")) != NULL) { + addUrl2Playlist(url); + } + else + { + std::string filename = sPath + '/' + cLine; + + std::string::size_type pos; + while((pos=filename.find('\\'))!=std::string::npos) + filename[pos]='/'; + + std::ifstream testfile; + testfile.open(filename.c_str(), std::ifstream::in); + if(testfile.good()) + { +#ifdef AUDIOPLAYER_CHECK_FOR_DUPLICATES + // Check for duplicates and remove (new entry has higher prio) + // this really needs some time :( + for (unsigned long i=0;igetType() == CFile::FILE_XML) + { + if (!files->Name.empty()) + { + scanXmlFile(files->Name); + } + } + } + if (m_select_title_by_name) + { + buildSearchTree(); + } +#ifdef AUDIOPLAYER_TIME_DEBUG + timeval end; + gettimeofday(&end,NULL); + printf("adding %ld files took: ",maxProgress+1); + printTimevalDiff(start,end); +#endif + result = true; + } + CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); + paintLCD(); + // if playlist is turned off -> start playing immediately + if (!m_show_playlist && !m_playlist.empty()) + play(m_selected); + + return ( result); +} + +//------------------------------------------------------------------------ +#define SC_BASE_DIR "http://www.shoutcast.com" +#define SC_INIT_DIR "/sbin/newxml.phtml" +bool CAudioPlayerGui::openSCbrowser(void) +{ + bool result = false; + CFileBrowser filebrowser(SC_BASE_DIR, CFileBrowser::ModeSC); + + filebrowser.Multi_Select = true; + filebrowser.Dirs_Selectable = true; + filebrowser.Filter = NULL;//&audiofilefilter; + + hide(); + + if (filebrowser.exec(SC_INIT_DIR)) + { +#ifdef AUDIOPLAYER_TIME_DEBUG + timeval start; + gettimeofday(&start,NULL); +#endif + CProgressWindow progress; + long maxProgress = (filebrowser.getSelectedFiles().size() > 1) ? filebrowser.getSelectedFiles().size() - 1: 1; + long currentProgress = -1; + //if (maxProgress > SHOW_FILE_LOAD_LIMIT) + { + progress.setTitle(LOCALE_AUDIOPLAYER_READING_FILES); + progress.exec(this,""); + } + + m_Path = filebrowser.getCurrentDir(); + CFileList::const_iterator files = filebrowser.getSelectedFiles().begin(); + neutrino_msg_t msg; + neutrino_msg_data_t data; + g_RCInput->getMsg(&msg, &data, 0); + for(; (files != filebrowser.getSelectedFiles().end()) && (msg != CRCInput::RC_home);files++) + { + //if (maxProgress > SHOW_FILE_LOAD_LIMIT) + { + currentProgress++; + // show progress + int global = 100*currentProgress/maxProgress; + progress.showGlobalStatus(global); + progress.showStatusMessageUTF(files->Name); + #ifdef LCD_UPDATE + CVFD::getInstance()->showProgressBar(global, "read metadata..."); + CVFD::getInstance()->setMode(CVFD::MODE_PROGRESSBAR); + #endif // LCD_UPDATE + } + //printf("processPlaylistUrl(%s, %s)\n", files->Url.c_str(), files->Name.c_str()); + processPlaylistUrl(files->Url.c_str(), files->Name.c_str(), files->Time); + g_RCInput->getMsg(&msg, &data, 0); + } + if (m_select_title_by_name) + { + buildSearchTree(); + } +#ifdef AUDIOPLAYER_TIME_DEBUG + timeval end; + gettimeofday(&end,NULL); + printf("adding %ld files took: ",maxProgress+1); + printTimevalDiff(start,end); +#endif + result = true; + } + CVFD::getInstance()->setMode(CVFD::MODE_AUDIO); + paintLCD(); + // if playlist is turned off -> start playing immediately + if (!m_show_playlist && !m_playlist.empty()) + play(m_selected); + + return ( result); +} + +//------------------------------------------------------------------------ + + +void CAudioPlayerGui::hide() +{ + // printf("hide(){\n"); + if(m_visible) + { + m_frameBuffer->paintBackgroundBoxRel(m_x - ConnectLineBox_Width-1, m_y + m_title_height - 1, + m_width + ConnectLineBox_Width+2, m_height + 2 - m_title_height); + clearItemID3DetailsLine(); + m_frameBuffer->paintBackgroundBoxRel(m_x, m_y, m_width, m_title_height); + m_visible = false; + } +} + +//------------------------------------------------------------------------ + +void CAudioPlayerGui::paintItem(int pos) +{ + if (!m_show_playlist) + return; + + int ypos = m_y + m_title_height + m_theight + pos*m_fheight; + int c_rad_small; + uint8_t color; + fb_pixel_t bgcolor; + + if ((pos + m_liststart) == m_selected) + { + if ((pos + m_liststart) == (unsigned)m_current) + { + color = COL_MENUCONTENTSELECTED + 2; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_2; + } + else + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + paintItemID3DetailsLine(pos); + c_rad_small = RADIUS_SMALL; + } + else + { + if (((pos + m_liststart) < m_playlist.size()) && (pos & 1)) + { + if ((pos + m_liststart) == (unsigned)m_current) + { + color = COL_MENUCONTENTDARK + 2; + bgcolor = COL_MENUCONTENTDARK_PLUS_2; + } + else + { + color = COL_MENUCONTENTDARK; + bgcolor = COL_MENUCONTENTDARK_PLUS_0; + } + } + else + { + if ((pos + m_liststart) == (unsigned)m_current) + { + color = COL_MENUCONTENT + 2; + bgcolor = COL_MENUCONTENT_PLUS_2; + } + else + { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + } + } + c_rad_small = 0; + } + + m_frameBuffer->paintBoxRel(m_x, ypos, m_width - 15, m_fheight, bgcolor, c_rad_small); + + if ((pos + m_liststart) < m_playlist.size()) + { + if (m_playlist[pos + m_liststart].FileType != CFile::STREAM_AUDIO && + !m_playlist[pos + m_liststart].MetaData.bitrate) + { + // id3tag noch nicht geholt + GetMetaData(m_playlist[pos + m_liststart]); + if(m_state != CAudioPlayerGui::STOP && !g_settings.audioplayer_highprio) + usleep(100*1000); + } + char sNr[20]; + sprintf(sNr, "%2d : ", pos + m_liststart + 1); + std::string tmp = sNr; + getFileInfoToDisplay(tmp, m_playlist[pos + m_liststart]); + + char dura[9]; + if (m_inetmode) + snprintf(dura, 8, "%ldk", m_playlist[pos + m_liststart].MetaData.total_time); + else + snprintf(dura, 8, "%ld:%02ld", m_playlist[pos + m_liststart].MetaData.total_time / 60, + m_playlist[pos + m_liststart].MetaData.total_time % 60); + int w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(dura) + 5; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + 10, ypos + m_fheight, m_width - 30 - w, + tmp, color, m_fheight, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + m_width - 15 - w, ypos + m_fheight, + w, dura, color, m_fheight); + if ((pos + m_liststart) == m_selected) + { + if (m_state == CAudioPlayerGui::STOP) + { + CVFD::getInstance()->showAudioTrack(m_playlist[pos + m_liststart].MetaData.artist, + m_playlist[pos + m_liststart].MetaData.title, + m_playlist[pos + m_liststart].MetaData.album); + } + } + } +} + +//--------------playlist---------------------------------------------------------- + +void CAudioPlayerGui::paintHead() +{ + if (!m_show_playlist) + return; + + int c_rad_mid = RADIUS_MID; + std::string strCaption; + if (m_inetmode) + strCaption = g_Locale->getText(LOCALE_INETRADIO_NAME); + else + strCaption = g_Locale->getText(LOCALE_AUDIOPLAYER_HEAD); + m_frameBuffer->paintBoxRel(m_x, m_y + m_title_height, m_width, m_theight, COL_MENUHEAD_PLUS_0, c_rad_mid, CORNER_TOP); + m_frameBuffer->paintIcon("mp3.raw",m_x + 7, m_y + m_title_height + 10); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(m_x + 35, m_y + m_theight + m_title_height + 0, + m_width - 45, strCaption, COL_MENUHEAD, 0, true); // UTF-8 + int ypos = m_y + m_title_height; + if(m_theight > 26) + ypos = (m_theight - 26) / 2 + m_y + m_title_height; +#ifdef ENABLE_GUI_MOUNT + if (!m_inetmode) + m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DBOX, m_x + m_width - 30, ypos); +#endif +#if 1 + if( CNeutrinoApp::getInstance()->isMuted() ) + { + int xpos = m_x + m_width - 75; + ypos = m_y + m_title_height; + if(m_theight > 32) + ypos = (m_theight - 32) / 2 + m_y + m_title_height; + m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MUTE, xpos, ypos); + } +#endif +} + +//------------------------------------------------------------------------ +const struct button_label AudioPlayerButtons[][4] = +{ + { + { NEUTRINO_ICON_BUTTON_RED , LOCALE_AUDIOPLAYER_STOP }, + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_REWIND }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_PAUSE }, + { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_AUDIOPLAYER_FASTFORWARD }, + }, + { + { NEUTRINO_ICON_BUTTON_RED , LOCALE_AUDIOPLAYER_DELETE }, + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_ADD }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_DELETEALL }, + { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_AUDIOPLAYER_SHUFFLE }, + }, + { + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_JUMP_BACKWARDS }, + { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_AUDIOPLAYER_JUMP_FORWARDS }, + }, + { + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_JUMP_BACKWARDS }, + { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_AUDIOPLAYER_JUMP_FORWARDS }, + }, + { + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_SAVE_PLAYLIST }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_BUTTON_SELECT_TITLE_BY_ID }, + }, + { + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_SAVE_PLAYLIST }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_BUTTON_SELECT_TITLE_BY_NAME }, + }, + { + { NEUTRINO_ICON_BUTTON_RED , LOCALE_AUDIOPLAYER_STOP }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_PAUSE }, + }, + { + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_ADD }, + { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_INETRADIO_NAME }, + }, + { + { NEUTRINO_ICON_BUTTON_RED , LOCALE_AUDIOPLAYER_DELETE }, + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_ADD }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_DELETEALL }, + { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_INETRADIO_NAME }, + }, +}; +//------------------------------------------------------------------------ + +void CAudioPlayerGui::paintFoot() +{ + // printf("paintFoot{\n"); + int top; + int c_rad_mid = RADIUS_MID; + if (m_show_playlist) + top = m_y + (m_height - m_info_height - 2 * m_buttonHeight); + else + top = m_y + (m_height - 2 * m_buttonHeight); + + int ButtonWidth = (m_width - 20) / 4; + int ButtonWidth2 = (m_width - 50) / 2; + m_frameBuffer->paintBoxRel(m_x, top, m_width, 2 * m_buttonHeight, COL_INFOBAR_SHADOW_PLUS_1, c_rad_mid, CORNER_BOTTOM); + m_frameBuffer->paintHLine(m_x, m_x + m_width, top, COL_INFOBAR_SHADOW_PLUS_1); + + if (!m_playlist.empty()) + { + // play + m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, m_x + 1 * ButtonWidth2 + 25, top + m_buttonHeight - 3); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL] + ->RenderString(m_x + 1 * ButtonWidth2 + 53, top + m_buttonHeight + 24 - 4, ButtonWidth2 - 28, + g_Locale->getText(LOCALE_AUDIOPLAYER_PLAY), COL_INFOBAR /*_SHADOW_PLUS_1*/, 0, true); // UTF-8 + // keylevel switch + m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, m_x + 0 * ButtonWidth + 25, top + m_buttonHeight - 3); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL] + ->RenderString(m_x + 0 * ButtonWidth + 53 , top + m_buttonHeight + 24 - 4, ButtonWidth2 - 28, + g_Locale->getText(LOCALE_AUDIOPLAYER_KEYLEVEL), COL_INFOBAR /*_SHADOW_PLUS_1*/, 0, true); // UTF-8 + } + + if (m_key_level == 0) + { + if (m_playlist.empty()) { + if (m_inetmode) + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + 10, top + 4, ButtonWidth, 2, AudioPlayerButtons[7]); + else + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + 10, top + 4, ButtonWidth, 1, &(AudioPlayerButtons[7][0])); + } else + if (m_inetmode) + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + 10, top + 4, ButtonWidth, 4, AudioPlayerButtons[8]); + else + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + 10, top + 4, ButtonWidth, 4, AudioPlayerButtons[1]); + } + else if (m_key_level == 1) + { + if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO) + { + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, m_x + 10, top + 4, ButtonWidth, 4, AudioPlayerButtons[0]); + } + else + { + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, m_x + 10, top + 4, ButtonWidth*2, 2, AudioPlayerButtons[6]); + } + } + else + { // key_level == 2 + if (m_state == CAudioPlayerGui::STOP) + { + if (m_select_title_by_name) + { + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + ButtonWidth + 10, top + 4, ButtonWidth, 2, AudioPlayerButtons[5]); + } + else + { + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + ButtonWidth + 10, top + 4, ButtonWidth, 2, AudioPlayerButtons[4]); + } + } + else + { + if (m_select_title_by_name) + { + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + ButtonWidth + 10, top + 4, ButtonWidth*2, 2, AudioPlayerButtons[3]); + } + else + { + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + ButtonWidth + 10, top + 4, ButtonWidth*2, 2, AudioPlayerButtons[2]); + } + } + } +} +//------------------------------------------------------------------------ +void CAudioPlayerGui::paintInfo() +{ + int c_rad_mid = RADIUS_MID; + if(m_state == CAudioPlayerGui::STOP && m_show_playlist) + m_frameBuffer->paintBackgroundBoxRel(m_x, m_y, m_width, m_title_height); + else + { + if (!m_show_playlist) + { + // no playlist -> smaller Info-Box + m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10 - m_fheight, COL_MENUCONTENT_PLUS_6, c_rad_mid); + m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2 , m_width - 4, m_title_height - 14 - m_fheight, COL_MENUCONTENTSELECTED_PLUS_0, c_rad_mid); + } + else + { + m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10, COL_MENUCONTENT_PLUS_6, c_rad_mid); + m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2 , m_width - 4, m_title_height - 14, COL_MENUCONTENTSELECTED_PLUS_0, c_rad_mid); + } + + // first line (Track number) + std::string tmp; + if (m_inetmode) { + tmp = m_curr_audiofile.MetaData.album; + } else { + char sNr[20]; + sprintf(sNr, ": %2d", m_current + 1); + tmp = g_Locale->getText(LOCALE_AUDIOPLAYER_PLAYING); + tmp += sNr ; + } + + int w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + int xstart = (m_width - w) / 2; + if(xstart < 10) + xstart = 10; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 1*m_fheight, m_width - 20, + tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + + // second line (Artist/Title...) + if (m_curr_audiofile.FileType != CFile::STREAM_AUDIO && + !m_curr_audiofile.MetaData.bitrate) + { + GetMetaData(m_curr_audiofile); + } + + if (m_curr_audiofile.MetaData.title.empty()) + tmp = m_curr_audiofile.MetaData.artist; + else if (m_curr_audiofile.MetaData.artist.empty()) + tmp = m_curr_audiofile.MetaData.title; + else if (g_settings.audioplayer_display == TITLE_ARTIST) + { + tmp = m_curr_audiofile.MetaData.title; + tmp += " / "; + tmp += m_curr_audiofile.MetaData.artist; + } + else //if(g_settings.audioplayer_display == ARTIST_TITLE) + { + tmp = m_curr_audiofile.MetaData.artist; + tmp += " / "; + tmp += m_curr_audiofile.MetaData.title; + } + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + xstart=(m_width-w)/2; + if(xstart < 10) + xstart=10; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x+xstart, m_y +4+ 2*m_fheight, m_width- 20, tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + + // reset so fields get painted always + m_metainfo.clear(); + m_time_total = 0; + m_time_played = 0; + updateMetaData(); + + updateTimes(true); + } +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::paint() +{ + if (m_show_playlist) + { + m_liststart = (m_selected / m_listmaxshow) * m_listmaxshow; + paintHead(); + for (unsigned int count=0;countpaintBoxRel(m_x + m_width - 15, ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc = ((m_playlist.size() - 1) / m_listmaxshow) + 1; + int sbs = (m_selected / m_listmaxshow); + + m_frameBuffer->paintBoxRel(m_x + m_width - 13, ypos + 2 + sbs*(sb-4)/sbc , 11, (sb-4)/sbc, COL_MENUCONTENT_PLUS_3, RADIUS_SMALL); + } + + paintFoot(); + paintInfo(); + m_visible = true; + +} + +//------------------------------------------------------------------------ + +void CAudioPlayerGui::clearItemID3DetailsLine () +{ + paintItemID3DetailsLine(-1); +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::paintItemID3DetailsLine (int pos) +{ + int xpos = m_x - ConnectLineBox_Width; + int ypos1 = m_y + m_title_height + m_theight+ 0 + pos*m_fheight; + int ypos2 = m_y + (m_height - m_info_height); + int ypos1a = ypos1 + (m_fheight / 2) - 2; + int ypos2a = ypos2 + (m_info_height / 2) - 2; + fb_pixel_t col1 = COL_MENUCONTENT_PLUS_6; + fb_pixel_t col2 = COL_MENUCONTENT_PLUS_1; + int c_rad_small = RADIUS_SMALL; + + + // Clear + m_frameBuffer->paintBackgroundBoxRel(xpos - 1, m_y + m_title_height, ConnectLineBox_Width + 1, + m_height - m_title_height); + + // paint Line if detail info (and not valid list pos) + if (!m_playlist.empty() && (pos >= 0)) + { + // 1. col thick line + m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 4, ypos1, 4, m_fheight, col2 /*, c_rad_small, CORNER_LEFT*/);//FIXME + m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 3, ypos1, 8, m_fheight, col1 /*, c_rad_small, CORNER_LEFT*/); // item marker + + m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 4, ypos2, 4, m_info_height, col1); + + m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 16, ypos1a, 4, ypos2a - ypos1a, col1); + + m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 16, ypos1a, 12, 4, col1); + m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 16, ypos2a, 12, 4, col1); + + // 2. col small line + m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 4, ypos2, 1, m_info_height, col2); + + m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 16, ypos1a, 1, ypos2a - ypos1a + 4, col2); + + m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 16, ypos1a, 12, 1, col2); + m_frameBuffer->paintBoxRel(xpos + ConnectLineBox_Width - 12, ypos2a, 8, 1, col2); + + // -- small Frame around infobox + m_frameBuffer->paintBoxRel(m_x, ypos2 , 2 , m_info_height , col1); + m_frameBuffer->paintBoxRel(m_x + m_width - 2, ypos2 , 2 , m_info_height , col1); + m_frameBuffer->paintBoxRel(m_x, ypos2 , m_width -2 , 2 , col1); + m_frameBuffer->paintBoxRel(m_x, ypos2 + m_info_height -2, m_width -2 , 2 , col1); + // m_frameBuffer->paintBoxRel(m_x, ypos2, m_width, m_info_height, col1); + + // paint id3 infobox + m_frameBuffer->paintBoxRel(m_x + 2, ypos2 + 2 , m_width - 4, m_info_height - 4, COL_MENUCONTENTDARK_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + 10, ypos2 + 2 + 1*m_fheight, m_width- 80, + m_playlist[m_selected].MetaData.title, COL_MENUCONTENTDARK, 0, true); // UTF-8 + std::string tmp; + if (m_playlist[m_selected].MetaData.genre.empty()) + tmp = m_playlist[m_selected].MetaData.date; + else if (m_playlist[m_selected].MetaData.date.empty()) + tmp = m_playlist[m_selected].MetaData.genre; + else + { + tmp = m_playlist[m_selected].MetaData.genre; + tmp += " / "; + tmp += m_playlist[m_selected].MetaData.date; + } + int w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true) + 10; // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + m_width - w - 5, ypos2 + 2 + 1*m_fheight, + w, tmp, COL_MENUCONTENTDARK, 0, true); // UTF-8 + tmp = m_playlist[m_selected].MetaData.artist; + if (!(m_playlist[m_selected].MetaData.album.empty())) + { + tmp += " ("; + tmp += m_playlist[m_selected].MetaData.album; + tmp += ')'; + } + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + 10, ypos2 + 2*m_fheight - 2, m_width - 20, + tmp, COL_MENUCONTENTDARK, 0, true); // UTF-8 + } + else + { + m_frameBuffer->paintBackgroundBoxRel(m_x, ypos2, m_width, m_info_height); + } +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::stop() +{ + m_state = CAudioPlayerGui::STOP; + m_current = 0; + //LCD + paintLCD(); + //Display + paintInfo(); + m_key_level = 0; + paintFoot(); + + if(CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) + CAudioPlayer::getInstance()->stop(); +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::pause() +{ + if(m_state == CAudioPlayerGui::PLAY + || m_state == CAudioPlayerGui::FF + || m_state == CAudioPlayerGui::REV) + { + m_state = CAudioPlayerGui::PAUSE; + CAudioPlayer::getInstance()->pause(); + } + else if(m_state == CAudioPlayerGui::PAUSE) + { + m_state = CAudioPlayerGui::PLAY; + CAudioPlayer::getInstance()->pause(); + } + paintLCD(); +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::ff(unsigned int seconds) +{ + if(m_state == CAudioPlayerGui::FF) + { + m_state = CAudioPlayerGui::PLAY; + CAudioPlayer::getInstance()->ff(seconds); + } + else if(m_state == CAudioPlayerGui::PLAY + || m_state == CAudioPlayerGui::PAUSE + || m_state == CAudioPlayerGui::REV) + { + m_state = CAudioPlayerGui::FF; + CAudioPlayer::getInstance()->ff(seconds); + } + paintLCD(); +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::rev(unsigned int seconds) +{ + if(m_state == CAudioPlayerGui::REV) + { + m_state = CAudioPlayerGui::PLAY; + CAudioPlayer::getInstance()->rev(seconds); + } + else if(m_state == CAudioPlayerGui::PLAY + || m_state == CAudioPlayerGui::PAUSE + || m_state == CAudioPlayerGui::FF) + { + m_state = CAudioPlayerGui::REV; + CAudioPlayer::getInstance()->rev(seconds); + } + paintLCD(); +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::play(unsigned int pos) +{ + //printf("AudioPlaylist: play %d/%d\n",pos,playlist.size()); + unsigned int old_current = m_current; + unsigned int old_selected = m_selected; + + m_current = pos; + if(g_settings.audioplayer_follow) + m_selected = pos; + + if(m_selected - m_liststart >= m_listmaxshow && g_settings.audioplayer_follow) + { + m_liststart = m_selected; + if(!m_screensaver) + paint(); + } + else if(m_liststart < m_selected && g_settings.audioplayer_follow) + { + m_liststart = m_selected - m_listmaxshow + 1; + if(!m_screensaver) + paint(); + } + else + { + if(old_current >= m_liststart && old_current - m_liststart < m_listmaxshow) + { + if(!m_screensaver) + paintItem(old_current - m_liststart); + } + if(pos >= m_liststart && pos - m_liststart < m_listmaxshow) + { + if(!m_screensaver) + paintItem(pos - m_liststart); + } + if(g_settings.audioplayer_follow) + { + if(old_selected >= m_liststart && old_selected - m_liststart < m_listmaxshow) + if(!m_screensaver) + paintItem(old_selected - m_liststart); + } + } + + if (m_playlist[pos].FileType != CFile::STREAM_AUDIO && + !m_playlist[pos].MetaData.bitrate) + { + // id3tag noch nicht geholt + //printf("play: need getMetaData\n"); + GetMetaData(m_playlist[pos]); + } + m_metainfo.clear(); + m_time_played = 0; + m_time_total = m_playlist[m_current].MetaData.total_time; + m_state = CAudioPlayerGui::PLAY; + m_curr_audiofile = m_playlist[m_current]; + // Play + CAudioPlayer::getInstance()->play(&m_curr_audiofile, g_settings.audioplayer_highprio == 1); + //LCD + paintLCD(); + // Display + if(!m_screensaver) + paintInfo(); + m_key_level = 1; + if(!m_screensaver) + paintFoot(); +} +//------------------------------------------------------------------------ + +int CAudioPlayerGui::getNext() +{ + int ret= m_current + 1; + if(m_playlist.empty()) + return -1; + if((unsigned)ret >= m_playlist.size()) + { + if (g_settings.audioplayer_repeat_on == 1) + ret = 0; + else + ret = -1; + } + return ret; +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::updateMetaData() +{ + bool updateMeta = false; + bool updateLcd = false; + bool updateScreen = false; + + if(m_state == CAudioPlayerGui::STOP || !m_show_playlist) + return; + + if( CAudioPlayer::getInstance()->hasMetaDataChanged() + || m_metainfo.empty() ) + { + const CAudioMetaData meta = + CAudioPlayer::getInstance()->getMetaData(); + + std::stringstream info; + info.precision(3); + + if ( meta.bitrate > 0 ) + { + info << " / "; + if ( meta.vbr ) + { + info << "VBR "; + } + info << meta.bitrate/1000 << "kbps"; + } + + if ( meta.samplerate > 0 ) + { + info << " / " << meta.samplerate/1000 << "." << (meta.samplerate/100)%10 <<"kHz"; + } + + m_metainfo = meta.type_info + info.str(); + updateMeta = true; + + if (!meta.artist.empty() && + meta.artist != m_curr_audiofile.MetaData.artist) + { + m_curr_audiofile.MetaData.artist = meta.artist; + updateScreen = true; + updateLcd = true; + } + if (!meta.title.empty() && + meta.title != m_curr_audiofile.MetaData.title) + { + m_curr_audiofile.MetaData.title = meta.title; + updateScreen = true; + updateLcd = true; + } + if (!meta.sc_station.empty() && + meta.sc_station != m_curr_audiofile.MetaData.album) + { + m_curr_audiofile.MetaData.album = meta.sc_station; + updateLcd = true; + } + } + //if (CAudioPlayer::getInstance()->getScBuffered() != 0) + if (CAudioPlayer::getInstance()->hasMetaDataChanged() != 0) + { + updateLcd = true; + } +//printf("CAudioPlayerGui::updateMetaData: updateLcd %d\n", updateLcd); + if(updateLcd) + paintLCD(); + if(updateScreen) + paintInfo(); + if(updateMeta || updateScreen) + { + m_frameBuffer->paintBoxRel(m_x + 10, m_y + 4 + 2*m_fheight, m_width - 20, + m_sheight, COL_MENUCONTENTSELECTED_PLUS_0); + int xstart = ((m_width - 20 - g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getRenderWidth(m_metainfo))/2)+10; + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL] + ->RenderString(m_x + xstart, m_y + 4 + 2*m_fheight + m_sheight, + m_width- 2*xstart, m_metainfo, COL_MENUCONTENTSELECTED); + } +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::updateTimes(const bool force) +{ + if (m_state != CAudioPlayerGui::STOP) + { + bool updateTotal = force; + bool updatePlayed = force; + + if (m_time_total != CAudioPlayer::getInstance()->getTimeTotal()) + { + m_time_total = CAudioPlayer::getInstance()->getTimeTotal(); + if (m_curr_audiofile.MetaData.total_time != CAudioPlayer::getInstance()->getTimeTotal()) + { + m_curr_audiofile.MetaData.total_time = CAudioPlayer::getInstance()->getTimeTotal(); + if(m_current >= 0) + m_playlist[m_current].MetaData.total_time = CAudioPlayer::getInstance()->getTimeTotal(); + } + updateTotal = true; + } + if ((m_time_played != CAudioPlayer::getInstance()->getTimePlayed())) + { + m_time_played = CAudioPlayer::getInstance()->getTimePlayed(); + updatePlayed = true; + } + if(!m_screensaver) + { + char tot_time[11]; + snprintf(tot_time, 10, " / %ld:%02ld", m_time_total / 60, m_time_total % 60); + char tmp_time[8]; + snprintf(tmp_time, 7, "%ld:00", m_time_total / 60); + char play_time[8]; + snprintf(play_time, 7, "%ld:%02ld", m_time_played / 60, m_time_played % 60); + + int w1 = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tot_time); + int w2 = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp_time); + + if (updateTotal) + { + m_frameBuffer->paintBoxRel(m_x + m_width - w1 - 10, m_y + 4, w1 + 4, + m_fheight, COL_MENUCONTENTSELECTED_PLUS_0); + if(m_time_total > 0) + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + m_width - w1 - 10, m_y + 4 + m_fheight, + w1, tot_time, COL_MENUCONTENTSELECTED); + } + if (updatePlayed || (m_state == CAudioPlayerGui::PAUSE)) + { + //m_frameBuffer->paintBoxRel(m_x + m_width - w1 - w2 - 15, m_y + 4, w2 + 4, m_fheight, + m_frameBuffer->paintBoxRel(m_x + m_width - w1 - w2 - 16, m_y + 4, w2 + 5, m_fheight, + COL_MENUCONTENTSELECTED_PLUS_0); + struct timeval tv; + gettimeofday(&tv, NULL); + if ((m_state != CAudioPlayerGui::PAUSE) || (tv.tv_sec & 1)) + { + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + m_width - w1 - w2 - 11, m_y + 4 + m_fheight, + w2+4, play_time, COL_MENUCONTENTSELECTED); + } + } + } + if((updatePlayed || updateTotal) && m_time_total != 0) + { + CVFD::getInstance()->showAudioProgress(100 * m_time_played / m_time_total, CNeutrinoApp::getInstance()->isMuted()); + } + } +} + +//------------------------------------------------------------------------ + +void CAudioPlayerGui::paintLCD() +{ + switch(m_state) + { + case CAudioPlayerGui::STOP: + CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_STOP); + CVFD::getInstance()->showAudioProgress(0, CNeutrinoApp::getInstance()->isMuted()); + break; + case CAudioPlayerGui::PLAY: + CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_PLAY); + + CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, + m_curr_audiofile.MetaData.album); + if(m_curr_audiofile.FileType != CFile::STREAM_AUDIO && m_time_total != 0) + CVFD::getInstance()->showAudioProgress(100 * m_time_played / m_time_total, CNeutrinoApp::getInstance()->isMuted()); + +#ifdef INCLUDE_UNUSED_STUFF + else + CVFD::getInstance()->showAudioProgress(100 * CAudioPlayer::getInstance()->getScBuffered() / 65536, CNeutrinoApp::getInstance()->isMuted()); +#endif /* INCLUDE_UNUSED_STUFF */ + break; + case CAudioPlayerGui::PAUSE: + CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_PAUSE); + CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, + m_curr_audiofile.MetaData.album); + break; + case CAudioPlayerGui::FF: + CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_FF); + CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, + m_curr_audiofile.MetaData.album); + break; + case CAudioPlayerGui::REV: + CVFD::getInstance()->showAudioPlayMode(CVFD::AUDIO_MODE_REV); + CVFD::getInstance()->showAudioTrack(m_curr_audiofile.MetaData.artist, m_curr_audiofile.MetaData.title, + m_curr_audiofile.MetaData.album); + break; + } +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::screensaver(bool on) +{ + if(on) + { + m_screensaver = true; + m_frameBuffer->ClearFrameBuffer(); + stimer = g_RCInput->addTimer(10*1000*1000, false); + } + else + { + if(stimer) + g_RCInput->killTimer(stimer); + stimer = 0; + m_screensaver = false; +#if 0 + m_frameBuffer->loadPal("radiomode.pal", 18, COL_MAXFREE); + m_frameBuffer->useBackground(m_frameBuffer->loadBackground("radiomode.raw"));// set useBackground true or false + m_frameBuffer->paintBackground(); +#endif + paint(); + m_idletime = time(NULL); + } +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::GetMetaData(CAudiofileExt &File) +{ + // printf("GetMetaData\n"); + bool ret = 1; + + if (CFile::STREAM_AUDIO != File.FileType) + ret = CAudioPlayer::getInstance()->readMetaData( &File, + m_state != CAudioPlayerGui::STOP && + !g_settings.audioplayer_highprio); + + if (!ret || (File.MetaData.artist.empty() && File.MetaData.title.empty() )) + { + //Set from Filename + std::string tmp = File.Filename.substr(File.Filename.rfind('/') + 1); + tmp = tmp.substr(0,tmp.length()-4); //remove extension (.mp3) + std::string::size_type i = tmp.rfind(" - "); + if(i != std::string::npos) + { // Trennzeichen " - " gefunden + File.MetaData.artist = tmp.substr(0, i); + File.MetaData.title = tmp.substr(i + 3); + } + else + { + i = tmp.rfind('-'); + if(i != std::string::npos) + { //Trennzeichen "-" + File.MetaData.artist = tmp.substr(0, i); + File.MetaData.title = tmp.substr(i + 1); + } + else + File.MetaData.title = tmp; + } + File.MetaData.artist = FILESYSTEM_ENCODING_TO_UTF8_STRING(File.MetaData.artist); + File.MetaData.title = FILESYSTEM_ENCODING_TO_UTF8_STRING(File.MetaData.title ); + } +} +//------------------------------------------------------------------------ + +bool CAudioPlayerGui::getNumericInput(neutrino_msg_t& msg, int& val) { + + neutrino_msg_data_t data; + int x1 = (g_settings.screen_EndX - g_settings.screen_StartX) / 2 + g_settings.screen_StartX - 50; + int y1 = (g_settings.screen_EndY - g_settings.screen_StartY) / 2 + g_settings.screen_StartY; + char str[11]; + do + { + val = val * 10 + CRCInput::getNumericValue(msg); + sprintf(str, "%d", val); + int w = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getRenderWidth(str); + int h = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getHeight(); + m_frameBuffer->paintBoxRel(x1 - 7, y1 - h - 5, w + 14, h + 10, COL_MENUCONTENT_PLUS_6); + m_frameBuffer->paintBoxRel(x1 - 4, y1 - h - 3, w + 8, h + 6, COL_MENUCONTENTSELECTED_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->RenderString(x1, y1, w + 1, str, COL_MENUCONTENTSELECTED, 0); + while (true) + { + g_RCInput->getMsg(&msg, &data, 100); + if (msg > CRCInput::RC_MaxRC && msg != CRCInput::RC_timeout) + { // not a key event + CNeutrinoApp::getInstance()->handleMsg(msg, data); + continue; + } + if (msg & (CRCInput::RC_Repeat|CRCInput::RC_Release)) // repeat / release + continue; + break; + } + } while (g_RCInput->isNumeric(msg) && val < 1000000); + return (msg == CRCInput::RC_ok); +} + +//------------------------------------------------------------------------ + + +void CAudioPlayerGui::getFileInfoToDisplay(std::string &info, CAudiofileExt &file) +{ + std::string fileInfo; + std::string artist; + std::string title; + + if (!m_inetmode) { + artist ="Artist?"; + title = "Title?"; + } + + if (!file.MetaData.bitrate) + { + GetMetaData(file); + } + + if (!file.MetaData.artist.empty()) + artist = file.MetaData.artist; + + if (!file.MetaData.title.empty()) + title = file.MetaData.title; + + if(g_settings.audioplayer_display == TITLE_ARTIST) + { + fileInfo += title; + if (!title.empty() && !artist.empty()) fileInfo += ", "; + fileInfo += artist; + } + else //if(g_settings.audioplayer_display == ARTIST_TITLE) + { + fileInfo += artist; + if (!title.empty() && !artist.empty()) fileInfo += ", "; + fileInfo += title; + } + + if (!file.MetaData.album.empty()) + { + fileInfo += " ("; + fileInfo += file.MetaData.album; + fileInfo += ')'; + } + if (fileInfo.empty()) + { + fileInfo += "Unknown"; + } + file.firstChar = tolower(fileInfo[0]); + info += fileInfo; +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::addToPlaylist(CAudiofileExt &file) +{ + //printf("add2Playlist: %s\n", file.Filename.c_str()); + if (m_select_title_by_name) + { + if (!file.MetaData.bitrate) + { + std::string t = ""; + getFileInfoToDisplay(t,file); + } + } + m_playlist.push_back(file); + m_playlistHasChanged = true; +} + +//------------------------------------------------------------------------ +void CAudioPlayerGui::removeFromPlaylist(long pos) +{ + unsigned char firstChar = ' '; + if (m_select_title_by_name) + { + // must be called before m_playlist.erase() + firstChar = getFirstChar(m_playlist[pos]); + } + + m_playlist.erase(m_playlist.begin() + pos); + m_playlistHasChanged = true; + + if (m_select_title_by_name) + { + +#ifdef AUDIOPLAYER_TIME_DEBUG + timeval start; + gettimeofday(&start,NULL); +#endif + //printf("searching for key: %c val: %ld\n",firstChar,pos); + + CTitle2Pos::iterator item = m_title2Pos.find(firstChar); + if (item != m_title2Pos.end()) + { + //const CPosList::size_type del = + item->second.erase(pos); + + // delete empty entries + if (item->second.size() == 0) + { + m_title2Pos.erase(item); + } + } + else + { + printf("could not find key: %c pos: %ld\n",firstChar,pos); + } + // decrease position information for all titles with a position + // behind item to delete + long p = 0; + for (CTitle2Pos::iterator title=m_title2Pos.begin(); + title!=m_title2Pos.end();title++) + { + CPosList newList; + for (CPosList::iterator posIt=title->second.begin(); + posIt!=title->second.end();posIt++) + { + p = *(posIt); + if (*posIt > pos) + p--; + // old list is sorted so we can give a hint to insert at the end + newList.insert(newList.end(), p); + } + //title->second.clear(); + title->second = newList; + } +#ifdef AUDIOPLAYER_TIME_DEBUG + timeval end; + gettimeofday(&end,NULL); + printf("delete took: "); + printTimevalDiff(start,end); +#endif + + } +} + + + +//------------------------------------------------------------------------ + +void CAudioPlayerGui::selectTitle(unsigned char selectionChar) +{ + unsigned long i; + + //printf("fastLookup: key %c\n",selectionChar); + CTitle2Pos::iterator it = m_title2Pos.find(selectionChar); + if (it!=m_title2Pos.end()) + { + // search for the next greater id + // if nothing found take the first + CPosList::iterator posIt = it->second.upper_bound(m_selected); + if (posIt != it->second.end()) + { + i = *posIt; + //printf("upper bound i: %ld\n",i); + } + else + { + if (it->second.size() > 0) + { + i = *(it->second.begin()); + //printf("using begin i: %ld\n",i); + } + else + { + //printf("no title with that key\n"); + return; + } + } + } + else + { + //printf("no title with that key\n"); + return; + } + + int prevselected = m_selected; + m_selected = i; + + paintItem(prevselected - m_liststart); + unsigned int oldliststart = m_liststart; + m_liststart = (m_selected / m_listmaxshow)*m_listmaxshow; + //printf("before paint\n"); + if(oldliststart != m_liststart) + { + paint(); + } + else + { + paintItem(m_selected - m_liststart); + } +} +//------------------------------------------------------------------------ + +void CAudioPlayerGui::printSearchTree() +{ + for (CTitle2Pos::iterator it=m_title2Pos.begin(); + it!=m_title2Pos.end();it++) + { + printf("key: %c\n",it->first); + long pos=-1; + for (CPosList::iterator it2=it->second.begin(); + it2!=it->second.end();it2++) + { + pos++; + printf(" val: %ld ",*it2); + if (pos % 5 == 4) + printf("\n"); + } + printf("\n"); + } +} + +//------------------------------------------------------------------------ + +void CAudioPlayerGui::buildSearchTree() +{ + + // printf("before\n"); + // printSearchTree(); + +#ifdef AUDIOPLAYER_TIME_DEBUG + timeval start; + gettimeofday(&start,NULL); +#endif + + CProgressWindow progress; + progress.setTitle(LOCALE_AUDIOPLAYER_BUILDING_SEARCH_INDEX); + progress.exec(this, ""); + + long maxProgress = (m_playlist.size() > 1) ? m_playlist.size() - 1 : 1; + + m_title2Pos.clear(); + long listPos = -1; + + for (CAudioPlayList::iterator it=m_playlist.begin(); + it!=m_playlist.end();it++) + { + // if (m_state == CAudioPlayerGui::PLAY) + // usleep(10*1000); + listPos++; + progress.showGlobalStatus(100*listPos / maxProgress); + //std::string info; + progress.showStatusMessageUTF(it->Filename); + unsigned char firstChar = getFirstChar(*it); + const std::pair item = + m_title2Pos.insert(CTitle2PosItem(firstChar,CPosList())); + item.first->second.insert(listPos); + } + progress.hide(); + m_playlistHasChanged = false; + +#ifdef AUDIOPLAYER_TIME_DEBUG + timeval end; + gettimeofday(&end,NULL); + printf("searchtree took: "); + printTimevalDiff(start,end); +#endif + // printf("after:\n"); + //printSearchTree(); +} + +//------------------------------------------------------------------------ + +unsigned char CAudioPlayerGui::getFirstChar(CAudiofileExt &file) +{ + if (file.firstChar == '\0') + { + std::string info; + getFileInfoToDisplay(info,file); + } + //printf("getFirstChar: %c\n",file.firstChar); + return file.firstChar; +} + + +//------------------------------------------------------------------------ +#ifdef AUDIOPLAYER_TIME_DEBUG +void CAudioPlayerGui::printTimevalDiff(timeval &start, timeval &end) +{ + + long secs = end.tv_sec - start.tv_sec; + long usecs = end.tv_usec -start.tv_usec; + if (usecs < 0) + { + usecs = 1000000 + usecs; + secs--; + } + printf("%ld:%ld\n",secs,usecs); +} +#endif + +//------------------------------------------------------------------------ + +void CAudioPlayerGui::savePlaylist() +{ + const char *path; + + // .m3u playlist + // http://hanna.pyxidis.org/tech/m3u.html + + CFileBrowser browser; + browser.Multi_Select = false; + browser.Dir_Mode = true; + CFileFilter dirFilter; + dirFilter.addFilter("m3u"); + browser.Filter = &dirFilter; + // select preferred directory if exists + if (strlen(g_settings.network_nfs_audioplayerdir) != 0) + path = g_settings.network_nfs_audioplayerdir; + else + path = "/"; + + // let user select target directory + this->hide(); + if (browser.exec(path)) + { + // refresh view + this->paint(); + CFile *file = browser.getSelectedFile(); + std::string absPlaylistDir = file->getPath(); + + // add a trailing slash if necessary + if ((absPlaylistDir.empty()) || ((*(absPlaylistDir.rbegin()) != '/'))) + { + absPlaylistDir += '/'; + } + absPlaylistDir += file->getFileName(); + + const int filenamesize = 30; + char filename[filenamesize + 1] = ""; + + if (file->getType() == CFile::FILE_PLAYLIST) + { + // file is playlist so we should ask if we can overwrite it + std::string name = file->getPath(); + name += '/'; + name += file->getFileName(); + bool overwrite = askToOverwriteFile(name); + if (!overwrite) + { + return; + } + snprintf(filename, name.size(), "%s", name.c_str()); + } + else if (file->getType() == CFile::FILE_DIR) + { + // query for filename + this->hide(); + CStringInputSMS filenameInput(LOCALE_AUDIOPLAYER_PLAYLIST_NAME, + filename, + filenamesize - 1, + LOCALE_AUDIOPLAYER_PLAYLIST_NAME_HINT1, + LOCALE_AUDIOPLAYER_PLAYLIST_NAME_HINT2, + "abcdefghijklmnopqrstuvwxyz0123456789-.,:!?/ "); + filenameInput.exec(NULL, ""); + // refresh view + this->paint(); + std::string name = absPlaylistDir; + name += '/'; + name += filename; + name += ".m3u"; + std::ifstream input(name.c_str()); + + // test if file exists and query for overwriting it or not + if (input.is_open()) + { + bool overwrite = askToOverwriteFile(name); + if (!overwrite) + { + return; + } + } + input.close(); + } + else + { + std::cout << "CAudioPlayerGui: neither .m3u nor directory selected, abort" << std::endl; + return; + } + std::string absPlaylistFilename = absPlaylistDir; + absPlaylistFilename += '/'; + absPlaylistFilename += filename; + absPlaylistFilename += ".m3u"; + std::ofstream playlistFile(absPlaylistFilename.c_str()); + std::cout << "CAudioPlayerGui: writing playlist to " << absPlaylistFilename << std::endl; + if (!playlistFile) + { + // an error occured + const int msgsize = 255; + char msg[msgsize] = ""; + snprintf(msg, + msgsize, + "%s\n%s", + g_Locale->getText(LOCALE_AUDIOPLAYER_PLAYLIST_FILEERROR_MSG), + absPlaylistFilename.c_str()); + + DisplayErrorMessage(msg); + // refresh view + this->paint(); + std::cout << "CAudioPlayerGui: could not create play list file " + << absPlaylistFilename << std::endl; + return; + } + // writing .m3u file + playlistFile << "#EXTM3U" << std::endl; + + CAudioPlayList::const_iterator it; + for (it = m_playlist.begin();it!=m_playlist.end();it++) + { + playlistFile << "#EXTINF:" << it->MetaData.total_time << "," + << it->MetaData.artist << " - " << it->MetaData.title << std::endl; + if (m_inetmode) + playlistFile << it->Filename << std::endl; + else + playlistFile << absPath2Rel(absPlaylistDir, it->Filename) << std::endl; + } + playlistFile.close(); + } + this->paint(); +} +//------------------------------------------------------------------------ + +bool CAudioPlayerGui::askToOverwriteFile(const std::string& filename) { + + char msg[filename.length() + 127]; + snprintf(msg, + filename.length() + 126, + "%s\n%s", + g_Locale->getText(LOCALE_AUDIOPLAYER_PLAYLIST_FILEOVERWRITE_MSG), + filename.c_str()); + bool res = (ShowMsgUTF(LOCALE_AUDIOPLAYER_PLAYLIST_FILEOVERWRITE_TITLE, + msg,CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbNo) + == CMessageBox::mbrYes); + this->paint(); + return res; +} +//------------------------------------------------------------------------ + +std::string CAudioPlayerGui::absPath2Rel(const std::string& fromDir, + const std::string& absFilename) { + std::string res = ""; + + int length = fromDir.length() < absFilename.length() ? fromDir.length() : absFilename.length(); + int lastSlash = 0; + // find common prefix for both paths + // fromDir: /foo/bar/angle/1 (length: 16) + // absFilename: /foo/bar/devil/2/fire.mp3 (length: 19) + // -> /foo/bar/ is prefix, lastSlash will be 8 + for (int i=0;i + +#include +#include +#include +#include +#include + +typedef std::set CPosList; + +typedef std::map CTitle2Pos; +typedef std::pair CTitle2PosItem; + +class CAudiofileExt : public CAudiofile +{ +public: + + CAudiofileExt(); + + CAudiofileExt(std::string name, CFile::FileType type); + + CAudiofileExt(const CAudiofileExt& src); + + void operator=(const CAudiofileExt& src); + + + char firstChar; +}; + +typedef std::vector CAudioPlayList; + +class RandomNumber +{ + public: + RandomNumber() + { + srand(time(0)); + } + + int operator()(int n) + { + return ((long long)n * rand() / RAND_MAX); + } +}; + +class CAudioPlayerGui : public CMenuTarget +{ + public: + enum State + { + PLAY=0, + STOP, + PAUSE, + FF, + REV + }; + + enum DisplayOrder {ARTIST_TITLE = 0, TITLE_ARTIST=1}; + + private: + void Init(void); + CFrameBuffer * m_frameBuffer; + unsigned int m_selected; + int m_current; + unsigned int m_liststart; + unsigned int m_listmaxshow; + int m_fheight; // Fonthoehe Playlist-Inhalt + int m_theight; // Fonthoehe Playlist-Titel + int m_sheight; // Fonthoehe MP Info + int m_buttonHeight; + int m_title_height; + int m_info_height; + int m_key_level; + bool m_visible; + State m_state; + time_t m_time_total; + time_t m_time_played; + std::string m_metainfo; + bool m_select_title_by_name; + bool m_show_playlist; + + bool m_playlistHasChanged; + + CAudioPlayList m_playlist; + CAudioPlayList m_radiolist; + CAudioPlayList m_filelist; + CTitle2Pos m_title2Pos; + CAudiofileExt m_curr_audiofile; + std::string m_Path; + + int m_width; + int m_height; + int m_x; + int m_y; + int m_title_w; + + int m_LastMode; + int m_idletime; + bool m_screensaver; + bool m_vol_ost; + bool m_inetmode; + uint32_t stimer; + + SMSKeyInput m_SMSKeyInput; + + void paintItem(int pos); + void paint(); + void paintHead(); + void paintFoot(); + void paintInfo(); + void paintLCD(); + void hide(); + + void get_id3(CAudiofileExt * audiofile); + void get_mp3info(CAudiofileExt * audiofile); + CFileFilter audiofilefilter; + void paintItemID3DetailsLine (int pos); + void clearItemID3DetailsLine (); + void play(unsigned int pos); + void stop(); + void pause(); + void ff(unsigned int seconds=0); + void rev(unsigned int seconds=0); + int getNext(); + void GetMetaData(CAudiofileExt &File); + void updateMetaData(); + void updateTimes(const bool force = false); + void showMetaData(); + void screensaver(bool on); + bool getNumericInput(neutrino_msg_t& msg,int& val); + + void addToPlaylist(CAudiofileExt &file); + void removeFromPlaylist(long pos); + + /** + * Adds an url (shoutcast, ...) to the to the audioplayer playlist + */ + void addUrl2Playlist(const char *url, const char *name = NULL, const time_t bitrate = 0); + + /** + * Adds a url which points to an .m3u format (playlist, ...) to the audioplayer playlist + */ + void processPlaylistUrl(const char *url, const char *name = NULL, const time_t bitrate = 0); + + /** + * Loads a given XML file of internet audiostreams or playlists and processes them + */ + void scanXmlFile(std::string filename); + + /** + * Processes a loaded XML file/data of internet audiostreams or playlists + */ + void scanXmlData(xmlDocPtr answer_parser, const char *nametag, const char *urltag, const char *bitratetag = NULL, bool usechild = false); + + /** + * Reads the icecast directory (XML file) and calls scanXmlData + */ + void readDir_ic(void); + + void selectTitle(unsigned char selectionChar); + /** + * Appends the file information to the given string. + * @param fileInfo a string where the file information will be appended + * @param file the file to return the information for + */ + void getFileInfoToDisplay(std::string& fileInfo, CAudiofileExt &file); + + void printSearchTree(); + + void buildSearchTree(); + + unsigned char getFirstChar(CAudiofileExt &file); + + void printTimevalDiff(timeval &start, timeval &end); + + /** + * Saves the current playlist into a .m3u playlist file. + */ + void savePlaylist(); + + /** + * Converts an absolute filename to a relative one + * as seen from a file in fromDir. + * Example: + * absFilename: /mnt/audio/A/abc.mp3 + * fromDir: /mnt/audio/B + * => ../A/abc.mp3 will be returned + * @param fromDir the directory from where we want to + * access the file + * @param absFilename the file we want to access in a + * relative way from fromDir (given as an absolute path) + * @return the location of absFilename as seen from fromDir + * (relative path) + */ + std::string absPath2Rel(const std::string& fromDir, + const std::string& absFilename); + + /** + * Asks the user if the file filename should be overwritten or not + * @param filename the name of the file + * @return true if file should be overwritten, false otherwise + */ + bool askToOverwriteFile(const std::string& filename); + bool openFilebrowser(void); + bool openSCbrowser(void); + bool clearPlaylist(void); + bool shufflePlaylist(void); + bool playNext(bool allow_rotate = false); + bool playPrev(bool allow_rotate = false); + + public: + CAudioPlayerGui(bool inetmode = false); + ~CAudioPlayerGui(); + int show(); + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + + +#endif diff --git a/src/gui/bedit/Makefile.am b/src/gui/bedit/Makefile.am new file mode 100644 index 000000000..8d78d480e --- /dev/null +++ b/src/gui/bedit/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +INCLUDES = \ + -I$(top_srcdir)/daemons \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/libeventserver \ + -I$(top_srcdir)/lib/libconfigfile \ + -I$(top_srcdir)/lib/xmltree \ + @FREETYPE_CFLAGS@ \ + -I$(top_srcdir)/lib + + +noinst_LIBRARIES = libneutrino_gui_bedit.a + +libneutrino_gui_bedit_a_SOURCES = \ + bouqueteditor_bouquets.cpp \ + bouqueteditor_channels.cpp \ + bouqueteditor_chanselect.cpp + diff --git a/src/gui/bedit/bouqueteditor_bouquets.cpp b/src/gui/bedit/bouqueteditor_bouquets.cpp new file mode 100644 index 000000000..797caf4c6 --- /dev/null +++ b/src/gui/bedit/bouqueteditor_bouquets.cpp @@ -0,0 +1,579 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +extern CBouquetManager *g_bouquetManager; + +#define ROUND_RADIUS 9 + +CBEBouquetWidget::CBEBouquetWidget() +{ + frameBuffer = CFrameBuffer::getInstance(); + + ButtonHeight = 25; + + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getHeight(); + + selected = 0; + liststart = 0; + state = beDefault; + blueFunction = beRename; + Bouquets = &g_bouquetManager->Bouquets; +} + +void CBEBouquetWidget::paintItem(int pos) +{ + uint8_t color; + fb_pixel_t bgcolor; + int ypos = y+ theight+0 + pos*fheight; + unsigned int current = liststart + pos; + + if (current == selected) { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor, ROUND_RADIUS, 3); + } else { + bool has_channels = true; + if(current < Bouquets->size()) + has_channels = ((*Bouquets)[current]->tvChannels.size() > 0) || ((*Bouquets)[current]->radioChannels.size() > 0); + color = has_channels ? COL_MENUCONTENT : COL_MENUCONTENTINACTIVE; + bgcolor = has_channels ? COL_MENUCONTENT_PLUS_0 : COL_MENUCONTENTINACTIVE_PLUS_0; + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor); + } + + if(current < Bouquets->size()) { + if ((current == selected) && (state == beMoving)) + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_YELLOW, x + 8, ypos+4); + + if ((*Bouquets)[current]->bLocked) + frameBuffer->paintIcon("lock.raw", x + 7, ypos); + + if ((*Bouquets)[current]->bHidden) + frameBuffer->paintIcon("hidden.raw", x + 37, ypos); + + //g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+68, ypos+ fheight, width-68, (*Bouquets)[current]->Name, color, 0, true); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+68, ypos+ fheight, width-68, (*Bouquets)[current]->bFav ? g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME) : (*Bouquets)[current]->Name, color, 0, true); + } +} + +void CBEBouquetWidget::paint() +{ + liststart = (selected/listmaxshow)*listmaxshow; + + for(unsigned int count=0;countpaintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((Bouquets->size()- 1)/ listmaxshow)+ 1; + float sbh= (sb- 4)/ sbc; + int sbs= (selected/listmaxshow); + + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ int(sbs* sbh) , 11, int(sbh), COL_MENUCONTENT_PLUS_3); +} + +void CBEBouquetWidget::paintHead() +{ + frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10,y+theight+0, width, g_Locale->getText(LOCALE_BOUQUETLIST_HEAD), COL_MENUHEAD, 0, true); // UTF-8 +} + +const struct button_label CBEBouquetWidgetButtons[3] = +{ + { NEUTRINO_ICON_BUTTON_RED , LOCALE_BOUQUETEDITOR_DELETE }, + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_BOUQUETEDITOR_ADD }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_BOUQUETEDITOR_MOVE } +}; + +void CBEBouquetWidget::paintFoot() +{ + struct button_label Button[4]; + Button[0] = CBEBouquetWidgetButtons[0]; + Button[1] = CBEBouquetWidgetButtons[1]; + Button[2] = CBEBouquetWidgetButtons[2]; + Button[3].button = NEUTRINO_ICON_BUTTON_BLUE; + + frameBuffer->paintBoxRel(x,y+height, width,ButtonHeight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2); + //frameBuffer->paintHLine(x, x+width, y, COL_INFOBAR_SHADOW_PLUS_0); + + switch( blueFunction) + { + case beRename: + Button[3].locale = LOCALE_BOUQUETEDITOR_RENAME; + break; + case beHide: + Button[3].locale = LOCALE_BOUQUETEDITOR_HIDE; + break; + case beLock: + Button[3].locale = LOCALE_BOUQUETEDITOR_LOCK; + break; + } + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 5, y + height + 4, (width - 28 - 10) / 4, 4, Button); + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DBOX, x+width - 28, y+height); +} + +void CBEBouquetWidget::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height+ButtonHeight); +} + +int CBEBouquetWidget::exec(CMenuTarget* parent, const std::string & actionKey) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = menu_return::RETURN_REPAINT; + + if (parent) + parent->hide(); + + width = w_max (500, 0); + height = h_max (440, 50); + listmaxshow = (height-theight-0)/fheight; + height = theight+0+listmaxshow*fheight; // recalc height + x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - height) / 2; + + Bouquets = &g_bouquetManager->Bouquets; + paintHead(); + paint(); + paintFoot(); + + bouquetsChanged = false; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_EPG]); + + bool loop=true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_EPG]); + + if ((msg == CRCInput::RC_timeout) || + (msg == (neutrino_msg_t)g_settings.key_channelList_cancel)) + { + if (state == beDefault) + { + if (bouquetsChanged) + { + int result = ShowLocalizedMessage(LOCALE_BOUQUETEDITOR_NAME, LOCALE_BOUQUETEDITOR_SAVECHANGES, CMessageBox::mbrYes, CMessageBox::mbAll); + + switch( result ) + { + case CMessageBox::mbrYes : + loop=false; + saveChanges(); + break; + case CMessageBox::mbrNo : + loop=false; + discardChanges(); + break; + case CMessageBox::mbrCancel : + paintHead(); + paint(); + paintFoot(); + break; + } + } + else + { + loop = false; + } + } + else if (state == beMoving) + { + cancelMoveBouquet(); + } + } + // + // -- For more convenience: include browsing of list (paging) (rasc, 2002-04-02) + // -- The keys should be configurable. Problem is: red/green key, which is the + // -- default in neutrino is used as a function key here... so use left/right + // + else if (msg==CRCInput::RC_up || msg==(neutrino_msg_t)g_settings.key_channelList_pageup) + { + if (!(Bouquets->empty())) + { + int step = 0; + int prev_selected = selected; + + step = (msg == (neutrino_msg_t)g_settings.key_channelList_pageup) ? listmaxshow : 1; // browse or step 1 + selected -= step; + if((prev_selected-step) < 0) // because of uint + { + selected = Bouquets->size()-1; + } + + if (state == beDefault) + { + paintItem(prev_selected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paint(); + } + else + { + paintItem(selected - liststart); + } + } + else if (state == beMoving) + { + internalMoveBouquet(prev_selected, selected); + } + } + } + else if (msg==CRCInput::RC_down || msg==(neutrino_msg_t)g_settings.key_channelList_pagedown) + { + unsigned int step = 0; + int prev_selected = selected; + + step = (msg == (neutrino_msg_t)g_settings.key_channelList_pagedown) ? listmaxshow : 1; // browse or step 1 + selected += step; + + if(selected >= Bouquets->size()) + { + if (((Bouquets->size() / listmaxshow) + 1) * listmaxshow == Bouquets->size() + listmaxshow) // last page has full entries + selected = 0; + else + selected = ((step == listmaxshow) && (selected < (((Bouquets->size() / listmaxshow) + 1) * listmaxshow))) ? (Bouquets->size() - 1) : 0; + } + + if (state == beDefault) + { + paintItem(prev_selected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paint(); + } + else + { + paintItem(selected - liststart); + } + } + else if (state == beMoving) + { + internalMoveBouquet(prev_selected, selected); + } + } + else if(msg==CRCInput::RC_red) + { + if (state == beDefault) + deleteBouquet(); + } + else if(msg==CRCInput::RC_green) + { + if (state == beDefault) + addBouquet(); + } + else if(msg==CRCInput::RC_yellow) + { + if (selected < Bouquets->size()) /* Bouquets->size() might be 0 */ + { + liststart = (selected/listmaxshow)*listmaxshow; + if (state == beDefault) + beginMoveBouquet(); + paintItem(selected - liststart); + } + } + else if(msg==CRCInput::RC_blue) + { + if (selected < Bouquets->size()) /* Bouquets->size() might be 0 */ + { + if (state == beDefault) + switch (blueFunction) + { + case beRename: + renameBouquet(); + break; + case beHide: + switchHideBouquet(); + break; + case beLock: + switchLockBouquet(); + break; + } + } + } + else if(msg==CRCInput::RC_setup) + { + if (state == beDefault) + switch (blueFunction) + { + case beRename: + blueFunction = beHide; + break; + case beHide: + blueFunction = beLock; + break; + case beLock: + blueFunction = beRename; + break; + } + paintFoot(); + } + else if(msg==CRCInput::RC_ok) + { + if (state == beDefault) + { + if (selected < Bouquets->size()) /* Bouquets->size() might be 0 */ + { + //CBEChannelWidget* channelWidget = new CBEChannelWidget((*Bouquets)[selected]->Name, selected); + CBEChannelWidget* channelWidget = new CBEChannelWidget((*Bouquets)[selected]->bFav ? g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME) : (*Bouquets)[selected]->Name, selected); + channelWidget->exec( this, ""); + if (channelWidget->hasChanged()) + bouquetsChanged = true; + delete channelWidget; + paintHead(); + paint(); + paintFoot(); + } + } + else if (state == beMoving) + { + finishMoveBouquet(); + } + } + else if( CRCInput::isNumeric(msg) ) + { + if (state == beDefault) + { + //kein pushback - wenn man versehentlich wo draufkommt is die edit-arbeit umsonst + //selected = oldselected; + //g_RCInput->postMsg( msg, data ); + //loop=false; + } + else if (state == beMoving) + { + cancelMoveBouquet(); + } + } + else + { + CNeutrinoApp::getInstance()->handleMsg( msg, data ); + // kein canceling... + } + } + hide(); + return res; +} + +void CBEBouquetWidget::deleteBouquet() +{ + if (selected >= Bouquets->size()) /* Bouquets->size() might be 0 */ + return; + + if (ShowMsgUTF(LOCALE_FILEBROWSER_DELETE, (*Bouquets)[selected]->bFav ? g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME) : (*Bouquets)[selected]->Name, CMessageBox::mbrNo, CMessageBox::mbYes|CMessageBox::mbNo)!=CMessageBox::mbrYes) + return; + + //g_Zapit->deleteBouquet(selected); + //Bouquets.clear(); + //g_Zapit->getBouquets(Bouquets, true, true); + g_bouquetManager->deleteBouquet(selected); + Bouquets = &g_bouquetManager->Bouquets; + if (selected >= Bouquets->size()) + selected = Bouquets->empty() ? 0 : (Bouquets->size() - 1); + bouquetsChanged = true; + paint(); +} + +void CBEBouquetWidget::addBouquet() +{ + std::string newName = inputName("", LOCALE_BOUQUETEDITOR_BOUQUETNAME); + if (!(newName.empty())) + { + //g_Zapit->addBouquet(ZapitTools::Latin1_to_UTF8(newName.c_str()).c_str()); + //Bouquets.clear(); + //g_Zapit->getBouquets(Bouquets, true, true); + g_bouquetManager->addBouquet(newName, true); + Bouquets = &g_bouquetManager->Bouquets; + selected = Bouquets->empty() ? 0 : (Bouquets->size() - 1); + bouquetsChanged = true; + } + paintHead(); + paint(); + paintFoot(); +} + +void CBEBouquetWidget::beginMoveBouquet() +{ + state = beMoving; + origPosition = selected; + newPosition = selected; +} + +void CBEBouquetWidget::finishMoveBouquet() +{ + state = beDefault; + if (newPosition != origPosition) + { + //g_Zapit->moveBouquet(origPosition, newPosition); + //Bouquets.clear(); + //g_Zapit->getBouquets(Bouquets, true, true); + Bouquets = &g_bouquetManager->Bouquets; + bouquetsChanged = true; + } + paint(); +} + +void CBEBouquetWidget::cancelMoveBouquet() +{ + state = beDefault; + internalMoveBouquet( newPosition, origPosition); + bouquetsChanged = false; +} + +void CBEBouquetWidget::internalMoveBouquet( unsigned int fromPosition, unsigned int toPosition) +{ + if ( (int) toPosition == -1 ) return; + if ( toPosition == Bouquets->size()) return; + + //g_Zapit->moveBouquet(fromPosition, toPosition); + g_bouquetManager->moveBouquet(fromPosition, toPosition); + Bouquets = &g_bouquetManager->Bouquets; + bouquetsChanged = true; +#if 0 + CZapitClient::responseGetBouquets Bouquet = Bouquets[fromPosition]; + if (fromPosition < toPosition) + { + for (unsigned int i=fromPosition; i toPosition) + { + for (unsigned int i=fromPosition; i>toPosition; i--) + Bouquets[i] = Bouquets[i-1]; + } + Bouquets[toPosition] = Bouquet; +#endif + selected = toPosition; + newPosition = toPosition; + paint(); +} + +void CBEBouquetWidget::renameBouquet() +{ + if ((*Bouquets)[selected]->bFav) + return; + + std::string newName = inputName((*Bouquets)[selected]->Name.c_str(), LOCALE_BOUQUETEDITOR_NEWBOUQUETNAME); + if (newName != (*Bouquets)[selected]->Name) + { + //g_Zapit->renameBouquet(selected, ZapitTools::Latin1_to_UTF8(newName.c_str()).c_str()); + //Bouquets.clear(); + //g_Zapit->getBouquets(Bouquets, true, true); + + g_bouquetManager->Bouquets[selected]->Name = newName; + g_bouquetManager->Bouquets[selected]->bUser = true; + //Bouquets = &g_bouquetManager->Bouquets; + bouquetsChanged = true; + } + paintHead(); + paint(); + paintFoot(); +} + +void CBEBouquetWidget::switchHideBouquet() +{ + bouquetsChanged = true; + (*Bouquets)[selected]->bHidden = !(*Bouquets)[selected]->bHidden; + //g_Zapit->setBouquetHidden(selected, Bouquets[selected].hidden); + paint(); +} + +void CBEBouquetWidget::switchLockBouquet() +{ + bouquetsChanged = true; + (*Bouquets)[selected]->bLocked = !(*Bouquets)[selected]->bLocked; + //g_Zapit->setBouquetLock(selected, Bouquets[selected].locked); + paint(); +} + +std::string CBEBouquetWidget::inputName(const char * const defaultName, const neutrino_locale_t caption) +{ + char Name[30]; + + strncpy(Name, defaultName, 30); + + CStringInputSMS * nameInput = new CStringInputSMS(caption, Name, 29, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-.,:|!?/ "); + nameInput->exec(this, ""); + delete nameInput; + + return std::string(Name); +} + +void CBEBouquetWidget::saveChanges() +{ + CHintBox* hintBox= new CHintBox(LOCALE_BOUQUETEDITOR_NAME, g_Locale->getText(LOCALE_BOUQUETEDITOR_SAVINGCHANGES), 480); // UTF-8 + hintBox->paint(); + g_Zapit->saveBouquets(); + hintBox->hide(); + delete hintBox; +} + +void CBEBouquetWidget::discardChanges() +{ + CHintBox* hintBox= new CHintBox(LOCALE_BOUQUETEDITOR_NAME, g_Locale->getText(LOCALE_BOUQUETEDITOR_DISCARDINGCHANGES), 480); // UTF-8 + hintBox->paint(); + g_Zapit->restoreBouquets(); + hintBox->hide(); + delete hintBox; +} diff --git a/src/gui/bedit/bouqueteditor_bouquets.h b/src/gui/bedit/bouqueteditor_bouquets.h new file mode 100644 index 000000000..4a0cd2ac4 --- /dev/null +++ b/src/gui/bedit/bouqueteditor_bouquets.h @@ -0,0 +1,121 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __bouqueteditor_bouquets__ +#define __bouqueteditor_bouquets__ + +#include +#include + +#include +#include +#include + +#include + +/* class for handling when bouquets changed. */ +/* This class should be a temporarily work around */ +/* and should be replaced by standard neutrino event handlers */ +/* (libevent) */ +class CBouquetEditorEvents +{ +public: + virtual void onBouquetsChanged() {}; +}; + +class CBEBouquetWidget : public CMenuWidget +{ + + private: + + CFrameBuffer *frameBuffer; + + enum + { + beDefault, + beMoving + } state; + + enum + { + beRename, + beHide, + beLock + } blueFunction; + + unsigned int selected; + unsigned int origPosition; + unsigned int newPosition; + + unsigned int liststart; + unsigned int listmaxshow; + int fheight; // Fonthoehe Bouquetlist-Inhalt + int theight; // Fonthoehe Bouquetlist-Titel + + int ButtonHeight; + //std::string name; + bool bouquetsChanged; + int width; + int height; + int x; + int y; + + void paintItem(int pos); + void paint(); + void paintHead(); + void paintFoot(); + void hide(); + + void deleteBouquet(); + void addBouquet(); + void beginMoveBouquet(); + void finishMoveBouquet(); + void cancelMoveBouquet(); + void internalMoveBouquet( unsigned int fromPosition, unsigned int toPosition); + void renameBouquet(); + void switchHideBouquet(); + void switchLockBouquet(); + + void saveChanges(); + void discardChanges(); + + std::string inputName(const char * const defaultName, const neutrino_locale_t caption); + + public: + CBEBouquetWidget(); + + //CZapitClient::BouquetList Bouquets; + BouquetList * Bouquets; + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + + +#endif diff --git a/src/gui/bedit/bouqueteditor_channels.cpp b/src/gui/bedit/bouqueteditor_channels.cpp new file mode 100644 index 000000000..e0e48abe9 --- /dev/null +++ b/src/gui/bedit/bouqueteditor_channels.cpp @@ -0,0 +1,417 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +extern tallchans allchans; +extern CBouquetManager *g_bouquetManager; + +#define ROUND_RADIUS 9 + +CBEChannelWidget::CBEChannelWidget(const std::string & Caption, unsigned int Bouquet) +{ + frameBuffer = CFrameBuffer::getInstance(); + selected = 0; + ButtonHeight = 25; + + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getHeight(); + + liststart = 0; + state = beDefault; + caption = Caption; + bouquet = Bouquet; + mode = CZapitClient::MODE_TV; +} + +void CBEChannelWidget::paintItem(int pos) +{ + uint8_t color; + fb_pixel_t bgcolor; + int ypos = y+ theight+0 + pos*fheight; + unsigned int current = liststart + pos; + + if(current == selected) { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor, ROUND_RADIUS, 3); + } else { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor); + } + + if ((current == selected) && (state == beMoving)) + { + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_YELLOW, x + 8, ypos+4); + } + if(current < Channels->size()) + { + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 5+ numwidth+ 10, ypos+ fheight, width- numwidth- 20- 15, (*Channels)[current]->getName(), color, 0, true); + } +} + +void CBEChannelWidget::paint() +{ + liststart = (selected/listmaxshow)*listmaxshow; + int lastnum = liststart + listmaxshow; + + if(lastnum<10) + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("0"); + else if(lastnum<100) + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("00"); + else if(lastnum<1000) + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("000"); + else if(lastnum<10000) + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("0000"); + else // if(lastnum<100000) + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("00000"); + + for(unsigned int count=0;countpaintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((Channels->size()- 1)/ listmaxshow)+ 1; + float sbh= (sb- 4)/ sbc; + int sbs= (selected/listmaxshow); + + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ int(sbs* sbh) , 11, int(sbh), COL_MENUCONTENT_PLUS_3); +} + +void CBEChannelWidget::paintHead() +{ + frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10,y+theight+0, width, caption.c_str() , COL_MENUHEAD, 0, true); +} + +const struct button_label CBEChannelWidgetButtons[4] = +{ + { NEUTRINO_ICON_BUTTON_RED , LOCALE_BOUQUETEDITOR_DELETE }, + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_BOUQUETEDITOR_ADD }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_BOUQUETEDITOR_MOVE }, + { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_BOUQUETEDITOR_SWITCHMODE } +}; + +void CBEChannelWidget::paintFoot() +{ + frameBuffer->paintBoxRel(x,y+height, width,ButtonHeight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2); + //frameBuffer->paintHLine(x, x+width, y, COL_INFOBAR_SHADOW_PLUS_0); + + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 10, y + height + 4, (width - 20) / 4, 4, CBEChannelWidgetButtons); +} + +void CBEChannelWidget::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height+ButtonHeight); +} + +int CBEChannelWidget::exec(CMenuTarget* parent, const std::string & actionKey) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = menu_return::RETURN_REPAINT; + + if (parent) + parent->hide(); + + + width = w_max (500, 0); + height = h_max (440, 50); + listmaxshow = (height-theight-0)/fheight; + height = theight+0+listmaxshow*fheight; // recalc height + x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - height) / 2; + + Channels = mode == CZapitClient::MODE_TV ? &(g_bouquetManager->Bouquets[bouquet]->tvChannels) : &(g_bouquetManager->Bouquets[bouquet]->radioChannels); + paintHead(); + paint(); + paintFoot(); + + channelsChanged = false; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_EPG]); + + bool loop=true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_EPG]); + + if ((msg == CRCInput::RC_timeout) || + (msg == (neutrino_msg_t)g_settings.key_channelList_cancel)) + { + if (state == beDefault) + { + loop = false; + } + else if (state == beMoving) + { + cancelMoveChannel(); + } + } + else if (msg==CRCInput::RC_up || msg==(neutrino_msg_t)g_settings.key_channelList_pageup) + { + if (!(Channels->empty())) + { + int step = 0; + int prev_selected = selected; + + step = (msg==(neutrino_msg_t)g_settings.key_channelList_pageup) ? listmaxshow : 1; // browse or step 1 + selected -= step; + if((prev_selected-step) < 0) // because of uint + { + selected = Channels->size() - 1; + } + + if (state == beDefault) + { + paintItem(prev_selected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paint(); + } + else + { + paintItem(selected - liststart); + } + } + else if (state == beMoving) + { + internalMoveChannel(prev_selected, selected); + } + } + } + else if (msg==CRCInput::RC_down || msg==(neutrino_msg_t)g_settings.key_channelList_pagedown) + { + unsigned int step = 0; + int prev_selected = selected; + + step = (msg==(neutrino_msg_t)g_settings.key_channelList_pagedown) ? listmaxshow : 1; // browse or step 1 + selected += step; + + if(selected >= Channels->size()) + { + if (((Channels->size() / listmaxshow) + 1) * listmaxshow == Channels->size() + listmaxshow) // last page has full entries + selected = 0; + else + selected = ((step == listmaxshow) && (selected < (((Channels->size() / listmaxshow) + 1) * listmaxshow))) ? (Channels->size() - 1) : 0; + } + + if (state == beDefault) + { + paintItem(prev_selected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paint(); + } + else + { + paintItem(selected - liststart); + } + } + else if (state == beMoving) + { + internalMoveChannel(prev_selected, selected); + } + } + else if(msg==CRCInput::RC_red) + { + if (state == beDefault) + deleteChannel(); + } + else if(msg==CRCInput::RC_green) + { + if (state == beDefault) + addChannel(); + } + else if(msg==CRCInput::RC_blue) + { + if (state == beDefault) + { + if (mode == CZapitClient::MODE_TV) + mode = CZapitClient::MODE_RADIO; + else + mode = CZapitClient::MODE_TV; + + Channels = mode == CZapitClient::MODE_TV ? &(g_bouquetManager->Bouquets[bouquet]->tvChannels) : &(g_bouquetManager->Bouquets[bouquet]->radioChannels); + + selected = 0; + paint(); + } + } + else if(msg==CRCInput::RC_yellow) + { + liststart = (selected/listmaxshow)*listmaxshow; + if (state == beDefault) + beginMoveChannel(); + paintItem(selected - liststart); + } + else if(msg==CRCInput::RC_ok) + { + if (state == beDefault) + { + if (selected < Channels->size()) /* Channels.size() might be 0 */ + g_Zapit->zapTo_serviceID((*Channels)[selected]->channel_id); + + } else if (state == beMoving) { + finishMoveChannel(); + } + } + else if( CRCInput::isNumeric(msg) ) + { + if (state == beDefault) + { + //kein pushback - wenn man versehentlich wo draufkommt is die edit-arbeit umsonst + //selected = oldselected; + //g_RCInput->postMsg( msg, data ); + //loop=false; + } + else if (state == beMoving) + { + cancelMoveChannel(); + } + } + else if((msg == CRCInput::RC_sat) || (msg == CRCInput::RC_favorites)) { + } + else + { + CNeutrinoApp::getInstance()->handleMsg( msg, data ); + } + } + hide(); + return res; +} + +void CBEChannelWidget::deleteChannel() +{ + if (selected >= Channels->size()) /* Channels.size() might be 0 */ + return; + + if (ShowMsgUTF(LOCALE_FILEBROWSER_DELETE, (*Channels)[selected]->getName(), CMessageBox::mbrNo, CMessageBox::mbYes|CMessageBox::mbNo)!=CMessageBox::mbrYes) + return; + + g_bouquetManager->Bouquets[bouquet]->removeService((*Channels)[selected]->channel_id); + + Channels = mode == CZapitClient::MODE_TV ? &(g_bouquetManager->Bouquets[bouquet]->tvChannels) : &(g_bouquetManager->Bouquets[bouquet]->radioChannels); + + if (selected >= Channels->size()) + selected = Channels->empty() ? 0 : (Channels->size() - 1); + channelsChanged = true; + paint(); +} + +void CBEChannelWidget::addChannel() +{ + CBEChannelSelectWidget* channelSelectWidget = new CBEChannelSelectWidget(caption, bouquet, mode); + + channelSelectWidget->exec(this, ""); + if (channelSelectWidget->hasChanged()) + { + channelsChanged = true; + Channels = mode == CZapitClient::MODE_TV ? &(g_bouquetManager->Bouquets[bouquet]->tvChannels) : &(g_bouquetManager->Bouquets[bouquet]->radioChannels); + } + delete channelSelectWidget; + paintHead(); + paint(); + paintFoot(); +} + +void CBEChannelWidget::beginMoveChannel() +{ + state = beMoving; + origPosition = selected; + newPosition = selected; +} + +void CBEChannelWidget::finishMoveChannel() +{ + state = beDefault; + paint(); +} + +void CBEChannelWidget::cancelMoveChannel() +{ + state = beDefault; + internalMoveChannel( newPosition, origPosition); + channelsChanged = false; +} + +void CBEChannelWidget::internalMoveChannel( unsigned int fromPosition, unsigned int toPosition) +{ + if ( (int) toPosition == -1 ) return; + if ( toPosition == Channels->size()) return; + + g_bouquetManager->Bouquets[bouquet]->moveService(fromPosition, toPosition, + mode == CZapitClient::MODE_TV ? 1 : 2); + + channelsChanged = true; + Channels = mode == CZapitClient::MODE_TV ? &(g_bouquetManager->Bouquets[bouquet]->tvChannels) : &(g_bouquetManager->Bouquets[bouquet]->radioChannels); + + selected = toPosition; + newPosition = toPosition; + paint(); +} + +bool CBEChannelWidget::hasChanged() +{ + return (channelsChanged); +} diff --git a/src/gui/bedit/bouqueteditor_channels.h b/src/gui/bedit/bouqueteditor_channels.h new file mode 100644 index 000000000..8dbc27f53 --- /dev/null +++ b/src/gui/bedit/bouqueteditor_channels.h @@ -0,0 +1,103 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __bouqueteditor_channels__ +#define __bouqueteditor_channels__ + +#include +#include + +#include + +#include +#include +#include + +class CBEChannelWidget : public CMenuWidget +{ + + private: + + CFrameBuffer *frameBuffer; + + enum state_ + { + beDefault, + beMoving + } state; + + unsigned int selected; + unsigned int origPosition; + unsigned int newPosition; + + unsigned int liststart; + unsigned int listmaxshow; + unsigned int numwidth; + int fheight; + int theight; + + int ButtonHeight; + std::string caption; + bool channelsChanged; + + CZapitClient::channelsMode mode; + + unsigned int bouquet; + + int width; + int height; + int x; + int y; + + void paintItem(int pos); + void paint(); + void paintHead(); + void paintFoot(); + void hide(); + + void deleteChannel(); + void addChannel(); + void beginMoveChannel(); + void finishMoveChannel(); + void cancelMoveChannel(); + void internalMoveChannel( unsigned int fromPosition, unsigned int toPosition); + + public: + CBEChannelWidget( const std::string & Caption, unsigned int Bouquet); + + //CZapitClient::BouquetChannelList Channels; + ZapitChannelList * Channels; + int exec(CMenuTarget* parent, const std::string & actionKey); + bool hasChanged(); +}; + +#endif diff --git a/src/gui/bedit/bouqueteditor_chanselect.cpp b/src/gui/bedit/bouqueteditor_chanselect.cpp new file mode 100644 index 000000000..663155f8f --- /dev/null +++ b/src/gui/bedit/bouqueteditor_chanselect.cpp @@ -0,0 +1,176 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define ROUND_RADIUS 9 + +extern tallchans allchans; +extern CBouquetManager *g_bouquetManager; +void addChannelToBouquet(const unsigned int bouquet, const t_channel_id channel_id); + +CBEChannelSelectWidget::CBEChannelSelectWidget(const std::string & Caption, unsigned int Bouquet, CZapitClient::channelsMode Mode) + :CListBox(Caption.c_str()) +{ + bouquet = Bouquet; + mode = Mode; + ButtonHeight = 25; + + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getHeight(); + + liststart = 0; +} + +uint CBEChannelSelectWidget::getItemCount() +{ + return Channels.size(); +} + +bool CBEChannelSelectWidget::isChannelInBouquet( int index) +{ + for (unsigned int i=0; i< bouquetChannels->size(); i++) + { + if ((*bouquetChannels)[i]->channel_id == Channels[index]->channel_id) + return true; + } + return false; +} + +bool CBEChannelSelectWidget::hasChanged() +{ + return modified; +} + +void CBEChannelSelectWidget::paintItem(uint32_t itemNr, int paintNr, bool selected) +{ + int ypos = y+ theight + paintNr*fheight; + + uint8_t color; + fb_pixel_t bgcolor; + if (selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor, ROUND_RADIUS, 3); + } + else + { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor); + } + + + if(itemNr < getItemCount()) + { + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x + 8 + NEUTRINO_ICON_BUTTON_GREEN_WIDTH + 8, ypos+ fheight, width - (8 + NEUTRINO_ICON_BUTTON_GREEN_WIDTH + 8 + 8), Channels[itemNr]->getName(), color, 0, true); + + if( isChannelInBouquet(itemNr)) + { + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_GREEN, x+8, ypos+4); + } + else + { + frameBuffer->paintBoxRel(x+8, ypos+4, NEUTRINO_ICON_BUTTON_GREEN_WIDTH, fheight-4, bgcolor); + } + } +} + +void CBEChannelSelectWidget::onOkKeyPressed() +{ + setModified(); + if (isChannelInBouquet(selected)) + g_bouquetManager->Bouquets[bouquet]->removeService(Channels[selected]->channel_id); + else + addChannelToBouquet( bouquet, Channels[selected]->channel_id); + + bouquetChannels = mode == CZapitClient::MODE_TV ? &(g_bouquetManager->Bouquets[bouquet]->tvChannels) : &(g_bouquetManager->Bouquets[bouquet]->radioChannels); + + paintItem( selected, selected - liststart, false); + g_RCInput->postMsg( CRCInput::RC_down, 0 ); +} + +int CBEChannelSelectWidget::exec(CMenuTarget* parent, const std::string & actionKey) +{ + width = w_max (500, 0); + height = h_max (440, 50); + listmaxshow = (height-theight-0)/fheight; + height = theight+0+listmaxshow*fheight; // recalc height + x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - height) / 2; + + bouquetChannels = mode == CZapitClient::MODE_TV ? &(g_bouquetManager->Bouquets[bouquet]->tvChannels) : &(g_bouquetManager->Bouquets[bouquet]->radioChannels); + + Channels.clear(); + if (mode == CZapitClient::MODE_RADIO) { + for (tallchans_iterator it = allchans.begin(); it != allchans.end(); it++) + if (it->second.getServiceType() == ST_DIGITAL_RADIO_SOUND_SERVICE) + Channels.push_back(&(it->second)); + } else { + for (tallchans_iterator it = allchans.begin(); it != allchans.end(); it++) + if (it->second.getServiceType() != ST_DIGITAL_RADIO_SOUND_SERVICE) + Channels.push_back(&(it->second)); + } + sort(Channels.begin(), Channels.end(), CmpChannelByChName()); + + return CListBox::exec(parent, actionKey); +} + + +void CBEChannelSelectWidget::paintFoot() +{ + int ButtonWidth = width / 3; + frameBuffer->paintBoxRel(x,y+height, width,ButtonHeight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2); + //frameBuffer->paintHLine(x, x+width, y, COL_INFOBAR_SHADOW_PLUS_0); + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, x+width- 3* ButtonWidth+ 8, y+height+1); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+width- 3* ButtonWidth+ 38, y+height+24 - 2, width, g_Locale->getText(LOCALE_BOUQUETEDITOR_SWITCH), COL_INFOBAR, 0, true); // UTF-8 + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HOME, x+width - ButtonWidth+ 8, y+height+1); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+width - ButtonWidth+ 38, y+height+24 - 2, width, g_Locale->getText(LOCALE_BOUQUETEDITOR_RETURN), COL_INFOBAR, 0, true); // UTF-8 +} diff --git a/src/gui/bedit/bouqueteditor_chanselect.h b/src/gui/bedit/bouqueteditor_chanselect.h new file mode 100644 index 000000000..fa1f11098 --- /dev/null +++ b/src/gui/bedit/bouqueteditor_chanselect.h @@ -0,0 +1,70 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __bouqueteditor_chanselect__ +#define __bouqueteditor_chanselect__ + +#include +#include + +#include + +#include +#include +#include + +class CBEChannelSelectWidget : public CListBox +{ + private: + + unsigned int bouquet; + CZapitClient::channelsMode mode; + bool isChannelInBouquet( int index); + + uint getItemCount(); + void paintItem(uint32_t itemNr, int paintNr, bool selected); + void paintFoot(); + void onOkKeyPressed(); + + public: + //CZapitClient::BouquetChannelList Channels; // list of all channels + //CZapitClient::BouquetChannelList bouquetChannels; // list of chans that are currently selected + ZapitChannelList Channels; + ZapitChannelList * bouquetChannels; + + CBEChannelSelectWidget(const std::string & Caption, unsigned int Bouquet, CZapitClient::channelsMode Mode); + int exec(CMenuTarget* parent, const std::string & actionKey); + bool hasChanged(); + +}; + +#endif + diff --git a/src/gui/bookmarkmanager.cpp b/src/gui/bookmarkmanager.cpp new file mode 100644 index 000000000..d71dfdc9e --- /dev/null +++ b/src/gui/bookmarkmanager.cpp @@ -0,0 +1,489 @@ +/* + Neutrino-GUI - DBoxII-Project + + Part of Movieplayer (c) 2003, 2004 by gagga + Based on code by Zwen. Thanks. + + $Id: bookmarkmanager.cpp,v 1.12 2004/05/20 07:38:34 thegoodguy Exp $ + + Homepage: http://www.giggo.de/dbox2/movieplayer.html + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define info_height 60 + + +CBookmark::CBookmark(const std::string & inName, const std::string & inUrl, const std::string & inTime) +{ + name = inName; + url = inUrl; + time = inTime; +} + +//------------------------------ + +int CBookmarkManager::addBookmark (CBookmark inBookmark) { + if (bookmarks.size() < MAXBOOKMARKS) + { + bookmarks.push_back(inBookmark); + printf("CBookmarkManager: addBookmark: %s %s\n", inBookmark.getName(), inBookmark.getTime()); + bookmarksmodified = true; + return 0; + } + // TODO:show dialog to delete old bookmark + return -1; +} + +//------------------------------------------------------------------------ +inline int CBookmarkManager::createBookmark (const std::string & name, const std::string & url, const std::string & time) { + return addBookmark(CBookmark(name, url, time)); +} + +int CBookmarkManager::createBookmark (const std::string & url, const std::string & time) { + char bookmarkname[26]=""; + CStringInputSMS bookmarkname_input(LOCALE_MOVIEPLAYER_BOOKMARKNAME, bookmarkname, 25, LOCALE_MOVIEPLAYER_BOOKMARKNAME_HINT1, LOCALE_MOVIEPLAYER_BOOKMARKNAME_HINT2, "abcdefghijklmnopqrstuvwxyz0123456789-_"); + bookmarkname_input.exec(NULL, ""); + // TODO: return -1 if no name was entered + if(!strlen(bookmarkname)) return -1; + return createBookmark(std::string(bookmarkname), url, time); +} + +//------------------------------------------------------------------------ + +void CBookmarkManager::removeBookmark (unsigned int index) { + std::vector::iterator p = bookmarks.begin()+index; + bookmarks.erase(p); + bookmarksmodified=true; +} + +//------------------------------------------------------------------------ + +void CBookmarkManager::renameBookmark (unsigned int index) { + if (index >= bookmarks.size()) + return; + + CBookmark & theBookmark = bookmarks[index]; + char bookmarkname[26]; + strncpy (bookmarkname, theBookmark.getName(), 25); + CStringInputSMS bookmarkname_input(LOCALE_MOVIEPLAYER_BOOKMARKNAME, bookmarkname, 25, LOCALE_MOVIEPLAYER_BOOKMARKNAME_HINT1, LOCALE_MOVIEPLAYER_BOOKMARKNAME_HINT2, "abcdefghijklmnopqrstuvwxyz0123456789-_"); + bookmarkname_input.exec(NULL, ""); + + if (strcmp(theBookmark.getName(), bookmarkname) != 0) + { + theBookmark.setName(std::string(bookmarkname)); + bookmarksmodified=true; + } +} + +#define BOOKMARKSTRINGLENGTH (10 + 1) +#define BOOKMARKSTRINGMODIFICATIONPOINT 8 +const char * const BOOKMARKSTRING = "bookmark0."; + +//------------------------------------------------------------------------ +void CBookmarkManager::readBookmarkFile() { + if (bookmarkfile.loadConfig(BOOKMARKFILE)) + { + char bookmarkstring[BOOKMARKSTRINGLENGTH]; + strcpy(bookmarkstring, BOOKMARKSTRING); + + bookmarksmodified = false; + bookmarks.clear(); + + unsigned int bookmarkcount = bookmarkfile.getInt32("bookmarkcount", 0); + + if (bookmarkcount > MAXBOOKMARKS) + bookmarkcount = MAXBOOKMARKS; + + while (bookmarkcount-- > 0) + { + std::string tmp = bookmarkstring; + tmp += "name"; + std::string bookmarkname = bookmarkfile.getString(tmp, ""); + tmp = bookmarkstring; + tmp += "url"; + std::string bookmarkurl = bookmarkfile.getString(tmp, ""); + tmp = bookmarkstring; + tmp += "time"; + std::string bookmarktime = bookmarkfile.getString(tmp, ""); + + bookmarks.push_back(CBookmark(bookmarkname, bookmarkurl, bookmarktime)); + + bookmarkstring[BOOKMARKSTRINGMODIFICATIONPOINT]++; + } + } + else + bookmarkfile.clear(); +} + +//------------------------------------------------------------------------ +void CBookmarkManager::writeBookmarkFile() { + char bookmarkstring[BOOKMARKSTRINGLENGTH]; + strcpy(bookmarkstring, BOOKMARKSTRING); + + printf("CBookmarkManager: Writing bookmark file\n"); + + for (std::vector::const_iterator it = bookmarks.begin(); it != bookmarks.end(); it++) + { + std::string tmp = bookmarkstring; + tmp += "name"; + bookmarkfile.setString(tmp, it->getName()); + tmp = bookmarkstring; + tmp += "url"; + bookmarkfile.setString(tmp, it->getUrl()); + tmp = bookmarkstring; + tmp += "time"; + bookmarkfile.setString(tmp, it->getTime()); + + bookmarkstring[BOOKMARKSTRINGMODIFICATIONPOINT]++; + } + bookmarkfile.setInt32("bookmarkcount", bookmarks.size()); + bookmarkfile.saveConfig(BOOKMARKFILE); +} + +//------------------------------------------------------------------------ + +CBookmarkManager::CBookmarkManager() : bookmarkfile ('\t') +{ + readBookmarkFile(); +} + +//------------------------------------------------------------------------ + +CBookmarkManager::~CBookmarkManager () { + flush(); +} + +//------------------------------------------------------------------------ + +int CBookmarkManager::getBookmarkCount(void) const { + return bookmarks.size(); +} + +//------------------------------------------------------------------------ + +int CBookmarkManager::getMaxBookmarkCount(void) const { + return MAXBOOKMARKS; +} + +//------------------------------------------------------------------------ + +void CBookmarkManager::flush() { + if (bookmarksmodified) { + writeBookmarkFile(); + } +} + +//------------------------------------------------------------------------ + +const CBookmark * CBookmarkManager::getBookmark(CMenuTarget* parent) +{ + if(parent) + { + parent->hide(); + } + + frameBuffer = CFrameBuffer::getInstance(); + visible = false; + selected = 0; + // Max + width = 720; + if(g_settings.screen_EndX-g_settings.screen_StartX < width) + width=g_settings.screen_EndX-g_settings.screen_StartX-10; + buttonHeight = 25; + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + x=(((g_settings.screen_EndX- g_settings.screen_StartX)-width) / 2) + g_settings.screen_StartX; + y=(((g_settings.screen_EndY- g_settings.screen_StartY)-( height+ info_height) ) / 2) + g_settings.screen_StartY; + listmaxshow = (height-theight-0)/(fheight*2); + liststart = 0; + + height = (g_settings.screen_EndY-g_settings.screen_StartY)-(info_height+50); + listmaxshow = (height-theight-0)/(fheight*2); + height = theight+0+listmaxshow*fheight*2; // recalc height + if(bookmarks.size() < listmaxshow) + { + listmaxshow=bookmarks.size(); + height = theight+0+listmaxshow*fheight*2; // recalc height + } + if(selected==bookmarks.size() && !(bookmarks.empty())) + { + selected=bookmarks.size()-1; + liststart = (selected/listmaxshow)*listmaxshow; + } + x=(((g_settings.screen_EndX- g_settings.screen_StartX)-width) / 2) + g_settings.screen_StartX; + y=(((g_settings.screen_EndY- g_settings.screen_StartY)-( height+ info_height) ) / 2) + g_settings.screen_StartY; + + + int res = -1; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings::TIMING_MENU]); + uint32_t msg; uint32_t data; + + bool loop=true; + bool update=true; + while(loop) + { + if(update) + { + hide(); + update=false; + paint(); + } + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings::TIMING_MENU]); + + if( ( msg == CRCInput::RC_timeout ) || + ( msg == CRCInput::RC_home) ) + { //Exit after timeout or cancel key + res = -1; + loop=false; + } + else if ((msg == CRCInput::RC_up) && !(bookmarks.empty())) + { + int prevselected=selected; + if(selected==0) + { + selected = bookmarks.size()-1; + } + else + selected--; + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paint(); + } + else + { + paintItem(selected - liststart); + } + } + else if ((msg == CRCInput::RC_down) && !(bookmarks.empty())) + { + int prevselected=selected; + selected = (selected+1)%bookmarks.size(); + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paint(); + } + else + { + paintItem(selected - liststart); + } + } + else if ((msg == CRCInput::RC_ok) && !(bookmarks.empty())) + { + res = selected; + loop=false; + } + else if((msg == CRCInput::RC_red) && !(bookmarks.empty())) + { + removeBookmark(selected); + update=true; + } + else if((msg==CRCInput::RC_yellow) && !(bookmarks.empty())) + { + renameBookmark(selected); + update=true; + } + else if((msg==CRCInput::RC_blue)||(msg==CRCInput::RC_green)|| + (CRCInput::isNumeric(msg)) ) + { + //Ignore + } + else if(msg==CRCInput::RC_setup) + { + res=-1; + loop=false; + } + else if( msg == CRCInput::RC_help ) + { + // TODO Add Help + } + else + { + if( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + hide(); + + if ((res >=0) && (((unsigned int)res) < bookmarks.size())) + return &bookmarks[res]; + else + return NULL; +} + +//------------------------------------------------------------------------ +void CBookmarkManager::paintItem(int pos) +{ + int ypos = y+ theight+0 + pos*fheight*2; + + uint8_t color; + fb_pixel_t bgcolor; + + if (pos & 1) + { + color = COL_MENUCONTENTDARK; + bgcolor = COL_MENUCONTENTDARK_PLUS_0; + } + else + { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + } + + if (liststart + pos == selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + + int real_width=width; + if(bookmarks.size()>listmaxshow) + { + real_width-=15; //scrollbar + } + + frameBuffer->paintBoxRel(x,ypos, real_width, 2*fheight, bgcolor); + if(liststart+posRenderString(x+10,ypos+fheight, real_width-10, theBookmark.getName(), color, fheight, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10,ypos+2*fheight, real_width-10, theBookmark.getUrl(), color, fheight, true); // UTF-8 + + // LCD Display + if(liststart+pos==selected) + { + CVFD::getInstance()->showMenuText(0, theBookmark.getName(), -1, true); // UTF-8 + CVFD::getInstance()->showMenuText(1, theBookmark.getUrl(), -1, true); // UTF-8 + } + } +} + +//------------------------------------------------------------------------ + +void CBookmarkManager::hide() +{ + if(visible) + { + frameBuffer->paintBackgroundBoxRel(x, y, width, height+ info_height+ 5); + visible = false; + } +} + +//------------------------------------------------------------------------ +void CBookmarkManager::paintHead() +{ + frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0); + frameBuffer->paintIcon("bookmarkmanager.raw",x+5,y+4); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+35,y+theight+0, width- 45, g_Locale->getText(LOCALE_BOOKMARKMANAGER_NAME), COL_MENUHEAD, 0, true); // UTF-8 + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, x+ width- 30, y+ 5 ); +} + +const struct button_label BookmarkmanagerButtons[2] = +{ + { NEUTRINO_ICON_BUTTON_RED , LOCALE_BOOKMARKMANAGER_DELETE }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_BOOKMARKMANAGER_RENAME } +}; + +//------------------------------------------------------------------------ +void CBookmarkManager::paintFoot() +{ + int ButtonWidth = (width - 20) / 4; + frameBuffer->paintBoxRel(x,y+height, width,buttonHeight, COL_MENUHEAD_PLUS_0); + frameBuffer->paintHLine(x, x+width, y, COL_INFOBAR_SHADOW_PLUS_0); + + if (bookmarks.empty()) { + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, x+width- 1* ButtonWidth + 10, y+height); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+width-1 * ButtonWidth + 38, y+height+24 - 2, ButtonWidth- 28, g_Locale->getText(LOCALE_BOOKMARKMANAGER_SELECT), COL_INFOBAR, 0, true); // UTF-8 + } + else + { + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 10, y + height + 4, ButtonWidth, 2, BookmarkmanagerButtons); + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, x+width- 1* ButtonWidth + 10, y+height); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+width-1 * ButtonWidth + 38, y+height+24 - 2, ButtonWidth- 28, g_Locale->getText(LOCALE_BOOKMARKMANAGER_SELECT), COL_INFOBAR, 0, true); // UTF-8 + } +} + +//------------------------------------------------------------------------ +void CBookmarkManager::paint() +{ + unsigned int page_nr = (listmaxshow == 0) ? 0 : (selected / listmaxshow); + liststart = page_nr * listmaxshow; + + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, g_Locale->getText(LOCALE_BOOKMARKMANAGER_NAME)); + + paintHead(); + + for(unsigned int count=0;countlistmaxshow) + { + int ypos = y+ theight; + int sb = 2*fheight* listmaxshow; + frameBuffer->paintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((bookmarks.size()- 1)/ listmaxshow)+ 1; + float sbh= (sb- 4)/ sbc; + + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ int(page_nr * sbh) , 11, int(sbh), COL_MENUCONTENT_PLUS_3); + } + + paintFoot(); + visible = true; +} + diff --git a/src/gui/bookmarkmanager.h b/src/gui/bookmarkmanager.h new file mode 100644 index 000000000..b46a8442d --- /dev/null +++ b/src/gui/bookmarkmanager.h @@ -0,0 +1,115 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2003,2004 gagga + Homepage: http://www.giggo.de/dbox + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __bookmarkmanager__ +#define __bookmarkmanager__ + +#include +#include +#include + +#include +#include + +#include +#include + +#define MAXBOOKMARKS 10 +#define BOOKMARKFILE "/var/tuxbox/config/bookmarks" + +class CBookmark +{ + private: + std::string name; + std::string url; + std::string time; + public: + CBookmark(const std::string & name, const std::string & url, const std::string & time); + const char * const getName(void) const { return name.c_str(); }; + const char * const getUrl (void) const { return url .c_str(); }; + const char * const getTime(void) const { return time.c_str(); }; + inline void setName(const std::string & new_name) { name = new_name; }; + inline void setUrl (const std::string & new_url ) { url = new_url ; }; + inline void setTime(const std::string & new_time) { time = new_time; }; +}; + +//----------------------------------------- + +class CBookmarkManager +{ + private: + std::vector bookmarks; + CConfigFile bookmarkfile; + + CFrameBuffer *frameBuffer; + unsigned int selected; + unsigned int liststart; + unsigned int listmaxshow; + int fheight; // Fonthoehe Timerlist-Inhalt + int theight; // Fonthoehe Timerlist-Titel + int buttonHeight; + bool visible; + int width; + int height; + int x; + int y; + + + //int bookmarkCount; + bool bookmarksmodified; + void readBookmarkFile(); + void writeBookmarkFile(); + CBookmark getBookmark(); + int addBookmark(CBookmark inBookmark); + + void paintItem(int pos); + void paint(); + void paintHead(); + void paintFoot(); + void hide(); + + + + public: + CBookmarkManager(); + ~CBookmarkManager(); + int createBookmark(const std::string & name, const std::string & url, const std::string & time); + int createBookmark(const std::string & url, const std::string & time); + void removeBookmark(unsigned int index); + void renameBookmark(unsigned int index); + int getBookmarkCount(void) const; + int getMaxBookmarkCount(void) const; + void flush(); + + const CBookmark * getBookmark(CMenuTarget* parent); +}; + +#endif diff --git a/src/gui/bouquetlist.cpp b/src/gui/bouquetlist.cpp new file mode 100644 index 000000000..11514d9b2 --- /dev/null +++ b/src/gui/bouquetlist.cpp @@ -0,0 +1,549 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define ROUND_RADIUS 9 +extern CBouquetManager *g_bouquetManager; + +CBouquetList::CBouquetList(const char * const Name) +{ + frameBuffer = CFrameBuffer::getInstance(); + selected = 0; + liststart = 0; + if(Name == NULL) + name = g_Locale->getText(LOCALE_BOUQUETLIST_HEAD); + else + name = Name; + +} + +CBouquetList::~CBouquetList() +{ + for (std::vector::iterator it = Bouquets.begin(); it != Bouquets.end(); it++) { + delete (*it); + } + Bouquets.clear(); +} + +CBouquet* CBouquetList::addBouquet(CZapitBouquet * zapitBouquet) +{ + CBouquet* tmp = addBouquet(zapitBouquet->Name.c_str(), -1, zapitBouquet->bLocked); + tmp->zapitBouquet = zapitBouquet; + return tmp; +} + +CBouquet* CBouquetList::addBouquet(const char * const name, int BouquetKey, bool locked) +{ + if ( BouquetKey==-1 ) + BouquetKey= Bouquets.size(); + + CBouquet* tmp = new CBouquet( BouquetKey, name, locked ); + Bouquets.push_back(tmp); + return(tmp); +} + +void CBouquetList::deleteBouquet(CBouquet*bouquet) +{ + if (bouquet != NULL) { + std::vector::iterator it = find(Bouquets.begin(), Bouquets.end(), bouquet); + + if (it != Bouquets.end()) { + Bouquets.erase(it); + delete bouquet; + } + } +} + +int CBouquetList::getActiveBouquetNumber() +{ + return selected; +} + +void CBouquetList::adjustToChannel( int nChannelNr) +{ + for (uint32_t i=0; ichannelList->hasChannel(nChannelNr); + if (nChannelPos > -1) { + selected = i; + Bouquets[i]->channelList->setSelected(nChannelPos); + return; + } + } +} + +void CBouquetList::adjustToChannelID(t_channel_id channel_id) +{ + if(selected < Bouquets.size()) { + int nChannelPos = Bouquets[selected]->channelList->hasChannelID(channel_id); + if(nChannelPos > -1) { +printf("CBouquetList::adjustToChannelID to %llx -> not needed\n", channel_id); + Bouquets[selected]->channelList->setSelected(nChannelPos); + return; + } + } +printf("CBouquetList::adjustToChannelID to %llx\n", channel_id); + for (uint32_t i=0; i < Bouquets.size(); i++) { + if(i == selected) + continue; + int nChannelPos = Bouquets[i]->channelList->hasChannelID(channel_id); + if (nChannelPos > -1) { + selected = i; + Bouquets[i]->channelList->setSelected(nChannelPos); + return; + } + } +} +/* used in channellist to switch bouquets up/down */ +int CBouquetList::showChannelList( int nBouquet) +{ + if (nBouquet == -1) + nBouquet = selected; + + int nNewChannel = Bouquets[nBouquet]->channelList->exec(); + if (nNewChannel > -1) { + selected = nBouquet; + nNewChannel = -2; + } + return nNewChannel; +} +/* bShowChannelList default to false , return seems not checked anywhere */ +int CBouquetList::activateBouquet( int id, bool bShowChannelList) +{ + int res = -1; + + if(id < (int) Bouquets.size()) + selected = id; + + if (bShowChannelList) { + res = Bouquets[selected]->channelList->exec(); + if(res > -1) + res = -2; + } + return res; +} + +int CBouquetList::exec( bool bShowChannelList) +{ + /* select bouquet to show */ + int res = show(bShowChannelList); +//printf("Bouquet-exec: res %d bShowChannelList %d\n", res, bShowChannelList); fflush(stdout); + + if(!bShowChannelList) + return res; + /* if >= 0, call activateBouquet to show channel list */ + if ( res > -1) { + return activateBouquet(selected, bShowChannelList); + } + return res; +} + +int CBouquetList::doMenu() +{ + int i = 0; + int select = -1; + static int old_selected = 0; + int ret = menu_return::RETURN_NONE; + signed int bouquet_id; + char cnt[5]; + CZapitBouquet * tmp, * zapitBouquet; + ZapitChannelList* channels; + + if(!Bouquets.size() || g_settings.minimode) + return 0; + + zapitBouquet = Bouquets[selected]->zapitBouquet; + /* zapitBouquet not NULL only on real bouquets, not on virtual SAT or HD */ + if(!zapitBouquet) + return 0; + + CMenuWidget* menu = new CMenuWidget(LOCALE_CHANNELLIST_EDIT, NEUTRINO_ICON_SETTINGS); + CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select); + + sprintf(cnt, "%d", i); + if(!zapitBouquet->bUser) { + menu->addItem(new CMenuForwarder(LOCALE_FAVORITES_COPY, true, NULL, selector, cnt, CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE), old_selected == i ++); + ret = menu->exec(NULL, ""); + delete menu; + delete selector; + printf("CBouquetList::doMenu: %d selected\n", select); + if(select >= 0) { + old_selected = select; + switch(select) { + case 0: + hide(); + bouquet_id = g_bouquetManager->existsUBouquet(Bouquets[selected]->channelList->getName()); + if(bouquet_id < 0) { + tmp = g_bouquetManager->addBouquet(Bouquets[selected]->channelList->getName(), true); + } else + tmp = g_bouquetManager->Bouquets[bouquet_id]; + + channels = &zapitBouquet->tvChannels; + for(int i = 0; i < (int) channels->size(); i++) + tmp->addService((*channels)[i]); + return 1; + break; + default: + break; + } + } + } else { + menu->addItem(new CMenuForwarder(LOCALE_BOUQUETEDITOR_DELETE, true, NULL, selector, cnt, CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE), old_selected == i ++); + ret = menu->exec(NULL, ""); + delete menu; + delete selector; + printf("CBouquetList::doMenu: %d selected\n", select); + if(select >= 0) { + old_selected = select; + switch(select) { + case 0: + hide(); + bouquet_id = g_bouquetManager->existsUBouquet(Bouquets[selected]->channelList->getName()); + if(bouquet_id >= 0) { + g_bouquetManager->deleteBouquet(bouquet_id); + return 1; + } + break; + default: + break; + } + } + } + return 0; +} + +/* bShowChannelList default to true, returns new bouquet or -1/-2 */ +int CBouquetList::show(bool bShowChannelList) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + int res = -1; + + //if(Bouquets.size()==0) + // return res; + + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, ""); + + width = w_max (500, 0); + height = h_max (440, 40); + + buttonHeight = 7 + std::min(16, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight()); + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getHeight(); + listmaxshow = (height - theight - buttonHeight)/fheight; + height = theight + buttonHeight + listmaxshow * fheight; // recalc height + + x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - height) / 2; + + int maxpos= 1; + int i= Bouquets.size(); + while ((i= i/10)!=0) + maxpos++; + + paintHead(); + paint(); + + int oldselected = selected; + int firstselected = selected+ 1; + int zapOnExit = false; + + unsigned int chn= 0; + int pos= maxpos; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]); + + bool loop=true; + while (loop) { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]); + + if ((msg == CRCInput::RC_timeout ) || + (msg == (neutrino_msg_t)g_settings.key_channelList_cancel)) + { + selected = oldselected; + loop=false; + } + else if(msg == CRCInput::RC_red || msg == CRCInput::RC_favorites) { + CNeutrinoApp::getInstance()->SetChannelMode(LIST_MODE_FAV); + hide(); + return -3; + } else if(msg == CRCInput::RC_green) { + CNeutrinoApp::getInstance()->SetChannelMode(LIST_MODE_PROV); + hide(); + return -3; + } else if(msg == CRCInput::RC_yellow || msg == CRCInput::RC_sat) { + CNeutrinoApp::getInstance()->SetChannelMode(LIST_MODE_SAT); + hide(); + return -3; + } else if(msg == CRCInput::RC_blue) { + CNeutrinoApp::getInstance()->SetChannelMode(LIST_MODE_ALL); + hide(); + return -3; + } + else if(Bouquets.size() == 0) + continue; //FIXME msgs not forwarded to neutrino !! + else if ( msg == CRCInput::RC_setup) { + int ret = doMenu(); + if(ret) { + res = -4; + loop = false; + } else + paint(); + } + else if ( msg == (neutrino_msg_t) g_settings.key_list_start ) { + selected=0; + liststart = (selected/listmaxshow)*listmaxshow; + paint(); + } + else if ( msg == (neutrino_msg_t) g_settings.key_list_end ) { + selected=Bouquets.size()-1; + liststart = (selected/listmaxshow)*listmaxshow; + paint(); + } + else if (msg == CRCInput::RC_up || (int) msg == g_settings.key_channelList_pageup) + { + int step = 0; + int prev_selected = selected; + + step = ((int) msg == g_settings.key_channelList_pageup) ? listmaxshow : 1; // browse or step 1 + selected -= step; + if((prev_selected-step) < 0) // because of uint + selected = Bouquets.size()-1; + + paintItem(prev_selected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + paint(); + else + paintItem(selected - liststart); + } + else if (msg == CRCInput::RC_down || (int) msg == g_settings.key_channelList_pagedown) + { + unsigned int step = 0; + int prev_selected = selected; + + step = ((int) msg == g_settings.key_channelList_pagedown) ? listmaxshow : 1; // browse or step 1 + selected += step; + + if(selected >= Bouquets.size()) { + if (((Bouquets.size() / listmaxshow) + 1) * listmaxshow == Bouquets.size() + listmaxshow) // last page has full entries + selected = 0; + else + selected = ((step == listmaxshow) && (selected < (((Bouquets.size() / listmaxshow) + 1) * listmaxshow))) ? (Bouquets.size() - 1) : 0; + } + paintItem(prev_selected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + paint(); + else + paintItem(selected - liststart); + } + + else if ( msg == CRCInput::RC_ok ) { + if(!bShowChannelList || Bouquets[selected]->channelList->getSize() > 0) { + zapOnExit = true; + loop=false; + } + } + else if (CRCInput::isNumeric(msg)) { + if (pos == maxpos) { + if (msg == CRCInput::RC_0) { + chn = firstselected; + pos = maxpos; + } else { + chn = CRCInput::getNumericValue(msg); + pos = 1; + } + } else { + chn = chn * 10 + CRCInput::getNumericValue(msg); + pos++; + } + + if (chn > Bouquets.size()) { + chn = firstselected; + pos = maxpos; + } + + int prevselected=selected; + selected = (chn - 1) % Bouquets.size(); // is % necessary (i.e. can firstselected be > Bouquets.size()) ? + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) { + paint(); + } else { + paintItem(selected - liststart); + } + + } else { + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) { + loop = false; + res = -2; + } + }; + } + hide(); + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + if(zapOnExit) { + return (selected); + } else { + return (res); + } +} + +void CBouquetList::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height+10); +} + +void CBouquetList::paintItem(int pos) +{ + int ypos = y+ theight+0 + pos*fheight; + uint8_t color; + fb_pixel_t bgcolor; + bool iscurrent = true; + int npos = liststart + pos; + const char * name = NULL; + + if(npos < (int) Bouquets.size()) + name = (Bouquets[npos]->zapitBouquet && Bouquets[npos]->zapitBouquet->bFav) ? g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME) : Bouquets[npos]->channelList->getName(); + + if (npos == (int) selected) { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + frameBuffer->paintBoxRel(x, ypos, width- 15, fheight, bgcolor, ROUND_RADIUS, 3); + if(npos < (int) Bouquets.size()) + CVFD::getInstance()->showMenuText(0, name, -1, true); + } else { + if(npos < (int) Bouquets.size()) + iscurrent = Bouquets[npos]->channelList->getSize() > 0; + color = iscurrent ? COL_MENUCONTENT : COL_MENUCONTENTINACTIVE; + bgcolor = iscurrent ? COL_MENUCONTENT_PLUS_0 : COL_MENUCONTENTINACTIVE_PLUS_0; + frameBuffer->paintBoxRel(x, ypos, width- 15, fheight, bgcolor); + } + + if(npos < (int) Bouquets.size()) { + char tmp[10]; + sprintf((char*) tmp, "%d", npos+ 1); + + int numpos = x+5+numwidth- g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(tmp); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(numpos,ypos+fheight, numwidth+5, tmp, color, fheight); + + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 5+ numwidth+ 10, ypos+ fheight, width- numwidth- 20- 15, name, color, 0, true); // UTF-8 + //CVFD::getInstance()->showMenuText(0, bouq->channelList->getName(), -1, true); + } +} + +const struct button_label CBouquetListButtons[4] = +{ + { NEUTRINO_ICON_BUTTON_RED, LOCALE_CHANNELLIST_FAVS}, + { NEUTRINO_ICON_BUTTON_GREEN, LOCALE_CHANNELLIST_PROVS}, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_CHANNELLIST_SATS}, + { NEUTRINO_ICON_BUTTON_BLUE, LOCALE_CHANNELLIST_HEAD} +}; + +void CBouquetList::paintHead() +{ + frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10,y+theight+0, width, name, COL_MENUHEAD, 0, true); // UTF-8 +} + +void CBouquetList::paint() +{ + liststart = (selected/listmaxshow)*listmaxshow; + int lastnum = liststart + listmaxshow; + int bsize = Bouquets.size() > 0 ? Bouquets.size() : 1; + + if(lastnum<10) + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("0"); + else if(lastnum<100) + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("00"); + else if(lastnum<1000) + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("000"); + else if(lastnum<10000) + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("0000"); + else // if(lastnum<100000) + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("00000"); + + //frameBuffer->paintBoxRel(x, y+theight, width, height-theight+10, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2); + frameBuffer->paintBoxRel(x, y+theight, width, height - theight - buttonHeight, COL_MENUCONTENT_PLUS_0); + + int ButtonWidth = (width - 20) / 4; + + frameBuffer->paintBoxRel(x, y + (height - buttonHeight), width, buttonHeight - 1, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2); + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 10, y + (height - buttonHeight) + 3, ButtonWidth, sizeof(CBouquetListButtons)/sizeof(CBouquetListButtons[0]), CBouquetListButtons); + + if(Bouquets.size()) + { + for(unsigned int count=0;countpaintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((bsize - 1)/ listmaxshow)+ 1; + float sbh= (sb - 4)/ sbc; + int sbs= (selected/listmaxshow); + + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ int(sbs* sbh) , 11, int(sbh), COL_MENUCONTENT_PLUS_3); +} diff --git a/src/gui/bouquetlist.h b/src/gui/bouquetlist.h new file mode 100644 index 000000000..5f71dca09 --- /dev/null +++ b/src/gui/bouquetlist.h @@ -0,0 +1,123 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __bouquetlist__ +#define __bouquetlist__ + +#include + +#include +#include +#include + +#include +#include + + +typedef enum bouquetSwitchMode +{ + bsmBouquets, // pressing OK shows list of all Bouquets + bsmChannels, // pressing OK shows list of all channels of active bouquets + bsmAllChannels // OK shows lsit of all channels +} BouquetSwitchMode; + +class CBouquet +{ + + public: + int unique_key; + bool bLocked; + CChannelList* channelList; + CZapitBouquet * zapitBouquet; + + CBouquet(const int Unique_key, const char * const Name, const bool locked) + { + zapitBouquet = NULL; + unique_key = Unique_key; + bLocked = locked; + channelList = new CChannelList(Name); + } + + ~CBouquet() + { + delete channelList; + } +}; + + +class CBouquetList +{ + private: + CFrameBuffer *frameBuffer; + + std::string name; + unsigned int selected; + unsigned int liststart; + unsigned int listmaxshow; + unsigned int numwidth; + unsigned int maxpos; + int fheight; // Fonthoehe Bouquetlist-Inhalt + int theight; // Fonthoehe Bouquetlist-Titel + int buttonHeight; + + int width; + int height; + int x; + int y; + + void paintItem(int pos); + void paint(); + void paintHead(); + void hide(); + int doMenu(); + + public: + CBouquetList(const char * const Name = NULL); + ~CBouquetList(); + + std::vector Bouquets; + + CChannelList* orgChannelList; + CBouquet* addBouquet(const char * const name, int BouquetKey=-1, bool locked=false ); + CBouquet* addBouquet(CZapitBouquet * zapitBouquet); + void deleteBouquet(CBouquet* bouquet); + int getActiveBouquetNumber(); + int activateBouquet(int id, bool bShowChannelList); + int show(bool bShowChannelList = true); + int showChannelList(int nBouquet = -1); + void adjustToChannel(int nChannelNr); + void adjustToChannelID(t_channel_id channel_id); + int exec( bool bShowChannelList); +}; + + +#endif diff --git a/src/gui/cam_menu.cpp b/src/gui/cam_menu.cpp new file mode 100644 index 000000000..26caddc48 --- /dev/null +++ b/src/gui/cam_menu.cpp @@ -0,0 +1,402 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "gui/widget/menue.h" +#include "gui/widget/stringinput.h" +#include "gui/widget/messagebox.h" +#include "gui/widget/hintbox.h" +#include "gui/widget/progresswindow.h" + +#include "system/setting_helpers.h" +#include "system/settings.h" +#include "system/debug.h" + +#include +#include +#include +#include + +void CCAMMenuHandler::init(void) +{ + hintBox = NULL; + ci = cDvbCi::getInstance(); +} + +int CCAMMenuHandler::exec(CMenuTarget* parent, const std::string &actionkey) +{ +printf("CCAMMenuHandler::exec: actionkey %s\n", actionkey.c_str()); + if (parent) + parent->hide(); + + if(actionkey == "cam1") { + return doMenu(0); + } else if(actionkey == "cam2") { + return doMenu(1); + } + + return doMainMenu (); +} + +int CCAMMenuHandler::doMainMenu () +{ + int ret; + char name1[255], name2[255]; + //cDvbCiSlot *one, *two; + char str1[255]; + char str2[255]; + + //one = ci->GetSlot(0); + //two = ci->GetSlot(1); + + CMenuWidget* cammenu = new CMenuWidget(LOCALE_CAM_SETTINGS, NEUTRINO_ICON_SETTINGS); + cammenu->addItem( GenericMenuBack ); + cammenu->addItem( GenericMenuSeparatorLine ); + + CMenuWidget * tempMenu; + if(ci->CamPresent(0)) { + ci->GetName(0, name1); +printf("CCAMMenuHandler::doMenu cam1 name %s\n", name1); + cammenu->addItem(new CMenuForwarderNonLocalized(name1, true, NULL, this, "cam1", CRCInput::RC_1)); + } else { + sprintf(str1, "%s 1", g_Locale->getText(LOCALE_CAM_EMPTY)); + tempMenu = new CMenuWidget(str1, NEUTRINO_ICON_SETTINGS); + cammenu->addItem(new CMenuForwarderNonLocalized(str1, false, NULL, tempMenu)); + } + + if(ci->CamPresent(1)) { + ci->GetName(1, name2); +printf("CCAMMenuHandler::doMenu cam2 name %s\n", name2); + cammenu->addItem(new CMenuForwarderNonLocalized(name2, true, NULL, this, "cam2", CRCInput::RC_2)); + } else { + sprintf(str2, "%s 2", g_Locale->getText(LOCALE_CAM_EMPTY)); + tempMenu = new CMenuWidget(str2, NEUTRINO_ICON_SETTINGS); + cammenu->addItem(new CMenuForwarderNonLocalized(str2, false, NULL, tempMenu)); + } + + ret = cammenu->exec(NULL, ""); + delete cammenu; + return ret; +} + +#define CI_MSG_TIME 5 +int CCAMMenuHandler::handleMsg (const neutrino_msg_t msg, neutrino_msg_data_t data) +{ + int ret = messages_return::handled; +//printf("CCAMMenuHandler::handleMsg: msg 0x%x data 0x%x\n", msg, data); + int camret = handleCamMsg(msg, data); + if(camret < 0) { + ret = messages_return::unhandled; + } + return ret; +} + +int CCAMMenuHandler::handleCamMsg (const neutrino_msg_t msg, neutrino_msg_data_t data, bool from_menu) +{ + int ret = 0; + char str[255]; + char cnt[5]; + int i; + MMI_MENU_LIST_INFO Menu; + MMI_ENGUIRY_INFO MmiEnquiry; + int curslot; + MMI_MENU_LIST_INFO * pMenu = &Menu; + MMI_ENGUIRY_INFO * pMmiEnquiry = &MmiEnquiry; + +//printf("CCAMMenuHandler::handleCamMsg: msg 0x%x data 0x%x\n", msg, data); + + if(msg == NeutrinoMessages::EVT_CI_INSERTED) { + if(hintBox != NULL) { + hintBox->hide(); + delete hintBox; + } + sprintf(str, "%s %d", g_Locale->getText(LOCACE_CAM_INSERTED), (int) data+1); + + printf("CCAMMenuHandler::handleMsg: %s\n", str); + hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, str); + hintBox->paint(); + + sleep(CI_MSG_TIME); + hintBox->hide(); + delete hintBox; + hintBox = NULL; + + } else if (msg == NeutrinoMessages::EVT_CI_REMOVED) { + if(hintBox != NULL) { + hintBox->hide(); + delete hintBox; + } + sprintf(str, "%s %d", g_Locale->getText(LOCALE_CAM_REMOVED), (int) data+1); + + printf("CCAMMenuHandler::handleMsg: %s\n", str); + hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, str); + + hintBox->paint(); + + sleep(CI_MSG_TIME); + hintBox->hide(); + delete hintBox; + hintBox = NULL; + } else if(msg == NeutrinoMessages::EVT_CI_INIT_OK) { + if(hintBox != NULL) { + hintBox->hide(); + delete hintBox; + } + char name[255] = "Unknown"; + //cDvbCiSlot * slot = ci->GetSlot((int) data); + //if(slot) + // slot->GetName(name); + ci->GetName((int) data, name); + sprintf(str, "%s %d: %s", g_Locale->getText(LOCALE_CAM_INIT_OK), (int) data+1, name); + + printf("CCAMMenuHandler::handleMsg: %s\n", str); + hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, str); + hintBox->paint(); + sleep(CI_MSG_TIME); + hintBox->hide(); + delete hintBox; + hintBox = NULL; + } + else if(msg == NeutrinoMessages::EVT_CI_MMI_MENU || msg == NeutrinoMessages::EVT_CI_MMI_LIST) { + bool sublevel = false; + if(msg != NeutrinoMessages::EVT_CI_MMI_MENU) + sublevel = true; + + memcpy(pMenu, (MMI_MENU_LIST_INFO*) data, sizeof(MMI_MENU_LIST_INFO)); + free((void *)data); + curslot = pMenu->slot; + + printf("CCAMMenuHandler::handleCamMsg: slot %d menu ready, title %s choices %d\n", curslot, convertDVBUTF8(pMenu->title, strlen(pMenu->title), 0).c_str(), pMenu->choice_nb); + + if(hintBox) { + hintBox->hide(); + } + + int selected = -1; + if(pMenu->choice_nb) { + CMenuWidget* menu = new CMenuWidget(convertDVBUTF8(pMenu->title, strlen(pMenu->title), 0).c_str(), NEUTRINO_ICON_SETTINGS); + + CMenuSelectorTarget * selector = new CMenuSelectorTarget(&selected); + int slen = strlen(pMenu->subtitle); + if(slen) { + char * sptr = pMenu->subtitle; + char * tptr = sptr; + int bpos = 0; + for(int i = 0; i < slen; i++) { + if((tptr[i] == 0x8A) || ((bpos > 38) && (tptr[i] == 0x20)) ) { + bpos = 0; + tptr[i] = 0; +printf("CCAMMenuHandler::handleCamMsg: subtitle: %s\n", sptr); + menu->addItem(new CMenuForwarderNonLocalized(convertDVBUTF8(sptr, strlen(sptr), 0).c_str(), false)); + sptr = &tptr[i+1]; + } + bpos++; + } + if(strlen(sptr)) { +printf("CCAMMenuHandler::handleCamMsg: subtitle: %s\n", sptr); + menu->addItem(new CMenuForwarderNonLocalized(convertDVBUTF8(sptr, strlen(sptr), 0).c_str(), false)); + } + } + for(i = 0; i < pMenu->choice_nb; i++) { + sprintf(cnt, "%d", i); + if(sublevel) + menu->addItem(new CMenuForwarderNonLocalized(convertDVBUTF8(pMenu->choice_item[i], strlen(pMenu->choice_item[i]), 0).c_str(), true, NULL, selector, cnt)); + else + menu->addItem(new CMenuForwarderNonLocalized(convertDVBUTF8(pMenu->choice_item[i], strlen(pMenu->choice_item[i]), 0).c_str(), true, NULL, selector, cnt, CRCInput::convertDigitToKey(i+1))); + } + slen = strlen(pMenu->bottom); + if(slen) { +printf("CCAMMenuHandler::handleCamMsg: bottom: %s\n", pMenu->bottom); + menu->addItem(new CMenuForwarderNonLocalized(convertDVBUTF8(pMenu->bottom, slen, 0).c_str(), false)); + } + + menu->exec(NULL, ""); + + delete menu; + delete selector; + } else { + char str[255]; + snprintf(str, 255, "%s\n%s\n%s", pMenu->title, pMenu->subtitle, pMenu->bottom); + if(hintBox) + delete hintBox; + //hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, convertDVBUTF8(pMenu->title, strlen(pMenu->title), 0).c_str()); + hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, convertDVBUTF8(str, strlen(str), 0).c_str()); + hintBox->paint(); + sleep(4);//FIXME + if(!from_menu) { + delete hintBox; + hintBox = NULL; + } + return 1; + } + + if(sublevel) + return 0; + + if(selected >= 0) { + printf("CCAMMenuHandler::handleCamMsg: selected %d:%s sublevel %s\n", selected, pMenu->choice_item[i], sublevel ? "yes" : "no"); + CI_MenuAnswer(curslot, selected+1); + timeoutEnd = CRCInput::calcTimeoutEnd(10); + return 1; + } else { + return 2; + } + } + else if(msg == NeutrinoMessages::EVT_CI_MMI_REQUEST_INPUT) { + memcpy(pMmiEnquiry, (MMI_ENGUIRY_INFO*) data, sizeof(MMI_ENGUIRY_INFO)); + free((void *)data); + curslot = pMmiEnquiry->slot; + printf("CCAMMenuHandler::handleCamMsg: slot %d input request, text %s\n", curslot, convertDVBUTF8(pMmiEnquiry->enguiryText, strlen(pMmiEnquiry->enguiryText), 0).c_str()); + if(hintBox) + hintBox->hide(); + + char cPIN[pMmiEnquiry->answerlen+1]; + cPIN[0] = 0; + + CPINInput* PINInput = new CPINInput((char *) convertDVBUTF8(pMmiEnquiry->enguiryText, strlen(pMmiEnquiry->enguiryText), 0).c_str(), cPIN, 4, NONEXISTANT_LOCALE); + PINInput->exec(NULL, ""); + delete PINInput; + + printf("CCAMMenuHandler::handleCamMsg: input=[%s]\n", cPIN); + //if(cPIN[0] == 0) + // return 0; + + if((int) strlen(cPIN) != pMmiEnquiry->answerlen) { + printf("CCAMMenuHandler::handleCamMsg: wrong input len\n"); + CI_Answer(curslot, (unsigned char *) cPIN, 0); + return 0; + } else { + CI_Answer(curslot, (unsigned char *) cPIN, pMmiEnquiry->answerlen); + return 1; + } + } + else if(msg == NeutrinoMessages::EVT_CI_MMI_CLOSE) { + curslot = (int) data; + printf("CCAMMenuHandler::handleCamMsg: close request slot: %d\n", curslot); +#if 0 + if(hintBox) { + hintBox->hide(); + delete hintBox; + hintBox = NULL; + } +#endif + CI_CloseMMI(curslot); + return 0; + } + else if(msg == NeutrinoMessages::EVT_CI_MMI_TEXT) { + curslot = (int) data; + printf("CCAMMenuHandler::handleCamMsg: text\n"); + } else + ret = -1; +//printf("CCAMMenuHandler::handleCamMsg: return %d\n", ret); + return ret; +} + +int CCAMMenuHandler::doMenu (int slot) +{ + int res = menu_return::RETURN_REPAINT; + neutrino_msg_t msg; + neutrino_msg_data_t data; + bool doexit = false; + + while(!doexit) { + printf("CCAMMenuHandler::doMenu: slot %d\n", slot); + + timeoutEnd = CRCInput::calcTimeoutEnd(10); + + CI_EnterMenu(slot); + while(true) { + if(hintBox) + delete hintBox; + hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_CAM_WAITING)); + hintBox->paint(); + g_RCInput->getMsgAbsoluteTimeout (&msg, &data, &timeoutEnd); + printf("CCAMMenuHandler::doMenu: msg %x data %x\n", msg, data); + if (msg == CRCInput::RC_timeout) { + if(hintBox) + delete hintBox; + + hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_CAM_TIMEOUT)); + hintBox->paint(); + + printf("CCAMMenuHandler::doMenu: menu timeout\n"); + sleep(5); + delete hintBox; + hintBox = NULL; + CI_CloseMMI(slot); + return menu_return::RETURN_REPAINT; + } + /* -1 = not our event, 0 = back to top menu, 1 = continue loop, 2 = quit */ + int ret = handleCamMsg(msg, data, true); + if(ret < 0 && (msg > CRCInput::RC_Messages)) { + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & ( messages_return::cancel_all | messages_return::cancel_info ) ) + { + doexit = true; + res = menu_return::RETURN_EXIT_ALL; + } + } else if (ret == 1) { + timeoutEnd = CRCInput::calcTimeoutEnd(10); + continue; + } else if (ret == 2) { + doexit = true; + break; + } else { + break; + } + } + } + CI_CloseMMI(slot); + if(hintBox) { + delete hintBox; + hintBox = NULL; + } +printf("CCAMMenuHandler::doMenu: return\n"); + return res; +} diff --git a/src/gui/cam_menu.h b/src/gui/cam_menu.h new file mode 100644 index 000000000..09d629bee --- /dev/null +++ b/src/gui/cam_menu.h @@ -0,0 +1,48 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __cam_menu__ +#define __cam_menu__ + + +#include "widget/menue.h" +#include + +using namespace std; + +class CCAMMenuHandler : public CMenuTarget +{ + private: + CHintBox * hintBox; + cDvbCi * ci; + unsigned long long timeoutEnd; + //int slot; + int doMenu(int slot); + int doMainMenu(); + int handleCamMsg (const neutrino_msg_t msg, neutrino_msg_data_t data, bool from_menu = false); + public: + void init(void); + int exec(CMenuTarget* parent, const std::string &actionkey); + int handleMsg (const neutrino_msg_t msg, neutrino_msg_data_t data); +}; +#endif + diff --git a/src/gui/ch_mosaic.cpp b/src/gui/ch_mosaic.cpp new file mode 100644 index 000000000..c630c0a98 --- /dev/null +++ b/src/gui/ch_mosaic.cpp @@ -0,0 +1,256 @@ + +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ch_mosaic.h" + +#warning "experimental..." + + +/* + -- Channel/Service Mosaic + -- Display multiple channel images on screen + -- capture used from outdoor (tmbinc) + -- 2002-11 rasc + */ + + + + +// +// -- init Channel Mosaic Handler Class +// -- to be used for calls from Menue +// + +int CChMosaicHandler::exec(CMenuTarget* parent, const std::string &actionkey) +{ + int res = menu_return::RETURN_EXIT_ALL; + CChMosaic * mosaic; + + + if (parent) { + parent->hide(); + } + + mosaic = new CChMosaic; + mosaic->doMosaic (); + delete mosaic; + + return res; +} + + + + +#define SCREEN_X 720 +#define SCREEN_Y 572 +#define RATIO(y) (((y)*100)/126) // w/h PAL ratio + + +// +// -- Channel Mosaic Class +// -- do Mosaic +// + +CChMosaic::CChMosaic() +{ + pig = new CPIG (0); + capture = new CCAPTURE (0); + current_pig_pos = 0; + + channellist = CNeutrinoApp::getInstance()->channelList; + frameBuffer = CFrameBuffer::getInstance(); +} + + +CChMosaic::~CChMosaic() +{ + delete pig; + +} + + +void CChMosaic::doMosaic() +{ +#define W (150) +#define H (120) + struct PIG_COORD coord[] = { + { 40, 10, W,H }, + {200, 10, W,H }, + {360, 10, W,H }, + {520, 10, W,H }, + { 40,150, W,H }, + {200,150, W,H }, + {360,150, W,H }, + {520,150, W,H }, + { 40,290, W,H }, + {200,290, W,H }, + {360,290, W,H }, + {520,290, W,H }, + { 40,430, W,H }, + {200,430, W,H }, + {360,430, W,H }, + {520,430, W,H } + }; + + int channel; + int i; + + + + channellist = CNeutrinoApp::getInstance()->channelList; + channel = channellist->getActiveChannelNumber(); + + frameBuffer = CFrameBuffer::getInstance(); + + + + + // $$$ mute + + + // -- paint background and - windows + paintBackground(); + for (i=0; i < (int)(sizeof(coord)/sizeof(coord[0])); i++) { + paintMiniTVBackground(coord[i].x,coord[i].y, coord[i].w, coord[i].h); + } + + + + + // experimental + for (i=0; i < (int)(sizeof(coord)/sizeof(coord[0])); i++) { + + u_char frame_buf[SCREEN_X*SCREEN_Y*2]; + int j; + + + // -- adjust pig and zap to channel, set capture size + printf ("pig: %d \n",i); + pig->show (coord[i].x,coord[i].y, coord[i].w, coord[i].h); + channellist->zapTo(channel); + capture->set_coord (coord[i].x, coord[i].y, coord[i].w, coord[i].h); +// capture->set_output_size (coord[i].w, coord[i].h); + + sleep (2); + + + // -- inner loop + // -- try 4 times (4 * 0,5 sec) to get a captured frame + for (j=0; j < 4; j++) { + + neutrino_msg_t msg; + neutrino_msg_data_t data; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(500); + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + printf ("pig inner loop: %d - %d \n",i,j); + + + // $$$ TEST + capture->readframe (frame_buf); + //if (frame_buf[10] == 0x00) continue; + + int a; + for (a=0; a<0x10; a++) { + printf("%02x ",frame_buf[a]); + } + printf ("\n"); + + if (msg == CRCInput::RC_timeout) { + printf ("pig inner loop timeout: \n"); + i = i; + } + + + // -- push other events + if ( msg > CRCInput::RC_MaxRC ) { + CNeutrinoApp::getInstance()->handleMsg( msg, data ); + } + + + + // zap, sleep 0.5 sec + // capture frame + + // loop 4 times frame "empty"? + // --> wait 0,5 sec, re-capture + + } + + // display frame + + // display add info (sendername, epg info) + // + + + channel ++; + } + + + + + // -- clear + clearTV(); + + // $$$ unmute + +} + + + + + +// +// -- some paint abstraction functions in this class +// + +void CChMosaic::clearTV() +{ + frameBuffer->paintBackgroundBoxRel(0,0,SCREEN_X-1,SCREEN_Y-1); +} + +void CChMosaic::paintBackground() +{ + fb_pixel_t col = 254; + frameBuffer->paintBoxRel(0, 0, SCREEN_X-1, SCREEN_Y-1, col); + //frameBuffer->paintBoxRel(0, 0, SCREEN_X-1, SCREEN_Y-1, frameBuffer->realcolor[0xFe]); +} + +void CChMosaic::paintMiniTVBackground(int x, int y, int w, int h) +{ + fb_pixel_t col = 240; + frameBuffer->paintBoxRel(x,y,w,h, col); + //frameBuffer->paintBoxRel(x,y,w,h, frameBuffer->realcolor[0xF0]); +} + + diff --git a/src/gui/ch_mosaic.h b/src/gui/ch_mosaic.h new file mode 100644 index 000000000..e2a8c8b7a --- /dev/null +++ b/src/gui/ch_mosaic.h @@ -0,0 +1,70 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __ch_mosaic__ +#define __ch_mosaic__ + +#include +#include "widget/menue.h" + +#include +#include + + +using namespace std; + +class CChMosaicHandler : public CMenuTarget +{ + public: + int exec( CMenuTarget* parent, const std::string &actionkey); + +}; + + +class CChMosaic +{ + public: + CChMosaic (); + ~CChMosaic (); + void doMosaic (); + + private: + void clearTV (); + void paintBackground (); + void paintMiniTVBackground(int x, int y, int w, int h); + + CPIG *pig; + CCAPTURE *capture; + int current_pig_pos; + + struct PIG_COORD { + int x,y,w,h; + }; + + CChannelList *channellist; + CFrameBuffer *frameBuffer; + +}; + + +#endif + diff --git a/src/gui/channellist.cpp b/src/gui/channellist.cpp new file mode 100644 index 000000000..ae2e7948c --- /dev/null +++ b/src/gui/channellist.cpp @@ -0,0 +1,1645 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "gui/filebrowser.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern CFrontend * frontend; +extern CBouquetList * bouquetList; /* neutrino.cpp */ +extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ +extern SMSKeyInput * c_SMSKeyInput; +extern CPictureViewer * g_PicViewer; +extern CBouquetList * TVbouquetList; +extern CBouquetList * TVsatList; +extern CBouquetList * TVfavList; +extern CBouquetList * TVallList; +extern CBouquetList * RADIObouquetList; +extern CBouquetList * RADIOsatList; +extern CBouquetList * RADIOfavList; +extern CBouquetList * RADIOallList; + +#define PIC_W 52 +#define PIC_H 39 +#define ROUND_RADIUS 9 + +extern t_channel_id rec_channel_id; +extern bool autoshift; +int info_height = 0; +bool new_mode_active = 0; +//int list_changed = 0; +static bool pipzap; + +extern CBouquetManager *g_bouquetManager; +void sectionsd_getChannelEvents(CChannelEventList &eList, const bool tv_mode, t_channel_id *chidlist, int clen); +void sectionsd_getEventsServiceKey(t_channel_id serviceUniqueKey, CChannelEventList &eList, char search = 0, std::string search_text = ""); +void addChannelToBouquet(const unsigned int bouquet, const t_channel_id channel_id); + +extern int old_b_id; + +CChannelList::CChannelList(const char * const Name, bool historyMode, bool _vlist) +{ + frameBuffer = CFrameBuffer::getInstance(); + name = Name; + selected = 0; + liststart = 0; + tuned=0xfffffff; + zapProtection = NULL; + this->historyMode = historyMode; + vlist = _vlist; +//printf("************ NEW LIST %s : %x\n", name.c_str(), this);fflush(stdout); +} + +CChannelList::~CChannelList() +{ +//printf("************ DELETE LIST %s : %x\n", name.c_str(), this);fflush(stdout); + chanlist.clear(); +} + +void CChannelList::ClearList(void) +{ +//printf("************ CLEAR LIST %s : %x\n", name.c_str(), this);fflush(stdout); + chanlist.clear(); + chanlist.resize(1); +} + +void CChannelList::setSize(int newsize) +{ + chanlist.reserve(newsize); + //chanlist.resize(newsize); +} + +void CChannelList::addChannel(CZapitChannel* channel, int num) +{ +//printf("************ %s : addChannel: %s %x\n", name.c_str(), channel->getName().c_str(), channel);fflush(stdout); + if(num) + channel->number = num; + chanlist.push_back(channel); +} + +void CChannelList::putChannel(CZapitChannel* channel) +{ + int num = channel->number - 1; + if(num < 0) { + printf("CChannelList::addChannel error inserting at %d\n", num); + return; + } + if(num >= (int) chanlist.size()) { + chanlist.resize((unsigned) num + 1); + } + chanlist[num] = channel; +//printf("************ %s : me %x putChannel: %d: %s %x -> %x [0] %x\n", name.c_str(), this, num, channel->getName().c_str(), channel, chanlist[num], chanlist[0]);fflush(stdout); +} + +void CChannelList::updateEvents(void) +{ + CChannelEventList events; + + if (displayNext) { + if (chanlist.size()) { + time_t atime = time(NULL); + unsigned int count; + for (count=0; count < chanlist.size(); count++){ + //CChannelEventList events = g_Sectionsd->getEventsServiceKey(chanlist[liststart+count]->channel_id &0xFFFFFFFFFFFFULL); + sectionsd_getEventsServiceKey(chanlist[count]->channel_id &0xFFFFFFFFFFFFULL, events); + chanlist[count]->nextEvent.startTime = (long)0x7fffffff; + for ( CChannelEventList::iterator e= events.begin(); e != events.end(); ++e ) { + if (((long)(e->startTime) > atime) && + ((e->startTime) < (long)(chanlist[count]->nextEvent.startTime))) + { + chanlist[count]->nextEvent= *e; + break; //max: FIXME no sense to continue ? + } + } + } + } + } else { + t_channel_id *p_requested_channels = NULL; + int size_requested_channels = 0; + + if (chanlist.size()) { + size_requested_channels = chanlist.size()*sizeof(t_channel_id); + p_requested_channels = (t_channel_id*)malloc(size_requested_channels); + for (uint32_t count = 0; count < chanlist.size(); count++){ + p_requested_channels[count] = chanlist[count]->channel_id&0xFFFFFFFFFFFFULL; + } + + //CChannelEventList events = g_Sectionsd->getChannelEvents((CNeutrinoApp::getInstance()->getMode()) != NeutrinoMessages::mode_radio, p_requested_channels, size_requested_channels); + CChannelEventList events; + sectionsd_getChannelEvents(events, (CNeutrinoApp::getInstance()->getMode()) != NeutrinoMessages::mode_radio, p_requested_channels, size_requested_channels); + for (uint32_t count=0; count < chanlist.size(); count++) { + chanlist[count]->currentEvent = CChannelEvent(); + for ( CChannelEventList::iterator e = events.begin(); e != events.end(); ++e ) + if ((chanlist[count]->channel_id&0xFFFFFFFFFFFFULL) == e->get_channel_id()){ + chanlist[count]->currentEvent= *e; + break; + } + } + if (p_requested_channels != NULL) free(p_requested_channels); + } + } + events.clear(); +} + +struct CmpChannelBySat: public binary_function +{ + static bool comparetolower(const char a, const char b) + { + return tolower(a) < tolower(b); + }; + + bool operator() (const CZapitChannel * const c1, const CZapitChannel * const c2) + { + if(c1->getSatellitePosition() == c2->getSatellitePosition()) + return std::lexicographical_compare(c1->getName().begin(), c1->getName().end(), c2->getName().begin(), c2->getName().end(), comparetolower); + else + return c1->getSatellitePosition() < c2->getSatellitePosition(); +; + }; +}; + +struct CmpChannelByFreq: public binary_function +{ + static bool comparetolower(const char a, const char b) + { + return tolower(a) < tolower(b); + }; + + bool operator() (const CZapitChannel * const c1, const CZapitChannel * const c2) + { + if(c1->getFreqId() == c2->getFreqId()) + return std::lexicographical_compare(c1->getName().begin(), c1->getName().end(), c2->getName().begin(), c2->getName().end(), comparetolower); + else + return c1->getFreqId() < c2->getFreqId(); +; + }; +}; + +void CChannelList::SortAlpha(void) +{ + sort(chanlist.begin(), chanlist.end(), CmpChannelByChName()); +} + +void CChannelList::SortSat(void) +{ + sort(chanlist.begin(), chanlist.end(), CmpChannelBySat()); +} + +CZapitChannel* CChannelList::getChannel(int number) +{ + for (uint32_t i=0; i< chanlist.size();i++) { + if (chanlist[i]->number == number) + return chanlist[i]; + } + return(NULL); +} + +CZapitChannel* CChannelList::getChannel(t_channel_id channel_id) +{ + for (uint32_t i=0; i< chanlist.size();i++) { + if (chanlist[i]->channel_id == channel_id) + return chanlist[i]; + } + return(NULL); +} + +int CChannelList::getKey(int id) +{ + return chanlist[id]->number; +} + +static const std::string empty_string; + +const std::string & CChannelList::getActiveChannelName(void) const +{ + if (selected < chanlist.size()) + return chanlist[selected]->name; + else + return empty_string; +} + +t_satellite_position CChannelList::getActiveSatellitePosition(void) const +{ + if (selected < chanlist.size()) + return chanlist[selected]->getSatellitePosition(); + else + return 0; +} + +t_channel_id CChannelList::getActiveChannel_ChannelID(void) const +{ + if (selected < chanlist.size()) { +//printf("CChannelList::getActiveChannel_ChannelID me %x selected = %d %llx\n", (int) this, selected, chanlist[selected]->channel_id); + return chanlist[selected]->channel_id; + } else + return 0; +} + +int CChannelList::getActiveChannelNumber(void) const +{ + return (selected + 1); +} + +int CChannelList::doChannelMenu(void) +{ + int i = 0; + int select = -1; + static int old_selected = 0; + int ret = menu_return::RETURN_NONE; + signed int bouquet_id, old_bouquet_id, new_bouquet_id; + int result; + char cnt[5]; + t_channel_id channel_id; + + if(!bouquetList || g_settings.minimode) + return 0; + + CMenuWidget* menu = new CMenuWidget(LOCALE_CHANNELLIST_EDIT, NEUTRINO_ICON_SETTINGS); + CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select); + + sprintf(cnt, "%d", i); + menu->addItem(new CMenuForwarder(LOCALE_BOUQUETEDITOR_DELETE, true, NULL, selector, cnt, CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED), old_selected == i++); + sprintf(cnt, "%d", i); + menu->addItem(new CMenuForwarder(LOCALE_BOUQUETEDITOR_MOVE, true, NULL, selector, cnt, CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN), old_selected == i++); + sprintf(cnt, "%d", i); + menu->addItem(new CMenuForwarder(LOCALE_EXTRA_ADD_TO_BOUQUET, true, NULL, selector, cnt, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW), old_selected == i++); + sprintf(cnt, "%d", i); + menu->addItem(new CMenuForwarder(LOCALE_FAVORITES_MENUEADD, true, NULL, selector, cnt, CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE), old_selected == i++); + ret = menu->exec(NULL, ""); + delete menu; + delete selector; + + if(select >= 0) { + old_selected = select; + channel_id = chanlist[selected]->channel_id; + switch(select) { + case 0: + hide(); + result = ShowMsgUTF ( LOCALE_BOUQUETEDITOR_DELETE, "Delete channel from bouquet?", CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo ); + + if(result == CMessageBox::mbrYes) { + bouquet_id = bouquetList->getActiveBouquetNumber(); + bouquet_id = g_bouquetManager->existsBouquet(bouquetList->Bouquets[bouquet_id]->channelList->getName()); + if (bouquet_id == -1) + return 0; + if(g_bouquetManager->existsChannelInBouquet(bouquet_id, channel_id)) { + g_bouquetManager->Bouquets[bouquet_id]->removeService(channel_id); + return 1; + } + } + break; + case 1: // move + old_bouquet_id = bouquetList->getActiveBouquetNumber(); + old_bouquet_id = g_bouquetManager->existsBouquet(bouquetList->Bouquets[old_bouquet_id]->channelList->getName()); + + do { + new_bouquet_id = bouquetList->exec(false); + } while(new_bouquet_id == -3); + + hide(); + if(new_bouquet_id < 0) + return 0; + new_bouquet_id = g_bouquetManager->existsBouquet(bouquetList->Bouquets[new_bouquet_id]->channelList->getName()); + if ((new_bouquet_id == -1) || (new_bouquet_id == old_bouquet_id)) + return 0; + + if(!g_bouquetManager->existsChannelInBouquet(new_bouquet_id, channel_id)) { + addChannelToBouquet(new_bouquet_id, channel_id); + } + if(g_bouquetManager->existsChannelInBouquet(old_bouquet_id, channel_id)) { + g_bouquetManager->Bouquets[old_bouquet_id]->removeService(channel_id); + } + return 1; + + break; + case 2: // add to + do { + bouquet_id = bouquetList->exec(false); + } while(bouquet_id == -3); + hide(); + if(bouquet_id < 0) + return 0; + bouquet_id = g_bouquetManager->existsBouquet(bouquetList->Bouquets[bouquet_id]->channelList->getName()); + if (bouquet_id == -1) + return 0; + if(!g_bouquetManager->existsChannelInBouquet(bouquet_id, channel_id)) { + addChannelToBouquet(bouquet_id, channel_id); + return 1; + } + break; + case 3: // add to my favorites + bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true); + if(bouquet_id == -1) { + g_bouquetManager->addBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true); + bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true); + } + if(!g_bouquetManager->existsChannelInBouquet(bouquet_id, channel_id)) { + addChannelToBouquet(bouquet_id, channel_id); + return 1; + } + + break; + default: + break; + } + } + return 0; +} + +int CChannelList::exec() +{ + displayNext = 0; // always start with current events + int nNewChannel = show(); + if ( nNewChannel > -1) { +#if 0 + if(this != CNeutrinoApp::getInstance ()->channelList) + CNeutrinoApp::getInstance ()->channelList->adjustToChannelID(chanlist[nNewChannel]->channel_id, false); + zapTo(nNewChannel); +#endif + //channelList->zapTo(bouquetList->Bouquets[bouquetList->getActiveBouquetNumber()]->channelList->getKey(nNewChannel)-1); + CNeutrinoApp::getInstance ()->channelList->zapTo(getKey(nNewChannel)-1); + } + + return nNewChannel; +} + +#define CHANNEL_SMSKEY_TIMEOUT 800 +/* return: >= 0 to zap, -1 on cancel, -3 on list mode change, -4 list edited, -2 zap but no restore old list/chan ?? */ +int CChannelList::show() +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + bool actzap = 0; + int res = -1; + + new_mode_active = 0; + pipzap = 0; + + //width = w_max (560, 0); + //height = h_max (420 + (1+3+16+3), 60); + width = w_max (((g_settings.channellist_extended)?720:660), 0); + height = h_max (450, 60); + + if (chanlist.empty()) { + return res; + } + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, name.c_str()); + + buttonHeight = 7 + std::min(16, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight()); + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + + if(theight < PIC_H) theight = PIC_H; + + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getHeight(); + listmaxshow = (height - theight - buttonHeight -0)/fheight; + height = theight + buttonHeight + listmaxshow * fheight; + //info_height = fheight + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getHeight() + 10; + info_height = 2*fheight + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getHeight() + 10; + + x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - (height+ info_height)) / 2; + displayNext = false; + + paintHead(); + updateEvents(); + paint(); + + int oldselected = selected; + int zapOnExit = false; + bool bShowBouquetList = false; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]); + + bool loop=true; + while (loop) { + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd ); + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]); + + if ( ( msg == CRCInput::RC_timeout ) || ( msg == (neutrino_msg_t)g_settings.key_channelList_cancel) ) { + if(!actzap) + selected = oldselected; + loop=false; + res = -1; + } + else if ((msg == CRCInput::RC_red) || (msg == CRCInput::RC_epg)) { + hide(); + + if ( g_EventList->exec(chanlist[selected]->channel_id, chanlist[selected]->name) == menu_return::RETURN_EXIT_ALL) { + res = -2; + loop = false; + } + paintHead(); + paint(); + } + else if (msg == CRCInput::RC_blue && ( bouquetList != NULL ) ) { //FIXME + bShowBouquetList = true; + loop=false; + } + else if (msg == CRCInput::RC_sat || msg == CRCInput::RC_favorites) { + g_RCInput->postMsg (msg, 0); + loop = false; + res = -1; + } + else if ( msg == CRCInput::RC_setup) { + old_b_id = bouquetList->getActiveBouquetNumber(); + int ret = doChannelMenu(); + if(ret) { + res = -4; + loop = false; + } else { + old_b_id = -1; + paintHead(); + paint(); + } + + } + else if (msg == (neutrino_msg_t) g_settings.key_list_start) { + selected=0; + liststart = (selected/listmaxshow)*listmaxshow; + paint(); + if(new_mode_active) { actzap = true; zapTo(selected); } + } + else if (msg == (neutrino_msg_t) g_settings.key_list_end) { + selected=chanlist.size()-1; + liststart = (selected/listmaxshow)*listmaxshow; + paint(); + if(new_mode_active) { actzap = true; zapTo(selected); } + } + else if (msg == CRCInput::RC_up || (int) msg == g_settings.key_channelList_pageup) + { + int step = 0; + int prev_selected = selected; + + step = ((int) msg == g_settings.key_channelList_pageup) ? listmaxshow : 1; // browse or step 1 + selected -= step; + if((prev_selected-step) < 0) // because of uint + selected = chanlist.size() - 1; + + paintItem(prev_selected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + paint(); + else + paintItem(selected - liststart); + + if(new_mode_active) { actzap = true; zapTo(selected); } + //paintHead(); + } + else if (msg == CRCInput::RC_down || (int) msg == g_settings.key_channelList_pagedown) + { + unsigned int step = 0; + int prev_selected = selected; + + step = ((int) msg == g_settings.key_channelList_pagedown) ? listmaxshow : 1; // browse or step 1 + selected += step; + + if(selected >= chanlist.size()) { + if (((chanlist.size() / listmaxshow) + 1) * listmaxshow == chanlist.size() + listmaxshow) // last page has full entries + selected = 0; + else + selected = ((step == listmaxshow) && (selected < (((chanlist.size() / listmaxshow)+1) * listmaxshow))) ? (chanlist.size() - 1) : 0; + } + + paintItem(prev_selected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + paint(); + else + paintItem(selected - liststart); + + if(new_mode_active) { actzap = true; zapTo(selected); } + //paintHead(); + } + + else if ((msg == (neutrino_msg_t)g_settings.key_bouquet_up) && (bouquetList != NULL)) { + if (bouquetList->Bouquets.size() > 0) { + bool found = true; + uint32_t nNext = (bouquetList->getActiveBouquetNumber()+1) % bouquetList->Bouquets.size(); + if(bouquetList->Bouquets[nNext]->channelList->getSize() <= 0) { + found = false; + nNext = nNext < bouquetList->Bouquets.size()-1 ? nNext+1 : 0; + for(uint32_t i = nNext; i < bouquetList->Bouquets.size(); i++) { + if(bouquetList->Bouquets[i]->channelList->getSize() > 0) { + found = true; + nNext = i; + break; + } + } + } + if(found) { + bouquetList->activateBouquet(nNext, false); + res = bouquetList->showChannelList(); + loop = false; + } + } + } + else if ((msg == (neutrino_msg_t)g_settings.key_bouquet_down) && (bouquetList != NULL)) { + if (bouquetList->Bouquets.size() > 0) { + bool found = true; + int nNext = (bouquetList->getActiveBouquetNumber()+bouquetList->Bouquets.size()-1) % bouquetList->Bouquets.size(); + if(bouquetList->Bouquets[nNext]->channelList->getSize() <= 0) { + found = false; + nNext = nNext > 0 ? nNext-1 : bouquetList->Bouquets.size()-1; + for(int i = nNext; i > 0; i--) { + if(bouquetList->Bouquets[i]->channelList->getSize() > 0) { + found = true; + nNext = i; + break; + } + } + } + if(found) { + bouquetList->activateBouquet(nNext, false); + res = bouquetList->showChannelList(); + loop = false; + } + } + } + else if ( msg == CRCInput::RC_ok ) { + zapOnExit = true; + loop=false; + } + else if ( msg == CRCInput::RC_spkr ) { + new_mode_active = (new_mode_active ? 0 : 1); + paintHead(); + } + else if (CRCInput::isNumeric(msg) && (this->historyMode || g_settings.sms_channel)) { + if (this->historyMode) { //numeric zap + switch (msg) { + case CRCInput::RC_0:selected = 0;break; + case CRCInput::RC_1:selected = 1;break; + case CRCInput::RC_2:selected = 2;break; + case CRCInput::RC_3:selected = 3;break; + case CRCInput::RC_4:selected = 4;break; + case CRCInput::RC_5:selected = 5;break; + case CRCInput::RC_6:selected = 6;break; + case CRCInput::RC_7:selected = 7;break; + case CRCInput::RC_8:selected = 8;break; + case CRCInput::RC_9:selected = 9;break; + }; + zapOnExit = true; + loop = false; + } + else if(g_settings.sms_channel) { + uint32_t i; + unsigned char smsKey = 0; + c_SMSKeyInput->setTimeout(CHANNEL_SMSKEY_TIMEOUT); + + do { + smsKey = c_SMSKeyInput->handleMsg(msg); + //printf("SMS new key: %c\n", smsKey); + g_RCInput->getMsg_ms(&msg, &data, CHANNEL_SMSKEY_TIMEOUT-100); + } while ((msg >= CRCInput::RC_1) && (msg <= CRCInput::RC_9)); + + if (msg == CRCInput::RC_timeout || msg == CRCInput::RC_nokey) { + for(i = selected+1; i < chanlist.size(); i++) { + char firstCharOfTitle = chanlist[i]->name.c_str()[0]; + if(tolower(firstCharOfTitle) == smsKey) { +//printf("SMS chan found was= %d selected= %d i= %d %s\n", was_sms, selected, i, chanlist[i]->channel->name.c_str()); + break; + } + } + if(i >= chanlist.size()) { + for(i = 0; i < chanlist.size(); i++) { + char firstCharOfTitle = chanlist[i]->name.c_str()[0]; + if(tolower(firstCharOfTitle) == smsKey) { +//printf("SMS chan found was= %d selected= %d i= %d %s\n", was_sms, selected, i, chanlist[i]->channel->name.c_str()); + break; + } + } + } + if(i < chanlist.size()) { + int prevselected=selected; + selected=i; + + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) { + paint(); + } else { + paintItem(selected - liststart); + } + } + c_SMSKeyInput->resetOldKey(); + } + } + } + else if(CRCInput::isNumeric(msg)) { + //pushback key if... + selected = oldselected; + g_RCInput->postMsg( msg, data ); + loop=false; + } + else if ( msg == CRCInput::RC_yellow ) + { + displayNext = !displayNext; + paintHead(); // update button bar + updateEvents(); + paint(); + } + else if ((msg == CRCInput::RC_info) || (msg == CRCInput::RC_help)) { + hide(); + g_EpgData->show(chanlist[selected]->channel_id); + paintHead(); + paint(); + } else { + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) { + loop = false; + res = - 2; + } + } + } + hide(); + if (bShowBouquetList) { + res = bouquetList->exec(true); +printf("CChannelList:: bouquetList->exec res %d\n", res); + } + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + new_mode_active = 0; + + if(NeutrinoMessages::mode_ts == CNeutrinoApp::getInstance()->getMode()) + return -1; + + if(zapOnExit) + res = selected; + +printf("CChannelList::show *********** res %d\n", res); + return(res); +} + +void CChannelList::hide() +{ + frameBuffer->paintBackgroundBoxRel(x, y, width, height+ info_height+ 5); + clearItem2DetailsLine (); +} + +bool CChannelList::showInfo(int pos, int epgpos) +{ + if((pos >= (signed int) chanlist.size()) || (pos<0)) + return false; + + CZapitChannel* chan = chanlist[pos]; + g_InfoViewer->showTitle(pos+1, chan->name, chan->getSatellitePosition(), chan->channel_id, true, epgpos); // UTF-8 + return true; +} + +int CChannelList::handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t data) +{ + if ( msg == NeutrinoMessages::EVT_PROGRAMLOCKSTATUS) { + // 0x100 als FSK-Status zeigt an, dass (noch) kein EPG zu einem Kanal der NICHT angezeigt + // werden sollte (vorgesperrt) da ist + // oder das bouquet des Kanals ist vorgesperrt + +//printf("program-lock-status: %d\n", data); + + if ((g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_ONSIGNAL) || (g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_CHANGETOLOCKED)) + { + if ( zapProtection != NULL ) + zapProtection->fsk = data; + else { + // require password if either + // CHANGETOLOCK mode and channel/bouquet is pre locked (0x100) + // ONSIGNAL mode and fsk(data) is beyond configured value + // if programm has already been unlocked, dont require pin +#if 1 + if ((data >= (neutrino_msg_data_t)g_settings.parentallock_lockage) && + ((chanlist[selected]->last_unlocked_EPGid != g_RemoteControl->current_EPGid) || (g_RemoteControl->current_EPGid == 0)) && + ((g_settings.parentallock_prompt != PARENTALLOCK_PROMPT_CHANGETOLOCKED) || (data >= 0x100))) + { + g_RemoteControl->stopvideo(); + zapProtection = new CZapProtection( g_settings.parentallock_pincode, data ); + + if ( zapProtection->check() ) + { + g_RemoteControl->startvideo(); + + // remember it for the next time + chanlist[selected]->last_unlocked_EPGid= g_RemoteControl->current_EPGid; + } + delete zapProtection; + zapProtection = NULL; + } + else + g_RemoteControl->startvideo(); +#endif + } + } + else + g_RemoteControl->startvideo(); + + return messages_return::handled; + } + else + return messages_return::unhandled; +} +/* bToo default to true */ +bool CChannelList::adjustToChannelID(const t_channel_id channel_id, bool bToo) +{ + unsigned int i; + +printf("CChannelList::adjustToChannelID me %x list size %d channel_id %llx\n", (int) this, chanlist.size(), channel_id);fflush(stdout); + for (i = 0; i < chanlist.size(); i++) { + if(chanlist[i] == NULL) { + printf("CChannelList::adjustToChannelID REPORT BUG !! ******************************** %d is NULL !!\n", i); + continue; + } + if (chanlist[i]->channel_id == channel_id) { + selected = i; + lastChList.store (selected, channel_id, false); + + tuned = i; + if (bToo && (bouquetList != NULL)) { + //bouquetList->adjustToChannel( getActiveChannelNumber()); + //bouquetList->adjustToChannelID(channel_id); +//FIXME test + if(CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_tv) { + TVbouquetList->adjustToChannelID(channel_id); + TVsatList->adjustToChannelID(channel_id); + TVfavList->adjustToChannelID(channel_id); + TVallList->adjustToChannelID(channel_id); + } + else if(CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_radio) { + RADIObouquetList->adjustToChannelID(channel_id); + RADIOsatList->adjustToChannelID(channel_id); + RADIOfavList->adjustToChannelID(channel_id); + RADIOallList->adjustToChannelID(channel_id); + } + } +//printf("CChannelList::adjustToChannelID me %x to %llx bToo %s OK: %d\n", (int) this, channel_id, bToo ? "yes" : "no", i);fflush(stdout); + return true; + } + } +//printf("CChannelList::adjustToChannelID me %x to %llx bToo %s FAILED\n", (int) this, channel_id, bToo ? "yes" : "no");fflush(stdout); + + return false; +} + +int CChannelList::hasChannel(int nChannelNr) +{ + for (uint32_t i=0;ichannel_id == channel_id) + return i; + } + return -1; +} + +// for adjusting bouquet's channel list after numzap or quickzap +void CChannelList::setSelected( int nChannelNr) +{ + selected = nChannelNr; +} + +// -- Zap to channel with channel_id +bool CChannelList::zapTo_ChannelID(const t_channel_id channel_id) +{ +printf("**************************** CChannelList::zapTo_ChannelID %llx\n", channel_id); + for (unsigned int i=0; ichannel_id == channel_id) { + zapTo (i); + return true; + } + } + return false; +} + +/* forceStoreToLastChannels defaults to false */ +void CChannelList::zapTo(int pos, bool forceStoreToLastChannels) +{ + if (chanlist.empty()) { + DisplayErrorMessage(g_Locale->getText(LOCALE_CHANNELLIST_NONEFOUND)); // UTF-8 + return; + } + if ( (pos >= (signed int) chanlist.size()) || (pos< 0) ) { + pos = 0; + } + + CZapitChannel* chan = chanlist[pos]; +printf("**************************** CChannelList::zapTo me %x %s tuned %d new %d %s -> %llx\n", (int) this, name.c_str(), tuned, pos, chan->name.c_str(), chan->channel_id); + if ( pos!=(int)tuned ) { + tuned = pos; + g_RemoteControl->zapTo_ChannelID(chan->channel_id, chan->name, !chan->bAlwaysLocked); // UTF-8 + } + if(!new_mode_active) { + selected= pos; + lastChList.store (selected, chan->channel_id, forceStoreToLastChannels); + /* remove recordModeActive from infobar */ + if(g_settings.auto_timeshift && !CNeutrinoApp::getInstance()->recordingstatus) { + g_InfoViewer->handleMsg(NeutrinoMessages::EVT_RECORDMODE, 0); + } + g_RCInput->postMsg( NeutrinoMessages::SHOW_INFOBAR, 0 ); + + if (bouquetList != NULL) { + //bouquetList->adjustToChannel( getActiveChannelNumber()); + //bouquetList->adjustToChannelID(chan->channel_id); +//FIXME test + if(CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_tv) { + TVbouquetList->adjustToChannelID(chan->channel_id); + TVsatList->adjustToChannelID(chan->channel_id); + TVfavList->adjustToChannelID(chan->channel_id); + } + else if(CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_radio) { + RADIObouquetList->adjustToChannelID(chan->channel_id); + RADIOsatList->adjustToChannelID(chan->channel_id); + RADIOfavList->adjustToChannelID(chan->channel_id); + } + } + } +} + +int CChannelList::numericZap(int key) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = -1; + + if (chanlist.empty()) { + DisplayErrorMessage(g_Locale->getText(LOCALE_CHANNELLIST_NONEFOUND)); // UTF-8 + return res; + } + + // -- quickzap "0" to last seen channel... + if (key == g_settings.key_lastchannel) { + t_channel_id channel_id = lastChList.getlast(1); + if(channel_id) { + lastChList.clear_storedelay (); // ignore store delay + zapTo_ChannelID(channel_id); + } + return res; + } + + if (key == g_settings.key_zaphistory) { + if(!autoshift && CNeutrinoApp::getInstance()->recordingstatus) { + CChannelList * orgList = bouquetList->orgChannelList; + CChannelList * channelList = new CChannelList(g_Locale->getText(LOCALE_CHANNELLIST_CURRENT_TP), false, true); + t_channel_id recid = rec_channel_id >> 16; + for ( unsigned int i = 0 ; i < orgList->chanlist.size(); i++) { + if((orgList->chanlist[i]->channel_id >> 16) == recid) { + channelList->addChannel(orgList->chanlist[i]); + } + } + if (channelList->getSize() != 0) { + channelList->adjustToChannelID(orgList->getActiveChannel_ChannelID(), false); + this->frameBuffer->paintBackground(); + res = channelList->exec(); +#if 0 + int newChannel = channelList->show() ; + + if (newChannel > -1) { //FIXME handle edit/mode change ?? + orgList->zapTo_ChannelID(channelList->chanlist[newChannel]->channel_id); + } +#endif + } + delete channelList; + return res; + } + // -- zap history bouquet, similar to "0" quickzap, but shows a menue of last channels + if (this->lastChList.size() > 1) { + CChannelList * channelList = new CChannelList(g_Locale->getText(LOCALE_CHANNELLIST_HISTORY), true, true); + + for(unsigned int i = 1 ; i < this->lastChList.size() ; ++i) { + t_channel_id channel_id = this->lastChList.getlast(i); + if(channel_id) { + CZapitChannel* channel = getChannel(channel_id); + if(channel) channelList->addChannel(channel); + } + } + if (channelList->getSize() != 0) { + this->frameBuffer->paintBackground(); + //int newChannel = channelList->exec(); + res = channelList->exec(); + } + delete channelList; + } + return res; + } + + //int ox = 300; + //int oy = 200; + int sx = 4 * g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getRenderWidth(widest_number) + 14; + int sy = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->getHeight() + 6; + + int ox = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - sx)/2; + int oy = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - sy)/2; + char valstr[10]; + int chn = CRCInput::getNumericValue(key); + int pos = 1; + int lastchan= -1; + bool doZap = true; + bool showEPG = false; + + while(1) { + if (lastchan != chn) { + sprintf((char*) &valstr, "%d", chn); + while(strlen(valstr)<4) + strcat(valstr,"-"); //"_" + + frameBuffer->paintBoxRel(ox, oy, sx, sy, COL_INFOBAR_PLUS_0); + + for (int i=3; i>=0; i--) { + valstr[i+ 1]= 0; + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP]->RenderString(ox+7+ i*((sx-14)>>2), oy+sy-3, sx, &valstr[i], COL_INFOBAR); + } + + showInfo(chn- 1); + lastchan= chn; + } + + g_RCInput->getMsg( &msg, &data, g_settings.timing[SNeutrinoSettings::TIMING_NUMERICZAP] * 10 ); + + if ( msg == CRCInput::RC_timeout ) { + if ( ( chn > (int)chanlist.size() ) || (chn == 0) ) + chn = tuned + 1; + break; + } + else if ( msg == CRCInput::RC_favorites || msg == CRCInput::RC_sat) { + } + else if (CRCInput::isNumeric(msg)) { + if (pos == 4) { + chn = 0; + pos = 1; + } else { + chn *= 10; + pos++; + } + chn += CRCInput::getNumericValue(msg); + } + else if ( msg == CRCInput::RC_ok ) { + if ( ( chn > (signed int) chanlist.size() ) || ( chn == 0 ) ) { + chn = tuned + 1; + } + break; + } + else if ( msg == (neutrino_msg_t)g_settings.key_quickzap_down ) { + if ( chn == 1 ) + chn = chanlist.size(); + else { + chn--; + + if (chn > (int)chanlist.size()) + chn = (int)chanlist.size(); + } + } + else if ( msg == (neutrino_msg_t)g_settings.key_quickzap_up ) { + chn++; + + if (chn > (int)chanlist.size()) + chn = 1; + } + else if ( ( msg == CRCInput::RC_home ) || ( msg == CRCInput::RC_left ) || ( msg == CRCInput::RC_right) ) + { + doZap = false; + break; + } + else if ( msg == CRCInput::RC_red ) { + if ( ( chn <= (signed int) chanlist.size() ) && ( chn != 0 ) ) { + doZap = false; + showEPG = true; + break; + } + } + else if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) { + doZap = false; + //res = menu_return::RETURN_EXIT_ALL; + break; + } + } + + frameBuffer->paintBackgroundBoxRel(ox, oy, sx, sy); + + chn--; + if (chn<0) + chn=0; + if ( doZap ) { + if(g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR] == 0) + g_InfoViewer->killTitle(); + zapTo( chn ); + } else { + showInfo(tuned); + g_InfoViewer->killTitle(); + if ( showEPG ) + g_EventList->exec(chanlist[chn]->channel_id, chanlist[chn]->name); + } + return res; +} + +void CChannelList::virtual_zap_mode(bool up) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + if (chanlist.empty()) { + DisplayErrorMessage(g_Locale->getText(LOCALE_CHANNELLIST_NONEFOUND)); // UTF-8 + return; + } + + int chn = getActiveChannelNumber() + (up ? 1 : -1); + if (chn > (int)chanlist.size()) + chn = 1; + if (chn == 0) + chn = (int)chanlist.size(); + int lastchan= -1; + bool doZap = true; + bool showEPG = false; + int epgpos = 0; + + while(1) + { + if (lastchan != chn || (epgpos != 0)) + { + showInfo(chn- 1, epgpos); + lastchan= chn; + } + epgpos = 0; + g_RCInput->getMsg( &msg, &data, 15*10 ); // 15 seconds, not user changable + //printf("########### %u ### %u #### %u #######\n", msg, NeutrinoMessages::EVT_TIMER, CRCInput::RC_timeout); + + if ( msg == CRCInput::RC_ok ) + { + if ( ( chn > (signed int) chanlist.size() ) || ( chn == 0 ) ) + { + chn = tuned + 1; + } + break; + } + else if ( msg == CRCInput::RC_left ) + { + if ( chn == 1 ) + chn = chanlist.size(); + else + { + chn--; + + if (chn > (int)chanlist.size()) + chn = (int)chanlist.size(); + } + } + else if ( msg == CRCInput::RC_right ) + { + chn++; + + if (chn > (int)chanlist.size()) + chn = 1; + } + else if ( msg == CRCInput::RC_up ) + { + epgpos = -1; + } + else if ( msg == CRCInput::RC_down ) + { + epgpos = 1; + } + else if ( ( msg == CRCInput::RC_home ) || ( msg == CRCInput::RC_timeout ) ) + { + // Abbruch ohne Channel zu wechseln + doZap = false; + break; + } + else if ( msg == CRCInput::RC_red ) + { + // Rote Taste zeigt EPG fuer gewaehlten Kanal an + if ( ( chn <= (signed int) chanlist.size() ) && ( chn != 0 ) ) + { + doZap = false; + showEPG = true; + break; + } + } + else if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + doZap = false; + break; + } + } + g_InfoViewer->clearVirtualZapMode(); + + chn--; + if (chn<0) + chn=0; + if ( doZap ) + { + if(g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR] == 0) + g_InfoViewer->killTitle(); + zapTo( chn ); + } + else + { + showInfo(tuned); + g_InfoViewer->killTitle(); + + // Rote Taste zeigt EPG fuer gewaehlten Kanal an + if ( showEPG ) + g_EventList->exec(chanlist[chn]->channel_id, chanlist[chn]->name); + } +} + +void CChannelList::quickZap(int key, bool cycle) +{ + if(chanlist.size() == 0) + return; + + int bsize = bouquetList->Bouquets.size(); + if(!cycle && bsize > 1) { + int bactive = bouquetList->getActiveBouquetNumber(); + int cactive = selected; + +printf("CChannelList::quickZap: selected %d total %d active bouquet %d total %d\n", cactive, chanlist.size(), bactive, bsize); + if ( (key==g_settings.key_quickzap_down) || (key == CRCInput::RC_left)) { + cactive--; + if(cactive < 0) { + if(bactive == 0) + bactive = bsize - 1; + else + bactive--; + bouquetList->activateBouquet(bactive, false); + cactive = bouquetList->Bouquets[bactive]->channelList->getSize() - 1; + } else + selected = cactive; + } + else if ((key==g_settings.key_quickzap_up) || (key == CRCInput::RC_right)) { + cactive++; + if(cactive >= chanlist.size()) { + bactive = (bactive + 1) % bsize; + bouquetList->activateBouquet(bactive, false); + cactive = 0; + } else + selected = cactive; + } +printf("CChannelList::quickZap: new selected %d total %d active bouquet %d total %d\n", cactive, bouquetList->Bouquets[bactive]->channelList->getSize(), bactive, bsize); + CNeutrinoApp::getInstance()->channelList->zapTo(bouquetList->Bouquets[bactive]->channelList->getKey(cactive)-1); + } else { + if ( (key==g_settings.key_quickzap_down) || (key == CRCInput::RC_left)) { + if(selected == 0) + selected = chanlist.size()-1; + else + selected--; + } + else if ((key==g_settings.key_quickzap_up) || (key == CRCInput::RC_right)) { + selected = (selected+1)%chanlist.size(); + } + + //printf("[neutrino] quick zap selected = %d bouquetList %x getActiveBouquetNumber %d orgChannelList %x\n", selected, bouquetList, bouquetList->getActiveBouquetNumber(), bouquetList->orgChannelList); + + CNeutrinoApp::getInstance()->channelList->zapTo(getKey(selected)-1); + } + g_RCInput->clearRCMsg(); //FIXME test for n.103 +} + +void CChannelList::paintDetails(int index) +{ + CChannelEvent *p_event; + if (displayNext) { + p_event = &chanlist[index]->nextEvent; + } else { + p_event = &chanlist[index]->currentEvent; + } + +#if 0 + if (chanlist[index]->currentEvent.description.empty()) { + frameBuffer->paintBackgroundBoxRel(x, y+ height, width, info_height); + } else +#endif + { + frameBuffer->paintBoxRel(x+2, y + height + 2, width-4, info_height - 4, COL_MENUCONTENTDARK_PLUS_0, ROUND_RADIUS, 3);//round + + if (!p_event->description.empty()) { + char cNoch[50]; // UTF-8 + char cSeit[50]; // UTF-8 + + struct tm *pStartZeit = localtime(&p_event->startTime); + unsigned seit = ( time(NULL) - p_event->startTime ) / 60; + if (displayNext) { + sprintf(cNoch, "(%d min)", p_event->duration / 60); + sprintf(cSeit, g_Locale->getText(LOCALE_CHANNELLIST_START), pStartZeit->tm_hour, pStartZeit->tm_min); + } else { + sprintf(cSeit, g_Locale->getText(LOCALE_CHANNELLIST_SINCE), pStartZeit->tm_hour, pStartZeit->tm_min); + int noch = (p_event->startTime + p_event->duration - time(NULL)) / 60; + if ((noch< 0) || (noch>=10000)) + noch= 0; + sprintf(cNoch, "(%d / %d min)", seit, noch); + } + int seit_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth(cSeit, true); // UTF-8 + int noch_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(cNoch, true); // UTF-8 + + std::string text1= p_event->description; + std::string text2= p_event->text; + + int xstart = 10; + if (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1, true) > (width - 30 - seit_len) ) + { + // zu breit, Umbruch versuchen... + int pos; + do { + pos = text1.find_last_of("[ -.]+"); + if ( pos!=-1 ) + text1 = text1.substr( 0, pos ); + } while ( ( pos != -1 ) && (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1, true) > (width - 30 - seit_len) ) ); + + std::string text3 = p_event->description.substr(text1.length()+ 1); + + if (!(text2.empty())) + text3= text3+ " - "; + + xstart += g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text3, true); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ 2* fheight, width - 30- noch_len, text3, COL_MENUCONTENTDARK, 0, true); + } + + if (!(text2.empty())) { + while ( text2.find_first_of("[ -.+*#?=!$%&/]+") == 0 ) + text2 = text2.substr( 1 ); + text2 = text2.substr( 0, text2.find('\n') ); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ xstart, y+ height+ 5+ 2* fheight, width- xstart- 20- noch_len, text2, COL_MENUCONTENTDARK, 0, true); + } + + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ fheight, width - 30 - seit_len, text1, COL_MENUCONTENTDARK, 0, true); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString (x+ width- 10- seit_len, y+ height+ 5+ fheight , seit_len, cSeit, COL_MENUCONTENTDARK, 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(x+ width- 10- noch_len, y+ height+ 5+ 2* fheight- 2, noch_len, cNoch, COL_MENUCONTENTDARK, 0, true); // UTF-8 + } + + char buf[128]; + transponder_id_t ct = chanlist[index]->getTransponderId(); + transponder_list_t::iterator tpI = transponders.find(ct); + int len = snprintf(buf, sizeof(buf), "%d ", chanlist[index]->getFreqId()); + + if(tpI != transponders.end()) { + char * f, *s, *m; + switch(frontend->getInfo()->type) { + case FE_QPSK: + frontend->getDelSys(tpI->second.feparams.u.qpsk.fec_inner, dvbs_get_modulation(tpI->second.feparams.u.qpsk.fec_inner), f, s, m); + len += snprintf(&buf[len], sizeof(buf) - len, "%c %d %s %s %s ", tpI->second.polarization ? 'V' : 'H', tpI->second.feparams.u.qpsk.symbol_rate/1000, f, s, m); + break; + case FE_QAM: + frontend->getDelSys(tpI->second.feparams.u.qam.fec_inner, tpI->second.feparams.u.qam.modulation, f, s, m); + len += snprintf(&buf[len], sizeof(buf) - len, "%d %s %s %s ", tpI->second.feparams.u.qam.symbol_rate/1000, f, s, m); + break; + case FE_OFDM: + case FE_ATSC: + break; + } + } + + if(chanlist[index]->pname) + snprintf(&buf[len], sizeof(buf) - len, "(%s)\n", chanlist[index]->pname); + else { + sat_iterator_t sit = satellitePositions.find(chanlist[index]->getSatellitePosition()); + if(sit != satellitePositions.end()) { + int satNameWidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth (sit->second.name); + snprintf(&buf[len], sizeof(buf) - len, "(%s)\n", sit->second.name.c_str()); + } + } + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ 3*fheight, width - 30, buf, COL_MENUCONTENTDARK, 0, true); + } +} + +void CChannelList::clearItem2DetailsLine () +{ + paintItem2DetailsLine (-1, 0); +} + +void CChannelList::paintItem2DetailsLine (int pos, int ch_index) +{ + #define ConnectLineBox_Width 16 + + int xpos = x - ConnectLineBox_Width; + int ypos1 = y + theight+0 + pos*fheight; + int ypos2 = y + height; + int ypos1a = ypos1 + (fheight/2)-2; + int ypos2a = ypos2 + (info_height/2)-2; + fb_pixel_t col1 = COL_MENUCONTENT_PLUS_6; + fb_pixel_t col2 = COL_MENUCONTENT_PLUS_1; + + // Clear + frameBuffer->paintBackgroundBoxRel(xpos,y, ConnectLineBox_Width, height+info_height); + + // paint Line if detail info (and not valid list pos) + if (pos >= 0) { //pos >= 0 && chanlist[ch_index]->currentEvent.description != "") { + if(1) // FIXME why -> ? (!g_settings.channellist_extended) + { + int fh = fheight > 10 ? fheight - 10: 5; + frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos1+5, 4, fh, col1); + frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos1+5, 1, fh, col2); + + frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos2+7, 4,info_height-14, col1); + frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos2+7, 1,info_height-14, col2); + + frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-16, ypos1a, 4,ypos2a-ypos1a, col1); + frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-16, ypos1a, 1,ypos2a-ypos1a+4, col2); + + frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-16, ypos1a, 12,4, col1); + frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-16, ypos1a, 12,1, col2); + + frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-16, ypos2a, 12,4, col1); + frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-12, ypos2a, 8,1, col2); + + frameBuffer->paintBoxRel(x, ypos2, width, info_height, col1, ROUND_RADIUS, 3); + } + } +} + +void CChannelList::paintItem(int pos) +{ + int ypos = y+ theight+0 + pos*fheight; + uint8_t color; + fb_pixel_t bgcolor; + bool iscurrent = true; + unsigned int curr = liststart + pos; + + if(!autoshift && CNeutrinoApp::getInstance()->recordingstatus && curr < chanlist.size()) { + iscurrent = (chanlist[curr]->channel_id >> 16) == (rec_channel_id >> 16); +//printf("recording %llx current %llx current = %s\n", rec_channel_id, chanlist[liststart + pos]->channel->channel_id, iscurrent? "yes" : "no"); + } + if (curr == selected) { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + paintItem2DetailsLine (pos, curr); + paintDetails(curr); + frameBuffer->paintBoxRel(x + width - 100 - PIC_W, y+(theight-PIC_H)/2, PIC_W, PIC_H, COL_MENUHEAD_PLUS_0); + g_PicViewer->DisplayLogo(chanlist[selected]->channel_id, x + width - 100 - PIC_W, y+(theight-PIC_H)/2, PIC_W, PIC_H); + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor, ROUND_RADIUS, 3); + } else { + color = iscurrent ? COL_MENUCONTENT : COL_MENUCONTENTINACTIVE; + bgcolor = iscurrent ? COL_MENUCONTENT_PLUS_0 : COL_MENUCONTENTINACTIVE_PLUS_0; + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor, 0, 3); + } +#if 0 + if(curr < chanlist.size()) { + CZapitChannel* chan = chanlist[liststart+pos]; + char tmp[10]; + sprintf((char*) tmp, "%d", this->historyMode ? pos : chan->number); + int numpos = x+5+numwidth- g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(tmp); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(numpos,ypos+fheight, numwidth+5, tmp, color, fheight); + char nameAndDescription[255]; + if (!(chan->currentEvent.description.empty())) { + snprintf(nameAndDescription, sizeof(nameAndDescription), "%s - %s", + chan->name.c_str(), chan->currentEvent.description.c_str()); + } else { + snprintf(nameAndDescription, sizeof(nameAndDescription), "%s", chan->name.c_str()); + } + if (curr == selected) + CVFD::getInstance()->showMenuText(0, nameAndDescription, -1, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 5+ numwidth+ 10, ypos+ fheight, width- numwidth- 20- 15, nameAndDescription, color, 0, true); + } +#else + if(curr < chanlist.size()) { + char nameAndDescription[255]; + char tmp[10]; + CZapitChannel* chan = chanlist[curr]; + int prg_offset=0; + int title_offset=0; + uint8_t tcolor=(liststart + pos == selected) ? color : COL_MENUCONTENTINACTIVE; + int xtheight=fheight-2; + + if(g_settings.channellist_extended) + { + prg_offset=42; + title_offset=6; + } + + sprintf((char*) tmp, "%d", this->historyMode ? pos : chan->number); + + CChannelEvent *p_event=NULL; + if (displayNext) { + p_event = &chan->nextEvent; + } else { + p_event = &chan->currentEvent; + } + + if(chan->scrambled) + frameBuffer->paintIcon("ca.raw", x+width- 15 - 28, ypos + (fheight - 16)/2); + + int numpos = x+5+numwidth- g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(tmp); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(numpos,ypos+fheight, numwidth+5, tmp, color, fheight); + + int l=0; + if (this->historyMode) + l = snprintf(nameAndDescription, sizeof(nameAndDescription), ": %d %s", chan->number, chan->name.c_str()); + else + l = snprintf(nameAndDescription, sizeof(nameAndDescription), "%s", chan->name.c_str()); + + if (!(p_event->description.empty())) { + + snprintf(nameAndDescription+l, sizeof(nameAndDescription)-l," - "); + unsigned int ch_name_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(nameAndDescription, true); + unsigned int ch_desc_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth(p_event->description, true); + + if ( (width- numwidth- 60- 15- prg_offset - ch_name_len)< ch_desc_len ) + ch_desc_len = (width- numwidth- 60- 15- ch_name_len - prg_offset); + if (ch_desc_len< 0) + ch_desc_len = 0; + + if(g_settings.channellist_extended){ + if(displayNext) + { + struct tm *pStartZeit = localtime(&p_event->startTime); + + sprintf((char*) tmp, "%02d:%02d", pStartZeit->tm_hour, pStartZeit->tm_min); +// g_Font[SNeutrinoSettings::FONT_TYPE_IMAGEINFO_SMALL]->RenderString(x+ 5+ numwidth+ 6, ypos+ xtheight, width- numwidth- 20- 15 -poffs, tmp, COL_MENUCONTENT, 0, true); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(x+ 5+ numwidth+ 6, ypos+ xtheight, width- numwidth- 20- 15 -prg_offset, tmp, tcolor, 0, true); + } + else + { + time_t jetzt=time(NULL); + int runningPercent = 0; + + if (((jetzt - p_event->startTime + 30) / 60) < 0 ) + { + runningPercent= 0; + } + else + { + runningPercent=(jetzt-p_event->startTime) * 30 / p_event->duration; + if (runningPercent > 30) // this would lead to negative value in paintBoxRel + runningPercent = 30; // later on which can be fatal... + } + frameBuffer->paintBoxRel(x+ 5+ numwidth+ title_offset, ypos+fheight/4, 34, fheight/2, COL_MENUCONTENT_PLUS_3, 0);//fill passive + frameBuffer->paintBoxRel(x+ 5+ numwidth+ title_offset+2, ypos+2+fheight/4, 30, fheight/2-4, COL_MENUCONTENT_PLUS_1, 0);//frame(passive) + frameBuffer->paintBoxRel(x+ 5+ numwidth+ title_offset+2, ypos+2+fheight/4, runningPercent, fheight/2-4, COL_MENUCONTENT_PLUS_3, 0);//fill(active) + } + } + + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 5+ numwidth+ 10+prg_offset, ypos+ fheight, width- numwidth- 40- 15-prg_offset, nameAndDescription, color, 0, true); + if (g_settings.channellist_epgtext_align_right){ + // align right + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x + width - 20 - ch_desc_len - 28, ypos + fheight, ch_desc_len, p_event->description, (curr == selected)?COL_MENUCONTENTSELECTED:(!displayNext ? COL_MENUCONTENT : COL_MENUCONTENTINACTIVE) , 0, true); + } + else{ + // align left + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ 5+ numwidth+ 10+ ch_name_len+ 5+prg_offset, ypos+ fheight, ch_desc_len, p_event->description, (curr == selected)?COL_MENUCONTENTSELECTED:(!displayNext ? COL_MENUCONTENT : COL_MENUCONTENTINACTIVE) , 0, true); + } + } + else { + if(g_settings.channellist_extended){ + short runningPercent=0; + frameBuffer->paintBoxRel(x+ 5+ numwidth+ title_offset, ypos+fheight/4, 34, fheight/2, COL_MENUCONTENT_PLUS_3, 0);//fill passive + frameBuffer->paintBoxRel(x+ 5+ numwidth+ title_offset+2, ypos+2+fheight/4, 30, fheight/2-4, COL_MENUCONTENT_PLUS_1, 0);//frame(passive) + frameBuffer->paintBoxRel(x+ 5+ numwidth+ title_offset+2, ypos+2+fheight/4, runningPercent, fheight/2-4, COL_MENUCONTENT_PLUS_3, 0);//fill(active) + frameBuffer->paintLine(x+ 5+ numwidth+ title_offset, ypos+fheight/4+1,x+ 5+ numwidth+ title_offset+ 32, ypos+fheight/4+fheight/2-3, COL_MENUCONTENT_PLUS_3); + } + //name + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 5+ numwidth+ 10+prg_offset, ypos+ fheight, width- numwidth- 40- 15-prg_offset, nameAndDescription, color, 0, true); // UTF-8 + } + if (curr == selected) { + if (!(chan->currentEvent.description.empty())) { + snprintf(nameAndDescription, sizeof(nameAndDescription), "%s - %s", + chan->name.c_str(), p_event->description.c_str()); + CVFD::getInstance()->showMenuText(0, nameAndDescription, -1, true); // UTF-8 + } else + CVFD::getInstance()->showMenuText(0, chan->name.c_str(), -1, true); // UTF-8 + } + } +#endif +} + +#define NUM_LIST_BUTTONS 3 +struct button_label CChannelListButtons[NUM_LIST_BUTTONS] = +{ + { NEUTRINO_ICON_BUTTON_RED, LOCALE_INFOVIEWER_EVENTLIST}, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_INFOVIEWER_NEXT}, + { NEUTRINO_ICON_BUTTON_BLUE, LOCALE_BOUQUETLIST_HEAD} +#if 0 + { NEUTRINO_ICON_BUTTON_GREEN, LOCALE_BOUQUETEDITOR_DELETE}, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_BOUQUETEDITOR_MOVE}, + { NEUTRINO_ICON_BUTTON_BLUE, LOCALE_EXTRA_ADD_TO_BOUQUET} +#endif +}; + +#define NUM_VLIST_BUTTONS 3 +const struct button_label CChannelVListButtons[NUM_VLIST_BUTTONS] = +{ + { NEUTRINO_ICON_BUTTON_RED, LOCALE_INFOVIEWER_EVENTLIST}, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_INFOVIEWER_NEXT}, + { NEUTRINO_ICON_BUTTON_BLUE, LOCALE_BOUQUETLIST_HEAD} + //{ NEUTRINO_ICON_BUTTON_BLUE, LOCALE_EXTRA_ADD_TO_BOUQUET} +}; + +void CChannelList::paintHead() +{ + // head + frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1);//round + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10,y+theight+0, width- 65, name, COL_MENUHEAD, 0, true); // UTF-8 + + int ButtonWidth = (width - 20) / 4; + + // foot + if (displayNext) { + CChannelListButtons[1].locale = LOCALE_INFOVIEWER_NOW; + } else { + CChannelListButtons[1].locale = LOCALE_INFOVIEWER_NEXT; + } + + frameBuffer->paintBoxRel(x, y + (height - buttonHeight), width, buttonHeight - 1, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2); //round + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 10, y + (height - buttonHeight) + 3, ButtonWidth, + vlist ? NUM_VLIST_BUTTONS : NUM_LIST_BUTTONS, vlist ? CChannelVListButtons : CChannelListButtons); + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, x+ width- 30, y+ 5 ); + if (bouquetList != NULL) + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DBOX, x + width - 60, y + 5); // icon for bouquet list button + frameBuffer->paintIcon(new_mode_active ? NEUTRINO_ICON_BUTTON_MUTE_ZAP_ACTIVE : NEUTRINO_ICON_BUTTON_MUTE_ZAP_INACTIVE, x + width - 90, y + 5); +} + +void CChannelList::paint() +{ + liststart = (selected/listmaxshow)*listmaxshow; + //FIXME do we need to find biggest chan number in list ? + numwidth = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth("0000"); + //updateEvents(); + + frameBuffer->paintBoxRel(x, y+theight, width, height-buttonHeight-theight, COL_MENUCONTENT_PLUS_0, 0, 2); + + for(unsigned int count = 0; count < listmaxshow; count++) { + paintItem(count); + } + + int ypos = y+ theight; + int sb = fheight* listmaxshow; + frameBuffer->paintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((chanlist.size()- 1)/ listmaxshow)+ 1; + int sbs= (selected/listmaxshow); + + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ sbs*(sb-4)/sbc, 11, (sb-4)/sbc, COL_MENUCONTENT_PLUS_3); + +} + +int CChannelList::getSize() const +{ + return this->chanlist.size(); +} + +int CChannelList::getSelectedChannelIndex() const +{ + return this->selected; +} diff --git a/src/gui/channellist.h b/src/gui/channellist.h new file mode 100644 index 000000000..5539cf6d8 --- /dev/null +++ b/src/gui/channellist.h @@ -0,0 +1,135 @@ +#ifndef __channellist__ +#define __channellist__ + +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +enum { + LIST_MODE_FAV, + LIST_MODE_PROV, + LIST_MODE_SAT, + LIST_MODE_ALL +}; + +class CChannelList +{ + private: + CFrameBuffer *frameBuffer; + unsigned int selected; + CLastChannel lastChList; + unsigned int liststart; + unsigned int listmaxshow; + unsigned int numwidth; + int fheight; // Fonthoehe Channellist-Inhalt + int theight; // Fonthoehe Channellist-Titel + int buttonHeight; + + std::string name; + //std::vector chanlist; + std::vector chanlist; + CZapProtection* zapProtection; + + int width; + int height; + int x; + int y; + + bool historyMode; + bool vlist; // "virtual" list, not bouquet + bool displayNext; + + void paintDetails(int index); + void clearItem2DetailsLine (); + void paintItem2DetailsLine (int pos, int ch_index); + void paintItem(int pos); + void paint(); + void paintHead(); + void hide(); + + public: + CChannelList(const char * const Name, bool historyMode = false, bool _vlist = false ); + ~CChannelList(); + //void addChannel(int key, int number, const std::string& name, const t_satellite_position satellitePosition, t_channel_id ids = 0); // UTF-8 + void addChannel(CZapitChannel* chan, int num = 0); + void putChannel(CZapitChannel* chan); + //void addChannel(CZapitChannel* channel, int key, int number, bool locked = false); + CZapitChannel* getChannel(int number); + CZapitChannel* getChannel(t_channel_id channel_id); + CZapitChannel* getChannelFromIndex( uint32_t index) { if (chanlist.size() > index) return chanlist[index]; else return NULL;}; + CZapitChannel* operator[]( uint32_t index) { if (chanlist.size() > index) return chanlist[index]; else return NULL;}; + int getKey(int); + + const char * const getName (void) const { return name.c_str(); }; + const std::string & getActiveChannelName (void) const; // UTF-8 + t_satellite_position getActiveSatellitePosition(void) const; + int getActiveChannelNumber (void) const; + t_channel_id getActiveChannel_ChannelID(void) const; + +/* CChannel * getChannelFromChannelID(const t_channel_id channel_id); */ + + void zapTo(int pos, bool forceStoreToLastChannels = false); + void virtual_zap_mode(bool up); + bool zapTo_ChannelID(const t_channel_id channel_id); + bool adjustToChannelID(const t_channel_id channel_id, bool bToo = true); + bool showInfo(int pos, int epgpos = 0); + void updateEvents(void); + int numericZap(int key); + int show(); + int exec(); + void quickZap(int key, bool cycle = false); + int hasChannel(int nChannelNr); + int hasChannelID(t_channel_id channel_id); + void setSelected( int nChannelNr); // for adjusting bouquet's channel list after numzap or quickzap + + int handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t data); + + int getSize() const; + int getSelectedChannelIndex() const; + void setSize(int newsize); + unsigned int tuned; + int doChannelMenu(void); + void SortAlpha(void); + void SortSat(void); + void ClearList(void); + //friend class CZapitChannel; +}; +#endif diff --git a/src/gui/color.cpp b/src/gui/color.cpp new file mode 100644 index 000000000..d4e7e0fad --- /dev/null +++ b/src/gui/color.cpp @@ -0,0 +1,90 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + + +int convertSetupColor2RGB(const unsigned char r, const unsigned char g, const unsigned char b) +{ + unsigned char red = int( float(255./100.)*float(r) ); + unsigned char green = int( float(255./100.)*float(g) ); + unsigned char blue = int( float(255./100.)*float(b) ); + + return (red << 16) | (green << 8) | blue; +} + +int convertSetupAlpha2Alpha(unsigned char alpha) +{ + if(alpha == 0) return 0xFF; + else if(alpha >= 100) return 0; + unsigned char a = 100 - alpha; + int ret = int( float(0xFF/100.)*float(a) ); + return ret; +} + +void recalcColor(unsigned char &orginal, int fade) +{ + if(fade==100) + { + return; + } + int color = int( float( float(orginal) * float( float(fade) / 100.0)) ); + if(color>255) + color=255; + if(color<0) + color=0; + orginal = color; +} + +void protectColor( unsigned char &r, unsigned char &g, unsigned char &b, bool protect ) +{ + if (!protect) + return; + if ((r==0) && (g==0) && (b==0)) + { + r=1; + g=1; + b=1; + } +} + +void fadeColor(unsigned char &r, unsigned char &g, unsigned char &b, int fade, bool protect) +{ + recalcColor(r, fade); + recalcColor(g, fade); + recalcColor(b, fade); + protectColor(r,g,b, protect); +} diff --git a/src/gui/color.h b/src/gui/color.h new file mode 100644 index 000000000..d51dce641 --- /dev/null +++ b/src/gui/color.h @@ -0,0 +1,100 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __color__ +#define __color__ + +#define COL_MAXFREE 254-8*7 - 1 +#define COL_INFOBAR_SHADOW 254-8*7 +#define COL_INFOBAR 254-8*6 +#define COL_MENUHEAD 254-8*5 +#define COL_MENUCONTENT 254-8*4 +#define COL_MENUCONTENTDARK 254-8*3 +#define COL_MENUCONTENTSELECTED 254-8*2 +#define COL_MENUCONTENTINACTIVE 254-8*1 + +#define COL_BACKGROUND 255 + +#ifdef FB_USE_PALETTE +#define COL_INFOBAR_SHADOW_PLUS_0 (COL_INFOBAR_SHADOW + 0) +#define COL_INFOBAR_SHADOW_PLUS_1 (COL_INFOBAR_SHADOW + 1) +#define COL_INFOBAR_PLUS_0 (COL_INFOBAR + 0) +#define COL_INFOBAR_PLUS_1 (COL_INFOBAR + 1) +#define COL_INFOBAR_PLUS_3 (COL_INFOBAR + 3) +#define COL_INFOBAR_PLUS_7 (COL_INFOBAR + 7) +#define COL_MENUHEAD_PLUS_0 (COL_MENUHEAD + 0) +#define COL_MENUCONTENT_PLUS_0 (COL_MENUCONTENT + 0) +#define COL_MENUCONTENT_PLUS_1 (COL_MENUCONTENT + 1) +#define COL_MENUCONTENT_PLUS_2 (COL_MENUCONTENT + 2) +#define COL_MENUCONTENT_PLUS_3 (COL_MENUCONTENT + 3) +#define COL_MENUCONTENT_PLUS_4 (COL_MENUCONTENT + 4) +#define COL_MENUCONTENT_PLUS_5 (COL_MENUCONTENT + 5) +#define COL_MENUCONTENT_PLUS_6 (COL_MENUCONTENT + 6) +#define COL_MENUCONTENT_PLUS_7 (COL_MENUCONTENT + 7) +#define COL_MENUCONTENTDARK_PLUS_0 (COL_MENUCONTENTDARK + 0) +#define COL_MENUCONTENTDARK_PLUS_2 (COL_MENUCONTENTDARK + 2) +#define COL_MENUCONTENTSELECTED_PLUS_0 (COL_MENUCONTENTSELECTED + 0) +#define COL_MENUCONTENTSELECTED_PLUS_2 (COL_MENUCONTENTSELECTED + 2) +#define COL_MENUCONTENTINACTIVE_PLUS_0 (COL_MENUCONTENTINACTIVE + 0) +#define COL_BACKGROUND_PLUS_0 (COL_BACKGROUND + 0) +#else +#define COL_INFOBAR_SHADOW_PLUS_0 (CFrameBuffer::getInstance()->realcolor[(COL_INFOBAR_SHADOW + 0)]) +#define COL_INFOBAR_SHADOW_PLUS_1 (CFrameBuffer::getInstance()->realcolor[(COL_INFOBAR_SHADOW + 1)]) +#define COL_INFOBAR_PLUS_0 (CFrameBuffer::getInstance()->realcolor[(COL_INFOBAR + 0)]) +#define COL_INFOBAR_PLUS_1 (CFrameBuffer::getInstance()->realcolor[(COL_INFOBAR + 1)]) +#define COL_INFOBAR_PLUS_3 (CFrameBuffer::getInstance()->realcolor[(COL_INFOBAR + 3)]) +#define COL_INFOBAR_PLUS_7 (CFrameBuffer::getInstance()->realcolor[(COL_INFOBAR + 7)]) +#define COL_MENUHEAD_PLUS_0 (CFrameBuffer::getInstance()->realcolor[(COL_MENUHEAD + 0)]) +#define COL_MENUCONTENT_PLUS_0 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENT + 0)]) +#define COL_MENUCONTENT_PLUS_1 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENT + 1)]) +#define COL_MENUCONTENT_PLUS_2 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENT + 2)]) +#define COL_MENUCONTENT_PLUS_3 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENT + 3)]) +#define COL_MENUCONTENT_PLUS_4 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENT + 4)]) +#define COL_MENUCONTENT_PLUS_5 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENT + 5)]) +#define COL_MENUCONTENT_PLUS_6 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENT + 6)]) +#define COL_MENUCONTENT_PLUS_7 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENT + 7)]) +#define COL_MENUCONTENTDARK_PLUS_0 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENTDARK + 0)]) +#define COL_MENUCONTENTDARK_PLUS_2 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENTDARK + 2)]) +#define COL_MENUCONTENTSELECTED_PLUS_0 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENTSELECTED + 0)]) +#define COL_MENUCONTENTSELECTED_PLUS_2 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENTSELECTED + 2)]) +#define COL_MENUCONTENTINACTIVE_PLUS_0 (CFrameBuffer::getInstance()->realcolor[(COL_MENUCONTENTINACTIVE + 0)]) +#define COL_BACKGROUND_PLUS_0 (CFrameBuffer::getInstance()->realcolor[(COL_BACKGROUND + 0)]) +#endif + + +int convertSetupColor2RGB(unsigned char r, unsigned char g, unsigned char b); +int convertSetupAlpha2Alpha(unsigned char alpha); + +void fadeColor(unsigned char &r, unsigned char &g, unsigned char &b, int fade, bool protect=true); + + +#endif diff --git a/src/gui/customcolor.h b/src/gui/customcolor.h new file mode 100644 index 000000000..47a6020cc --- /dev/null +++ b/src/gui/customcolor.h @@ -0,0 +1,57 @@ +#ifndef __custom_color__ +#define __custom_color__ + +#define COLOR_CUSTOM 0x0 +#ifdef FB_USE_PALETTE +/* +#define COL_WHITE (COLOR_CUSTOM + 0) +#define COL_RED (COLOR_CUSTOM + 1) +#define COL_GREEN (COLOR_CUSTOM + 2) +#define COL_BLUE (COLOR_CUSTOM + 3) +#define COL_YELLOW (COLOR_CUSTOM + 4) +#define COL_BLACK (COLOR_CUSTOM + 5) +*/ +#define COL_DARK_RED 0x02 +#define COL_DARK_GREEN 0x03 +#define COL_DARK_BLUE 0x05 +#define COL_LIGHT_GRAY 0x08 +#define COL_DARK_GRAY 0x09 +#define COL_RED 0x0A +#define COL_GREEN 0x0B +#define COL_YELLOW 0x0C +#define COL_BLUE 0x0D +#define COL_PURP 0x0E +#define COL_LIGHT_BLUE 0x0F +#define COL_WHITE 0x10 +#define COL_BLACK 0x11 +#else +#define COL_DARK_RED0 0x02 +#define COL_DARK_GREEN0 0x03 +#define COL_DARK_BLUE0 0x05 +#define COL_LIGHT_GRAY0 0x08 +#define COL_DARK_GRAY0 0x09 +#define COL_RED0 0x0A +#define COL_GREEN0 0x0B +#define COL_YELLOW0 0x0C +#define COL_BLUE0 0x0D +#define COL_PURP0 0x0E +#define COL_LIGHT_BLUE0 0x0F +#define COL_WHITE0 0x10 +#define COL_BLACK0 0x11 + +#define COL_DARK_RED (CFrameBuffer::getInstance()->realcolor[0x02]) +#define COL_DARK_GREEN (CFrameBuffer::getInstance()->realcolor[0x03]) +#define COL_DARK_BLUE (CFrameBuffer::getInstance()->realcolor[0x05]) +#define COL_LIGHT_GRAY (CFrameBuffer::getInstance()->realcolor[0x08]) +#define COL_DARK_GRAY (CFrameBuffer::getInstance()->realcolor[0x09]) +#define COL_RED (CFrameBuffer::getInstance()->realcolor[0x0A]) +#define COL_GREEN (CFrameBuffer::getInstance()->realcolor[0x0B]) +#define COL_YELLOW (CFrameBuffer::getInstance()->realcolor[0x0C]) +#define COL_BLUE (CFrameBuffer::getInstance()->realcolor[0x0D]) +#define COL_PURP (CFrameBuffer::getInstance()->realcolor[0x0E]) +#define COL_LIGHT_BLUE (CFrameBuffer::getInstance()->realcolor[0x0F]) +#define COL_WHITE (CFrameBuffer::getInstance()->realcolor[0x10]) +#define COL_BLACK (CFrameBuffer::getInstance()->realcolor[0x11]) +#endif + +#endif diff --git a/src/gui/dboxinfo.cpp b/src/gui/dboxinfo.cpp new file mode 100644 index 000000000..43e39fa8d --- /dev/null +++ b/src/gui/dboxinfo.cpp @@ -0,0 +1,207 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +static const int FSHIFT = 16; /* nr of bits of precision */ +#define FIXED_1 (1<> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) +#define ROUND_RADIUS 9 + +CDBoxInfoWidget::CDBoxInfoWidget() +{ + frameBuffer = CFrameBuffer::getInstance(); + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + // width = 600; + // height = hheight+13*mheight+ 10; + width = w_max (600, 0); + height = h_max (hheight+14*mheight+ 10, 0); + + + x=(((g_settings.screen_EndX- g_settings.screen_StartX)-width) / 2) + g_settings.screen_StartX; + y=(((g_settings.screen_EndY- g_settings.screen_StartY)-height) / 2) + g_settings.screen_StartY; +} + + +int CDBoxInfoWidget::exec(CMenuTarget* parent, const std::string &) +{ + if (parent) + { + parent->hide(); + } + paint(); + + int res = g_RCInput->messageLoop(); + + hide(); + return res; +} + +void CDBoxInfoWidget::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height); +} +#define FP_IOCTL_GET_LNB_CURRENT 0x100 +#define FP_IOCTL_GETID 0 +#define FP_IOCTL_UPGRADE_CTRL 0x200 + +void CDBoxInfoWidget::paint() +{ + int ypos=y; + int i = 0; + frameBuffer->paintBoxRel(x, ypos, width, hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10, ypos+ hheight+1, width, "Uptime/Mem/Fs info", COL_MENUHEAD, 0, true); // UTF-8 + frameBuffer->paintBoxRel(x, ypos+ hheight, width, height- hheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2); + + ypos+= hheight + (mheight >>1); + +#if 0 + int power = 0; + int is_val = 0xdeadbabe; + int fp_ver = 0; + + int fp = open("/dev/dbox/fp0", O_RDWR); + if(fp > 0) { + fp_ver = ioctl(fp, FP_IOCTL_GETID); + if(fp_ver < 0) fp_ver = 0; + ioctl(fp, FP_IOCTL_UPGRADE_CTRL, &is_val); + if(is_val != 1) is_val = 0; + ioctl(fp, FP_IOCTL_GET_LNB_CURRENT, &power); + close(fp); + } + else is_val = 0; +#endif + char buf[256]; + FILE* fd = fopen("/proc/cpuinfo", "rt"); + if (fd==NULL) { + printf("error while opening proc-cpuinfo\n" ); + } else { + + fgets(buf,255,fd); + while(!feof(fd)) { + if(fgets(buf,255,fd)!=NULL) { + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+ 10, ypos+ mheight, width, buf, COL_MENUCONTENT); + ypos+= mheight; + i++; + if(i > 6) break; + } + } + fclose(fd); + } + +#if 0 + sprintf(buf, "FP version 1.0%d, Upgrade Available: %s, LNB current: %d\n", fp_ver, is_val == 1 ? "yes" : "no", power); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+ 10, ypos+ mheight, width, buf, COL_MENUCONTENT); + ypos+= mheight; +#endif + + int updays, uphours, upminutes; + struct sysinfo info; + struct tm *current_time; + time_t current_secs; + char ubuf[256], sbuf[256]; + + memset(sbuf, 0, 256); + time(¤t_secs); + current_time = localtime(¤t_secs); + + sysinfo(&info); + + sprintf( ubuf, "%2d:%02d%s up ", + current_time->tm_hour%12 ? current_time->tm_hour%12 : 12, + current_time->tm_min, current_time->tm_hour > 11 ? "pm" : "am"); + strcat(sbuf, ubuf); + updays = (int) info.uptime / (60*60*24); + if (updays) { + sprintf(ubuf, "%d day%s, ", updays, (updays != 1) ? "s" : ""); + strcat(sbuf, ubuf); + } + upminutes = (int) info.uptime / 60; + uphours = (upminutes / 60) % 24; + upminutes %= 60; + if(uphours) + sprintf(ubuf,"%2d:%02d, ", uphours, upminutes); + else + sprintf(ubuf,"%d min, ", upminutes); + strcat(sbuf, ubuf); + + sprintf(ubuf, "load: %ld.%02ld, %ld.%02ld, %ld.%02ld\n", + LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]), + LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]), + LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2])); + strcat(sbuf, ubuf); + ypos+= mheight/2; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+ 10, ypos+ mheight, width, sbuf, COL_MENUCONTENT); + ypos+= mheight; + + sprintf(ubuf, "memory total %dKb, free %dKb", (int) info.totalram/1024, (int) info.freeram/1024); + ypos+= mheight/2; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+ 10, ypos+ mheight, width, ubuf, COL_MENUCONTENT); + ypos+= mheight; + + struct statfs s; + //long blocks_used; + //long blocks_percent_used; + + if (::statfs("/var", &s) == 0) { + //printf("/var filesystem total %ldKb, free %ldKb\n", (long)s.f_blocks*s.f_bsize/1024, (long)s.f_bfree*s.f_bsize/1024); + sprintf(ubuf, "/var filesystem total %ldKb, free %ldKb", (long)s.f_blocks*s.f_bsize/1024, (long)s.f_bfree*s.f_bsize/1024); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+ 10, ypos+ mheight, width, ubuf, COL_MENUCONTENT); + ypos+= mheight; + } + else + perror("/var statfs"); + if (::statfs("/hdd", &s) == 0) { +//printf("STATFS: type %lX free: %ld\n", s.f_type, s.f_bfree); + if( (s.f_type != (int) 0xEF53) && (s.f_type != (int) 0x52654973) && (s.f_type != (int) 0x6969) && (s.f_type != (int) 0xFF534D42) && (s.f_type != (int) 0x517B) && (s.f_type != (int) 0x58465342) ) + return; + //printf("/hdd filesystem total %ldKb, free %ldKb\n", (long)(s.f_blocks/1024)*s.f_bsize, (long)(s.f_bfree/1024)*s.f_bsize); + sprintf(ubuf, "/hdd filesystem total %ldKb, free %ldKb", (long)(s.f_blocks/1024)*s.f_bsize, (long)(s.f_bfree/1024)*s.f_bsize); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+ 10, ypos+ mheight, width, ubuf, COL_MENUCONTENT); + } +} diff --git a/src/gui/dboxinfo.h b/src/gui/dboxinfo.h new file mode 100644 index 000000000..4d454e01d --- /dev/null +++ b/src/gui/dboxinfo.h @@ -0,0 +1,66 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __dboxinfo__ +#define __dboxinfo__ + +#include + +#include + +#include + + +class CDBoxInfoWidget : public CMenuTarget +{ + private: + + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hheight,mheight; // head/menu font height + + void paint(); + + public: + + CDBoxInfoWidget(); + + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); + +}; + + +#endif diff --git a/src/gui/dmx_tspidbandwidth.c b/src/gui/dmx_tspidbandwidth.c new file mode 100644 index 000000000..7f6fccb7e --- /dev/null +++ b/src/gui/dmx_tspidbandwidth.c @@ -0,0 +1,235 @@ +/* + * some definition + */ +#define TS_LEN 188 +#define TS_SYNC_BYTE 0x47 +#define TS_BUF_SIZE (TS_LEN * 2048) /* fix dmx buffer size */ + +static unsigned long timeval_to_ms(const struct timeval *tv) +{ + return (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000); +} + +long delta_time_ms (struct timeval *tv, struct timeval *last_tv) +{ + return timeval_to_ms(tv) - timeval_to_ms(last_tv); +} + +int ts_pidbandwidth (OPTION *opt) +{ + + u_char buf[TS_BUF_SIZE]; + struct pollfd pfd; + struct dmx_pes_filter_params flt; + int dmxfd; + struct timeval tv,last_tv, first_tv; + int pid; + unsigned long long b_total; + long b; + long packets_bad; + long packets_total; + struct { // simple struct for storing last average bandwidth + unsigned long kb_sec; + unsigned long b_sec; + } last_avg; + + + + + if (opt->ts_raw_mode) { + pid = PID_FULL_TS; + } else { + pid = opt->pid; + } + + + + indent (0); + out_nl (2,""); + out_nl (2,"---------------------------------------------------------"); + out_nl (2,"PID bandwidth statistics..."); + if (opt->ts_raw_mode) { + out (2,"Full Transponder"); + } else { + out (2,"PID: %u (0x%04x)", pid, pid); + } + if (opt->rd_packet_count != 0) { + out (2," - max packet count: %ld ", opt->rd_packet_count); + } + out_nl (2,""); + out_nl (2,"---------------------------------------------------------"); + + + + // -- open DVR device for reading + pfd.events = POLLIN | POLLPRI; + if((pfd.fd = open(opt->devDvr,O_RDONLY|O_NONBLOCK)) < 0){ + IO_error(opt->devDvr); + return -1; + } + + + + if ((dmxfd=open(opt->devDemux,O_RDWR)) < 0) { + IO_error(opt->devDemux); + close(pfd.fd); + return -1; + } + ioctl (dmxfd,DMX_SET_BUFFER_SIZE, sizeof(buf)); + + flt.pid = pid; + flt.input = DMX_IN_FRONTEND; + flt.output = DMX_OUT_TS_TAP; + flt.pes_type = DMX_PES_OTHER; + flt.flags = DMX_IMMEDIATE_START; + if (ioctl(dmxfd, DMX_SET_PES_FILTER, &flt) < 0) { + IO_error("DMX_SET_PES_FILTER"); + close(pfd.fd); + close(dmxfd); + return -1; + } + + + + gettimeofday (&first_tv, NULL); + last_tv.tv_sec = first_tv.tv_sec; + last_tv.tv_usec = first_tv.tv_usec; + + b_total = 0; + packets_total = 0; + packets_bad = 0; + + while ( !isSigAbort() ) { + int b_len, b_start; + + // -- we will poll the PID in 2 secs intervall + int timeout = 2000; + + b_len = 0; + b_start = 0; + if (poll(&pfd, 1, timeout) > 0) { + if (pfd.revents & POLLIN) { + + b_len = read(pfd.fd, buf, sizeof(buf)); + gettimeofday (&tv, NULL); + + + if (b_len >= TS_LEN) { + b_start = sync_ts (buf, b_len); + } else { + b_len = 0; + } + + b = b_len - b_start; + if (b == 0) continue; + if (b < 0) { + IO_error("read"); + continue; + } + + b_total += b; + + + + // -- calc bandwidth + + { + unsigned long long bit_s; + long d_tim_ms; + int packets; + + packets = b/TS_LEN; + packets_total += packets; + + + // output on different verbosity levels + // -- current bandwidth + d_tim_ms = delta_time_ms (&tv, &last_tv); + if (d_tim_ms <= 0) d_tim_ms = 1; // ignore usecs + + out (3, "packets read: %3d/(%ld) d_time: %2ld.%03ld s = ", + packets, packets_total, d_tim_ms / 1000UL, d_tim_ms % 1000UL); + + // -- current bandwidth in kbit/sec + // --- cast to unsigned long long so it doesn't overflow as + // --- early, add time / 2 before division for correct rounding + bit_s = (((unsigned long long)b * 8000ULL) + ((unsigned long long)d_tim_ms / 2ULL)) + / (unsigned long long)d_tim_ms; + + out (1, "%5llu.%03llu kbit/s", bit_s / 1000ULL, bit_s % 1000ULL); + + + // -- average bandwidth + d_tim_ms = delta_time_ms (&tv,&first_tv); + if (d_tim_ms <= 0) d_tim_ms = 1; // ignore usecs + + bit_s = ((b_total * 8000ULL) + ((unsigned long long)d_tim_ms / 2ULL)) + / (unsigned long long)d_tim_ms; + + last_avg.kb_sec = (unsigned long) (bit_s / 1000ULL); + last_avg.b_sec = (unsigned long) (bit_s % 1000ULL); + + out (2, " (Avrg: %5lu.%03lu kbit/s)", last_avg.kb_sec, last_avg.b_sec); + + + // -- bad packet(s) check in buffer + { + int bp; + + bp = ts_error_count (buf+b_start, b); + packets_bad += bp; + out (4, " [bad: %d]", bp); + } + + out_NL (1); + + } + + + last_tv.tv_sec = tv.tv_sec; + last_tv.tv_usec = tv.tv_usec; + + + + // count packets ? + if (opt->rd_packet_count > 0) { + opt->rd_packet_count -= b/TS_LEN; + if (opt->rd_packet_count <= 0) break; + } + + + } + } + + } + + + // -- packets stats + + out (4, "## "); + + if (opt->ts_raw_mode) { out (2,"PID: "); + } else { out (2,"PID: %u (0x%04x)", pid, pid); + } + + out (4, " bad/total packets: %ld/%ld (= %1.1Lf%%)", + packets_bad, packets_total, + (((long double) packets_bad)*100)/packets_total ); + out (4, " Avrg: %5lu.%03lu kbit/s", + last_avg.kb_sec, last_avg.b_sec); + out_NL(4); + + + + + if (ioctl(dmxfd, DMX_STOP) < 0) { + IO_error("DMX_STOP"); + } + close(dmxfd); + close(pfd.fd); + + + return 0; + +} + diff --git a/src/gui/epg_menu.cpp b/src/gui/epg_menu.cpp new file mode 100644 index 000000000..fc01605f7 --- /dev/null +++ b/src/gui/epg_menu.cpp @@ -0,0 +1,80 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include +#include +#include +#include + +// +// -- EPG Menue Handler Class +// -- to be used for calls from Menue +// -- (2004-03-06 rasc) +// + +int CEPGMenuHandler::exec(CMenuTarget* parent, const std::string &actionkey) +{ + int res = menu_return::RETURN_EXIT_ALL; + + + if (parent) { + parent->hide(); + } + + doMenu (); + return res; +} + +int CEPGMenuHandler::doMenu () +{ + CMenuWidget EPGSelector(LOCALE_EPGMENU_HEAD, "features.raw", 350); + + // EPGSelector.addItem(GenericMenuSeparator); + EPGSelector.addItem(new CMenuForwarder(LOCALE_EPGMENU_EVENTLIST , true, NULL, new CEventListHandler(), NULL, CRCInput::RC_red , NEUTRINO_ICON_BUTTON_RED ), false); + EPGSelector.addItem(new CMenuForwarder(LOCALE_EPGMENU_EPGPLUS , true, NULL, new CEPGplusHandler() , NULL, CRCInput::RC_green , NEUTRINO_ICON_BUTTON_GREEN ), false); + EPGSelector.addItem(new CMenuForwarder(LOCALE_EPGMENU_EVENTINFO , true, NULL, new CEPGDataHandler() , NULL, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW), false); + EPGSelector.addItem(new CMenuForwarder(LOCALE_EPGMENU_STREAMINFO, true, NULL, new CStreamInfo2() , NULL, CRCInput::RC_blue , NEUTRINO_ICON_BUTTON_BLUE ), false); + + EPGSelector.addItem(GenericMenuSeparator); + + return EPGSelector.exec(NULL, ""); +} + diff --git a/src/gui/epg_menu.h b/src/gui/epg_menu.h new file mode 100644 index 000000000..8c9a98add --- /dev/null +++ b/src/gui/epg_menu.h @@ -0,0 +1,43 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __epg_menu__ +#define __epg_menu__ + + +#include "widget/menue.h" + + + +using namespace std; + +class CEPGMenuHandler : public CMenuTarget +{ + public: + int exec( CMenuTarget* parent, const std::string &actionkey); + int doMenu(); + +}; + + +#endif + diff --git a/src/gui/epgplus.cpp b/src/gui/epgplus.cpp new file mode 100644 index 000000000..ae298cd59 --- /dev/null +++ b/src/gui/epgplus.cpp @@ -0,0 +1,1309 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Copyright (C) 2004 Martin Griep 'vivamiga' + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include "bouquetlist.h" + +#include +#include +#include + +#include +#include + +#define COL_MENUCONTENT_P1 254-8*4+1 +#define COL_MENUCONTENT_P2 254-8*4+2 +extern CBouquetList *bouquetList; + +Font * fonts[EpgPlus::NumberOfFontSettings]; +int sizes[EpgPlus::NumberOfSizeSettings]; + +time_t EpgPlus::duration = 0; + +int EpgPlus::horGap1Height = 0; +int EpgPlus::horGap2Height = 0; +int EpgPlus::verGap1Width = 0; +int EpgPlus::verGap2Width = 0; + +int EpgPlus::horGap1Color = 0; +int EpgPlus::horGap2Color = 0; +int EpgPlus::verGap1Color = 0; +int EpgPlus::verGap2Color = 0; + +int EpgPlus::sliderWidth = 0; +int EpgPlus::channelsTableWidth = 0; + +static EpgPlus::FontSetting fontSettingTable[] = { + {EpgPlus::EPGPlus_header_font, (char *) "Bold", 20}, + {EpgPlus::EPGPlus_timeline_fonttime, (char *) "Bold", 16}, + {EpgPlus::EPGPlus_timeline_fontdate, (char *) "Bold", 14}, + {EpgPlus::EPGPlus_channelentry_font, (char *) "Bold", 16}, + {EpgPlus::EPGPlus_channelevententry_font, (char *) "Regular", 16}, + {EpgPlus::EPGPlus_footer_fontbouquetchannelname, (char *) "Bold", 24}, + {EpgPlus::EPGPlus_footer_fonteventdescription, (char *) "Regular", 16}, + {EpgPlus::EPGPlus_footer_fonteventshortdescription, (char *) "Regular", 16}, + {EpgPlus::EPGPlus_footer_fontbuttons, (char *) "Regular", 16}, +}; + +static EpgPlus::SizeSetting sizeSettingTable[] = { + {EpgPlus::EPGPlus_channelentry_width, 100}, + {EpgPlus::EPGPlus_channelentry_separationlineheight, 2}, + {EpgPlus::EPGPlus_slider_width, 15}, + {EpgPlus::EPGPlus_horgap1_height, 4}, + {EpgPlus::EPGPlus_horgap2_height, 4}, + {EpgPlus::EPGPlus_vergap1_width, 4}, + {EpgPlus::EPGPlus_vergap2_width, 4}, +}; + +Font *EpgPlus::Header::font = NULL; + +EpgPlus::Header::Header (CFrameBuffer * frameBuffer, int x, int y, int width) +{ + this->frameBuffer = frameBuffer; + this->x = x; + this->y = y; + this->width = width; +} + +EpgPlus::Header::~Header () +{ +} + +void EpgPlus::Header::init () +{ + font = fonts[EPGPlus_header_font]; +} + +void EpgPlus::Header::paint () +{ + this->frameBuffer->paintBoxRel (this->x, this->y, this->width, this->font->getHeight (), COL_MENUHEAD_PLUS_0); + this->font->RenderString (this->x + 10, this->y + this->font->getHeight () + , this->width - 20, g_Locale->getText (LOCALE_EPGPLUS_HEAD) , COL_MENUHEAD, 0, true); +} + +int EpgPlus::Header::getUsedHeight () +{ + return font->getHeight (); +} + +Font *EpgPlus::TimeLine::fontTime = NULL; +Font *EpgPlus::TimeLine::fontDate = NULL; + +EpgPlus::TimeLine::TimeLine (CFrameBuffer * frameBuffer, int x, int y, int width, int startX, int durationX) +{ + this->frameBuffer = frameBuffer; + this->x = x; + this->y = y; + this->width = width; + this->startX = startX; + this->durationX = durationX; +} + +void EpgPlus::TimeLine::init () +{ + fontTime = fonts[EPGPlus_timeline_fonttime]; + fontDate = fonts[EPGPlus_timeline_fontdate]; +} + +EpgPlus::TimeLine::~TimeLine () +{ +} + +void EpgPlus::TimeLine::paint (time_t startTime, int duration) +{ + this->clearMark (); + + int xPos = this->startX; + + this->currentDuration = duration; + int numberOfTicks = this->currentDuration / (60 * 60) * 2; + int tickDist = (this->durationX) / numberOfTicks; + time_t tickTime = startTime; + bool toggleColor = false; + + // display date of begin + this->frameBuffer->paintBoxRel (this->x, this->y, this->width, this->fontTime->getHeight () + , toggleColor ? COL_MENUCONTENT_PLUS_2 : COL_MENUCONTENT_PLUS_1); + + this->fontDate->RenderString (this->x + 4, this->y + this->fontDate->getHeight () + , this->width, EpgPlus::getTimeString (startTime, "%d-%b") , COL_MENUCONTENT, 0, true); // UTF-8 + + // paint ticks + for (int i = 0; i < numberOfTicks; ++i, xPos += tickDist, tickTime += duration / numberOfTicks) { + int xWidth = tickDist; + if (xPos + xWidth > this->x + width) + xWidth = this->x + width - xPos; + + this->frameBuffer->paintBoxRel (xPos, this->y, xWidth, this->fontTime->getHeight () + , toggleColor ? COL_MENUCONTENT_PLUS_1 : COL_MENUCONTENT_PLUS_2); + + std::string timeStr = EpgPlus::getTimeString (tickTime, "%H"); + + int textWidth = this->fontTime->getRenderWidth (timeStr, true); + + this->fontTime->RenderString (xPos - textWidth - 4, this->y + this->fontTime->getHeight () + , textWidth, timeStr, toggleColor ? COL_MENUCONTENT_P1 : COL_MENUCONTENT_P2, 0, true); // UTF-8 + + timeStr = EpgPlus::getTimeString (tickTime, "%M"); + textWidth = this->fontTime->getRenderWidth (timeStr, true); + this->fontTime->RenderString (xPos + 4, this->y + this->fontTime->getHeight () + , textWidth, timeStr, toggleColor ? COL_MENUCONTENT_P1 : COL_MENUCONTENT_P2, 0, true); // UTF-8 + + toggleColor = !toggleColor; + } +} + +void EpgPlus::TimeLine::paintGrid () +{ + int xPos = this->startX; + int numberOfTicks = this->currentDuration / (60 * 60) * 2; + int tickDist = (this->durationX) / numberOfTicks; + // paint ticks + for (int i = 0; i < numberOfTicks; ++i, xPos += tickDist) { + // display a line for the tick + this->frameBuffer->paintVLineRel (xPos, this->y, this->fontTime->getHeight (), COL_MENUCONTENT_PLUS_5); + } +} + +void EpgPlus::TimeLine::paintMark (time_t startTime, int duration, int x, int width) +{ + // clear old mark + this->clearMark (); + + // paint new mark + this->frameBuffer->paintBoxRel (x, this->y + this->fontTime->getHeight () + , width, this->fontTime->getHeight () , COL_MENUCONTENTSELECTED_PLUS_0); + + // display start time before mark + std::string timeStr = EpgPlus::getTimeString (startTime, "%H:%M"); + int textWidth = this->fontTime->getRenderWidth (timeStr, true); + + this->fontTime->RenderString (x - textWidth, this->y + this->fontTime->getHeight () + this->fontTime->getHeight () + , textWidth, timeStr, COL_MENUCONTENT, 0, true); // UTF-8 + + // display end time after mark + timeStr = EpgPlus::getTimeString (startTime + duration, "%H:%M"); + textWidth = fontTime->getRenderWidth (timeStr, true); + + if (x + width + textWidth < this->x + this->width) { + this->fontTime->RenderString (x + width, this->y + this->fontTime->getHeight () + this->fontTime->getHeight () + , textWidth, timeStr, COL_MENUCONTENT, 0, true); // UTF-8 + } else if (textWidth < width - 10) { + this->fontTime->RenderString (x + width - textWidth, this->y + this->fontTime->getHeight () + this->fontTime->getHeight () + , textWidth, timeStr, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + } +} + +void EpgPlus::TimeLine::clearMark () +{ + this->frameBuffer->paintBoxRel (this->x, this->y + this->fontTime->getHeight () + , this->width, this->fontTime->getHeight () , COL_MENUCONTENT_PLUS_0); +} + +int EpgPlus::TimeLine::getUsedHeight () +{ + return std::max (fontDate->getHeight (), fontTime->getHeight ()) + + fontTime->getHeight (); +} + +Font *EpgPlus::ChannelEventEntry::font = NULL; +int EpgPlus::ChannelEventEntry::separationLineHeight = 0; + +EpgPlus::ChannelEventEntry::ChannelEventEntry (const CChannelEvent * channelEvent, CFrameBuffer * frameBuffer, TimeLine * timeLine, Footer * footer, int x, int y, int width) +{ + // copy neccessary? + if (channelEvent != NULL) + this->channelEvent = *channelEvent; + + this->frameBuffer = frameBuffer; + this->timeLine = timeLine; + this->footer = footer; + this->x = x; + this->y = y; + this->width = width; +} + +void EpgPlus::ChannelEventEntry::init () +{ + font = fonts[EPGPlus_channelevententry_font]; + separationLineHeight = sizes[EPGPlus_channelentry_separationlineheight]; +} + +EpgPlus::ChannelEventEntry::~ChannelEventEntry () +{ +} + +bool EpgPlus::ChannelEventEntry::isSelected (time_t selectedTime) const +{ + return (selectedTime >= this->channelEvent.startTime) && (selectedTime < this->channelEvent.startTime + time_t (this->channelEvent.duration)); +} + +bool sectionsd_getEPGidShort(event_id_t epgID, CShortEPGData * epgdata); +void EpgPlus::ChannelEventEntry::paint (bool isSelected, bool toggleColor) +{ + this->frameBuffer->paintBoxRel (this->x, this->y, this->width, this->font->getHeight () + , this->channelEvent.description.empty ()? COL_MENUCONTENT_PLUS_0 : (isSelected ? COL_MENUCONTENTSELECTED_PLUS_0 : (toggleColor ? COL_MENUCONTENT_PLUS_1 : COL_MENUCONTENT_PLUS_2))); + + this->font->RenderString (this->x + 2, this->y + this->font->getHeight () + , this->width - 4 > 0 ? this->width - 4 : 0, this->channelEvent.description, isSelected ? COL_MENUCONTENTSELECTED : (toggleColor ? COL_MENUCONTENT_P1 : COL_MENUCONTENT_P2) + , 0, true); + + // paint the separation line + if (separationLineHeight > 0) { + this->frameBuffer->paintBoxRel (this->x, this->y + this->font->getHeight () + , this->width, this->separationLineHeight, COL_MENUCONTENT_PLUS_5); + } + + if (isSelected) { + if (this->channelEvent.description.empty ()) { // dummy channel event + this->timeLine->clearMark (); + } else { + this->timeLine->paintMark (this->channelEvent.startTime, this->channelEvent.duration, this->x, this->width); + } + + CShortEPGData shortEpgData; + + //this->footer->paintEventDetails (this->channelEvent.description, g_Sectionsd->getEPGidShort (this->channelEvent.eventID, &shortEpgData) ? shortEpgData.info1 : ""); + this->footer->paintEventDetails (this->channelEvent.description, sectionsd_getEPGidShort(this->channelEvent.eventID, &shortEpgData) ? shortEpgData.info1 : ""); + + this->timeLine->paintGrid (); + } +} + +int EpgPlus::ChannelEventEntry::getUsedHeight () +{ + return font->getHeight () + separationLineHeight; +} + +Font *EpgPlus::ChannelEntry::font = NULL; +int EpgPlus::ChannelEntry::separationLineHeight = 0; + +EpgPlus::ChannelEntry::ChannelEntry (const CZapitChannel * channel, int index, CFrameBuffer * frameBuffer, Footer * footer, CBouquetList * bouquetList, int x, int y, int width) +{ + this->channel = channel; + + if (channel != NULL) { + std::stringstream displayName; + displayName << index + 1 << " " << channel->getName (); + + this->displayName = displayName.str (); + } + + this->index = index; + + this->frameBuffer = frameBuffer; + this->footer = footer; + this->bouquetList = bouquetList; + + this->x = x; + this->y = y; + this->width = width; +} + +void EpgPlus::ChannelEntry::init () +{ + font = fonts[EPGPlus_channelentry_font]; + separationLineHeight = sizes[EPGPlus_channelentry_separationlineheight]; +} + +EpgPlus::ChannelEntry::~ChannelEntry () +{ + for (TCChannelEventEntries::iterator It = this->channelEventEntries.begin (); + It != this->channelEventEntries.end (); It++) { + delete *It; + } + this->channelEventEntries.clear(); +} + +void EpgPlus::ChannelEntry::paint (bool isSelected, time_t selectedTime) +{ + this->frameBuffer->paintBoxRel (this->x, this->y, this->width, this->font->getHeight () + , isSelected ? COL_MENUCONTENTSELECTED_PLUS_0 : COL_MENUCONTENT_PLUS_0); + + this->font->RenderString (this->x + 2, this->y + this->font->getHeight () + , this->width - 4, this->displayName, isSelected ? COL_MENUCONTENTSELECTED : COL_MENUCONTENT, 0, true); + + if (isSelected) { + for (uint32_t i = 0; i < this->bouquetList->Bouquets.size (); + ++i) { + CBouquet *bouquet = this->bouquetList->Bouquets[i]; + for (int j = 0; j < bouquet->channelList->getSize (); + ++j) { + + if ((*bouquet->channelList)[j]->number == this->channel->number) { + this->footer->setBouquetChannelName (bouquet->channelList->getName () + , this->channel->getName () + ); + + bouquet = NULL; + + break; + } + } + if (bouquet == NULL) + break; + } + } + // paint the separation line + if (separationLineHeight > 0) { + this->frameBuffer->paintBoxRel (this->x, this->y + this->font->getHeight () + , this->width, this->separationLineHeight, COL_MENUCONTENT_PLUS_5); + } + + bool toggleColor = false; + for (TCChannelEventEntries::iterator It = this->channelEventEntries.begin (); + It != this->channelEventEntries.end (); + ++It) { + (*It)->paint (isSelected && (*It)->isSelected (selectedTime), toggleColor); + + toggleColor = !toggleColor; + } +} + +int EpgPlus::ChannelEntry::getUsedHeight () +{ + return font->getHeight () + + separationLineHeight; +} + +Font *EpgPlus::Footer::fontBouquetChannelName = NULL; +Font *EpgPlus::Footer::fontEventDescription = NULL; +Font *EpgPlus::Footer::fontEventShortDescription = NULL; +Font *EpgPlus::Footer::fontButtons = NULL; +int EpgPlus::Footer::color = 0; + +EpgPlus::Footer::Footer (CFrameBuffer * frameBuffer, int x, int y, int width) +{ + this->frameBuffer = frameBuffer; + this->x = x; + this->y = y; + this->width = width; +} + +EpgPlus::Footer::~Footer () +{ +} + +void EpgPlus::Footer::init () +{ + fontBouquetChannelName = fonts[EPGPlus_footer_fontbouquetchannelname]; + fontEventDescription = fonts[EPGPlus_footer_fonteventdescription]; + fontEventShortDescription = fonts[EPGPlus_footer_fonteventshortdescription]; + fontButtons = fonts[EPGPlus_footer_fontbuttons]; +} + +void EpgPlus::Footer::setBouquetChannelName (const std::string & newBouquetName, const std::string & newChannelName) +{ + this->currentBouquetName = newBouquetName; + this->currentChannelName = newChannelName; +} + +int EpgPlus::Footer::getUsedHeight () +{ + return fontBouquetChannelName->getHeight () + fontEventDescription->getHeight () + + fontEventShortDescription->getHeight () + fontButtons->getHeight (); +} + +void EpgPlus::Footer::paintEventDetails (const std::string & description, const std::string & shortDescription) +{ + int yPos = this->y; + + int height = this->fontBouquetChannelName->getHeight (); + + // clear the region + this->frameBuffer->paintBoxRel (this->x, yPos, this->width, height, COL_MENUHEAD_PLUS_0); + + yPos += height; + + // display new text + this->fontBouquetChannelName->RenderString (this->x + 10, yPos, this->width - 20, this->currentBouquetName + " : " + this->currentChannelName, COL_MENUHEAD, 0, true); + + height = this->fontEventDescription->getHeight (); + + // clear the region + this->frameBuffer->paintBoxRel (this->x, yPos, this->width, height, COL_MENUHEAD_PLUS_0); + + yPos += height; + + // display new text + this->fontEventDescription->RenderString (this->x + 10, yPos, this->width - 20, description, COL_MENUHEAD, 0, true); + + height = this->fontEventShortDescription->getHeight (); + + // clear the region + this->frameBuffer->paintBoxRel (this->x, yPos, this->width, height, COL_MENUHEAD_PLUS_0); + + yPos += height; + + // display new text + this->fontEventShortDescription->RenderString (this->x + 10, yPos, this->width - 20, shortDescription, COL_MENUHEAD, 0, true); +} + +struct button_label buttonLabels[] = { + {NEUTRINO_ICON_BUTTON_RED, LOCALE_EPGPLUS_ACTIONS}, + {NEUTRINO_ICON_BUTTON_GREEN, LOCALE_EPGPLUS_PAGE_UP}, + {NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_EPGPLUS_PAGE_DOWN}, + {NEUTRINO_ICON_BUTTON_BLUE, LOCALE_EPGPLUS_OPTIONS} +}; + +void EpgPlus::Footer::paintButtons (button_label * buttonLabels, int numberOfButtons) +{ + int yPos = this->y + this->getUsedHeight () - this->fontButtons->getHeight (); + + int buttonWidth = (this->width - 20) / 4; + + int buttonHeight = 7 + std::min (16, this->fontButtons->getHeight ()); + + this->frameBuffer->paintBoxRel (this->x, yPos, this->width, this->fontButtons->getHeight (), COL_MENUHEAD_PLUS_0); + + ::paintButtons (this->frameBuffer, this->fontButtons, g_Locale, this->x + 10, yPos + this->fontButtons->getHeight () - buttonHeight + 3, buttonWidth, numberOfButtons, buttonLabels); + + this->frameBuffer->paintIcon (NEUTRINO_ICON_BUTTON_HELP, this->x + this->width - 30, yPos - this->fontButtons->getHeight ()); +} + +EpgPlus::EpgPlus () +{ + this->init (); +} + +EpgPlus::~EpgPlus () +{ + this->free (); +} + +void sectionsd_getEventsServiceKey(t_channel_id serviceUniqueKey, CChannelEventList &eList, char search = 0, std::string search_text = ""); + +void EpgPlus::createChannelEntries (int selectedChannelEntryIndex) +{ + for (TChannelEntries::iterator It = this->displayedChannelEntries.begin (); + It != this->displayedChannelEntries.end (); It++) { + delete *It; + } + this->displayedChannelEntries.clear (); + + this->selectedChannelEntry = NULL; + + if (selectedChannelEntryIndex < this->channelList->getSize ()) { + for (;;) { + if (selectedChannelEntryIndex < this->channelListStartIndex) { + this->channelListStartIndex -= this->maxNumberOfDisplayableEntries; + if (this->channelListStartIndex < 0) + this->channelListStartIndex = 0; + } else if (selectedChannelEntryIndex >= this->channelListStartIndex + this->maxNumberOfDisplayableEntries) { + this->channelListStartIndex += this->maxNumberOfDisplayableEntries; + } else + break; + } + + int yPosChannelEntry = this->channelsTableY; + int yPosEventEntry = this->eventsTableY; + + for (int i = this->channelListStartIndex; (i < this->channelListStartIndex + this->maxNumberOfDisplayableEntries) + && (i < this->channelList->getSize ()); + ++i, yPosChannelEntry += this->entryHeight, yPosEventEntry += this->entryHeight) { + + CZapitChannel * channel = (*this->channelList)[i]; + + ChannelEntry *channelEntry = new ChannelEntry (channel, i, this->frameBuffer, this->footer, this->bouquetList, this->channelsTableX + 2, yPosChannelEntry, this->channelsTableWidth); +//printf("Going to get getEventsServiceKey for %llx\n", (channel->channel_id & 0xFFFFFFFFFFFFULL)); + //CChannelEventList channelEventList = g_Sectionsd->getEventsServiceKey (channel->channel->channel_id & 0xFFFFFFFFFFFFULL); + CChannelEventList channelEventList; + sectionsd_getEventsServiceKey(channel->channel_id & 0xFFFFFFFFFFFFULL, channelEventList); +//printf("channelEventList size %d\n", channelEventList.size()); + + int xPosEventEntry = this->eventsTableX; + int widthEventEntry = 0; + time_t lastEndTime = this->startTime; + + CChannelEventList::const_iterator lastIt (channelEventList.end ()); + //for (CChannelEventList::const_iterator It = channelEventList.begin (); (It != channelEventList.end ()) && (It->startTime < (this->startTime + this->duration)); ++It) + for (CChannelEventList::const_iterator It = channelEventList.begin (); It != channelEventList.end (); ++It) + { +//if(0x2bc000b004b7ULL == (channel->channel_id & 0xFFFFFFFFFFFFULL)) printf("*** Check1 event %s event start %ld this start %ld\n", It->description.c_str(), It->startTime, (this->startTime + this->duration)); + if(!(It->startTime < (this->startTime + this->duration)) ) + continue; + if ((lastIt == channelEventList.end ()) || (lastIt->startTime != It->startTime)) { + int startTimeDiff = It->startTime - this->startTime; + int endTimeDiff = this->startTime + time_t (this->duration) - It->startTime - time_t (It->duration); +//if(0x2bc000b004b7ULL == (channel->channel_id & 0xFFFFFFFFFFFFULL)) printf("*** Check event %s\n", It->description.c_str()); + if ((startTimeDiff >= 0) && (endTimeDiff >= 0)) { + // channel event fits completely in the visible part of time line + startTimeDiff = 0; + endTimeDiff = 0; + } else if ((startTimeDiff < 0) && (endTimeDiff < 0)) { + // channel event starts and ends outside visible part of the time line but covers complete visible part + } else if ((startTimeDiff < 0) && (endTimeDiff < this->duration)) { + // channel event starts before visible part of the time line but ends in the visible part + endTimeDiff = 0; + } else if ((endTimeDiff < 0) && (startTimeDiff < this->duration)) { + // channel event ends after visible part of the time line but starts in the visible part + startTimeDiff = 0; + } else if (startTimeDiff > 0) { // channel event starts and ends after visible part of the time line => break the loop +//if(0x2bc000b004b7ULL == (channel->channel_id & 0xFFFFFFFFFFFFULL)) printf("*** break 1\n"); + break; + } else { // channel event starts and ends after visible part of the time line => ignore the channel event +//if(0x2bc000b004b7ULL == (channel->channel_id & 0xFFFFFFFFFFFFULL)) printf("*** continue 1 startTimeDiff %ld endTimeDiff %ld\n", startTimeDiff, endTimeDiff); + continue; + } + + if (lastEndTime < It->startTime) { // there is a gap between last end time and new start time => fill it with a new event entry + + CChannelEvent channelEvent; + channelEvent.startTime = lastEndTime; + channelEvent.duration = It->startTime - channelEvent.startTime; + + ChannelEventEntry *channelEventEntry = new ChannelEventEntry (&channelEvent, this->frameBuffer, this->timeLine, this->footer, this->eventsTableX + ((channelEvent.startTime - this->startTime) * this->eventsTableWidth) / this->duration, yPosEventEntry, (channelEvent.duration * this->eventsTableWidth) / this->duration + 1); + channelEntry->channelEventEntries.push_back (channelEventEntry); + } + // correct position + xPosEventEntry = this->eventsTableX + ((It->startTime - startTimeDiff - this->startTime) * this->eventsTableWidth) / this->duration; + + // correct width + widthEventEntry = ((It->duration + startTimeDiff + endTimeDiff) * this->eventsTableWidth) / this->duration + 1; + + if (widthEventEntry < 0) + widthEventEntry = 0; + + if (xPosEventEntry + widthEventEntry > this->eventsTableX + this->eventsTableWidth) + widthEventEntry = this->eventsTableX + this->eventsTableWidth - xPosEventEntry; + + ChannelEventEntry *channelEventEntry = new ChannelEventEntry (&(*It) , this->frameBuffer, this->timeLine, this->footer, xPosEventEntry, yPosEventEntry, widthEventEntry); + + channelEntry->channelEventEntries.push_back (channelEventEntry); + lastEndTime = It->startTime + It->duration; + } + lastIt = It; + } + + if (lastEndTime < this->startTime + time_t (this->duration)) { // there is a gap between last end time and end of the timeline => fill it with a new event entry + + CChannelEvent channelEvent; + channelEvent.startTime = lastEndTime; + channelEvent.duration = this->startTime + this->duration - channelEvent.startTime; + + ChannelEventEntry *channelEventEntry = new ChannelEventEntry (&channelEvent, this->frameBuffer, this->timeLine, this->footer, this->eventsTableX + ((channelEvent.startTime - this->startTime) * this->eventsTableWidth) / this->duration, yPosEventEntry, (channelEvent.duration * this->eventsTableWidth) / this->duration + 1); + channelEntry->channelEventEntries.push_back (channelEventEntry); + } + this->displayedChannelEntries.push_back (channelEntry); + } + + this->selectedChannelEntry = this->displayedChannelEntries[selectedChannelEntryIndex - this->channelListStartIndex]; + } +} + +void EpgPlus::init () +{ + frameBuffer = CFrameBuffer::getInstance (); + currentViewMode = ViewMode_Scroll; + currentSwapMode = SwapMode_ByPage; + usableScreenWidth = w_max (g_settings.screen_EndX, 4); + usableScreenHeight = h_max (g_settings.screen_EndY, 4); + + std::string FileName = std::string (g_settings.font_file); + for (size_t i = 0; i < NumberOfFontSettings; ++i) { + std::string family = g_fontRenderer->getFamily (FileName.c_str ()); + Font *font = g_fontRenderer->getFont (family.c_str (), fontSettingTable[i].style, fontSettingTable[i].size); + + if (font == NULL) + font = g_fontRenderer->getFont (family.c_str (), "Regular", fontSettingTable[i].size); + + fonts[i] = font; + } + + for (size_t i = 0; i < NumberOfSizeSettings; ++i) { + sizes[i] = sizeSettingTable[i].size; + } + + Header::init (); + TimeLine::init (); + ChannelEntry::init (); + ChannelEventEntry::init (); + Footer::init (); + + this->selectedChannelEntry = NULL; + + channelsTableWidth = sizes[EPGPlus_channelentry_width]; + sliderWidth = sizes[EPGPlus_slider_width]; + + horGap1Height = sizes[EPGPlus_horgap1_height]; + horGap2Height = sizes[EPGPlus_horgap2_height]; + verGap1Width = sizes[EPGPlus_vergap1_width]; + verGap2Width = sizes[EPGPlus_vergap2_width]; + + int headerHeight = Header::getUsedHeight (); + int timeLineHeight = TimeLine::getUsedHeight (); + this->entryHeight = ChannelEntry::getUsedHeight (); + int footerHeight = Footer::getUsedHeight (); + + this->maxNumberOfDisplayableEntries = (this->usableScreenHeight - headerHeight - timeLineHeight - horGap1Height - horGap2Height - footerHeight) / this->entryHeight; + + this->usableScreenHeight = headerHeight + timeLineHeight + horGap1Height + this->maxNumberOfDisplayableEntries * this->entryHeight + horGap2Height + footerHeight; // recalc deltaY + this->usableScreenX = (((g_settings.screen_EndX - g_settings.screen_StartX) - this->usableScreenWidth) / 2) + g_settings.screen_StartX; + this->usableScreenY = (((g_settings.screen_EndY - g_settings.screen_StartY) - this->usableScreenHeight) / 2) + g_settings.screen_StartY; + + this->headerX = this->usableScreenX; + this->headerY = this->usableScreenY; + this->headerWidth = this->usableScreenWidth; + + this->timeLineX = this->usableScreenX; + this->timeLineY = this->usableScreenY + headerHeight; + this->timeLineWidth = this->usableScreenWidth; + + this->horGap1X = this->usableScreenX; + this->horGap1Y = this->timeLineY + timeLineHeight; + this->horGap1Width = this->usableScreenWidth; + + this->footerX = usableScreenX; + this->footerY = this->usableScreenY + this->usableScreenHeight - footerHeight; + this->footerWidth = this->usableScreenWidth; + + this->horGap2X = this->usableScreenX; + this->horGap2Y = this->footerY - horGap2Height; + this->horGap2Width = this->usableScreenWidth; + + this->channelsTableX = this->usableScreenX; + this->channelsTableY = this->timeLineY + timeLineHeight + horGap1Height; + this->channelsTableHeight = this->maxNumberOfDisplayableEntries * entryHeight; + + this->verGap1X = this->channelsTableX + channelsTableWidth; + this->verGap1Y = this->channelsTableY; + this->verGap1Height = this->channelsTableHeight; + + this->eventsTableX = this->channelsTableX + channelsTableWidth + verGap1Width; + this->eventsTableY = this->channelsTableY; + this->eventsTableWidth = this->usableScreenWidth - this->channelsTableWidth - this->sliderWidth - verGap1Width - verGap2Width; + this->eventsTableHeight = this->channelsTableHeight; + + this->sliderX = this->usableScreenX + this->usableScreenWidth - this->sliderWidth; + this->sliderY = this->eventsTableY; + this->sliderHeight = this->channelsTableHeight; + + this->verGap2X = this->sliderX - verGap2Width; + this->verGap2Y = this->channelsTableY; + this->verGap2Height = this->channelsTableHeight; + + this->channelListStartIndex = 0; + this->startTime = 0; + this->duration = 2 * 60 * 60; + + this->refreshAll = false; + this->currentViewMode = ViewMode_Scroll; + this->currentSwapMode = SwapMode_ByPage; + + this->header = new Header (this->frameBuffer, this->headerX, this->headerY, this->headerWidth); + + this->timeLine = new TimeLine (this->frameBuffer, this->timeLineX, this->timeLineY, this->timeLineWidth, this->eventsTableX, this->eventsTableWidth); + + this->footer = new Footer (this->frameBuffer, this->footerX, this->footerY, this->footerWidth); +} + +void EpgPlus::free () +{ + delete this->header; + delete this->timeLine; + delete this->footer; + int i; + for (i = 0; i < NumberOfFontSettings; ++i) { + delete fonts[i]; + } +} + +int EpgPlus::exec (CChannelList * channelList, int selectedChannelIndex, CBouquetList * bouquetList) +{ + this->channelList = channelList; + this->channelListStartIndex = int (selectedChannelIndex / maxNumberOfDisplayableEntries) * maxNumberOfDisplayableEntries; + this->bouquetList = bouquetList; + + int res = menu_return::RETURN_REPAINT; + + do { + this->refreshAll = false; + this->refreshFooterButtons = false; + time_t currentTime = time (NULL); + tm tmStartTime = *localtime (¤tTime); + + tmStartTime.tm_sec = 0; + tmStartTime.tm_min = int (tmStartTime.tm_min / 15) * 15; + + this->startTime = mktime (&tmStartTime); + this->selectedTime = this->startTime; + this->firstStartTime = this->startTime; + + if (this->selectedChannelEntry != NULL) { + selectedChannelIndex = this->selectedChannelEntry->index; + } + + neutrino_msg_t msg; + neutrino_msg_data_t data; + + this->createChannelEntries (selectedChannelIndex); + + this->header->paint (); + + this->footer->paintButtons (buttonLabels, sizeof (buttonLabels) / sizeof (button_label)); + + this->paint (); + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd (g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]); + bool loop = true; + while (loop) { + g_RCInput->getMsgAbsoluteTimeout (&msg, &data, &timeoutEnd); + + if (msg <= CRCInput::RC_MaxRC) + timeoutEnd = CRCInput::calcTimeoutEnd (g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]); + + if ((msg == CRCInput::RC_page_down) || (msg == CRCInput::RC_yellow)) { + switch (this->currentSwapMode) { + case SwapMode_ByPage: + { + int selectedChannelEntryIndex = this->selectedChannelEntry->index; + selectedChannelEntryIndex += this->maxNumberOfDisplayableEntries; + + if (selectedChannelEntryIndex > this->channelList->getSize () - 1) + selectedChannelEntryIndex = 0; + + this->createChannelEntries (selectedChannelEntryIndex); + + this->paint (); + } + break; + case SwapMode_ByBouquet: + { + unsigned int currentBouquetNumber = bouquetList->getActiveBouquetNumber (); + + ++currentBouquetNumber; + + if (currentBouquetNumber == bouquetList->Bouquets.size ()) + currentBouquetNumber = 0; + + CBouquet *bouquet = bouquetList->Bouquets[currentBouquetNumber]; + + if (bouquet->channelList->getSize () > 0) { + // select first channel of bouquet + + bouquetList->activateBouquet (currentBouquetNumber, false); + + this->channelListStartIndex = (*bouquet->channelList)[0]->number - 1; + this->createChannelEntries (this->channelListStartIndex); + + this->paint (); + } + } + break; + } + } + //else if ( (msg == (neutrino_msg_t)g_settings.key_channelList_pageup) + else if ((msg == CRCInput::RC_page_up) || (msg == CRCInput::RC_green)) { + switch (this->currentSwapMode) { + case SwapMode_ByPage: + { + int selectedChannelEntryIndex = this->selectedChannelEntry->index; + selectedChannelEntryIndex -= this->maxNumberOfDisplayableEntries; + + if (selectedChannelEntryIndex < 0) + selectedChannelEntryIndex = this->channelList->getSize () - 1; + + this->createChannelEntries (selectedChannelEntryIndex); + + this->paint (); + } + break; + case SwapMode_ByBouquet: + { + unsigned int currentBouquetNumber = bouquetList->getActiveBouquetNumber (); + + --currentBouquetNumber; + + if (currentBouquetNumber == unsigned (-1)) + currentBouquetNumber = bouquetList->Bouquets.size () - 1; + + CBouquet *bouquet = bouquetList->Bouquets[currentBouquetNumber]; + + if (bouquet->channelList->getSize () > 0) { + // select first channel of bouquet + + bouquetList->activateBouquet (currentBouquetNumber, false); + + this->channelListStartIndex = (*bouquet->channelList)[0]->number - 1; + this->createChannelEntries (this->channelListStartIndex); + + this->paint (); + } + } + break; + } + } else if (msg == (neutrino_msg_t) CRCInput::RC_red) { + CMenuWidget menuWidgetActions (LOCALE_EPGPLUS_ACTIONS, "features.raw", 400); + if (!g_settings.minimode) + menuWidgetActions.addItem (new CMenuForwarder (LOCALE_EPGPLUS_RECORD, true, NULL, new MenuTargetAddRecordTimer (this), NULL, CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED), false); + menuWidgetActions.addItem (new CMenuForwarder (LOCALE_EPGPLUS_REFRESH_EPG, true, NULL, new MenuTargetRefreshEpg (this), NULL, CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN), false); + menuWidgetActions.addItem (new CMenuForwarder (LOCALE_EPGPLUS_REMIND, true, NULL, new MenuTargetAddReminder (this), NULL, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW), false); + + menuWidgetActions.exec (NULL, ""); + + this->refreshAll = true; + } else if (msg == (neutrino_msg_t) CRCInput::RC_blue) { + + CMenuWidget menuWidgetOptions (LOCALE_EPGPLUS_OPTIONS, "features.raw", 500); + menuWidgetOptions.addItem (new MenuOptionChooserSwitchSwapMode (this)); + menuWidgetOptions.addItem (new MenuOptionChooserSwitchViewMode (this)); + + int result = menuWidgetOptions.exec (NULL, ""); + if (result == menu_return::RETURN_REPAINT) { + this->refreshAll = true; + } else if (result == menu_return::RETURN_EXIT_ALL) { + this->refreshAll = true; + } + } else if (CRCInput::isNumeric (msg)) { //numeric zap + this->hide (); + this->channelList->numericZap (msg); + + int selectedChannelEntryIndex = this->channelList->getSelectedChannelIndex (); + if (selectedChannelEntryIndex < this->channelList->getSize ()) { + this->hide (); + this->createChannelEntries (selectedChannelEntryIndex); + + this->header->paint (); + this->footer->paintButtons (buttonLabels, sizeof (buttonLabels) / sizeof (button_label)); + this->paint (); + } + + } else if (msg == CRCInput::RC_up) { + int selectedChannelEntryIndex = this->selectedChannelEntry->index; + int prevSelectedChannelEntryIndex = selectedChannelEntryIndex; + + --selectedChannelEntryIndex; + if (selectedChannelEntryIndex < 0) { + selectedChannelEntryIndex = this->channelList->getSize () - 1; + } + + + int oldChannelListStartIndex = this->channelListStartIndex; + + this->channelListStartIndex = (selectedChannelEntryIndex / this->maxNumberOfDisplayableEntries) * this->maxNumberOfDisplayableEntries; + + if (oldChannelListStartIndex != this->channelListStartIndex) { + + this->createChannelEntries (selectedChannelEntryIndex); + + this->paint (); + } else { + this->selectedChannelEntry = this->displayedChannelEntries[selectedChannelEntryIndex - this->channelListStartIndex]; + + this->paintChannelEntry (prevSelectedChannelEntryIndex - this->channelListStartIndex); + this->paintChannelEntry (selectedChannelEntryIndex - this->channelListStartIndex); + } + } else if (msg == CRCInput::RC_down) { + int selectedChannelEntryIndex = this->selectedChannelEntry->index; + int prevSelectedChannelEntryIndex = this->selectedChannelEntry->index; + + selectedChannelEntryIndex = (selectedChannelEntryIndex + 1) % this->channelList->getSize (); + + + int oldChannelListStartIndex = this->channelListStartIndex; + this->channelListStartIndex = (selectedChannelEntryIndex / this->maxNumberOfDisplayableEntries) * this->maxNumberOfDisplayableEntries; + + if (oldChannelListStartIndex != this->channelListStartIndex) { + this->createChannelEntries (selectedChannelEntryIndex); + + this->paint (); + } else { + this->selectedChannelEntry = this->displayedChannelEntries[selectedChannelEntryIndex - this->channelListStartIndex]; + + this->paintChannelEntry (prevSelectedChannelEntryIndex - this->channelListStartIndex); + this->paintChannelEntry (this->selectedChannelEntry->index - this->channelListStartIndex); + } + + } else if ((msg == CRCInput::RC_timeout) || (msg == (neutrino_msg_t) g_settings.key_channelList_cancel)) { + loop = false; + } + + else if (msg == CRCInput::RC_left) { + switch (this->currentViewMode) { + case ViewMode_Stretch: + { + if (this->duration - 30 * 60 > 30 * 60) { + this->duration -= 30 * 60; + this->hide (); + this->refreshAll = true; + } + } + break; + case ViewMode_Scroll: + { + TCChannelEventEntries::const_iterator It = this->getSelectedEvent (); + + if ((It != this->selectedChannelEntry->channelEventEntries.begin ()) + && (It != this->selectedChannelEntry->channelEventEntries.end ()) + ) { + --It; + this->selectedTime = (*It)->channelEvent.startTime + (*It)->channelEvent.duration / 2; + if (this->selectedTime < this->startTime) + this->selectedTime = this->startTime; + + this->selectedChannelEntry->paint (true, this->selectedTime); + } else { + if (this->startTime != this->firstStartTime) { + + if (this->startTime - this->duration > this->firstStartTime) { + this->startTime -= this->duration; + } else { + this->startTime = this->firstStartTime; + } + + this->selectedTime = this->startTime + this->duration - 1; // select last event + this->createChannelEntries (this->selectedChannelEntry->index); + + this->paint (); + } + } + } + break; + } + } else if (msg == CRCInput::RC_right) { + switch (this->currentViewMode) { + case ViewMode_Stretch: + { + if (this->duration + 30 * 60 < 4 * 60 * 60) { + this->duration += 60 * 60; + this->hide (); + this->refreshAll = true; + } + } + break; + + case ViewMode_Scroll: + { + TCChannelEventEntries::const_iterator It = this->getSelectedEvent (); + + if ((It != this->selectedChannelEntry->channelEventEntries.end () - 1) + && (It != this->selectedChannelEntry->channelEventEntries.end ())) { + ++It; + + this->selectedTime = (*It)->channelEvent.startTime + (*It)->channelEvent.duration / 2; + + if (this->selectedTime > this->startTime + time_t (this->duration)) + this->selectedTime = this->startTime + this->duration; + + this->selectedChannelEntry->paint (true, this->selectedTime); + } else { + this->startTime += this->duration; + this->createChannelEntries (this->selectedChannelEntry->index); + + this->selectedTime = this->startTime; + this->createChannelEntries (this->selectedChannelEntry->index); + + this->paint (); + } + } + break; + } + } else if (msg == CRCInput::RC_ok) { + this->channelList->zapTo (this->selectedChannelEntry->index); + } else if (msg == CRCInput::RC_help || msg == CRCInput::RC_info) { + TCChannelEventEntries::const_iterator It = this->getSelectedEvent (); + + if (It != this->selectedChannelEntry->channelEventEntries.end ()) { + + if ((*It)->channelEvent.eventID != 0) { + this->hide (); + + time_t startTime = (*It)->channelEvent.startTime; + res = g_EpgData->show (this->selectedChannelEntry->channel->channel_id, (*It)->channelEvent.eventID, &startTime); + + if (res == menu_return::RETURN_EXIT_ALL) { + loop = false; + } else { + g_RCInput->getMsg (&msg, &data, 0); + + if ((msg != CRCInput::RC_red) && (msg != CRCInput::RC_timeout)) { + // RC_red schlucken + g_RCInput->postMsg (msg, data); + } + + this->header->paint (); + this->footer->paintButtons (buttonLabels, sizeof (buttonLabels) / sizeof (button_label)); + this->paint (); + } + } + } + else if (msg == CRCInput::RC_sat || msg == CRCInput::RC_favorites) { + g_RCInput->postMsg (msg, 0); + res = menu_return::RETURN_EXIT_ALL; + loop = false; + } + } else { + if (CNeutrinoApp::getInstance ()->handleMsg (msg, data) & messages_return::cancel_all) { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + + if (this->refreshAll) + loop = false; + else if (this->refreshFooterButtons) + this->footer->paintButtons (buttonLabels, sizeof (buttonLabels) / sizeof (button_label)); + + } + + this->hide (); + for (TChannelEntries::iterator It = this->displayedChannelEntries.begin (); + It != this->displayedChannelEntries.end (); It++) { + delete *It; + } + this->displayedChannelEntries.clear (); + } + while (this->refreshAll); + + return res; +} + +EpgPlus::TCChannelEventEntries::const_iterator EpgPlus::getSelectedEvent () const +{ + for (TCChannelEventEntries::const_iterator It = this->selectedChannelEntry->channelEventEntries.begin (); + It != this->selectedChannelEntry->channelEventEntries.end (); + ++It) { + if ((*It)->isSelected (this->selectedTime)) { + return It; + } + } + return this->selectedChannelEntry->channelEventEntries.end (); +} + +void EpgPlus::hide () +{ + this->frameBuffer->paintBackgroundBoxRel (this->usableScreenX, this->usableScreenY, this->usableScreenWidth, this->usableScreenHeight); +} + +void EpgPlus::paintChannelEntry (int position) +{ + ChannelEntry *channelEntry = this->displayedChannelEntries[position]; + + bool currentChannelIsSelected = false; + if (this->channelListStartIndex + position == this->selectedChannelEntry->index) { + currentChannelIsSelected = true; + } + channelEntry->paint (currentChannelIsSelected, this->selectedTime); +} + +std::string EpgPlus::getTimeString (const time_t & time, const std::string & format) +{ + char tmpstr[256]; + struct tm *tmStartTime = localtime (&time); + + strftime (tmpstr, sizeof (tmpstr), format.c_str (), tmStartTime); + return tmpstr; +} + +void EpgPlus::paint () +{ + // clear + this->frameBuffer->paintBackgroundBoxRel (this->channelsTableX, this->channelsTableY, this->usableScreenWidth, this->channelsTableHeight); + + // paint the gaps + this->frameBuffer->paintBoxRel (this->horGap1X, this->horGap1Y, this->horGap1Width, horGap1Height, horGap1Color); + this->frameBuffer->paintBoxRel (this->horGap2X, this->horGap2Y, this->horGap2Width, horGap2Height, horGap2Color); + this->frameBuffer->paintBoxRel (this->verGap1X, this->verGap1Y, verGap1Width, this->verGap1Height, verGap1Color); + this->frameBuffer->paintBoxRel (this->verGap2X, this->verGap2Y, verGap2Width, this->verGap2Height, verGap2Color); + + // paint the time line + timeLine->paint (this->startTime, this->duration); + + // paint the channel entries + for (int i = 0; i < (int) this->displayedChannelEntries.size (); ++i) { + this->paintChannelEntry (i); + } + + // paint the time line grid + this->timeLine->paintGrid (); + + // paint slider + this->frameBuffer->paintBoxRel (this->sliderX, this->sliderY, this->sliderWidth, this->sliderHeight, COL_MENUCONTENT_PLUS_0); + + int tmp = ((this->channelList->getSize () - 1) / this->maxNumberOfDisplayableEntries) + 1; + float sliderKnobHeight = (sliderHeight - 4) / tmp; + int sliderKnobPosition = this->selectedChannelEntry == NULL ? 0 : (this->selectedChannelEntry->index / this->maxNumberOfDisplayableEntries); + + this->frameBuffer->paintBoxRel (this->sliderX + 2, this->sliderY + int (sliderKnobPosition * sliderKnobHeight) + , this->sliderWidth - 4, int (sliderKnobHeight) , COL_MENUCONTENT_PLUS_3); +} + +// -- EPG+ Menue Handler Class +// -- to be used for calls from Menue +// -- (2004-03-05 rasc) + +int CEPGplusHandler::exec (CMenuTarget * parent, const std::string & actionKey) +{ + int res = menu_return::RETURN_EXIT_ALL; + EpgPlus *e; + CChannelList *channelList; + + if (parent) + parent->hide (); + + e = new EpgPlus; + + channelList = CNeutrinoApp::getInstance ()->channelList; + e->exec (channelList, channelList->getSelectedChannelIndex (), bouquetList); + delete e; + + return res; +} + +EpgPlus::MenuTargetAddReminder::MenuTargetAddReminder (EpgPlus * epgPlus) { + this->epgPlus = epgPlus; +} + +int EpgPlus::MenuTargetAddReminder::exec (CMenuTarget * parent, const std::string & actionKey) +{ + TCChannelEventEntries::const_iterator It = this->epgPlus->getSelectedEvent (); + + if ((It != this->epgPlus->selectedChannelEntry->channelEventEntries.end ()) + && (!(*It)->channelEvent.description.empty ()) + ) { + if (g_Timerd->isTimerdAvailable ()) { + g_Timerd->addZaptoTimerEvent (this->epgPlus->selectedChannelEntry->channel->channel_id, (*It)->channelEvent.startTime, (*It)->channelEvent.startTime - ANNOUNCETIME, 0, (*It)->channelEvent.eventID, (*It)->channelEvent.startTime, 0); + + ShowMsgUTF (LOCALE_TIMER_EVENTTIMED_TITLE, g_Locale->getText (LOCALE_TIMER_EVENTTIMED_MSG) + , CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); // UTF-8 + } else + printf ("timerd not available\n"); + } + return menu_return::RETURN_EXIT_ALL; +} + +EpgPlus::MenuTargetAddRecordTimer::MenuTargetAddRecordTimer (EpgPlus * epgPlus) { + this->epgPlus = epgPlus; +} + +int EpgPlus::MenuTargetAddRecordTimer::exec (CMenuTarget * parent, const std::string & actionKey) +{ + TCChannelEventEntries::const_iterator It = this->epgPlus->getSelectedEvent (); + + if ((It != this->epgPlus->selectedChannelEntry->channelEventEntries.end ()) + && (!(*It)->channelEvent.description.empty ()) + ) { + if (g_Timerd->isTimerdAvailable ()) { + + g_Timerd->addRecordTimerEvent (this->epgPlus->selectedChannelEntry->channel->channel_id, (*It)->channelEvent.startTime, (*It)->channelEvent.startTime + (*It)->channelEvent.duration, (*It)->channelEvent.eventID, (*It)->channelEvent.startTime, (*It)->channelEvent.startTime - (ANNOUNCETIME + 120) + , TIMERD_APIDS_CONF, true); + ShowMsgUTF (LOCALE_TIMER_EVENTRECORD_TITLE, g_Locale->getText (LOCALE_TIMER_EVENTRECORD_MSG) + , CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); // UTF-8 + } else + printf ("timerd not available\n"); + } + return menu_return::RETURN_EXIT_ALL; +} + +EpgPlus::MenuTargetRefreshEpg::MenuTargetRefreshEpg (EpgPlus * epgPlus) { + this->epgPlus = epgPlus; +} + +int EpgPlus::MenuTargetRefreshEpg::exec (CMenuTarget * parent, const std::string & actionKey) +{ + this->epgPlus->refreshAll = true; + return menu_return::RETURN_EXIT_ALL; +} + +struct CMenuOptionChooser::keyval menuOptionChooserSwitchSwapModes[] = { + {EpgPlus::SwapMode_ByPage, LOCALE_EPGPLUS_BYPAGE_MODE}, + {EpgPlus::SwapMode_ByBouquet, LOCALE_EPGPLUS_BYBOUQUET_MODE} +}; + +EpgPlus::MenuOptionChooserSwitchSwapMode::MenuOptionChooserSwitchSwapMode (EpgPlus * epgPlus) +:CMenuOptionChooser (LOCALE_EPGPLUS_SWAP_MODE, (int *) &epgPlus->currentSwapMode, menuOptionChooserSwitchSwapModes, sizeof (menuOptionChooserSwitchSwapModes) / sizeof (CMenuOptionChooser::keyval) + , true, NULL, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW) { + this->epgPlus = epgPlus; + this->oldSwapMode = epgPlus->currentSwapMode; + this->oldTimingMenuSettings = g_settings.timing[SNeutrinoSettings::TIMING_MENU]; +} + +EpgPlus::MenuOptionChooserSwitchSwapMode::~MenuOptionChooserSwitchSwapMode () +{ + g_settings.timing[SNeutrinoSettings::TIMING_MENU] = this->oldTimingMenuSettings; + + if (this->epgPlus->currentSwapMode != this->oldSwapMode) { + switch (this->epgPlus->currentSwapMode) { + case SwapMode_ByPage: + buttonLabels[1].locale = LOCALE_EPGPLUS_PAGE_DOWN; + buttonLabels[2].locale = LOCALE_EPGPLUS_PAGE_UP; + break; + case SwapMode_ByBouquet: + buttonLabels[1].locale = LOCALE_EPGPLUS_PREV_BOUQUET; + buttonLabels[2].locale = LOCALE_EPGPLUS_NEXT_BOUQUET; + break; + } + this->epgPlus->refreshAll = true; + } +} + +int EpgPlus::MenuOptionChooserSwitchSwapMode::exec (CMenuTarget * parent) +{ + // change time out settings temporary + g_settings.timing[SNeutrinoSettings::TIMING_MENU] = 1; + + CMenuOptionChooser::exec (parent); + + return menu_return::RETURN_REPAINT; +} + +struct CMenuOptionChooser::keyval menuOptionChooserSwitchViewModes[] = { + {EpgPlus::ViewMode_Scroll, LOCALE_EPGPLUS_STRETCH_MODE}, + {EpgPlus::ViewMode_Stretch, LOCALE_EPGPLUS_SCROLL_MODE} +}; + +EpgPlus::MenuOptionChooserSwitchViewMode::MenuOptionChooserSwitchViewMode (EpgPlus * epgPlus) +:CMenuOptionChooser (LOCALE_EPGPLUS_VIEW_MODE, (int *) &epgPlus->currentViewMode, menuOptionChooserSwitchViewModes, sizeof (menuOptionChooserSwitchViewModes) / sizeof (CMenuOptionChooser::keyval) + , true, NULL, CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE) { + this->oldTimingMenuSettings = g_settings.timing[SNeutrinoSettings::TIMING_MENU]; +} + +EpgPlus::MenuOptionChooserSwitchViewMode::~MenuOptionChooserSwitchViewMode () +{ + g_settings.timing[SNeutrinoSettings::TIMING_MENU] = this->oldTimingMenuSettings; +} + +int EpgPlus::MenuOptionChooserSwitchViewMode::exec (CMenuTarget * parent) +{ + // change time out settings temporary + g_settings.timing[SNeutrinoSettings::TIMING_MENU] = 1; + + CMenuOptionChooser::exec (parent); + + return menu_return::RETURN_REPAINT; +} diff --git a/src/gui/epgplus.h b/src/gui/epgplus.h new file mode 100644 index 000000000..a4dc32660 --- /dev/null +++ b/src/gui/epgplus.h @@ -0,0 +1,556 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Copyright (C) 2004 Martin Griep 'vivamiga' + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __EPGPLUS_HPP__ +#define __EPGPLUS_HPP__ + +#include +#include +#include +#include + +#include "color.h" +#include "channellist.h" +#include "infoviewer.h" +#include "filebrowser.h" + +#include "widget/menue.h" + +#include + +class CBouquetList; +class ConfigFile; +struct button_label; + +class EpgPlus +{ +//// types, inner classes +public: + enum FontSettingID + { + EPGPlus_header_font = 0, + EPGPlus_timeline_fonttime, + EPGPlus_timeline_fontdate, + EPGPlus_channelentry_font, + EPGPlus_channelevententry_font, + EPGPlus_footer_fontbouquetchannelname, + EPGPlus_footer_fonteventdescription, + EPGPlus_footer_fonteventshortdescription, + EPGPlus_footer_fontbuttons, + NumberOfFontSettings + }; + + enum SizeSettingID + { + EPGPlus_channelentry_width = 0, + EPGPlus_channelentry_separationlineheight, + EPGPlus_slider_width, + EPGPlus_horgap1_height, + EPGPlus_horgap2_height, + EPGPlus_vergap1_width, + EPGPlus_vergap2_width, + NumberOfSizeSettings + }; + + struct FontSetting + { + FontSettingID settingID; + char* style; + int size; + }; + + struct SizeSetting + { + SizeSettingID settingID; + int size; + }; + + + enum TViewMode + { + ViewMode_Stretch, + ViewMode_Scroll, + }; + + enum TSwapMode + { + SwapMode_ByPage, + SwapMode_ByBouquet, + }; + + class Footer; + + class Header + { + //// construction / destruction + public: + Header ( CFrameBuffer* frameBuffer , int x , int y , int width); + + ~Header(); + + //// methods + public: + static void init(); + + void paint(); + + static int getUsedHeight(); + + //// attributes + public: + CFrameBuffer* frameBuffer; + + int x; + int y; + int width; + + static Font* font; + }; + + + class TimeLine + { + //// construction / destruction + public: + TimeLine ( CFrameBuffer* frameBuffer , int x , int y , int width , int startX , int durationX); + + ~TimeLine(); + + //// methods + public: + static void init(); + + void paint ( time_t startTime , int duration); + + void paintMark ( time_t startTime , int duration , int x , int width); + + void paintGrid(); + + void clearMark(); + + static int getUsedHeight(); + + //// attributes + public: + CFrameBuffer* frameBuffer; + + int currentDuration; + + int x; + int y; + int width; + + static Font* fontTime; + static Font* fontDate; + + int startX; + int durationX; + }; + + class ChannelEventEntry + { + //// construction / destruction + public: + ChannelEventEntry + ( const CChannelEvent* channelEvent + , CFrameBuffer* frameBuffer + , TimeLine* timeLine + , Footer* footer + , int x + , int y + , int width + ); + + ~ChannelEventEntry(); + + //// methods + public: + static void init(); + + bool isSelected + ( time_t selectedTime + ) const; + + void paint + ( bool isSelected + , bool toggleColor + ); + + static int getUsedHeight(); + + //// attributes + public: + CChannelEvent channelEvent; + + CFrameBuffer* frameBuffer; + TimeLine* timeLine; + Footer* footer; + + int x; + int y; + int width; + static int separationLineHeight; + + static Font* font; + }; + + typedef std::vector TCChannelEventEntries; + + class ChannelEntry + { + //// construction / destruction + public: + ChannelEntry + ( const CZapitChannel* channel + , int index + , CFrameBuffer* frameBuffer + , Footer* footer + , CBouquetList* bouquetList + , int x + , int y + , int width + ); + + ~ChannelEntry(); + + //// methods + public: + static void init(); + + void paint + ( bool isSelected + , time_t selectedTime + ); + + static int getUsedHeight(); + + //// attributes + public: + const CZapitChannel * channel; + std::string displayName; + int index; + + CFrameBuffer* frameBuffer; + Footer* footer; + CBouquetList* bouquetList; + + int x; + int y; + int width; + static int separationLineHeight; + + static Font* font; + + TCChannelEventEntries channelEventEntries; + }; + + typedef std::vector TChannelEntries; + + class Footer + { + //// construction / destruction + public: + Footer + ( CFrameBuffer* frameBuffer + , int x + , int y + , int width + ); + + ~Footer(); + + //// methods + public: + static void init(); + + void setBouquetChannelName + ( const std::string& newBouquetName + , const std::string& newChannelName + ); + + void paintEventDetails + ( const std::string& description + , const std::string& shortDescription + ); + + void paintButtons + ( button_label* buttonLabels + , int numberOfButtons + ); + + static int getUsedHeight(); + + //// attributes + public: + CFrameBuffer* frameBuffer; + + int x; + int y; + int width; + + static Font* fontBouquetChannelName; + static Font* fontEventDescription; + static Font* fontEventShortDescription; + static Font* fontButtons; + + static int color; + + std::string currentBouquetName; + std::string currentChannelName; + }; + + + class MenuTargetAddReminder : public CMenuTarget + { + public: + MenuTargetAddReminder ( EpgPlus* epgPlus); + + public: + int exec ( CMenuTarget* parent , const std::string& actionKey); + + private: + EpgPlus* epgPlus; + + }; + + class MenuTargetAddRecordTimer : public CMenuTarget + { + public: + MenuTargetAddRecordTimer ( EpgPlus* epgPlus); + + public: + int exec ( CMenuTarget* parent , const std::string& actionKey); + + private: + EpgPlus* epgPlus; + + }; + + class MenuTargetRefreshEpg : public CMenuTarget + { + public: + MenuTargetRefreshEpg ( EpgPlus* epgPlus); + + public: + int exec ( CMenuTarget* parent , const std::string& actionKey); + + private: + EpgPlus* epgPlus; + + }; + + class MenuOptionChooserSwitchSwapMode : public CMenuOptionChooser + { + public: + MenuOptionChooserSwitchSwapMode ( EpgPlus* epgPlus); + + virtual ~MenuOptionChooserSwitchSwapMode(); + + public: + int exec + ( CMenuTarget* parent); + + private: + int oldTimingMenuSettings; + TSwapMode oldSwapMode; + EpgPlus* epgPlus; + }; + + class MenuOptionChooserSwitchViewMode : public CMenuOptionChooser + { + public: + MenuOptionChooserSwitchViewMode ( EpgPlus* epgPlus); + + virtual ~MenuOptionChooserSwitchViewMode(); + + public: + int exec ( CMenuTarget* parent); + + private: + int oldTimingMenuSettings; + }; + + class MenuTargetSettings : public CMenuTarget + { + public: + MenuTargetSettings ( EpgPlus* epgPlus); + + public: + int exec ( CMenuTarget* parent , const std::string& actionKey); + + private: + EpgPlus* epgPlus; + }; + + typedef time_t DurationSetting; + +/* + struct Settings + { + Settings ( bool doInit = true); + + virtual ~Settings(); + + FontSetting* fontSettings; + SizeSetting* sizeSettings; + DurationSetting durationSetting; + }; + typedef std::map Fonts; + typedef std::map Sizes; + static Font * fonts[NumberOfFontSettings]; + static int sizes[NumberOfSizeSettings]; +*/ + + friend class EpgPlus::MenuOptionChooserSwitchSwapMode; + friend class EpgPlus::MenuOptionChooserSwitchViewMode; + friend class EpgPlus::ChannelEntry; + friend class EpgPlus::ChannelEventEntry; + +//// construction / destruction +public: + EpgPlus(); + ~EpgPlus(); + +//// methods +public: + void init(); + void free(); + + int exec ( CChannelList* channelList , int selectedChannelIndex , CBouquetList* bouquetList); + +private: + static std::string getTimeString ( const time_t& time , const std::string& format); + + TCChannelEventEntries::const_iterator getSelectedEvent() const; + + void createChannelEntries ( int selectedChannelEntryIndex); + void paint(); + void paintChannelEntry ( int position); + void hide(); + +//// properties +private: + CFrameBuffer* frameBuffer; + + TChannelEntries displayedChannelEntries; + + Header* header; + TimeLine* timeLine; + + CChannelList* channelList; + CBouquetList* bouquetList; + + Footer* footer; + + ChannelEntry* selectedChannelEntry; + time_t selectedTime; + + int channelListStartIndex; + int maxNumberOfDisplayableEntries; // maximal number of displayable entrys + + time_t startTime; + time_t firstStartTime; + static time_t duration; + + int entryHeight; + + TViewMode currentViewMode; + TSwapMode currentSwapMode; + + int headerX; + int headerY; + int headerWidth; + + int usableScreenWidth; + int usableScreenHeight; + int usableScreenX; + int usableScreenY; + + int timeLineX; + int timeLineY; + int timeLineWidth; + + int channelsTableX; + int channelsTableY; + static int channelsTableWidth; + int channelsTableHeight; + + int eventsTableX; + int eventsTableY; + int eventsTableWidth; + int eventsTableHeight; + + int sliderX; + int sliderY; + static int sliderWidth; + int sliderHeight; + static int sliderBackColor; + static int sliderKnobColor; + + int footerX; + int footerY; + int footerWidth; + + int horGap1X; + int horGap1Y; + int horGap1Width; + int horGap2X; + int horGap2Y; + int horGap2Width; + int verGap1X; + int verGap1Y; + int verGap1Height; + int verGap2X; + int verGap2Y; + int verGap2Height; + + static int horGap1Height; + static int horGap2Height; + static int verGap1Width; + static int verGap2Width; + + static int horGap1Color; + static int horGap2Color; + static int verGap1Color; + static int verGap2Color; + + bool refreshAll; + bool refreshFooterButtons; +}; + +class CEPGplusHandler : public CMenuTarget +{ + public: + int exec( CMenuTarget* parent, const std::string &actionKey); +}; + +#endif diff --git a/src/gui/epgview.cpp b/src/gui/epgview.cpp new file mode 100644 index 000000000..312729e31 --- /dev/null +++ b/src/gui/epgview.cpp @@ -0,0 +1,1080 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +extern CPictureViewer * g_PicViewer; +#define PIC_W 52 +#define PIC_H 39 +static CScale * timescale; + +#define ICON_LARGE_WIDTH 26 +#define ROUND_RADIUS 9 + +int findItem(std::string strItem, std::vector & vecItems) { + for (std::vector::size_type nCnt = 0; nCnt < vecItems.size(); nCnt++) { + std::string strThisItem = vecItems[nCnt]; + if (strItem == strThisItem) { + return nCnt; + } + } + return -1; +} + +// 21.07.2005 - rainerk +// Merge multiple extended event strings into one description and localize the label +// Examples: +// Actor1-ActorX -> Darsteller 1, 2, 3 +// Year of production -> Produktionsjahr +// Director -> Regisseur +// Guests -> Gäste +void reformatExtendedEvents(std::string strItem, std::string strLabel, bool bUseRange, CEPGData & epgdata) { + std::vector & vecDescriptions = epgdata.itemDescriptions; + std::vector & vecItems = epgdata.items; + // Merge multiple events into 1 (Actor1-) + if (bUseRange) { + bool bHasItems = false; + char index[3]; + // Maximum of 10 items should suffice + for (int nItem = 1; nItem < 11; nItem++) { + sprintf(index, "%d", nItem); + // Look for matching items + int nPos = findItem(std::string(strItem) + std::string(index), vecDescriptions); + if (-1 != nPos) { + std::string item = std::string(vecItems[nPos]); + vecDescriptions.erase(vecDescriptions.begin() + nPos); + vecItems.erase(vecItems.begin() + nPos); + if (false == bHasItems) { + // First item added, so create new label item + vecDescriptions.push_back(strLabel); + vecItems.push_back(item + ", "); + bHasItems = true; + } else { + vecItems.back().append(item).append(", "); + } + } + } + // Remove superfluous ", " + if (bHasItems) { + vecItems.back().resize(vecItems.back().length() - 2); + } + } else { // Single string event (e.g. Director) + // Look for matching items + int nPos = findItem(strItem, vecDescriptions); + if (-1 != nPos) { + vecDescriptions[nPos] = strLabel; + } + } +} + +CEpgData::CEpgData() +{ + bigFonts = false; + frameBuffer = CFrameBuffer::getInstance(); + timescale = new CScale(100, 12, 30, 100, 70, true); +} + +#define MAX_W 540 +#define MAX_H 320 + +void CEpgData::start() +{ + ox = w_max (MAX_W * (bigFonts ? BIG_FONT_FAKTOR : 1), 0); + oy = h_max (MAX_H * (bigFonts ? BIG_FONT_FAKTOR : 1), 0); + sx = (((g_settings.screen_EndX-g_settings.screen_StartX) -ox) / 2) + g_settings.screen_StartX; + + topheight = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_TITLE]->getHeight(); + topboxheight = topheight + 6; + + if(topboxheight < PIC_H) topboxheight = PIC_H; + + botheight = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->getHeight(); + botboxheight = botheight + 6; + medlineheight = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->getHeight(); + medlinecount = (oy- botboxheight)/medlineheight; + sb = medlinecount* medlineheight; + + oy = botboxheight+medlinecount*medlineheight; // recalculate //FIXME + sy = (((g_settings.screen_EndY-g_settings.screen_StartY)-(oy- topboxheight) ) / 2) + g_settings.screen_StartY; + toph = topboxheight; +} + +void CEpgData::addTextToArray(const std::string & text) // UTF-8 +{ + //printf("line: >%s<\n", text.c_str() ); + if (text==" ") + { + emptyLineCount ++; + if(emptyLineCount<2) + { + epgText.push_back(text); + } + } + else + { + emptyLineCount = 0; + epgText.push_back(text); + } +} + +void CEpgData::processTextToArray(std::string text) // UTF-8 +{ + std::string aktLine = ""; + std::string aktWord = ""; + int aktWidth = 0; + text += ' '; + char* text_= (char*) text.c_str(); + + while(*text_!=0) + { + if ( (*text_==' ') || (*text_=='\n') || (*text_=='-') || (*text_=='.') ) + { + // Houdini: if there is a newline (especially in the Premiere Portal EPGs) do not forget to add aktWord to aktLine + // after width check, if width check failes do newline, add aktWord to next line + // and "reinsert" i.e. reloop for the \n + if(*text_!='\n') + aktWord += *text_; + + // check the wordwidth - add to this line if size ok + int aktWordWidth = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->getRenderWidth(aktWord, true); + if((aktWordWidth+aktWidth)<(ox- 20- 15)) + {//space ok, add + aktWidth += aktWordWidth; + aktLine += aktWord; + + if(*text_=='\n') + { //enter-handler + addTextToArray( aktLine ); + aktLine = ""; + aktWidth= 0; + } + aktWord = ""; + } + else + {//new line needed + addTextToArray( aktLine ); + aktLine = aktWord; + aktWidth = aktWordWidth; + aktWord = ""; + // Houdini: in this case where we skipped \n and space is too low, exec newline and rescan \n + // otherwise next word comes direct after aktLine + if(*text_=='\n') + continue; + } + } + else + { + aktWord += *text_; + } + text_++; + } + //add the rest + addTextToArray( aktLine + aktWord ); +} + +void CEpgData::showText( int startPos, int ypos ) +{ + // recalculate + medlineheight = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->getHeight(); + medlinecount=(oy- botboxheight)/medlineheight; + + int textCount = epgText.size(); + int y=ypos; + + frameBuffer->paintBoxRel(sx, y, ox- 15, sb, COL_MENUCONTENT_PLUS_0); + + for(int i=startPos; iRenderString(sx+10, y+medlineheight, ox- 15- 15, epgText[i], COL_MENUCONTENT, 0, true); // UTF-8 + else + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->RenderString(sx+10, y+medlineheight, ox- 15- 15, epgText[i], COL_MENUCONTENT, 0, true); // UTF-8 + } + + frameBuffer->paintBoxRel(sx+ ox- 15, ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((textCount- 1)/ medlinecount)+ 1; + float sbh= (sb- 4)/ sbc; + int sbs= (startPos+ 1)/ medlinecount; + + frameBuffer->paintBoxRel(sx+ ox- 13, ypos+ 2+ int(sbs* sbh) , 11, int(sbh), COL_MENUCONTENT_PLUS_3); +} + +#define GENRE_MOVIE_COUNT 9 +const neutrino_locale_t genre_movie[GENRE_MOVIE_COUNT] = +{ + LOCALE_GENRE_MOVIE_0, + LOCALE_GENRE_MOVIE_1, + LOCALE_GENRE_MOVIE_2, + LOCALE_GENRE_MOVIE_3, + LOCALE_GENRE_MOVIE_4, + LOCALE_GENRE_MOVIE_5, + LOCALE_GENRE_MOVIE_6, + LOCALE_GENRE_MOVIE_7, + LOCALE_GENRE_MOVIE_8 +}; +#define GENRE_NEWS_COUNT 5 +const neutrino_locale_t genre_news[GENRE_NEWS_COUNT] = +{ + LOCALE_GENRE_NEWS_0, + LOCALE_GENRE_NEWS_1, + LOCALE_GENRE_NEWS_2, + LOCALE_GENRE_NEWS_3, + LOCALE_GENRE_NEWS_4 +}; +#define GENRE_SHOW_COUNT 4 +const neutrino_locale_t genre_show[GENRE_SHOW_COUNT] = +{ + LOCALE_GENRE_SHOW_0, + LOCALE_GENRE_SHOW_1, + LOCALE_GENRE_SHOW_2, + LOCALE_GENRE_SHOW_3 +}; +#define GENRE_SPORTS_COUNT 12 +const neutrino_locale_t genre_sports[GENRE_SPORTS_COUNT] = +{ + LOCALE_GENRE_SPORTS_0, + LOCALE_GENRE_SPORTS_1, + LOCALE_GENRE_SPORTS_2, + LOCALE_GENRE_SPORTS_3, + LOCALE_GENRE_SPORTS_4, + LOCALE_GENRE_SPORTS_5, + LOCALE_GENRE_SPORTS_6, + LOCALE_GENRE_SPORTS_7, + LOCALE_GENRE_SPORTS_8, + LOCALE_GENRE_SPORTS_9, + LOCALE_GENRE_SPORTS_10, + LOCALE_GENRE_SPORTS_11 +}; +#define GENRE_CHILDRENS_PROGRAMMES_COUNT 6 +const neutrino_locale_t genre_childrens_programmes[GENRE_CHILDRENS_PROGRAMMES_COUNT] = +{ + LOCALE_GENRE_CHILDRENS_PROGRAMMES_0, + LOCALE_GENRE_CHILDRENS_PROGRAMMES_1, + LOCALE_GENRE_CHILDRENS_PROGRAMMES_2, + LOCALE_GENRE_CHILDRENS_PROGRAMMES_3, + LOCALE_GENRE_CHILDRENS_PROGRAMMES_4, + LOCALE_GENRE_CHILDRENS_PROGRAMMES_5 +}; +#define GENRE_MUSIC_DANCE_COUNT 7 +const neutrino_locale_t genre_music_dance[GENRE_MUSIC_DANCE_COUNT] = +{ + LOCALE_GENRE_MUSIC_DANCE_0, + LOCALE_GENRE_MUSIC_DANCE_1, + LOCALE_GENRE_MUSIC_DANCE_2, + LOCALE_GENRE_MUSIC_DANCE_3, + LOCALE_GENRE_MUSIC_DANCE_4, + LOCALE_GENRE_MUSIC_DANCE_5, + LOCALE_GENRE_MUSIC_DANCE_6 +}; +#define GENRE_ARTS_COUNT 12 +const neutrino_locale_t genre_arts_dance[GENRE_ARTS_COUNT] = +{ + LOCALE_GENRE_ARTS_0, + LOCALE_GENRE_ARTS_1, + LOCALE_GENRE_ARTS_2, + LOCALE_GENRE_ARTS_3, + LOCALE_GENRE_ARTS_4, + LOCALE_GENRE_ARTS_5, + LOCALE_GENRE_ARTS_6, + LOCALE_GENRE_ARTS_7, + LOCALE_GENRE_ARTS_8, + LOCALE_GENRE_ARTS_9, + LOCALE_GENRE_ARTS_10, + LOCALE_GENRE_ARTS_11 +}; +#define GENRE_SOCIAL_POLITICAL_COUNT 4 +const neutrino_locale_t genre_social_political[GENRE_SOCIAL_POLITICAL_COUNT] = +{ + LOCALE_GENRE_SOCIAL_POLITICAL_0, + LOCALE_GENRE_SOCIAL_POLITICAL_1, + LOCALE_GENRE_SOCIAL_POLITICAL_2, + LOCALE_GENRE_SOCIAL_POLITICAL_3 +}; +#define GENRE_DOCUS_MAGAZINES_COUNT 8 +const neutrino_locale_t genre_docus_magazines[GENRE_DOCUS_MAGAZINES_COUNT] = +{ + LOCALE_GENRE_DOCUS_MAGAZINES_0, + LOCALE_GENRE_DOCUS_MAGAZINES_1, + LOCALE_GENRE_DOCUS_MAGAZINES_2, + LOCALE_GENRE_DOCUS_MAGAZINES_3, + LOCALE_GENRE_DOCUS_MAGAZINES_4, + LOCALE_GENRE_DOCUS_MAGAZINES_5, + LOCALE_GENRE_DOCUS_MAGAZINES_6, + LOCALE_GENRE_DOCUS_MAGAZINES_7 +}; +#define GENRE_TRAVEL_HOBBIES_COUNT 8 +const neutrino_locale_t genre_travel_hobbies[GENRE_TRAVEL_HOBBIES_COUNT] = +{ + LOCALE_GENRE_TRAVEL_HOBBIES_0, + LOCALE_GENRE_TRAVEL_HOBBIES_1, + LOCALE_GENRE_TRAVEL_HOBBIES_2, + LOCALE_GENRE_TRAVEL_HOBBIES_3, + LOCALE_GENRE_TRAVEL_HOBBIES_4, + LOCALE_GENRE_TRAVEL_HOBBIES_5, + LOCALE_GENRE_TRAVEL_HOBBIES_6, + LOCALE_GENRE_TRAVEL_HOBBIES_7 +}; +const unsigned char genre_sub_classes[10] = +{ + GENRE_MOVIE_COUNT, + GENRE_NEWS_COUNT, + GENRE_SHOW_COUNT, + GENRE_SPORTS_COUNT, + GENRE_CHILDRENS_PROGRAMMES_COUNT, + GENRE_MUSIC_DANCE_COUNT, + GENRE_ARTS_COUNT, + GENRE_SOCIAL_POLITICAL_COUNT, + GENRE_DOCUS_MAGAZINES_COUNT, + GENRE_TRAVEL_HOBBIES_COUNT +}; +const neutrino_locale_t * genre_sub_classes_list[10] = +{ + genre_movie, + genre_news, + genre_show, + genre_sports, + genre_childrens_programmes, + genre_music_dance, + genre_arts_dance, + genre_social_political, + genre_docus_magazines, + genre_travel_hobbies +}; + +bool CEpgData::hasFollowScreenings(const t_channel_id channel_id, const std::string & title) { + time_t curtime = time(NULL); + + for (CChannelEventList::iterator e = evtlist.begin(); e != evtlist.end(); ++e ) + { + if (e->startTime > curtime && e->eventID && e->description == title) + return true; + } + return false; +} + +const char * GetGenre(const unsigned char contentClassification) // UTF-8 +{ + neutrino_locale_t res; + + //unsigned char i = (contentClassification & 0x0F0); + int i = (contentClassification & 0xF0); +//printf("GetGenre: contentClassification %X i %X bool %s\n", contentClassification, i, i < 176 ? "yes" : "no"); fflush(stdout); + if ((i >= 0x010) && (i < 0x0B0)) + { + i >>= 4; + i--; +//printf("GetGenre: i %d content %d\n", i, contentClassification & 0x0F); fflush(stdout); + res = genre_sub_classes_list[i][((contentClassification & 0x0F) < genre_sub_classes[i]) ? (contentClassification & 0x0F) : 0]; + } + else + res = LOCALE_GENRE_UNKNOWN; + return g_Locale->getText(res); +} + +static bool sortByDateTime (const CChannelEvent& a, const CChannelEvent& b) +{ + return a.startTime< b.startTime; +} + +extern char recDir[255]; +void sectionsd_getEventsServiceKey(t_channel_id serviceUniqueKey, CChannelEventList &eList, char search = 0, std::string search_text = ""); +bool sectionsd_getComponentTagsUniqueKey(const event_id_t uniqueKey, CSectionsdClient::ComponentTagList& tags); + +void CEpgData::showHead(const t_channel_id channel_id) +{ + int pos; + std::string text1 = epgData.title; + std::string text2 = ""; + if (g_Font[SNeutrinoSettings::FONT_TYPE_EPG_TITLE]->getRenderWidth(text1, true) > ox - PIC_W - 5) + { + do + { + pos = text1.find_last_of("[ .]+"); + if ( pos!=-1 ) + text1 = text1.substr( 0, pos ); + } while ( ( pos != -1 ) && (g_Font[SNeutrinoSettings::FONT_TYPE_EPG_TITLE]->getRenderWidth(text1, true) > 520 - PIC_W - 5)); + text2 = epgData.title.substr(text1.length()+ 1, uint(-1) ); + } + int oldtoph= toph; + + toph = text2 != "" ? 2* topboxheight : topboxheight; + + if (oldtoph > toph) + frameBuffer->paintBackgroundBox (sx, sy- oldtoph- 1, sx+ ox, sy /*- toph*/); + + //show the epg title + frameBuffer->paintBoxRel(sx, sy- toph, ox, toph, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1);//round + bool logo_ok = false; + + logo_ok = g_PicViewer->DisplayLogo(channel_id, sx+10, sy- toph+ (toph-PIC_H)/2/*5*/, PIC_W, PIC_H); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_TITLE]->RenderString(sx+15 +(logo_ok? PIC_W+10: 0), sy- toph+ topheight+ 3, ox-15- (logo_ok ? PIC_W+5: 0), text1, COL_MENUHEAD, 0, true); + if (!(text2.empty())) + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_TITLE]->RenderString(sx+15+(logo_ok? PIC_W+10: 0), sy- toph+ 2* topheight+ 3, ox-15 - (logo_ok ? PIC_W+5: 0), text2, COL_MENUHEAD, 0, true); + +} + +int CEpgData::show(const t_channel_id channel_id, unsigned long long a_id, time_t* a_startzeit, bool doLoop ) +{ + int res = menu_return::RETURN_REPAINT; + static unsigned long long id; + static time_t startzeit; + + if(a_startzeit) + startzeit=*a_startzeit; + id=a_id; + + int height; + height = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->getHeight(); + if (doLoop) + { + //start(); + frameBuffer->paintBoxRel(g_settings.screen_StartX, g_settings.screen_StartY, 50, height+5, COL_INFOBAR_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->RenderString(g_settings.screen_StartX+10, g_settings.screen_StartY+height, 40, "-@-", COL_INFOBAR); + if(!bigFonts && g_settings.bigFonts) { + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->setSize((int)(g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->getSize() * BIG_FONT_FAKTOR)); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->setSize((int)(g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->getSize() * BIG_FONT_FAKTOR)); + } + bigFonts = g_settings.bigFonts; + start(); + } + + GetEPGData(channel_id, id, &startzeit ); + if (doLoop) + { + //evtlist = g_Sectionsd->getEventsServiceKey(channel_id&0xFFFFFFFFFFFFULL); + evtlist.clear(); + sectionsd_getEventsServiceKey(channel_id&0xFFFFFFFFFFFFULL, evtlist); + // Houdini added for Private Premiere EPG start sorted by start date/time 2005-08-15 + sort(evtlist.begin(),evtlist.end(),sortByDateTime); + frameBuffer->paintBackgroundBoxRel(g_settings.screen_StartX, g_settings.screen_StartY, 50, height+5); + } + + if (epgData.title.empty()) /* no epg info found */ + { + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_EPGVIEWER_NOTFOUND)); // UTF-8 + hide(); + return res; + } + + // 21.07.2005 - rainerk + // Only show info1 if it's not included in info2! + std::string strEpisode = ""; // Episode title in case info1 gets stripped + if (!epgData.info1.empty()) { + bool bHide = false; + if (false == epgData.info2.empty()) { + // Look for the first . in info1, usually this is the title of an episode. + std::string::size_type nPosDot = epgData.info1.find('.'); + if (std::string::npos != nPosDot) { + nPosDot += 2; // Skip dot and first blank +/* Houdini: changed for safty reason (crashes with some events at WDR regional) + if (nPosDot < epgData.info2.length()) { // Make sure we don't overrun the buffer +*/ + if (nPosDot < epgData.info2.length() && nPosDot < epgData.info1.length()) { // Make sure we don't overrun the buffer + + // Check if the stuff after the dot equals the beginning of info2 + if (0 == epgData.info2.find(epgData.info1.substr(nPosDot, epgData.info1.length() - nPosDot))) { + strEpisode = epgData.info1.substr(0, nPosDot) + "\n"; + bHide = true; + } + } + } + // Compare strings normally if not positively found to be equal before + if (false == bHide && false == (std::string::npos == epgData.info2.find(epgData.info1))) { + bHide = true; + } + } + if (false == bHide) { + processTextToArray(epgData.info1); + } + } + + info1_lines = epgText.size(); + + //scan epg-data - sort to list + if ((epgData.info2.empty()) && (info1_lines == 0)) + processTextToArray(g_Locale->getText(LOCALE_EPGVIEWER_NODETAILED)); // UTF-8 + else + processTextToArray(strEpisode + epgData.info2); + + // 21.07.2005 - rainerk + // Show extended information + if(0 != epgData.itemDescriptions.size() && 0 != epgData.items.size()) { + char line[256]; + std::vector::iterator description; + std::vector::iterator item; + processTextToArray(""); // Add a blank line +//printf("show:: items %d descriptions %d\n", epgData.items.size(), epgData.itemDescriptions.size()); + for (description = epgData.itemDescriptions.begin(), item = epgData.items.begin(); description != epgData.itemDescriptions.end(), item != epgData.items.end(); ++description, ++item) { +//printf("item:: %s: %s\n", (*(description)).c_str(), (*(item)).c_str());fflush(stdout); + sprintf(line, "%s: %s", (*(description)).c_str(), (*(item)).c_str()); + processTextToArray(line); +//printf("after processTextToArray\n"); + } + } +//printf("after epgData.itemDescriptions.size\n"); + + if (epgData.fsk > 0) + { + char _tfsk[11]; + sprintf (_tfsk, "FSK: ab %d", epgData.fsk ); + processTextToArray( _tfsk ); // UTF-8 + } + + if (epgData.contentClassification.length()> 0) + processTextToArray(GetGenre(epgData.contentClassification[0])); // UTF-8 +// processTextToArray( epgData.userClassification.c_str() ); + + + // -- display more screenings on the same channel + // -- 2002-05-03 rasc + if (hasFollowScreenings(channel_id, epgData.title)) { + processTextToArray(""); // UTF-8 + processTextToArray(std::string(g_Locale->getText(LOCALE_EPGVIEWER_MORE_SCREENINGS)) + ':'); // UTF-8 + FollowScreenings(channel_id, epgData.title); + } + + showHead(channel_id); + + //show date-time.... + frameBuffer->paintBoxRel(sx, sy+oy-botboxheight, ox, botboxheight, COL_MENUHEAD_PLUS_0); + std::string fromto; + int widthl,widthr; + fromto = epg_start; + fromto += " - "; + fromto += epg_end; + + widthl = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->getRenderWidth(fromto); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->RenderString(sx+40, sy+oy-3, widthl, fromto, COL_MENUHEAD); + widthr = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->getRenderWidth(epg_date); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->RenderString(sx+ox-40-widthr, sy+oy-3, widthr, epg_date, COL_MENUHEAD); + + int showPos = 0; + textCount = epgText.size(); + int textypos = sy; + showText(showPos, textypos); + + // show Timer Event Buttons + showTimerEventBar (true); + + //show Content&Component for Dolby & 16:9 + CSectionsdClient::ComponentTagList tags; + //if ( g_Sectionsd->getComponentTagsUniqueKey( epgData.eventID, tags ) ) + if ( sectionsd_getComponentTagsUniqueKey( epgData.eventID, tags ) ) + { + for (unsigned int i=0; i< tags.size(); i++) + { + if( tags[i].streamContent == 1 && (tags[i].componentType == 2 || tags[i].componentType == 3) ) + { + frameBuffer->paintIcon("16_9.raw" ,ox+sx-(ICON_LARGE_WIDTH+2)-(ICON_LARGE_WIDTH+2),sy + oy+5 ); + } + else if( tags[i].streamContent == 2 && tags[i].componentType == 5 ) + { + frameBuffer->paintIcon("dd.raw", ox+sx-(ICON_LARGE_WIDTH+2), sy + oy+5); + } + } + } + + //show progressbar + if ( epg_done!= -1 ) + { + int pbx = sx + 10 + widthl + 10 + ((ox-104-widthr-widthl-10-10-20)>>1); + timescale->reset(); + timescale->paint(pbx+2, sy+oy-height+2, epg_done); + } + + GetPrevNextEPGData( epgData.eventID, &epgData.epg_times.startzeit ); + if (prev_id != 0) + { + frameBuffer->paintBoxRel(sx+ 5, sy+ oy- botboxheight+ 4, botboxheight- 8, botboxheight- 8, COL_MENUCONTENT_PLUS_3); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->RenderString(sx+ 10, sy+ oy- 3, widthr, "<", COL_MENUCONTENT + 3); + } + + if (next_id != 0) + { + frameBuffer->paintBoxRel(sx+ ox- botboxheight+ 8- 5, sy+ oy- botboxheight+ 4, botboxheight- 8, botboxheight- 8, COL_MENUCONTENT_PLUS_3); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->RenderString(sx+ ox- botboxheight+ 8, sy+ oy- 3, widthr, ">", COL_MENUCONTENT + 3); + } + + if ( doLoop ) + { + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int scrollCount; + + bool loop = true; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_EPG]); + + while(loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + scrollCount = medlinecount; + + switch ( msg ) + { + case NeutrinoMessages::EVT_TIMER: + if (data == g_InfoViewer->lcdUpdateTimer) { + GetEPGData(channel_id, id, &startzeit ); + if ( epg_done!= -1 ) { + int pbx = sx + 10 + widthl + 10 + ((ox-104-widthr-widthl-10-10-20)>>1); + timescale->reset(); + timescale->paint(pbx+2, sy+oy-height+2, epg_done); + } + } + CNeutrinoApp::getInstance()->handleMsg(msg, data); + break; + case NeutrinoMessages::EVT_CURRENTNEXT_EPG: + if (/*!id && */ ((*(t_channel_id *) data) == (channel_id & 0xFFFFFFFFFFFFULL))) { + show(channel_id); + showPos=0; + } + CNeutrinoApp::getInstance()->handleMsg(msg, data); + break; + case CRCInput::RC_left: + if (prev_id != 0) + { + frameBuffer->paintBoxRel(sx+ 5, sy+ oy- botboxheight+ 4, botboxheight- 8, botboxheight- 8, COL_MENUCONTENT_PLUS_1); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->RenderString(sx+ 10, sy+ oy- 3, widthr, "<", COL_MENUCONTENT + 1); + + show(channel_id, prev_id, &prev_zeit, false); + showPos=0; + } + break; + + case CRCInput::RC_right: + if (next_id != 0) + { + frameBuffer->paintBoxRel(sx+ ox- botboxheight+ 8- 5, sy+ oy- botboxheight+ 4, botboxheight- 8, botboxheight- 8, COL_MENUCONTENT_PLUS_1); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_DATE]->RenderString(sx+ ox- botboxheight+ 8, sy+ oy- 3, widthr, ">", COL_MENUCONTENT + 1); + + show(channel_id, next_id, &next_zeit, false); + showPos=0; + } + break; + + case CRCInput::RC_down: + if(showPos+scrollCountisTimerdAvailable()) + { + bool doRecord = true; + //char *recDir = g_settings.network_nfs_recordingdir; + strcpy(recDir, g_settings.network_nfs_recordingdir); + if (g_settings.recording_choose_direct_rec_dir == 2) { + CFileBrowser b; + b.Dir_Mode=true; + hide(); + if (b.exec(g_settings.network_nfs_recordingdir)) { + strcpy(recDir, b.getSelectedFile()->Name.c_str()); + } else + doRecord = false; + show(channel_id,epgData.eventID,&epgData.epg_times.startzeit,false); + } + else if (g_settings.recording_choose_direct_rec_dir == 1) + { + int id = -1; + CMountChooser recDirs(LOCALE_TIMERLIST_RECORDING_DIR,NEUTRINO_ICON_SETTINGS,&id,NULL,g_settings.network_nfs_recordingdir); + if (recDirs.hasItem()) + { + hide(); + recDirs.exec(NULL,""); + show(channel_id,epgData.eventID,&epgData.epg_times.startzeit,false); + } else + { + printf("no network devices available\n"); + } + if (id != -1) + strcpy(recDir, g_settings.network_nfs_local_dir[id]); + //recDir = g_settings.network_nfs_local_dir[id]; + //else + //recDir = NULL; + } + //if (recDir != NULL) + if (doRecord) + { + if (g_Timerd->addRecordTimerEvent(channel_id, + epgData.epg_times.startzeit, + epgData.epg_times.startzeit + epgData.epg_times.dauer, + epgData.eventID, epgData.epg_times.startzeit, + epgData.epg_times.startzeit - (ANNOUNCETIME + 120 ), + TIMERD_APIDS_CONF, true, recDir,false) == -1) + { + if(askUserOnTimerConflict(epgData.epg_times.startzeit - (ANNOUNCETIME + 120), + epgData.epg_times.startzeit + epgData.epg_times.dauer)) + { + g_Timerd->addRecordTimerEvent(channel_id, + epgData.epg_times.startzeit, + epgData.epg_times.startzeit + epgData.epg_times.dauer, + epgData.eventID, epgData.epg_times.startzeit, + epgData.epg_times.startzeit - (ANNOUNCETIME + 120 ), + TIMERD_APIDS_CONF, true, recDir,true); + ShowLocalizedMessage(LOCALE_TIMER_EVENTRECORD_TITLE, LOCALE_TIMER_EVENTRECORD_MSG, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + } + } else { + ShowLocalizedMessage(LOCALE_TIMER_EVENTRECORD_TITLE, LOCALE_TIMER_EVENTRECORD_MSG, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + } + } + } + else + printf("timerd not available\n"); + } + break; + + // 31.05.2002 dirch zapto timer + case CRCInput::RC_yellow: + { + //CTimerdClient timerdclient; + if(g_Timerd->isTimerdAvailable()) + { + g_Timerd->addZaptoTimerEvent(channel_id, + epgData.epg_times.startzeit, + epgData.epg_times.startzeit - ANNOUNCETIME, 0, + epgData.eventID, epgData.epg_times.startzeit, 0); + ShowLocalizedMessage(LOCALE_TIMER_EVENTTIMED_TITLE, LOCALE_TIMER_EVENTTIMED_MSG, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + } + else + printf("timerd not available\n"); + break; + } + + case CRCInput::RC_info: + case CRCInput::RC_help: + bigFonts = bigFonts ? false : true; + frameBuffer->paintBackgroundBox (sx, sy- toph, sx+ ox, sy+ oy); + showTimerEventBar (false); + start(); +//printf("bigFonts %d\n", bigFonts); + if(bigFonts) + { + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->setSize((int)(g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->getSize() * BIG_FONT_FAKTOR)); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->setSize((int)(g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->getSize() * BIG_FONT_FAKTOR)); + }else + { + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->setSize((int)(g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->getSize() / BIG_FONT_FAKTOR)); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->setSize((int)(g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->getSize() / BIG_FONT_FAKTOR)); + } + g_settings.bigFonts = bigFonts; + show(channel_id, id, &startzeit, false); + showPos=0; + break; + + case CRCInput::RC_ok: + case CRCInput::RC_timeout: + loop = false; + break; + case CRCInput::RC_favorites: + case CRCInput::RC_sat: + g_RCInput->postMsg (msg, 0); + loop = false; + break; + + default: + // konfigurierbare Keys handlen... + if (msg == (neutrino_msg_t)g_settings.key_channelList_cancel) + loop = false; + else + { + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + } + hide(); + } + return res; +} + +void CEpgData::hide() +{ + // 2004-09-10 rasc (bugfix, scale large font settings back to normal) + if (bigFonts) { + bigFonts = false; + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->setSize((int)(g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]->getSize() / BIG_FONT_FAKTOR)); + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->setSize((int)(g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2]->getSize() / BIG_FONT_FAKTOR)); + } + + frameBuffer->paintBackgroundBox (sx, sy- toph, sx+ ox, sy+ oy); + showTimerEventBar (false); +} + +bool sectionsd_getEPGid(const event_id_t epgID, const time_t startzeit, CEPGData * epgdata); +bool sectionsd_getActualEPGServiceKey(const t_channel_id uniqueServiceKey, CEPGData * epgdata); + +void CEpgData::GetEPGData(const t_channel_id channel_id, unsigned long long id, time_t* startzeit ) +{ + epgText.clear(); + emptyLineCount = 0; + epgData.title.clear(); + + bool res; + if ( id!= 0 ) + //res = g_Sectionsd->getEPGid( id, *startzeit, &epgData ); + res = sectionsd_getEPGid(id, *startzeit, &epgData); + else + //res = g_Sectionsd->getActualEPGServiceKey(channel_id&0xFFFFFFFFFFFFULL, &epgData ); + res = sectionsd_getActualEPGServiceKey(channel_id&0xFFFFFFFFFFFFULL, &epgData ); + + if ( res ) + { + // If we have items, merge and localize them (e.g. actor1, actor2, ... -> Actors) + if (false == epgData.itemDescriptions.empty()) { + reformatExtendedEvents("Year of production", g_Locale->getText(LOCALE_EPGEXTENDED_YEAR_OF_PRODUCTION), false, epgData); + reformatExtendedEvents("Original title", g_Locale->getText(LOCALE_EPGEXTENDED_ORIGINAL_TITLE), false, epgData); + reformatExtendedEvents("Director", g_Locale->getText(LOCALE_EPGEXTENDED_DIRECTOR), false, epgData); + reformatExtendedEvents("Actor", g_Locale->getText(LOCALE_EPGEXTENDED_ACTORS), true, epgData); + reformatExtendedEvents("Guests", g_Locale->getText(LOCALE_EPGEXTENDED_GUESTS), false, epgData); + reformatExtendedEvents("Presenter", g_Locale->getText(LOCALE_EPGEXTENDED_PRESENTER), false, epgData); + } + + struct tm *pStartZeit = localtime(&(epgData.epg_times).startzeit); + char temp[11]; + strftime( temp, sizeof(temp), "%d.%m.%Y", pStartZeit); + epg_date= temp; + strftime( temp, sizeof(temp), "%H:%M", pStartZeit); + epg_start= temp; + + long int uiEndTime((epgData.epg_times).startzeit+ (epgData.epg_times).dauer); + struct tm *pEndeZeit = localtime((time_t*)&uiEndTime); + strftime( temp, sizeof(temp), "%H:%M", pEndeZeit); + epg_end= temp; + + epg_done= -1; + if (( time(NULL)- (epgData.epg_times).startzeit )>= 0 ) + { + unsigned nProcentagePassed=(unsigned)((float)(time(NULL)-(epgData.epg_times).startzeit)/(float)(epgData.epg_times).dauer*100.); + if (nProcentagePassed<= 100) + epg_done= nProcentagePassed; + } + } +//printf("GetEPGData:: items %d descriptions %d\n", epgData.items.size(), epgData.itemDescriptions.size()); +} + +void CEpgData::GetPrevNextEPGData( unsigned long long id, time_t* startzeit ) +{ + prev_id= 0; + next_id= 0; + unsigned int i; + + for ( i= 0; i< evtlist.size(); i++ ) + { + //printf("%d %llx/%llx - %x %x\n", i, evtlist[i].eventID, id, evtlist[i].startTime, *startzeit); + if ( ( evtlist[i].eventID == id ) && ( evtlist[i].startTime == *startzeit ) ) + { + if ( i > 0 ) + { + prev_id= evtlist[i- 1].eventID; + prev_zeit= evtlist[i- 1].startTime; + } + if ( i < ( evtlist.size()- 1 ) ) + { + next_id= evtlist[i+ 1].eventID; + next_zeit= evtlist[i+ 1].startTime; + } + break; + } + } + /* Houdini: dirty RTL double event workaround, if prev/next event has same starttime as actual event skip it */ + if ((prev_zeit == *startzeit) && ((i-1) > 0)) + { + prev_id = evtlist[i- 2].eventID; + prev_zeit = evtlist[i- 2].startTime; + } + if ((next_zeit == *startzeit) && ((i+1) < (evtlist.size()- 1))) + { + next_id = evtlist[i+ 2].eventID; + next_zeit = evtlist[i+ 2].startTime; + } + +} + +// +// -- get following screenings of this program title +// -- yek! a better class design would be more helpfull +// -- BAD THING: Cross channel screenings will not be shown +// -- $$$TODO +// -- 2002-05-03 rasc +// + +int CEpgData::FollowScreenings (const t_channel_id channel_id, const std::string & title) + +{ + CChannelEventList::iterator e; + time_t curtime; + struct tm *tmStartZeit; + std::string screening_dates,screening_nodual; + int count; + char tmpstr[256]; + + + count = 0; + screening_dates = screening_nodual = ""; + // alredy read: evtlist = g_Sectionsd->getEventsServiceKey( channel_id&0xFFFFFFFFFFFFULL ); + curtime = time(NULL); + + for ( e= evtlist.begin(); e != evtlist.end(); ++e ) + { + if (e->startTime <= curtime) continue; + if (! e->eventID) continue; + if (e->description == title) { + count++; + tmStartZeit = localtime(&(e->startTime)); + + screening_dates = " "; + + screening_dates += g_Locale->getText(CLocaleManager::getWeekday(tmStartZeit)); + screening_dates += '.'; + + strftime(tmpstr, sizeof(tmpstr), " %d.", tmStartZeit ); + screening_dates += tmpstr; + + screening_dates += g_Locale->getText(CLocaleManager::getMonth(tmStartZeit)); + + strftime(tmpstr, sizeof(tmpstr), ". %H:%M ", tmStartZeit ); + screening_dates += tmpstr; + if (screening_dates != screening_nodual){ + screening_nodual=screening_dates; + processTextToArray(screening_dates ); // UTF-8 + } + } + } + if (count == 0) + processTextToArray("---\n"); // UTF-8 + return count; +} + + +// +// -- Just display or hide TimerEventbar +// -- 2002-05-13 rasc +// + +void CEpgData::showTimerEventBar (bool show) + +{ + int x,y,w,h; + int cellwidth; // 4 cells + int h_offset, pos; + + w = ox; + h = 30; + x = sx; + y = sy + oy; + h_offset = 5; + cellwidth = w / 4; + + + frameBuffer->paintBackgroundBoxRel(x,y,w,h); + // hide only? + if (! show) return; + + frameBuffer->paintBoxRel(x,y,w,h, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2);//round + + // Button: Timer Record & Channelswitch + if (g_settings.recording_type != CNeutrinoApp::RECORDING_OFF) + { + pos = 0; + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_RED, x+8+cellwidth*pos, y+h_offset ); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+29+cellwidth*pos, y+h-h_offset, w-30, g_Locale->getText(LOCALE_TIMERBAR_RECORDEVENT), COL_INFOBAR, 0, true); // UTF-8 + } + // Button: Timer Channelswitch + pos = 2; + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_YELLOW, x+8+cellwidth*pos, y+h_offset ); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+29+cellwidth*pos, y+h-h_offset, w-30, g_Locale->getText(LOCALE_TIMERBAR_CHANNELSWITCH), COL_INFOBAR, 0, true); // UTF-8 +} + +// -- EPG Data Viewer Menu Handler Class +// -- to be used for calls from Menue +// -- (2004-03-06 rasc) + +int CEPGDataHandler::exec(CMenuTarget* parent, const std::string &actionkey) +{ + int res = menu_return::RETURN_EXIT_ALL; + CChannelList *channelList; + CEpgData *e; + + + if (parent) { + parent->hide(); + } + + e = new CEpgData; + + channelList = CNeutrinoApp::getInstance()->channelList; + e->show( channelList->getActiveChannel_ChannelID() ); + delete e; + + return res; +} diff --git a/src/gui/epgview.h b/src/gui/epgview.h new file mode 100644 index 000000000..f536429cd --- /dev/null +++ b/src/gui/epgview.h @@ -0,0 +1,108 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __epgview__ +#define __epgview__ + +#include +#include +#include +#include + +#include +#include "widget/menue.h" + +#include + +#include +#include + + +#define BIG_FONT_FAKTOR 1.5 + +class CEpgData +{ + private: + CFrameBuffer *frameBuffer; + CChannelEventList evtlist; + CEPGData epgData; + + std::string epg_date; + std::string epg_start; + std::string epg_end; + int epg_done; + bool bigFonts; + + unsigned long long prev_id; + time_t prev_zeit; + unsigned long long next_id; + time_t next_zeit; + + int ox, oy, sx, sy, toph, sb; + int emptyLineCount, info1_lines; + int textCount; + std::vector epgText; + int topheight,topboxheight; + int botheight,botboxheight; + int medlineheight,medlinecount; + + void GetEPGData(const t_channel_id channel_id, unsigned long long id, time_t* startzeit ); + void GetPrevNextEPGData( unsigned long long id, time_t* startzeit ); + void addTextToArray( const std::string & text ); + void processTextToArray(std::string text); + void showText( int startPos, int ypos ); + bool hasFollowScreenings(const t_channel_id channel_id, const std::string & title); + int FollowScreenings(const t_channel_id channel_id, const std::string & title); + void showTimerEventBar(bool show); + void showHead(const t_channel_id channel_id); + + public: + + CEpgData(); + void start( ); + int show(const t_channel_id channel_id, unsigned long long id = 0, time_t* startzeit = NULL, bool doLoop = true ); + void hide(); +}; + + + +class CEPGDataHandler : public CMenuTarget +{ + public: + int exec( CMenuTarget* parent, const std::string &actionkey); + +}; + + + +#endif + diff --git a/src/gui/eventlist.cpp b/src/gui/eventlist.cpp new file mode 100644 index 000000000..701d03221 --- /dev/null +++ b/src/gui/eventlist.cpp @@ -0,0 +1,1077 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "widget/hintbox.h" +#include "gui/bouquetlist.h" +#include + +extern CBouquetList * bouquetList; +extern t_channel_id live_channel_id; + +#include /* CZapitClient::Utf8_to_Latin1 */ +#include + +#include + +#include +extern CPictureViewer * g_PicViewer; +#define PIC_W 52 +#define PIC_H 39 + +#define ROUND_RADIUS 9 + +void sectionsd_getEventsServiceKey(t_channel_id serviceUniqueKey, CChannelEventList &eList, char search = 0, std::string search_text = ""); +bool sectionsd_getActualEPGServiceKey(const t_channel_id uniqueServiceKey, CEPGData * epgdata); +bool sectionsd_getLinkageDescriptorsUniqueKey(const event_id_t uniqueKey, CSectionsdClient::LinkageDescriptorList& descriptors); + +// sort operators +bool sortById (const CChannelEvent& a, const CChannelEvent& b) +{ + return a.eventID < b.eventID ; +} +bool sortByDescription (const CChannelEvent& a, const CChannelEvent& b) +{ + if(a.description == b.description) + return a.eventID < b.eventID; + else + return a.description < b.description ; +} +static bool sortByDateTime (const CChannelEvent& a, const CChannelEvent& b) +{ + return a.startTime < b.startTime; +} + +EventList::EventList() +{ + frameBuffer = CFrameBuffer::getInstance(); + selected = 0; + current_event = 0; + liststart = 0; + sort_mode = 0; + + m_search_list = SEARCH_LIST_NONE; + m_search_epg_item = SEARCH_LIST_NONE; + m_search_epg_item = SEARCH_EPG_TITLE; + m_search_channel_id = 1; + m_search_bouquet_id= 1; +} + +EventList::~EventList() +{ +} + +void EventList::readEvents(const t_channel_id channel_id) +{ + //evtlist = g_Sectionsd->getEventsServiceKey(channel_id &0xFFFFFFFFFFFFULL); + evtlist.clear(); + sectionsd_getEventsServiceKey(channel_id &0xFFFFFFFFFFFFULL, evtlist); + time_t azeit=time(NULL); + + CChannelEventList::iterator e; + + if ( evtlist.size() != 0 ) { + + CEPGData epgData; + // todo: what if there are more than one events in the Portal + //if (g_Sectionsd->getActualEPGServiceKey(channel_id&0xFFFFFFFFFFFFULL, &epgData )) + if (sectionsd_getActualEPGServiceKey(channel_id&0xFFFFFFFFFFFFULL, &epgData )) + { +// epgData.eventID; +// epgData.epg_times.startzeit; + CSectionsdClient::LinkageDescriptorList linkedServices; + //if ( g_Sectionsd->getLinkageDescriptorsUniqueKey( epgData.eventID, linkedServices ) ) + if ( sectionsd_getLinkageDescriptorsUniqueKey( epgData.eventID, linkedServices ) ) + { + if ( linkedServices.size()> 1 ) + { + CChannelEventList evtlist2; // stores the temporary eventlist of the subchannel channelid + t_channel_id channel_id2; +#if 0 + for (e=evtlist.begin(); e!=evtlist.end(); ++e ) + { + if ( e->startTime > azeit ) { + break; + } + } + // next line is to have a valid e + if (evtlist.end() == e) --e; +#endif + for (unsigned int i=0; igetEventsServiceKey(channel_id2); + evtlist2.clear(); + sectionsd_getEventsServiceKey(channel_id2 &0xFFFFFFFFFFFFULL, evtlist2); + + for (unsigned int loop=0 ; loop= azeit) /*&& + (evtlist2[loop].startTime < e->startTime + (int)e->duration)*/ ) +#endif + { + //FIXME: bad ?evtlist2[loop].sub = true; + evtlist.push_back(evtlist2[loop]); + } + } + evtlist2.clear(); + } + } + } + } + } + // Houdini added for Private Premiere EPG, start sorted by start date/time + sort(evtlist.begin(),evtlist.end(),sortByDateTime); + // Houdini: dirty workaround for RTL double events, remove them + CChannelEventList::iterator e2; + for ( e=evtlist.begin(); e!=evtlist.end(); ++e ) + { + e2 = e+1; + if ( e2!=evtlist.end() && (e->startTime == e2->startTime)) { + evtlist.erase(e2); + } + } + timerlist.clear(); + g_Timerd->getTimerList (timerlist); + + } + + current_event = (unsigned int)-1; + for ( e=evtlist.begin(); e!=evtlist.end(); ++e ) + { + if ( e->startTime > azeit ) { + break; + } + current_event++; + } + + if ( evtlist.size() == 0 ) + { + CChannelEvent evt; + + evt.description = g_Locale->getText(LOCALE_EPGLIST_NOEVENTS); + evt.eventID = 0; + evtlist.push_back(evt); + + } + if (current_event == (unsigned int)-1) + current_event = 0; + selected= current_event; + + return; +} + + +int EventList::exec(const t_channel_id channel_id, const std::string& channelname) // UTF-8 +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + bool in_search = 0; + + width = w_max (580, 20); + height = h_max (480, 20); + + iheight = 30; // info bar height (see below, hard coded at this time) + theight = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_TITLE]->getHeight(); + + if(theight < PIC_H) theight = PIC_H; + + fheight1 = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMLARGE]->getHeight(); + { + int h1 = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMSMALL]->getHeight(); + int h2 = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_DATETIME]->getHeight(); + fheight2 = (h1 > h2) ? h1 : h2; + } + fheight = fheight1 + fheight2 + 2; + fwidth1 = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_DATETIME]->getRenderWidth("DDD, 00:00, "); + fwidth2 = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMSMALL]->getRenderWidth("[999 min] "); + + + listmaxshow = (height-theight-iheight-0)/fheight; + height = theight+iheight+0+listmaxshow*fheight; // recalc height + + x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - height) / 2; + + int res = menu_return::RETURN_REPAINT; +//printf("EventList::exec: channel_id %llx\n", channel_id); + if(m_search_list == SEARCH_LIST_NONE) // init globals once only + { + m_search_epg_item = SEARCH_EPG_TITLE; + //m_search_keyword = ""; + m_search_list = SEARCH_LIST_CHANNEL; + //m_search_channel_id = channel_id; + m_search_bouquet_id= bouquetList->getActiveBouquetNumber(); + //m_search_source_text = ""; + } + m_search_channel_id = channel_id; + m_showChannel = false; // do not show the channel in normal mode, we just need it in search mode + + name = channelname; + sort_mode=0; + paintHead(channel_id); + readEvents(channel_id); + paint(channel_id); + showFunctionBar(true); + + int oldselected = selected; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]); + + bool loop = true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]); + + if (msg == CRCInput::RC_up || (int) msg == g_settings.key_channelList_pageup) + { + int step = 0; + int prev_selected = selected; + + step = ((int) msg == g_settings.key_channelList_pageup) ? listmaxshow : 1; // browse or step 1 + selected -= step; + if((prev_selected-step) < 0) // because of uint + selected = evtlist.size() - 1; + + paintItem(prev_selected - liststart, channel_id); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + + if(oldliststart!=liststart) + paint(channel_id); + else + paintItem(selected - liststart, channel_id); + +#if 0 + if ((g_settings.key_channelList_addremind != CRCInput::RC_nokey) || + ((g_settings.recording_type != CNeutrinoApp::RECORDING_OFF) && + (g_settings.key_channelList_addrecord != CRCInput::RC_nokey))) + { + showFunctionBar(true); + } +#endif + } + else if (msg == CRCInput::RC_down || (int) msg == g_settings.key_channelList_pagedown) + { + unsigned int step = 0; + int prev_selected = selected; + + step = ((int) msg == g_settings.key_channelList_pagedown) ? listmaxshow : 1; // browse or step 1 + selected += step; + + if(selected >= evtlist.size()) { + if (((evtlist.size() / listmaxshow) + 1) * listmaxshow == evtlist.size() + listmaxshow) // last page has full entries + selected = 0; + else + selected = ((step == listmaxshow) && (selected < (((evtlist.size() / listmaxshow) + 1) * listmaxshow))) ? (evtlist.size() - 1) : 0; + } + + paintItem(prev_selected - liststart, channel_id); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + paint(channel_id); + else + paintItem(selected - liststart, channel_id); +#if 0 + if ((g_settings.key_channelList_addremind != CRCInput::RC_nokey) || + ((g_settings.recording_type != CNeutrinoApp::RECORDING_OFF) && + (g_settings.key_channelList_addrecord != CRCInput::RC_nokey))) + { + showFunctionBar(true); + } +#endif + } + + else if (msg == (neutrino_msg_t)g_settings.key_channelList_sort) + { + unsigned long long selected_id = evtlist[selected].eventID; + if(sort_mode==0) + { + sort_mode++; + sort(evtlist.begin(),evtlist.end(),sortByDescription); + } +#if 0 + else if(sort_mode==1) + { + sort_mode++; + sort(evtlist.begin(),evtlist.end(),sortById); + } +#endif + else + { + sort_mode=0; + sort(evtlist.begin(),evtlist.end(),sortByDateTime); + } + // find selected + for ( selected=0 ; selected < evtlist.size(); selected++ ) + { + if ( evtlist[selected].eventID == selected_id ) + break; + } + oldselected=selected; + if(selected <=listmaxshow) + liststart=0; + else + liststart=(selected/listmaxshow)*listmaxshow; + hide(); + paintHead(channel_id); + paint(channel_id); + showFunctionBar(true); + + } + + // -- I commented out the following part (code is working) + // -- reason: this is a little bit confusing, because e.g. you can enter the function + // -- with RED, but pressing RED doesn't leave - it triggers a record timer instead + // -- I think it's sufficient, to press RIGHT or HELP to get movie details and then + // -- press "auto record" or "auto switch" (rasc 2003-06-28) + // --- hm, no need to comment out that part, leave the decision to the user + // --- either set addrecord timer key to "no key" and leave eventlist with red (default now), + // --- or set addrecord timer key to "red key" (zwen 2003-07-29) + + else if ((msg == (neutrino_msg_t)g_settings.key_channelList_addrecord) && !g_settings.minimode) + { + if (g_settings.recording_type != CNeutrinoApp::RECORDING_OFF) + { + int tID = -1; + CTimerd::CTimerEventTypes etype = isScheduled(channel_id, &evtlist[selected], &tID); + if(etype == CTimerd::TIMER_RECORD) { + g_Timerd->removeTimerEvent(tID); + timerlist.clear(); + g_Timerd->getTimerList (timerlist); + paint(channel_id); + continue; + } + char *recDir = g_settings.network_nfs_recordingdir; + if (g_settings.recording_choose_direct_rec_dir) + { + int id = -1; + CMountChooser recDirs(LOCALE_TIMERLIST_RECORDING_DIR,NEUTRINO_ICON_SETTINGS,&id,NULL,g_settings.network_nfs_recordingdir); + if (recDirs.hasItem()) + { + hide(); + recDirs.exec(NULL,""); + paint(channel_id); + } else + { + printf("[CEventList] no network devices available\n"); + } + if (id != -1) + recDir = g_settings.network_nfs_local_dir[id]; + else + recDir = NULL; + } + if (recDir != NULL) + { + + //FIXME: bad ?if (g_Timerd->addRecordTimerEvent(evtlist[selected].sub ? GET_CHANNEL_ID_FROM_EVENT_ID(evtlist[selected].eventID) : channel_id, + if (g_Timerd->addRecordTimerEvent(channel_id, + evtlist[selected].startTime, + evtlist[selected].startTime + evtlist[selected].duration, + evtlist[selected].eventID, evtlist[selected].startTime, + evtlist[selected].startTime - (ANNOUNCETIME + 120), + TIMERD_APIDS_CONF, true, recDir,false) == -1) + { + if(askUserOnTimerConflict(evtlist[selected].startTime - (ANNOUNCETIME + 120), + evtlist[selected].startTime + evtlist[selected].duration)) + { + //g_Timerd->addRecordTimerEvent(evtlist[selected].sub ? GET_CHANNEL_ID_FROM_EVENT_ID(evtlist[selected].eventID) : channel_id, + g_Timerd->addRecordTimerEvent(channel_id, + evtlist[selected].startTime, + evtlist[selected].startTime + evtlist[selected].duration, + evtlist[selected].eventID, evtlist[selected].startTime, + evtlist[selected].startTime - (ANNOUNCETIME + 120), + TIMERD_APIDS_CONF, true, recDir,true); + ShowLocalizedMessage(LOCALE_TIMER_EVENTRECORD_TITLE, LOCALE_TIMER_EVENTRECORD_MSG, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + } + } else { + ShowLocalizedMessage(LOCALE_TIMER_EVENTRECORD_TITLE, LOCALE_TIMER_EVENTRECORD_MSG, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + } + } + timerlist.clear(); + g_Timerd->getTimerList (timerlist); + paint(channel_id); + } + } + else if ( msg == (neutrino_msg_t) g_settings.key_channelList_addremind ) + { + int tID = -1; + CTimerd::CTimerEventTypes etype = isScheduled(channel_id, &evtlist[selected], &tID); + if(etype == CTimerd::TIMER_ZAPTO) { + g_Timerd->removeTimerEvent(tID); + timerlist.clear(); + g_Timerd->getTimerList (timerlist); + paint(channel_id); + continue; + } + // FIXME g_Timerd->addZaptoTimerEvent(evtlist[selected].sub ? GET_CHANNEL_ID_FROM_EVENT_ID(evtlist[selected].eventID) : channel_id, + g_Timerd->addZaptoTimerEvent(channel_id, + evtlist[selected].startTime, + evtlist[selected].startTime - ANNOUNCETIME, 0, + evtlist[selected].eventID, evtlist[selected].startTime, 0); + ShowLocalizedMessage(LOCALE_TIMER_EVENTTIMED_TITLE, LOCALE_TIMER_EVENTTIMED_MSG, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + timerlist.clear(); + g_Timerd->getTimerList (timerlist); + paint(channel_id); + } + + else if (msg == CRCInput::RC_timeout) + { + selected = oldselected; + loop = false; + } + else if (msg == (neutrino_msg_t)g_settings.key_channelList_cancel) + { + if(in_search) { + in_search = false; + name = channelname; + paintHead(channel_id); + readEvents(channel_id); + paint(channel_id); + showFunctionBar(true); + } else { + selected = oldselected; + loop = false; + } + } + else if ( msg==CRCInput::RC_left || msg==CRCInput::RC_red ) + { + loop= false; + } + else if (msg==CRCInput::RC_help || msg==CRCInput::RC_right || msg==CRCInput::RC_ok || msg==CRCInput::RC_info) + { + if ( evtlist[selected].eventID != 0 ) + { + hide(); + + //FIXME res = g_EpgData->show(evtlist[selected].sub ? GET_CHANNEL_ID_FROM_EVENT_ID(evtlist[selected].eventID) : channel_id, evtlist[selected].eventID, &evtlist[selected].startTime); + res = g_EpgData->show(channel_id, evtlist[selected].eventID, &evtlist[selected].startTime); + if ( res == menu_return::RETURN_EXIT_ALL ) + { + loop = false; + } + else + { + g_RCInput->getMsg( &msg, &data, 0 ); + + if ( ( msg != CRCInput::RC_red ) && ( msg != CRCInput::RC_timeout ) ) + { + // RC_red schlucken + g_RCInput->postMsg( msg, data ); + } + timerlist.clear(); + g_Timerd->getTimerList (timerlist); + + paintHead(channel_id); + paint(channel_id); + showFunctionBar(true); + } + } + } + else if ( msg==CRCInput::RC_green ) + { + in_search = findEvents(); + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_CHANLIST]); + } + else if (msg == CRCInput::RC_sat || msg == CRCInput::RC_favorites) { + g_RCInput->postMsg (msg, 0); + res = menu_return::RETURN_EXIT_ALL; + loop = false; + } + else + { + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + + hide(); + + return res; +} + +void EventList::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height); + showFunctionBar (false); + +} + +CTimerd::CTimerEventTypes EventList::isScheduled(t_channel_id channel_id, CChannelEvent * event, int * tID) +{ + CTimerd::TimerList::iterator timer = timerlist.begin(); + for(; timer != timerlist.end(); timer++) { + if(timer->channel_id == channel_id && (timer->eventType == CTimerd::TIMER_ZAPTO || timer->eventType == CTimerd::TIMER_RECORD)) { + if(timer->epgID == event->eventID) { + if(timer->epg_starttime == event->startTime) { + if(tID) + *tID = timer->eventID; + return timer->eventType; + } + } + } + } + return (CTimerd::CTimerEventTypes) 0; +} + +void EventList::paintItem(unsigned int pos, t_channel_id channel_id) +{ + uint8_t color; + fb_pixel_t bgcolor; + int ypos = y+ theight+0 + pos*fheight; + std::string datetime1_str, datetime2_str, duration_str; + const char * icontype = 0; + + if (liststart+pos==selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + else if (liststart+pos == current_event ) + { + color = COL_MENUCONTENT + 1; + bgcolor = COL_MENUCONTENT_PLUS_1; + } + else + { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + } + + frameBuffer->paintBoxRel(x, ypos, width- 15, fheight, bgcolor, color == COL_MENUCONTENTSELECTED ? ROUND_RADIUS : 0, 3); + + if(liststart+posgetText(CLocaleManager::getWeekday(tmStartZeit)); + + strftime(tmpstr, sizeof(tmpstr), ". %H:%M, ", tmStartZeit ); + datetime1_str += tmpstr; + + strftime(tmpstr, sizeof(tmpstr), " %d. ", tmStartZeit ); + datetime2_str = tmpstr; + + datetime2_str += g_Locale->getText(CLocaleManager::getMonth(tmStartZeit)); + + datetime2_str += '.'; + + if ( m_showChannel ) // show the channel if we made a event search only (which could be made through all channels ). + { + t_channel_id channel = evtlist[liststart+pos].get_channel_id(); + datetime2_str += " "; + datetime2_str += g_Zapit->getChannelName(channel); + } + + sprintf(tmpstr, "[%d min]", evtlist[liststart+pos].duration / 60 ); + duration_str = tmpstr; +#if 0 + CTimerd::TimerList::iterator timer = timerlist.begin(); + for(; timer != timerlist.end(); timer++) { + if(timer->channel_id == channel_id && (timer->eventType == CTimerd::TIMER_ZAPTO || timer->eventType == CTimerd::TIMER_RECORD)) { + if(timer->epgID == evtlist[liststart+pos].eventID) { + if(timer->epg_starttime == evtlist[liststart+pos].startTime) + icontype = timer->eventType == CTimerd::TIMER_ZAPTO ? NEUTRINO_ICON_BUTTON_YELLOW : NEUTRINO_ICON_BUTTON_RED; + break; + } + } + } +#endif + } + CTimerd::CTimerEventTypes etype = isScheduled(channel_id, &evtlist[liststart+pos]); + icontype = etype == CTimerd::TIMER_ZAPTO ? NEUTRINO_ICON_BUTTON_YELLOW : etype == CTimerd::TIMER_RECORD ? NEUTRINO_ICON_BUTTON_RED : 0; + + // 1st line + g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_DATETIME]->RenderString(x+5, ypos+ fheight1+3, fwidth1+5, datetime1_str, color, 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_DATETIME]->RenderString(x+5+fwidth1, ypos+ fheight1+3, width-fwidth1-10- 20, datetime2_str, color, 0, true); // UTF-8 + + int seit = ( evtlist[liststart+pos].startTime - time(NULL) ) / 60; + if ( (seit> 0) && (seit<100) && (duration_str.length()!=0) ) + { + char beginnt[100]; + sprintf((char*) &beginnt, "in %d min", seit); + int w = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMSMALL]->getRenderWidth(beginnt) + 10; + + g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMSMALL]->RenderString(x+width-fwidth2-5- 20- w, ypos+ fheight1+3, fwidth2, beginnt, color); + } + g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMSMALL]->RenderString(x+width-fwidth2-5- 20, ypos+ fheight1+3, fwidth2, duration_str, color, 0, true); // UTF-8 + if(icontype != 0) + frameBuffer->paintIcon(icontype, x+2, ypos + fheight - 16 - (fheight1 - 16)/2); + // 2nd line + g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMLARGE]->RenderString(x+ 20, ypos+ fheight, width- 25- 20, evtlist[liststart+pos].description, color, 0, true); + } +} + +void EventList::paintHead(t_channel_id channel_id) +{ + bool logo_ok = false; + + frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); +#ifndef FB_USE_PALETTE + logo_ok = g_PicViewer->DisplayLogo(channel_id, x+10, y+(theight-PIC_H)/2, PIC_W, PIC_H); +#endif + g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_TITLE]->RenderString(x+15+(logo_ok? 5+PIC_W:0),y+theight+1, width, name.c_str(), COL_MENUHEAD, 0, true); // UTF-8 +} + +void EventList::paint(t_channel_id channel_id) +{ + liststart = (selected/listmaxshow)*listmaxshow; + + if (evtlist[0].eventID != 0) + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, x+ width- 30, y+ 5 ); + + frameBuffer->paintBoxRel(x, y+theight, width, height-theight-iheight, COL_MENUCONTENT_PLUS_0, 0, 1); + for(unsigned int count=0;countpaintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((evtlist.size()- 1)/ listmaxshow)+ 1; + float sbh= (sb- 4)/ sbc; + int sbs= (selected/listmaxshow); + + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ int(sbs* sbh) , 11, int(sbh), COL_MENUCONTENT_PLUS_3); + +} + +void EventList::showFunctionBar (bool show) +{ + int bx,by,bw,bh; + int cellwidth; // 4 cells + int h_offset, pos; + int bdx; + + bw = width; + bh = iheight; + bx = x; + by = y + height-iheight; + h_offset = 5; + cellwidth = bw / 4; + bdx = iheight-1; + + + frameBuffer->paintBackgroundBoxRel(bx,by,bw,bh); + // -- hide only? + if (! show) return; + + // -- frameBuffer->paintBoxRel(x,y,w,h, COL_INFOBAR_SHADOW_PLUS_1); + //frameBuffer->paintBoxRel(bx,by,bw,bh, COL_MENUHEAD_PLUS_0); + frameBuffer->paintBoxRel(bx,by,bw,bh, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2); + + + // -- Button: Timer Record & Channelswitch + if ((g_settings.recording_type != CNeutrinoApp::RECORDING_OFF) && + ((unsigned int) g_settings.key_channelList_addrecord != CRCInput::RC_nokey)) + { + pos = 0; +#warning FIXME: display other icons depending on g_settings.key_channelList_addrecord + if ((g_settings.key_channelList_addrecord == CRCInput::RC_red) && !g_settings.minimode) { + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_RED, bx+8+cellwidth*pos, by+h_offset); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(bx+bdx+cellwidth*pos, by+bh-h_offset, bw-30, g_Locale->getText(LOCALE_EVENTLISTBAR_RECORDEVENT), COL_INFOBAR, 0, true); // UTF-8 + } + } + if (1) + { + pos = 1; + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_GREEN, bx+8+cellwidth*pos, by+h_offset); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(bx+bdx+cellwidth*pos, by+bh-h_offset, bw-30, g_Locale->getText(LOCALE_EVENTFINDER_SEARCH), COL_INFOBAR, + 0, true); // UTF-8 + } + + // Button: Timer Channelswitch + if ((unsigned int) g_settings.key_channelList_addremind != CRCInput::RC_nokey) + { + pos = 2; +#warning FIXME: display other icons depending on g_settings.key_channelList_addremind + if (g_settings.key_channelList_addremind == CRCInput::RC_yellow) + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_YELLOW, bx+8+cellwidth*pos, by+h_offset ); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(bx+bdx+cellwidth*pos, by+bh-h_offset, bw-30, g_Locale->getText(LOCALE_EVENTLISTBAR_CHANNELSWITCH), COL_INFOBAR, 0, true); // UTF-8 + } + + // Button: Event Re-Sort + if ((unsigned int) g_settings.key_channelList_sort != CRCInput::RC_nokey) + { + pos = 3; +#warning FIXME: display other icons depending on g_settings.key_channelList_sort value + if (g_settings.key_channelList_sort == CRCInput::RC_blue) + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_BLUE, bx+8+cellwidth*pos, by+h_offset ); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(bx+bdx+cellwidth*pos, by+bh-h_offset, bw-30, g_Locale->getText(LOCALE_EVENTLISTBAR_EVENTSORT), COL_INFOBAR, 0, true); // UTF-8 + } +} + +int CEventListHandler::exec(CMenuTarget* parent, const std::string &actionkey) +{ + int res = menu_return::RETURN_EXIT_ALL; + EventList *e; + CChannelList *channelList; + + + if (parent) { + parent->hide(); + } + + e = new EventList; + + channelList = CNeutrinoApp::getInstance()->channelList; + //e->exec(channelList->getActiveChannel_ChannelID(), channelList->getActiveChannelName()); // UTF-8 + //e->exec(g_Zapit->getCurrentServiceID(), channelList->getActiveChannelName()); // UTF-8 + e->exec(live_channel_id, channelList->getActiveChannelName()); // UTF-8 + delete e; + + return res; +} + + + +/************************************************************************************************/ +int EventList::findEvents(void) +/************************************************************************************************/ +{ + int res = 0; + int event = 0; + t_channel_id channel_id; //g_Zapit->getCurrentServiceID() + + CEventFinderMenu menu( &event, + &m_search_epg_item, + &m_search_keyword, + &m_search_list, + &m_search_channel_id, + &m_search_bouquet_id + ); + hide(); + menu.exec(NULL,""); + + if(event == 1) + { + res = 1; + m_showChannel = true; // force the event list to paint the channel name + evtlist.clear(); + if(m_search_list == SEARCH_LIST_CHANNEL) + { + //g_Sectionsd->getEventsServiceKeySearchAdd(evtlist,m_search_channel_id & 0xFFFFFFFFFFFFULL,m_search_epg_item,m_search_keyword); + sectionsd_getEventsServiceKey(m_search_channel_id & 0xFFFFFFFFFFFFULL, evtlist, m_search_epg_item,m_search_keyword); + } + else if(m_search_list == SEARCH_LIST_BOUQUET) + { + int channel_nr = bouquetList->Bouquets[m_search_bouquet_id]->channelList->getSize(); + for(int channel = 0; channel < channel_nr; channel++) + { + channel_id = bouquetList->Bouquets[m_search_bouquet_id]->channelList->getChannelFromIndex(channel)->channel_id; + //g_Sectionsd->getEventsServiceKeySearchAdd(evtlist,channel_id & 0xFFFFFFFFFFFFULL,m_search_epg_item,m_search_keyword); + sectionsd_getEventsServiceKey(channel_id & 0xFFFFFFFFFFFFULL, evtlist, m_search_epg_item,m_search_keyword); + } + } + else if(m_search_list == SEARCH_LIST_ALL) + { + CHintBox box(LOCALE_TIMING_EPG,g_Locale->getText(LOCALE_EVENTFINDER_SEARCHING)); + box.paint(); + int bouquet_nr = bouquetList->Bouquets.size(); + for(int bouquet = 0; bouquet < bouquet_nr; bouquet++) + { + int channel_nr = bouquetList->Bouquets[bouquet]->channelList->getSize(); + for(int channel = 0; channel < channel_nr; channel++) + { + channel_id = bouquetList->Bouquets[bouquet]->channelList->getChannelFromIndex(channel)->channel_id; + //g_Sectionsd->getEventsServiceKeySearchAdd(evtlist,channel_id & 0xFFFFFFFFFFFFULL,m_search_epg_item,m_search_keyword); + sectionsd_getEventsServiceKey(channel_id & 0xFFFFFFFFFFFFULL,evtlist, m_search_epg_item,m_search_keyword); + } + } + box.hide(); + } + sort(evtlist.begin(),evtlist.end(),sortByDateTime); + current_event = (unsigned int)-1; + time_t azeit=time(NULL); + + CChannelEventList::iterator e; + for ( e=evtlist.begin(); e!=evtlist.end(); ++e ) + { + if ( e->startTime > azeit ) { + break; + } + current_event++; + } + if(evtlist.empty()) + { + if ( evtlist.size() == 0 ) + { + CChannelEvent evt; + //evt.description = m_search_keyword + ": " + g_Locale->getText(LOCALE_EPGVIEWER_NOTFOUND); + evt.description = g_Locale->getText(LOCALE_EPGVIEWER_NOTFOUND); + evt.eventID = 0; + evtlist.push_back(evt); + } + } + if (current_event == (unsigned int)-1) + current_event = 0; + selected= current_event; + + name = g_Locale->getText(LOCALE_EVENTFINDER_SEARCH); + name += ": '"; + name += m_search_keyword; + name += "'"; + } + paintHead(0); + paint(); + showFunctionBar(true); + return(res); +} + +/************************************************************************************************/ +/* +class CSearchNotifier : public CChangeObserver +{ + private: + CMenuItem* menuItem; + public: + CSearchNotifier( CMenuItem* i){menuItem=i}; + bool changeNotify(const neutrino_locale_t t, void * data) + { + int selected = *(int*)data; + menuItem->setActive(1); + menuItem + } +}; +*/ +/************************************************************************************************ +bool CEventFinderMenuHandler::changeNotify(const neutrino_locale_t OptionName, void *Data) +{ + if(OptionName == ) + { + } + + return true; +} +*/ + +#define SEARCH_LIST_OPTION_COUNT 3 +const CMenuOptionChooser::keyval SEARCH_LIST_OPTIONS[SEARCH_LIST_OPTION_COUNT] = +{ +// { EventList::SEARCH_LIST_NONE , LOCALE_PICTUREVIEWER_RESIZE_NONE }, + { EventList::SEARCH_LIST_CHANNEL , LOCALE_TIMERLIST_CHANNEL }, + { EventList::SEARCH_LIST_BOUQUET , LOCALE_BOUQUETLIST_HEAD }, + { EventList::SEARCH_LIST_ALL , LOCALE_CHANNELLIST_HEAD } +}; + + +#define SEARCH_EPG_OPTION_COUNT 3 +const CMenuOptionChooser::keyval SEARCH_EPG_OPTIONS[SEARCH_EPG_OPTION_COUNT] = +{ +// { EventList::SEARCH_EPG_NONE , LOCALE_PICTUREVIEWER_RESIZE_NONE }, + { EventList::SEARCH_EPG_TITLE , LOCALE_FONTSIZE_EPG_TITLE }, + { EventList::SEARCH_EPG_INFO1 , LOCALE_FONTSIZE_EPG_INFO1 }, + { EventList::SEARCH_EPG_INFO2 , LOCALE_FONTSIZE_EPG_INFO2 } +// ,{ EventList::SEARCH_EPG_GENRE , LOCALE_MOVIEBROWSER_INFO_GENRE_MAJOR } +}; + + + +/************************************************************************************************/ +CEventFinderMenu::CEventFinderMenu( int* event, + int* search_epg_item, + std::string* search_keyword, + int* search_list, + t_channel_id* search_channel_id, + t_bouquet_id* search_bouquet_id) +/************************************************************************************************/ +{ + m_event = event; + m_search_epg_item = search_epg_item; + m_search_keyword = search_keyword; + m_search_list = search_list; + m_search_channel_id = search_channel_id; + m_search_bouquet_id = search_bouquet_id; +} + + +/************************************************************************************************/ +int CEventFinderMenu::exec(CMenuTarget* parent, const std::string &actionkey) +/************************************************************************************************/ +{ + int res = menu_return::RETURN_REPAINT; + + + if(actionkey =="") + { + if(parent != NULL) + parent->hide(); + //printf("0\n"); + showMenu(); + } + else if(actionkey =="1") + { + //printf("1\n"); + *m_event = true; + res = menu_return::RETURN_EXIT_ALL; + } + else if(actionkey =="2") + { + //printf("2\n"); + /* + if(*m_search_list == EventList::SEARCH_LIST_CHANNEL) + { + mf[1]->setActive(true); + m_search_channelname = g_Zapit->getChannelName(*m_search_channel_id);; + } + else if(*m_search_list == EventList::SEARCH_LIST_BOUQUET) + { + mf[1]->setActive(true); + m_search_channelname = bouquetList->Bouquets[*m_search_bouquet_id]->channelList->getName(); + } + else if(*m_search_list == EventList::SEARCH_LIST_ALL) + { + mf[1]->setActive(false); + m_search_channelname = ""; + } + */ + } + else if(actionkey =="3") + { + //printf("3\n"); + // get channel id / bouquet id + if(*m_search_list == EventList::SEARCH_LIST_CHANNEL) + { + int nNewChannel; + int nNewBouquet; + nNewBouquet = bouquetList->show(); + //printf("new_bouquet_id %d\n",nNewBouquet); + if (nNewBouquet > -1) + { + nNewChannel = bouquetList->Bouquets[nNewBouquet]->channelList->show(); + //printf("nNewChannel %d\n",nNewChannel); + if (nNewChannel > -1) + { + *m_search_bouquet_id = nNewBouquet; + *m_search_channel_id = bouquetList->Bouquets[nNewBouquet]->channelList->getActiveChannel_ChannelID(); + m_search_channelname = g_Zapit->getChannelName(*m_search_channel_id); + } + } + } + else if(*m_search_list == EventList::SEARCH_LIST_BOUQUET) + { + int nNewBouquet; + nNewBouquet = bouquetList->show(); + //printf("new_bouquet_id %d\n",nNewBouquet); + if (nNewBouquet > -1) + { + *m_search_bouquet_id = nNewBouquet; + m_search_channelname = bouquetList->Bouquets[nNewBouquet]->channelList->getName(); + } + } + } + else if(actionkey =="4") + { + //printf("4\n"); + } + + return res; +} + +/************************************************************************************************/ +int CEventFinderMenu::showMenu(void) +/************************************************************************************************/ +{ + int res = menu_return::RETURN_REPAINT; + *m_event = false; + + if(*m_search_list == EventList::SEARCH_LIST_CHANNEL) + { + m_search_channelname = g_Zapit->getChannelName(*m_search_channel_id); + } + else if(*m_search_list == EventList::SEARCH_LIST_BOUQUET) + { + m_search_channelname = bouquetList->Bouquets[*m_search_bouquet_id]->channelList->getName(); + } + else if(*m_search_list == EventList::SEARCH_LIST_ALL) + { + m_search_channelname ==""; + } + + CStringInputSMS stringInput(LOCALE_EVENTFINDER_KEYWORD,m_search_keyword, 20, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.: "); + + CMenuForwarder* mf2 = new CMenuForwarder(LOCALE_EVENTFINDER_KEYWORD ,true, *m_search_keyword, &stringInput, NULL, CRCInput::RC_1 ); + CMenuOptionChooser* mo0 = new CMenuOptionChooser(LOCALE_EVENTFINDER_SEARCH_WITHIN_LIST , m_search_list, SEARCH_LIST_OPTIONS, SEARCH_LIST_OPTION_COUNT, true, NULL, CRCInput::RC_2); + CMenuForwarderNonLocalized* mf1 = new CMenuForwarderNonLocalized("", *m_search_list != EventList::SEARCH_LIST_ALL, m_search_channelname, this, "3", CRCInput::RC_3 ); + CMenuOptionChooser* mo1 = new CMenuOptionChooser(LOCALE_EVENTFINDER_SEARCH_WITHIN_EPG, m_search_epg_item, SEARCH_EPG_OPTIONS, SEARCH_EPG_OPTION_COUNT, true, NULL, CRCInput::RC_4); + CMenuForwarder* mf0 = new CMenuForwarder(LOCALE_EVENTFINDER_START_SEARCH, true, NULL, this, "1", CRCInput::RC_5 ); + + CMenuWidget searchMenu(LOCALE_EVENTFINDER_HEAD, "features.raw", 450); + + searchMenu.addItem(GenericMenuSeparator); + searchMenu.addItem(mf2, false); + searchMenu.addItem(GenericMenuSeparatorLine); + searchMenu.addItem(mo0, false); + searchMenu.addItem(mf1, false); + searchMenu.addItem(mo1, false); + searchMenu.addItem(GenericMenuSeparatorLine); + searchMenu.addItem(mf0, false); + + res = searchMenu.exec(NULL,""); + return(res); +} + diff --git a/src/gui/eventlist.h b/src/gui/eventlist.h new file mode 100644 index 000000000..0e3fd528d --- /dev/null +++ b/src/gui/eventlist.h @@ -0,0 +1,150 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __EVENTLIST_HPP__ +#define __EVENTLIST_HPP__ + +#include +#include + +#include +#include +#include +#include + +#include "color.h" +#include "infoviewer.h" + +#include "widget/menue.h" + +#include + + +class EventList +{ + // Eventfinder start + public: + typedef enum + { + SEARCH_EPG_NONE, + SEARCH_EPG_TITLE, + SEARCH_EPG_INFO1, + SEARCH_EPG_INFO2, + SEARCH_EPG_GENRE, + SEARCH_EPG_ALL + }SEARCH_EPG; + typedef enum + { + SEARCH_LIST_NONE, + SEARCH_LIST_CHANNEL, + SEARCH_LIST_BOUQUET, + SEARCH_LIST_ALL + }SEARCH_LIST; + private: + int m_search_epg_item; + std::string m_search_keyword; + int m_search_list; + t_channel_id m_search_channel_id; + t_bouquet_id m_search_bouquet_id; + bool m_showChannel; + + private: + int findEvents(void); + // Eventfinder end + + private: + CFrameBuffer *frameBuffer; + CChannelEventList evtlist; + CTimerd::TimerList timerlist; + void readEvents(const t_channel_id channel_id); + unsigned int selected; + unsigned int current_event; + unsigned int liststart; + unsigned int listmaxshow; + unsigned int numwidth; + int fheight; // Fonthoehe Channellist-Inhalt + int fheight1,fheight2; + int fwidth1,fwidth2; + int theight; // Fonthoehe Channellist-Titel + int iheight; // Height info bar + + int key; + std::string name; + + int width; + int height; + int x; + int y; + int sort_mode; + + void paintItem(unsigned pos, t_channel_id channel_id = 0); + void paint(t_channel_id channel_id = 0); + void paintHead(t_channel_id channel_id); + void hide(); + void showFunctionBar(bool show); + CTimerd::CTimerEventTypes isScheduled(t_channel_id channel_id, CChannelEvent * event, int * tID = NULL); + + public: + EventList(); + ~EventList(); + int exec(const t_channel_id channel_id, const std::string& channelname); // UTF-8 +}; + +class CEventListHandler : public CMenuTarget +{ + public: + int exec( CMenuTarget* parent, const std::string &actionkey); + +}; + +class CEventFinderMenu : public CMenuTarget +{ + private: + int* m_event; + int* m_search_epg_item; + std::string* m_search_keyword; + int* m_search_list; + std::string m_search_channelname; + t_channel_id* m_search_channel_id; + t_bouquet_id* m_search_bouquet_id; + int showMenu(void); + public: + CEventFinderMenu( int* event, + int* search_epg_item, + std::string* search_keyword, + int* search_list, + t_channel_id* search_channel_id, + t_bouquet_id* search_bouquet_id); + int exec( CMenuTarget* parent, const std::string &actionkey); + +}; +#endif diff --git a/src/gui/favorites.cpp b/src/gui/favorites.cpp new file mode 100644 index 000000000..58afb0e71 --- /dev/null +++ b/src/gui/favorites.cpp @@ -0,0 +1,169 @@ +/* + Neutrino-GUI - DBoxII-Project + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include +#include +#include + +#include + + +#include + +extern CBouquetList * bouquetList; /* neutrino.cpp */ +extern t_channel_id live_channel_id; +void addChannelToBouquet(const unsigned int bouquet, const t_channel_id channel_id); +extern CBouquetManager *g_bouquetManager; +// +// -- Add current channel to Favorites-Bouquet +// -- Return Status (bit-Status):A +// -- 1 = Bouquet created +// -- 2 = Channel added (if not set, channel already in BQ) +// -- rasc +// + +int CFavorites::addChannelToFavorites(bool show_list) +{ + signed int bouquet_id; + t_channel_id channel_id; + const char * fav_bouquetname; + int status = 0; + + + // no bouquet-List? do nothing + if (!bouquetList) return status; + + if(show_list) + { + bouquet_id = bouquetList->exec(false); + if (bouquet_id < 0) + return bouquet_id; + printf("[favorites] bouquet name %s\n", bouquetList->Bouquets[bouquet_id]->channelList->getName()); + bouquet_id = g_Zapit->existsBouquet(bouquetList->Bouquets[bouquet_id]->channelList->getName()); + if (bouquet_id == -1) + return bouquet_id; + } + else + { + // -- check if Favorite Bouquet exists: if not, create it. + bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true); + if (bouquet_id == -1) { + g_bouquetManager->addBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true); + bouquet_id = g_bouquetManager->existsUBouquet(g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME), true); + // status |= 1; + } + } + + //channel_id = g_Zapit->getCurrentServiceID(); + channel_id = live_channel_id; + + if(!g_bouquetManager->existsChannelInBouquet(bouquet_id, channel_id)) { + addChannelToBouquet(bouquet_id, channel_id); + status |= 2; + } + + // -- tell zapit to save Boquets and reinit (if changed) + if (status) + { + g_Zapit->saveBouquets(); + } + + return status; +} + +// +// -- Menue Handler Interface +// -- to fit the MenueClasses from McClean +// -- Add current channel to Favorites and display user messagebox +// + +int CFavorites::exec(CMenuTarget* parent, const std::string & actionKey) +{ + int status; + std::string str; + int res = menu_return::RETURN_EXIT_ALL; + bool show_list; + //printf("[favorites] key %s\n", actionKey.c_str()); + show_list = (actionKey == "showlist"); + if (parent) + parent->hide(); + + if (!bouquetList) { + ShowLocalizedMessage(LOCALE_FAVORITES_BOUQUETNAME, LOCALE_FAVORITES_NOBOUQUETS, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + return res; + } + + + CHintBox* hintBox = new CHintBox(LOCALE_FAVORITES_BOUQUETNAME, g_Locale->getText(LOCALE_FAVORITES_ADDCHANNEL), 380); // UTF-8 + if(!show_list) + hintBox->paint(); + + status = addChannelToFavorites(show_list); + + hintBox->hide(); + delete hintBox; + + // -- Display result + + //printf("[favorites] status %d\n", status); + if(status < 0) + return menu_return::RETURN_REPAINT; + + str = ""; + if(show_list) + { + if (status & 2) str += g_Locale->getText(LOCALE_EXTRA_CHADDED); + else str += g_Locale->getText(LOCALE_EXTRA_CHALREADYINBQ); + ShowMsgUTF(LOCALE_EXTRA_ADD_TO_BOUQUET, str, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); // UTF-8 + } + else + { + if (status & 1) str += g_Locale->getText(LOCALE_FAVORITES_BQCREATED); + if (status & 2) str += g_Locale->getText(LOCALE_FAVORITES_CHADDED); + else str += g_Locale->getText(LOCALE_FAVORITES_CHALREADYINBQ); + if (status) str += g_Locale->getText(LOCALE_FAVORITES_FINALHINT); + ShowMsgUTF(LOCALE_FAVORITES_BOUQUETNAME, str, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); // UTF-8 + } + + + + // if (status) { + // g_RCInput->postMsg( NeutrinoMessages::EVT_BOUQUETSCHANGED, 0 ); + // } + + return res; +} diff --git a/src/gui/favorites.h b/src/gui/favorites.h new file mode 100644 index 000000000..060d72d5c --- /dev/null +++ b/src/gui/favorites.h @@ -0,0 +1,47 @@ +/* + Neutrino-GUI - DBoxII-Project + + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __favorites__ +#define __favorites__ + +#include + +#include + + +// +// -- Implement Favorites... +// -- Class for adding Favorite channels to a bouquet called "Neutrino__Favorites" +// -- Bouquet will be created on the first add! +// +class CFavorites : public CMenuTarget +{ + + public: + + int addChannelToFavorites (bool show_list); + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + + +#endif diff --git a/src/gui/filebrowser.cpp b/src/gui/filebrowser.cpp new file mode 100644 index 000000000..665adba2e --- /dev/null +++ b/src/gui/filebrowser.cpp @@ -0,0 +1,1518 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* include before to enable 64 bit file offsets */ +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +#ifdef __USE_FILE_OFFSET64 +typedef struct dirent64 dirent_struct; +#define my_alphasort alphasort64 +#define my_scandir scandir64 +typedef struct stat64 stat_struct; +#define my_stat stat64 +#define my_lstat lstat64 +#else +typedef struct dirent dirent_struct; +#define my_alphasort alphasort +#define my_scandir scandir +typedef struct stat stat_struct; +#define my_stat stat +#define my_lstat lstat +#error not using 64 bit file offsets +#endif + +#define SMSKEY_TIMEOUT 2000 +//------------------------------------------------------------------------ +size_t CurlWriteToString(void *ptr, size_t size, size_t nmemb, void *data) +{ + std::string* pStr = (std::string*) data; + pStr->append((char*) ptr, nmemb); // do only add the correct size, do not go until end of data (chunked transfer) + return size*nmemb; +} + +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ + +SMSKeyInput::SMSKeyInput() +{ + resetOldKey(); + m_timeout = SMSKEY_TIMEOUT; +} +//------------------------------------------------------------------------ + +unsigned char SMSKeyInput::handleMsg(const neutrino_msg_t msg) +{ + timeval keyTime; + gettimeofday(&keyTime,NULL); + bool timeoutNotReached = (keyTime.tv_sec*1000+keyTime.tv_usec/1000 + <= m_oldKeyTime.tv_sec*1000+m_oldKeyTime.tv_usec/1000 + m_timeout); + +// printf("act: %ld , old: %ld (diff: %ld ) , timeout: %ld => timout= %d\n", +// keyTime.tv_sec*1000+keyTime.tv_usec/1000, +// m_oldKeyTime.tv_sec*1000+m_oldKeyTime.tv_usec/1000, +// keyTime.tv_sec*1000+keyTime.tv_usec/1000 - +// m_oldKeyTime.tv_sec*1000+m_oldKeyTime.tv_usec/1000, +// m_timeout,!timeoutNotReached); + + unsigned char key = 0; + if(msg == CRCInput::RC_1) + { + key = '1'; + } + if(msg == CRCInput::RC_2) + { + if(m_oldKey == 'a' && timeoutNotReached) + key = 'b'; + else if(m_oldKey == 'b' && timeoutNotReached) + key = 'c'; + else if(m_oldKey == 'c' && timeoutNotReached) + key = '2'; + else + key = 'a'; + } + else if(msg == CRCInput::RC_3) + { + if(m_oldKey == 'd' && timeoutNotReached) + key = 'e'; + else if(m_oldKey == 'e' && timeoutNotReached) + key = 'f'; + else if(m_oldKey == 'f' && timeoutNotReached) + key = '3'; + else + key = 'd'; + } + else if(msg == CRCInput::RC_4) + { + if(m_oldKey == 'g' && timeoutNotReached) + key = 'h'; + else if(m_oldKey == 'h' && timeoutNotReached) + key = 'i'; + else if(m_oldKey == 'i' && timeoutNotReached) + key = '4'; + else + key = 'g'; + } + else if(msg == CRCInput::RC_5) + { + if(m_oldKey == 'j' && timeoutNotReached) + key = 'k'; + else if(m_oldKey == 'k' && timeoutNotReached) + key = 'l'; + else if(m_oldKey == 'l' && timeoutNotReached) + key = '5'; + else + key = 'j'; + } + else if(msg == CRCInput::RC_6) + { + if(m_oldKey == 'm' && timeoutNotReached) + key = 'n'; + else if(m_oldKey == 'n' && timeoutNotReached) + key = 'o'; + else if(m_oldKey == 'o' && timeoutNotReached) + key = '6'; + else + key = 'm'; + } + else if(msg == CRCInput::RC_7) + { + if(m_oldKey == 'p' && timeoutNotReached) + key = 'q'; + else if(m_oldKey == 'q' && timeoutNotReached) + key = 'r'; + else if(m_oldKey == 'r' && timeoutNotReached) + key = 's'; + else if(m_oldKey == 's' && timeoutNotReached) + key = 's'; + else + key = 'p'; + } + else if(msg == CRCInput::RC_8) + { + if(m_oldKey == 't' && timeoutNotReached) + key = 'u'; + else if(m_oldKey == 'u' && timeoutNotReached) + key = 'v'; + else if(m_oldKey == 'v' && timeoutNotReached) + key = '8'; + else + key = 't'; + } + else if(msg == CRCInput::RC_9) + { + if(m_oldKey == 'w' && timeoutNotReached) + key = 'x'; + else if(m_oldKey == 'x' &&timeoutNotReached) + key = 'y'; + else if(m_oldKey == 'y' &&timeoutNotReached) + key = 'z'; + else if(m_oldKey == 'z' && timeoutNotReached) + key = '9'; + else + key = 'w'; + } + else if(msg == CRCInput::RC_0) + { + key = '0'; + } + m_oldKeyTime=keyTime; + m_oldKey=key; + return key; +} +//------------------------------------------------------------------------ + +void SMSKeyInput::resetOldKey() +{ + m_oldKeyTime.tv_sec = 0; + m_oldKeyTime.tv_usec = 0; + m_oldKey = 0; +} + +unsigned char SMSKeyInput::getOldKey() const +{ + return m_oldKey; +} + +const timeval* SMSKeyInput::getOldKeyTime() const +{ + return &m_oldKeyTime; +} + +time_t SMSKeyInput::getOldKeyTimeSec() const +{ + return m_oldKeyTime.tv_sec; +} + + +int SMSKeyInput::getTimeout() const +{ + return m_timeout; +} + +void SMSKeyInput::setTimeout(int timeout) +{ + m_timeout = timeout; +} + + +//------------------------------------------------------------------------ +//------------------------------------------------------------------------ + +bool comparetolower(const char a, const char b) +{ + return tolower(a) < tolower(b); +}; + +// sort operators +bool sortByName (const CFile& a, const CFile& b) +{ + if (std::lexicographical_compare(a.Name.begin(), a.Name.end(), b.Name.begin(), b.Name.end(), comparetolower)) + return true; + + if (std::lexicographical_compare(b.Name.begin(), b.Name.end(), a.Name.begin(), a.Name.end(), comparetolower)) + return false; + + return a.Mode < b.Mode; +/* + int result = __gnu_cxx::lexicographical_compare_3way(a.Name.begin(), a.Name.end(), b.Name.begin(), b.Name.end(), comparetolower); + + if (result == 0) + return a.Mode < b.Mode; + else + return result < 0; +*/ +} + +bool sortByNameDirsFirst(const CFile& a, const CFile& b) +// Sorts alphabetically with Directories first +{ + int typea, typeb; + typea = a.getType(); + typeb = b.getType(); + + if (typea == CFile::FILE_DIR) + if (typeb == CFile::FILE_DIR) + //both directories + return sortByName(a, b); + else + //only a is directory + return true; + else if (typeb == CFile::FILE_DIR) + //only b is directory + return false; + else + //no directory + return sortByName(a, b); +} + +bool sortByType (const CFile& a, const CFile& b) +{ + if(a.Mode == b.Mode) + return sortByName(a, b); + else + return a.Mode < b.Mode; +} + +bool sortByDate (const CFile& a, const CFile& b) +{ + if(a.getFileName()=="..") + return true; + if(b.getFileName()=="..") + return false; + return a.Time < b.Time ; +} + +bool sortBySize (const CFile& a, const CFile& b) +{ + if(a.getFileName()=="..") + return true; + if(b.getFileName()=="..") + return false; + return a.Size < b.Size; +} + +bool (* const sortBy[FILEBROWSER_NUMBER_OF_SORT_VARIANTS])(const CFile& a, const CFile& b) = +{ + &sortByName, + &sortByNameDirsFirst, + &sortByType, + &sortByDate, + &sortBySize +}; + +const neutrino_locale_t sortByNames[FILEBROWSER_NUMBER_OF_SORT_VARIANTS] = +{ + LOCALE_FILEBROWSER_SORT_NAME, + LOCALE_FILEBROWSER_SORT_NAMEDIRSFIRST, + LOCALE_FILEBROWSER_SORT_TYPE, + LOCALE_FILEBROWSER_SORT_DATE, + LOCALE_FILEBROWSER_SORT_SIZE +}; + +//------------------------------------------------------------------------ + +CFileBrowser::CFileBrowser() +{ + commonInit(); + base = ""; + m_Mode = ModeFile; +} + +CFileBrowser::CFileBrowser(const char * const _base, const tFileBrowserMode mode) +{ + commonInit(); + base = _base; + m_Mode = mode; +} + +void CFileBrowser::commonInit() +{ + frameBuffer = CFrameBuffer::getInstance(); + + Filter = NULL; + use_filter = true; + Multi_Select = false; + Dirs_Selectable = false; + Dir_Mode = false; + Hide_records = false; + selected = 0; + selections.clear(); + + x = g_settings.screen_StartX + 20; + y = g_settings.screen_StartY + 20; + + width = (g_settings.screen_EndX - g_settings.screen_StartX - 40); + height = (g_settings.screen_EndY - g_settings.screen_StartY - 40); + + theight = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_TITLE]->getHeight(); + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getHeight(); + foheight = 30; + + liststart = 0; + listmaxshow = std::max(1,(int)(height - theight - 2 * foheight)/fheight); + + //recalc height + height = theight + listmaxshow * fheight + 2 * foheight; + + m_SMSKeyInput.setTimeout(SMSKEY_TIMEOUT); +} + +//------------------------------------------------------------------------ + + +CFileBrowser::~CFileBrowser() +{ +} + +//------------------------------------------------------------------------ + +CFile *CFileBrowser::getSelectedFile() +{ + if ((!(filelist.empty())) && (!(filelist[selected].Name.empty()))) + return &filelist[selected]; + else + return NULL; +} + +//------------------------------------------------------------------------ + +void CFileBrowser::ChangeDir(const std::string & filename, int selection) +{ + std::string newpath; + if((m_Mode != ModeSC) && (filename == "..")) + { + std::string::size_type pos = Path.substr(0,Path.length()-1).rfind('/'); + +#ifdef ENABLE_MOVIEPLAYER_VLC + bool is_vlc = (strncmp(Path.c_str(), VLC_URI, strlen(VLC_URI)) == 0); +#endif + if (pos == std::string::npos) + { + newpath = Path; + } + else + { +#ifdef ENABLE_MOVIEPLAYER_VLC + if (is_vlc && (pos < strlen(VLC_URI) - 1)) + newpath = VLC_URI; + else +#endif + newpath = Path.substr(0, pos + 1); + } + +#ifdef ENABLE_MOVIEPLAYER_VLC + if (strncmp(is_vlc ? &(newpath.c_str()[strlen(VLC_URI)]) : newpath.c_str(), base.c_str(), base.length()) != 0) + return; +#endif + } + else + { + newpath=filename; + } + if(m_Mode != ModeSC && (newpath.rfind('/') != newpath.length()-1 || newpath.length() == 0)) + { + newpath += '/'; + } + filelist.clear(); + Path = newpath; + name = newpath; + CFileList allfiles; + readDir(newpath, &allfiles); + // filter + CFileList::iterator file = allfiles.begin(); + for(; file != allfiles.end() ; file++) + { + if(Filter != NULL && (!S_ISDIR(file->Mode)) && use_filter) + { + if(!Filter->matchFilter(file->Name)) + { + continue; + } + if(Hide_records) { + int ext_pos = file->Name.rfind('.'); + if( ext_pos > 0) { + std::string extension = file->Name.substr(ext_pos + 1, name.length() - ext_pos); + if(strcasecmp(extension.c_str(), "ts") == 0) { + std::string fname = file->Name.substr(0, ext_pos) + ".xml"; + if(access(fname.c_str(), F_OK) == 0) + continue; + } + } + } + } + if(Dir_Mode && (!S_ISDIR(file->Mode))) + { + continue; + } + filelist.push_back(*file); + } + // sort result + sort(filelist.begin(), filelist.end(), sortBy[g_settings.filebrowser_sortmethod]); + + selected = 0; + if ((selection != -1) && (selection < (int)filelist.size())) + selected = selection; + paintHead(); + paint(); +} + +//------------------------------------------------------------------------ +bool CFileBrowser::readDir(const std::string & dirname, CFileList* flist) +{ + bool ret; + +#ifdef ENABLE_INTERNETRADIO + if (m_Mode == ModeSC) { + ret = readDir_sc(dirname, flist); + } + else +#endif +#ifdef ENABLE_MOVIEPLAYER_VLC + if (strncmp(dirname.c_str(), VLC_URI, strlen(VLC_URI)) == 0) + { + ret = readDir_vlc(dirname, flist); + } + else +#endif + { + ret = readDir_std(dirname, flist); + } + return ret; +} + +#ifdef ENABLE_MOVIEPLAYER_VLC +bool CFileBrowser::readDir_vlc(const std::string & dirname, CFileList* flist) +{ +// printf("readDir_vlc %s\n",dirname.c_str()); + std::string answer=""; + char *dir_escaped = curl_escape(dirname.substr(strlen(VLC_URI)).c_str(), 0); + std::string url = m_baseurl; + url += dir_escaped; + curl_free(dir_escaped); + std::cout << "[FileBrowser] vlc URL: " << url << std::endl; + CURL *curl_handle; + CURLcode httpres; + /* init the curl session */ + curl_handle = curl_easy_init(); + /* timeout. 15 seconds should be enough */ + curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 15); + /* specify URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, CurlWriteToString); + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl_handle, CURLOPT_FILE, (void *)&answer); + /* Generate error if http error >= 400 occurs */ + curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1); + /* error handling */ + char error[CURL_ERROR_SIZE]; + curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error); + /* get it! */ + httpres = curl_easy_perform(curl_handle); + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + + // std::cout << "Answer:" << std::endl << "----------------" << std::endl << answer << std::endl; + + if (!answer.empty() && httpres == 0) + { + xmlDocPtr answer_parser = parseXml(answer.c_str()); + + if (answer_parser != NULL) { + xmlNodePtr element = xmlDocGetRootElement(answer_parser); + element = element->xmlChildrenNode; + char *ptr; + if (element == NULL) { + printf("[FileBrowser] vlc: Drive is not readable. Possibly no disc inserted\n"); + CFile file; + file.Mode = S_IFDIR + 0777 ; + file.Name = dirname + ".."; + file.Size = 0; + file.Time = 0; + flist->push_back(file); + } else { + while (element) { + CFile file; + ptr = xmlGetAttribute(element, (char *) "type"); + if (strcmp(ptr, "directory")==0) + file.Mode = S_IFDIR + 0777 ; + else + file.Mode = S_IFREG + 0777 ; + + file.Name = dirname + xmlGetAttribute(element, (char *) "name"); + ptr = xmlGetAttribute(element, (char *) "size"); + if (ptr) + file.Size = atoi(ptr); + else + file.Size = 0; + file.Time = 0; + + element = element->xmlNextNode; + flist->push_back(file); + } + } + xmlFreeDoc(answer_parser); + return true; + } + } + + /* since all CURL error messages use only US-ASCII characters, when can safely print them as if they were UTF-8 encoded */ + if (httpres == 22) { + strcat(error, "\nProbably wrong vlc version\nPlease use vlc 0.8.5 or higher"); + } + DisplayErrorMessage(error); // UTF-8 + CFile file; + + file.Name = dirname + ".."; + file.Mode = S_IFDIR + 0777; + file.Size = 0; + file.Time = 0; + flist->push_back(file); + + return false; +} +#endif /* ENABLE_MOVIEPLAYER_VLC */ + +#ifdef ENABLE_INTERNETRADIO +bool CFileBrowser::readDir_sc(const std::string & dirname, CFileList* flist) +{ +#define GET_SHOUTCAST_TIMEOUT 60 +/* how the shoutcast xml interfaces looks/works: +1st step: get http://www.shoutcast.com/sbin/newxml.phtml +example answer: + + +... + + + + += 400 occurs */ + curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1); + /* set timeout to 30 seconds */ + curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, GET_SHOUTCAST_TIMEOUT); + + /* error handling */ + char error[CURL_ERROR_SIZE]; + curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error); + /* get it! */ + httpres = curl_easy_perform(curl_handle); + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + + //std::cout << "Answer:" << std::endl << "----------------" << std::endl << answer << std::endl; + + if (!answer.empty() && httpres == 0) + { +printf("CFileBrowser::readDir_sc: read done, size %d\n", answer.size()); + xmlDocPtr answer_parser = parseXml(answer.c_str()); + + if (answer_parser != NULL) { + char *ptr; + unsigned char xml_decode = 0; + xmlNodePtr element = xmlDocGetRootElement(answer_parser); + + if (strcmp(xmlGetName(element), "genrelist") == 0) + xml_decode = 1; + else if (strcmp(xmlGetName(element), "stationlist") == 0) + xml_decode = 2; + element = element->xmlChildrenNode; + + if (element == NULL) { + printf("[FileBrowser] SC: Directory cannot be read.\n"); + CFile file; + file.Mode = S_IFDIR + 0777 ; + file.Name = dirname + ".."; + file.Size = 0; + file.Time = 0; + flist->push_back(file); + } else { + char * tunein_base = NULL; + + if (xml_decode == 1) { + CFile file; + file.Mode = S_IFDIR + 0777 ; + file.Name = " Top500"; // use space to have it at the beginning of the list + file.Url = "/sbin/newxml.phtml?genre=Top500"; + file.Size = 0; + file.Time = 0; + flist->push_back(file); + } else if (xml_decode == 2) { + CFile file2; + file2.Mode = S_IFDIR + 0777 ; + file2.Name = ".."; + file2.Url = "/sbin/newxml.phtml"; + file2.Size = 0; + file2.Time = 0; + flist->push_back(file2); + } + while (element) { + CFile file; + if (xml_decode == 1) { + file.Mode = S_IFDIR + 0777 ; + file.Name = xmlGetAttribute(element, (char *) "name"); + file.Url = "/sbin/newxml.phtml?genre=" + file.Name; + file.Size = 0; + file.Time = 0; + flist->push_back(file); + } + else if (xml_decode == 2) { + ptr = xmlGetName(element); + if (ptr != NULL) { + if (strcmp(ptr, "tunein")==0) { + ptr = xmlGetAttribute(element, (char *) "base"); + if (ptr) + tunein_base = ptr; + } else if (strcmp(ptr, "station")==0) { + ptr = xmlGetAttribute(element, (char *) "mt"); + if (ptr && (strcmp(ptr, "audio/mpeg")==0)) { + file.Mode = S_IFREG + 0777 ; + file.Name = xmlGetAttribute(element, (char *) "name"); + file.Url = base + tunein_base + (std::string)"?id=" + xmlGetAttribute(element, (char *) "id"); + //printf("adding %s (%s)\n", file.Name.c_str(), file.Url.c_str()); + ptr = xmlGetAttribute(element, (char *) "br"); + if (ptr) { + file.Size = atoi(ptr); + file.Time = atoi(ptr); + } else { + file.Size = 0; + file.Time = 0; + } + flist->push_back(file); + } + } + } + } + element = element->xmlNextNode; + } + } + xmlFreeDoc(answer_parser); + return true; + } + } + + /* since all CURL error messages use only US-ASCII characters, when can safely print them as if they were UTF-8 encoded */ + if (httpres == 22) { + strcat(error, "\nProbably wrong link."); + } +printf("CFileBrowser::readDir_sc: httpres %d error, %s\n", httpres, error); + DisplayErrorMessage(error); // UTF-8 + CFile file; + + file.Name = dirname + ".."; + file.Mode = S_IFDIR + 0777; + file.Size = 0; + file.Time = 0; + flist->push_back(file); + + return false; +} +#endif + +bool CFileBrowser::readDir_std(const std::string & dirname, CFileList* flist) +{ +// printf("readDir_std %s\n",dirname.c_str()); + stat_struct statbuf; + dirent_struct **namelist; + int n; + + n = my_scandir(dirname.c_str(), &namelist, 0, my_alphasort); + if (n < 0) + { + perror(("Filebrowser scandir: "+dirname).c_str()); + return false; + } + for(int i = 0; i < n;i++) + { + CFile file; + if(strcmp(namelist[i]->d_name,".") != 0) + { + file.Name = dirname + namelist[i]->d_name; + +// printf("file.Name: '%s', getFileName: '%s' getPath: '%s'\n",file.Name.c_str(),file.getFileName().c_str(),file.getPath().c_str()); + if(my_stat((file.Name).c_str(),&statbuf) != 0) + perror("stat error"); + else + { + file.Mode = statbuf.st_mode; + file.Size = statbuf.st_size; + file.Time = statbuf.st_mtime; + flist->push_back(file); + } + } + free(namelist[i]); + } + + free(namelist); + + return true; +} + +//------------------------------------------------------------------------ + +bool CFileBrowser::exec(const char * const dirname) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + bool res = false; + +#ifdef ENABLE_INTERNETRADIO + if (m_Mode == ModeSC) { + m_baseurl = base; + } else +#endif + { + m_baseurl = "http://" + g_settings.streaming_server_ip + ':' + + g_settings.streaming_server_port + "/requests/browse.xml?dir="; + } + name = dirname; + std::replace(name.begin(), name.end(), '\\', '/'); + + paintHead(); + ChangeDir(name); + paint(); + paintFoot(); + + int oldselected = selected; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_FILEBROWSER]); + + bool loop=true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + neutrino_msg_t msg_repeatok = msg & ~CRCInput::RC_Repeat; + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_FILEBROWSER]); + + if(!CRCInput::isNumeric(msg)) + { + m_SMSKeyInput.resetOldKey(); + } + + if (msg == CRCInput::RC_yellow) + { + if ((Multi_Select) && (selected < filelist.size())) + { + if(filelist[selected].getFileName() != "..") + { + if( (S_ISDIR(filelist[selected].Mode) && Dirs_Selectable) || !S_ISDIR(filelist[selected].Mode) ) + { + filelist[selected].Marked = !filelist[selected].Marked; + paintItem(selected - liststart); + } + } + msg_repeatok = CRCInput::RC_down; // jump to next item + } + } + + if ((msg == CRCInput::RC_red) || msg == CRCInput::RC_page_down) + { + selected += listmaxshow; + if (selected >= filelist.size()) { + if (((filelist.size() / listmaxshow) + 1) * listmaxshow == filelist.size() + listmaxshow) // last page has full entries + selected = 0; + else + selected = selected < (((filelist.size() / listmaxshow) + 1) * listmaxshow) ? (filelist.size() - 1) : 0; + } + liststart = (selected / listmaxshow) * listmaxshow; + paint(); + } + else if ((msg == CRCInput::RC_green) || (msg == CRCInput::RC_page_up) ) + { + if ((int(selected)-int(listmaxshow))<0) + selected=filelist.size()-1; + else + selected -= listmaxshow; + liststart = (selected/listmaxshow)*listmaxshow; + paint(); + } + else if (msg_repeatok == CRCInput::RC_up) + { + int prevselected=selected; + if(selected==0) + { + selected = filelist.size()-1; + } + else + selected--; + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paint(); + } + else + { + paintItem(selected - liststart); + } + } + else if (msg_repeatok == CRCInput::RC_down) + { + if (!(filelist.empty())) + { + int prevselected=selected; + selected = (selected + 1) % filelist.size(); + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + paint(); + else + paintItem(selected - liststart); + } + } + else if ( ( msg == CRCInput::RC_timeout ) ) + { + selected = oldselected; + loop=false; + } + else if ( msg == CRCInput::RC_right ) + { + if (!(filelist.empty())) + { + if (S_ISDIR(filelist[selected].Mode)) + { +#ifdef ENABLE_INTERNETRADIO + if (m_Mode == ModeSC) { + ChangeDir(filelist[selected].Url); + } else +#endif + { + if (filelist[selected].getFileName() != "..") { + selections.push_back(selected); + ChangeDir(filelist[selected].Name); + } + } + } + } + } + else if ( msg == CRCInput::RC_left ) + { +#ifdef ENABLE_INTERNETRADIO + if (m_Mode == ModeSC) + { + for(unsigned int i = 0; i < filelist.size();i++) { + if (S_ISDIR(filelist[i].Mode) && filelist[i].getFileName() == "..") { + ChangeDir(filelist[i].Url); + break; + } + } + } + else +#endif + if (selections.size() > 0) + { + ChangeDir("..",selections.back()); + selections.pop_back(); + } else + { + ChangeDir(".."); + } + } + else if ( msg == CRCInput::RC_blue ) + { + if(Filter != NULL) + { + use_filter = !use_filter; + paintFoot(); + ChangeDir(Path); + } + } + else if ( msg == CRCInput::RC_home ) + { + loop = false; + } + else if ( msg == CRCInput::RC_spkr && strncmp(Path.c_str(), VLC_URI, strlen(VLC_URI)) != 0) //Not in vlc mode + { + if(".." !=(filelist[selected].getFileName().substr(0,2))) // do not delete that + { + std::stringstream _msg; + _msg << g_Locale->getText(LOCALE_FILEBROWSER_DODELETE1) << " "; + if (filelist[selected].getFileName().length() > 25) + { + _msg << filelist[selected].getFileName().substr(0, 25) << "..."; + } + else + _msg << filelist[selected].getFileName(); + + _msg << " " << g_Locale->getText(LOCALE_FILEBROWSER_DODELETE2); + if (ShowMsgUTF(LOCALE_FILEBROWSER_DELETE, _msg.str(), CMessageBox::mbrNo, CMessageBox::mbYes|CMessageBox::mbNo)==CMessageBox::mbrYes) + { + recursiveDelete(filelist[selected].Name.c_str()); + if(".ts" ==(filelist[selected].getFileName().substr(filelist[selected].getFileName().length()-3,filelist[selected].getFileName().length())))//if bla.ts + { + recursiveDelete((filelist[selected].Name.substr(0,filelist[selected].Name.length()-7)+".xml").c_str());//remove bla.xml von bla.ts + } + ChangeDir(Path); + + } + } + } + else if (msg == CRCInput::RC_ok) + { + if (!(filelist.empty())) + { + if (filelist[selected].getFileName() == "..") + { +#ifdef ENABLE_INTERNETRADIO + if (m_Mode == ModeSC) + ChangeDir(filelist[selected].Url); + else +#endif + { + if (selections.size() > 0) + { + ChangeDir("..",selections.back()); + selections.pop_back(); + } else + { + std::string::size_type pos = Path.substr(0,Path.length()-1).rfind('/'); + if (pos != std::string::npos) { + ChangeDir(".."); + } + else { + loop = false; + res = true; + filelist[selected].Name = "/"; + } + } + } + } + else + { + std::string filename = filelist[selected].Name; + if ( filename.length() > 1 ) + { + if((!Multi_Select) && S_ISDIR(filelist[selected].Mode) && !Dir_Mode) + { +#ifdef ENABLE_INTERNETRADIO + if (m_Mode == ModeSC) + ChangeDir(filelist[selected].Url); + else +#endif + ChangeDir(filelist[selected].Name); + } + else + { + filelist[selected].Marked = true; + loop = false; + res = true; + } + } + } + } + } + else if (msg==CRCInput::RC_help) + { + if (++g_settings.filebrowser_sortmethod >= FILEBROWSER_NUMBER_OF_SORT_VARIANTS) + g_settings.filebrowser_sortmethod = 0; + + sort(filelist.begin(), filelist.end(), sortBy[g_settings.filebrowser_sortmethod]); + + paint(); + paintFoot(); + } + else if (CRCInput::isNumeric(msg_repeatok)) + { + if (!(filelist.empty())) + SMSInput(msg_repeatok); + } + else + { + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + } + } + } + + hide(); + + selected_filelist.clear(); + + if(res && Multi_Select) + { + CProgressWindow * progress = new CProgressWindow(); + progress->setTitle(LOCALE_FILEBROWSER_SCAN); + progress->exec(NULL,""); + for(unsigned int i = 0; i < filelist.size();i++) + if(filelist[i].Marked) + { + if(S_ISDIR(filelist[i].Mode)) { +#ifdef ENABLE_INTERNETRADIO + if (m_Mode == ModeSC) + addRecursiveDir(&selected_filelist,filelist[i].Url, true, progress); + else +#endif + addRecursiveDir(&selected_filelist,filelist[i].Name, true, progress); + } else + selected_filelist.push_back(filelist[i]); + } + progress->hide(); + delete progress; + } + + return res; +} + +//------------------------------------------------------------------------ + +void CFileBrowser::addRecursiveDir(CFileList * re_filelist, std::string rpath, bool bRootCall, CProgressWindow * progress) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int n; + + //printf("addRecursiveDir %s\n",rpath.c_str()); + + if (bRootCall) bCancel=false; + + g_RCInput->getMsg_us(&msg, &data, 1); + if (msg==CRCInput::RC_home) + { + // home key cancel scan + bCancel=true; + } + else if (msg!=CRCInput::RC_timeout) + { + // other event, save to low priority queue + g_RCInput->postMsg( msg, data, false ); + } + if(bCancel) + return; + + if ((m_Mode != ModeSC) && ((rpath.empty()) || ((*rpath.rbegin()) != '/'))) + { + rpath += '/'; + } + + CFileList tmplist; + if(!readDir(rpath, &tmplist)) + { + perror(("Recursive scandir: "+rpath).c_str()); + } + else + { + n = tmplist.size(); + if(progress) + { + progress->showStatusMessageUTF(FILESYSTEM_ENCODING_TO_UTF8_STRING(rpath)); + } + for(int i = 0; i < n;i++) + { + if(progress) + { + progress->showGlobalStatus(100/n*i); + } + std::string basename = tmplist[i].Name.substr(tmplist[i].Name.rfind('/')+1); + if( basename != ".." ) + { + if(Filter != NULL && (!S_ISDIR(tmplist[i].Mode)) && use_filter) + { + if(!Filter->matchFilter(tmplist[i].Name)) + { + continue; + } + } + if(!S_ISDIR(tmplist[i].Mode)) + re_filelist->push_back(tmplist[i]); + else + addRecursiveDir(re_filelist,tmplist[i].Name, false, progress); + } + } + } +} + + +//------------------------------------------------------------------------ + +void CFileBrowser::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height); +} + +//------------------------------------------------------------------------ + +void CFileBrowser::paintItem(unsigned int pos) +{ + int colwidth1, colwidth2, colwidth3, colwidth1_dir, colwidth2_dir; + int c_rad_small; + uint8_t color; + fb_pixel_t bgcolor; + int ypos = y+ theight+0 + pos*fheight; + CFile * actual_file = NULL; + std::string fileicon; + + colwidth2_dir = 180; + colwidth1_dir = width - 35 - colwidth2_dir - 10; + + if (liststart + pos == selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + c_rad_small = RADIUS_SMALL; +// paintFoot(); + } + else + { + color = COL_MENUCONTENT;//DARK; + bgcolor = COL_MENUCONTENT_PLUS_0;//DARK; + c_rad_small = 0; + } + + if( (liststart + pos) < filelist.size() ) + { + actual_file = &filelist[liststart+pos]; + if (actual_file->Marked) + { + color = COL_MENUCONTENTINACTIVE; //+= 2; FIXME + bgcolor = (liststart + pos == selected) ? COL_MENUCONTENTSELECTED_PLUS_2 : COL_MENUCONTENT_PLUS_2; + } + + if (g_settings.filebrowser_showrights == 0 && S_ISREG(actual_file->Mode)) + { + colwidth2 = 0; + colwidth3 = 90; + } + else + { + colwidth2 = 90; + colwidth3 = 90; + } + colwidth1 = width - 35 - colwidth2 - colwidth3 - 10; + + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor, c_rad_small); + + if ( actual_file->Name.length() > 0 ) + { + if (liststart+pos==selected) + CVFD::getInstance()->showMenuText(0, FILESYSTEM_ENCODING_TO_UTF8_STRING(actual_file->getFileName()).c_str(), -1, true); // UTF-8 + + switch(actual_file->getType()) + { + case CFile::FILE_CDR: + case CFile::FILE_MP3: + case CFile::FILE_OGG: + case CFile::FILE_WAV: +#ifdef ENABLE_FLAC + case CFile::FILE_FLAC: +#endif + fileicon = "mp3.raw"; +// color = COL_MENUCONTENT; + break; + + case CFile::FILE_DIR: + fileicon = "folder.raw"; + break; + + case CFile::FILE_PICTURE: + case CFile::FILE_TEXT: + default: + fileicon = "file.raw"; + } + frameBuffer->paintIcon(fileicon, x+5 , ypos + (fheight-16) / 2 ); + + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(x + 35, ypos + fheight, colwidth1 - 10 , FILESYSTEM_ENCODING_TO_UTF8_STRING(actual_file->getFileName()), color, 0, true); // UTF-8 + + if( S_ISREG(actual_file->Mode) ) + { + if (g_settings.filebrowser_showrights != 0) + { + const char * attribute = "xwr"; + char modestring[9 + 1]; + for (int m = 8; m >= 0; m--) + { + modestring[8 - m] = (actual_file->Mode & (1 << m)) ? attribute[m % 3] : '-'; + } + modestring[9] = 0; + + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(x + 35 + colwidth1 , ypos+ fheight, colwidth2 - 10, modestring, color, 0, true); // UTF-8 + } + +#define GIGABYTE 1073741824LL +#define MEGABYTE 1048576LL +#define KILOBYTE 1024LL + char tmpstr[256]; + const char *unit = ""; + long long factor = 0; + if (actual_file->Size >= GIGABYTE) + { + factor = GIGABYTE; + unit = "G"; + } + else if (actual_file->Size >= MEGABYTE) + { + factor = MEGABYTE; + unit = "M"; + } + else if (actual_file->Size >= KILOBYTE) + { + factor = KILOBYTE; + unit = "k"; + } + if (factor) + { + int a = actual_file->Size / factor; + int b = (actual_file->Size - a * factor) * 1000 / factor; + snprintf(tmpstr, sizeof(tmpstr), "%d.%03d%s", a, b, unit); + } + else + snprintf(tmpstr,sizeof(tmpstr),"%d", (int)actual_file->Size); + + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(x + 35 + colwidth1 + colwidth2, ypos+ fheight, colwidth3 - 10, tmpstr, color); + } + + if( S_ISDIR(actual_file->Mode) ) + { + char timestring[18]; + time_t rawtime; + + rawtime = actual_file->Time; + strftime(timestring, 18, "%d-%m-%Y %H:%M", gmtime(&rawtime)); + + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(x + 35 + colwidth1_dir, ypos+ fheight, colwidth2_dir - 10, timestring, color); + } + } + } + else + frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, COL_MENUCONTENT_PLUS_0/*DARK*/); +} + +//------------------------------------------------------------------------ + +void CFileBrowser::paintHead() +{ + char l_name[100]; + frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0, RADIUS_MID, CORNER_TOP); +#ifdef ENABLE_INTERNETRADIO + if(m_Mode == ModeSC) + snprintf(l_name, sizeof(l_name), "%s %s", g_Locale->getText(LOCALE_AUDIOPLAYER_ADD_SC), FILESYSTEM_ENCODING_TO_UTF8_STRING(name).c_str()); // UTF-8 + else +#endif + snprintf(l_name, sizeof(l_name), "%s %s", g_Locale->getText(LOCALE_FILEBROWSER_HEAD), FILESYSTEM_ENCODING_TO_UTF8_STRING(name).c_str()); // UTF-8 + + g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_TITLE]->RenderString(x+10,y+theight+1, width-11, l_name, COL_MENUHEAD, 0, true); // UTF-8 +} + +//------------------------------------------------------------------------ + +const struct button_label FileBrowserButtons[3] = +{ + { NEUTRINO_ICON_BUTTON_RED , LOCALE_FILEBROWSER_NEXTPAGE }, + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_FILEBROWSER_PREVPAGE }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_FILEBROWSER_MARK }, +}; +const struct button_label FileBrowserFilterButton[2] = +{ + { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_FILEBROWSER_FILTER_INACTIVE }, + { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_FILEBROWSER_FILTER_ACTIVE }, +}; + +void CFileBrowser::paintFoot() +{ + int dx = (width-20) / 4; + //Second Line (bottom, top) + int by2 = y + height - (foheight - 4); + int ty2 = by2 + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight(); + + //Background + frameBuffer->paintBoxRel(x, y + height - (2 * foheight ), width, (2 * foheight ), COL_INFOBAR_SHADOW_PLUS_1, RADIUS_MID, CORNER_BOTTOM); + + if (!(filelist.empty())) + { + int by = y + height - 2 * (foheight - 4); + + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 10, by, dx, Multi_Select ? 3 : 2, FileBrowserButtons); + + if(Filter != NULL) + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 10 + (3 * dx), by, dx, 1, &(FileBrowserFilterButton[use_filter?0:1])); + + //OK-Button + if( (filelist[selected].getType() != CFile::FILE_UNKNOWN) || (S_ISDIR(filelist[selected].Mode)) ) + { + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, x +3 , by2 - 3); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x + 35, ty2, dx - 35, g_Locale->getText(LOCALE_FILEBROWSER_SELECT), COL_INFOBAR /*_SHADOW_PLUS_1*/, 0, true); // UTF-8 + + } + + //?-Button + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, x + (1 * dx), by2 - 3); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x + 35 + (1 * dx), ty2, dx - 35, g_Locale->getText(sortByNames[g_settings.filebrowser_sortmethod]), COL_INFOBAR /*_SHADOW_PLUS_1*/, 0, true); // UTF-8 + + //Mute-Button + if (strncmp(Path.c_str(), VLC_URI, strlen(VLC_URI)) != 0) { //Not in vlc mode + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MUTE_SMALL, x + (2 * dx), by2 - 3); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x + 35 + (2 * dx), ty2, dx - 35, g_Locale->getText(LOCALE_FILEBROWSER_DELETE), COL_INFOBAR /*_SHADOW_PLUS_1*/, 0, true); // UTF-8 + } + + if(m_SMSKeyInput.getOldKey()!=0) + { + char cKey[2]={m_SMSKeyInput.getOldKey(),0}; + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x + width - 16, by2 , 16, cKey, COL_MENUHEAD, 0, true); // UTF-8 + } + } +} + +//------------------------------------------------------------------------ + +void CFileBrowser::paint() +{ + liststart = (selected/listmaxshow)*listmaxshow; + +// if (filelist[0].Name.length() != 0) +// frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, x+ width- 30, y+ 5 ); + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, g_Locale->getText(LOCALE_FILEBROWSER_HEAD)); + + for(unsigned int count=0;countpaintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((filelist.size()- 1)/ listmaxshow)+ 1; + int sbs= (selected/listmaxshow); + + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ sbs*(sb-4)/sbc, 11, (sb-4)/sbc, COL_MENUCONTENT_PLUS_3, RADIUS_SMALL); +} + +//------------------------------------------------------------------------ + +void CFileBrowser::SMSInput(const neutrino_msg_t msg) +{ + unsigned char key = m_SMSKeyInput.handleMsg(msg); + + unsigned int i; + for(i=(selected+1) % filelist.size(); i != selected ; i= (i+1) % filelist.size()) + { + if(tolower(filelist[i].getFileName()[0]) == key) + { + break; + } + } + int prevselected=selected; + selected=i; + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paint(); + } + else + { + paintItem(selected - liststart); + } +} + +//------------------------------------------------------------------------ + +void CFileBrowser::recursiveDelete(const char* file) +{ + stat_struct statbuf; + dirent_struct **namelist; + int n; + printf("Delete %s\n", file); + if(my_lstat(file,&statbuf) == 0) + { + if(S_ISDIR(statbuf.st_mode)) + { + n = my_scandir(file, &namelist, 0, my_alphasort); + while(n--) + { + if(strcmp(namelist[n]->d_name, ".")!=0 && strcmp(namelist[n]->d_name, "..")!=0) + { + std::string fullname = (std::string)file + "/" + namelist[n]->d_name; + recursiveDelete(fullname.c_str()); + } + free(namelist[n]); + } + free(namelist); + rmdir(file); + } + else + { + unlink(file); + } + } + else + perror(file); +} diff --git a/src/gui/filebrowser.h b/src/gui/filebrowser.h new file mode 100644 index 000000000..6a8497ce4 --- /dev/null +++ b/src/gui/filebrowser.h @@ -0,0 +1,233 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __FILEBROWSER_HPP__ +#define __FILEBROWSER_HPP__ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#define ENABLE_INTERNETRADIO +#define VLC_URI "vlc://" + +/** + * Converts input of numeric keys to SMS style char input. + */ +class SMSKeyInput +{ + // time since last input + timeval m_oldKeyTime; + + // last key input + unsigned char m_oldKey; + + // keypresses within this period are taken as a sequence + int m_timeout; +public: + SMSKeyInput(); + + /** + * Returns the SMS char calculated with respect to the new input. + * @param msg the current RC input + * @return the calculated SMS char + */ + unsigned char handleMsg(const neutrino_msg_t msg); + + /** + * Resets the key history which is needed for proper calculation + * of the SMS char by #handleMsg(neutrino_msg_t) + */ + void resetOldKey(); + + /** + * @return the last key calculated by #handleMsg(neutrino_msg_t) + */ + unsigned char getOldKey() const; + + /** + * Returns time of last key push. + * resolution: usecs + */ + const timeval* getOldKeyTime() const; + + /** + * Returns time of last key push. + * resolution: seconds + */ + time_t getOldKeyTimeSec() const; + + int getTimeout() const; + + /** + * Sets the timeout. + * @param timeout keypresses within this period are taken as a + * sequence. unit: msecs + */ + void setTimeout(int timeout); +}; +//------------------------------------------------------------------------ + + +class CFileFilter +{ + std::vector Filter; +public: + void addFilter(const std::string & filter){Filter.push_back(filter);}; + bool matchFilter(const std::string & name) + { + int ext_pos = 0; + ext_pos = name.rfind('.'); + if( ext_pos > 0) + { + std::string extension; + extension = name.substr(ext_pos + 1, name.length() - ext_pos); + for(unsigned int i = 0; i < Filter.size();i++) + if(strcasecmp(Filter[i].c_str(),extension.c_str()) == 0) + return true; + } + return false; + }; + void Clear(void) { Filter.clear();}; +}; +//------------------------------------------------------------------------ + +#define FILEBROWSER_NUMBER_OF_SORT_VARIANTS 5 + +class CFileBrowser +{ + private: + CFrameBuffer *frameBuffer; + + CFileList selected_filelist; + bool readDir(const std::string & dirname, CFileList* flist); +#ifdef ENABLE_MOVIEPLAYER_VLC + bool readDir_vlc(const std::string & dirname, CFileList* flist); +#endif + bool readDir_std(const std::string & dirname, CFileList* flist); +#ifdef ENABLE_INTERNETRADIO + bool readDir_sc(const std::string & dirname, CFileList* flist); +#endif + void addRecursiveDir(CFileList * re_filelist, std::string path, bool bRootCall, CProgressWindow * progress = NULL); + void SMSInput(const neutrino_msg_t msg); + + unsigned int selected; + unsigned int liststart; + unsigned int listmaxshow; + std::vector selections; + + int fheight; // Fonthoehe Filelist-Inhalt + int theight; // Fonthoehe Filelist-Titel + int foheight; // Hoehe der button leiste + std::string name; + std::string base; + std::string m_baseurl; + int width; + int height; + bool use_filter; + bool bCancel; + + int x; + int y; + + SMSKeyInput m_SMSKeyInput; + + void paintItem(unsigned pos); + void paint(); + void paintHead(); + void paintFoot(); + void recursiveDelete(const char* file); + + protected: + void commonInit(); + + public: + CFileList filelist; + + typedef enum { + ModeFile, + ModeVLC, + ModeSC + } tFileBrowserMode; + + /** + * @param selection select the specified entry, ignored if selection == -1 + */ + void ChangeDir(const std::string & filename, int selection = -1); + void hide(); + + std::string Path; + bool Multi_Select; + bool Dirs_Selectable; + bool Dir_Mode; + bool Hide_records; + CFileFilter * Filter; + + CFileBrowser(); + CFileBrowser(const char * const _base, const tFileBrowserMode mode = ModeFile); + ~CFileBrowser(); + + bool exec(const char * const dirname); + CFile *getSelectedFile(); + + inline const CFileList & getSelectedFiles(void) const + { + return selected_filelist; + } + + inline const std::string & getCurrentDir(void) const + { + return Path; + } + +// size_t CurlWriteToString(void *ptr, size_t size, size_t nmemb, void *data); + private: + tFileBrowserMode m_Mode; +}; + +#endif diff --git a/src/gui/hdd_menu.cpp b/src/gui/hdd_menu.cpp new file mode 100644 index 000000000..9d587f6a6 --- /dev/null +++ b/src/gui/hdd_menu.cpp @@ -0,0 +1,458 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "gui/widget/menue.h" +#include "gui/widget/stringinput.h" +#include "gui/widget/messagebox.h" +#include "gui/widget/hintbox.h" +#include "gui/widget/progresswindow.h" + +#include "system/setting_helpers.h" +#include "system/settings.h" +#include "system/debug.h" + +#include +#include + +int safe_mkdir(char * path); + +static int my_filter(const struct dirent * dent) +{ + if(dent->d_name[0] == 's' && dent->d_name[1] == 'd') + return 1; + return 0; +} + +int CHDDMenuHandler::exec(CMenuTarget* parent, const std::string &actionkey) +{ + if (parent) + parent->hide(); + + return doMenu (); +} + +int CHDDMenuHandler::doMenu () +{ + FILE * f; + int fd; + struct dirent **namelist; + int ret; + + bool hdd_found = 0; + int n = scandir("/sys/block", &namelist, my_filter, alphasort); +#if 0 + if(n <= 0) { + //FIXME no hdd found message + return 0; + } +#endif + + CMenuWidget* hddmenu = new CMenuWidget(LOCALE_HDD_SETTINGS, NEUTRINO_ICON_SETTINGS); + hddmenu->addItem( GenericMenuBack ); + hddmenu->addItem( GenericMenuSeparatorLine ); + + hddmenu->addItem( new CMenuOptionChooser(LOCALE_HDD_SLEEP, &g_settings.hdd_sleep, HDD_SLEEP_OPTIONS, HDD_SLEEP_OPTION_COUNT, true)); + hddmenu->addItem( new CMenuOptionChooser(LOCALE_HDD_NOISE, &g_settings.hdd_noise, HDD_NOISE_OPTIONS, HDD_NOISE_OPTION_COUNT, true)); + + hddmenu->addItem(new CMenuForwarder(LOCALE_HDD_ACTIVATE, true, "", new CHDDDestExec())); + + //if(n > 0) + hddmenu->addItem( GenericMenuSeparatorLine ); + + for(int i = 0; i < n;i++) { + char str[256]; + char vendor[128], model[128]; + int64_t bytes; + int64_t megabytes; + int removable = 0; + + printf("HDD: checking /sys/block/%s\n", namelist[i]->d_name); + sprintf(str, "/dev/%s", namelist[i]->d_name); + fd = open(str, O_RDONLY); + if(fd < 0) { + printf("Cant open %s\n", str); + continue; + } + if (ioctl(fd, BLKGETSIZE64, &bytes)) + perror("BLKGETSIZE64"); + + megabytes = bytes/1000000; + + sprintf(str, "/sys/block/%s/device/vendor", namelist[i]->d_name); + f = fopen(str, "r"); + if(!f) { + printf("Cant open %s\n", str); + continue; + } + fscanf(f, "%s", vendor); + fclose(f); + + sprintf(str, "/sys/block/%s/device/model", namelist[i]->d_name); + f = fopen(str, "r"); + if(!f) { + printf("Cant open %s\n", str); + continue; + } + fscanf(f, "%s", model); + fclose(f); + + sprintf(str, "/sys/block/%s/removable", namelist[i]->d_name); + f = fopen(str, "r"); + if(!f) { + printf("Cant open %s\n", str); + continue; + } + fscanf(f, "%d", &removable); + fclose(f); + + sprintf(str, "%s %s (%s-%s %lld %s)\n", g_Locale->getText(LOCALE_HDD_MANAGE), namelist[i]->d_name, vendor, model, megabytes < 10000 ? megabytes : megabytes/1000, megabytes < 10000 ? "MB" : "GB"); + printf("HDD: %s\n", str); + CMenuWidget * tempMenu = new CMenuWidget(str, NEUTRINO_ICON_SETTINGS); + tempMenu->addItem( GenericMenuBack ); + tempMenu->addItem( GenericMenuSeparatorLine ); + //tempMenu->addItem( new CMenuOptionChooser(LOCALE_HDD_FS, &g_settings.hdd_fs, HDD_FILESYS_OPTIONS, HDD_FILESYS_OPTION_COUNT, true)); + tempMenu->addItem(new CMenuForwarder(LOCALE_HDD_FORMAT, true, "", new CHDDFmtExec, namelist[i]->d_name)); + tempMenu->addItem(new CMenuForwarder(LOCALE_HDD_CHECK, true, "", new CHDDChkExec, namelist[i]->d_name)); + hddmenu->addItem(new CMenuForwarderNonLocalized(str, removable ? false : true, NULL, tempMenu)); + hdd_found = 1; + } + if(!hdd_found) + hddmenu->addItem(new CMenuForwarder(LOCALE_HDD_NOT_FOUND, false)); + + ret = hddmenu->exec(NULL, ""); + delete hddmenu; + return ret; +} + +int CHDDDestExec::exec(CMenuTarget* parent, const std::string&) +{ + char cmd[100]; + + printf("CHDDDestExec: noise %d sleep %d\n", g_settings.hdd_noise, g_settings.hdd_sleep); + //FIXME: atm we can have 2 hdd, sata and usb + sprintf(cmd, "hdparm -S%d /dev/sda >/dev/null 2>/dev/null", g_settings.hdd_sleep); + system(cmd); + sprintf(cmd, "hdparm -M%d /dev/sda >/dev/null 2>/dev/null", g_settings.hdd_noise); + system(cmd); + sprintf(cmd, "hdparm -S%d /dev/sdb >/dev/null 2>/dev/null", g_settings.hdd_sleep); + system(cmd); + sprintf(cmd, "hdparm -M%d /dev/sdb >/dev/null 2>/dev/null", g_settings.hdd_noise); + system(cmd); + sprintf(cmd, "hdparm -K /dev/sda >/dev/null 2>/dev/null"); + system(cmd); + sprintf(cmd, "hdparm -K /dev/sdb >/dev/null 2>/dev/null"); + system(cmd); + return 1; +} + +static int check_and_umount(char * dev, char * path) +{ + char buffer[255]; + FILE *f = fopen("/proc/mounts", "r"); + if(f == NULL) + return -1; + while (fgets (buffer, 255, f) != NULL) { + if(strstr(buffer, dev)) { + printf("HDD: %s mounted\n", path); + fclose(f); + return umount(path); + } + } + fclose(f); + printf("HDD: %s not mounted\n", path); + return 0; +} + +int CHDDFmtExec::exec(CMenuTarget* parent, const std::string& key) +{ + char cmd[100]; + CHintBox * hintbox; + int res; + FILE * f; + char src[128], dst[128]; + CProgressWindow * progress; + bool idone; + + sprintf(src, "/dev/%s1", key.c_str()); + sprintf(dst, "/media/%s1", key.c_str()); + + printf("CHDDFmtExec: key %s\n", key.c_str()); + + res = ShowMsgUTF ( LOCALE_HDD_FORMAT, g_Locale->getText(LOCALE_HDD_FORMAT_WARN), CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo ); + if(res != CMessageBox::mbrYes) + return 0; + + bool srun = system("killall -9 smbd"); + + //res = check_and_umount(dst); + res = check_and_umount(src, dst); + printf("CHDDFmtExec: umount res %d\n", res); + + if(res) { + hintbox = new CHintBox(LOCALE_HDD_FORMAT, g_Locale->getText(LOCALE_HDD_UMOUNT_WARN)); + hintbox->paint(); + sleep(2); + delete hintbox; + goto _return; + } + + f = fopen("/proc/sys/kernel/hotplug", "w"); + if(f) { + fprintf(f, "none\n"); + fclose(f); + } + + progress = new CProgressWindow(); + progress->setTitle(LOCALE_HDD_FORMAT); + progress->exec(NULL,""); + progress->showStatusMessageUTF("Executing fdisk"); + progress->showGlobalStatus(0); + + sprintf(cmd, "/sbin/sfdisk -f -uM /dev/%s", key.c_str()); + printf("CHDDFmtExec: executing %s\n", cmd); + f=popen(cmd, "w"); + if (!f) { + hintbox = new CHintBox(LOCALE_HDD_FORMAT, g_Locale->getText(LOCALE_HDD_FORMAT_FAILED)); + hintbox->paint(); + sleep(2); + delete hintbox; + goto _remount; + } + + fprintf(f, "0,\n;\n;\n;\ny\n"); + pclose(f); + //sleep(1); + + switch(g_settings.hdd_fs) { + case 0: + sprintf(cmd, "/sbin/mkfs.ext3 -T largefile -m0 %s", src); + break; + case 1: + sprintf(cmd, "/sbin/mkreiserfs -f -f %s", src); + break; + default: + return 0; + } + + printf("CHDDFmtExec: executing %s\n", cmd); + + f=popen(cmd, "r"); + if (!f) { + hintbox = new CHintBox(LOCALE_HDD_FORMAT, g_Locale->getText(LOCALE_HDD_FORMAT_FAILED)); + hintbox->paint(); + sleep(2); + delete hintbox; + goto _remount; + } + + char buf[256]; + idone = false; + while(fgets(buf, 255, f) != NULL) + { + printf("%s", buf); + if(!idone && strncmp(buf, "Writing inode", 13)) { + idone = true; + buf[21] = 0; + progress->showGlobalStatus(20); + progress->showStatusMessageUTF(buf); + } + else if(strncmp(buf, "Creating", 8)) { + progress->showGlobalStatus(40); + progress->showStatusMessageUTF(buf); + } + else if(strncmp(buf, "Writing superblocks", 19)) { + progress->showGlobalStatus(60); + progress->showStatusMessageUTF(buf); + } + } + pclose(f); + progress->showGlobalStatus(100); + sleep(2); + + sprintf(cmd, "/sbin/tune2fs -r 0 -c 0 -i 0 %s", src); + printf("CHDDFmtExec: executing %s\n", cmd); + system(cmd); + +_remount: + progress->hide(); + delete progress; + + switch(g_settings.hdd_fs) { + case 0: + res = mount(src, dst, "ext3", 0, NULL); + break; + case 1: + res = mount(src, dst, "reiserfs", 0, NULL); + break; + default: + break; + } + f = fopen("/proc/sys/kernel/hotplug", "w"); + if(f) { + fprintf(f, "/sbin/hotplug\n"); + fclose(f); + } + + if(!res) { + sprintf(cmd, "%s/movies", dst); + safe_mkdir((char *) cmd); + sprintf(cmd, "%s/pictures", dst); + safe_mkdir((char *) cmd); + sprintf(cmd, "%s/epg", dst); + safe_mkdir((char *) cmd); + sprintf(cmd, "%s/music", dst); + safe_mkdir((char *) cmd); + sync(); + } +_return: + if(!srun) system("smbd"); + return menu_return::RETURN_REPAINT; +} + +int CHDDChkExec::exec(CMenuTarget* parent, const std::string& key) +{ + char cmd[100]; + CHintBox * hintbox; + int res; + char src[128], dst[128]; + FILE * f; + CProgressWindow * progress; + int oldpass = 0, pass, step, total; + int percent = 0, opercent = 0; + + sprintf(src, "/dev/%s1", key.c_str()); + sprintf(dst, "/media/%s1", key.c_str()); + +printf("CHDDChkExec: key %s\n", key.c_str()); + + bool srun = system("killall -9 smbd"); + + //res = check_and_umount(dst); + res = check_and_umount(src, dst); + printf("CHDDChkExec: umount res %d\n", res); + if(res) { + hintbox = new CHintBox(LOCALE_HDD_CHECK, g_Locale->getText(LOCALE_HDD_UMOUNT_WARN)); + hintbox->paint(); + sleep(2); + delete hintbox; + return menu_return::RETURN_REPAINT; + } + + switch(g_settings.hdd_fs) { + case 0: + sprintf(cmd, "/sbin/fsck.ext3 -C 1 -f -y %s", src); + break; + case 1: + sprintf(cmd, "/sbin/reiserfsck --fix-fixable %s", src); + break; + default: + return 0; + } + + printf("CHDDChkExec: Executing %s\n", cmd); + f=popen(cmd, "r"); + if(!f) { + hintbox = new CHintBox(LOCALE_HDD_CHECK, g_Locale->getText(LOCALE_HDD_CHECK_FAILED)); + hintbox->paint(); + sleep(2); + delete hintbox; + goto ret1; + } + + progress = new CProgressWindow(); + progress->setTitle(LOCALE_HDD_CHECK); + progress->exec(NULL,""); + + char buf[256]; + while(fgets(buf, 255, f) != NULL) + { + if(isdigit(buf[0])) { + sscanf(buf, "%d %d %d\n", &pass, &step, &total); + if(total == 0) + total = 1; + if(oldpass != pass) { + oldpass = pass; + progress->showGlobalStatus(pass > 0 ? (pass-1)*20: 0); + } + percent = (step * 100) / total; + if(opercent != percent) { + opercent = percent; +//printf("CHDDChkExec: pass %d : %d\n", pass, percent); + progress->showLocalStatus(percent); + } + } + else if(!strncmp(buf, "Pass", 4)) + progress->showStatusMessageUTF(buf); + } +//printf("CHDDChkExec: %s\n", buf); + pclose(f); + progress->showGlobalStatus(100); + progress->showStatusMessageUTF(buf); + sleep(2); + progress->hide(); + delete progress; + +ret1: + switch(g_settings.hdd_fs) { + case 0: + res = mount(src, dst, "ext3", 0, NULL); + break; + case 1: + res = mount(src, dst, "reiserfs", 0, NULL); + break; + default: + break; + } + printf("CHDDChkExec: mount res %d\n", res); + + if(!srun) system("smbd"); + return menu_return::RETURN_REPAINT; +} diff --git a/src/gui/hdd_menu.h b/src/gui/hdd_menu.h new file mode 100644 index 000000000..36bffde05 --- /dev/null +++ b/src/gui/hdd_menu.h @@ -0,0 +1,55 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __hdd_menu__ +#define __hdd_menu__ + + +#include "widget/menue.h" + +using namespace std; + +class CHDDDestExec : public CMenuTarget +{ +public: + int exec(CMenuTarget* parent, const std::string&); +}; +class CHDDFmtExec : public CMenuTarget +{ +public: + int exec(CMenuTarget* parent, const std::string&); +}; +class CHDDChkExec : public CMenuTarget +{ +public: + int exec(CMenuTarget* parent, const std::string&); +}; + +class CHDDMenuHandler : public CMenuTarget +{ + public: + int exec( CMenuTarget* parent, const std::string &actionkey); + int doMenu(); +}; + +#endif + diff --git a/src/gui/imageinfo.cpp b/src/gui/imageinfo.cpp new file mode 100644 index 000000000..9298f9eb0 --- /dev/null +++ b/src/gui/imageinfo.cpp @@ -0,0 +1,233 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define SCREEN_X 720 +#define SCREEN_Y 572 + +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +extern cVideo * videoDecoder; + +extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ + +CImageInfo::CImageInfo() +{ + Init(); +} + +void CImageInfo::Init(void) +{ + frameBuffer = CFrameBuffer::getInstance(); + + font_head = SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME;; + font_small = SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL; + font_info = SNeutrinoSettings::FONT_TYPE_MENU; + + hheight = g_Font[font_head]->getHeight(); + iheight = g_Font[font_info]->getHeight(); + sheight = g_Font[font_small]->getHeight(); + + max_width = frameBuffer->getScreenWidth(true); + max_height = frameBuffer->getScreenHeight(true); + + width = frameBuffer->getScreenWidth() - 10; + height = frameBuffer->getScreenHeight() - 10; + x=(((g_settings.screen_EndX- g_settings.screen_StartX)-width) / 2) + g_settings.screen_StartX; + y=(((g_settings.screen_EndY- g_settings.screen_StartY)-height) / 2) + g_settings.screen_StartY; +} + +CImageInfo::~CImageInfo() +{ + videoDecoder->Pig(-1, -1, -1, -1); +} + +int CImageInfo::exec(CMenuTarget* parent, const std::string &) +{ + if (parent) + parent->hide(); + + width = frameBuffer->getScreenWidth() - 10; + height = frameBuffer->getScreenHeight() - 10; + x=(((g_settings.screen_EndX- g_settings.screen_StartX)-width) / 2) + g_settings.screen_StartX; + y=(((g_settings.screen_EndY- g_settings.screen_StartY)-height) / 2) + g_settings.screen_StartY; + + paint(); + + //paint_pig( width-170, y, 215, 170); + paint_pig (width - width/3 - 10, y + 10, width/3, height/3); + + neutrino_msg_t msg; + + while (1) + { + neutrino_msg_data_t data; + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd_MS(100); + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if (msg <= CRCInput::RC_MaxRC) + { + break; + } + + if ( msg > CRCInput::RC_MaxRC && msg != CRCInput::RC_timeout) + { + CNeutrinoApp::getInstance()->handleMsg( msg, data ); + } + } + + hide(); + + return menu_return::RETURN_REPAINT; +} + +void CImageInfo::hide() +{ + //frameBuffer->paintBackgroundBoxRel(0,0, max_width,max_height); + frameBuffer->paintBackground(); + videoDecoder->Pig(-1, -1, -1, -1); +} + +void CImageInfo::paint_pig(int x, int y, int w, int h) +{ + //frameBuffer->paintBoxRel(x,y,w,h, COL_BACKGROUND); + frameBuffer->paintBackgroundBoxRel(x,y,w,h); + videoDecoder->Pig(x, y, w, h, frameBuffer->getScreenWidth(true), frameBuffer->getScreenHeight(true)); +} + +void CImageInfo::paintLine(int xpos, int font, const char* text) +{ + char buf[100]; + sprintf((char*) buf, "%s", text); + //g_Font[font]->RenderString(xpos, ypos, width-10, buf, COL_MENUCONTENT, 0, true); + g_Font[font]->RenderString(xpos, ypos, width-10, buf, COL_INFOBAR, 0, true); +} + +void CImageInfo::paint() +{ + const char * head_string; + char imagedate[18] = ""; + int xpos = x+10; + + ypos = y+5; + + head_string = g_Locale->getText(LOCALE_IMAGEINFO_HEAD); + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, head_string); + + //frameBuffer->paintBoxRel(0, 0, max_width, max_height, COL_MENUHEAD_PLUS_0); + frameBuffer->paintBoxRel(0, 0, max_width, max_height, COL_INFOBAR_PLUS_0); + g_Font[font_head]->RenderString(xpos, ypos+ hheight+1, width, head_string, COL_MENUHEAD, 0, true); + + ypos += hheight; + ypos += (iheight >>1); + + + CConfigFile config('\t'); + config.loadConfig("/.version"); + + const char * imagename = config.getString("imagename", "Neutrino").c_str(); + const char * homepage = config.getString("homepage", "n/a").c_str(); + const char * creator = config.getString("creator", "n/a").c_str(); + const char * version = config.getString("version", "no version").c_str(); + const char * docs = config.getString("docs", "man neutrino").c_str(); + const char * forum = config.getString("forum", "http://forum.tuxbox.org").c_str(); + + static CFlashVersionInfo versionInfo(version); + const char * releaseCycle = versionInfo.getReleaseCycle(); + sprintf((char*) imagedate, "%s %s", versionInfo.getDate(), versionInfo.getTime()); + + ypos += iheight; + paintLine(xpos , font_info, g_Locale->getText(LOCALE_IMAGEINFO_IMAGE)); + paintLine(xpos+125, font_info, imagename); + + ypos += iheight; + paintLine(xpos , font_info, g_Locale->getText(LOCALE_IMAGEINFO_DATE)); + paintLine(xpos+125, font_info, imagedate); + + ypos += iheight; + paintLine(xpos , font_info, g_Locale->getText(LOCALE_IMAGEINFO_VERSION)); + paintLine(xpos+125, font_info, releaseCycle); + + ypos += iheight; + paintLine(xpos , font_info, g_Locale->getText(LOCALE_IMAGEINFO_CREATOR)); + paintLine(xpos+125, font_info, creator); + + ypos += iheight+15; + paintLine(xpos , font_info, g_Locale->getText(LOCALE_IMAGEINFO_HOMEPAGE)); + paintLine(xpos+125, font_info, homepage); + + ypos += iheight; + paintLine(xpos , font_info, g_Locale->getText(LOCALE_IMAGEINFO_DOKUMENTATION)); + paintLine(xpos+125, font_info, docs); + + ypos += iheight; + paintLine(xpos , font_info, g_Locale->getText(LOCALE_IMAGEINFO_FORUM)); + paintLine(xpos+125, font_info, forum); + + ypos += iheight+15; + paintLine(xpos, font_info,g_Locale->getText(LOCALE_IMAGEINFO_LICENSE)); + paintLine(xpos+125, font_small, "This program is free software; you can redistribute it and/or modify"); + + ypos+= sheight; + paintLine(xpos+125, font_small, "it under the terms of the GNU General Public License as published by"); + + ypos+= sheight; + paintLine(xpos+125, font_small, "the Free Software Foundation; either version 2 of the License, or"); + + ypos+= sheight; + paintLine(xpos+125, font_small, "(at your option) any later version."); + + ypos+= sheight+10; + paintLine(xpos+125, font_small, "This program is distributed in the hope that it will be useful,"); + + ypos+= sheight; + paintLine(xpos+125, font_small, "but WITHOUT ANY WARRANTY; without even the implied warranty of"); + + ypos+= sheight; + paintLine(xpos+125, font_small, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); + + ypos+= sheight; + paintLine(xpos+125, font_small, "See the GNU General Public License for more details."); + + ypos+= sheight+10; + paintLine(xpos+125, font_small, "You should have received a copy of the GNU General Public License"); + + ypos+= sheight; + paintLine(xpos+125, font_small, "along with this program; if not, write to the Free Software"); + + ypos+= sheight; + paintLine(xpos+125, font_small, "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA."); +} diff --git a/src/gui/imageinfo.h b/src/gui/imageinfo.h new file mode 100644 index 000000000..f5bf95fc2 --- /dev/null +++ b/src/gui/imageinfo.h @@ -0,0 +1,69 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __imageinfo__ +#define __imageinfo__ + +#include + +#include + +#include +#include + +class CImageInfo : public CMenuTarget +{ + private: + void Init(void); + CConfigFile * configfile; + CFrameBuffer *frameBuffer; + int x; + int y; + int ypos; + int width; + int height; + int hheight,iheight,sheight; // head/info/small font height + + int max_height; // Frambuffer 0.. max + int max_width; + + int font_head; + int font_info; + int font_small; + + CPIG *pig; + + void paint(); + void paint_pig(int x, int y, int w, int h); + void paintLine(int xpos, int font, const char* text); + + public: + + CImageInfo(); + ~CImageInfo(); + + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + +#endif + diff --git a/src/gui/infoclock.cpp b/src/gui/infoclock.cpp new file mode 100644 index 000000000..2f9f11d9c --- /dev/null +++ b/src/gui/infoclock.cpp @@ -0,0 +1,87 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include "infoclock.h" + +#define XOFF 10 +#define YOFF 0 + +CInfoClock::CInfoClock() +{ + frameBuffer = CFrameBuffer::getInstance(); + + time_height = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->getHeight(); + int t1 = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->getRenderWidth(widest_number); + int t2 = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->getRenderWidth(":"); + time_width = t1*6 + t2*2; + thrTimer = 0; +} + +CInfoClock::~CInfoClock() +{ + if(thrTimer) + pthread_cancel(thrTimer); + thrTimer = 0; +} + +void CInfoClock::paintTime( bool show_dot) +{ + int x = g_settings.screen_EndX - XOFF; + int y = g_settings.screen_StartY + YOFF; + + char timestr[10]; + time_t tm; + + tm = time(0); + if(show_dot) + strftime((char*) ×tr, 20, "%H:%M:%S", localtime(&tm)); + else + strftime((char*) ×tr, 20, "%H.%M:%S", localtime(&tm)); + frameBuffer->paintBoxRel(x - time_width - 15, y, time_width, time_height, COL_MENUCONTENT_PLUS_0, 7, 3); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->RenderString(x - time_width- 10, y+ time_height, time_width, timestr, COL_MENUCONTENT); +} + +void* CInfoClock::TimerProc(void *arg) +{ + + bool show_dot = false; + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0); + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS,0); + + CInfoClock *InfoClock = (CInfoClock*) arg; + + InfoClock->paintTime(show_dot); + while(1) { + sleep(1); + show_dot = !show_dot; + InfoClock->paintTime(show_dot); + } +} + +void CInfoClock::StartClock() +{ + if(!thrTimer) { + pthread_create (&thrTimer, NULL, TimerProc, (void*) this) ; + pthread_detach(thrTimer); + } +} + +void CInfoClock::StopClock() +{ + int x = g_settings.screen_EndX - XOFF; + int y = g_settings.screen_StartY + YOFF; + if(thrTimer) { + pthread_cancel(thrTimer); + thrTimer = 0; + frameBuffer->paintBackgroundBoxRel(x - time_width - 15, y, time_width, time_height); + } +} diff --git a/src/gui/infoclock.h b/src/gui/infoclock.h new file mode 100644 index 000000000..68fca718e --- /dev/null +++ b/src/gui/infoclock.h @@ -0,0 +1,36 @@ +#ifndef __infoclock__ +#define __infoclock__ + + +#include +#include +#include + +#include "gui/color.h" + +#include + + +class CInfoClock +{ + private: + CFrameBuffer * frameBuffer; + + pthread_t thrTimer; + int time_width; + int time_height; + void paintTime( bool show_dot); + + static void CleanUpProc(void* arg); + static void* TimerProc(void *arg); + + public: + CInfoClock(); + ~CInfoClock(); + + void StartClock(); + void StopClock(); + +}; + +#endif diff --git a/src/gui/infoviewer.cpp b/src/gui/infoviewer.cpp new file mode 100644 index 000000000..93a66287a --- /dev/null +++ b/src/gui/infoviewer.cpp @@ -0,0 +1,1316 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include + +void sectionsd_getEventsServiceKey(t_channel_id serviceUniqueKey, CChannelEventList &eList, char search = 0, std::string search_text = ""); +void sectionsd_getCurrentNextServiceKey(t_channel_id uniqueServiceKey, CSectionsdClient::responseGetCurrentNextInfoChannelID& current_next ); + +extern CRemoteControl *g_RemoteControl; /* neutrino.cpp */ +extern CPictureViewer * g_PicViewer; +extern CFrontend * frontend; +extern cVideo * videoDecoder; +extern t_channel_id live_channel_id; //zapit + +#define COL_INFOBAR_BUTTONS (COL_INFOBAR_SHADOW + 1) +#define COL_INFOBAR_BUTTONS_BACKGROUND (COL_INFOBAR_SHADOW_PLUS_1) + +#define ICON_LARGE_WIDTH 26 +#define ICON_SMALL_WIDTH 16 +#define ICON_LARGE 30 +#define ICON_SMALL 18 +#define ICON_Y_1 18 + +#define ICON_OFFSET (2 + ICON_LARGE_WIDTH + 2 + ICON_LARGE_WIDTH + 2 + ICON_SMALL_WIDTH + 2) + +#define BOTTOM_BAR_OFFSET 0 +#define SHADOW_OFFSET 6 +#define borderwidth 4 +#define LEFT_OFFSET 5 +#define ASIZE 100 + +// in us +#define FADE_TIME 40000 + +#define LCD_UPDATE_TIME_TV_MODE (60 * 1000 * 1000) + +#define ROUND_RADIUS 7 + +int time_left_width; +int time_dot_width; +int time_width; +int time_height; +bool newfreq = true; +char old_timestr[10]; +static event_id_t last_curr_id = 0, last_next_id = 0; + +extern CZapitClient::SatelliteList satList; +static bool sortByDateTime (const CChannelEvent& a, const CChannelEvent& b) +{ + return a.startTime < b.startTime; +} + +extern int timeshift; +extern unsigned char file_prozent; +extern std::string g_file_epg; +extern std::string g_file_epg1; +extern bool autoshift; +extern uint32_t shift_timer; + +#define RED_BAR 40 +#define YELLOW_BAR 70 +#define GREEN_BAR 100 +#define BAR_BORDER 1 +#define BAR_WIDTH 72 //(68+BAR_BORDER*2) +#define BAR_HEIGHT 12 //(13 + BAR_BORDER*2) +#define TIME_BAR_HEIGHT 12 +// InfoViewer: H 63 W 27 +#define NUMBER_H 63 +#define NUMBER_W 27 +extern char act_emu_str[20]; +extern std::string ext_channel_name; +int m_CA_Status; +static CScale * timescale; +static CScale * hddscale; +static CScale * varscale; +extern bool timeset; + +CInfoViewer::CInfoViewer () +{ + Init(); +} + +void CInfoViewer::Init() +{ + frameBuffer = CFrameBuffer::getInstance (); + + BoxStartX = BoxStartY = BoxEndX = BoxEndY = 0; + recordModeActive = false; + is_visible = false; + showButtonBar = false; + //gotTime = g_Sectionsd->getIsTimeSet (); + gotTime = timeset; + CA_Status = false; + virtual_zap_mode = false; + chanready = 1; + fileplay = 0; + sigscale = new CScale(BAR_WIDTH, 8, RED_BAR, GREEN_BAR, YELLOW_BAR); + snrscale = new CScale(BAR_WIDTH, 8, RED_BAR, GREEN_BAR, YELLOW_BAR); + hddscale = new CScale(100, 4, 50, GREEN_BAR, 75, true); + varscale = new CScale(100, 4, 50, GREEN_BAR, 75, true); + timescale = new CScale(100, TIME_BAR_HEIGHT, 30, GREEN_BAR, 70, true); + channel_id = live_channel_id; +} + +void CInfoViewer::start () +{ + ChanWidth = 122; + ChanHeight = 70; + + lcdUpdateTimer = g_RCInput->addTimer (LCD_UPDATE_TIME_TV_MODE, false, true); +} + +void CInfoViewer::paintTime (bool show_dot, bool firstPaint) +{ + if (gotTime) { + int ChanNameY = BoxStartY + (ChanHeight >> 1) + 5; //oberkante schatten? + + char timestr[10]; + struct timeb tm; + + ftime (&tm); + strftime ((char *) ×tr, 20, "%H:%M", localtime (&tm.time)); + + if ((!firstPaint) && (strcmp (timestr, old_timestr) == 0)) { + if (show_dot) + frameBuffer->paintBoxRel (BoxEndX - time_width + time_left_width - LEFT_OFFSET, ChanNameY, time_dot_width, time_height / 2 + 2, COL_INFOBAR_PLUS_0); + else + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->RenderString (BoxEndX - time_width + time_left_width - LEFT_OFFSET, ChanNameY + time_height, time_dot_width, ":", COL_INFOBAR); + strcpy (old_timestr, timestr); + } else { + strcpy (old_timestr, timestr); + + if (!firstPaint) { + frameBuffer->paintBoxRel (BoxEndX - time_width - LEFT_OFFSET, ChanNameY, time_width + LEFT_OFFSET, time_height, COL_INFOBAR_PLUS_0, ROUND_RADIUS, 1); + } + + timestr[2] = 0; + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->RenderString (BoxEndX - time_width - LEFT_OFFSET, ChanNameY + time_height, time_left_width, timestr, COL_INFOBAR); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->RenderString (BoxEndX - time_left_width - LEFT_OFFSET, ChanNameY + time_height, time_left_width, ×tr[3], COL_INFOBAR); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->RenderString (BoxEndX - time_width + time_left_width - LEFT_OFFSET, ChanNameY + time_height, time_dot_width, ":", COL_INFOBAR); + if (show_dot) + frameBuffer->paintBoxRel (BoxEndX - time_left_width - time_dot_width - LEFT_OFFSET, ChanNameY, time_dot_width, time_height / 2 + 2, COL_INFOBAR_PLUS_0); + } + } +} + +void CInfoViewer::showRecordIcon (const bool show) +{ + recordModeActive = CNeutrinoApp::getInstance ()->recordingstatus || shift_timer; + if (recordModeActive) { + int ChanNameX = BoxStartX + ChanWidth + 20; + if (show) { + frameBuffer->paintIcon (autoshift ? "ats.raw" : NEUTRINO_ICON_BUTTON_RED, ChanNameX, BoxStartY + 12); + if(!autoshift && !shift_timer) { + int chanH = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight (); + frameBuffer->paintBoxRel (ChanNameX + 28 + SHADOW_OFFSET, BoxStartY + 12 + SHADOW_OFFSET, 300, 20, COL_INFOBAR_SHADOW_PLUS_0); + frameBuffer->paintBoxRel (ChanNameX + 28, BoxStartY + 12, 300, 20, COL_INFOBAR_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString (ChanNameX + 30, BoxStartY + 12 + chanH, 300, ext_channel_name.c_str (), COL_INFOBAR, 0, true); + } else + frameBuffer->paintBackgroundBoxRel (ChanNameX + 28, BoxStartY + 12, 300 + SHADOW_OFFSET, 20 + SHADOW_OFFSET); + } else { + frameBuffer->paintBackgroundBoxRel (ChanNameX, BoxStartY + 10, 20, 20); + } + } +} + +void CInfoViewer::showTitle (const int ChanNum, const std::string & Channel, const t_satellite_position satellitePosition, const t_channel_id new_channel_id, const bool calledFromNumZap, int epgpos) +{ + last_curr_id = last_next_id = 0; + std::string ChannelName = Channel; + bool show_dot = true; + bool fadeOut = false; + int fadeValue; + bool new_chan = false; +//printf("CInfoViewer::showTitle ************************* chan num %d name %s\n", ChanNum, Channel.c_str()); + //aspectRatio = videoDecoder->getAspectRatio() > 2 ? 1 : 0; + aspectRatio = 0; + + showButtonBar = !calledFromNumZap; + bool fadeIn = g_settings.widget_fade && (!is_visible) && showButtonBar; + + is_visible = true; + if (!calledFromNumZap && fadeIn) + fadeTimer = g_RCInput->addTimer (FADE_TIME, false); + + fileplay = (ChanNum == 0); + newfreq = true; + sigscale->reset(); snrscale->reset(); timescale->reset(); hddscale->reset(); varscale->reset(); + + InfoHeightY = NUMBER_H * 9 / 8 + 2 * g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getHeight () + 25; + InfoHeightY_Info = 40; + + time_height = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->getHeight () + 5; + time_left_width = 2 * g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->getRenderWidth (widest_number); + time_dot_width = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->getRenderWidth (":"); + time_width = time_left_width * 2 + time_dot_width; + + BoxStartX = g_settings.screen_StartX + 10; + BoxEndX = g_settings.screen_EndX - 10; + BoxEndY = g_settings.screen_EndY - 10; + + int BoxEndInfoY = showButtonBar ? (BoxEndY - InfoHeightY_Info) : (BoxEndY); + BoxStartY = BoxEndInfoY - InfoHeightY; + + if (!gotTime) + gotTime = timeset; + + if (fadeIn) { + fadeValue = 0x10; + frameBuffer->setBlendLevel(fadeValue, fadeValue); + } else + fadeValue = g_settings.gtx_alpha1; + + // kill linke seite + frameBuffer->paintBackgroundBox (BoxStartX, BoxStartY + ChanHeight, BoxStartX + (ChanWidth / 3), BoxStartY + ChanHeight + InfoHeightY_Info + 10); + // kill progressbar + frameBuffer->paintBackgroundBox (BoxEndX - 120, BoxStartY, BoxEndX, BoxStartY + ChanHeight); + + int col_NumBoxText; + int col_NumBox; + if (virtual_zap_mode) { + col_NumBoxText = COL_MENUHEAD; + col_NumBox = COL_MENUHEAD_PLUS_0; + if ((channel_id != new_channel_id) || (evtlist.empty())) { + evtlist.clear(); + //evtlist = g_Sectionsd->getEventsServiceKey(new_channel_id & 0xFFFFFFFFFFFFULL); + sectionsd_getEventsServiceKey(new_channel_id & 0xFFFFFFFFFFFFULL, evtlist); + if (!evtlist.empty()) + sort(evtlist.begin(),evtlist.end(), sortByDateTime); + new_chan = true; + } + } else { + col_NumBoxText = COL_INFOBAR; + col_NumBox = COL_INFOBAR_PLUS_0; + } + if (! calledFromNumZap && !(g_RemoteControl->subChannels.empty()) && (g_RemoteControl->selected_subchannel > 0)) + { + channel_id = g_RemoteControl->subChannels[g_RemoteControl->selected_subchannel].getChannelID(); + ChannelName = g_RemoteControl->subChannels[g_RemoteControl->selected_subchannel].subservice_name; + } else { + channel_id = new_channel_id; + } + + int ChanNameX = BoxStartX + ChanWidth + SHADOW_OFFSET; + int ChanNameY = BoxStartY + (ChanHeight / 2) + 5; //oberkante schatten? + ChanInfoX = BoxStartX + (ChanWidth / 3); + + asize = (BoxEndX - (2*ICON_LARGE_WIDTH + 2*ICON_SMALL_WIDTH + 4*2) - 102) - ChanInfoX; + asize = asize - (NEUTRINO_ICON_BUTTON_RED_WIDTH+6)*4; + asize = asize / 4; + + //Shadow + frameBuffer->paintBox (BoxEndX-20, ChanNameY + SHADOW_OFFSET, BoxEndX + SHADOW_OFFSET, BoxEndY, COL_INFOBAR_SHADOW_PLUS_0, ROUND_RADIUS, 1); + frameBuffer->paintBox (ChanInfoX + SHADOW_OFFSET, BoxEndY -20, BoxEndX + SHADOW_OFFSET, BoxEndY + SHADOW_OFFSET, COL_INFOBAR_SHADOW_PLUS_0, ROUND_RADIUS, 2); //round + + //infobox + frameBuffer->paintBoxRel (ChanNameX-10, ChanNameY, BoxEndX-ChanNameX+10, BoxEndInfoY-ChanNameY, COL_INFOBAR_PLUS_0, ROUND_RADIUS, 1); // round + + //number box + frameBuffer->paintBoxRel (BoxStartX + SHADOW_OFFSET, BoxStartY + SHADOW_OFFSET, ChanWidth, ChanHeight + 4, COL_INFOBAR_SHADOW_PLUS_0, ROUND_RADIUS, 3); // round + frameBuffer->paintBoxRel (BoxStartX, BoxStartY, ChanWidth, ChanHeight + 4, COL_INFOBAR_PLUS_0, ROUND_RADIUS, 3); // round + + int ChanNumYPos = BoxStartY + ChanHeight; + if (g_settings.infobar_sat_display && satellitePosition != 0 && satellitePositions.size()) { + sat_iterator_t sit = satellitePositions.find(satellitePosition); + + if(sit != satellitePositions.end()) { + int satNameWidth = g_SignalFont->getRenderWidth (sit->second.name); + if (satNameWidth > (ChanWidth - 4)) + satNameWidth = ChanWidth - 4; + + int chanH = g_SignalFont->getHeight (); + g_SignalFont->RenderString (3 + BoxStartX + ((ChanWidth - satNameWidth) / 2), BoxStartY + chanH, satNameWidth, sit->second.name, COL_INFOBAR); + } + ChanNumYPos += 5; + } + paintTime (show_dot, true); + showRecordIcon (show_dot); + show_dot = !show_dot; + + char strChanNum[10]; + sprintf (strChanNum, "%d", ChanNum); + + int ChanNumWidth = 0; + bool logo_ok = false; + if(showButtonBar) { +#define PIC_W 52 +#define PIC_H 39 +#define PIC_X (ChanNameX + 10) +#define PIC_Y (ChanNameY + time_height - PIC_H) + logo_ok = g_PicViewer->DisplayLogo(channel_id, PIC_X, PIC_Y, PIC_W, PIC_H); + ChanNumWidth = PIC_W + 10; + } + if (ChanNum && !logo_ok) { + int ChanNumHeight = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_NUMBER]->getHeight (); + ChanNumWidth = 5 + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_NUMBER]->getRenderWidth (strChanNum); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_NUMBER]->RenderString (ChanNameX + 5, ChanNameY + ChanNumHeight, ChanNumWidth, strChanNum, col_NumBoxText); + } + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->RenderString (ChanNameX + 10 + ChanNumWidth, ChanNameY + time_height, BoxEndX - (ChanNameX + 20) - time_width - LEFT_OFFSET - 5 - ChanNumWidth, ChannelName, COL_INFOBAR, 0, true); // UTF-8 + + int ChanInfoY = BoxStartY + ChanHeight + 10; + ButtonWidth = (BoxEndX - ChanInfoX - ICON_OFFSET) >> 2; + + frameBuffer->paintBox (ChanInfoX, ChanInfoY, ChanNameX, BoxEndInfoY, COL_INFOBAR_PLUS_0); + + if (showButtonBar) { + sec_timer_id = g_RCInput->addTimer (1*1000*1000, false); + if (BOTTOM_BAR_OFFSET > 0) + frameBuffer->paintBackgroundBox (ChanInfoX, BoxEndInfoY, BoxEndX, BoxEndInfoY + BOTTOM_BAR_OFFSET); + + frameBuffer->paintBox (ChanInfoX, BoxEndInfoY-2, BoxEndX, BoxEndY-20, COL_BLACK); + { // FIXME + int xcnt = (BoxEndX - ChanInfoX) / 4; + int ycnt = (BoxEndY - BoxEndInfoY - 18) / 4; + for(int i = 0; i < xcnt; i++) { + for(int j = 0; j < ycnt; j++) + frameBuffer->paintBoxRel (ChanInfoX + i*4, BoxEndInfoY + j*4, 2, 2, COL_INFOBAR_PLUS_1); + } + } + frameBuffer->paintBox (ChanInfoX, BoxEndY-20, BoxEndX, BoxEndY, COL_INFOBAR_BUTTONS_BACKGROUND, ROUND_RADIUS, 2); //round + + showSNR(); + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_BLUE, ChanInfoX + 16*3 + asize * 3 + 2*7, BoxEndY - ICON_Y_1); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(ChanInfoX + 16*4 + asize * 3 + 2*8, BoxEndY+2, ButtonWidth - (2 + NEUTRINO_ICON_BUTTON_BLUE_WIDTH + 2 + 2), g_Locale->getText(LOCALE_INFOVIEWER_STREAMINFO), COL_INFOBAR_BUTTONS, 0, true); // UTF-8 + + showButton_Audio (); + showButton_SubServices (); + showIcon_CA_Status(0); + showIcon_16_9 (); + showIcon_VTXT (); + showIcon_SubT(); + } + + if (fileplay) { + show_Data (); + } else { + //info_CurrentNext = getEPG (channel_id); + sectionsd_getCurrentNextServiceKey(channel_id & 0xFFFFFFFFFFFFULL, info_CurrentNext); + if (!evtlist.empty()) { + if (new_chan) { + for ( eli=evtlist.begin(); eli!=evtlist.end(); ++eli ) { + if ((uint)eli->startTime >= info_CurrentNext.current_zeit.startzeit + info_CurrentNext.current_zeit.dauer) + break; + } + if (eli == evtlist.end()) // the end is not valid, so go back + --eli; + } + + if (epgpos != 0) { + info_CurrentNext.flags = 0; + if ((epgpos > 0) && (eli != evtlist.end())) { + ++eli; // next epg + if (eli == evtlist.end()) // the end is not valid, so go back + --eli; + } + else if ((epgpos < 0) && (eli != evtlist.begin())) { + --eli; // prev epg + } + info_CurrentNext.flags = CSectionsdClient::epgflags::has_current; + info_CurrentNext.current_uniqueKey = eli->eventID; + info_CurrentNext.current_zeit.startzeit = eli->startTime; + info_CurrentNext.current_zeit.dauer = eli->duration; + if (eli->description.empty()) + info_CurrentNext.current_name = g_Locale->getText(LOCALE_INFOVIEWER_NOEPG); + else + info_CurrentNext.current_name = eli->description; + info_CurrentNext.current_fsk = '\0'; + + if (eli != evtlist.end()) { + ++eli; + if (eli != evtlist.end()) { + info_CurrentNext.flags = CSectionsdClient::epgflags::has_current | CSectionsdClient::epgflags::has_next; + info_CurrentNext.next_uniqueKey = eli->eventID; + info_CurrentNext.next_zeit.startzeit = eli->startTime; + info_CurrentNext.next_zeit.dauer = eli->duration; + if (eli->description.empty()) + info_CurrentNext.next_name = g_Locale->getText(LOCALE_INFOVIEWER_NOEPG); + else + info_CurrentNext.next_name = eli->description; + } + --eli; + } + } + } + + if (!(info_CurrentNext.flags & (CSectionsdClient::epgflags::has_later | CSectionsdClient::epgflags::has_current | CSectionsdClient::epgflags::not_broadcast))) { + // nicht gefunden / noch nicht geladen + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (ChanNameX + 10, ChanInfoY + 2 * g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getHeight () + 5, BoxEndX - (ChanNameX + 20), g_Locale->getText (gotTime ? (showButtonBar ? LOCALE_INFOVIEWER_EPGWAIT : LOCALE_INFOVIEWER_EPGNOTLOAD) : LOCALE_INFOVIEWER_WAITTIME), COL_INFOBAR, 0, true); // UTF-8 + } else { + show_Data (); + } + } + showLcdPercentOver (); + + if ((g_RemoteControl->current_channel_id == channel_id) && !(((info_CurrentNext.flags & CSectionsdClient::epgflags::has_next) && (info_CurrentNext.flags & (CSectionsdClient::epgflags::has_current | CSectionsdClient::epgflags::has_no_current))) || (info_CurrentNext.flags & CSectionsdClient::epgflags::not_broadcast))) { + g_Sectionsd->setServiceChanged (channel_id & 0xFFFFFFFFFFFFULL, true); + } + + neutrino_msg_t msg; + neutrino_msg_data_t data; + + CNeutrinoApp *neutrino = CNeutrinoApp::getInstance (); + if (!calledFromNumZap) { + + bool hideIt = true; + virtual_zap_mode = false; + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd (g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR]); + + int res = messages_return::none; + time_t ta, tb; + + while (!(res & (messages_return::cancel_info | messages_return::cancel_all))) { + g_RCInput->getMsgAbsoluteTimeout (&msg, &data, &timeoutEnd); +#if 0 + if (!(info_CurrentNext.flags & (CSectionsdClient::epgflags::has_current))) { + if (difftime (time (&tb), ta) > 1.1) { + time (&ta); + info_CurrentNext = getEPG (channel_id); + if ((info_CurrentNext.flags & (CSectionsdClient::epgflags::has_current))) { + show_Data (); + showLcdPercentOver (); + } + } + } +#endif + if (msg == CRCInput::RC_sat || msg == CRCInput::RC_favorites) { + g_RCInput->postMsg (msg, 0); + res = messages_return::cancel_info; + } + else if (msg == CRCInput::RC_help || msg == CRCInput::RC_info) { + g_RCInput->postMsg (NeutrinoMessages::SHOW_EPG, 0); + res = messages_return::cancel_info; + } else if ((msg == NeutrinoMessages::EVT_TIMER) && (data == fadeTimer)) { + if (fadeOut) { // disappear + fadeValue -= 0x10; + if (fadeValue <= 0x10) { + fadeValue = g_settings.gtx_alpha1; + g_RCInput->killTimer (fadeTimer); + res = messages_return::cancel_info; + } else + frameBuffer->setBlendLevel(fadeValue, fadeValue); + } else { // appears + fadeValue += 0x10; + if (fadeValue >= g_settings.gtx_alpha1) { + fadeValue = g_settings.gtx_alpha1; + g_RCInput->killTimer (fadeTimer); + fadeIn = false; + frameBuffer->setBlendLevel(g_settings.gtx_alpha1, g_settings.gtx_alpha2); + } else + frameBuffer->setBlendLevel(fadeValue, fadeValue); + } + } else if ((msg == CRCInput::RC_ok) || (msg == CRCInput::RC_home) || (msg == CRCInput::RC_timeout)) { + if (fadeIn) { + g_RCInput->killTimer (fadeTimer); + fadeIn = false; + } + if ((!fadeOut) && g_settings.widget_fade) { + fadeOut = true; + fadeTimer = g_RCInput->addTimer (FADE_TIME, false); + timeoutEnd = CRCInput::calcTimeoutEnd (1); + } else { +#if 0 + if ((msg != CRCInput::RC_timeout) && (msg != CRCInput::RC_ok)) + if (!fileplay && !timeshift) + g_RCInput->postMsg (msg, data); +#endif + res = messages_return::cancel_info; + } + } else if ((msg == NeutrinoMessages::EVT_TIMER) && (data == sec_timer_id)) { + showSNR (); + paintTime (show_dot, false); + showRecordIcon (show_dot); + show_dot = !show_dot; + + showIcon_16_9(); + } else if ( g_settings.virtual_zap_mode && ((msg == CRCInput::RC_right) || msg == CRCInput::RC_left )) { + virtual_zap_mode = true; + res = messages_return::cancel_all; + hideIt = true; + } else if (!fileplay && !timeshift) { + if ((msg == (neutrino_msg_t) g_settings.key_quickzap_up) || (msg == (neutrino_msg_t) g_settings.key_quickzap_down) || (msg == CRCInput::RC_0) || (msg == NeutrinoMessages::SHOW_INFOBAR)) { + hideIt = false; + //hideIt = (g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR] == 0) ? true : false; + g_RCInput->postMsg (msg, data); + res = messages_return::cancel_info; + } else if (msg == NeutrinoMessages::EVT_TIMESET) { + // Handle anyway! + neutrino->handleMsg (msg, data); + g_RCInput->postMsg (NeutrinoMessages::SHOW_INFOBAR, 0); + hideIt = false; + res = messages_return::cancel_all; + } else { + if (msg == CRCInput::RC_standby) { + g_RCInput->killTimer (sec_timer_id); + if (fadeIn || fadeOut) + g_RCInput->killTimer (fadeTimer); + } + res = neutrino->handleMsg (msg, data); + if (res & messages_return::unhandled) { + // raus hier und im Hauptfenster behandeln... + g_RCInput->postMsg (msg, data); + res = messages_return::cancel_info; + } + } + } + } + + if (hideIt) + killTitle (); + + g_RCInput->killTimer (sec_timer_id); + sec_timer_id = 0; + if (fadeIn || fadeOut) { + g_RCInput->killTimer (fadeTimer); + frameBuffer->setBlendLevel(g_settings.gtx_alpha1, g_settings.gtx_alpha2); + } + if (virtual_zap_mode) + CNeutrinoApp::getInstance()->channelList->virtual_zap_mode(msg == CRCInput::RC_right); + + } + aspectRatio = 0; + fileplay = 0; +} + +void CInfoViewer::showSubchan () +{ + CFrameBuffer *frameBuffer = CFrameBuffer::getInstance (); + CNeutrinoApp *neutrino = CNeutrinoApp::getInstance (); + + std::string subChannelName; // holds the name of the subchannel/audio channel + int subchannel = 0; // holds the channel index + + if (!(g_RemoteControl->subChannels.empty ())) { + // get info for nvod/subchannel + subchannel = g_RemoteControl->selected_subchannel; + if (g_RemoteControl->selected_subchannel >= 0) + subChannelName = g_RemoteControl->subChannels[g_RemoteControl->selected_subchannel].subservice_name; + } else if (g_RemoteControl->current_PIDs.APIDs.size () > 1 && g_settings.audiochannel_up_down_enable) { + // get info for audio channel + subchannel = g_RemoteControl->current_PIDs.PIDs.selected_apid; + subChannelName = g_RemoteControl->current_PIDs.APIDs[g_RemoteControl->current_PIDs.PIDs.selected_apid].desc; + } + + if (!(subChannelName.empty ())) { + char text[100]; + sprintf (text, "%d - %s", subchannel, subChannelName.c_str ()); + + int dx = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getRenderWidth (text) + 20; + int dy = 25; + + if (g_RemoteControl->director_mode) { + int w = 20 + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getRenderWidth (g_Locale->getText (LOCALE_NVODSELECTOR_DIRECTORMODE), true) + 20; // UTF-8 + if (w > dx) + dx = w; + dy = dy * 2; + } else + dy = dy + 5; + + int x = 0, y = 0; + if (g_settings.infobar_subchan_disp_pos == 0) { + // Rechts-Oben + x = g_settings.screen_EndX - dx - 10; + y = g_settings.screen_StartY + 10; + } else if (g_settings.infobar_subchan_disp_pos == 1) { + // Links-Oben + x = g_settings.screen_StartX + 10; + y = g_settings.screen_StartY + 10; + } else if (g_settings.infobar_subchan_disp_pos == 2) { + // Links-Unten + x = g_settings.screen_StartX + 10; + y = g_settings.screen_EndY - dy - 10; + } else if (g_settings.infobar_subchan_disp_pos == 3) { + // Rechts-Unten + x = g_settings.screen_EndX - dx - 10; + y = g_settings.screen_EndY - dy - 10; + } + + fb_pixel_t pixbuf[(dx + 2 * borderwidth) * (dy + 2 * borderwidth)]; + frameBuffer->SaveScreen (x - borderwidth, y - borderwidth, dx + 2 * borderwidth, dy + 2 * borderwidth, pixbuf); + + // clear border + frameBuffer->paintBackgroundBoxRel (x - borderwidth, y - borderwidth, dx + 2 * borderwidth, borderwidth); + frameBuffer->paintBackgroundBoxRel (x - borderwidth, y + dy, dx + 2 * borderwidth, borderwidth); + frameBuffer->paintBackgroundBoxRel (x - borderwidth, y, borderwidth, dy); + frameBuffer->paintBackgroundBoxRel (x + dx, y, borderwidth, dy); + + frameBuffer->paintBoxRel (x, y, dx, dy, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (x + 10, y + 30, dx - 20, text, COL_MENUCONTENT); + + if (g_RemoteControl->director_mode) { + frameBuffer->paintIcon (NEUTRINO_ICON_BUTTON_YELLOW, x + 8, y + dy - 20); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString (x + 30, y + dy - 2, dx - 40, g_Locale->getText (LOCALE_NVODSELECTOR_DIRECTORMODE), COL_MENUCONTENT, 0, true); // UTF-8 + } + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd (2); + int res = messages_return::none; + + neutrino_msg_t msg; + neutrino_msg_data_t data; + + while (!(res & (messages_return::cancel_info | messages_return::cancel_all))) { + g_RCInput->getMsgAbsoluteTimeout (&msg, &data, &timeoutEnd); + + if (msg == CRCInput::RC_timeout) { + res = messages_return::cancel_info; + } else { + res = neutrino->handleMsg (msg, data); + + if (res & messages_return::unhandled) { + // raus hier und im Hauptfenster behandeln... + g_RCInput->postMsg (msg, data); + res = messages_return::cancel_info; + } + } + } + frameBuffer->RestoreScreen (x - borderwidth, y - borderwidth, dx + 2 * borderwidth, dy + 2 * borderwidth, pixbuf); + } else { + g_RCInput->postMsg (NeutrinoMessages::SHOW_INFOBAR, 0); + } +} + +void CInfoViewer::showIcon_16_9 () +{ + if((aspectRatio == 0) || (aspectRatio != videoDecoder->getAspectRatio())) { + aspectRatio = videoDecoder->getAspectRatio(); + frameBuffer->paintIcon ((aspectRatio > 2) ? "16_9.raw" : "16_9_gray.raw", BoxEndX - (2*ICON_LARGE_WIDTH + 2*ICON_SMALL_WIDTH + 4*2), BoxEndY - ICON_Y_1); + } +} + +extern "C" void tuxtxt_start(int tpid); +extern "C" int tuxtxt_stop(); + +void CInfoViewer::showIcon_VTXT () const +{ + frameBuffer->paintIcon ((g_RemoteControl->current_PIDs.PIDs.vtxtpid != 0) ? "vtxt.raw" : "vtxt_gray.raw", BoxEndX - (2*ICON_SMALL_WIDTH + 2*2), BoxEndY - ICON_Y_1); +} + +void CInfoViewer::showIcon_SubT() const +{ + bool have_sub = false; + CZapitChannel * cc = CNeutrinoApp::getInstance()->channelList->getChannel(CNeutrinoApp::getInstance()->channelList->getActiveChannelNumber()); + if(cc && cc->getSubtitleCount()) + have_sub = true; + + frameBuffer->paintIcon(have_sub ? "subt.raw" : "subt_gray.raw", BoxEndX - (ICON_SMALL_WIDTH + 2), BoxEndY - ICON_Y_1); +} + +void CInfoViewer::showFailure () +{ + ShowHintUTF (LOCALE_MESSAGEBOX_ERROR, g_Locale->getText (LOCALE_INFOVIEWER_NOTAVAILABLE), 430); // UTF-8 +} + +void CInfoViewer::showMotorMoving (int duration) +{ + char text[256]; + char buffer[10]; + + sprintf (buffer, "%d", duration); + strcpy (text, g_Locale->getText (LOCALE_INFOVIEWER_MOTOR_MOVING)); + strcat (text, " ("); + strcat (text, buffer); + strcat (text, " s)"); + + ShowHintUTF (LOCALE_MESSAGEBOX_INFO, text, g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth (text, true) + 10, duration); // UTF-8 +} + +int CInfoViewer::handleMsg (const neutrino_msg_t msg, neutrino_msg_data_t data) +{ + + if ((msg == NeutrinoMessages::EVT_CURRENTNEXT_EPG) || (msg == NeutrinoMessages::EVT_NEXTPROGRAM)) { +//printf("CInfoViewer::handleMsg: NeutrinoMessages::EVT_CURRENTNEXT_EPG data %llx current %llx\n", *(t_channel_id *) data, channel_id & 0xFFFFFFFFFFFFULL); + if ((*(t_channel_id *) data) == (channel_id & 0xFFFFFFFFFFFFULL)) { + getEPG (*(t_channel_id *) data, info_CurrentNext); + if (is_visible) + show_Data (true); + showLcdPercentOver (); + } + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_TIMER) { + if (data == fadeTimer) { + // hierher kann das event nur dann kommen, wenn ein anderes Fenster im Vordergrund ist! + g_RCInput->killTimer (fadeTimer); + frameBuffer->setBlendLevel(g_settings.gtx_alpha1, g_settings.gtx_alpha2); + + return messages_return::handled; + } else if (data == lcdUpdateTimer) { +//printf("CInfoViewer::handleMsg: lcdUpdateTimer\n"); + if ( is_visible ) + show_Data( true ); + showLcdPercentOver (); + return messages_return::handled; + } else if (data == sec_timer_id) { + showSNR (); + return messages_return::handled; + } + } else if (msg == NeutrinoMessages::EVT_RECORDMODE) { + recordModeActive = data; + if(is_visible) showRecordIcon(true); + } else if (msg == NeutrinoMessages::EVT_ZAP_GOTAPIDS) { + if ((*(t_channel_id *) data) == channel_id) { + if (is_visible && showButtonBar) + showButton_Audio (); + } + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_ZAP_GOTPIDS) { + if ((*(t_channel_id *) data) == channel_id) { + if (is_visible && showButtonBar) { + showIcon_VTXT (); + showIcon_SubT(); + showIcon_CA_Status (0); + } + } + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_ZAP_GOT_SUBSERVICES) { + if ((*(t_channel_id *) data) == channel_id) { + if (is_visible && showButtonBar) + showButton_SubServices (); + } + return messages_return::handled; + } else if ((msg == NeutrinoMessages::EVT_ZAP_COMPLETE) || + (msg == NeutrinoMessages::EVT_ZAP_ISNVOD)) + { + channel_id = (*(t_channel_id *)data); + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_ZAP_SUB_COMPLETE) { + chanready = 1; + showSNR (); + //if ((*(t_channel_id *)data) == channel_id) + { + if (is_visible && showButtonBar && (!g_RemoteControl->are_subchannels)) + show_Data (true); + } + showLcdPercentOver (); + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_ZAP_SUB_FAILED) { + chanready = 1; + showSNR (); + // show failure..! + CVFD::getInstance ()->showServicename ("(" + g_RemoteControl->getCurrentChannelName () + ')'); + printf ("zap failed!\n"); + showFailure (); + CVFD::getInstance ()->showPercentOver (255); + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_ZAP_FAILED) { + chanready = 1; + showSNR (); + if ((*(t_channel_id *) data) == channel_id) { + // show failure..! + CVFD::getInstance ()->showServicename ("(" + g_RemoteControl->getCurrentChannelName () + ')'); + printf ("zap failed!\n"); + showFailure (); + CVFD::getInstance ()->showPercentOver (255); + } + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_ZAP_MOTOR) { + chanready = 0; + showMotorMoving (data); + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_MODECHANGED) { + aspectRatio = data; + if (is_visible && showButtonBar) + showIcon_16_9 (); + + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_TIMESET) { + gotTime = true; + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_ZAP_CA_CLEAR) { + Set_CA_Status (false); + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_ZAP_CA_LOCK) { + Set_CA_Status (true); + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_ZAP_CA_FTA) { + Set_CA_Status (false); + return messages_return::handled; + } else if (msg == NeutrinoMessages::EVT_ZAP_CA_ID) { + chanready = 1; + Set_CA_Status (data); + showSNR (); + return messages_return::handled; + } + + return messages_return::unhandled; +} + +void CInfoViewer::showButton_SubServices () +{ + if (!(g_RemoteControl->subChannels.empty ())) { + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_YELLOW, + ChanInfoX + 2 + NEUTRINO_ICON_BUTTON_RED_WIDTH + 2 + asize + 2 + NEUTRINO_ICON_BUTTON_GREEN_WIDTH + 2 + asize + 2, BoxEndY- ICON_Y_1 ); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString( + ChanInfoX + 2 + NEUTRINO_ICON_BUTTON_RED_WIDTH + 2 + asize + 2 + NEUTRINO_ICON_BUTTON_GREEN_WIDTH + 2 + asize + 2 + NEUTRINO_ICON_BUTTON_YELLOW_WIDTH + 2, + BoxEndY+2, asize, g_Locale->getText((g_RemoteControl->are_subchannels) ? LOCALE_INFOVIEWER_SUBSERVICE : LOCALE_INFOVIEWER_SELECTTIME), COL_INFOBAR_BUTTONS, 0, true); // UTF-8 + } +} + +CSectionsdClient::CurrentNextInfo CInfoViewer::getEPG (const t_channel_id for_channel_id, CSectionsdClient::CurrentNextInfo &info) +{ + static CSectionsdClient::CurrentNextInfo oldinfo; + + //g_Sectionsd->getCurrentNextServiceKey (for_channel_id & 0xFFFFFFFFFFFFULL, info); + sectionsd_getCurrentNextServiceKey(for_channel_id & 0xFFFFFFFFFFFFULL, info); + +//printf("CInfoViewer::getEPG: old uniqueKey %llx new %llx\n", oldinfo.current_uniqueKey, info.current_uniqueKey); + if (info.current_uniqueKey != oldinfo.current_uniqueKey || info.next_uniqueKey != oldinfo.next_uniqueKey) { + if (info.flags & (CSectionsdClient::epgflags::has_current | CSectionsdClient::epgflags::has_next)) { + CSectionsdClient::CurrentNextInfo * _info = new CSectionsdClient::CurrentNextInfo; + *_info = info; + neutrino_msg_t msg; + if (info.flags & CSectionsdClient::epgflags::has_current) + msg = NeutrinoMessages::EVT_CURRENTEPG; + else + msg = NeutrinoMessages::EVT_NEXTEPG; + g_RCInput->postMsg(msg, (unsigned) _info, false ); + } else { + t_channel_id *p = new t_channel_id; + *p = for_channel_id; + g_RCInput->postMsg (NeutrinoMessages::EVT_NOEPG_YET, (const neutrino_msg_data_t) p, false); // data is pointer to allocated memory + } + oldinfo = info; + } + + return info; +} + +#define get_set CNeutrinoApp::getInstance()->getScanSettings() + +void CInfoViewer::showSNR () +{ + char percent[10]; + uint16_t ssig, ssnr; + int sw, snr, sig, posx, posy; + int height, ChanNumYPos; + int barwidth = BAR_WIDTH; + + if (is_visible && !fileplay) { + if (newfreq && chanready) { + char freq[20]; + + newfreq = false; + CZapitClient::CCurrentServiceInfo si = g_Zapit->getCurrentServiceInfo (); + sprintf (freq, "%d.%d MHz %c", si.tsfrequency / 1000, si.tsfrequency % 1000, si.polarisation ? 'V' : 'H'); +#if 0 +//FIXME this sets default params for scan menu + sprintf (get_set.TP_freq, "%d", si.tsfrequency); + sprintf (get_set.TP_rate, "%d", si.rate); + get_set.TP_pol = si.polarisation; + get_set.TP_fec = si.fec; +#endif + + int chanH = g_SignalFont->getHeight (); + int satNameWidth = g_SignalFont->getRenderWidth (freq); + g_SignalFont->RenderString (3 + BoxStartX + ((ChanWidth - satNameWidth) / 2), BoxStartY + 2 * chanH - 3, satNameWidth, freq, COL_INFOBAR); + } + ssig = frontend->getSignalStrength(); + ssnr = frontend->getSignalNoiseRatio(); + + sig = (ssig & 0xFFFF) * 100 / 65535; + snr = (ssnr & 0xFFFF) * 100 / 65535; + height = g_SignalFont->getHeight () - 1; + ChanNumYPos = BoxStartY + ChanHeight + 4 - 2 * height; + + if (sigscale->getPercent() != sig) { + posx = BoxStartX + 4; + posy = ChanNumYPos + 3; + sigscale->paint(posx, posy+4, sig); + + sprintf (percent, "%d%%S", sig); + posx = posx + barwidth + 2; + sw = BoxStartX + ChanWidth - posx; + frameBuffer->paintBoxRel (posx, posy, sw, height, COL_INFOBAR_PLUS_0); + g_SignalFont->RenderString (posx, posy + height, sw, percent, COL_INFOBAR); + } + if (snrscale->getPercent() != snr) { + posx = BoxStartX + 4; + posy = ChanNumYPos + 3 + height - 2; + + snrscale->paint(posx, posy+4, snr); + + sprintf (percent, "%d%%Q", snr); + posx = posx + barwidth + 2; + sw = BoxStartX + ChanWidth - posx -4; + frameBuffer->paintBoxRel (posx, posy, sw, height-2, COL_INFOBAR_PLUS_0); + g_SignalFont->RenderString (posx, posy + height, sw, percent, COL_INFOBAR); + } + } + if(is_visible) { + struct statfs s; + int per = 0; + if (::statfs("/var", &s) == 0) { + per = (s.f_blocks - s.f_bfree) / (s.f_blocks/100); + } + varscale->paint(BoxEndX - (2*ICON_LARGE_WIDTH + 2*ICON_SMALL_WIDTH + 4*2) - 102, BoxEndY - ICON_Y_1, per); + per = 0; + //HD info + if (::statfs(g_settings.network_nfs_recordingdir, &s) == 0) { + switch(s.f_type) + { + case (int) 0xEF53: /*EXT2 & EXT3*/ + case (int) 0x6969: /*NFS*/ + case (int) 0xFF534D42: /*CIFS*/ + case (int) 0x517B: /*SMB*/ + case (int) 0x52654973: /*REISERFS*/ + case (int) 0x65735546: /*fuse for ntfs*/ + case (int) 0x58465342: /*xfs*/ + case (int) 0x4d44: /*msdos*/ + per = (s.f_blocks - s.f_bfree) / (s.f_blocks/100); + break; + default: + fprintf( stderr,"%s Unknow File system type: %i\n",g_settings.network_nfs_recordingdir ,s.f_type); + break; + } + } + + hddscale->paint(BoxEndX - (2*ICON_LARGE_WIDTH + 2*ICON_SMALL_WIDTH + 4*2) - 102, BoxEndY - ICON_Y_1 + 10, per); + } +} + +void CInfoViewer::show_Data (bool calledFromEvent) +{ + char runningStart[10]; + char runningRest[20]; + char runningPercent = 0; + static char oldrunningPercent = 255; + + char nextStart[10]; + char nextDuration[10]; + + int is_nvod = false; + int b114 = BoxEndX - 114 + 7; + int b112 = BoxEndX - 112 + 7; + + if (fileplay) { + int posy = BoxStartY + 12; + runningPercent = file_prozent; + if(runningPercent > 100) + runningPercent = 100; + + if(!calledFromEvent || (oldrunningPercent != runningPercent)) { + frameBuffer->paintBoxRel (b114+4, posy, 102, 18, COL_INFOBAR_SHADOW_PLUS_0); + frameBuffer->paintBoxRel (b112+4, posy + 2, 98, 14, COL_INFOBAR_PLUS_0); + oldrunningPercent = file_prozent; + } + timescale->paint(b112+4, posy + 2, runningPercent); + + int xStart = BoxStartX + ChanWidth; + int ChanInfoY = BoxStartY + ChanHeight + 15; //+10 + int height = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getHeight (); + int duration1TextPos = BoxEndX - 30; + + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (xStart, ChanInfoY + height, duration1TextPos - xStart - 5, g_file_epg, COL_INFOBAR, 0, true); + ChanInfoY += height; + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (xStart, ChanInfoY + height, duration1TextPos - xStart - 5, g_file_epg1, COL_INFOBAR, 0, true); + + return; + } + if (is_visible) { + + if ((g_RemoteControl->current_channel_id == channel_id) && (g_RemoteControl->subChannels.size () > 0) && (!g_RemoteControl->are_subchannels)) { + is_nvod = true; + info_CurrentNext.current_zeit.startzeit = g_RemoteControl->subChannels[g_RemoteControl->selected_subchannel].startzeit; + info_CurrentNext.current_zeit.dauer = g_RemoteControl->subChannels[g_RemoteControl->selected_subchannel].dauer; + } else { + if ((info_CurrentNext.flags & CSectionsdClient::epgflags::has_current) && (info_CurrentNext.flags & CSectionsdClient::epgflags::has_next) && (showButtonBar)) { + if ((uint) info_CurrentNext.next_zeit.startzeit < (info_CurrentNext.current_zeit.startzeit + info_CurrentNext.current_zeit.dauer)) { + is_nvod = true; + } + } + } + + time_t jetzt = time (NULL); + + if (info_CurrentNext.flags & CSectionsdClient::epgflags::has_current) { + int seit = (jetzt - info_CurrentNext.current_zeit.startzeit + 30) / 60; + int rest = (info_CurrentNext.current_zeit.dauer / 60) - seit; + if (seit < 0) { + runningPercent = 0; + sprintf (runningRest, "in %d min", -seit); + } else { + runningPercent = (unsigned) ((float) (jetzt - info_CurrentNext.current_zeit.startzeit) / (float) info_CurrentNext.current_zeit.dauer * 100.); + if(runningPercent > 100) + runningPercent = 100; + sprintf (runningRest, "%d / %d min", seit, rest); + } + + struct tm *pStartZeit = localtime (&info_CurrentNext.current_zeit.startzeit); + sprintf (runningStart, "%02d:%02d", pStartZeit->tm_hour, pStartZeit->tm_min); + } else + last_curr_id = 0; + + if (info_CurrentNext.flags & CSectionsdClient::epgflags::has_next) { + unsigned dauer = info_CurrentNext.next_zeit.dauer / 60; + sprintf (nextDuration, "%d min", dauer); + struct tm *pStartZeit = localtime (&info_CurrentNext.next_zeit.startzeit); + sprintf (nextStart, "%02d:%02d", pStartZeit->tm_hour, pStartZeit->tm_min); + } else + last_next_id = 0; + + int height = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->getHeight () / 3; + int ChanInfoY = BoxStartY + ChanHeight + 15; //+10 + + if (showButtonBar) { + int posy = BoxStartY + 16; + int height2 = 20; + //percent + if (info_CurrentNext.flags & CSectionsdClient::epgflags::has_current) { +//printf("CInfoViewer::show_Data: ************************************************* runningPercent %d\n", runningPercent); + if(!calledFromEvent || (oldrunningPercent != runningPercent)) { + frameBuffer->paintBoxRel (BoxEndX - 104, posy + 6, 108, 14, COL_INFOBAR_SHADOW_PLUS_0, 1, 3); + frameBuffer->paintBoxRel (BoxEndX - 108, posy + 2, 108, 14, COL_INFOBAR_PLUS_0, 1, 3); + oldrunningPercent = runningPercent; + } + timescale->paint(BoxEndX - 102, posy + 2, runningPercent); + } else { + oldrunningPercent = 255; + frameBuffer->paintBackgroundBoxRel (BoxEndX - 108, posy, 112, height2); + } + if (info_CurrentNext.flags & CSectionsdClient::epgflags::has_anything) { + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_RED, ChanInfoX + 2, BoxEndY - ICON_Y_1); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(ChanInfoX + (2 + NEUTRINO_ICON_BUTTON_RED_WIDTH + 2), BoxEndY+2, asize, g_Locale->getText(LOCALE_INFOVIEWER_EVENTLIST), COL_INFOBAR_BUTTONS, 0, true); // UTF-8 + } + } + + height = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getHeight (); + int xStart = BoxStartX + ChanWidth; + + //frameBuffer->paintBox (ChanInfoX + 10, ChanInfoY, BoxEndX, ChanInfoY + height, COL_INFOBAR_PLUS_0); + + if ((info_CurrentNext.flags & CSectionsdClient::epgflags::not_broadcast) || ((calledFromEvent) && !(info_CurrentNext.flags & (CSectionsdClient::epgflags::has_next | CSectionsdClient::epgflags::has_current)))) { + // no EPG available + ChanInfoY += height; + frameBuffer->paintBox (ChanInfoX + 10, ChanInfoY, BoxEndX, ChanInfoY + height, COL_INFOBAR_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (BoxStartX + ChanWidth + 20, ChanInfoY + height, BoxEndX - (BoxStartX + ChanWidth + 20), g_Locale->getText (gotTime ? LOCALE_INFOVIEWER_NOEPG : LOCALE_INFOVIEWER_WAITTIME), COL_INFOBAR, 0, true); // UTF-8 + } else { + // irgendein EPG gefunden + int duration1Width = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getRenderWidth (runningRest); + int duration1TextPos = BoxEndX - duration1Width - LEFT_OFFSET; + + int duration2Width = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->getRenderWidth (nextDuration); + int duration2TextPos = BoxEndX - duration2Width - LEFT_OFFSET; + + if ((info_CurrentNext.flags & CSectionsdClient::epgflags::has_next) && (!(info_CurrentNext.flags & CSectionsdClient::epgflags::has_current))) { + // there are later events available - yet no current + frameBuffer->paintBox (ChanInfoX + 10, ChanInfoY, BoxEndX, ChanInfoY + height, COL_INFOBAR_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (xStart, ChanInfoY + height, BoxEndX - xStart, g_Locale->getText (LOCALE_INFOVIEWER_NOCURRENT), COL_INFOBAR, 0, true); // UTF-8 + + ChanInfoY += height; + + //info next + //frameBuffer->paintBox (ChanInfoX + 10, ChanInfoY, BoxEndX, ChanInfoY + height, COL_INFOBAR_PLUS_0); + + if(last_next_id != info_CurrentNext.next_uniqueKey) { + frameBuffer->paintBox (ChanInfoX + 10, ChanInfoY, BoxEndX, ChanInfoY + height, COL_INFOBAR_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (ChanInfoX + 10, ChanInfoY + height, 100, nextStart, COL_INFOBAR); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (xStart, ChanInfoY + height, duration2TextPos - xStart - 5, info_CurrentNext.next_name, COL_INFOBAR, 0, true); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (duration2TextPos, ChanInfoY + height, duration2Width, nextDuration, COL_INFOBAR); + last_next_id = info_CurrentNext.next_uniqueKey; + } + } else { + if(last_curr_id != info_CurrentNext.current_uniqueKey) { + frameBuffer->paintBox (ChanInfoX + 10, ChanInfoY, BoxEndX, ChanInfoY + height, COL_INFOBAR_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (ChanInfoX + 10, ChanInfoY + height, 100, runningStart, COL_INFOBAR); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (xStart, ChanInfoY + height, duration1TextPos - xStart - 5, info_CurrentNext.current_name, COL_INFOBAR, 0, true); + + last_curr_id = info_CurrentNext.current_uniqueKey; + } + frameBuffer->paintBox (BoxEndX - 80, ChanInfoY, BoxEndX, ChanInfoY + height, COL_INFOBAR_PLUS_0);//FIXME duration1TextPos not really good + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (duration1TextPos, ChanInfoY + height, duration1Width, runningRest, COL_INFOBAR); + + ChanInfoY += height; + + //info next + //frameBuffer->paintBox (ChanInfoX + 10, ChanInfoY, BoxEndX, ChanInfoY + height, COL_INFOBAR_PLUS_0); + + if ((!is_nvod) && (info_CurrentNext.flags & CSectionsdClient::epgflags::has_next)) { + if(last_next_id != info_CurrentNext.next_uniqueKey) { + frameBuffer->paintBox (ChanInfoX + 10, ChanInfoY, BoxEndX, ChanInfoY + height, COL_INFOBAR_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (ChanInfoX + 10, ChanInfoY + height, 100, nextStart, COL_INFOBAR); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (xStart, ChanInfoY + height, duration2TextPos - xStart - 5, info_CurrentNext.next_name, COL_INFOBAR, 0, true); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO]->RenderString (duration2TextPos, ChanInfoY + height, duration2Width, nextDuration, COL_INFOBAR); + last_next_id = info_CurrentNext.next_uniqueKey; + } + } //else + //frameBuffer->paintBox (ChanInfoX + 10, ChanInfoY, BoxEndX, ChanInfoY + height, COL_INFOBAR_PLUS_0);//why this... + } + } + } +} + +void CInfoViewer::showButton_Audio () +{ + // green, in case of several APIDs + uint32_t count = g_RemoteControl->current_PIDs.APIDs.size (); + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_GREEN, ChanInfoX + 2 + NEUTRINO_ICON_BUTTON_RED_WIDTH + 2 + asize + 2, BoxEndY- ICON_Y_1); + + if (count > 0) { + int selected = g_RemoteControl->current_PIDs.PIDs.selected_apid; + + int sx = ChanInfoX + 2 + NEUTRINO_ICON_BUTTON_RED_WIDTH + 2 + asize + 2 + NEUTRINO_ICON_BUTTON_GREEN_WIDTH + 2; + + frameBuffer->paintBox (sx, BoxEndY-20, sx+asize, BoxEndY, COL_INFOBAR_BUTTONS_BACKGROUND); + + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(sx, BoxEndY+2, asize, + g_RemoteControl->current_PIDs.APIDs[selected].desc, COL_INFOBAR_BUTTONS, 0, true); // UTF-8 + } + const char *dd_icon; + if ((g_RemoteControl->current_PIDs.PIDs.selected_apid < count) && (g_RemoteControl->current_PIDs.APIDs[g_RemoteControl->current_PIDs.PIDs.selected_apid].is_ac3)) + dd_icon = "dd.raw"; + else if (g_RemoteControl->has_ac3) + dd_icon = "dd_avail.raw"; + else + dd_icon = "dd_gray.raw"; + + frameBuffer->paintIcon (dd_icon, BoxEndX - (ICON_LARGE_WIDTH + 2*ICON_SMALL_WIDTH + 3*2), BoxEndY - ICON_Y_1); +} + +void CInfoViewer::killTitle () +{ + if (is_visible) { + is_visible = false; + frameBuffer->paintBackgroundBox (BoxStartX, BoxStartY, BoxEndX + SHADOW_OFFSET, BoxEndY + SHADOW_OFFSET); + } +} + +void CInfoViewer::Set_CA_Status (int Status) +{ + CA_Status = Status; + m_CA_Status = Status; + if (is_visible && showButtonBar) + showIcon_CA_Status (1); +} + +void CInfoViewer::showLcdPercentOver () +{ + if (g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME] != 1) { + if (fileplay || (NeutrinoMessages::mode_ts == CNeutrinoApp::getInstance()->getMode())) { + CVFD::getInstance ()->showPercentOver (file_prozent); + return; + } + int runningPercent = -1; + time_t jetzt = time (NULL); +#if 0 + if (!(info_CurrentNext.flags & CSectionsdClient::epgflags::has_current) || jetzt > (int) (info_CurrentNext.current_zeit.startzeit + info_CurrentNext.current_zeit.dauer)) { + info_CurrentNext = getEPG (channel_id); + } +#endif + if (info_CurrentNext.flags & CSectionsdClient::epgflags::has_current) { + if (jetzt < info_CurrentNext.current_zeit.startzeit) + runningPercent = 0; + else + runningPercent = MIN ((unsigned) ((float) (jetzt - info_CurrentNext.current_zeit.startzeit) / (float) info_CurrentNext.current_zeit.dauer * 100.), 100); + } + CVFD::getInstance ()->showPercentOver (runningPercent); + } +} + +int CInfoViewerHandler::exec (CMenuTarget * parent, const std::string & actionkey) +{ + int res = menu_return::RETURN_EXIT_ALL; + CChannelList *channelList; + CInfoViewer *i; + + if (parent) { + parent->hide (); + } + + i = new CInfoViewer; + + channelList = CNeutrinoApp::getInstance ()->channelList; + i->start (); + i->showTitle (channelList->getActiveChannelNumber (), channelList->getActiveChannelName (), channelList->getActiveSatellitePosition (), channelList->getActiveChannel_ChannelID ()); // UTF-8 + delete i; + + return res; +} + + + +#define ICON_H 16 +#define ICON_Y_2 (16 + 2 + ICON_H) +#define MAX_EW 146 + + +void CInfoViewer::paint_ca_icons(int caid, char * icon) +{ + char buf[20]; + int endx = ChanInfoX - 8 + ((BoxEndX - ChanInfoX)/4)*4; + int py = BoxEndY - InfoHeightY_Info; + int px = 0; + + switch ( caid & 0xFF00 ) { + case 0x0E00: + px = endx - 48 - 38 - 9*10 - 7*14 - 10; sprintf(buf, "%s_%s.raw", "powervu", icon); + break; + case 0x4A00: + px = endx - 48 - 38 - 8*10 - 6*14 - 10; sprintf(buf, "%s_%s.raw", "d", icon); + break; + case 0x2600: + px = endx - 48 - 38 - 7*10 - 5*14 - 10; sprintf(buf, "%s_%s.raw", "biss", icon); + break; + case 0x600: + case 0x602: + case 0x1700: + px = endx - 48 - 38 - 6*10 - 4*14 - 10; sprintf(buf, "%s_%s.raw", "ird", icon); + break; + case 0x100: + px = endx - 48 - 38 - 5*10 - 4*14; sprintf(buf, "%s_%s.raw", "seca", icon); + break; + case 0x500: + px = endx - 48 - 38 - 4*10 - 3*14; sprintf(buf, "%s_%s.raw", "via", icon); + break; + case 0x1800: + case 0x1801: + px = endx - 48 - 38 - 3*10 - 2*14; sprintf(buf, "%s_%s.raw", "nagra", icon); + break; + case 0xB00: + px = endx - 48 - 38 - 2*10 - 1*14; sprintf(buf, "%s_%s.raw", "conax", icon); + break; + case 0xD00: + px = endx - 48 - 38 - 1*10; sprintf(buf, "%s_%s.raw", "cw", icon); + break; + case 0x900: + px = endx - 48; sprintf(buf, "%s_%s.raw", "nds", icon); + break; + default: + break; + }/*case*/ + if(px) { + frameBuffer->paintIcon(buf, px, py ); + } +} + +static char * gray = (char *) "white"; +//static char * green = (char *) "green"; +static char * white = (char *) "yellow"; +extern int pmt_caids[10]; + +void CInfoViewer::showIcon_CA_Status (int notfirst) +{ +#if 0 + FILE *f; + char input[256]; + char buf[256]; + int acaid = 0; + int py = BoxEndY - InfoHeightY_Info; +#endif + int i; + int caids[] = { 0x1700, 0x0100, 0x0500, 0x1800, 0xB00, 0xD00, 0x900, 0x2600, 0x4a00, 0x0E00 }; + + if(!notfirst) { + for(i=0; i < (int)(sizeof(caids)/sizeof(int)); i++) { + paint_ca_icons(caids[i], (char *) (pmt_caids[i] ? white : gray)); + } + } +} diff --git a/src/gui/infoviewer.h b/src/gui/infoviewer.h new file mode 100644 index 000000000..2a363443e --- /dev/null +++ b/src/gui/infoviewer.h @@ -0,0 +1,137 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __infoview__ +#define __infoview__ + +#include + +#include +#include +#include +#include +#include "widget/menue.h" +#include +#include + +class CInfoViewer +{ + private: + void Init(void); + CFrameBuffer * frameBuffer; + + bool gotTime; + bool recordModeActive; +#ifndef SKIP_CA_STATUS + bool CA_Status; +#endif + + int InfoHeightY; + int InfoHeightY_Info; + bool showButtonBar; + bool fileplay; + + int BoxEndX; + int BoxEndY; + int BoxStartX; + int BoxStartY; + int ButtonWidth; + + int ChanWidth; + int ChanHeight; + int ChanInfoX; + + int asize; + + CSectionsdClient::CurrentNextInfo info_CurrentNext; + t_channel_id channel_id; + + char aspectRatio; + + uint32_t sec_timer_id; + uint32_t fadeTimer; + bool virtual_zap_mode; + CChannelEventList evtlist; + CChannelEventList::iterator eli; + + void show_Data( bool calledFromEvent = false ); + void paintTime( bool show_dot, bool firstPaint ); + + void showButton_Audio(); + void showButton_SubServices(); + + void showIcon_16_9(); +#ifndef SKIP_CA_STATUS + void showIcon_CA_Status(int); + void paint_ca_icons(int, char*); +#endif + void showIcon_VTXT() const; + void showRecordIcon(const bool show); + void showIcon_SubT() const; + + void showFailure(); + void showMotorMoving(int duration); + void showLcdPercentOver(); + void showSNR(); + CScale * snrscale, * sigscale; + + public: + bool chanready; + bool is_visible; + uint32_t lcdUpdateTimer; + + CInfoViewer(); + + void start(); + + void showTitle(const int ChanNum, const std::string & Channel, const t_satellite_position satellitePosition, const t_channel_id new_channel_id = 0, const bool calledFromNumZap = false, int epgpos = 0); // Channel must be UTF-8 encoded + void lookAheadEPG(const int ChanNum, const std::string & Channel, const t_channel_id new_channel_id = 0, const bool calledFromNumZap = false); //alpha: fix for nvod subchannel update + void killTitle(); + CSectionsdClient::CurrentNextInfo getEPG(const t_channel_id for_channel_id, CSectionsdClient::CurrentNextInfo &info); + + void showSubchan(); +#ifndef SKIP_CA_STATUS + void Set_CA_Status(int Status); +#endif + + int handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t data); + void clearVirtualZapMode() {virtual_zap_mode = false;} +}; + +class CInfoViewerHandler : public CMenuTarget +{ + public: + int exec( CMenuTarget* parent, const std::string &actionkey); + int doMenu(); + +}; +#endif diff --git a/src/gui/motorcontrol.cpp b/src/gui/motorcontrol.cpp new file mode 100644 index 000000000..34510f9c5 --- /dev/null +++ b/src/gui/motorcontrol.cpp @@ -0,0 +1,705 @@ +/* + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +extern CFrontend * frontend; + +static int g_sig; +static int g_snr; +static int last_snr = 0; +static int moving = 0; + +#define RED_BAR 40 +#define YELLOW_BAR 70 +#define GREEN_BAR 100 + +#define BAR_BORDER 2 +#define BAR_WIDTH 100 +#define BAR_HEIGHT 16 //(13 + BAR_BORDER*2) +#define ROUND_RADIUS 9 + +#define get_set CNeutrinoApp::getInstance()->getScanSettings() +CMotorControl::CMotorControl() +{ + Init(); +} + +void CMotorControl::Init(void) +{ + frameBuffer = CFrameBuffer::getInstance(); + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + + satfindpid = -1; + + width = w_max(470, 0); + mheight = mheight - 2; + height = hheight + (20 * mheight) - 5; + height = h_max(height, 0); + + x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - height) / 2; + + stepSize = 1; //default: 1 step + stepMode = STEP_MODE_ON; + installerMenue = false; + motorPosition = 1; + satellitePosition = 0; + stepDelay = 10; + sigscale = new CScale(BAR_WIDTH, BAR_HEIGHT, RED_BAR, GREEN_BAR, YELLOW_BAR); + snrscale = new CScale(BAR_WIDTH, BAR_HEIGHT, RED_BAR, GREEN_BAR, YELLOW_BAR); +} + +int CMotorControl::exec(CMenuTarget* parent, const std::string &) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + TP_params TP; + int wasgrow = 0; + last_snr = 0; + moving = 0; + + CZapitClient::ScanSatelliteList satList; + CZapitClient::commandSetScanSatelliteList sat; + sat_iterator_t sit; + + sigscale->reset(); + snrscale->reset(); + + bool istheend = false; + int lim_cmd; + if (!frameBuffer->getActive()) + return menu_return::RETURN_EXIT_ALL; + + if (parent) + parent->hide(); + + x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - height) / 2; + + /* send satellite list to zapit */ + for(sit = satellitePositions.begin(); sit != satellitePositions.end(); sit++) { + if(!strcmp(sit->second.name.c_str(),get_set.satNameNoDiseqc)) { + sat.position = sit->first; + strncpy(sat.satName, get_set.satNameNoDiseqc, 50); + satList.push_back(sat); + break; + } + } + + g_Zapit->setScanSatelliteList( satList); + + TP.feparams.frequency = atoi(get_set.TP_freq); + TP.feparams.u.qpsk.symbol_rate = atoi(get_set.TP_rate); + TP.feparams.u.qpsk.fec_inner = (fe_code_rate_t)get_set.TP_fec; + TP.polarization = get_set.TP_pol; +#if 0 + CZapitClient::CCurrentServiceInfo si = g_Zapit->getCurrentServiceInfo (); + TP.feparams.frequency = si.tsfrequency; + TP.feparams.u.qpsk.symbol_rate = si.rate; + TP.feparams.u.qpsk.fec_inner = si.fec; + TP.polarization = si.polarisation; +#endif + + g_Zapit->stopPlayBack(); + g_Zapit->tune_TP(TP); + + paint(); + paintMenu(); + paintStatus(); + + while (!istheend) + { + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd_MS(250); + msg = CRCInput::RC_nokey; + + while (!(msg == CRCInput::RC_timeout) && (!(msg == CRCInput::RC_home))) + { + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd); + showSNR(); +//printf("SIG: %d SNR %d last %d\n", g_sig, g_snr, last_snr); + if(moving && (stepMode == STEP_MODE_AUTO)) { + if(last_snr < g_snr) { + wasgrow = 1; + } + //if((last_snr > g_snr) && last_snr > 37000) { + if(wasgrow && (last_snr > g_snr) && last_snr > 50) { +//printf("Must stop rotor!!!\n"); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x60, 0, 0, 0); + moving = 0; + paintStatus(); + last_snr = 0; + } else + last_snr = g_snr; + } else + wasgrow = 0; + + if (installerMenue) + { + switch(msg) + { + case CRCInput::RC_ok: + case CRCInput::RC_0: + printf("[motorcontrol] 0 key received... goto userMenue\n"); + installerMenue = false; + paintMenu(); + paintStatus(); + break; + + case CRCInput::RC_1: + case CRCInput::RC_right: + printf("[motorcontrol] left/1 key received... drive/Step motor west, stepMode: %d\n", stepMode); + motorStepWest(); + paintStatus(); + break; + + case CRCInput::RC_red: + case CRCInput::RC_2: + printf("[motorcontrol] 2 key received... halt motor\n"); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x60, 0, 0, 0); + moving = 0; + paintStatus(); + break; + + case CRCInput::RC_3: + case CRCInput::RC_left: + printf("[motorcontrol] right/3 key received... drive/Step motor east, stepMode: %d\n", stepMode); + motorStepEast(); + paintStatus(); + break; + + case CRCInput::RC_4: + printf("[motorcontrol] 4 key received... set west (soft) limit\n"); + if(g_settings.rotor_swap) lim_cmd = 0x66; + else lim_cmd = 0x67; + g_Zapit->sendMotorCommand(0xE1, 0x31, lim_cmd, 0, 0, 0); + break; + + case CRCInput::RC_5: + printf("[motorcontrol] 5 key received... disable (soft) limits\n"); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x63, 0, 0, 0); + break; + + case CRCInput::RC_6: + printf("[motorcontrol] 6 key received... set east (soft) limit\n"); + if(g_settings.rotor_swap) lim_cmd = 0x67; + else lim_cmd = 0x66; + g_Zapit->sendMotorCommand(0xE1, 0x31, lim_cmd, 0, 0, 0); + break; + + case CRCInput::RC_7: + printf("[motorcontrol] 7 key received... goto reference position\n"); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x6B, 1, 0, 0); + satellitePosition = 0; + paintStatus(); + break; + + case CRCInput::RC_8: + printf("[motorcontrol] 8 key received... enable (soft) limits\n"); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x6A, 1, 0, 0); + break; + + case CRCInput::RC_9: + printf("[motorcontrol] 9 key received... (re)-calculate positions\n"); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x6F, 1, 0, 0); + break; + + case CRCInput::RC_plus: + case CRCInput::RC_up: + printf("[motorcontrol] up key received... increase satellite position: %d\n", ++motorPosition); + satellitePosition = 0; + paintStatus(); + break; + + case CRCInput::RC_minus: + case CRCInput::RC_down: + if (motorPosition > 1) motorPosition--; + printf("[motorcontrol] down key received... decrease satellite position: %d\n", motorPosition); + satellitePosition = 0; + paintStatus(); + break; + + case CRCInput::RC_blue: + if (++stepMode > 3) + stepMode = 0; + if (stepMode == STEP_MODE_OFF) + satellitePosition = 0; + last_snr = 0; + printf("[motorcontrol] red key received... toggle stepmode on/off: %d\n", stepMode); + paintStatus(); + break; + + default: + //printf("[motorcontrol] message received...\n"); + if ((msg >= CRCInput::RC_WithData) && (msg < CRCInput::RC_WithData + 0x10000000)) + delete (unsigned char*) data; + break; + } + } + else + { + switch(msg) + { + case CRCInput::RC_ok: + case CRCInput::RC_0: + printf("[motorcontrol] 0 key received... goto installerMenue\n"); + installerMenue = true; + paintMenu(); + paintStatus(); + break; + + case CRCInput::RC_1: + case CRCInput::RC_right: + printf("[motorcontrol] left/1 key received... drive/Step motor west, stepMode: %d\n", stepMode); + motorStepWest(); + paintStatus(); + break; + + case CRCInput::RC_red: + case CRCInput::RC_2: + printf("[motorcontrol] 2 key received... halt motor\n"); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x60, 0, 0, 0); + break; + + case CRCInput::RC_3: + case CRCInput::RC_left: + printf("[motorcontrol] right/3 key received... drive/Step motor east, stepMode: %d\n", stepMode); + motorStepEast(); + paintStatus(); + break; + + case CRCInput::RC_green: + case CRCInput::RC_5: + printf("[motorcontrol] 5 key received... store present satellite number: %d\n", motorPosition); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x6A, 1, motorPosition, 0); + break; + + case CRCInput::RC_6: + if (stepSize < 0x7F) stepSize++; + printf("[motorcontrol] 6 key received... increase Step size: %d\n", stepSize); + paintStatus(); + break; + + case CRCInput::RC_yellow: + case CRCInput::RC_7: + printf("[motorcontrol] 7 key received... goto satellite number: %d\n", motorPosition); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x6B, 1, motorPosition, 0); + satellitePosition = 0; + paintStatus(); + break; + + case CRCInput::RC_9: + if (stepSize > 1) stepSize--; + printf("[motorcontrol] 9 key received... decrease Step size: %d\n", stepSize); + paintStatus(); + break; + + case CRCInput::RC_plus: + case CRCInput::RC_up: + printf("[motorcontrol] up key received... increase satellite position: %d\n", ++motorPosition); + satellitePosition = 0; + paintStatus(); + break; + + case CRCInput::RC_minus: + case CRCInput::RC_down: + if (motorPosition > 1) motorPosition--; + printf("[motorcontrol] down key received... decrease satellite position: %d\n", motorPosition); + satellitePosition = 0; + paintStatus(); + break; + + case CRCInput::RC_blue: + if (++stepMode > 2) + stepMode = 0; + if (stepMode == STEP_MODE_OFF) + satellitePosition = 0; + printf("[motorcontrol] red key received... toggle stepmode on/off: %d\n", stepMode); + paintStatus(); + break; + + default: + //printf("[motorcontrol] message received...\n"); + if ((msg >= CRCInput::RC_WithData) && (msg < CRCInput::RC_WithData + 0x10000000)) + delete (unsigned char*) data; + break; + } + } + } + + istheend = (msg == CRCInput::RC_home); + } + + hide(); + + return menu_return::RETURN_REPAINT; +} + +void CMotorControl::motorStepWest(void) +{ + int cmd; + printf("[motorcontrol] motorStepWest\n"); + if(g_settings.rotor_swap) cmd = 0x68; + else cmd = 0x69; + switch(stepMode) + { + case STEP_MODE_ON: + g_Zapit->sendMotorCommand(0xE0, 0x31, cmd, 1, (-1 * stepSize), 0); + satellitePosition += stepSize; + break; + case STEP_MODE_TIMED: + g_Zapit->sendMotorCommand(0xE0, 0x31, cmd, 1, 40, 0); + usleep(stepSize * stepDelay * 1000); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x60, 0, 0, 0); //halt motor + satellitePosition += stepSize; + break; + case STEP_MODE_AUTO: + moving = 1; + paintStatus(); + default: + g_Zapit->sendMotorCommand(0xE0, 0x31, cmd, 1, 40, 0); + } +} + +void CMotorControl::motorStepEast(void) +{ + int cmd; + if(g_settings.rotor_swap) cmd = 0x69; + else cmd = 0x68; + printf("[motorcontrol] motorStepEast\n"); + switch(stepMode) + { + case STEP_MODE_ON: + g_Zapit->sendMotorCommand(0xE0, 0x31, cmd, 1, (-1 * stepSize), 0); + satellitePosition -= stepSize; + break; + case STEP_MODE_TIMED: + g_Zapit->sendMotorCommand(0xE0, 0x31, cmd, 1, 40, 0); + usleep(stepSize * stepDelay * 1000); + g_Zapit->sendMotorCommand(0xE0, 0x31, 0x60, 0, 0, 0); //halt motor + satellitePosition -= stepSize; + break; + case STEP_MODE_AUTO: + moving = 1; + default: + g_Zapit->sendMotorCommand(0xE0, 0x31, cmd, 1, 40, 0); + } +} + +void CMotorControl::hide() +{ + frameBuffer->paintBackgroundBoxRel(x, y, width, height + 20); + stopSatFind(); +} + +void CMotorControl::paintLine(int x, int * y, int width, char * txt) +{ + *y += mheight; + frameBuffer->paintBoxRel(x, *y - mheight, width, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x, *y, width, txt, COL_MENUCONTENT, 0, true); +} + +void CMotorControl::paintLine(int x, int y, int width, char * txt) +{ + //frameBuffer->paintBoxRel(x, y - mheight, width, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x, y, width, txt, COL_MENUCONTENT, 0, true); +} + +void CMotorControl::paintSeparator(int xpos, int * ypos, int width, char * txt) +{ + //int stringwidth = 0; + //int stringstartposX = 0; + int th = 10; + //*ypos += mheight; + *ypos += th; + frameBuffer->paintHLineRel(xpos, width - 20, *ypos - (th >> 1), COL_MENUCONTENT_PLUS_3); + frameBuffer->paintHLineRel(xpos, width - 20, *ypos - (th >> 1) + 1, COL_MENUCONTENT_PLUS_1); + +#if 0 + stringwidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(txt); + stringstartposX = 0; + stringstartposX = (xpos + (width >> 1)) - (stringwidth >> 1); + frameBuffer->paintBoxRel(stringstartposX - 5, *ypos - mheight, stringwidth + 10, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposX, *ypos, stringwidth, txt, COL_MENUCONTENT); +#endif +} + +void CMotorControl::paintStatus() +{ + char buf[256]; + char buf2[256]; + + int xpos1 = x + 10; + int xpos2 = xpos1 + 10 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth((char *) g_Locale->getText(LOCALE_MOTORCONTROL_MOTOR_POS)); + int width2 = width - (xpos2 - xpos1) - 10; + int width1 = width - 10; + + ypos = ypos_status; + paintSeparator(xpos1, &ypos, width, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_SETTINGS)); + + paintLine(xpos1, &ypos, width1, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_MOTOR_POS)); + sprintf(buf, "%d", motorPosition); + paintLine(xpos2, ypos, width2 , buf); + + paintLine(xpos1, &ypos, width1, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_MOVEMENT)); + switch(stepMode) + { + case STEP_MODE_ON: + strcpy(buf, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STEP_MODE)); + break; + case STEP_MODE_OFF: + strcpy(buf, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_DRIVE_MODE)); + break; + case STEP_MODE_AUTO: + strcpy(buf, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_DRIVE_MODE_AUTO)); + break; + case STEP_MODE_TIMED: + strcpy(buf, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_TIMED_MODE)); + break; + } + paintLine(xpos2, ypos, width2, buf); + + paintLine(xpos1, &ypos, width1, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STEP_SIZE)); + switch(stepMode) + { + case STEP_MODE_ON: + sprintf(buf, "%d", stepSize); + break; + case STEP_MODE_AUTO: + if(moving) + strcpy(buf, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STOP_MOVING)); + else + strcpy(buf, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STOP_STOPPED)); + break; + case STEP_MODE_OFF: + strcpy(buf, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_NO_MODE)); + break; + case STEP_MODE_TIMED: + sprintf(buf, "%d ", stepSize * stepDelay); + strcat(buf, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_MSEC)); + break; + } + paintLine(xpos2, ypos, width2, buf); + + paintSeparator(xpos1, &ypos, width, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STATUS)); + strcpy(buf, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_SAT_POS)); + sprintf(buf2, "%d", satellitePosition); + strcat(buf, buf2); + paintLine(xpos1, &ypos, width1, buf); + paintSeparator(xpos1, &ypos, width, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_SETTINGS)); +} + +void CMotorControl::paint() +{ + ypos = y; + frameBuffer->paintBoxRel(x, ypos, width, hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x + 10, ypos + hheight, width, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_HEAD), COL_MENUHEAD, 0, true); // UTF-8 + frameBuffer->paintBoxRel(x, ypos + hheight, width, height - hheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2); + + ypos += hheight + (mheight >> 1) - 10; + ypos_menue = ypos; +} + +void CMotorControl::paintMenu() +{ + ypos = ypos_menue; + + int xpos1 = x + 10; + int xpos2 = xpos1 + 10 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth("(7/yellow)"); + int width2 = width - (xpos2 - xpos1) - 10; + int width1 = width - 10; + + paintLine(xpos1, &ypos, width1, (char *) "(0/OK)"); + if(installerMenue) + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_USER_MENU)); + else + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_INSTALL_MENU)); + + paintLine(xpos1, &ypos, width1, (char *) "(1/right)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STEP_WEST)); + paintLine(xpos1, &ypos, width1, (char *) "(2/red)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_HALT)); + paintLine(xpos1, &ypos, width1, (char *) "(3/left)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STEP_EAST)); + + if (installerMenue) + { + paintLine(xpos1, &ypos, width1,(char *) "(4)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_WEST_LIMIT)); + paintLine(xpos1, &ypos, width1, (char *) "(5)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_DISABLE_LIMIT)); + paintLine(xpos1, &ypos, width1, (char *) "(6)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_EAST_LIMIT)); + paintLine(xpos1, &ypos, width1, (char *) "(7)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_REF_POSITION)); + paintLine(xpos1, &ypos, width1, (char *) "(8)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_ENABLE_LIMIT)); + paintLine(xpos1, &ypos, width1, (char *) "(9)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_CALC_POSITIONS)); + paintLine(xpos1, &ypos, width1, (char *) "(+/up)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_POS_INCREASE)); + paintLine(xpos1, &ypos, width1, (char *) "(-/down)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_POS_DECREASE)); + paintLine(xpos1, &ypos, width1,(char *) "(blue)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STEP_DRIVE)); + } + else + { + paintLine(xpos1, &ypos, width1, (char *) "(4)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_NOTDEF)); + paintLine(xpos1, &ypos, width1, (char *) "(5/green)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STORE)); + paintLine(xpos1, &ypos, width1,(char *) "(6)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STEP_INCREASE)); + paintLine(xpos1, &ypos, width1, (char *) "(7/yellow)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_GOTO)); + paintLine(xpos1, &ypos, width1, (char *) "(8)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_NOTDEF)); + paintLine(xpos1, &ypos, width1, (char *) "(9)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STEP_DECREASE)); + paintLine(xpos1, &ypos, width1, (char *) "(+/up)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_POS_INCREASE)); + paintLine(xpos1, &ypos, width1, (char *) "(-/down)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_POS_DECREASE)); + paintLine(xpos1, &ypos, width1, (char *) "(blue)"); + paintLine(xpos2, ypos, width2, (char *) g_Locale->getText(LOCALE_MOTORCONTROL_STEP_DRIVE)); + } + + ypos_status = ypos; +} + +void CMotorControl::startSatFind(void) +{ +#if 0 + if (satfindpid != -1) { + kill(satfindpid, SIGKILL); + waitpid(satfindpid, 0, 0); + satfindpid = -1; + } + + switch ((satfindpid = fork())) { + case -1: + printf("[motorcontrol] fork"); + break; + case 0: + printf("[motorcontrol] starting satfind...\n"); +#if HAVE_DVB_API_VERSION >= 3 + if (execlp("/bin/satfind", "satfind", NULL) < 0) +#else + //if (execlp("/bin/satfind", "satfind", "--tune", NULL) < 0) + if (execlp("/bin/satfind", "satfind", NULL) < 0) +#endif + printf("[motorcontrol] execlp satfind failed.\n"); + break; + } /* switch */ +#endif +} + +void CMotorControl::stopSatFind(void) +{ + + if (satfindpid != -1) { + printf("[motorcontrol] killing satfind...\n"); + kill(satfindpid, SIGKILL); + waitpid(satfindpid, 0, 0); + satfindpid = -1; + } +} + +#define BARWT 10 +#define BAR_BL 2 +#define BARW (BARWT - BAR_BL) +#define BARWW (BARWT - BARW) + +void CMotorControl::showSNR() +{ + char percent[10]; + //char ber[20]; + int barwidth = 100; + uint16_t ssig, ssnr; + int sig, snr; + int bheight, posx, posy; + + int sw; + + ssig = frontend->getSignalStrength(); + ssnr = frontend->getSignalNoiseRatio(); + + snr = (ssnr & 0xFFFF) * 100 / 65535; + sig = (ssig & 0xFFFF) * 100 / 65535; + if(sig < 5) + return; + g_sig = ssig & 0xFFFF; + g_snr = snr; + + bheight = mheight - 5; + posy = y + height - mheight - 5; + + if(sigscale->getPercent() != sig) { + posx = x + 10; + sprintf(percent, "%d%% SIG", sig); + sw = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth ("100% SIG"); + + sigscale->paint(posx-1, posy, sig); + + posx = posx + barwidth + 3; + frameBuffer->paintBoxRel(posx, posy - 2, sw+4, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString (posx+2, posy + mheight, sw, percent, COL_MENUCONTENT); + } + + if(snrscale->getPercent() != snr) { + posx = x + 10 + 210; + sprintf(percent, "%d%% SNR", snr); + sw = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth ("100% SNR"); + snrscale->paint(posx-1, posy, snr); + + posx = posx + barwidth + 3; + frameBuffer->paintBoxRel(posx, posy - 2, sw+4, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString (posx+2, posy + mheight, sw, percent, COL_MENUCONTENT); + } +} diff --git a/src/gui/motorcontrol.h b/src/gui/motorcontrol.h new file mode 100644 index 000000000..5d88e5a03 --- /dev/null +++ b/src/gui/motorcontrol.h @@ -0,0 +1,90 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __motorcontrol__ +#define __motorcontrol__ + +#include +#include +#include +#include + + +#define STEP_MODE_OFF 0 +#define STEP_MODE_AUTO 1 +#define STEP_MODE_ON 2 +#define STEP_MODE_TIMED 3 + +class CMotorControl : public CMenuTarget +{ + private: + void Init(void); + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hheight,mheight; // head/menu font height + int ypos; + int ypos_status; + int ypos_menue; + + int8_t stepSize; + int32_t stepDelay; + int stepMode; + bool installerMenue; + uint8_t motorPosition; + int32_t satellitePosition; + int satfindpid; + CScale * snrscale, * sigscale; + + void paint(); + void paintMenu(void); + void paintStatus(void); + void paintLine(int x, int * y, int width, char * txt); + void paintLine(int x, int y, int width, char * txt); + void paintSeparator(int xpos, int * ypos, int width, char * txt); + void motorStepEast(void); + void motorStepWest(void); + void startSatFind(void); + void stopSatFind(void); + void showSNR(void); + + public: + + CMotorControl(); + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + + +#endif diff --git a/src/gui/moviebrowser.cpp b/src/gui/moviebrowser.cpp new file mode 100644 index 000000000..b9a5392f7 --- /dev/null +++ b/src/gui/moviebrowser.cpp @@ -0,0 +1,4317 @@ +/*************************************************************************** + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + $Id: moviebrowser.cpp,v 1.10 2006/09/11 21:11:35 guenther Exp $ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + *********************************************************** + + Module Name: moviebrowser.cpp . + + Description: Implementation of the CMovieBrowser class + This class provides a filebrowser window to view, select and start a movies from HD. + This class does replace the Filebrowser + + Date: Nov 2005 + + Author: Günther@tuxbox.berlios.org + based on code of Steffen Hehn 'McClean' +****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "moviebrowser.h" +#include "filebrowser.h" +#include "widget/hintbox.h" +#include "widget/helpbox.h" +#include "widget/messagebox.h" +#include "widget/stringinput_ext.h" +#include +#include +#include +#include "neutrino.h" +#include +#include // for statfs +#include +#include +#include +#include +#include +#include + +extern CPictureViewer * g_PicViewer; +#define PIC_W 52 +#define PIC_H 39 +static CScale * timescale; +#define ROUND_RADIUS 9 + +#define my_scandir scandir64 +#define my_alphasort alphasort64 +typedef struct stat64 stat_struct; +typedef struct dirent64 dirent_struct; +#define my_stat stat64 +static off64_t get_full_len(char * startname); +//static off64_t truncate_movie(char * name, off64_t size, int len, int seconds); +static off64_t truncate_movie(MI_MOVIE_INFO * minfo); +static off64_t cut_movie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie); +static off64_t copy_movie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie, bool onefile); +void strReplace(std::string& orig, const char* fstr, const std::string rstr); + +#define TRACE printf +#define TRACE_1 printf + +#define VLC_URI "vlc://" + +#define NUMBER_OF_MOVIES_LAST 40 // This is the number of movies shown in last recored and last played list + +#define MESSAGEBOX_BROWSER_ROW_ITEM_COUNT 20 +const CMenuOptionChooser::keyval MESSAGEBOX_BROWSER_ROW_ITEM[MESSAGEBOX_BROWSER_ROW_ITEM_COUNT] = +{ + { MB_INFO_FILENAME, LOCALE_MOVIEBROWSER_INFO_FILENAME }, + { MB_INFO_FILEPATH, LOCALE_MOVIEBROWSER_INFO_PATH }, + { MB_INFO_TITLE, LOCALE_MOVIEBROWSER_INFO_TITLE }, + { MB_INFO_SERIE, LOCALE_MOVIEBROWSER_INFO_SERIE }, + { MB_INFO_INFO1, LOCALE_MOVIEBROWSER_INFO_INFO1 }, + { MB_INFO_MAJOR_GENRE, LOCALE_MOVIEBROWSER_INFO_GENRE_MAJOR }, + { MB_INFO_MINOR_GENRE, LOCALE_MOVIEBROWSER_INFO_GENRE_MINOR }, + { MB_INFO_PARENTAL_LOCKAGE, LOCALE_MOVIEBROWSER_INFO_PARENTAL_LOCKAGE }, + { MB_INFO_CHANNEL, LOCALE_MOVIEBROWSER_INFO_CHANNEL }, + { MB_INFO_QUALITY, LOCALE_MOVIEBROWSER_INFO_QUALITY }, + { MB_INFO_PREVPLAYDATE, LOCALE_MOVIEBROWSER_INFO_PREVPLAYDATE }, + { MB_INFO_RECORDDATE, LOCALE_MOVIEBROWSER_INFO_RECORDDATE }, + { MB_INFO_PRODDATE, LOCALE_MOVIEBROWSER_INFO_PRODYEAR }, + { MB_INFO_COUNTRY, LOCALE_MOVIEBROWSER_INFO_PRODCOUNTRY }, + { MB_INFO_GEOMETRIE, LOCALE_MOVIEBROWSER_INFO_VIDEOFORMAT }, + { MB_INFO_AUDIO, LOCALE_MOVIEBROWSER_INFO_AUDIO }, + { MB_INFO_LENGTH, LOCALE_MOVIEBROWSER_INFO_LENGTH }, + { MB_INFO_SIZE, LOCALE_MOVIEBROWSER_INFO_SIZE }, + { MB_INFO_BOOKMARK, LOCALE_MOVIEBROWSER_MENU_MAIN_BOOKMARKS }, + { MB_INFO_FILENAME, LOCALE_MOVIEBROWSER_INFO_FILENAME } + }; + +#define MESSAGEBOX_YES_NO_OPTIONS_COUNT 2 +const CMenuOptionChooser::keyval MESSAGEBOX_YES_NO_OPTIONS[MESSAGEBOX_YES_NO_OPTIONS_COUNT] = +{ + { 0, LOCALE_MESSAGEBOX_NO }, + { 1, LOCALE_MESSAGEBOX_YES } +}; + +#define MESSAGEBOX_PARENTAL_LOCK_OPTIONS_COUNT 3 +const CMenuOptionChooser::keyval MESSAGEBOX_PARENTAL_LOCK_OPTIONS[MESSAGEBOX_PARENTAL_LOCK_OPTIONS_COUNT] = +{ + { 1, LOCALE_MOVIEBROWSER_MENU_PARENTAL_LOCK_ACTIVATED_YES }, + { 0, LOCALE_MOVIEBROWSER_MENU_PARENTAL_LOCK_ACTIVATED_NO }, + { 2, LOCALE_MOVIEBROWSER_MENU_PARENTAL_LOCK_ACTIVATED_NO_TEMP } +}; + +#define MESSAGEBOX_PARENTAL_LOCKAGE_OPTION_COUNT 6 +const CMenuOptionChooser::keyval MESSAGEBOX_PARENTAL_LOCKAGE_OPTIONS[MESSAGEBOX_PARENTAL_LOCKAGE_OPTION_COUNT] = +{ + { 0, LOCALE_MOVIEBROWSER_INFO_PARENTAL_LOCKAGE_0YEAR }, + { 6, LOCALE_MOVIEBROWSER_INFO_PARENTAL_LOCKAGE_6YEAR }, + { 12, LOCALE_MOVIEBROWSER_INFO_PARENTAL_LOCKAGE_12YEAR }, + { 16, LOCALE_MOVIEBROWSER_INFO_PARENTAL_LOCKAGE_16YEAR }, + { 18, LOCALE_MOVIEBROWSER_INFO_PARENTAL_LOCKAGE_18YEAR }, + { 99, LOCALE_MOVIEBROWSER_INFO_PARENTAL_LOCKAGE_ALWAYS } +}; + +#define MAX_WINDOW_WIDTH (g_settings.screen_EndX - g_settings.screen_StartX - 40) +#define MAX_WINDOW_HEIGHT (g_settings.screen_EndY - g_settings.screen_StartY - 40) + +#define MIN_WINDOW_WIDTH ((g_settings.screen_EndX - g_settings.screen_StartX)>>1) +#define MIN_WINDOW_HEIGHT 200 + +#define TITLE_BACKGROUND_COLOR ((CFBWindow::color_t)COL_MENUHEAD_PLUS_0) +#define TITLE_FONT_COLOR ((CFBWindow::color_t)COL_MENUHEAD) + +#define TEXT_FONT g_Font[SNeutrinoSettings::FONT_TYPE_MENU] +#define TITLE_FONT g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE] +#define FOOT_FONT g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL] + +#define INTER_FRAME_SPACE 4 // space between e.g. upper and lower window +#define TEXT_BORDER_WIDTH 8 + +const neutrino_locale_t m_localizedItemName[MB_INFO_MAX_NUMBER+1] = +{ + LOCALE_MOVIEBROWSER_SHORT_FILENAME, + LOCALE_MOVIEBROWSER_SHORT_PATH, + LOCALE_MOVIEBROWSER_SHORT_TITLE , + LOCALE_MOVIEBROWSER_SHORT_SERIE, + LOCALE_MOVIEBROWSER_SHORT_INFO1, + LOCALE_MOVIEBROWSER_SHORT_GENRE_MAJOR, + LOCALE_MOVIEBROWSER_SHORT_GENRE_MINOR, + LOCALE_MOVIEBROWSER_SHORT_INFO2, + LOCALE_MOVIEBROWSER_SHORT_PARENTAL_LOCKAGE , + LOCALE_MOVIEBROWSER_SHORT_CHANNEL , + LOCALE_MOVIEBROWSER_SHORT_BOOK, + LOCALE_MOVIEBROWSER_SHORT_QUALITY, + LOCALE_MOVIEBROWSER_SHORT_PREVPLAYDATE, + LOCALE_MOVIEBROWSER_SHORT_RECORDDATE, + LOCALE_MOVIEBROWSER_SHORT_PRODYEAR, + LOCALE_MOVIEBROWSER_SHORT_COUNTRY, + LOCALE_MOVIEBROWSER_SHORT_FORMAT , + LOCALE_MOVIEBROWSER_SHORT_AUDIO , + LOCALE_MOVIEBROWSER_SHORT_LENGTH, + LOCALE_MOVIEBROWSER_SHORT_SIZE, + NONEXISTANT_LOCALE +}; + +// default row size in pixel for any element +#define MB_ROW_WIDTH_FILENAME 150 +#define MB_ROW_WIDTH_FILEPATH 150 +#define MB_ROW_WIDTH_TITLE 300 +#define MB_ROW_WIDTH_SERIE 100 +#define MB_ROW_WIDTH_INFO1 100 +#define MB_ROW_WIDTH_MAJOR_GENRE 100 +#define MB_ROW_WIDTH_MINOR_GENRE 30 +#define MB_ROW_WIDTH_INFO2 30 +#define MB_ROW_WIDTH_PARENTAL_LOCKAGE 25 +#define MB_ROW_WIDTH_CHANNEL 80 +#define MB_ROW_WIDTH_BOOKMARK 50 +#define MB_ROW_WIDTH_QUALITY 25 +#define MB_ROW_WIDTH_PREVPLAYDATE 80 +#define MB_ROW_WIDTH_RECORDDATE 80 +#define MB_ROW_WIDTH_PRODDATE 50 +#define MB_ROW_WIDTH_COUNTRY 50 +#define MB_ROW_WIDTH_GEOMETRIE 50 +#define MB_ROW_WIDTH_AUDIO 50 +#define MB_ROW_WIDTH_LENGTH 40 +#define MB_ROW_WIDTH_SIZE 45 + +const int m_defaultRowWidth[MB_INFO_MAX_NUMBER+1] = +{ + MB_ROW_WIDTH_FILENAME , + MB_ROW_WIDTH_FILEPATH, + MB_ROW_WIDTH_TITLE, + MB_ROW_WIDTH_SERIE, + MB_ROW_WIDTH_INFO1, + MB_ROW_WIDTH_MAJOR_GENRE , + MB_ROW_WIDTH_MINOR_GENRE , + MB_ROW_WIDTH_INFO2 , + MB_ROW_WIDTH_PARENTAL_LOCKAGE , + MB_ROW_WIDTH_CHANNEL, + MB_ROW_WIDTH_BOOKMARK, + MB_ROW_WIDTH_QUALITY , + MB_ROW_WIDTH_PREVPLAYDATE, + MB_ROW_WIDTH_RECORDDATE , + MB_ROW_WIDTH_PRODDATE , + MB_ROW_WIDTH_COUNTRY , + MB_ROW_WIDTH_GEOMETRIE, + MB_ROW_WIDTH_AUDIO , + MB_ROW_WIDTH_LENGTH, + MB_ROW_WIDTH_SIZE, + 0 //MB_ROW_WIDTH_MAX_NUMBER +}; +static MI_MOVIE_INFO* playing_info; +//------------------------------------------------------------------------ +// sorting +//------------------------------------------------------------------------ +#define FILEBROWSER_NUMBER_OF_SORT_VARIANTS 5 + +bool sortDirection = 0; + +bool compare_to_lower(const char a, const char b) +{ + return tolower(a) < tolower(b); +}; + +// sort operators +bool sortByTitle (const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) +{ + if (std::lexicographical_compare(a->epgTitle.begin(), a->epgTitle.end(), b->epgTitle.begin(), b->epgTitle.end(), compare_to_lower)) + return true; + if (std::lexicographical_compare(b->epgTitle.begin(), b->epgTitle.end(), a->epgTitle.begin(), a->epgTitle.end(), compare_to_lower)) + return false; + return a->file.Time < b->file.Time; +} +bool sortByGenre (const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) +{ + if (std::lexicographical_compare(a->epgInfo1.begin(), a->epgInfo1.end(), b->epgInfo1.begin(), b->epgInfo1.end(), compare_to_lower)) + return true; + if (std::lexicographical_compare(b->epgInfo1.begin(), b->epgInfo1.end(), a->epgInfo1.begin(), a->epgInfo1.end(), compare_to_lower)) + return false; + return sortByTitle(a,b); +} +bool sortByChannel (const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) +{ + if (std::lexicographical_compare(a->epgChannel.begin(), a->epgChannel.end(), b->epgChannel.begin(), b->epgChannel.end(), compare_to_lower)) + return true; + if (std::lexicographical_compare(b->epgChannel.begin(), b->epgChannel.end(), a->epgChannel.begin(), a->epgChannel.end(), compare_to_lower)) + return false; + return sortByTitle(a,b); +} +bool sortByFileName (const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) +{ + if (std::lexicographical_compare(a->file.getFileName().begin(), a->file.getFileName().end(), b->file.getFileName().begin(), b->file.getFileName().end(), compare_to_lower)) + return true; + if (std::lexicographical_compare(b->file.getFileName().begin(), b->file.getFileName().end(), a->file.getFileName().begin(), a->file.getFileName().end(), compare_to_lower)) + return false; + return a->file.Time < b->file.Time; +} +bool sortByRecordDate (const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) +{ + if(sortDirection) + return a->file.Time > b->file.Time ; + else + return a->file.Time < b->file.Time ; +} +bool sortBySize (const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) +{ + if(sortDirection) + return a->file.Size > b->file.Size; + else + return a->file.Size < b->file.Size; +} +bool sortByAge (const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) +{ + if(sortDirection) + return a->parentalLockAge > b->parentalLockAge; + else + return a->parentalLockAge < b->parentalLockAge; +} +bool sortByQuality (const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) +{ + if(sortDirection) + return a->quality > b->quality; + else + return a->quality < b->quality; +} +bool sortByDir (const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) +{ + if(sortDirection) + return a->dirItNr > b->dirItNr; + else + return a->dirItNr < b->dirItNr; +} + +bool sortByLastPlay (const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) +{ + if(sortDirection) + return a->dateOfLastPlay > b->dateOfLastPlay; + else + return a->dateOfLastPlay < b->dateOfLastPlay; +} + +bool (* const sortBy[MB_INFO_MAX_NUMBER+1])(const MI_MOVIE_INFO* a, const MI_MOVIE_INFO* b) = +{ + &sortByFileName , //MB_INFO_FILENAME = 0, + &sortByDir, //MB_INFO_FILEPATH = 1, + &sortByTitle, //MB_INFO_TITLE = 2, + NULL, //MB_INFO_SERIE = 3, + &sortByGenre, //MB_INFO_INFO1 = 4, + NULL, //MB_INFO_MAJOR_GENRE = 5, + NULL, //MB_INFO_MINOR_GENRE = 6, + NULL, //MB_INFO_INFO2 = 7, + &sortByAge, //MB_INFO_PARENTAL_LOCKAGE = 8, + &sortByChannel, //MB_INFO_CHANNEL = 9, + NULL, //MB_INFO_BOOKMARK = 10, + &sortByQuality, //MB_INFO_QUALITY = 11, + &sortByLastPlay, //MB_INFO_PREVPLAYDATE = 12, + &sortByRecordDate, //MB_INFO_RECORDDATE = 13, + NULL, //MB_INFO_PRODDATE = 14, + NULL, //MB_INFO_COUNTRY = 15, + NULL, //MB_INFO_GEOMETRIE = 16, + NULL, //MB_INFO_AUDIO = 17, + NULL, //MB_INFO_LENGTH = 18, + &sortBySize, //MB_INFO_SIZE = 19, + NULL //MB_INFO_MAX_NUMBER = 20 +}; +/************************************************************************ + Public API +************************************************************************/ + +CMovieBrowser::CMovieBrowser(const char* path): configfile ('\t') +{ + m_selectedDir = path; + //addDir(m_selectedDir); + CMovieBrowser(); +} + +CMovieBrowser::CMovieBrowser(): configfile ('\t') +{ + TRACE("$Id: moviebrowser.cpp,v 1.10 2006/09/11 21:11:35 guenther Exp $\r\n"); + init(); +} + +CMovieBrowser::~CMovieBrowser() +{ + //TRACE("[mb] del\r\n"); + //saveSettings(&m_settings); + hide(); + m_dir.clear(); + + m_dirNames.clear(); + for(unsigned int i=0; i < m_vMovieInfo.size(); i++) + { + m_vMovieInfo[i].audioPids.clear(); + } + m_vMovieInfo.clear(); + m_vHandleBrowserList.clear(); + m_vHandleRecordList.clear(); + m_vHandlePlayList.clear(); + m_vHandleSerienames.clear(); + + for(int i = 0; i < LF_MAX_ROWS; i++) + { + m_browserListLines.lineArray[i].clear(); + m_recordListLines.lineArray[i].clear(); + m_playListLines.lineArray[i].clear(); + m_FilterLines.lineArray[i].clear(); + } +} + +void CMovieBrowser::fileInfoStale(void) +{ + m_file_info_stale = true; + m_seriename_stale = true; + + // Also release memory buffers, since we have to reload this stuff next time anyhow + m_dirNames.clear(); + + for(unsigned int i=0; i < m_vMovieInfo.size(); i++) + { + m_vMovieInfo[i].audioPids.clear(); + } + + m_vMovieInfo.clear(); + m_vHandleBrowserList.clear(); + m_vHandleRecordList.clear(); + m_vHandlePlayList.clear(); + m_vHandleSerienames.clear(); + + for(int i = 0; i < LF_MAX_ROWS; i++) + { + m_browserListLines.lineArray[i].clear(); + m_recordListLines.lineArray[i].clear(); + m_playListLines.lineArray[i].clear(); + m_FilterLines.lineArray[i].clear(); + } +}; + +void CMovieBrowser::init(void) +{ + //TRACE("[mb]->init\r\n"); + initGlobalSettings(); + loadSettings(&m_settings); + + //restart_mb_timeout = 0; + m_file_info_stale = true; + m_seriename_stale = true; + + m_pcWindow = CFrameBuffer::getInstance(); + m_pcBrowser = NULL; + m_pcLastPlay = NULL; + m_pcLastRecord = NULL; + m_pcInfo = NULL; + + m_windowFocus = MB_FOCUS_BROWSER; + + m_pcFontFoot = FOOT_FONT; + m_pcFontTitle = TITLE_FONT; + + m_textTitle = g_Locale->getText(LOCALE_MOVIEBROWSER_HEAD); + + m_currentStartPos = 0; + + m_movieSelectionHandler = NULL; + m_currentBrowserSelection = 0; + m_currentRecordSelection = 0; + m_currentPlaySelection = 0; + m_prevBrowserSelection = 0; + m_prevRecordSelection = 0; + m_prevPlaySelection = 0; + + m_storageType = MB_STORAGE_TYPE_NFS; + + m_parentalLock = m_settings.parentalLock; + + // check g_setting values + if(m_settings.gui >= MB_GUI_MAX_NUMBER) + m_settings.gui = MB_GUI_MOVIE_INFO; + + if(m_settings.sorting.direction >= MB_DIRECTION_MAX_NUMBER) + m_settings.sorting.direction = MB_DIRECTION_DOWN; + if(m_settings.sorting.item >= MB_INFO_MAX_NUMBER) + m_settings.sorting.item = MB_INFO_TITLE; + + if(m_settings.filter.item >= MB_INFO_MAX_NUMBER) + m_settings.filter.item = MB_INFO_MAX_NUMBER; + + if(m_settings.parentalLockAge >= MI_PARENTAL_MAX_NUMBER) + m_settings.parentalLockAge = MI_PARENTAL_OVER18; + if(m_settings.parentalLock >= MB_PARENTAL_LOCK_MAX_NUMBER) + m_settings.parentalLock = MB_PARENTAL_LOCK_OFF; + + if(m_settings.browserFrameHeight < MIN_BROWSER_FRAME_HEIGHT ) + m_settings.browserFrameHeight = MIN_BROWSER_FRAME_HEIGHT; + if(m_settings.browserFrameHeight > MAX_BROWSER_FRAME_HEIGHT) + m_settings.browserFrameHeight = MAX_BROWSER_FRAME_HEIGHT; + /***** Browser List **************/ + if(m_settings.browserRowNr == 0) + { + TRACE(" row error\r\n"); + // init browser row elements if not configured correctly by neutrino.config + m_settings.browserRowNr = 6; + m_settings.browserRowItem[0] = MB_INFO_TITLE; + m_settings.browserRowItem[1] = MB_INFO_INFO1; + m_settings.browserRowItem[2] = MB_INFO_RECORDDATE; + m_settings.browserRowItem[3] = MB_INFO_SIZE; + m_settings.browserRowItem[4] = MB_INFO_PARENTAL_LOCKAGE; + m_settings.browserRowItem[5] = MB_INFO_QUALITY; + m_settings.browserRowWidth[0] = m_defaultRowWidth[m_settings.browserRowItem[0]]; //300; + m_settings.browserRowWidth[1] = m_defaultRowWidth[m_settings.browserRowItem[1]]; //100; + m_settings.browserRowWidth[2] = m_defaultRowWidth[m_settings.browserRowItem[2]]; //80; + m_settings.browserRowWidth[3] = m_defaultRowWidth[m_settings.browserRowItem[3]]; //50; + m_settings.browserRowWidth[4] = m_defaultRowWidth[m_settings.browserRowItem[4]]; //30; + m_settings.browserRowWidth[5] = m_defaultRowWidth[m_settings.browserRowItem[5]]; //30; + } + + initFrames(); + initRows(); + //initDevelopment(); + + refreshLastPlayList(); + refreshLastRecordList(); + refreshBrowserList(); + refreshFilterList(); +#if 0 + TRACE_1("Frames\r\n\tScren:\t%3d,%3d,%3d,%3d\r\n\tMain:\t%3d,%3d,%3d,%3d\r\n\tTitle:\t%3d,%3d,%3d,%3d \r\n\tBrowsr:\t%3d,%3d,%3d,%3d \r\n\tPlay:\t%3d,%3d,%3d,%3d \r\n\tRecord:\t%3d,%3d,%3d,%3d\r\n\r\n", + g_settings.screen_StartX, + g_settings.screen_StartY, + g_settings.screen_EndX, + g_settings.screen_EndY, + m_cBoxFrame.iX, + m_cBoxFrame.iY, + m_cBoxFrame.iWidth, + m_cBoxFrame.iHeight, + m_cBoxFrameTitleRel.iX, + m_cBoxFrameTitleRel.iY, + m_cBoxFrameTitleRel.iWidth, + m_cBoxFrameTitleRel.iHeight, + m_cBoxFrameBrowserList.iX, + m_cBoxFrameBrowserList.iY, + m_cBoxFrameBrowserList.iWidth, + m_cBoxFrameBrowserList.iHeight, + m_cBoxFrameLastPlayList.iX, + m_cBoxFrameLastPlayList.iY, + m_cBoxFrameLastPlayList.iWidth, + m_cBoxFrameLastPlayList.iHeight, + m_cBoxFrameLastRecordList.iX, + m_cBoxFrameLastRecordList.iY, + m_cBoxFrameLastRecordList.iWidth, + m_cBoxFrameLastRecordList.iHeight + ); +#endif +} + +void CMovieBrowser::initGlobalSettings(void) +{ + //TRACE("[mb]->initGlobalSettings\r\n"); + + m_settings.gui = MB_GUI_MOVIE_INFO; + + m_settings.sorting.direction = MB_DIRECTION_DOWN; + m_settings.sorting.item = MB_INFO_TITLE; + + m_settings.filter.item = MB_INFO_MAX_NUMBER; + m_settings.filter.optionString = ""; + m_settings.filter.optionVar = 0; + + m_settings.parentalLockAge = MI_PARENTAL_OVER18; + m_settings.parentalLock = MB_PARENTAL_LOCK_OFF; + + for(int i = 0; i < MB_MAX_DIRS; i++) + { + m_settings.storageDir[i] = ""; + m_settings.storageDirUsed[i] = 0; + } + + /***** Browser List **************/ + m_settings.browserFrameHeight = g_settings.screen_EndY - g_settings.screen_StartY - 20 - ((g_settings.screen_EndY - g_settings.screen_StartY - 20)>>1) - (INTER_FRAME_SPACE>>1); + + m_settings.browserRowNr = 6; + m_settings.browserRowItem[0] = MB_INFO_TITLE; + m_settings.browserRowItem[1] = MB_INFO_INFO1; + m_settings.browserRowItem[2] = MB_INFO_RECORDDATE; + m_settings.browserRowItem[3] = MB_INFO_SIZE; + m_settings.browserRowItem[4] = MB_INFO_PARENTAL_LOCKAGE; + m_settings.browserRowItem[5] = MB_INFO_QUALITY; + m_settings.browserRowWidth[0] = m_defaultRowWidth[m_settings.browserRowItem[0]]; //300; + m_settings.browserRowWidth[1] = m_defaultRowWidth[m_settings.browserRowItem[1]]; //100; + m_settings.browserRowWidth[2] = m_defaultRowWidth[m_settings.browserRowItem[2]]; //80; + m_settings.browserRowWidth[3] = m_defaultRowWidth[m_settings.browserRowItem[3]]; //50; + m_settings.browserRowWidth[4] = m_defaultRowWidth[m_settings.browserRowItem[4]]; //30; + m_settings.browserRowWidth[5] = m_defaultRowWidth[m_settings.browserRowItem[5]]; //30; + + m_settings.storageDirMovieUsed = true; + m_settings.storageDirRecUsed = true; + m_settings.reload = true; + m_settings.remount = false; + m_settings.browser_serie_mode = 0; + m_settings.serie_auto_create = 0; +} + +void CMovieBrowser::initFrames(void) +{ + //TRACE("[mb]->initFrames\r\n"); + m_cBoxFrame.iX = g_settings.screen_StartX + 10; + m_cBoxFrame.iY = g_settings.screen_StartY + 10; + m_cBoxFrame.iWidth = g_settings.screen_EndX - g_settings.screen_StartX - 20; + m_cBoxFrame.iHeight = g_settings.screen_EndY - g_settings.screen_StartY - 20; + + m_cBoxFrameTitleRel.iX = 0; + m_cBoxFrameTitleRel.iY = 0; + m_cBoxFrameTitleRel.iWidth = m_cBoxFrame.iWidth; + m_cBoxFrameTitleRel.iHeight = m_pcFontTitle->getHeight(); +#ifndef FB_USE_PALETTE + if(m_cBoxFrameTitleRel.iHeight < PIC_H) m_cBoxFrameTitleRel.iHeight = PIC_H; +#endif + + m_cBoxFrameBrowserList.iX = m_cBoxFrame.iX; + m_cBoxFrameBrowserList.iY = m_cBoxFrame.iY + m_cBoxFrameTitleRel.iHeight; + m_cBoxFrameBrowserList.iWidth = m_cBoxFrame.iWidth; + m_cBoxFrameBrowserList.iHeight = m_settings.browserFrameHeight; //m_cBoxFrame.iHeight - (m_cBoxFrame.iHeight>>1) - (INTER_FRAME_SPACE>>1); + + m_cBoxFrameFootRel.iX = 0; + m_cBoxFrameFootRel.iY = m_cBoxFrame.iHeight - m_pcFontFoot->getHeight(); + m_cBoxFrameFootRel.iWidth = m_cBoxFrameBrowserList.iWidth; + m_cBoxFrameFootRel.iHeight = m_pcFontFoot->getHeight(); + + m_cBoxFrameLastPlayList.iX = m_cBoxFrameBrowserList.iX; + m_cBoxFrameLastPlayList.iY = m_cBoxFrameBrowserList.iY ; + m_cBoxFrameLastPlayList.iWidth = (m_cBoxFrameBrowserList.iWidth>>1) - (INTER_FRAME_SPACE>>1); + m_cBoxFrameLastPlayList.iHeight = m_cBoxFrameBrowserList.iHeight; + + m_cBoxFrameLastRecordList.iX = m_cBoxFrameLastPlayList.iX + m_cBoxFrameLastPlayList.iWidth + INTER_FRAME_SPACE; + m_cBoxFrameLastRecordList.iY = m_cBoxFrameLastPlayList.iY; + m_cBoxFrameLastRecordList.iWidth = m_cBoxFrame.iWidth - m_cBoxFrameLastPlayList.iWidth - INTER_FRAME_SPACE; + m_cBoxFrameLastRecordList.iHeight = m_cBoxFrameLastPlayList.iHeight; + + m_cBoxFrameInfo.iX = m_cBoxFrameBrowserList.iX; + m_cBoxFrameInfo.iY = m_cBoxFrameBrowserList.iY + m_cBoxFrameBrowserList.iHeight + INTER_FRAME_SPACE; + m_cBoxFrameInfo.iWidth = m_cBoxFrameBrowserList.iWidth; + m_cBoxFrameInfo.iHeight = m_cBoxFrame.iHeight - m_cBoxFrameBrowserList.iHeight - INTER_FRAME_SPACE - m_cBoxFrameFootRel.iHeight - m_cBoxFrameTitleRel.iHeight; + + m_cBoxFrameFilter.iX = m_cBoxFrameInfo.iX; + m_cBoxFrameFilter.iY = m_cBoxFrameInfo.iY; + m_cBoxFrameFilter.iWidth = m_cBoxFrameInfo.iWidth; + m_cBoxFrameFilter.iHeight = m_cBoxFrameInfo.iHeight; +} + +void CMovieBrowser::initRows(void) +{ + //TRACE("[mb]->initRows\r\n"); + + /***** Last Play List **************/ + m_settings.lastPlayRowNr = 2; + m_settings.lastPlayRow[0] = MB_INFO_TITLE; + m_settings.lastPlayRow[1] = MB_INFO_PREVPLAYDATE; + m_settings.lastPlayRow[2] = MB_INFO_MAX_NUMBER; + m_settings.lastPlayRow[3] = MB_INFO_MAX_NUMBER; + m_settings.lastPlayRow[4] = MB_INFO_MAX_NUMBER; + m_settings.lastPlayRow[5] = MB_INFO_MAX_NUMBER; + m_settings.lastPlayRowWidth[0] = 190; + m_settings.lastPlayRowWidth[1] = m_defaultRowWidth[m_settings.lastPlayRow[1]]; + m_settings.lastPlayRowWidth[2] = m_defaultRowWidth[m_settings.lastPlayRow[2]]; + m_settings.lastPlayRowWidth[3] = m_defaultRowWidth[m_settings.lastPlayRow[3]]; + m_settings.lastPlayRowWidth[4] = m_defaultRowWidth[m_settings.lastPlayRow[4]]; + m_settings.lastPlayRowWidth[5] = m_defaultRowWidth[m_settings.lastPlayRow[5]]; + + /***** Last Record List **************/ + m_settings.lastRecordRowNr = 2; + m_settings.lastRecordRow[0] = MB_INFO_TITLE; + m_settings.lastRecordRow[1] = MB_INFO_RECORDDATE; + m_settings.lastRecordRow[2] = MB_INFO_MAX_NUMBER; + m_settings.lastRecordRow[3] = MB_INFO_MAX_NUMBER; + m_settings.lastRecordRow[4] = MB_INFO_MAX_NUMBER; + m_settings.lastRecordRow[5] = MB_INFO_MAX_NUMBER; + m_settings.lastRecordRowWidth[0] = 190; + m_settings.lastRecordRowWidth[1] = m_defaultRowWidth[m_settings.lastRecordRow[1]]; + m_settings.lastRecordRowWidth[2] = m_defaultRowWidth[m_settings.lastRecordRow[2]]; + m_settings.lastRecordRowWidth[3] = m_defaultRowWidth[m_settings.lastRecordRow[3]]; + m_settings.lastRecordRowWidth[4] = m_defaultRowWidth[m_settings.lastRecordRow[4]]; + m_settings.lastRecordRowWidth[5] = m_defaultRowWidth[m_settings.lastRecordRow[5]]; +} + +void CMovieBrowser::initDevelopment(void) +{ + TRACE("[mb]->initDevelopment\r\n"); + std::string name; + name = "/mnt/movies/"; + //addDir(name); + name = "/mnt/record/"; + //addDir(name); + name = "/mnt/nfs/"; + //addDir(name); + +} + +void CMovieBrowser::defaultSettings(MB_SETTINGS* settings) +{ + CFile file; + file.Name = MOVIEBROWSER_SETTINGS_FILE; + delFile(file); + //configfile.clear(); + loadSettings(settings); +} + +bool CMovieBrowser::loadSettings(MB_SETTINGS* settings) +{ + bool result = true; + //TRACE("CMovieBrowser::loadSettings\r\n"); + //configfile.loadConfig(MOVIEBROWSER_SETTINGS_FILE); + if(configfile.loadConfig(MOVIEBROWSER_SETTINGS_FILE)) + { + settings->lastPlayMaxItems = configfile.getInt32("mb_lastPlayMaxItems", NUMBER_OF_MOVIES_LAST); + settings->lastRecordMaxItems = configfile.getInt32("mb_lastRecordMaxItems", NUMBER_OF_MOVIES_LAST); + settings->browser_serie_mode = configfile.getInt32("mb_browser_serie_mode", 0); + settings->serie_auto_create = configfile.getInt32("mb_serie_auto_create", 0); + + settings->gui = (MB_GUI)configfile.getInt32("mb_gui", MB_GUI_MOVIE_INFO); + + settings->sorting.item = (MB_INFO_ITEM)configfile.getInt32("mb_sorting_item", MB_INFO_TITLE); + settings->sorting.direction = (MB_DIRECTION)configfile.getInt32("mb_sorting_direction", MB_DIRECTION_UP); + + settings->filter.item = (MB_INFO_ITEM)configfile.getInt32("mb_filter_item", MB_INFO_INFO1); + settings->filter.optionString = configfile.getString("mb_filter_optionString", ""); + settings->filter.optionVar = configfile.getInt32("mb_filter_optionVar", 0); + + settings->parentalLockAge = (MI_PARENTAL_LOCKAGE)configfile.getInt32("mb_parentalLockAge", MI_PARENTAL_OVER18); + settings->parentalLock = (MB_PARENTAL_LOCK)configfile.getInt32("mb_parentalLock", MB_PARENTAL_LOCK_ACTIVE); + + settings->storageDirRecUsed = (bool)configfile.getInt32("mb_storageDir_rec", true ); + settings->storageDirMovieUsed = (bool)configfile.getInt32("mb_storageDir_movie", true ); + + settings->reload = (bool)configfile.getInt32("mb_reload", false ); + settings->remount = (bool)configfile.getInt32("mb_remount", false ); + + char cfg_key[81]; + for(int i = 0; i < MB_MAX_DIRS; i++) + { + sprintf(cfg_key, "mb_dir_%d", i); + settings->storageDir[i] = configfile.getString( cfg_key, "" ); + sprintf(cfg_key, "mb_dir_used%d", i); + settings->storageDirUsed[i] = configfile.getInt32( cfg_key,false ); + } + /* these variables are used for the listframes */ + settings->browserFrameHeight = configfile.getInt32("mb_browserFrameHeight", 250); + settings->browserRowNr = configfile.getInt32("mb_browserRowNr", 0); + for(int i = 0; i < MB_MAX_ROWS && i < settings->browserRowNr; i++) + { + sprintf(cfg_key, "mb_browserRowItem_%d", i); + settings->browserRowItem[i] = (MB_INFO_ITEM)configfile.getInt32(cfg_key, MB_INFO_MAX_NUMBER); + sprintf(cfg_key, "mb_browserRowWidth_%d", i); + settings->browserRowWidth[i] = configfile.getInt32(cfg_key, 50); + } + } + else + { + TRACE("CMovieBrowser::loadSettings failed\r\n"); + configfile.clear(); + result = false; + } + return (result); +} + +bool CMovieBrowser::saveSettings(MB_SETTINGS* settings) +{ + bool result = true; + TRACE("[mb] saveSettings\r\n"); + + configfile.setInt32("mb_lastPlayMaxItems", settings->lastPlayMaxItems); + configfile.setInt32("mb_lastRecordMaxItems", settings->lastRecordMaxItems); + configfile.setInt32("mb_browser_serie_mode", settings->browser_serie_mode); + configfile.setInt32("mb_serie_auto_create", settings->serie_auto_create); + + configfile.setInt32("mb_gui", settings->gui); + + configfile.setInt32("mb_sorting_item", settings->sorting.item); + configfile.setInt32("mb_sorting_direction", settings->sorting.direction); + + configfile.setInt32("mb_filter_item", settings->filter.item); + configfile.setString("mb_filter_optionString", settings->filter.optionString); + configfile.setInt32("mb_filter_optionVar", settings->filter.optionVar); + + configfile.setInt32("mb_storageDir_rec", settings->storageDirRecUsed ); + configfile.setInt32("mb_storageDir_movie", settings->storageDirMovieUsed ); + + configfile.setInt32("mb_parentalLockAge", settings->parentalLockAge); + configfile.setInt32("mb_parentalLock", settings->parentalLock); + + configfile.setInt32("mb_reload", settings->reload); + configfile.setInt32("mb_remount", settings->remount); + + char cfg_key[81]; + for(int i = 0; i < MB_MAX_DIRS; i++) + { + sprintf(cfg_key, "mb_dir_%d", i); + configfile.setString( cfg_key, settings->storageDir[i] ); + sprintf(cfg_key, "mb_dir_used%d", i); + configfile.setInt32( cfg_key, settings->storageDirUsed[i] ); // do not save this so far + } + /* these variables are used for the listframes */ + configfile.setInt32("mb_browserFrameHeight", settings->browserFrameHeight); + configfile.setInt32("mb_browserRowNr",settings->browserRowNr); + for(int i = 0; i < MB_MAX_ROWS && i < settings->browserRowNr; i++) + { + sprintf(cfg_key, "mb_browserRowItem_%d", i); + configfile.setInt32(cfg_key, settings->browserRowItem[i]); + sprintf(cfg_key, "mb_browserRowWidth_%d", i); + configfile.setInt32(cfg_key, settings->browserRowWidth[i]); + } + + configfile.saveConfig(MOVIEBROWSER_SETTINGS_FILE); + return (result); +} + +int CMovieBrowser::exec(CMenuTarget* parent, const std::string & actionKey) +{ + int returnval = menu_return::RETURN_REPAINT; + + if(actionKey == "loaddefault") + { + defaultSettings(&m_settings); + } + else if(actionKey == "save_options") + { + } + else if(actionKey == "show_movie_info_menu") + { + if(m_movieSelectionHandler != NULL) + showMovieInfoMenu(m_movieSelectionHandler); + } + else if(actionKey == "save_movie_info") + { + if(m_movieSelectionHandler != NULL) + m_movieInfo.saveMovieInfo( *m_movieSelectionHandler); + } + else if(actionKey == "save_movie_info_all") + { + std::vector * current_list=NULL; + + if(m_movieSelectionHandler != NULL) + { + if(m_windowFocus == MB_FOCUS_BROWSER) current_list = &m_vHandleBrowserList; + else if(m_windowFocus == MB_FOCUS_LAST_PLAY) current_list = &m_vHandlePlayList; + else if(m_windowFocus == MB_FOCUS_LAST_RECORD) current_list = &m_vHandleRecordList ; + + if(current_list != NULL) + { + CHintBox loadBox(LOCALE_MOVIEBROWSER_HEAD,g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_HEAD_UPDATE)); + loadBox.paint(); + for(unsigned int i = 0; i< current_list->size();i++) + { + if( !((*current_list)[i]->parentalLockAge != 0 && movieInfoUpdateAllIfDestEmptyOnly == true) && + movieInfoUpdateAll[MB_INFO_TITLE] ) + (*current_list)[i]->parentalLockAge = m_movieSelectionHandler->parentalLockAge; + + if( !(!(*current_list)[i]->serieName.empty() && movieInfoUpdateAllIfDestEmptyOnly == true) && + movieInfoUpdateAll[MB_INFO_SERIE] ) + (*current_list)[i]->serieName = m_movieSelectionHandler->serieName; + + if( !(!(*current_list)[i]->productionCountry.empty() && movieInfoUpdateAllIfDestEmptyOnly == true) && + movieInfoUpdateAll[MB_INFO_COUNTRY] ) + (*current_list)[i]->productionCountry = m_movieSelectionHandler->productionCountry; + + if( !((*current_list)[i]->genreMajor!=0 && movieInfoUpdateAllIfDestEmptyOnly == true) && + movieInfoUpdateAll[MB_INFO_MAJOR_GENRE] ) + (*current_list)[i]->genreMajor = m_movieSelectionHandler->genreMajor; + + if( !((*current_list)[i]->quality!=0 && movieInfoUpdateAllIfDestEmptyOnly == true) && + movieInfoUpdateAll[MB_INFO_QUALITY] ) + (*current_list)[i]->quality = m_movieSelectionHandler->quality; + + m_movieInfo.saveMovieInfo( *((*current_list)[i]) ); + } + loadBox.hide(); + } + } + } + else if(actionKey == "reload_movie_info") + { + loadMovies(); + refresh(); + } + else if(actionKey == "run") + { + if(parent) parent->hide (); + exec(NULL); + } + else if(actionKey == "book_clear_all") + { + if(m_movieSelectionHandler != NULL) + { + m_movieSelectionHandler->bookmarks.start =0; + m_movieSelectionHandler->bookmarks.end =0; + m_movieSelectionHandler->bookmarks.lastPlayStop =0; + for(int i=0; ibookmarks.user[i].name.empty(); + m_movieSelectionHandler->bookmarks.user[i].length =0; + m_movieSelectionHandler->bookmarks.user[i].pos =0; + } + } + } + return returnval; +} + +int CMovieBrowser::exec(const char* path) +{ + bool res = false; + + TRACE("[mb] start MovieBrowser\r\n"); + int timeout = -1; + int returnDefaultOnTimeout = true; + neutrino_msg_t msg; + neutrino_msg_data_t data; + + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, g_Locale->getText(LOCALE_MOVIEBROWSER_HEAD)); + // might be removed, for development it is good to reload the settings at any startup for testing + //loadSettings(&m_settings); + //init(); // FIXME test -> crash + loadSettings(&m_settings); + initFrames(); + + // Clear all, to avoid 'jump' in screen + m_vHandleBrowserList.clear(); + m_vHandleRecordList.clear(); + m_vHandlePlayList.clear(); + + for(int i = 0; i < LF_MAX_ROWS; i++) + { + m_browserListLines.lineArray[i].clear(); + m_recordListLines.lineArray[i].clear(); + m_playListLines.lineArray[i].clear(); + } + + m_selectedDir = path; + + if(paint() == false) + return res;// paint failed due to less memory , exit + + if ( timeout == -1 ) + timeout = g_settings.timing[SNeutrinoSettings::TIMING_FILEBROWSER]; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd( timeout ); + + if(m_settings.remount == true) + { + TRACE("[mb] remount\r\n"); + //umount automount dirs + for(int i = 0; i < NETWORK_NFS_NR_OF_ENTRIES; i++) + { + if(g_settings.network_nfs_automount[i]) + umount2(g_settings.network_nfs_local_dir[i],MNT_FORCE); + } + CFSMounter::automount(); + } + + refreshTitle(); + if(m_file_info_stale == true) + { + TRACE("[mb] reload\r\n"); + loadMovies(); + } + else + { + // since we cleared everything above, we have to refresh the list now. + refreshBrowserList(); + refreshLastPlayList(); + refreshLastRecordList(); + } + + // get old movie selection and set position in windows + m_currentBrowserSelection = m_prevBrowserSelection; + m_currentRecordSelection = m_prevRecordSelection; + m_currentPlaySelection = m_prevPlaySelection; + + m_pcBrowser->setSelectedLine(m_currentBrowserSelection); + m_pcLastRecord->setSelectedLine(m_currentRecordSelection); + m_pcLastPlay->setSelectedLine(m_currentPlaySelection); + + updateMovieSelection(); + //refreshMovieInfo(); + + onSetGUIWindow(m_settings.gui); + + bool loop = true; + bool result; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + result = onButtonPress(msg); + if(result == false) + { + if (msg == CRCInput::RC_timeout && returnDefaultOnTimeout) + { + TRACE("[mb] Timerevent\n"); + //if( restart_mb_timeout == 1) + // restart_mb_timeout = 0; + //else + loop = false; + } + else if(msg == CRCInput::RC_ok) + { + m_currentStartPos = 0; + + if(m_movieSelectionHandler != NULL) + { + // If there is any available bookmark, show the bookmark menu + if( m_movieSelectionHandler->bookmarks.lastPlayStop != 0 || + m_movieSelectionHandler->bookmarks.start != 0) + { + TRACE("[mb] stop: %d start:%d \r\n",m_movieSelectionHandler->bookmarks.lastPlayStop,m_movieSelectionHandler->bookmarks.start); + m_currentStartPos = showStartPosSelectionMenu(); // display start menu m_currentStartPos = + } + if(m_currentStartPos >= 0) { + playing_info = m_movieSelectionHandler; + TRACE("[mb] start pos: %d s\r\n",m_currentStartPos); + res = true; + loop = false; + } else + refresh(); + } + } + else if (msg == CRCInput::RC_home) + { + loop = false; + } + else if (msg == CRCInput::RC_sat || msg == CRCInput::RC_favorites) { + //FIXME do nothing ? + } + else if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) + { + TRACE("[mb]->exec: getInstance\r\n"); + //res = menu_return::RETURN_EXIT_ALL; + loop = false; + } + } + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(timeout); // calcualate next timeout + } + hide(); + //TRACE(" return %d\r\n",res); + + m_prevBrowserSelection = m_currentBrowserSelection; + m_prevRecordSelection = m_currentRecordSelection; + m_prevPlaySelection = m_currentPlaySelection; + + saveSettings(&m_settings); // might be better done in ~CMovieBrowser, but for any reason this does not work if MB is killed by neutrino shutdown + + // make stale if we should reload the next time, but not if movie has to be played + if(m_settings.reload == true && res == false) + { + TRACE("[mb] force reload next time\r\n"); + fileInfoStale(); + } + + //CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + return (res); +} + +void CMovieBrowser::hide(void) +{ + //TRACE("[mb]->Hide\r\n"); + m_pcWindow->paintBackground(); + if (m_pcFilter != NULL) + { + m_currentFilterSelection = m_pcFilter->getSelectedLine(); + delete m_pcFilter; + m_pcFilter = NULL; + } + if (m_pcBrowser != NULL) + { + m_currentBrowserSelection = m_pcBrowser->getSelectedLine(); + delete m_pcBrowser; + m_pcBrowser = NULL; + } + if (m_pcLastPlay != NULL) + { + m_currentPlaySelection = m_pcLastPlay->getSelectedLine(); + delete m_pcLastPlay; + m_pcLastPlay = NULL; + } + if (m_pcLastRecord != NULL) + { + m_currentRecordSelection = m_pcLastRecord->getSelectedLine(); + delete m_pcLastRecord; + m_pcLastRecord = NULL; + } + if (m_pcInfo != NULL) delete m_pcInfo; + //if (m_pcWindow != NULL) delete m_pcWindow; + + //m_pcWindow = NULL; + m_pcInfo = NULL; + +} + +int CMovieBrowser::paint(void) +{ + TRACE("[mb]->Paint\r\n"); + + //CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, g_Locale->getText(LOCALE_MOVIEBROWSER_HEAD)); + + //Font* font = TEXT_FONT; + Font* font = NULL; + + m_pcBrowser = new CListFrame(&m_browserListLines, font, CListFrame::SCROLL | CListFrame::HEADER_LINE, + &m_cBoxFrameBrowserList); + m_pcLastPlay = new CListFrame(&m_playListLines, font, CListFrame::SCROLL | CListFrame::HEADER_LINE | CListFrame::TITLE, + &m_cBoxFrameLastPlayList, g_Locale->getText(LOCALE_MOVIEBROWSER_HEAD_PLAYLIST), + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]); + m_pcLastRecord = new CListFrame(&m_recordListLines, font, CListFrame::SCROLL | CListFrame::HEADER_LINE | CListFrame::TITLE, + &m_cBoxFrameLastRecordList, g_Locale->getText(LOCALE_MOVIEBROWSER_HEAD_RECORDLIST), + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]); + m_pcFilter = new CListFrame(&m_FilterLines, font, CListFrame::SCROLL | CListFrame::TITLE, + &m_cBoxFrameFilter, g_Locale->getText(LOCALE_MOVIEBROWSER_HEAD_FILTER), + g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]); + m_pcInfo = new CTextBox(" ", NULL, CTextBox::SCROLL, &m_cBoxFrameInfo); + + + if( m_pcBrowser == NULL || m_pcLastPlay == NULL || + m_pcLastRecord == NULL || m_pcInfo == NULL || m_pcFilter == NULL) + { + TRACE("[mb] paint, ERROR: not enought memory to allocate windows"); + if (m_pcFilter != NULL)delete m_pcFilter; + if (m_pcBrowser != NULL)delete m_pcBrowser; + if (m_pcLastPlay != NULL) delete m_pcLastPlay; + if (m_pcLastRecord != NULL)delete m_pcLastRecord; + if (m_pcInfo != NULL) delete m_pcInfo; + + m_pcInfo = NULL; + m_pcLastPlay = NULL; + m_pcLastRecord = NULL; + m_pcBrowser = NULL; + m_pcFilter = NULL; + + return (false); + } + //onSetGUIWindow(m_settings.gui); + //refreshTitle(); + //refreshFoot(); + refreshLCD(); + //refresh(); + return (true); +} + +void CMovieBrowser::refresh(void) +{ + //TRACE("[mb]->refresh\r\n"); + + refreshTitle(); + if (m_pcBrowser != NULL && m_showBrowserFiles == true ) + m_pcBrowser->refresh(); + if (m_pcLastPlay != NULL && m_showLastPlayFiles == true ) + m_pcLastPlay->refresh(); + if (m_pcLastRecord != NULL && m_showLastRecordFiles == true) + m_pcLastRecord->refresh(); + if (m_pcInfo != NULL && m_showMovieInfo == true) + refreshMovieInfo(); + //m_pcInfo->refresh(); + if (m_pcFilter != NULL && m_showFilter == true) + m_pcFilter->refresh(); + + refreshFoot(); + refreshLCD(); +} + +std::string CMovieBrowser::getCurrentDir(void) +{ + return(m_selectedDir); +} + +CFile* CMovieBrowser::getSelectedFile(void) +{ + //TRACE("[mb]->getSelectedFile: %s\r\n",m_movieSelectionHandler->file.Name.c_str()); + + if(m_movieSelectionHandler != NULL) + return(&m_movieSelectionHandler->file); + else + return(NULL); +} + +void CMovieBrowser::refreshMovieInfo(void) +{ +//TRACE("[mb]->refreshMovieInfo m_vMovieInfo.size %d\n", m_vMovieInfo.size()); + std::string emptytext = " "; + if(m_vMovieInfo.size() <= 0) { + if(m_pcInfo != NULL) + m_pcInfo->setText(&emptytext); + return; + } + if (m_movieSelectionHandler == NULL) + { + // There is no selected element, clear LCD + m_pcInfo->setText(&emptytext); + } + else + { + bool logo_ok = false; + int divx = 720/m_cBoxFrameInfo.iHeight; + int picw = 720/divx; + int pich = 576/divx; +#ifndef FB_USE_PALETTE + std::string fname = m_movieSelectionHandler->file.Name; + strReplace(fname, ".ts", ".bmp"); +//printf("screenshot name: %s\n", fname.c_str()); + logo_ok = !access(fname.c_str(), F_OK); +#endif + m_pcInfo->setText(&m_movieSelectionHandler->epgInfo2, logo_ok ? m_cBoxFrameInfo.iWidth-picw-20: 0); + +#ifndef FB_USE_PALETTE +//printf("refreshMovieInfo: EpgId %llx id %llx y %d\n", m_movieSelectionHandler->epgEpgId, m_movieSelectionHandler->epgId, m_cBoxFrameTitleRel.iY); + int lx = m_cBoxFrame.iX+m_cBoxFrameTitleRel.iX+m_cBoxFrameTitleRel.iWidth-PIC_W-10; + int ly = m_cBoxFrameTitleRel.iY+m_cBoxFrame.iY+ (m_cBoxFrameTitleRel.iHeight-PIC_H)/2; + m_pcWindow->paintBoxRel(lx, ly, PIC_W, PIC_H, TITLE_BACKGROUND_COLOR); + g_PicViewer->DisplayLogo(m_movieSelectionHandler->epgEpgId >>16, lx, ly, PIC_W, PIC_H); + if(logo_ok) { +#if 0 + lx = m_cBoxFrameInfo.iX+m_cBoxFrameInfo.iWidth - picw -10; + ly = m_cBoxFrameInfo.iY + (m_cBoxFrameInfo.iHeight-pich)/2; + g_PicViewer->DisplayImage(fname, lx, ly, picw, pich); +#endif + lx = m_cBoxFrameInfo.iX+m_cBoxFrameInfo.iWidth - picw -10; + ly = m_cBoxFrameInfo.iY + (m_cBoxFrameInfo.iHeight-pich)/2; + m_pcWindow->paintVLineRel(lx, ly, pich, COL_WHITE); + m_pcWindow->paintVLineRel(lx+picw, ly, pich, COL_WHITE); + m_pcWindow->paintHLineRel(lx, picw, ly, COL_WHITE); + m_pcWindow->paintHLineRel(lx, picw, ly+pich, COL_WHITE); + g_PicViewer->DisplayImage(fname, lx+3, ly+3, picw-3, pich-3); + } +#endif + } +} + +void CMovieBrowser::refreshLCD(void) +{ + if(m_vMovieInfo.size() <= 0) return; + + //CVFD * lcd = CVFD::getInstance(); + if(m_movieSelectionHandler == NULL) + { + // There is no selected element, clear LCD + //lcd->showMenuText(0, " ", -1, true); // UTF-8 + //lcd->showMenuText(1, " ", -1, true); // UTF-8 + } + else + { + CVFD::getInstance()->showMenuText(0, m_movieSelectionHandler->epgTitle.c_str(), -1, true); // UTF-8 + //lcd->showMenuText(1, m_movieSelectionHandler->epgInfo1.c_str(), -1, true); // UTF-8 + } +} + +void CMovieBrowser::refreshFilterList(void) +{ + TRACE("[mb]->refreshFilterList %d\r\n",m_settings.filter.item); + + std::string string_item; + + m_FilterLines.rows = 1; + m_FilterLines.lineArray[0].clear(); + m_FilterLines.rowWidth[0] = 400; + m_FilterLines.lineHeader[0]= ""; + + if(m_vMovieInfo.size() <= 0) + return; // exit here if nothing else is to do + + if(m_settings.filter.item == MB_INFO_MAX_NUMBER) + { + // show Main List + string_item = g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_GENRE_MAJOR); + m_FilterLines.lineArray[0].push_back(string_item); + string_item = g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_INFO1); + m_FilterLines.lineArray[0].push_back(string_item); + string_item = g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_PATH); + m_FilterLines.lineArray[0].push_back(string_item); + string_item = g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_SERIE); + m_FilterLines.lineArray[0].push_back(string_item); + } + else + { + std::string tmp = g_Locale->getText(LOCALE_MENU_BACK); + m_FilterLines.lineArray[0].push_back(tmp); + + if(m_settings.filter.item == MB_INFO_FILEPATH) + { + for(unsigned int i =0 ; i < m_dirNames.size() ;i++) + { + m_FilterLines.lineArray[0].push_back(m_dirNames[i]); + } + } + else if(m_settings.filter.item == MB_INFO_INFO1) + { + for(unsigned int i = 0; i < m_vMovieInfo.size(); i++) + { + bool found = false; + for(unsigned int t = 0; t < m_FilterLines.lineArray[0].size() && found == false; t++) + { + if(strcmp(m_FilterLines.lineArray[0][t].c_str(),m_vMovieInfo[i].epgInfo1.c_str()) == 0) + found = true; + } + if(found == false) + m_FilterLines.lineArray[0].push_back(m_vMovieInfo[i].epgInfo1); + } + } + else if(m_settings.filter.item == MB_INFO_MAJOR_GENRE) + { + for(int i = 0; i < GENRE_ALL_COUNT; i++) + { + std::string tmp = g_Locale->getText(GENRE_ALL[i].value); + m_FilterLines.lineArray[0].push_back(tmp); + } + } + else if(m_settings.filter.item == MB_INFO_SERIE) + { + updateSerienames(); + for(unsigned int i = 0; i < m_vHandleSerienames.size(); i++) + { + m_FilterLines.lineArray[0].push_back(m_vHandleSerienames[i]->serieName); + } + } + } + m_pcFilter->setLines(&m_FilterLines); +} + +void CMovieBrowser::refreshLastPlayList(void) //P2 +{ + //TRACE("[mb]->refreshlastPlayList \r\n"); + std::string string_item; + + // Initialise and clear list array + m_playListLines.rows = m_settings.lastPlayRowNr; + for(int row = 0 ;row < m_settings.lastPlayRowNr; row++) + { + m_playListLines.lineArray[row].clear(); + m_playListLines.rowWidth[row] = m_settings.lastPlayRowWidth[row]; + m_playListLines.lineHeader[row]= g_Locale->getText(m_localizedItemName[m_settings.lastPlayRow[row]]); + } + m_vHandlePlayList.clear(); + + if(m_vMovieInfo.size() <= 0) { + if(m_pcLastPlay != NULL) + m_pcLastPlay->setLines(&m_playListLines); + return; // exit here if nothing else is to do + } + + MI_MOVIE_INFO* movie_handle; + // prepare Browser list for sorting and filtering + for(unsigned int file=0; file < m_vMovieInfo.size(); file++) + { + if( /*isFiltered(m_vMovieInfo[file]) == false &&*/ + isParentalLock(m_vMovieInfo[file]) == false) + { + movie_handle = &(m_vMovieInfo[file]); + m_vHandlePlayList.push_back(movie_handle); + } + } + // sort the not filtered files + onSortMovieInfoHandleList(m_vHandlePlayList,MB_INFO_PREVPLAYDATE,MB_DIRECTION_DOWN); + + for( int handle=0; handle < (int) m_vHandlePlayList.size() && handle < m_settings.lastPlayMaxItems ;handle++) + { + for(int row = 0; row < m_settings.lastPlayRowNr ;row++) + { + if ( getMovieInfoItem(*m_vHandlePlayList[handle], m_settings.lastPlayRow[row], &string_item) == false) + { + string_item = "n/a"; + if(m_settings.lastPlayRow[row] == MB_INFO_TITLE) + getMovieInfoItem(*m_vHandlePlayList[handle], MB_INFO_FILENAME, &string_item); + } + m_playListLines.lineArray[row].push_back(string_item); + } + } + m_pcLastPlay->setLines(&m_playListLines); + + m_currentPlaySelection = m_pcLastPlay->getSelectedLine(); + // update selected movie if browser is in the focus + if (m_windowFocus == MB_FOCUS_LAST_PLAY) + { + updateMovieSelection(); + } +} + +void CMovieBrowser::refreshLastRecordList(void) //P2 +{ + //TRACE("[mb]->refreshLastRecordList \r\n"); + std::string string_item; + + // Initialise and clear list array + m_recordListLines.rows = m_settings.lastRecordRowNr; + for(int row = 0 ;row < m_settings.lastRecordRowNr; row++) + { + m_recordListLines.lineArray[row].clear(); + m_recordListLines.rowWidth[row] = m_settings.lastRecordRowWidth[row]; + m_recordListLines.lineHeader[row]= g_Locale->getText(m_localizedItemName[m_settings.lastRecordRow[row]]); + } + m_vHandleRecordList.clear(); + + if(m_vMovieInfo.size() <= 0) { + if(m_pcLastRecord != NULL) + m_pcLastRecord->setLines(&m_recordListLines); + return; // exit here if nothing else is to do + } + + MI_MOVIE_INFO* movie_handle; + // prepare Browser list for sorting and filtering + for(unsigned int file=0; file < m_vMovieInfo.size() ;file++) + { + if( /*isFiltered(m_vMovieInfo[file]) == false &&*/ + isParentalLock(m_vMovieInfo[file]) == false) + { + movie_handle = &(m_vMovieInfo[file]); + m_vHandleRecordList.push_back(movie_handle); + } + } + // sort the not filtered files + onSortMovieInfoHandleList(m_vHandleRecordList,MB_INFO_RECORDDATE,MB_DIRECTION_DOWN); + + for( int handle=0; handle < (int) m_vHandleRecordList.size() && handle < m_settings.lastRecordMaxItems ;handle++) + { + for(int row = 0; row < m_settings.lastRecordRowNr ;row++) + { + if ( getMovieInfoItem(*m_vHandleRecordList[handle], m_settings.lastRecordRow[row], &string_item) == false) + { + string_item = "n/a"; + if(m_settings.lastRecordRow[row] == MB_INFO_TITLE) + getMovieInfoItem(*m_vHandleRecordList[handle], MB_INFO_FILENAME, &string_item); + } + m_recordListLines.lineArray[row].push_back(string_item); + } + } + + m_pcLastRecord->setLines(&m_recordListLines); + + m_currentRecordSelection = m_pcLastRecord->getSelectedLine(); + // update selected movie if browser is in the focus + if (m_windowFocus == MB_FOCUS_LAST_RECORD) + { + updateMovieSelection(); + } +} + +void CMovieBrowser::refreshBrowserList(void) //P1 +{ + //TRACE("[mb]->refreshBrowserList \r\n"); + std::string string_item; + + // Initialise and clear list array + m_browserListLines.rows = m_settings.browserRowNr; + for(int row = 0; row < m_settings.browserRowNr; row++) + { + m_browserListLines.lineArray[row].clear(); + m_browserListLines.rowWidth[row] = m_settings.browserRowWidth[row]; + m_browserListLines.lineHeader[row]= g_Locale->getText(m_localizedItemName[m_settings.browserRowItem[row]]); + } + m_vHandleBrowserList.clear(); + + if(m_vMovieInfo.size() <= 0) + { + m_currentBrowserSelection = 0; + m_movieSelectionHandler = NULL; + if(m_pcBrowser != NULL) + m_pcBrowser->setLines(&m_browserListLines);//FIXME last delete test + return; // exit here if nothing else is to do + } + + MI_MOVIE_INFO* movie_handle; + // prepare Browser list for sorting and filtering + for(unsigned int file=0; file < m_vMovieInfo.size(); file++) + { + if( isFiltered(m_vMovieInfo[file]) == false && + isParentalLock(m_vMovieInfo[file]) == false && + (m_settings.browser_serie_mode == 0 || m_vMovieInfo[file].serieName.empty() || m_settings.filter.item == MB_INFO_SERIE) ) + { + movie_handle = &(m_vMovieInfo[file]); + m_vHandleBrowserList.push_back(movie_handle); + } + } + // sort the not filtered files + onSortMovieInfoHandleList(m_vHandleBrowserList,m_settings.sorting.item,MB_DIRECTION_AUTO); + + for(unsigned int handle=0; handle < m_vHandleBrowserList.size() ;handle++) + { + for(int row = 0; row < m_settings.browserRowNr ;row++) + { + if ( getMovieInfoItem(*m_vHandleBrowserList[handle], m_settings.browserRowItem[row], &string_item) == false) + { + string_item = "n/a"; + if(m_settings.browserRowItem[row] == MB_INFO_TITLE) + getMovieInfoItem(*m_vHandleBrowserList[handle], MB_INFO_FILENAME, &string_item); + } + m_browserListLines.lineArray[row].push_back(string_item); + } + } + m_pcBrowser->setLines(&m_browserListLines); + + m_currentBrowserSelection = m_pcBrowser->getSelectedLine(); + // update selected movie if browser is in the focus + if (m_windowFocus == MB_FOCUS_BROWSER) + { + updateMovieSelection(); + } +} + +void CMovieBrowser::refreshBookmarkList(void) // P3 +{ + //TRACE("[mb]->refreshBookmarkList \r\n"); +} + +void CMovieBrowser::refreshTitle(void) +{ + //Paint Text Background + //TRACE("[mb]->refreshTitle : %s\r\n",m_textTitle.c_str()); + m_pcWindow->paintBoxRel(m_cBoxFrame.iX+m_cBoxFrameTitleRel.iX, m_cBoxFrame.iY+ m_cBoxFrameTitleRel.iY, + m_cBoxFrameTitleRel.iWidth, m_cBoxFrameTitleRel.iHeight, TITLE_BACKGROUND_COLOR, ROUND_RADIUS, 1); + + m_pcFontTitle->RenderString(m_cBoxFrame.iX+m_cBoxFrameTitleRel.iX + TEXT_BORDER_WIDTH, m_cBoxFrame.iY+m_cBoxFrameTitleRel.iY + m_cBoxFrameTitleRel.iHeight, m_cBoxFrameTitleRel.iWidth - (TEXT_BORDER_WIDTH << 1), m_textTitle.c_str(), TITLE_FONT_COLOR, 0, true); // UTF-8 +} + +#define ADD_FOOT_HEIGHT 4 +void CMovieBrowser::refreshFoot(void) +{ + //TRACE("[mb]->refreshButtonLine \r\n"); + int color = (CFBWindow::color_t) COL_MENUHEAD; + + std::string filter_text = g_Locale->getText(LOCALE_MOVIEBROWSER_FOOT_FILTER); + filter_text += m_settings.filter.optionString; + std::string sort_text = g_Locale->getText(LOCALE_MOVIEBROWSER_FOOT_SORT); + sort_text += g_Locale->getText(m_localizedItemName[m_settings.sorting.item]); + std::string ok_text = g_Locale->getText(LOCALE_MOVIEBROWSER_FOOT_PLAY); + + // draw the background first + m_pcWindow->paintBoxRel(m_cBoxFrame.iX+m_cBoxFrameFootRel.iX, m_cBoxFrame.iY+ m_cBoxFrameFootRel.iY, + m_cBoxFrameFootRel.iWidth, m_cBoxFrameFootRel.iHeight+ 6, + (CFBWindow::color_t)COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2); + + int width = m_cBoxFrameFootRel.iWidth>>2; + + int xpos1 = m_cBoxFrameFootRel.iX+10; + int width1 = width; + int xpos2 = xpos1 + width1; + int width2 = width + width; + int xpos4 = xpos2 + width2; + int width4 = width; + //int xpos4 = xpos3 + width3; + //int width4 = width; + + // draw Button blue (filter) + //xpos += ButtonWidth + ButtonSpacing; + // draw yellow (sort) + if (m_settings.gui != MB_GUI_LAST_PLAY && m_settings.gui != MB_GUI_LAST_RECORD) + { + m_pcWindow->paintIcon(NEUTRINO_ICON_BUTTON_RED, m_cBoxFrame.iX+xpos1, m_cBoxFrame.iY+m_cBoxFrameFootRel.iY + (ADD_FOOT_HEIGHT>>1)); + m_pcFontFoot->RenderString(m_cBoxFrame.iX+xpos1 + 20, m_cBoxFrame.iY+m_cBoxFrameFootRel.iY + m_cBoxFrameFootRel.iHeight + 4 , width1-30, sort_text.c_str(), (CFBWindow::color_t)color, 0, true); // UTF-8 + } + + if (m_settings.gui != MB_GUI_LAST_PLAY && m_settings.gui != MB_GUI_LAST_RECORD) + { + m_pcWindow->paintIcon(NEUTRINO_ICON_BUTTON_GREEN, m_cBoxFrame.iX+xpos2, m_cBoxFrame.iY+m_cBoxFrameFootRel.iY + (ADD_FOOT_HEIGHT>>1)); + m_pcFontFoot->RenderString(m_cBoxFrame.iX+ xpos2 + 20, m_cBoxFrame.iY+m_cBoxFrameFootRel.iY + m_cBoxFrameFootRel.iHeight + 4 , width2 -30, filter_text.c_str(), (CFBWindow::color_t)color, 0, true); // UTF-8 + } + //std::string ok_text; + if(m_settings.gui == MB_GUI_FILTER && m_windowFocus == MB_FOCUS_FILTER) + { + ok_text = "select"; + } + else + { + ok_text = g_Locale->getText(LOCALE_MOVIEBROWSER_FOOT_PLAY); + } + m_pcWindow->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, m_cBoxFrame.iX+xpos4, m_cBoxFrame.iY+m_cBoxFrameFootRel.iY + (ADD_FOOT_HEIGHT>>1)); + m_pcFontFoot->RenderString(m_cBoxFrame.iX+xpos4 + 30, m_cBoxFrame.iY+m_cBoxFrameFootRel.iY + m_cBoxFrameFootRel.iHeight + 4 , width4-30, ok_text.c_str(), (CFBWindow::color_t)color, 0, true); // UTF-8 +} + +bool CMovieBrowser::onButtonPress(neutrino_msg_t msg) +{ +// TRACE("[mb]->onButtonPress %d\r\n",msg); + bool result = false; + + result = onButtonPressMainFrame(msg); + if(result == false) + { + // if Main Frame didnot process the button, the focused window may do + switch(m_windowFocus) + { + case MB_FOCUS_BROWSER: + result = onButtonPressBrowserList(msg); + break; + case MB_FOCUS_LAST_PLAY: + result = onButtonPressLastPlayList(msg); + break; + case MB_FOCUS_LAST_RECORD: + result = onButtonPressLastRecordList(msg); + break; + case MB_FOCUS_MOVIE_INFO: + result = onButtonPressMovieInfoList(msg); + break; + case MB_FOCUS_FILTER: + result = onButtonPressFilterList(msg); + break; + default: + break; + } + } + return (result); +} + +bool CMovieBrowser::onButtonPressMainFrame(neutrino_msg_t msg) +{ + //TRACE("[mb]->onButtonPressMainFrame: %d\r\n",msg); + bool result = true; + + if (msg == CRCInput::RC_home) + { + if(m_settings.gui == MB_GUI_FILTER) + onSetGUIWindow(MB_GUI_MOVIE_INFO); + else + result = false; + } + else if (msg == CRCInput::RC_minus) + { + onSetGUIWindowPrev(); + //refreshMovieInfo(); + } + else if (msg == CRCInput::RC_plus) + { + onSetGUIWindowNext(); + //refreshMovieInfo(); + } + else if (msg == CRCInput::RC_green) + { + if(m_settings.gui == MB_GUI_MOVIE_INFO) + onSetGUIWindow(MB_GUI_FILTER); + else if(m_settings.gui == MB_GUI_FILTER) + onSetGUIWindow(MB_GUI_MOVIE_INFO); + // no effect if gui is last play or record + } + else if (msg == CRCInput::RC_yellow) + { + onSetFocusNext(); + } + else if (msg == CRCInput::RC_blue) + { + loadMovies(); + refresh(); + } + else if (msg == CRCInput::RC_red ) + { + if(m_settings.gui != MB_GUI_LAST_PLAY && m_settings.gui != MB_GUI_LAST_RECORD) + { + // sorting is not avialable for last play and record + do + { + if(m_settings.sorting.item + 1 >= MB_INFO_MAX_NUMBER) + m_settings.sorting.item = (MB_INFO_ITEM)0; + else + m_settings.sorting.item = (MB_INFO_ITEM)(m_settings.sorting.item + 1); + }while(sortBy[m_settings.sorting.item] == NULL); + + TRACE("[mb]->new sorting %d,%s\r\n",m_settings.sorting.item,g_Locale->getText(m_localizedItemName[m_settings.sorting.item])); + refreshBrowserList(); + refreshFoot(); + } + } + else if (msg == CRCInput::RC_spkr) + { + if(m_vMovieInfo.size() > 0) + { + if(m_movieSelectionHandler != NULL) + { + onDeleteFile(*m_movieSelectionHandler); + } + } + } + else if (msg == CRCInput::RC_help || msg == CRCInput::RC_info) + { + if(m_movieSelectionHandler != NULL) + { + m_movieInfo.showMovieInfo(*m_movieSelectionHandler); + //m_movieInfo.printDebugMovieInfo(*m_movieSelectionHandler); //FIXME + refresh(); + } + } + else if (msg == CRCInput::RC_setup) + { + if(m_movieSelectionHandler != NULL) + showMenu(m_movieSelectionHandler); + } + else if (msg == CRCInput::RC_text || msg == CRCInput::RC_radio) { + if(ShowMsgUTF (LOCALE_MESSAGEBOX_INFO, msg == CRCInput::RC_radio ? "Copy jumps from movie to new file ?" : "Copy jumps from movie to new files ?", CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo) == CMessageBox::mbrYes) { + CHintBox * hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, "Coping, please wait"); + hintBox->paint(); + sleep(1); + hintBox->hide(); + delete hintBox; + m_pcWindow->paintBackground(); // clear screen + off64_t res = copy_movie(m_movieSelectionHandler, &m_movieInfo, msg == CRCInput::RC_radio); + //g_RCInput->clearRCMsg(); + if(res == 0) + ShowMsgUTF(LOCALE_MESSAGEBOX_ERROR, "Copy failed, is there jump bookmarks ? Or check free space.", CMessageBox::mbrCancel, CMessageBox::mbCancel, "error.raw"); + else + loadMovies(); + refresh(); + } + } + else if (msg == CRCInput::RC_audio) { +#if 0 + if((m_movieSelectionHandler == playing_info) && (NeutrinoMessages::mode_ts == CNeutrinoApp::getInstance()->getMode())) + ShowMsgUTF(LOCALE_MESSAGEBOX_ERROR, "Impossible to cut playing movie.", CMessageBox::mbrCancel, CMessageBox::mbCancel, "error.raw"); + else +#endif + if(ShowMsgUTF (LOCALE_MESSAGEBOX_INFO, "Cut jumps from movie ?", CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo) == CMessageBox::mbrYes) { + CHintBox * hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, "Cutting, please wait"); + hintBox->paint(); + sleep(1); + hintBox->hide(); + delete hintBox; + m_pcWindow->paintBackground(); // clear screen + off64_t res = cut_movie(m_movieSelectionHandler, &m_movieInfo); + //g_RCInput->clearRCMsg(); + if(res == 0) + ShowMsgUTF(LOCALE_MESSAGEBOX_ERROR, "Cut failed, is there jump bookmarks ? Or check free space.", CMessageBox::mbrCancel, CMessageBox::mbCancel, "error.raw"); + else { + loadMovies(); + } + refresh(); + } + } + else if (msg == CRCInput::RC_games) { + if((m_movieSelectionHandler == playing_info) && (NeutrinoMessages::mode_ts == CNeutrinoApp::getInstance()->getMode())) + ShowMsgUTF(LOCALE_MESSAGEBOX_ERROR, "Impossible to truncate playing movie.", CMessageBox::mbrCancel, CMessageBox::mbCancel, "error.raw"); + else if(m_movieSelectionHandler->bookmarks.end == 0) + ShowMsgUTF(LOCALE_MESSAGEBOX_ERROR, "No End bookmark defined!", CMessageBox::mbrCancel, CMessageBox::mbCancel, "error.raw"); + else { + if(ShowMsgUTF (LOCALE_MESSAGEBOX_INFO, "Truncate movie ?", CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo) == CMessageBox::mbrYes) { + CHintBox * hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, "Truncating, please wait"); + hintBox->paint(); + off64_t res = truncate_movie(m_movieSelectionHandler); + hintBox->hide(); + delete hintBox; + g_RCInput->clearRCMsg(); + if(res == 0) + ShowMsgUTF(LOCALE_MESSAGEBOX_ERROR, "Truncate failed.", CMessageBox::mbrCancel, CMessageBox::mbCancel, "error.raw"); + else { +//printf("New movie info: size %lld len %d\n", res, m_movieSelectionHandler->bookmarks.end/60); + m_movieInfo.saveMovieInfo( *m_movieSelectionHandler); + loadMovies(); + } + refresh(); + } + } + } else if (msg == CRCInput::RC_topleft) { + if (m_movieSelectionHandler != NULL) { + if(ShowMsgUTF (LOCALE_MESSAGEBOX_INFO, "Remove screenshot ?", CMessageBox::mbrNo, CMessageBox:: mbYes | CMessageBox::mbNo) == CMessageBox::mbrYes) { + std::string fname = m_movieSelectionHandler->file.Name; + strReplace(fname, ".ts", ".bmp"); + unlink(fname.c_str()); + refresh(); + } + } + } + else + { + //TRACE("[mb]->onButtonPressMainFrame none\r\n"); + result = false; + } + + return (result); +} + +bool CMovieBrowser::onButtonPressBrowserList(neutrino_msg_t msg) +{ + //TRACE("[mb]->onButtonPressBrowserList %d\r\n",msg); + bool result = true; + + if(msg==CRCInput::RC_up) + { + m_pcBrowser->scrollLineUp(1); + } + else if (msg == CRCInput::RC_down) + { + m_pcBrowser->scrollLineDown(1); + } + else if (msg == CRCInput::RC_page_up) + { + m_pcBrowser->scrollPageUp(1); + } + else if (msg == CRCInput::RC_page_down) + { + m_pcBrowser->scrollPageDown(1); + } + else if (msg == CRCInput::RC_left) + { + m_pcBrowser->scrollPageUp(1); + } + else if (msg == CRCInput::RC_right) + { + m_pcBrowser->scrollPageDown(1); + } + else + { + // default + result = false; + } + if(result == true) + updateMovieSelection(); + + return (result); +} + +bool CMovieBrowser::onButtonPressLastPlayList(neutrino_msg_t msg) +{ + //TRACE("[mb]->onButtonPressLastPlayList %d\r\n",msg); + bool result = true; + + if(msg==CRCInput::RC_up) + { + m_pcLastPlay->scrollLineUp(1); + } + else if (msg == CRCInput::RC_down) + { + m_pcLastPlay->scrollLineDown(1); + } + else if (msg == CRCInput::RC_left) + { + m_pcLastPlay->scrollPageUp(1); + } + else if (msg == CRCInput::RC_right) + { + m_pcLastPlay->scrollPageDown(1); + } + else + { + // default + result = false; + } + if(result == true) + updateMovieSelection(); + + return (result); +} + +bool CMovieBrowser::onButtonPressLastRecordList(neutrino_msg_t msg) +{ + //TRACE("[mb]->onButtonPressLastRecordList %d\r\n",msg); + bool result = true; + + if(msg==CRCInput::RC_up) + { + m_pcLastRecord->scrollLineUp(1); + } + else if (msg == CRCInput::RC_down) + { + m_pcLastRecord->scrollLineDown(1); + } + else if (msg == CRCInput::RC_left) + { + m_pcLastRecord->scrollPageUp(1); + } + else if (msg == CRCInput::RC_right) + { + m_pcLastRecord->scrollPageDown(1); + } + else + { + // default + result = false; + } + + if(result == true) + updateMovieSelection(); + + return (result); +} + +bool CMovieBrowser::onButtonPressBookmarkList(neutrino_msg_t msg) +{ + //TRACE("[mb]->onButtonPressBookmarkList %d\r\n",msg); + bool result = true; + + result = false; + return (result); +} + +bool CMovieBrowser::onButtonPressFilterList(neutrino_msg_t msg) +{ + //TRACE("[mb]->onButtonPressFilterList %d,%d\r\n",msg,m_settings.filter.item); + bool result = true; + + if(msg==CRCInput::RC_up) + { + m_pcFilter->scrollLineUp(1); + } + else if (msg == CRCInput::RC_down) + { + m_pcFilter->scrollLineDown(1); + } + else if (msg == CRCInput::RC_page_up) + { + m_pcFilter->scrollPageUp(1); + } + else if (msg == CRCInput::RC_page_down) + { + m_pcFilter->scrollPageDown(1); + } + else if (msg == CRCInput::RC_ok) + { + int selected_line = m_pcFilter->getSelectedLine(); + if(m_settings.filter.item == MB_INFO_MAX_NUMBER) + { + if(selected_line == 0) m_settings.filter.item = MB_INFO_MAJOR_GENRE; + if(selected_line == 1) m_settings.filter.item = MB_INFO_INFO1; + if(selected_line == 2) m_settings.filter.item = MB_INFO_FILEPATH; + if(selected_line == 3) m_settings.filter.item = MB_INFO_SERIE; + refreshFilterList(); + m_pcFilter->setSelectedLine(0); + } + else + { + if(selected_line == 0) + { + m_settings.filter.item = MB_INFO_MAX_NUMBER; + m_settings.filter.optionString = ""; + m_settings.filter.optionVar = 0; + refreshFilterList(); + m_pcFilter->setSelectedLine(0); + refreshBrowserList(); + refreshLastPlayList(); + refreshLastRecordList(); + refreshFoot(); + } + else + { + updateFilterSelection(); + } + } + } + else if (msg == CRCInput::RC_left) + { + m_pcFilter->scrollPageUp(1); + } + else if (msg == CRCInput::RC_right) + { + m_pcFilter->scrollPageDown(1); + } + else + { + // default + result = false; + } + + return (result); +} + +bool CMovieBrowser::onButtonPressMovieInfoList(neutrino_msg_t msg) +{ +// TRACE("[mb]->onButtonPressEPGInfoList %d\r\n",msg); + bool result = true; + + if(msg == CRCInput::RC_up) + { + m_pcInfo->scrollPageUp(1); + } + else if (msg == CRCInput::RC_down) + { + m_pcInfo->scrollPageDown(1); + } + else + { + // default + result = false; + } + + return (result); +} + +void CMovieBrowser::onDeleteFile(MI_MOVIE_INFO& movieSelectionHandler) +{ + //TRACE( "[onDeleteFile] "); + int test= movieSelectionHandler.file.Name.find(".ts"); + if(test == -1) + { + // not a TS file, return!!!!! + TRACE( "show_ts_info: not a TS file "); + } + else + { + std::string msg = g_Locale->getText(LOCALE_FILEBROWSER_DODELETE1); + msg += "\r\n "; + if (movieSelectionHandler.file.Name.length() > 40) + { + msg += movieSelectionHandler.file.Name.substr(0,40); + msg += "..."; + } + else + msg += movieSelectionHandler.file.Name; + + msg += "\r\n "; + msg += g_Locale->getText(LOCALE_FILEBROWSER_DODELETE2); + if (ShowMsgUTF(LOCALE_FILEBROWSER_DELETE, msg, CMessageBox::mbrNo, CMessageBox::mbYes|CMessageBox::mbNo)==CMessageBox::mbrYes) + { + delFile(movieSelectionHandler.file); + +#if 1 + int i = 1; + char newpath[1024]; + do { + sprintf(newpath, "%s.%03d", movieSelectionHandler.file.Name.c_str(), i); + if(access(newpath, R_OK)) { + break; + } else { + unlink(newpath); + TRACE(" delete file: %s\r\n", newpath); + } + i++; + } while(1); + std::string fname = movieSelectionHandler.file.Name; + strReplace(fname, ".ts", ".bmp"); + unlink(fname.c_str()); +#endif + + CFile file_xml = movieSelectionHandler.file; + if(m_movieInfo.convertTs2XmlName(&file_xml.Name) == true) + { + delFile(file_xml); + } + + m_vMovieInfo.erase( (std::vector::iterator)&movieSelectionHandler); + TRACE("List size: %d\n", m_vMovieInfo.size()); + //if(m_vMovieInfo.size() == 0) fileInfoStale(); + //if(m_vMovieInfo.size() == 0) onSetGUIWindow(m_settings.gui); + updateSerienames(); + refreshBrowserList(); + refreshLastPlayList(); + refreshLastRecordList(); + refreshMovieInfo(); + + //loadMovies(); // //TODO we might remove the handle from the handle list only, to avoid reload ..... + refresh(); + } + } +} + +void CMovieBrowser::onSetGUIWindow(MB_GUI gui) +{ + m_settings.gui = gui; + + if(gui == MB_GUI_MOVIE_INFO) + { + TRACE("[mb] browser info\r\n"); + // Paint these frames ... + m_showMovieInfo = true; + m_showBrowserFiles = true; + + // ... and hide these frames + m_showLastRecordFiles = false; + m_showLastPlayFiles = false; + m_showFilter = false; + + m_pcLastPlay->hide(); + m_pcLastRecord->hide(); + m_pcFilter->hide(); + m_pcBrowser->paint(); + onSetFocus(MB_FOCUS_BROWSER); + m_pcInfo->paint(); + refreshMovieInfo(); + } + else if(gui == MB_GUI_LAST_PLAY) + { + TRACE("[mb] last play \r\n"); + // Paint these frames ... + m_showLastRecordFiles = true; + m_showLastPlayFiles = true; + m_showMovieInfo = true; + + // ... and hide these frames + m_showBrowserFiles = false; + m_showFilter = false; + + m_pcBrowser->hide(); + m_pcFilter->hide(); + m_pcLastRecord->paint(); + m_pcLastPlay->paint(); + + onSetFocus(MB_FOCUS_LAST_PLAY); + m_pcInfo->paint(); + refreshMovieInfo(); + } + else if(gui == MB_GUI_LAST_RECORD) + { + TRACE("[mb] last record \r\n"); + // Paint these frames ... + m_showLastRecordFiles = true; + m_showLastPlayFiles = true; + m_showMovieInfo = true; + + // ... and hide these frames + m_showBrowserFiles = false; + m_showFilter = false; + + m_pcBrowser->hide(); + m_pcFilter->hide(); + m_pcLastRecord->paint(); + m_pcLastPlay->paint(); + + onSetFocus(MB_FOCUS_LAST_RECORD); + m_pcInfo->paint(); + refreshMovieInfo(); + } + else if(gui == MB_GUI_FILTER) + { + TRACE("[mb] filter \r\n"); + // Paint these frames ... + m_showFilter = true; + // ... and hide these frames + m_showMovieInfo = false; + m_pcInfo->hide(); + m_pcFilter->paint(); + + onSetFocus(MB_FOCUS_FILTER); + } +} + +void CMovieBrowser::onSetGUIWindowNext(void) +{ + if(m_settings.gui == MB_GUI_MOVIE_INFO ) + { + onSetGUIWindow(MB_GUI_LAST_PLAY); + } + else if(m_settings.gui == MB_GUI_LAST_PLAY) + { + onSetGUIWindow(MB_GUI_LAST_RECORD); + } + else + { + onSetGUIWindow(MB_GUI_MOVIE_INFO); + } +} + +void CMovieBrowser::onSetGUIWindowPrev(void) +{ + if(m_settings.gui == MB_GUI_MOVIE_INFO ) + { + onSetGUIWindow(MB_GUI_LAST_RECORD); + } + else if(m_settings.gui == MB_GUI_LAST_RECORD) + { + onSetGUIWindow(MB_GUI_LAST_PLAY); + } + else + { + onSetGUIWindow(MB_GUI_MOVIE_INFO); + } +} + +void CMovieBrowser::onSetFocus(MB_FOCUS new_focus) +{ + //TRACE("[mb]->onSetFocus %d \r\n",new_focus); + m_windowFocus = new_focus; + if(m_windowFocus == MB_FOCUS_BROWSER) + { + m_pcBrowser->showSelection(true); + m_pcLastRecord->showSelection(false); + m_pcLastPlay->showSelection(false); + m_pcFilter->showSelection(false); + //m_pcInfo->showSelection(false); + } + else if(m_windowFocus == MB_FOCUS_LAST_PLAY) + { + m_pcBrowser->showSelection(false); + m_pcLastRecord->showSelection(false); + m_pcLastPlay->showSelection(true); + m_pcFilter->showSelection(false); + //m_pcInfo->showSelection(false); + } + else if(m_windowFocus == MB_FOCUS_LAST_RECORD) + { + m_pcBrowser->showSelection(false); + m_pcLastRecord->showSelection(true); + m_pcLastPlay->showSelection(false); + m_pcFilter->showSelection(false); + //m_pcInfo->showSelection(false); + } + else if(m_windowFocus == MB_FOCUS_MOVIE_INFO) + { + m_pcBrowser->showSelection(false); + m_pcLastRecord->showSelection(false); + m_pcLastPlay->showSelection(false); + m_pcFilter->showSelection(false); + //m_pcInfo->showSelection(true); + } + else if(m_windowFocus == MB_FOCUS_FILTER) + { + m_pcBrowser->showSelection(false); + m_pcLastRecord->showSelection(false); + m_pcLastPlay->showSelection(false); + m_pcFilter->showSelection(true); + //m_pcInfo->showSelection(false); + } + updateMovieSelection(); + refreshFoot(); +} + +void CMovieBrowser::onSetFocusNext(void) +{ + //TRACE("[mb]->onSetFocusNext \r\n"); + + if(m_settings.gui == MB_GUI_FILTER) + { + if(m_windowFocus == MB_FOCUS_BROWSER) + { + TRACE("[mb] MB_FOCUS_FILTER\r\n"); + onSetFocus(MB_FOCUS_FILTER); + } + else + { + TRACE("[mb] MB_FOCUS_BROWSER\r\n"); + onSetFocus(MB_FOCUS_BROWSER); + } + } + else if(m_settings.gui == MB_GUI_MOVIE_INFO) + { + if(m_windowFocus == MB_FOCUS_BROWSER) + { + TRACE("[mb] MB_FOCUS_MOVIE_INFO\r\n"); + onSetFocus(MB_FOCUS_MOVIE_INFO); + m_windowFocus = MB_FOCUS_MOVIE_INFO; + } + else + { + TRACE("[mb] MB_FOCUS_BROWSER\r\n"); + onSetFocus(MB_FOCUS_BROWSER); + } + } + else if(m_settings.gui == MB_GUI_LAST_PLAY) + { + if(m_windowFocus == MB_FOCUS_MOVIE_INFO) + { + onSetFocus(MB_FOCUS_LAST_PLAY); + } + else if(m_windowFocus == MB_FOCUS_LAST_PLAY) + { + onSetFocus(MB_FOCUS_MOVIE_INFO); + } + } + else if(m_settings.gui == MB_GUI_LAST_RECORD) + { + if(m_windowFocus == MB_FOCUS_MOVIE_INFO) + { + onSetFocus(MB_FOCUS_LAST_RECORD); + } + else if(m_windowFocus == MB_FOCUS_LAST_RECORD) + { + onSetFocus(MB_FOCUS_MOVIE_INFO); + } + } +} + +bool CMovieBrowser::onSortMovieInfoHandleList(std::vector& handle_list, MB_INFO_ITEM sort_item, MB_DIRECTION direction) +{ + //TRACE("sort: %d\r\n",direction); + if(handle_list.size() <= 0) + return (false); // nothing to sort, return immedately + if(sortBy[sort_item] == NULL) + return (false); + + if(direction == MB_DIRECTION_AUTO) + { + if( sort_item == MB_INFO_QUALITY || + sort_item == MB_INFO_PARENTAL_LOCKAGE || + sort_item == MB_INFO_PREVPLAYDATE || + sort_item == MB_INFO_RECORDDATE || + sort_item == MB_INFO_PRODDATE || + sort_item == MB_INFO_SIZE) + { + sortDirection = 1; + } + else + { + sortDirection = 0; + } + } + else if(direction == MB_DIRECTION_UP) + { + sortDirection = 0; + } + else + { + sortDirection = 1; + } + + //TRACE("sort: %d\r\n",sortDirection); + sort(handle_list.begin(), handle_list.end(), sortBy[sort_item]); + + return (true); +} + +void CMovieBrowser::updateDir(void) +{ + m_dir.clear(); +#if 0 + // check if there is a movie dir and if we should use it + if(g_settings.network_nfs_moviedir[0] != 0 ) + { + std::string name = g_settings.network_nfs_moviedir; + addDir(name,&m_settings.storageDirMovieUsed); + } +#endif + // check if there is a record dir and if we should use it + if(g_settings.network_nfs_recordingdir[0] != 0 ) + { + std::string name = g_settings.network_nfs_recordingdir; + addDir(name,&m_settings.storageDirRecUsed); + } + + for(int i = 0; i < MB_MAX_DIRS; i++) + { + if(!m_settings.storageDir[i].empty()) + addDir(m_settings.storageDir[i],&m_settings.storageDirUsed[i]); + } +} + +void CMovieBrowser::loadAllTsFileNamesFromStorage(void) +{ + //TRACE("[mb]->loadAllTsFileNamesFromStorage \r\n"); + bool result; + int i,size; + + m_movieSelectionHandler = NULL; + m_dirNames.clear(); + m_vMovieInfo.clear(); + + updateDir(); + + size = m_dir.size(); + for(i=0; i < size;i++) + { + if(*m_dir[i].used == true ) + result = loadTsFileNamesFromDir(m_dir[i].name); + } + + TRACE("[mb] Dir%d, Files:%d \r\n",m_dirNames.size(),m_vMovieInfo.size()); + /* + if(m_vMovieInfo.size() == 0) + { + std::string msg = g_Locale->getText(LOCALE_MOVIEBROWSER_ERROR_NO_MOVIES); + DisplayErrorMessage(msg.c_str()); + } + */ +} + +/************************************************************************ +Note: this function is used recursive, do not add any return within the body due to the recursive counter +************************************************************************/ +bool CMovieBrowser::loadTsFileNamesFromDir(const std::string & dirname) +{ + //TRACE("[mb]->loadTsFileNamesFromDir %s\r\n",dirname.c_str()); + + static int recursive_counter = 0; // recursive counter to be used to avoid hanging + bool result = false; + int file_found_in_dir = false; + + if (recursive_counter > 10) + { + TRACE("[mb]loadTsFileNamesFromDir: return->recoursive error\r\n"); + return (false); // do not go deeper than 10 directories + } + + /* check if directory was already searched once */ + int size = m_dirNames.size(); + for(int i = 0; i < size; i++) + { + if(strcmp(m_dirNames[i].c_str(),dirname.c_str()) == 0) + { + // string is identical to previous one + TRACE("[mb]Dir already in list: %s\r\n",dirname.c_str()); + return (false); + } + } + /* !!!!!! no return statement within the body after here !!!!*/ + recursive_counter++; + + CFileList flist; + if(readDir(dirname, &flist) == true) + { + MI_MOVIE_INFO movieInfo; + //m_movieInfo.clearMovieInfo(&movieInfo); // refresh structure + for(unsigned int i = 0; i < flist.size(); i++) + { + if( S_ISDIR(flist[i].Mode)) + { + flist[i].Name += '/'; + //TRACE("[mb] Dir: '%s'\r\n",movieInfo.file.Name.c_str()); + loadTsFileNamesFromDir(flist[i].Name); + } + else + { + int test=flist[i].getFileName().find(".ts"); + if( test == -1) + { + //TRACE("[mb] other file: '%s'\r\n",movieInfo.file.Name.c_str()); + } + else + { + m_movieInfo.clearMovieInfo(&movieInfo); // refresh structure + movieInfo.file.Name = flist[i].Name; + if(m_movieInfo.loadMovieInfo(&movieInfo)) { //FIXME atm we show only ts+xml (records) here + movieInfo.file.Mode = flist[i].Mode; + //movieInfo.file.Size = flist[i].Size; + movieInfo.file.Size = get_full_len((char *)flist[i].Name.c_str()); + movieInfo.file.Time = flist[i].Time; + //TRACE(" N:%s,s:%d,t:%d\r\n",movieInfo.file.getFileName().c_str(),movieInfo.file.Size,movieInfo.file.Time); + //TRACE(" N:%s,s:%d\r\n",movieInfo.file.getFileName().c_str(),movieInfo.file.Size>>20); + //TRACE(" s:%d\r\n",movieInfo.file.getFileName().c_str(),movieInfo.file.Size); + //TRACE(" s:%llu\r\n",movieInfo.file.getFileName().c_str(),movieInfo.file.Size); + if(file_found_in_dir == false) + { + // first file in directory found, add directory to list + m_dirNames.push_back(dirname); + file_found_in_dir = true; + //TRACE("[mb] new dir: :%s\r\n",dirname); + } + movieInfo.dirItNr = m_dirNames.size()-1; + m_vMovieInfo.push_back(movieInfo); + } + } + } + } + result = true; + } + + recursive_counter--; + return (result); +} + +bool CMovieBrowser::readDir(const std::string & dirname, CFileList* flist) +{ + bool result = false; + if (strncmp(dirname.c_str(), VLC_URI, strlen(VLC_URI)) == 0) + { + result = readDir_vlc(dirname, flist); + } + else + { + result = readDir_std(dirname, flist); + } + return(result); +} + +bool CMovieBrowser::readDir_vlc(const std::string & dirname, CFileList* flist) +{ + return false; +} + +bool CMovieBrowser::readDir_std(const std::string & dirname, CFileList* flist) +{ + bool result = true; + //TRACE("readDir_std %s\n",dirname.c_str()); + stat_struct statbuf; + dirent_struct **namelist; + int n; + + n = my_scandir(dirname.c_str(), &namelist, 0, my_alphasort); + if (n < 0) + { + perror(("[mb] scandir: "+dirname).c_str()); + return false; + } + CFile file; + for(int i = 0; i < n;i++) + { + if(namelist[i]->d_name[0] != '.') + { + file.Name = dirname; + file.Name += namelist[i]->d_name; + +// printf("file.Name: '%s', getFileName: '%s' getPath: '%s'\n",file.Name.c_str(),file.getFileName().c_str(),file.getPath().c_str()); + if(my_stat((file.Name).c_str(),&statbuf) != 0) + perror("stat error"); + else + { + file.Mode = statbuf.st_mode; + file.Time = statbuf.st_mtime; + file.Size = statbuf.st_size; + flist->push_back(file); + } + } + free(namelist[i]); + } + + free(namelist); + + return(result); +} + +bool CMovieBrowser::delFile(CFile& file) +{ + bool result = false; + //only std supported yet + if(1) + { + result = delFile_std(file); + } + else + { + result = delFile_vlc(file); + } + return(result); +} + +bool CMovieBrowser::delFile_vlc(CFile& file) +{ + bool result = false; + return(result); +} + +bool CMovieBrowser::delFile_std(CFile& file) +{ + bool result = true; + unlink(file.Name.c_str()); // fix: use full path + TRACE(" delete file: %s\r\n",file.Name.c_str()); + return(result); +} + +void CMovieBrowser::updateMovieSelection(void) +{ + //TRACE("[mb]->updateMovieSelection %d\r\n",m_windowFocus); + if (m_vMovieInfo.size() == 0) return; + bool new_selection = false; + + unsigned int old_movie_selection; + if(m_windowFocus == MB_FOCUS_BROWSER) + { + if(m_vHandleBrowserList.size() == 0) + { + // There are no elements in the Filebrowser, clear all handles + m_currentBrowserSelection = 0; + m_movieSelectionHandler = NULL; + new_selection = true; + } + else + { + old_movie_selection = m_currentBrowserSelection; + m_currentBrowserSelection = m_pcBrowser->getSelectedLine(); + //TRACE(" sel1:%d\r\n",m_currentBrowserSelection); + if(m_currentBrowserSelection != old_movie_selection) + new_selection = true; + + if(m_currentBrowserSelection < m_vHandleBrowserList.size()) + m_movieSelectionHandler = m_vHandleBrowserList[m_currentBrowserSelection]; + } + } + else if(m_windowFocus == MB_FOCUS_LAST_PLAY) + { + if(m_vHandlePlayList.size() == 0) + { + // There are no elements in the Filebrowser, clear all handles + m_currentPlaySelection = 0; + m_movieSelectionHandler = NULL; + new_selection = true; + } + else + { + old_movie_selection = m_currentPlaySelection; + m_currentPlaySelection = m_pcLastPlay->getSelectedLine(); + //TRACE(" sel2:%d\r\n",m_currentPlaySelection); + if(m_currentPlaySelection != old_movie_selection) + new_selection = true; + + if(m_currentPlaySelection < m_vHandlePlayList.size()) + m_movieSelectionHandler = m_vHandlePlayList[m_currentPlaySelection]; + } + } + else if(m_windowFocus == MB_FOCUS_LAST_RECORD) + { + if(m_vHandleRecordList.size() == 0) + { + // There are no elements in the Filebrowser, clear all handles + m_currentRecordSelection = 0; + m_movieSelectionHandler = NULL; + new_selection = true; + } + else + { + old_movie_selection = m_currentRecordSelection; + m_currentRecordSelection = m_pcLastRecord->getSelectedLine(); + //TRACE(" sel3:%d\r\n",m_currentRecordSelection); + if(m_currentRecordSelection != old_movie_selection) + new_selection = true; + + if(m_currentRecordSelection < m_vHandleRecordList.size()) + m_movieSelectionHandler = m_vHandleRecordList[m_currentRecordSelection]; + } + } + + if(new_selection == true) + { + //TRACE("new\r\n"); + refreshMovieInfo(); + refreshLCD(); + } + //TRACE("\r\n"); +} + +void CMovieBrowser::updateFilterSelection(void) +{ + //TRACE("[mb]->updateFilterSelection \r\n"); + if(m_FilterLines.lineArray[0].size() == 0) return; + + bool result = true; + int selected_line = m_pcFilter->getSelectedLine(); + if(selected_line > 0) + selected_line--; + + if(m_settings.filter.item == MB_INFO_FILEPATH) + { + m_settings.filter.optionString = m_FilterLines.lineArray[0][selected_line+1]; + m_settings.filter.optionVar = selected_line; + } + else if(m_settings.filter.item == MB_INFO_INFO1) + { + m_settings.filter.optionString = m_FilterLines.lineArray[0][selected_line+1]; + } + else if(m_settings.filter.item == MB_INFO_MAJOR_GENRE) + { + m_settings.filter.optionString = g_Locale->getText(GENRE_ALL[selected_line].value); + m_settings.filter.optionVar = GENRE_ALL[selected_line].key; + } + else if(m_settings.filter.item == MB_INFO_SERIE) + { + m_settings.filter.optionString = m_FilterLines.lineArray[0][selected_line+1]; + } + else + { + result = false; + } + if(result == true) + { + refreshBrowserList(); + refreshLastPlayList(); + refreshLastRecordList(); + refreshFoot(); + } +} + +bool CMovieBrowser::addDir(std::string& dirname, int* used) +{ + if(dirname.empty()) return false; + if(dirname == "/") return false; + + MB_DIR newdir; + newdir.name = dirname; + + if(newdir.name.rfind('/') != newdir.name.length()-1 || + newdir.name.length() == 0 || + newdir.name == VLC_URI) + { + newdir.name += '/'; + } + + int size = m_dir.size(); + for(int i = 0; i < size; i++) + { + if(strcmp(m_dir[i].name.c_str(),newdir.name.c_str()) == 0) + { + // string is identical to previous one + TRACE("[mb] Dir already in list: %s\r\n",newdir.name.c_str()); + return (false); + } + } + TRACE("[mb] new Dir: %s\r\n",newdir.name.c_str()); + newdir.used = used; + m_dir.push_back(newdir); + if(*used == true) + { + m_file_info_stale = true; // we got a new Dir, search again for all movies next time + m_seriename_stale = true; + } + return (true); +} + +void CMovieBrowser::loadMovies(void) +{ + time_t time_start = time(NULL); + clock_t clock_start = clock()/10000; // CLOCKS_PER_SECOND + //clock_t clock_prev = clock_start; + clock_t clock_act = clock_start; + + TRACE("[mb] loadMovies: \n"); + + CHintBox loadBox(LOCALE_MOVIEBROWSER_HEAD,g_Locale->getText(LOCALE_MOVIEBROWSER_SCAN_FOR_MOVIES)); + loadBox.paint(); + +//clock_act = clock()/10000;TRACE("[mb] *1: time %9ld clock %6ld dclock %6ld*\n",(long)time(NULL),clock_act,clock_act - clock_prev);clock_prev = clock_act; + loadAllTsFileNamesFromStorage(); // P1 +//clock_act = clock()/10000;TRACE("[mb] *2: time %9ld clock %6ld dclock %6ld*\n",(long)time(NULL),clock_act,clock_act - clock_prev);clock_prev = clock_act; + //loadAllMovieInfo(); // P1 +//clock_act = clock()/10000;TRACE("[mb] *3: time %9ld clock %6ld dclock %6ld*\n",(long)time(NULL),clock_act,clock_act - clock_prev);clock_prev = clock_act; + m_file_info_stale = false; + m_seriename_stale = true; // we reloded the movie info, so make sure the other list are updated later on as well + updateSerienames(); +//clock_act = clock()/10000;TRACE("[mb] *4: time %9ld clock %6ld dclock %6ld*\n",(long)time(NULL),clock_act,clock_act - clock_prev);clock_prev = clock_act; + if(m_settings.serie_auto_create == 1) + { + autoFindSerie(); + } + + loadBox.hide(); + +//clock_act = clock()/10000;TRACE("[mb] *5: time %9ld clock %6ld dclock %6ld*\n",(long)time(NULL),clock_act,clock_act - clock_prev);clock_prev = clock_act; + refreshBrowserList(); +//clock_act = clock()/10000;TRACE("[mb] *6: time %9ld clock %6ld dclock %6ld*\n",(long)time(NULL),clock_act,clock_act - clock_prev);clock_prev = clock_act; + refreshLastPlayList(); + refreshLastRecordList(); + refreshFilterList(); + refreshMovieInfo(); // is done by refreshBrowserList if needed +//clock_act = clock()/10000;TRACE("[mb] *7: time %9ld clock %6ld dclock %6ld*\n",(long)time(NULL),clock_act,clock_act - clock_prev);clock_prev = clock_act; +TRACE("[mb] ***Total:time %ld clock %ld***\n",(time(NULL)-time_start), clock_act-clock_start); +} + +void CMovieBrowser::loadAllMovieInfo(void) +{ + //TRACE("[mb]->loadAllMovieInfo \r\n"); + + for(unsigned int i=0; i < m_vMovieInfo.size();i++) + { + m_movieInfo.loadMovieInfo( &(m_vMovieInfo[i])); + } +} + +void CMovieBrowser::showHelp(void) +{ + CMovieHelp help; + help.exec(NULL,NULL); +} + +#define MAX_STRING 30 +void CMovieBrowser::showMovieInfoMenu(MI_MOVIE_INFO* movie_info) +{ + unsigned int i = 0; + + /********************************************************************/ + /** MovieInfo menu ******************************************************/ + + /********************************************************************/ + /** bookmark ******************************************************/ + CStringInput* pBookNameInput[MAX_NUMBER_OF_BOOKMARK_ITEMS]; + CIntInput* pBookPosIntInput[MAX_NUMBER_OF_BOOKMARK_ITEMS]; + CIntInput* pBookTypeIntInput[MAX_NUMBER_OF_BOOKMARK_ITEMS]; + CMenuWidget* pBookItemMenu[MAX_NUMBER_OF_BOOKMARK_ITEMS]; + + CIntInput bookStartIntInput (LOCALE_MOVIEBROWSER_EDIT_BOOK, (int&)movie_info->bookmarks.start, 5, LOCALE_MOVIEBROWSER_EDIT_BOOK_POS_INFO1, LOCALE_MOVIEBROWSER_EDIT_BOOK_POS_INFO2); + CIntInput bookLastIntInput (LOCALE_MOVIEBROWSER_EDIT_BOOK, (int&)movie_info->bookmarks.lastPlayStop, 5, LOCALE_MOVIEBROWSER_EDIT_BOOK_POS_INFO1, LOCALE_MOVIEBROWSER_EDIT_BOOK_POS_INFO2); + CIntInput bookEndIntInput (LOCALE_MOVIEBROWSER_EDIT_BOOK, (int&)movie_info->bookmarks.end, 5, LOCALE_MOVIEBROWSER_EDIT_BOOK_POS_INFO1, LOCALE_MOVIEBROWSER_EDIT_BOOK_POS_INFO2); + + CMenuWidget bookmarkMenu (LOCALE_MOVIEBROWSER_BOOK_HEAD , "streaming.raw"); + + bookmarkMenu.addItem(GenericMenuSeparator); + bookmarkMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_CLEAR_ALL, true, NULL, this, "book_clear_all",CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE)); + bookmarkMenu.addItem(GenericMenuSeparatorLine); + bookmarkMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIESTART, true, bookStartIntInput.getValue(), &bookStartIntInput)); + bookmarkMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIEEND, true, bookLastIntInput.getValue(), &bookLastIntInput)); + bookmarkMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_LASTMOVIESTOP, true, bookEndIntInput.getValue(), &bookEndIntInput)); + bookmarkMenu.addItem(GenericMenuSeparatorLine); + + for(int i =0 ; i < MI_MOVIE_BOOK_USER_MAX && i < MAX_NUMBER_OF_BOOKMARK_ITEMS; i++ ) + { + pBookNameInput[i] = new CStringInput (LOCALE_MOVIEBROWSER_EDIT_BOOK, &movie_info->bookmarks.user[i].name, 20, LOCALE_MOVIEBROWSER_EDIT_BOOK_NAME_INFO1, LOCALE_MOVIEBROWSER_EDIT_BOOK_NAME_INFO2, "abcdefghijklmnopqrstuvwxyz0123456789-.: "); + pBookPosIntInput[i] = new CIntInput (LOCALE_MOVIEBROWSER_EDIT_BOOK, (int&) movie_info->bookmarks.user[i].pos, 20, LOCALE_MOVIEBROWSER_EDIT_BOOK_POS_INFO1, LOCALE_MOVIEBROWSER_EDIT_BOOK_POS_INFO2); + pBookTypeIntInput[i] = new CIntInput (LOCALE_MOVIEBROWSER_EDIT_BOOK, (int&) movie_info->bookmarks.user[i].length, 20, LOCALE_MOVIEBROWSER_EDIT_BOOK_TYPE_INFO1, LOCALE_MOVIEBROWSER_EDIT_BOOK_TYPE_INFO2); + + pBookItemMenu[i] = new CMenuWidget(LOCALE_MOVIEBROWSER_BOOK_HEAD, "streaming.raw"); + pBookItemMenu[i]->addItem(GenericMenuSeparator); + pBookItemMenu[i]->addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_NAME, true, movie_info->bookmarks.user[i].name,pBookNameInput[i])); + pBookItemMenu[i]->addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_POSITION, true, pBookPosIntInput[i]->getValue(), pBookPosIntInput[i])); + pBookItemMenu[i]->addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_TYPE, true, pBookTypeIntInput[i]->getValue(),pBookTypeIntInput[i])); + + bookmarkMenu.addItem( new CMenuForwarderNonLocalized (movie_info->bookmarks.user[i].name.c_str(), true, pBookPosIntInput[i]->getValue(),pBookItemMenu[i])); + } + +/********************************************************************/ +/** serie******************************************************/ + CStringInput serieUserInput(LOCALE_MOVIEBROWSER_EDIT_SERIE, &movie_info->serieName, 20, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-.: "); + + CMenuWidget serieMenu (LOCALE_MOVIEBROWSER_SERIE_HEAD, "streaming.raw"); + serieMenu.addItem(GenericMenuSeparator); + serieMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_SERIE_NAME, true, movie_info->serieName,&serieUserInput)); + serieMenu.addItem(GenericMenuSeparatorLine); + for(unsigned int i=0; i < m_vHandleSerienames.size(); i++) + serieMenu.addItem( new CMenuSelector(m_vHandleSerienames[i]->serieName.c_str(), true, movie_info->serieName)); + + /********************************************************************/ + /** update movie info ******************************************************/ + for(i=0; idirItNr].c_str(),BUFFER_SIZE); + snprintf(size,BUFFER_SIZE,"%5llu",movie_info->file.Size>>20); + } + + CStringInput titelUserInput(LOCALE_MOVIEBROWSER_INFO_TITLE, &movie_info->epgTitle, MAX_STRING, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-.: "); + //CStringInputSMS titelUserInput(LOCALE_MOVIEBROWSER_INFO_TITLE, &movie_info->epgTitle, MAX_STRING, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-.: "); + CStringInput channelUserInput(LOCALE_MOVIEBROWSER_INFO_CHANNEL, &movie_info->epgChannel, 15, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-.: "); + CStringInput epgUserInput(LOCALE_MOVIEBROWSER_INFO_INFO1, &movie_info->epgInfo1, 20, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-.: "); + CDateInput dateUserDateInput(LOCALE_MOVIEBROWSER_INFO_LENGTH, &movie_info->dateOfLastPlay, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE); + CDateInput recUserDateInput(LOCALE_MOVIEBROWSER_INFO_LENGTH, &movie_info->file.Time, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE); + CIntInput lengthUserIntInput(LOCALE_MOVIEBROWSER_INFO_LENGTH, (int&)movie_info->length, 3, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE); + CStringInput countryUserInput(LOCALE_MOVIEBROWSER_INFO_PRODCOUNTRY, &movie_info->productionCountry, 11, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "ABCDEFGHIJKLMNOPQRSTUVWXYZ "); + CIntInput yearUserIntInput(LOCALE_MOVIEBROWSER_INFO_PRODYEAR, (int&)movie_info->productionDate, 4, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE); + + CMenuWidget movieInfoMenu (LOCALE_MOVIEBROWSER_INFO_HEAD, "streaming.raw",m_cBoxFrame.iWidth); + + movieInfoMenu.addItem(GenericMenuSeparator); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_MENU_SAVE, true, NULL, this, "save_movie_info", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_HEAD_UPDATE, true, NULL, &movieInfoMenuUpdate, NULL, CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN)); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_HEAD, true, NULL, &bookmarkMenu, NULL, CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE)); + movieInfoMenu.addItem(GenericMenuSeparatorLine); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_TITLE, true, movie_info->epgTitle, &titelUserInput,NULL, CRCInput::RC_1, NEUTRINO_ICON_BUTTON_1)); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_SERIE, true, movie_info->serieName, &serieMenu,NULL, CRCInput::RC_2, NEUTRINO_ICON_BUTTON_2)); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_INFO1, (movie_info->epgInfo1.size() <= MAX_STRING) /*true*/, movie_info->epgInfo1, &epgUserInput,NULL, CRCInput::RC_3, NEUTRINO_ICON_BUTTON_3)); + movieInfoMenu.addItem( new CMenuOptionChooser(LOCALE_MOVIEBROWSER_INFO_GENRE_MAJOR, &movie_info->genreMajor, GENRE_ALL, GENRE_ALL_COUNT, true,NULL, CRCInput::RC_4, NEUTRINO_ICON_BUTTON_4)); + movieInfoMenu.addItem(GenericMenuSeparatorLine); + movieInfoMenu.addItem( new CMenuOptionNumberChooser(LOCALE_MOVIEBROWSER_INFO_QUALITY,&movie_info->quality,true,0,3, NULL)); + movieInfoMenu.addItem( new CMenuOptionChooser(LOCALE_MOVIEBROWSER_INFO_PARENTAL_LOCKAGE, &movie_info->parentalLockAge, MESSAGEBOX_PARENTAL_LOCKAGE_OPTIONS, MESSAGEBOX_PARENTAL_LOCKAGE_OPTION_COUNT, true,NULL, CRCInput::RC_6, NEUTRINO_ICON_BUTTON_6 )); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_PRODYEAR, true, yearUserIntInput.getValue(), &yearUserIntInput,NULL, CRCInput::RC_7, NEUTRINO_ICON_BUTTON_7)); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_PRODCOUNTRY, true, movie_info->productionCountry, &countryUserInput,NULL, CRCInput::RC_8, NEUTRINO_ICON_BUTTON_8)); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_LENGTH, true, lengthUserIntInput.getValue(), &lengthUserIntInput,NULL, CRCInput::RC_9, NEUTRINO_ICON_BUTTON_9)); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_CHANNEL, true, movie_info->epgChannel, &channelUserInput,NULL, CRCInput::RC_0, NEUTRINO_ICON_BUTTON_0));//LOCALE_TIMERLIST_CHANNEL + movieInfoMenu.addItem(GenericMenuSeparatorLine); + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_PATH, false, dirItNr)); //LOCALE_TIMERLIST_RECORDING_DIR + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_PREVPLAYDATE, false, dateUserDateInput.getValue()));//LOCALE_FLASHUPDATE_CURRENTVERSIONDATE + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_RECORDDATE, false, recUserDateInput.getValue()));//LOCALE_FLASHUPDATE_CURRENTVERSIONDATE + movieInfoMenu.addItem( new CMenuForwarder(LOCALE_MOVIEBROWSER_INFO_SIZE, false, size, NULL)); + + movieInfoMenu.exec(NULL,""); + + for(int i =0 ; i < MI_MOVIE_BOOK_USER_MAX && i < MAX_NUMBER_OF_BOOKMARK_ITEMS; i++ ) + { + delete pBookNameInput[i] ; + delete pBookPosIntInput[i] ; + delete pBookTypeIntInput[i]; + delete pBookItemMenu[i]; + } +} + +extern "C" int pinghost( const char *hostname ); +bool CMovieBrowser::showMenu(MI_MOVIE_INFO* movie_info) +{ + /* first clear screen */ + m_pcWindow->paintBackground(); + int i; +/********************************************************************/ +/** directory menu ******************************************************/ + CDirMenu dirMenu(&m_dir); + +/********************************************************************/ +/** options menu **************************************************/ + +/********************************************************************/ +/** parental lock **************************************************/ + CMenuWidget parentalMenu (LOCALE_MOVIEBROWSER_MENU_PARENTAL_LOCK_HEAD , "streaming.raw",450); + parentalMenu.addItem(GenericMenuSeparator); + parentalMenu.addItem( new CMenuOptionChooser(LOCALE_MOVIEBROWSER_MENU_PARENTAL_LOCK_ACTIVATED, (int*)(&m_parentalLock), MESSAGEBOX_PARENTAL_LOCK_OPTIONS, MESSAGEBOX_PARENTAL_LOCK_OPTIONS_COUNT, true )); + parentalMenu.addItem( new CMenuOptionChooser(LOCALE_MOVIEBROWSER_MENU_PARENTAL_LOCK_RATE_HEAD, (int*)(&m_settings.parentalLockAge), MESSAGEBOX_PARENTAL_LOCKAGE_OPTIONS, MESSAGEBOX_PARENTAL_LOCKAGE_OPTION_COUNT, true )); + + +/********************************************************************/ +/** optionsVerzeichnisse **************************************************/ + CMenuWidget optionsMenuDir (LOCALE_MOVIEBROWSER_MENU_DIRECTORIES_HEAD , "streaming.raw",450); + optionsMenuDir.addItem(GenericMenuSeparator); + optionsMenuDir.addItem( new CMenuOptionChooser(LOCALE_MOVIEBROWSER_USE_REC_DIR, (int*)(&m_settings.storageDirRecUsed), MESSAGEBOX_YES_NO_OPTIONS, MESSAGEBOX_YES_NO_OPTIONS_COUNT, true )); + optionsMenuDir.addItem( new CMenuForwarder( LOCALE_MOVIEBROWSER_DIR , false ,g_settings.network_nfs_recordingdir)); + + optionsMenuDir.addItem( new CMenuOptionChooser(LOCALE_MOVIEBROWSER_USE_MOVIE_DIR, (int*)(&m_settings.storageDirMovieUsed), MESSAGEBOX_YES_NO_OPTIONS, MESSAGEBOX_YES_NO_OPTIONS_COUNT, true )); + optionsMenuDir.addItem( new CMenuForwarder (LOCALE_MOVIEBROWSER_DIR, false , g_settings.network_nfs_moviedir)); + optionsMenuDir.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_MOVIEBROWSER_DIR_HEAD)); + + CFileChooser* dirInput[MB_MAX_DIRS]; + CMenuOptionChooser* chooser[MB_MAX_DIRS]; + COnOffNotifier* notifier[MB_MAX_DIRS]; + CMenuForwarder* forwarder[MB_MAX_DIRS]; + for(i=0; igetValue(), browserRowWidthIntInput[i])); + if(i MAX_BROWSER_FRAME_HEIGHT) + m_settings.browserFrameHeight = MAX_BROWSER_FRAME_HEIGHT; + if (m_settings.browserRowNr > MB_MAX_ROWS ) + m_settings.browserRowNr = MB_MAX_ROWS; + if (m_settings.browserRowNr < 1 ) + m_settings.browserRowNr = 1; + for(i = 0; i < m_settings.browserRowNr; i++) + { + if( m_settings.browserRowWidth[i] >500) + m_settings.browserRowWidth[i] = 500; + if( m_settings.browserRowWidth[i] < 10) + m_settings.browserRowWidth[i] = 10; + } + + if(dirMenu.isChanged()) + loadMovies(); + + updateSerienames(); + refreshBrowserList(); + refreshLastPlayList(); + refreshLastRecordList(); + refreshFilterList(); + refresh(); + + for(i=0; ishowStartPosSelectionMenu\r\n"); + int pos = -1; + int result = 0; + int menu_nr= 0; + int position[MAX_NUMBER_OF_BOOKMARK_ITEMS]; + + if(m_movieSelectionHandler == NULL) return(result); + + char start_pos[13]; snprintf(start_pos, 12,"%3d min",m_movieSelectionHandler->bookmarks.start/60); + char play_pos[13]; snprintf(play_pos, 12,"%3d min",m_movieSelectionHandler->bookmarks.lastPlayStop/60); + + char book[MI_MOVIE_BOOK_USER_MAX][20]; + + CMenuWidgetSelection startPosSelectionMenu(LOCALE_MOVIEBROWSER_START_HEAD , "streaming.raw"); + + startPosSelectionMenu.addItem(GenericMenuSeparator); + + //startPosSelectionMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_START_RECORD_START, true,NULL)); + //position[menu_nr++] = 0; + if(m_movieSelectionHandler->bookmarks.start != 0) + { + startPosSelectionMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIESTART, true, start_pos)); + position[menu_nr++] = m_movieSelectionHandler->bookmarks.start; + } + if(m_movieSelectionHandler->bookmarks.lastPlayStop != 0) + { + startPosSelectionMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_LASTMOVIESTOP, true, play_pos)); + position[menu_nr++] = m_movieSelectionHandler->bookmarks.lastPlayStop; + } + startPosSelectionMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_START_RECORD_START, true,NULL)); + position[menu_nr++] = 0; + + startPosSelectionMenu.addItem(GenericMenuSeparatorLine); + int sep_pos = menu_nr; + + for(int i =0 ; i < MI_MOVIE_BOOK_USER_MAX && menu_nr < MAX_NUMBER_OF_BOOKMARK_ITEMS; i++ ) + { + if( m_movieSelectionHandler->bookmarks.user[i].pos != 0 ) + { + if(m_movieSelectionHandler->bookmarks.user[i].length >= 0) + position[menu_nr] = m_movieSelectionHandler->bookmarks.user[i].pos; + else + position[menu_nr] = m_movieSelectionHandler->bookmarks.user[i].pos + m_movieSelectionHandler->bookmarks.user[i].length; + + snprintf(book[i], 19,"%5d min",position[menu_nr]/60); +TRACE("[mb] adding boomark menu N %d, position %d\n", menu_nr, position[menu_nr]); + startPosSelectionMenu.addItem(new CMenuForwarderNonLocalized (m_movieSelectionHandler->bookmarks.user[i].name.c_str(), true, book[i])); + menu_nr++; + } + } + + startPosSelectionMenu.exec(NULL, "12345"); + /* check what menu item was ok'd and set the appropriate play offset*/ + //result = startPosSelectionMenu.getSelected(); + result = startPosSelectionMenu.getSelectedLine(); +printf("startPosSelectionMenu result %d\n", result); + if(result < 0) + return -1; + //TRACE("[mb] selected bookmark %d\n", result); + if(result != 0 && result <= MAX_NUMBER_OF_BOOKMARK_ITEMS) + { + result--; + if(result > sep_pos) result--; + pos = position[result]; + } + TRACE("[mb] selected bookmark %d position %d \n", result, pos); + + return(pos) ; +} + +bool CMovieBrowser::isParentalLock(MI_MOVIE_INFO& movie_info) +{ + bool result = false; + if(m_parentalLock == MB_PARENTAL_LOCK_ACTIVE && m_settings.parentalLockAge <= movie_info.parentalLockAge ) + { + result = true; + } + return (result); +} + +bool CMovieBrowser::isFiltered(MI_MOVIE_INFO& movie_info) +{ + bool result = true; + + switch(m_settings.filter.item) + { + case MB_INFO_FILEPATH: + if(m_settings.filter.optionVar == movie_info.dirItNr) + result = false; + break; + case MB_INFO_INFO1: + if(strcmp(m_settings.filter.optionString.c_str(),movie_info.epgInfo1.c_str()) == 0) + result = false; + break; + case MB_INFO_MAJOR_GENRE: + if(m_settings.filter.optionVar == movie_info.genreMajor) + result = false; + break; + case MB_INFO_SERIE: + if(strcmp(m_settings.filter.optionString.c_str(),movie_info.serieName.c_str()) == 0) + result = false; + break; + break; + default: + result = false; + break; + } + return (result); +} + +bool CMovieBrowser::getMovieInfoItem(MI_MOVIE_INFO& movie_info, MB_INFO_ITEM item, std::string* item_string) +{ + #define MAX_STR_TMP 100 + char str_tmp[MAX_STR_TMP]; + bool result = true; + *item_string=""; + tm* tm_tmp; + + char text[20]; + int i=0; + int counter=0; + + switch(item) + { + case MB_INFO_FILENAME: // = 0, + *item_string = movie_info.file.getFileName(); + break; + case MB_INFO_FILEPATH: // = 1, + if(m_dirNames.size() > 0) + *item_string = m_dirNames[movie_info.dirItNr]; + break; + case MB_INFO_TITLE: // = 2, + *item_string = movie_info.epgTitle; + if(strcmp("not available",movie_info.epgTitle.c_str()) == 0) + result = false; + if(movie_info.epgTitle.empty()) + result = false; + break; + case MB_INFO_SERIE: // = 3, + *item_string = movie_info.serieName; + break; + case MB_INFO_INFO1: // = 4, + *item_string = movie_info.epgInfo1; + break; + case MB_INFO_MAJOR_GENRE: // = 5, + snprintf(str_tmp,MAX_STR_TMP,"%2d",movie_info.genreMajor); + *item_string = str_tmp; + break; + case MB_INFO_MINOR_GENRE: // = 6, + snprintf(str_tmp,MAX_STR_TMP,"%2d",movie_info.genreMinor); + *item_string = str_tmp; + break; + case MB_INFO_INFO2: // = 7, + *item_string = movie_info.epgInfo2; + break; + case MB_INFO_PARENTAL_LOCKAGE: // = 8, + snprintf(str_tmp,MAX_STR_TMP,"%2d",movie_info.parentalLockAge); + *item_string = str_tmp; + break; + case MB_INFO_CHANNEL: // = 9, + *item_string = movie_info.epgChannel; + break; + case MB_INFO_BOOKMARK: // = 10, + // we just return the number of bookmarks + for(i = 0; i < MI_MOVIE_BOOK_USER_MAX; i++) + { + if(movie_info.bookmarks.user[i].pos != 0) + counter++; + } + snprintf(text, 8,"%d",counter); + text[9] = 0; // just to make sure string is terminated + *item_string = text; + break; + case MB_INFO_QUALITY: // = 11, + snprintf(str_tmp,MAX_STR_TMP,"%d",movie_info.quality); + *item_string = str_tmp; + break; + case MB_INFO_PREVPLAYDATE: // = 12, + tm_tmp = localtime(&movie_info.dateOfLastPlay); + snprintf(str_tmp,MAX_STR_TMP,"%02d.%02d.%02d",tm_tmp->tm_mday,(tm_tmp->tm_mon)+ 1, tm_tmp->tm_year >= 100 ? tm_tmp->tm_year-100 : tm_tmp->tm_year); + *item_string = str_tmp; + break; + case MB_INFO_RECORDDATE: // = 13, + tm_tmp = localtime(&movie_info.file.Time); + snprintf(str_tmp,MAX_STR_TMP,"%02d.%02d.%02d",tm_tmp->tm_mday,(tm_tmp->tm_mon) + 1,tm_tmp->tm_year >= 100 ? tm_tmp->tm_year-100 : tm_tmp->tm_year); + *item_string = str_tmp; + break; + case MB_INFO_PRODDATE: // = 14, + snprintf(str_tmp,MAX_STR_TMP,"%d",movie_info.productionDate); + *item_string = str_tmp; + break; + case MB_INFO_COUNTRY: // = 15, + *item_string = movie_info.productionCountry; + break; + case MB_INFO_GEOMETRIE: // = 16, + result = false; + break; + case MB_INFO_AUDIO: // = 17, +#if 1 // MB_INFO_AUDIO test + // we just return the number of audiopids + char text[10]; + snprintf(text, 8,"%d",movie_info.audioPids.size()); + text[9] = 0; // just to make sure string is terminated + *item_string = text; +#else // MB_INFO_AUDIO test + for(i=0; i < movie_info.audioPids.size() && i < 10; i++) + { + if(movie_info.audioPids[i].epgAudioPidName[0].size() < 2) + { + text[counter++] = '?'; // two chars ??? -> strange name + continue; + } + + // check for Dolby Digital / AC3 Audio audiopids (less than 5.1 is not remarkable) + if( (movie_info.audioPids[i].epgAudioPidName.find("AC3") != -1 ) || + (movie_info.audioPids[i].epgAudioPidName.find("5.1") != -1 )) + { + ac3_found = true; + } + // Check for german audio pids + if( movie_info.audioPids[i].epgAudioPidName[0] == 'D' || // Deutsch + movie_info.audioPids[i].epgAudioPidName[0] == 'd' || + movie_info.audioPids[i].epgAudioPidName[0] == 'G' || // German + movie_info.audioPids[i].epgAudioPidName[0] == 'g' || + movie_info.audioPids[i].epgAudioPidName[0] == 'M' || // for Mono, mono and Stereo, stereo we assume German ;) + movie_info.audioPids[i].epgAudioPidName[0] == 'n' || + (movie_info.audioPids[i].epgAudioPidName[0] == 'S' && movie_info.audioPids[i].epgAudioPidName[1] == 't' ) || + (movie_info.audioPids[i].epgAudioPidName[0] == 's' && movie_info.audioPids[i].epgAudioPidName[1] == 't' )) + { + text[counter++] = 'D'; + continue; + } + // Check for english audio pids + if( movie_info.audioPids[i].epgAudioPidName[0] == 'E' || + movie_info.audioPids[i].epgAudioPidName[0] == 'e') + { + text[counter++] = 'E'; + continue; + } + // Check for french audio pids + if( movie_info.audioPids[i].epgAudioPidName[0] == 'F' || + movie_info.audioPids[i].epgAudioPidName[0] == 'f') + { + text[counter++] = 'F'; + continue; + } + // Check for italian audio pids + if( movie_info.audioPids[i].epgAudioPidName[0] == 'I' || + movie_info.audioPids[i].epgAudioPidName[0] == 'i') + { + text[counter++] = 'I'; + continue; + } + // Check for spanish audio pids + if( movie_info.audioPids[i].epgAudioPidName[0] == 'E' || + movie_info.audioPids[i].epgAudioPidName[0] == 'e' || + movie_info.audioPids[i].epgAudioPidName[0] == 'S' || + movie_info.audioPids[i].epgAudioPidName[0] == 's') + { + text[counter++] = 'S'; + continue; + } + text[counter++] = '?'; // We have not found any language for this pid + } + if(ac3_found == true) + { + text[counter++] = '5'; + text[counter++] = '.'; + text[counter++] = '1'; + } + text[counter] = 0; // terminate string +#endif // MB_INFO_AUDIO test + break; + case MB_INFO_LENGTH: // = 18, + snprintf(str_tmp,MAX_STR_TMP,"%4d",movie_info.length); + *item_string = str_tmp; + break; + case MB_INFO_SIZE: // = 19, + snprintf(str_tmp,MAX_STR_TMP,"%4llu",movie_info.file.Size>>20); + *item_string = str_tmp; + break; + case MB_INFO_MAX_NUMBER: // = 20 + default: + *item_string=""; + result = false; + break; + } + //TRACE(" getMovieInfoItem: %d,>%s<",item,*item_string.c_str()); + return(result); +} + +void CMovieBrowser::updateSerienames(void) +{ + if(m_seriename_stale == false) + return; + + m_vHandleSerienames.clear(); + for(unsigned int i = 0; i < m_vMovieInfo.size(); i++) + { + if(!m_vMovieInfo[i].serieName.empty()) + { + // current series name is not empty, lets see if we already have it in the list, and if not save it to the list. + bool found = false; + for(unsigned int t = 0; t < m_vHandleSerienames.size() && found == false; t++) + { + if(strcmp(m_vHandleSerienames[t]->serieName.c_str(),m_vMovieInfo[i].serieName.c_str()) == 0) + found = true; + } + if(found == false) + m_vHandleSerienames.push_back(&m_vMovieInfo[i]); + } + } + TRACE("[mb]->updateSerienames: %d\r\n",m_vHandleSerienames.size()); + // TODO sort(m_serienames.begin(), m_serienames.end(), my_alphasort); + m_seriename_stale = false; +} + +void CMovieBrowser::autoFindSerie(void) +{ + TRACE("autoFindSerie\n"); + updateSerienames(); // we have to make sure that the seriename array is up to date, otherwise this does not work + // if the array is not stale, the function is left immediately + for(unsigned int i = 0; i < m_vMovieInfo.size(); i++) + { + // For all movie infos, which do not have a seriename, we try to find one. + // We search for a movieinfo with seriename, and than we do check if the title is the same + // in case of same title, we assume both belongs to the same serie + //TRACE("%s ",m_vMovieInfo[i].serieName); + if( m_vMovieInfo[i].serieName.empty()) + { + for(unsigned int t=0; t < m_vHandleSerienames.size();t++) + { + //TRACE("%s ",m_vHandleSerienames[i].serieName); + if(m_vMovieInfo[i].epgTitle == m_vHandleSerienames[t]->epgTitle ) + { + //TRACE("x"); + m_vMovieInfo[i].serieName = m_vHandleSerienames[t]->serieName; + break; // we found a maching serie, nothing to do else, leave for(t=0) + } + } + //TRACE("\n"); + } + } +} + +CMenuSelector::CMenuSelector(const char * OptionName, const bool Active , char * OptionValue, int* ReturnInt ,int ReturnIntValue ) : CMenuItem() +{ + height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + optionValueString = NULL; + optionName = OptionName; + optionValue = OptionValue; + active = Active; + returnIntValue = ReturnIntValue; + returnInt = ReturnInt; +}; + +CMenuSelector::CMenuSelector(const char * OptionName, const bool Active , std::string& OptionValue, int* ReturnInt ,int ReturnIntValue ) : CMenuItem() +{ + height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + optionValueString = &OptionValue; + optionName = OptionName; + strncpy(buffer,OptionValue.c_str(),BUFFER_MAX); + buffer[BUFFER_MAX-1] = 0;// terminate string + optionValue = buffer; + active = Active; + returnIntValue = ReturnIntValue; + returnInt = ReturnInt; +}; + +int CMenuSelector::exec(CMenuTarget* parent) +{ + if(returnInt != NULL) + *returnInt= returnIntValue; + + if(optionValue != NULL && optionName != NULL) + { + if(optionValueString == NULL) + strcpy(optionValue,optionName); + else + *optionValueString = optionName; + } + return menu_return::RETURN_EXIT; +}; + +int CMenuSelector::paint(bool selected, bool last) +{ + CFrameBuffer * frameBuffer = CFrameBuffer::getInstance(); + + unsigned char color = COL_MENUCONTENT; + fb_pixel_t bgcolor = COL_MENUCONTENT_PLUS_0; + if (selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + if (!active) + { + color = COL_MENUCONTENTINACTIVE; + bgcolor = COL_MENUCONTENTINACTIVE_PLUS_0; + } + + frameBuffer->paintBoxRel(x, y, dx, height, bgcolor); + + int stringstartposName = x + offx + 10; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposName, y+height,dx- (stringstartposName - x), optionName, color, 0, true); // UTF-8 + + if (selected) + CVFD::getInstance()->showMenuText(0, optionName, -1, true); // UTF-8 + + return y+height; +} + +int CMovieHelp::exec(CMenuTarget* parent, const std::string & actionKey) +{ + Helpbox helpbox; + helpbox.addLine(NEUTRINO_ICON_BUTTON_RED, "Sortierung ändern"); + helpbox.addLine(NEUTRINO_ICON_BUTTON_GREEN, "Filterfenster einblenden"); + helpbox.addLine(NEUTRINO_ICON_BUTTON_YELLOW, "Aktives Fenster wechseln"); + helpbox.addLine(NEUTRINO_ICON_BUTTON_BLUE, "Filminfos neu laden"); + helpbox.addLine(NEUTRINO_ICON_BUTTON_DBOX, "Hauptmenü"); + helpbox.addLine("+/- Ansicht wechseln"); + helpbox.addLine(""); + helpbox.addLine("Während der Filmwiedergabe:"); + helpbox.addLine(NEUTRINO_ICON_BUTTON_BLUE, " Markierungsmenu "); + helpbox.addLine(NEUTRINO_ICON_BUTTON_0, " Markierungsaktion nicht ausführen"); + helpbox.addLine(""); + helpbox.addLine("MovieBrowser $Revision: 1.10 $"); + helpbox.addLine("by Günther"); + helpbox.show(LOCALE_MESSAGEBOX_INFO); + return(0); +} +///////////////////////////////////////////////// +// MenuTargets +//////////////////////////////////////////////// +int CFileChooser::exec(CMenuTarget* parent, const std::string & actionKey) +{ + if(parent != NULL) + parent->hide(); + + CFileBrowser browser; + browser.Dir_Mode=true; + if (browser.exec(dirPath->c_str())) + { + *dirPath = browser.getSelectedFile()->Name; + short a = dirPath->compare(0,5,"/mnt/"); + short b = dirPath->compare(0,7,"/media/"); + if(a != 0 && b != 0) + *dirPath =""; // We clear the string if the selected folder is not at leaset /mnt/ or /hdd (There is no other possibility to clear this) + } + + return menu_return::RETURN_REPAINT; +} + +CDirMenu::CDirMenu(std::vector* dir_list) +{ + unsigned int i; + changed = false; + dirList = dir_list; + + if( dirList->empty()) + return; + + for(i = 0; i < MAX_DIR; i++) + dirNfsMountNr[i]=-1; + + for(i = 0; i < dirList->size() && i < MAX_DIR; i++) + { + for(int nfs = 0; nfs < NETWORK_NFS_NR_OF_ENTRIES; nfs++) + { + std::string tmp = g_settings.network_nfs_local_dir[nfs]; + int result = -1; + if(tmp.size()) + result = (*dirList)[i].name.compare( 0,tmp.size(),tmp) ; +printf("[CDirMenu] (nfs%d) %s == (mb%d) %s (%d)\n",nfs,g_settings.network_nfs_local_dir[nfs],i,(*dirList)[i].name.c_str(),result); + + if(result == 0) + { + dirNfsMountNr[i] = nfs; + break; + } + } + } +}; + +int CDirMenu::exec(CMenuTarget* parent, const std::string & actionKey) +{ + int returnval = menu_return::RETURN_REPAINT; + + if(actionKey == "") + { + if(parent) + parent->hide(); + + changed = false; + show(); + } + else if(actionKey.size() == 1) + { + printf("[CDirMenu].exec %s\n",actionKey.c_str()); + int number = atoi(actionKey.c_str()); + if(number < MAX_DIR) + { + if(dirState[number] == DIR_STATE_SERVER_DOWN) + { + std::string command = "etherwake "; + command += g_settings.network_nfs_mac[dirNfsMountNr[number]]; + printf("try to start server: %s\n",command.c_str()); + if(system(command.c_str()) != 0) + perror("etherwake failed"); + + dirOptionText[number]="STARTE SERVER"; + } + else if(dirState[number] == DIR_STATE_NOT_MOUNTED) + { + printf("[CDirMenu] try to mount %d,%d\n",number,dirNfsMountNr[number]); + CFSMounter::MountRes res; + res = CFSMounter::mount( g_settings.network_nfs_ip[dirNfsMountNr[number]].c_str(), + g_settings.network_nfs_dir[dirNfsMountNr[number]] , + g_settings.network_nfs_local_dir[dirNfsMountNr[number]] , + (CFSMounter::FSType)g_settings.network_nfs_type[dirNfsMountNr[number]] , + g_settings.network_nfs_username[dirNfsMountNr[number]] , + g_settings.network_nfs_password[dirNfsMountNr[number]] , + g_settings.network_nfs_mount_options1[dirNfsMountNr[number]] , + g_settings.network_nfs_mount_options2[dirNfsMountNr[number]] ); + if(res == CFSMounter::MRES_OK) // if mount is successful we set the state to active in any case + { + *(*dirList)[number].used = true; + } + // try to mount + updateDirState(); + changed = true; + } + else if(dirState[number] == DIR_STATE_MOUNTED) + { + if(*(*dirList)[number].used == true) + { + *(*dirList)[number].used = false; + } + else + { + *(*dirList)[number].used = true; + } + //CFSMounter::umount(g_settings.network_nfs_local_dir[dirNfsMountNr[number]]); + updateDirState(); + changed = true; + } + } + } + return returnval; +} + +void CDirMenu::updateDirState(void) +{ + unsigned int drivefree = 0; + struct statfs s; + + for(unsigned int i = 0; i < dirList->size() && i < MAX_DIR; i++) + { + dirOptionText[i]="UNBEKANNT"; + dirState[i]=DIR_STATE_UNKNOWN; + // 1st ping server +printf("updateDirState: %d: state %d nfs %d\n", i, dirState[i], dirNfsMountNr[i]); + if(dirNfsMountNr[i] != -1) + { + int retvalue = pinghost(g_settings.network_nfs_ip[dirNfsMountNr[i]].c_str()); + if (retvalue == 0)//LOCALE_PING_UNREACHABLE + { + dirOptionText[i]="Server, offline"; + dirState[i]=DIR_STATE_SERVER_DOWN; + } + else if (retvalue == 1)//LOCALE_PING_OK + { + if(CFSMounter::isMounted (g_settings.network_nfs_local_dir[dirNfsMountNr[i]]) == 0) + { + dirOptionText[i]="Not mounted"; + dirState[i]=DIR_STATE_NOT_MOUNTED; + } + else + { + dirState[i]=DIR_STATE_MOUNTED; + } + } + } + else + { + // not a nfs dir, probably IDE? we accept this so far + dirState[i]=DIR_STATE_MOUNTED; + } + if(dirState[i] == DIR_STATE_MOUNTED) + { + if(*(*dirList)[i].used == true) + { + if (statfs((*dirList)[i].name.c_str(), &s) >= 0 ) + { + drivefree = (s.f_bfree * s.f_bsize)>>30; + char tmp[20]; + snprintf(tmp, 19,"%3d GB free",drivefree); + tmp[19]=0; + dirOptionText[i]=tmp; + } + else + { + dirOptionText[i]="? GB free"; + } + } + else + { + dirOptionText[i] = "Inactive"; + } + } + } +} + + +void CDirMenu::show(void) +{ + if(dirList->empty()) + return; + + char tmp[20]; + + CMenuWidget dirMenu (LOCALE_MOVIEBROWSER_MENU_DIRECTORIES_HEAD , "streaming.raw",440); + dirMenu.addItem(GenericMenuSeparator); + + updateDirState(); + for(unsigned int i = 0; i < dirList->size() && i < MAX_DIR; i++) + { + sprintf(tmp,"%d",i); + tmp[1]=0; + dirMenu.addItem( new CMenuForwarderNonLocalized ( (*dirList)[i].name.c_str(), (dirState[i] != DIR_STATE_UNKNOWN), dirOptionText[i], this,tmp)); + } + dirMenu.exec(NULL," "); + return; + +} + +off64_t get_full_len(char * startname) +{ + off64_t fulllength=0; + struct stat64 s; + char spart[255]; + int part = 0; + + stat64(startname, &s); + do { + fulllength +=s.st_size; + sprintf(spart, "%s.%03d", startname, ++part); + } while (!stat64(spart, &s)); + return fulllength; +} + +static void reset_atime(char * path, time_t tt) +{ + struct utimbuf ut; + ut.actime = tt-1; + ut.modtime = tt-1; + utime(path, &ut); +} + +#define BUF_SIZE 1395*188 +#define SAFE_GOP 1395*188 +#define MP_TS_SIZE 262072 // ~0.5 sec +#define MINUTEOFFSET 117*262072 +#define SECONDOFFSET MP_TS_SIZE*2 +static off64_t truncate_movie(MI_MOVIE_INFO * minfo) +{ + struct stat64 s; + char spart[255]; + int part = 0, tpart = 0; + bool found = 0; + char * name = (char *) minfo->file.Name.c_str(); + off64_t size = minfo->file.Size; + int len = minfo->length; + int seconds = minfo->bookmarks.end; + off64_t minuteoffset = len ? size / len : MINUTEOFFSET; + minuteoffset = (minuteoffset / MP_TS_SIZE) * MP_TS_SIZE; + if(minuteoffset < 10000000 || minuteoffset > 90000000) + minuteoffset = MINUTEOFFSET; + off64_t secsize = minuteoffset/60; + off64_t secoffset = secsize * seconds; + off64_t newsize = secoffset; + +//printf("truncate: name %s size %lld len %d sec truncate to %d sec, new size %lld\n", name, size, len, seconds, secoffset); + sprintf(spart, "%s", name); + while (!stat64(spart, &s)) { + if(found) { +//printf("truncate: check part %d file %s - TO REMOVE\n", part, spart); + unlink(spart); + } else { +//printf("truncate: check part %d file %s - OK\n", part, spart); + if(secoffset < s.st_size) { + tpart = part; + found = 1; + } else + secoffset -= s.st_size; + } + sprintf(spart, "%s.%03d", name, ++part); + } + if(found) { + if(tpart) + sprintf(spart, "%s.%03d", name, tpart); + else + sprintf(spart, "%s", name); +printf("truncate: part %s to size %lld\n", spart, secoffset); + truncate(spart, secoffset); + minfo->file.Size = newsize; + minfo->length = minfo->bookmarks.end/60; + minfo->bookmarks.end = 0; + reset_atime(spart, minfo->file.Time); + return newsize; + } + return 0; +} + +struct mybook { + off64_t pos; + off64_t len; + bool ok; +}; +#define REAL_CUT 1 + +static int check_pes_start (unsigned char *packet) +{ + // PCKT: 47 41 91 37 07 50 3F 14 BF 04 FE B9 00 00 01 EA 00 00 8C ... + if (packet[0] == 0x47 && // sync byte 0x47 + (packet[1] & 0x40)) // pusi == 1 + { + /* good, now we have to check if it is video stream */ + unsigned char *pes = packet + 4; + if (packet[3] & 0x20) // adaptation field is present + pes += packet[4] + 1; + + if (!memcmp(pes, "\x00\x00\x01", 3) && (pes[3] & 0xF0) == 0xE0) // PES start & video type + { + //return 1; //(pes[4] << 8) | pes[5]; // PES packet len + pes += 4; + while (pes < (packet + 188 - 4)) + if (!memcmp (pes, "\x00\x00\x01\xB8", 4)) // GOP detect + return 1; + else + pes++; + } + } + return 0; +} + +int find_gop(unsigned char *buf, int r) +{ + for(int j = 0; j < r/188; j++) { + if(check_pes_start(&buf[188*j])) { + return 188*j; + } + } + return -1; +} + +off64_t fake_read(int fd, unsigned char *buf, size_t size, off64_t fsize) +{ + off64_t cur = lseek64 (fd, 0, SEEK_CUR); + + buf[0] = 0x47; + if((cur + size) > fsize) + return (fsize - cur); + else + return size; +} + +#define PSI_SIZE 188*3 +static int read_psi(char * spart, unsigned char * buf) +{ + int srcfd = open (spart, O_RDONLY | O_LARGEFILE); + if(srcfd >= 0) { + /* read psi */ + int r = read (srcfd, buf, PSI_SIZE); + close(srcfd); + if(r != PSI_SIZE) { + perror("read psi"); + return -1; + } + return 0; + } + return -1; +} + +static void save_info(CMovieInfo * cmovie, MI_MOVIE_INFO * minfo, char * dpart, off64_t spos, off64_t secsize) +{ + MI_MOVIE_INFO ninfo; + + cmovie->copy(minfo, &ninfo); + ninfo.file.Name = dpart; + ninfo.file.Size = spos; + ninfo.length = spos/secsize/60; + ninfo.bookmarks.end = 0; + ninfo.bookmarks.start = 0; + ninfo.bookmarks.lastPlayStop = 0; + for(int book_nr = 0; book_nr < MI_MOVIE_BOOK_USER_MAX; book_nr++) { + if( ninfo.bookmarks.user[book_nr].pos != 0 && ninfo.bookmarks.user[book_nr].length > 0 ) { + ninfo.bookmarks.user[book_nr].pos = 0; + ninfo.bookmarks.user[book_nr].length = 0; + } + } + cmovie->saveMovieInfo(ninfo); + cmovie->clearMovieInfo(&ninfo); + reset_atime(dpart, minfo->file.Time); +} + +static void find_new_part(char * npart, char * dpart) +{ + struct stat64 s; + int dp = 0; + sprintf(dpart, "%s_%d.ts", npart, dp); + while (!stat64(dpart, &s)) { + sprintf(dpart, "%s_%d.ts", npart, ++dp); + } +} + +int compare_book(const void *x, const void *y) +{ + struct mybook * px, * py; + int dx, dy; + px = (struct mybook*) x; + py = (struct mybook*) y; + dx = px->pos / (off64_t) 1024; + dy = py->pos / (off64_t) 1024; + int res = dx - dy; +//printf("SORT: %lld and %lld res %d\n", px->pos, py->pos, res); + return res; +} + +static int get_input(bool * stop) +{ + neutrino_msg_data_t data; + neutrino_msg_t msg; + int retval = 0; + * stop = false; + g_RCInput->getMsg(&msg, &data, 1, false); + if(msg == CRCInput::RC_home) { + if(ShowMsgUTF (LOCALE_MESSAGEBOX_INFO, "Cancel movie cut/split ?", CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo) == CMessageBox::mbrYes) { + * stop = true; + } + } + if(msg != CRCInput::RC_timeout) + retval |= 1; + if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) + retval |= 2; +//printf("input: msg %d (%x) ret %d\n", msg, msg, retval); + return retval; +} + +static off64_t cut_movie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie) +{ + struct mybook books[MI_MOVIE_BOOK_USER_MAX+2]; + int bcount = 0; + int dstfd, srcfd; + int part = 0; + struct stat64 s; + char spart[255]; + char dpart[255]; + char npart[255]; + unsigned char * buf; + unsigned char psi[PSI_SIZE]; + int r, i; + off64_t sdone, spos; + off64_t newsize; + time_t tt; + int percent = 0; + char * name = (char *) minfo->file.Name.c_str(); + CFile file; + MI_MOVIE_INFO ninfo; + bool need_gop = 0; + off64_t tdone = 0; + int was_cancel = 0; + int retval = 0; + time_t tt1; + off64_t bpos, bskip; + + buf = (unsigned char *) malloc(BUF_SIZE); + if(buf == 0) { + perror("malloc"); + return 0; + } + + CFrameBuffer * frameBuffer = CFrameBuffer::getInstance(); + if(!timescale) + timescale = new CScale(200, 15, 0, 100, 0); + int dx = 256; + int x = (((g_settings.screen_EndX- g_settings.screen_StartX)- dx) / 2) + g_settings.screen_StartX; + int y = g_settings.screen_EndY - 50; + frameBuffer->paintBoxRel (x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0); + timescale->paint(x + 41, y + 12, percent); + int len = minfo->length; + off64_t size = minfo->file.Size; + //off64_t secsize = len ? size/len/60 : 511040; + off64_t minuteoffset = len ? size / len : MINUTEOFFSET; + minuteoffset = (minuteoffset / MP_TS_SIZE) * MP_TS_SIZE; + if(minuteoffset < 5000000 || minuteoffset > 190000000) + minuteoffset = MINUTEOFFSET; + off64_t secsize = minuteoffset/60; + newsize = size; + + if(minfo->bookmarks.start != 0) { + books[bcount].pos = 0; + books[bcount].len = (minfo->bookmarks.start * secsize)/188 * 188; + if(books[bcount].len > SAFE_GOP) + books[bcount].len -= SAFE_GOP; + books[bcount].ok = 1; +printf("cut: start bookmark %d at %lld len %lld\n", bcount, books[bcount].pos, books[bcount].len); + bcount++; + } + for(int book_nr = 0; book_nr < MI_MOVIE_BOOK_USER_MAX; book_nr++) { + if( minfo->bookmarks.user[book_nr].pos != 0 && minfo->bookmarks.user[book_nr].length > 0 ) { + books[bcount].pos = (minfo->bookmarks.user[book_nr].pos * secsize)/188 * 188; + books[bcount].len = (minfo->bookmarks.user[book_nr].length * secsize)/188 * 188; + if(books[bcount].len > SAFE_GOP) + books[bcount].len -= SAFE_GOP; + books[bcount].ok = 1; +printf("cut: jump bookmark %d at %lld len %lld -> skip to %lld\n", bcount, books[bcount].pos, books[bcount].len, books[bcount].pos+books[bcount].len); + bcount++; + } + } + if(minfo->bookmarks.end != 0) { + books[bcount].pos = ((off64_t) minfo->bookmarks.end * secsize)/188 * 188; + books[bcount].len = size - books[bcount].pos; + //if(books[bcount].pos > SAFE_GOP) + // books[bcount].pos -= SAFE_GOP; + books[bcount].ok = 1; +printf("cut: end bookmark %d at %lld\n", bcount, books[bcount].pos); + bcount++; + } +printf("\n"); + if(!bcount) return 0; + qsort(books, bcount, sizeof(struct mybook), compare_book); + for(i = 0; i < bcount; i++) { + if(books[i].ok) { + printf("cut: bookmark %d at %lld len %lld -> skip to %lld\n", i, books[i].pos, books[i].len, books[i].pos+books[i].len); + newsize -= books[i].len; + off64_t curend = books[i].pos + books[i].len; + for(int j = i + 1; j < bcount; j++) { + if((books[j].pos > books[i].pos) && (books[j].pos < curend)) { + off64_t newend = books[j].pos + books[j].len; + if(newend > curend) { + printf("cut: bad bookmark %d, position %lld len %lld, ajusting..\n", j, books[j].pos, books[j].len); + books[j].pos = curend; + books[j].len = newend - curend; + } else { + printf("cut: bad bookmark %d, position %lld len %lld, skipping..\n", j, books[j].pos, books[j].len); + books[j].ok = 0; + } + } + } + } + } + sprintf(npart, "%s", name); + char * ptr = strstr(npart, ".ts"); + if(ptr) + *ptr = 0; + find_new_part(npart, dpart); +tt = time(0); +printf("\n********* new file %s expected size %lld, start time %s", dpart, newsize, ctime (&tt)); + dstfd = open (dpart, O_CREAT|O_WRONLY|O_TRUNC| O_LARGEFILE); + if(dstfd < 0) { + perror(dpart); + return 0; + } + part = 0; + i = 0; + off64_t offset = 0; + spos = 0; + sprintf(spart, "%s", name); + if(read_psi(spart, &psi[0])) { + perror(spart); + goto ret_err; + } + write(dstfd, psi, PSI_SIZE); + bpos = books[i].pos; + bskip = books[i].len; + while (!stat64(spart, &s)) { +printf("cut: open part %d file %s size %lld offset %lld book pos %lld\n", part, spart, s.st_size, offset, bpos); + srcfd = open (spart, O_RDONLY | O_LARGEFILE); + if(srcfd < 0) { + perror(spart); + goto ret_err; + } + if(offset >= s.st_size) { + offset -= s.st_size; + bpos -= s.st_size; + goto next_file; + } + lseek64 (srcfd, offset, SEEK_SET); + sdone = offset; + while(true) { + off64_t until = bpos; +printf("\ncut: reading from %lld to %lld (%lld) want gop %d\n", sdone, until, until - sdone, need_gop); + while(sdone < until) { + bool stop; + int msg = get_input(&stop); + was_cancel = msg & 2; + if(stop) { + close(srcfd); + unlink(dpart); + retval = 1; + goto ret_err; + } + if(msg) { + timescale->reset(); + frameBuffer->paintBoxRel (x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0); + } + size_t toread = (until-sdone) > BUF_SIZE ? BUF_SIZE : until - sdone; +#if REAL_CUT + r = read (srcfd, buf, toread); +#else + r = fake_read (srcfd, buf, toread, s.st_size); +#endif + if(r > 0) { + int wptr = 0; +// FIXME: TEST +if(r != BUF_SIZE) printf("****** short read ? %d\n", r); +if(buf[0] != 0x47) printf("cut: buffer not aligned at %lld\n", sdone); + if(need_gop) { + int gop = find_gop(buf, r); + if(gop >= 0) { + printf("cut: GOP found at %lld offset %d\n", (off64_t)(sdone+gop), gop); + newsize -= gop; + wptr = gop; + } else + printf("cut: GOP needed, but not found\n"); + need_gop = 0; + } + sdone += r; + spos += r - wptr; + percent = (int) ((float)(spos)/(float)(newsize)*100.); + timescale->paint(x + 41, y + 12, percent); +#if REAL_CUT + int wr = write(dstfd, &buf[wptr], r-wptr); + if(wr < (r-wptr)) { + perror(dpart); + close(srcfd); + goto ret_err; + } +#endif + } else if(sdone < s.st_size) { + /* read error ? */ + close(srcfd); + perror(spart); + goto ret_err; + } else { +printf("cut: next file -> sdone %lld spos %lld bpos %lld\n", sdone, spos, bpos); + offset = 0; + bpos -= sdone; + goto next_file; + } + } +printf("cut: current file pos %lld write pos %lld book pos %lld still to read %lld\n", sdone, spos, bpos, sdone - bpos); + need_gop = 1; + offset = bpos + bskip; + i++; + while(i < bcount) { + if(books[i].ok) + break; + else + i++; + } + if(i < bcount) { + bpos = books[i].pos; + bskip = books[i].len; + } else + bpos = size; +printf("cut: next bookmark pos: %lld abs %lld relative next file pos %lld cur file size %lld\n", bpos, bpos - tdone, offset, s.st_size); + bpos -= tdone; /* all books from 0, converting to 0 + total size skipped */ + if(offset >= s.st_size) { + offset -= s.st_size; + bpos -= s.st_size; + goto next_file; + } + lseek64 (srcfd, offset, SEEK_SET); + sdone = offset; + } +next_file: + tdone += s.st_size; + close(srcfd); + sprintf(spart, "%s.%03d", name, ++part); + } + tt1 = time(0); +printf("********* total written %lld tooks %ld secs end time %s", spos, tt1-tt, ctime (&tt1)); + + save_info(cmovie, minfo, dpart, spos, secsize); + retval = 1; + lseek64 (dstfd, 0, SEEK_SET); +ret_err: + close(dstfd); + free(buf); + if(was_cancel) + g_RCInput->postMsg(CRCInput::RC_home, 0); + return retval; +} + +static off64_t copy_movie(MI_MOVIE_INFO * minfo, CMovieInfo * cmovie, bool onefile) +{ + struct mybook books[MI_MOVIE_BOOK_USER_MAX+2]; + int bcount = 0; + int dstfd = -1, srcfd; + int part = 0; + struct stat64 s; + char spart[255]; + char dpart[255]; + char npart[255]; + unsigned char * buf; + unsigned char psi[PSI_SIZE]; + int r, i; + off64_t sdone, spos = 0, btotal = 0; + off64_t newsize; + time_t tt; + int percent = 0; + char * name = (char *) minfo->file.Name.c_str(); + CFile file; + bool need_gop = 0; + bool dst_done = 0; + bool was_cancel; + int retval = 0; + + buf = (unsigned char *) malloc(BUF_SIZE); + if(buf == 0) { + perror("malloc"); + return 0; + } + + int len = minfo->length; + off64_t size = minfo->file.Size; + off64_t minuteoffset = len ? size / len : MINUTEOFFSET; + minuteoffset = (minuteoffset / MP_TS_SIZE) * MP_TS_SIZE; + if(minuteoffset < 5000000 || minuteoffset > 190000000) + minuteoffset = MINUTEOFFSET; + off64_t secsize = minuteoffset/60; + //off64_t secsize = len ? size/len/60 : 511040; +printf("copy: len %d minute %lld second %lld\n", len, len ? size/len : 511040*60, secsize); + + CFrameBuffer * frameBuffer = CFrameBuffer::getInstance(); + if(!timescale) + timescale = new CScale(200, 15, 0, 100, 0); + int dx = 256; + int x = (((g_settings.screen_EndX- g_settings.screen_StartX)- dx) / 2) + g_settings.screen_StartX; + int y = g_settings.screen_EndY - 50; + frameBuffer->paintBoxRel (x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0); + timescale->paint(x + 41, y + 12, percent); + + newsize = 0; + for(int book_nr = 0; book_nr < MI_MOVIE_BOOK_USER_MAX; book_nr++) { + if( minfo->bookmarks.user[book_nr].pos != 0 && minfo->bookmarks.user[book_nr].length > 0 ) { + books[bcount].pos = (minfo->bookmarks.user[book_nr].pos * secsize)/188 * 188; + if(books[bcount].pos > SAFE_GOP) + books[bcount].pos -= SAFE_GOP; + books[bcount].len = (minfo->bookmarks.user[book_nr].length * secsize)/188 * 188; + books[bcount].ok = 1; +printf("copy: jump bookmark %d at %lld len %lld\n", bcount, books[bcount].pos, books[bcount].len); + newsize += books[bcount].len; + bcount++; + } + } + if(!bcount) return 0; + +tt = time(0); +printf("********* %d boormarks, to %s file(s), expected size to copy %lld, start time %s", bcount, onefile ? "one" : "many", newsize, ctime (&tt)); + sprintf(npart, "%s", name); + char * ptr = strstr(npart, ".ts"); + if(ptr) + *ptr = 0; + sprintf(spart, "%s", name); + srcfd = open (spart, O_RDONLY | O_LARGEFILE); + if(read_psi(spart, &psi[0])) { + perror(spart); + goto ret_err; + } + for(i = 0; i < bcount; i++) { +printf("\ncopy: processing bookmark %d at %lld len %lld\n", i, books[i].pos, books[i].len); + off64_t bpos = books[i].pos; + off64_t bskip = books[i].len; + part = 0; + sprintf(spart, "%s", name); + int sres; + while (!(sres = stat64(spart, &s))) { + if(bpos >= s.st_size) { + bpos -= s.st_size; + sprintf(spart, "%s.%03d", name, ++part); +//printf("copy: check src part %s\n", spart); + continue; + } + break; + } + if(sres != 0) { + printf("file for bookmark %d with offset %lld not found\n", i, books[i].pos); + continue; + } + if(!dst_done || !onefile) { + find_new_part(npart, dpart); + dstfd = open (dpart, O_CREAT|O_WRONLY|O_TRUNC| O_LARGEFILE); +printf("copy: new file %s fd %d\n", dpart, dstfd); + if(dstfd < 0) { + printf("failed to open %s\n", dpart); + goto ret_err;; + } + dst_done = 1; + spos = 0; + write(dstfd, psi, PSI_SIZE); + } + need_gop = 1; +next_file: + stat64(spart, &s); +printf("copy: open part %d file %s size %lld offset %lld\n", part, spart, s.st_size, bpos); + srcfd = open (spart, O_RDONLY | O_LARGEFILE); + if(srcfd < 0) { + printf("failed to open %s\n", spart); + close(dstfd); + goto ret_err; + } + lseek64 (srcfd, bpos, SEEK_SET); + sdone = bpos; + off64_t until = bpos + bskip; +printf("copy: read from %lld to %lld read size %d want gop %d\n", bpos, until, BUF_SIZE, need_gop); + while(sdone < until) { + size_t toread = (until-sdone) > BUF_SIZE ? BUF_SIZE : until - sdone; + bool stop; + int msg = get_input(&stop); + was_cancel = msg & 2; + if(stop) { + close(srcfd); + close(dstfd); + unlink(dpart); + retval = 1; + goto ret_err; + } + if(msg) { + frameBuffer->paintBoxRel (x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0); + timescale->reset(); + } +#if REAL_CUT + r = read (srcfd, buf, toread); +#else + r = fake_read (srcfd, buf, toread, s.st_size); +#endif + if(r > 0) { + int wptr = 0; +// FIXME: TEST +if(r != BUF_SIZE) printf("****** short read ? %d\n", r); +if(buf[0] != 0x47) printf("copy: buffer not aligned at %lld\n", sdone); + if(need_gop) { + int gop = find_gop(buf, r); + if(gop >= 0) { + printf("cut: GOP found at %lld offset %d\n", (off64_t)(sdone+gop), gop); + newsize -= gop; + wptr = gop; + } else + printf("cut: GOP needed, but not found\n"); + need_gop = 0; + } + sdone += r; + bskip -= r; + spos += r - wptr; + btotal += r; + percent = (int) ((float)(btotal)/(float)(newsize)*100.); + timescale->paint(x + 41, y + 12, percent); +#if REAL_CUT + int wr = write(dstfd, &buf[wptr], r-wptr); + if(wr < (r-wptr)) { + printf("write to %s failed\n", dpart); + close(srcfd); + close(dstfd); + goto ret_err; + } +#endif + } else if(sdone < s.st_size) { + /* read error ? */ + printf("%s: read failed\n", spart); + close(srcfd); + close(dstfd); + goto ret_err; + } else { +printf("copy: -> next file, file pos %lld written %lld left %lld\n", sdone, spos, bskip); + bpos = 0; + close(srcfd); + sprintf(spart, "%s.%03d", name, ++part); + goto next_file; + } + } /* while(sdone < until) */ + close(srcfd); + + if(!onefile) { + close(dstfd); + save_info(cmovie, minfo, dpart, spos, secsize); +time_t tt1 = time(0); +printf("copy: ********* %s: total written %lld took %ld secs\n", dpart, spos, tt1-tt); + } + } /* for all books */ + if(onefile) { + close(dstfd); + save_info(cmovie, minfo, dpart, spos, secsize); +time_t tt1 = time(0); +printf("copy: ********* %s: total written %lld took %ld secs\n", dpart, spos, tt1-tt); + } + retval = 1; +ret_err: + free(buf); + if(was_cancel) + g_RCInput->postMsg(CRCInput::RC_home, 0); + return retval; +} diff --git a/src/gui/moviebrowser.h b/src/gui/moviebrowser.h new file mode 100644 index 000000000..5dce329f4 --- /dev/null +++ b/src/gui/moviebrowser.h @@ -0,0 +1,709 @@ +/*************************************************************************** + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + $Id: moviebrowser.h,v 1.5 2006/09/11 21:11:35 guenther Exp $ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + *********************************************************** + + Module Name: moviebrowser.h . + + Description: implementation of the CMovieBrowser class + + Date: Nov 2005 + + Author: Günther@tuxbox.berlios.org + based on code of Steffen Hehn 'McClean' + + $Log: moviebrowser.h,v $ + Revision 1.5 2006/09/11 21:11:35 guenther + General menu clean up + Dir menu updated + Add options menu + In movie info menu "update all" added + Serie option added (hide serie, auto serie) + Update movie info on delete movie + Delete Background when menu is entered + Timeout updated (MB does not exit after options menu is left) + + Revision 1.4 2006/02/20 01:10:34 guenther + - temporary parental lock updated - remove 1s debug prints in movieplayer- Delete file without rescan of movies- Crash if try to scroll in list with 2 movies only- UTF8XML to UTF8 conversion in preview- Last file selection recovered- use of standard folders adjustable in config- reload and remount option in config + + Revision 1.3 2005/12/18 09:23:53 metallica + fix compil warnings + + Revision 1.2 2005/12/12 07:58:02 guenther + - fix bug on deleting CMovieBrowser - speed up parse time (20 ms per .ts file now)- update stale function- refresh directories on reload- print scan time in debug console + + +****************************************************************************/ +#ifndef MOVIEBROWSER_H_ +#define MOVIEBROWSER_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include "gui/widget/listframe.h" +#include "gui/widget/menue.h" +#include "gui/widget/textbox.h" +#include "gui/movieinfo.h" +#include "driver/file.h" +#include +#include "driver/pictureviewer/pictureviewer.h" + +#define MAX_NUMBER_OF_BOOKMARK_ITEMS MI_MOVIE_BOOK_USER_MAX // we just use the same size as used in Movie info (MAX_NUMBER_OF_BOOKMARK_ITEMS is used for the number of menu items) +#define MOVIEBROWSER_SETTINGS_FILE CONFIGDIR "/moviebrowser.conf" + +#define MIN_BROWSER_FRAME_HEIGHT 100 +#define MAX_BROWSER_FRAME_HEIGHT 400 +/* !!!! Do NOT change the order of the enum, just add items at the end !!!! */ +typedef enum +{ + MB_INFO_FILENAME = 0, + MB_INFO_FILEPATH = 1, + MB_INFO_TITLE = 2, + MB_INFO_SERIE = 3, + MB_INFO_INFO1 = 4, + MB_INFO_MAJOR_GENRE = 5, + MB_INFO_MINOR_GENRE = 6, + MB_INFO_INFO2 = 7, + MB_INFO_PARENTAL_LOCKAGE = 8, + MB_INFO_CHANNEL = 9, + MB_INFO_BOOKMARK = 10, + MB_INFO_QUALITY = 11, + MB_INFO_PREVPLAYDATE = 12, + MB_INFO_RECORDDATE = 13, + MB_INFO_PRODDATE = 14, + MB_INFO_COUNTRY = 15, + MB_INFO_GEOMETRIE = 16, + MB_INFO_AUDIO = 17, + MB_INFO_LENGTH = 18, + MB_INFO_SIZE = 19, + MB_INFO_MAX_NUMBER = 20 // MUST be allways the last item in the list +}MB_INFO_ITEM; + + + +typedef enum +{ + MB_DIRECTION_AUTO = 0, + MB_DIRECTION_UP = 1, + MB_DIRECTION_DOWN = 2, + MB_DIRECTION_MAX_NUMBER = 3 // MUST be allways the last item in the list +}MB_DIRECTION; + +typedef struct +{ + MB_INFO_ITEM item; + MB_DIRECTION direction; +}MB_SORTING; + +typedef enum +{ + MB_STORAGE_TYPE_UNDEFINED = 0, + MB_STORAGE_TYPE_NFS = 1, + MB_STORAGE_TYPE_VLC = 2, + MB_STORAGE_MAX_NUMBER = 3 // MUST be allways the last item in the list +}MB_STORAGE_TYPE; + +typedef struct +{ + MB_INFO_ITEM item; + std::string optionString; + int optionVar; +}MB_FILTER; + +typedef enum +{ + MB_FOCUS_BROWSER = 0, + MB_FOCUS_LAST_PLAY = 1, + MB_FOCUS_LAST_RECORD = 2, + MB_FOCUS_MOVIE_INFO = 3, + MB_FOCUS_FILTER = 4, + MB_FOCUS_MAX_NUMBER = 5 // MUST be allways the last item in the list +}MB_FOCUS; + +typedef enum +{ + MB_GUI_BROWSER_ONLY = 0, + MB_GUI_MOVIE_INFO = 1, + MB_GUI_LAST_PLAY = 2, + MB_GUI_LAST_RECORD = 3, + MB_GUI_FILTER = 4, + MB_GUI_MAX_NUMBER = 5 // MUST be allways the last item in the list +}MB_GUI; + + +typedef enum +{ + MB_PARENTAL_LOCK_OFF = 0, + MB_PARENTAL_LOCK_ACTIVE = 1, + MB_PARENTAL_LOCK_OFF_TMP = 2, // use this to activate the lock temporarily until next dbox start up + MB_PARENTAL_LOCK_MAX_NUMBER = 3 // MUST be allways the last item in the list +}MB_PARENTAL_LOCK; + +typedef struct +{ + std::string name; + int* used; +}MB_DIR; + +#define MB_MAX_ROWS 6 +#define MB_MAX_DIRS 5 +/* MB_SETTINGS to be stored in g_settings anytime ....*/ +typedef struct +{ + // moviebrowser + MB_GUI gui; //MB_GUI + MB_SORTING sorting; //MB_SORTING + MB_FILTER filter;//MB_FILTER + MI_PARENTAL_LOCKAGE parentalLockAge ;//MI_PARENTAL_LOCKAGE + MB_PARENTAL_LOCK parentalLock;//MB_PARENTAL_LOCK + + std::string storageDir[MB_MAX_DIRS]; + int storageDirUsed[MB_MAX_DIRS]; + int storageDirRecUsed; + int storageDirMovieUsed; + + int reload; + int remount; + + int browser_serie_mode; + int serie_auto_create; + /* these variables are used for the listframes */ + int browserFrameHeight; + int browserRowNr; + MB_INFO_ITEM browserRowItem[MB_MAX_ROWS];//MB_INFO_ITEM + int browserRowWidth[MB_MAX_ROWS]; + + // to be added to config later + int lastPlayMaxItems; + int lastPlayRowNr; + MB_INFO_ITEM lastPlayRow[MB_MAX_ROWS]; + int lastPlayRowWidth[MB_MAX_ROWS]; + + int lastRecordMaxItems; + int lastRecordRowNr; + MB_INFO_ITEM lastRecordRow[MB_MAX_ROWS]; + int lastRecordRowWidth[MB_MAX_ROWS]; +}MB_SETTINGS; + +// Priorities for Developmemt: P1: critical feature, P2: important feature, P3: for next release, P4: looks nice, lets see +class CMovieBrowser : public CMenuTarget +{ + public: // Variables ///////////////////////////////////////////////// + int Multi_Select; // for FileBrowser compatibility, not used in MovieBrowser + int Dirs_Selectable; // for FileBrowser compatibility, not used in MovieBrowser + + private: // Variables + //CFBWindow* m_pcWindow; + CFrameBuffer * m_pcWindow; + + CListFrame* m_pcBrowser; + CListFrame* m_pcLastPlay; + CListFrame* m_pcLastRecord; + CTextBox* m_pcInfo; + CListFrame* m_pcFilter; + + CBox m_cBoxFrame; + CBox m_cBoxFrameLastPlayList; + CBox m_cBoxFrameLastRecordList; + CBox m_cBoxFrameBrowserList; + CBox m_cBoxFrameInfo; + CBox m_cBoxFrameBookmarkList; + CBox m_cBoxFrameFilter; + CBox m_cBoxFrameFootRel; + CBox m_cBoxFrameTitleRel; + + LF_LINES m_browserListLines; + LF_LINES m_recordListLines; + LF_LINES m_playListLines; + LF_LINES m_FilterLines; + + std::vector m_vMovieInfo; + std::vector m_vHandleBrowserList; + std::vector m_vHandleRecordList; + std::vector m_vHandlePlayList; + std::vector m_dirNames; +// std::vector m_serienames; + std::vector m_vHandleSerienames; + + unsigned int m_currentBrowserSelection; + unsigned int m_currentRecordSelection; + unsigned int m_currentPlaySelection; + unsigned int m_currentFilterSelection; + unsigned int m_prevBrowserSelection; + unsigned int m_prevRecordSelection; + unsigned int m_prevPlaySelection; + + bool m_showBrowserFiles; + bool m_showLastRecordFiles; + bool m_showLastPlayFiles; + bool m_showMovieInfo; + bool m_showFilter; + + MI_MOVIE_INFO* m_movieSelectionHandler; + int m_currentStartPos; + std::string m_selectedDir; + MB_FOCUS m_windowFocus; + + bool m_file_info_stale; // if this bit is set, MovieBrowser shall reload all movie infos from HD + bool m_seriename_stale; + + Font* m_pcFontFoot; + Font* m_pcFontTitle; + std::string m_textTitle; + + MB_PARENTAL_LOCK m_parentalLock; + MB_STORAGE_TYPE m_storageType; + + CConfigFile configfile; + CMovieInfo m_movieInfo; + MB_SETTINGS m_settings; + std::vector m_dir; + + int movieInfoUpdateAll[MB_INFO_MAX_NUMBER]; + int movieInfoUpdateAllIfDestEmptyOnly; + + //bool restart_mb_timeout; + + public: // Functions //////////////////////////////////////////////////////////7 + CMovieBrowser(const char* path); //P1 + CMovieBrowser(); //P1 + ~CMovieBrowser(); //P1 + int exec(const char* path); //P1 + int exec(CMenuTarget* parent, const std::string & actionKey); + std::string getCurrentDir(void); //P1 for FileBrowser compatibility + CFile* getSelectedFile(void); //P1 for FileBrowser compatibility + MI_MOVIE_BOOKMARKS* getCurrentMovieBookmark(void){if(m_movieSelectionHandler == NULL) return NULL; return(&(m_movieSelectionHandler->bookmarks));}; + int getCurrentStartPos(void){return(m_currentStartPos);}; //P1 return start position in [s] + MI_MOVIE_INFO* getCurrentMovieInfo(void){return(m_movieSelectionHandler);}; //P1 return start position in [s] + void fileInfoStale(void); // call this function to force the Moviebrowser to reload all movie information from HD + + bool readDir(const std::string & dirname, CFileList* flist); + bool readDir_vlc(const std::string & dirname, CFileList* flist); + bool readDir_std(const std::string & dirname, CFileList* flist); + + bool delFile(CFile& file); + bool delFile_vlc(CFile& file); + bool delFile_std(CFile& file); + + private: //Functions + ///// MovieBrowser init /////////////// + void init(void); //P1 + void initGlobalSettings(void); //P1 + void initFrames(void); + void initDevelopment(void); //P1 for development testing only + void initRows(void); + void reinit(void); //P1 + + ///// MovieBrowser Main Window////////// + int paint(void); //P1 + void refresh(void); //P1 + void hide(void); //P1 + void refreshLastPlayList(void); //P2 + void refreshLastRecordList(void); //P2 + void refreshBrowserList(void); //P1 + void refreshFilterList(void); //P1 + void refreshMovieInfo(void); //P1 + void refreshBookmarkList(void); // P3 + void refreshFoot(void); //P2 + void refreshTitle(void); //P2 + void refreshInfo(void); // P2 + void refreshLCD(void); // P2 + + ///// Events /////////////////////////// + bool onButtonPress(neutrino_msg_t msg); // P1 + bool onButtonPressMainFrame(neutrino_msg_t msg); // P1 + bool onButtonPressBrowserList(neutrino_msg_t msg); // P1 + bool onButtonPressLastPlayList(neutrino_msg_t msg); // P2 + bool onButtonPressLastRecordList(neutrino_msg_t msg); // P2 + bool onButtonPressFilterList(neutrino_msg_t msg); // P2 + bool onButtonPressBookmarkList(neutrino_msg_t msg); // P3 + bool onButtonPressMovieInfoList(neutrino_msg_t msg); // P2 + void onSetFocus(MB_FOCUS new_focus); // P2 + void onSetFocusNext(void); // P2 + void onSetFocusPrev(void); // P2 + void onSetGUIWindow(MB_GUI gui); + void onSetGUIWindowNext(void); + void onSetGUIWindowPrev(void); + void onDeleteFile(MI_MOVIE_INFO& movieSelectionHandler); // P4 + bool onSortMovieInfoHandleList(std::vector& pv_handle_list, MB_INFO_ITEM sort_type, MB_DIRECTION direction); + + ///// parse Storage Directories ///////////// + bool addDir(std::string& dirname, int* used); + void updateDir(void); + void loadAllTsFileNamesFromStorage(void); // P1 + bool loadTsFileNamesFromDir(const std::string & dirname); // P1 + void getStorageInfo(void); // P3 + + ///// Menu //////////////////////////////////// + bool showMenu(MI_MOVIE_INFO* movie_info); // P2 + void showMovieInfoMenu(MI_MOVIE_INFO* movie_info); // P2 + int showStartPosSelectionMenu(void); // P2 + + ///// settings /////////////////////////////////// + bool loadSettings(MB_SETTINGS* settings); // P2 + bool saveSettings(MB_SETTINGS* settings); // P2 + void defaultSettings(MB_SETTINGS* settings); + + ///// EPG_DATA /XML /////////////////////////////// + void loadMovies(); + void loadAllMovieInfo(void); // P1 + void saveMovieInfo(std::string* filename, MI_MOVIE_INFO* movie_info); // P2 + + // misc + void showHelp(void); + bool isFiltered(MI_MOVIE_INFO& movie_info); + bool isParentalLock(MI_MOVIE_INFO& movie_info); + bool getMovieInfoItem(MI_MOVIE_INFO& movie_info, MB_INFO_ITEM item, std::string* item_string); + void updateMovieSelection(void); + void updateFilterSelection(void); + void updateSerienames(void); + void autoFindSerie(void); +}; + +// Class to show Moviebrowser Information, to be used by menu +class CMovieHelp : public CMenuTarget +{ + private: + + public: + CMovieHelp(){}; + ~CMovieHelp(){}; + int exec( CMenuTarget* parent, const std::string & actionKey ); +}; + +// I tried a lot to use the menu.cpp as ListBox selection, and I got three solution which are all garbage. +//Might be replaced by somebody who is familiar with this stuff . + +// CLass to verifiy a menu was selected by the user. There might be better ways to do so. +class CSelectedMenu : public CMenuTarget +{ + public: + bool selected; + CSelectedMenu(void){selected = false;}; +inline int exec(CMenuTarget* parent, const std::string & actionKey){selected = true; return menu_return::RETURN_EXIT;}; +}; + + +// This Class creates a menue item, which writes its caption to an given string (or an given int value to an given variable). +// The programm could use this class to verify, what menu was selected. +// A good listbox class might do the same. There might be better ways to do so. +#define BUFFER_MAX 20 +class CMenuSelector : public CMenuItem +{ + private: + const char * optionName; + char * optionValue; + std::string* optionValueString; + int returnIntValue; + int* returnInt; + int height; + char buffer[BUFFER_MAX]; + public: + CMenuSelector(const char * OptionName, const bool Active = true, char * OptionValue = NULL, int* ReturnInt = NULL,int ReturnIntValue = 0); + CMenuSelector(const char * OptionName, const bool Active , std::string & OptionValue, int* ReturnInt = NULL,int ReturnIntValue = 0); + int exec(CMenuTarget* parent); + int paint(bool selected, bool last = 0); + int getHeight(void) const{return height;}; + bool isSelectable(void) const { return active;} +}; + +// CLass to get the menu line selected by the user. There might be better ways to do so. +class CMenuWidgetSelection : public CMenuWidget +{ + public: + CMenuWidgetSelection(const neutrino_locale_t Name, const std::string & Icon = "", const int mwidth = 400, const int mheight = 576) : CMenuWidget( Name,Icon,mwidth, mheight){;}; + int getSelectedLine(void){return exit_pressed ? -1 : selected;}; +}; + + +class CFileChooser : public CMenuWidget +{ + private: + std::string* dirPath; + + public: + CFileChooser(std::string* path){dirPath= path;}; + int exec(CMenuTarget* parent, const std::string & actionKey); + }; + +typedef enum +{ + DIR_STATE_UNKNOWN = 0, + DIR_STATE_SERVER_DOWN = 1, + DIR_STATE_NOT_MOUNTED = 2, + DIR_STATE_MOUNTED = 3, + DIR_STATE_DISABLED = 4 +}DIR_STATE; + +#define MAX_DIR 10 +class CDirMenu : public CMenuWidget +{ + private: + std::vector* dirList; + DIR_STATE dirState[MAX_DIR]; + std::string dirOptionText[MAX_DIR]; + int dirNfsMountNr[MAX_DIR]; + bool changed; + + void updateDirState(void); + + public: + CDirMenu(std::vector* dir_list); + int exec(CMenuTarget* parent, const std::string & actionKey); + void show(void); + bool isChanged(){return changed;}; + }; + + +// EPG Genre , taken from epgview, TODO: migth be splitted in major/minor to increase handling, might be moved to CMovieInfo +#define GENRE_ALL_COUNT 76 +const CMenuOptionChooser::keyval GENRE_ALL[GENRE_ALL_COUNT] = +{ + { 0x00, LOCALE_GENRE_UNKNOWN}, + { 0x10, LOCALE_GENRE_MOVIE_0}, + { 0x11, LOCALE_GENRE_MOVIE_1}, + { 0x12, LOCALE_GENRE_MOVIE_2}, + { 0x13, LOCALE_GENRE_MOVIE_3}, + { 0x14, LOCALE_GENRE_MOVIE_4}, + { 0x15, LOCALE_GENRE_MOVIE_5}, + { 0x16, LOCALE_GENRE_MOVIE_6}, + { 0x17, LOCALE_GENRE_MOVIE_7}, + { 0x18, LOCALE_GENRE_MOVIE_8}, + { 0x20, LOCALE_GENRE_NEWS_0}, + { 0x21, LOCALE_GENRE_NEWS_1}, + { 0x22, LOCALE_GENRE_NEWS_2}, + { 0x23, LOCALE_GENRE_NEWS_3}, + { 0x24, LOCALE_GENRE_NEWS_4}, + { 0x30, LOCALE_GENRE_SHOW_0}, + { 0x31, LOCALE_GENRE_SHOW_1}, + { 0x32, LOCALE_GENRE_SHOW_2}, + { 0x33, LOCALE_GENRE_SHOW_3}, + { 0x40, LOCALE_GENRE_SPORTS_0}, + { 0x41, LOCALE_GENRE_SPORTS_1}, + { 0x42, LOCALE_GENRE_SPORTS_2}, + { 0x43, LOCALE_GENRE_SPORTS_3}, + { 0x44, LOCALE_GENRE_SPORTS_4}, + { 0x45, LOCALE_GENRE_SPORTS_5}, + { 0x46, LOCALE_GENRE_SPORTS_6}, + { 0x47, LOCALE_GENRE_SPORTS_7}, + { 0x48, LOCALE_GENRE_SPORTS_8}, + { 0x49, LOCALE_GENRE_SPORTS_9}, + { 0x4A, LOCALE_GENRE_SPORTS_10}, + { 0x4B, LOCALE_GENRE_SPORTS_11}, + { 0x50, LOCALE_GENRE_CHILDRENS_PROGRAMMES_0}, + { 0x51, LOCALE_GENRE_CHILDRENS_PROGRAMMES_1}, + { 0x52, LOCALE_GENRE_CHILDRENS_PROGRAMMES_2}, + { 0x53, LOCALE_GENRE_CHILDRENS_PROGRAMMES_3}, + { 0x54, LOCALE_GENRE_CHILDRENS_PROGRAMMES_4}, + { 0x55, LOCALE_GENRE_CHILDRENS_PROGRAMMES_5}, + { 0x60, LOCALE_GENRE_MUSIC_DANCE_0}, + { 0x61, LOCALE_GENRE_MUSIC_DANCE_1}, + { 0x62, LOCALE_GENRE_MUSIC_DANCE_2}, + { 0x63, LOCALE_GENRE_MUSIC_DANCE_3}, + { 0x64, LOCALE_GENRE_MUSIC_DANCE_4}, + { 0x65, LOCALE_GENRE_MUSIC_DANCE_5}, + { 0x66, LOCALE_GENRE_MUSIC_DANCE_6}, + { 0x70, LOCALE_GENRE_ARTS_0}, + { 0x71, LOCALE_GENRE_ARTS_1}, + { 0x72, LOCALE_GENRE_ARTS_2}, + { 0x73, LOCALE_GENRE_ARTS_3}, + { 0x74, LOCALE_GENRE_ARTS_4}, + { 0x75, LOCALE_GENRE_ARTS_5}, + { 0x76, LOCALE_GENRE_ARTS_6}, + { 0x77, LOCALE_GENRE_ARTS_7}, + { 0x78, LOCALE_GENRE_ARTS_8}, + { 0x79, LOCALE_GENRE_ARTS_9}, + { 0x7A, LOCALE_GENRE_ARTS_10}, + { 0x7B, LOCALE_GENRE_ARTS_11}, + { 0x80, LOCALE_GENRE_SOCIAL_POLITICAL_0}, + { 0x81, LOCALE_GENRE_SOCIAL_POLITICAL_1}, + { 0x82, LOCALE_GENRE_SOCIAL_POLITICAL_2}, + { 0x83, LOCALE_GENRE_SOCIAL_POLITICAL_3}, + { 0x90, LOCALE_GENRE_DOCUS_MAGAZINES_0}, + { 0x91, LOCALE_GENRE_DOCUS_MAGAZINES_1}, + { 0x92, LOCALE_GENRE_DOCUS_MAGAZINES_2}, + { 0x93, LOCALE_GENRE_DOCUS_MAGAZINES_3}, + { 0x94, LOCALE_GENRE_DOCUS_MAGAZINES_4}, + { 0x95, LOCALE_GENRE_DOCUS_MAGAZINES_5}, + { 0x96, LOCALE_GENRE_DOCUS_MAGAZINES_6}, + { 0x97, LOCALE_GENRE_DOCUS_MAGAZINES_7}, + { 0xA0, LOCALE_GENRE_TRAVEL_HOBBIES_0}, + { 0xA1, LOCALE_GENRE_TRAVEL_HOBBIES_1}, + { 0xA2, LOCALE_GENRE_TRAVEL_HOBBIES_2}, + { 0xA3, LOCALE_GENRE_TRAVEL_HOBBIES_3}, + { 0xA4, LOCALE_GENRE_TRAVEL_HOBBIES_4}, + { 0xA5, LOCALE_GENRE_TRAVEL_HOBBIES_5}, + { 0xA6, LOCALE_GENRE_TRAVEL_HOBBIES_6}, + { 0xA7, LOCALE_GENRE_TRAVEL_HOBBIES_7} +}; + +#define GENRE_MOVIE_COUNT 9 +const CMenuOptionChooser::keyval genre_movie[GENRE_MOVIE_COUNT] = +{ + { 0, LOCALE_GENRE_MOVIE_0}, + { 1, LOCALE_GENRE_MOVIE_1}, + { 2, LOCALE_GENRE_MOVIE_2}, + { 3, LOCALE_GENRE_MOVIE_3}, + { 4, LOCALE_GENRE_MOVIE_4}, + { 5, LOCALE_GENRE_MOVIE_5}, + { 6, LOCALE_GENRE_MOVIE_6}, + { 7, LOCALE_GENRE_MOVIE_7}, + { 8, LOCALE_GENRE_MOVIE_8} +}; +#define GENRE_NEWS_COUNT 5 +const CMenuOptionChooser::keyval genre_news[GENRE_NEWS_COUNT] = +{ + { 0, LOCALE_GENRE_NEWS_0}, + { 1, LOCALE_GENRE_NEWS_1}, + { 2, LOCALE_GENRE_NEWS_2}, + { 3, LOCALE_GENRE_NEWS_3}, + { 4, LOCALE_GENRE_NEWS_4} +}; +#define GENRE_SHOW_COUNT 4 +const CMenuOptionChooser::keyval genre_show[GENRE_SHOW_COUNT] = +{ + { 0, LOCALE_GENRE_SHOW_0}, + { 1, LOCALE_GENRE_SHOW_1}, + { 2, LOCALE_GENRE_SHOW_2}, + { 3, LOCALE_GENRE_SHOW_3} +}; +#define GENRE_SPORTS_COUNT 12 +const CMenuOptionChooser::keyval genre_sports[GENRE_SPORTS_COUNT] = +{ + { 0, LOCALE_GENRE_SPORTS_0}, + { 1, LOCALE_GENRE_SPORTS_1}, + { 2, LOCALE_GENRE_SPORTS_2}, + { 3, LOCALE_GENRE_SPORTS_3}, + { 4, LOCALE_GENRE_SPORTS_4}, + { 5, LOCALE_GENRE_SPORTS_5}, + { 6, LOCALE_GENRE_SPORTS_6}, + { 7, LOCALE_GENRE_SPORTS_7}, + { 8, LOCALE_GENRE_SPORTS_8}, + { 9, LOCALE_GENRE_SPORTS_9}, + {10, LOCALE_GENRE_SPORTS_10}, + {11, LOCALE_GENRE_SPORTS_11} +}; +#define GENRE_CHILDRENS_PROGRAMMES_COUNT 6 +const CMenuOptionChooser::keyval genre_childrens_programmes[GENRE_CHILDRENS_PROGRAMMES_COUNT] = +{ + { 0, LOCALE_GENRE_CHILDRENS_PROGRAMMES_0}, + { 1, LOCALE_GENRE_CHILDRENS_PROGRAMMES_1}, + { 2, LOCALE_GENRE_CHILDRENS_PROGRAMMES_2}, + { 3, LOCALE_GENRE_CHILDRENS_PROGRAMMES_3}, + { 4, LOCALE_GENRE_CHILDRENS_PROGRAMMES_4}, + { 5, LOCALE_GENRE_CHILDRENS_PROGRAMMES_5} +}; +#define GENRE_MUSIC_DANCE_COUNT 7 +const CMenuOptionChooser::keyval genre_music_dance[GENRE_MUSIC_DANCE_COUNT] = +{ + { 0, LOCALE_GENRE_MUSIC_DANCE_0}, + { 1, LOCALE_GENRE_MUSIC_DANCE_1}, + { 2, LOCALE_GENRE_MUSIC_DANCE_2}, + { 3, LOCALE_GENRE_MUSIC_DANCE_3}, + { 4, LOCALE_GENRE_MUSIC_DANCE_4}, + { 5, LOCALE_GENRE_MUSIC_DANCE_5}, + { 6, LOCALE_GENRE_MUSIC_DANCE_6} +}; +#define GENRE_ARTS_COUNT 12 +const CMenuOptionChooser::keyval genre_arts_dance[GENRE_ARTS_COUNT] = +{ + { 0, LOCALE_GENRE_ARTS_0}, + { 1, LOCALE_GENRE_ARTS_1}, + { 2, LOCALE_GENRE_ARTS_2}, + { 3, LOCALE_GENRE_ARTS_3}, + { 4, LOCALE_GENRE_ARTS_4}, + { 5, LOCALE_GENRE_ARTS_5}, + { 6, LOCALE_GENRE_ARTS_6}, + { 7, LOCALE_GENRE_ARTS_7}, + { 8, LOCALE_GENRE_ARTS_8}, + { 9, LOCALE_GENRE_ARTS_9}, + {10, LOCALE_GENRE_ARTS_10}, + {11, LOCALE_GENRE_ARTS_11} +}; +#define GENRE_SOCIAL_POLITICAL_COUNT 4 +const CMenuOptionChooser::keyval genre_social_political[GENRE_SOCIAL_POLITICAL_COUNT] = +{ + { 0, LOCALE_GENRE_SOCIAL_POLITICAL_0}, + { 1, LOCALE_GENRE_SOCIAL_POLITICAL_1}, + { 2, LOCALE_GENRE_SOCIAL_POLITICAL_2}, + { 3, LOCALE_GENRE_SOCIAL_POLITICAL_3} +}; +#define GENRE_DOCUS_MAGAZINES_COUNT 8 +const CMenuOptionChooser::keyval genre_docus_magazines[GENRE_DOCUS_MAGAZINES_COUNT] = +{ + { 0, LOCALE_GENRE_DOCUS_MAGAZINES_0}, + { 1, LOCALE_GENRE_DOCUS_MAGAZINES_1}, + { 2, LOCALE_GENRE_DOCUS_MAGAZINES_2}, + { 3, LOCALE_GENRE_DOCUS_MAGAZINES_3}, + { 4, LOCALE_GENRE_DOCUS_MAGAZINES_4}, + { 5, LOCALE_GENRE_DOCUS_MAGAZINES_5}, + { 6, LOCALE_GENRE_DOCUS_MAGAZINES_6}, + { 7, LOCALE_GENRE_DOCUS_MAGAZINES_7} +}; +#define GENRE_TRAVEL_HOBBIES_COUNT 8 +const CMenuOptionChooser::keyval genre_travel_hobbies[GENRE_TRAVEL_HOBBIES_COUNT] = +{ + { 0, LOCALE_GENRE_TRAVEL_HOBBIES_0}, + { 1, LOCALE_GENRE_TRAVEL_HOBBIES_1}, + { 2, LOCALE_GENRE_TRAVEL_HOBBIES_2}, + { 3, LOCALE_GENRE_TRAVEL_HOBBIES_3}, + { 4, LOCALE_GENRE_TRAVEL_HOBBIES_4}, + { 5, LOCALE_GENRE_TRAVEL_HOBBIES_5}, + { 6, LOCALE_GENRE_TRAVEL_HOBBIES_6}, + { 7, LOCALE_GENRE_TRAVEL_HOBBIES_7} +}; + +#define GENRE_MAJOR_COUNT 10 +const CMenuOptionChooser::keyval genre_major[GENRE_MAJOR_COUNT] = +{ + { 1, LOCALE_GENRE_MOVIE_0}, + { 2, LOCALE_GENRE_NEWS_0}, + { 3, LOCALE_GENRE_SHOW_0}, + { 4, LOCALE_GENRE_SPORTS_0}, + { 5, LOCALE_GENRE_CHILDRENS_PROGRAMMES_0}, + { 6, LOCALE_GENRE_MUSIC_DANCE_0}, + { 7, LOCALE_GENRE_ARTS_0}, + { 8, LOCALE_GENRE_SOCIAL_POLITICAL_0}, + { 9, LOCALE_GENRE_DOCUS_MAGAZINES_0}, + { 10, LOCALE_GENRE_TRAVEL_HOBBIES_0} +}; + + +#endif /*MOVIEBROWSER_H_*/ + + + + diff --git a/src/gui/movieinfo.cpp b/src/gui/movieinfo.cpp new file mode 100644 index 000000000..63b3a8062 --- /dev/null +++ b/src/gui/movieinfo.cpp @@ -0,0 +1,1042 @@ + /*************************************************************************** + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + *********************************************************** + + Module Name: movieinfo.cpp . + + Description: Implementation of the CMovieInfo class + This class loads, saves and shows the movie Information from the any .xml File on HD + + Date: Nov 2005 + + Author: Günther@tuxbox.berlios.org + + Revision History: + Date Author Change Description + Nov 2005 Günther initial start + +****************************************************************************/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +//#define XMLTREE_LIB +#ifdef XMLTREE_LIB +#include +#include +#endif +#define TRACE printf +#define VLC_URI "vlc://" + +/************************************************************************ + +************************************************************************/ +CMovieInfo::CMovieInfo() +{ + //TRACE("[mi] new\r\n"); +} + +CMovieInfo::~CMovieInfo() +{ + //TRACE("[mi] del\r\n"); + ; +} + +/************************************************************************ + +************************************************************************/ +bool CMovieInfo::convertTs2XmlName(char *char_filename, int size) +{ + bool result = false; + std::string filename = char_filename; + if (convertTs2XmlName(&filename) == true) { + strncpy(char_filename, filename.c_str(), size); + char_filename[size - 1] = 0; + result = true; + } + return (result); +} + +/************************************************************************ + +************************************************************************/ +bool CMovieInfo::convertTs2XmlName(std::string * filename) +{ + //TRACE("[mi]->convertTs2XmlName\r\n"); + int bytes = filename->find(".ts"); + bool result = false; + + if (bytes != -1) { + if (bytes > 3) { + if ((*filename)[bytes - 4] == '.') { + bytes = bytes - 4; + } + } + *filename = filename->substr(0, bytes) + ".xml"; + result = true; + } else // not a TS file, return!!!!! + { + //TRACE(" not a TS file "); + } + + return (result); +} + +/************************************************************************ + +************************************************************************/ +#define XML_ADD_TAG_STRING(_xml_text_,_tag_name_,_tag_content_){ \ + _xml_text_ += "\t\t<"_tag_name_">"; \ + _xml_text_ += _tag_content_; \ + _xml_text_ += "\n";} + +#define XML_ADD_TAG_UNSIGNED(_xml_text_,_tag_name_,_tag_content_){\ + _xml_text_ += "\t\t<"_tag_name_">";\ + char _tmp_[50];\ + sprintf(_tmp_, "%u", (unsigned int) _tag_content_);\ + _xml_text_ += _tmp_;\ + _xml_text_ += "\n";} + +#define XML_ADD_TAG_LONG(_xml_text_,_tag_name_,_tag_content_){\ + _xml_text_ += "\t\t<"_tag_name_">";\ + char _tmp_[50];\ + sprintf(_tmp_, "%llu", _tag_content_);\ + _xml_text_ += _tmp_;\ + _xml_text_ += "\n";} + +#define XML_GET_DATA_STRING(_node_,_tag_,_string_dest_){\ + if(!strcmp(_node_->GetType(), _tag_))\ + {\ + if(_node_->GetData() != NULL)\ + {\ + _string_dest_ = _node_->GetData();\ + }\ + }} +#define XML_GET_DATA_INT(_node_,_tag_,_int_dest_){\ + if(!strcmp(_node_->GetType(), _tag_))\ + {\ + if(_node_->GetData() != NULL)\ + {\ + _int_dest_ = atoi(_node_->GetData());\ + }\ + }} + +#define XML_GET_DATA_LONG(_node_,_tag_,_int_dest_){\ + if(!strcmp(_node_->GetType(), _tag_))\ + {\ + if(_node_->GetData() != NULL)\ + {\ + sscanf(_node_->GetData(), "%llu", &_int_dest_); \ + }\ + }} +//sscanf(_node_->GetData(), "%lld", &_int_dest_); + +bool CMovieInfo::encodeMovieInfoXml(std::string * extMessage, MI_MOVIE_INFO * movie_info) +{ + //TRACE("[mi]->encodeMovieInfoXml\r\n"); + char tmp[40]; + + *extMessage = "\n\n"; + *extMessage += "<" MI_XML_TAG_NEUTRINO " commandversion=\"1\">\n"; + *extMessage += "\t<" MI_XML_TAG_RECORD " command=\""; + *extMessage += "record"; + *extMessage += "\">\n"; + XML_ADD_TAG_STRING(*extMessage, MI_XML_TAG_CHANNELNAME, movie_info->epgChannel); + XML_ADD_TAG_STRING(*extMessage, MI_XML_TAG_EPGTITLE, movie_info->epgTitle); + XML_ADD_TAG_LONG(*extMessage, MI_XML_TAG_ID, movie_info->epgId); + XML_ADD_TAG_STRING(*extMessage, MI_XML_TAG_INFO1, movie_info->epgInfo1); + XML_ADD_TAG_STRING(*extMessage, MI_XML_TAG_INFO2, movie_info->epgInfo2); + XML_ADD_TAG_LONG(*extMessage, MI_XML_TAG_EPGID, movie_info->epgEpgId); // %llu + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_MODE, movie_info->epgMode); //%d + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_VIDEOPID, movie_info->epgVideoPid); //%u + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_VIDEOTYPE, movie_info->VideoType); //%u + if (movie_info->audioPids.size() > 0) { + //*extMessage += "\t\t<"MI_XML_TAG_AUDIOPIDS" selected=\""; + //sprintf(tmp, "%u", movie_info->audioPids[0].epgAudioPid); //pids.APIDs[i].pid); + //*extMessage += tmp; + //*extMessage += "\">\n"; + *extMessage += "\t\t<" MI_XML_TAG_AUDIOPIDS ">\n"; + + for (unsigned int i = 0; i < movie_info->audioPids.size(); i++) // pids.APIDs.size() + { + *extMessage += "\t\t\t<" MI_XML_TAG_AUDIO " " MI_XML_TAG_PID "=\""; + sprintf(tmp, "%u", movie_info->audioPids[i].epgAudioPid); //pids.APIDs[i].pid); + *extMessage += tmp; + *extMessage += "\" " MI_XML_TAG_ATYPE "=\""; + sprintf(tmp, "%u", movie_info->audioPids[i].atype); //pids.APIDs[i].pid); + *extMessage += tmp; + *extMessage += "\" " MI_XML_TAG_SELECTED "=\""; + sprintf(tmp, "%u", movie_info->audioPids[i].selected); //pids.APIDs[i].pid); + *extMessage += tmp; + *extMessage += "\" " MI_XML_TAG_NAME "=\""; + *extMessage += movie_info->audioPids[i].epgAudioPidName; // ZapitTools::UTF8_to_UTF8XML(g_RemoteControl->current_PIDs.APIDs[i].desc); + *extMessage += "\"/>\n"; + } + *extMessage += "\t\t\n"; + } + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_VTXTPID, movie_info->epgVTXPID); //%u + /***************************************************** + * new tags */ + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_GENRE_MAJOR, movie_info->genreMajor); + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_GENRE_MINOR, movie_info->genreMinor); + XML_ADD_TAG_STRING(*extMessage, MI_XML_TAG_SERIE_NAME, movie_info->serieName); + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_LENGTH, movie_info->length); + XML_ADD_TAG_STRING(*extMessage, MI_XML_TAG_PRODUCT_COUNTRY, movie_info->productionCountry); + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_PRODUCT_DATE, movie_info->productionDate); + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_QUALITY, movie_info->quality); + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_PARENTAL_LOCKAGE, movie_info->parentalLockAge); + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_DATE_OF_LAST_PLAY, movie_info->dateOfLastPlay); + *extMessage += "\t\t<" MI_XML_TAG_BOOKMARK ">\n"; + *extMessage += "\t"; + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_BOOKMARK_START, movie_info->bookmarks.start); + *extMessage += "\t"; + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_BOOKMARK_END, movie_info->bookmarks.end); + *extMessage += "\t"; + XML_ADD_TAG_UNSIGNED(*extMessage, MI_XML_TAG_BOOKMARK_LAST, movie_info->bookmarks.lastPlayStop); + for (int i = 0; i < MI_MOVIE_BOOK_USER_MAX; i++) { + if (movie_info->bookmarks.user[i].pos != 0 || i == 0) { + // encode any valid book, at least 1 + *extMessage += "\t\t\t<" MI_XML_TAG_BOOKMARK_USER " " MI_XML_TAG_BOOKMARK_USER_POS "=\""; + sprintf(tmp, "%d", movie_info->bookmarks.user[i].pos); //pids.APIDs[i].pid); + *extMessage += tmp; + *extMessage += "\" " MI_XML_TAG_BOOKMARK_USER_TYPE "=\""; + sprintf(tmp, "%d", movie_info->bookmarks.user[i].length); //pids.APIDs[i].pid); + *extMessage += tmp; + *extMessage += "\" " MI_XML_TAG_BOOKMARK_USER_NAME "=\""; + *extMessage += movie_info->bookmarks.user[i].name; + *extMessage += "\"/>\n"; + } + } + + *extMessage += "\t\t\n"; + /*****************************************************/ + + *extMessage += "\t\n"; + *extMessage += "\n"; + return true; +} + +/************************************************************************ + +************************************************************************/ +bool CMovieInfo::saveMovieInfo(MI_MOVIE_INFO & movie_info, CFile * file) +{ + //TRACE("[mi]->saveXml \r\n"); + bool result = true; + std::string text; + CFile file_xml; + + if (file == NULL) { + file_xml.Name = movie_info.file.Name; + result = convertTs2XmlName(&file_xml.Name); + } else { + file_xml.Name = file->Name; + } + TRACE("[mi] saveXml: %s\r\n", file_xml.Name.c_str()); + + if (result == true) { + result = encodeMovieInfoXml(&text, &movie_info); + if (result == true) { + result = saveFile(file_xml, text.c_str(), text.size()); // save + if (result == false) { + TRACE("[mi] saveXml: save error\r\n"); + } + } else { + TRACE("[mi] saveXml: encoding error\r\n"); + } + } else { + TRACE("[mi] saveXml: error\r\n"); + } + return (result); +} + +/************************************************************************ + +************************************************************************/ +bool CMovieInfo::loadMovieInfo(MI_MOVIE_INFO * movie_info, CFile * file) +{ + //TRACE("[mi]->loadMovieInfo \r\n"); + bool result = true; + CFile file_xml; + + if (file == NULL) { + // if there is no give file, we use the file name from movie info but we have to convert the ts name to xml name first + file_xml.Name = movie_info->file.Name; + result = convertTs2XmlName(&file_xml.Name); + } else { + file_xml.Name = file->Name; + } + + if (result == true) { + // load xml file in buffer + char text[6000]; + result = loadFile(file_xml, text, 6000); + if (result == true) { +#ifdef XMLTREE_LIB + result = parseXmlTree(text, movie_info); +#else /* XMLTREE_LIB */ + result = parseXmlQuickFix(text, movie_info); +#endif /* XMLTREE_LIB */ + } + } + if (movie_info->productionDate > 50 && movie_info->productionDate < 200) // backwardcompaibility + movie_info->productionDate += 1900; + + return (result); +} + +/************************************************************************ + +************************************************************************/ +bool CMovieInfo::parseXmlTree(char *text, MI_MOVIE_INFO * movie_info) +{ +#ifndef XMLTREE_LIB + return (false); // no XML lib available return false +#else /* XMLTREE_LIB */ + + //int helpIDtoLoad = 80; + + //XMLTreeParser *parser=new XMLTreeParser("ISO-8859-1"); + XMLTreeParser *parser = new XMLTreeParser(NULL); + + if (!parser->Parse(text, strlen(text), 1)) { + TRACE("parse error: %s at line %d \r\n", parser->ErrorString(parser->GetErrorCode()), parser->GetCurrentLineNumber()); + //fclose(in); + delete parser; + return (false); + } + + XMLTreeNode *root = parser->RootNode(); + if (!root) { + TRACE(" root error \r\n"); + return (false); + } + + if (strcmp(root->GetType(), MI_XML_TAG_NEUTRINO)) { + TRACE("not neutrino file. %s", root->GetType()); + return (false); + } + + XMLTreeNode *node = parser->RootNode(); + + for (node = node->GetChild(); node; node = node->GetNext()) { + if (!strcmp(node->GetType(), MI_XML_TAG_RECORD)) { + for (XMLTreeNode * xam1 = node->GetChild(); xam1; xam1 = xam1->GetNext()) { + XML_GET_DATA_STRING(xam1, MI_XML_TAG_CHANNELNAME, movie_info->epgChannel); + XML_GET_DATA_STRING(xam1, MI_XML_TAG_EPGTITLE, movie_info->epgTitle); + XML_GET_DATA_LONG(xam1, MI_XML_TAG_ID, movie_info->epgId); + XML_GET_DATA_STRING(xam1, MI_XML_TAG_INFO1, movie_info->epgInfo1); + XML_GET_DATA_STRING(xam1, MI_XML_TAG_INFO2, movie_info->epgInfo2); + XML_GET_DATA_LONG(xam1, MI_XML_TAG_EPGID, movie_info->epgEpgId); // %llu + XML_GET_DATA_INT(xam1, MI_XML_TAG_MODE, movie_info->epgMode); //%d + XML_GET_DATA_INT(xam1, MI_XML_TAG_VIDEOPID, movie_info->epgVideoPid); //%u + XML_GET_DATA_INT(xam1, MI_XML_TAG_VIDEOTYPE, movie_info->VideoType); //%u + if (!strcmp(xam1->GetType(), MI_XML_TAG_AUDIOPIDS)) { + for (XMLTreeNode * xam2 = xam1->GetChild(); xam2; xam2 = xam2->GetNext()) { + if (!strcmp(xam2->GetType(), MI_XML_TAG_AUDIO)) { + EPG_AUDIO_PIDS pids; + pids.epgAudioPid = atoi(xam2->GetAttributeValue((char *)MI_XML_TAG_PID)); + pids.atype = atoi(xam2->GetAttributeValue((char *)MI_XML_TAG_ATYPE)); + pids.selected = atoi(xam2->GetAttributeValue((char *)MI_XML_TAG_SELECTED)); + pids.epgAudioPidName = xam2->GetAttributeValue((char *)MI_XML_TAG_NAME); +//printf("MOVIE INFO: apid %d type %d name %s selected %d\n", pids.epgAudioPid, pids.atype, pids.epgAudioPidName.c_str(), pids.selected); + movie_info->audioPids.push_back(pids); + } + } + } + XML_GET_DATA_INT(xam1, MI_XML_TAG_VTXTPID, movie_info->epgVTXPID); //%u + /***************************************************** + * new tags */ + XML_GET_DATA_INT(xam1, MI_XML_TAG_GENRE_MAJOR, movie_info->genreMajor); + XML_GET_DATA_INT(xam1, MI_XML_TAG_GENRE_MINOR, movie_info->genreMinor); + XML_GET_DATA_STRING(xam1, MI_XML_TAG_SERIE_NAME, movie_info->serieName); + XML_GET_DATA_INT(xam1, MI_XML_TAG_LENGTH, movie_info->length); + XML_GET_DATA_STRING(xam1, MI_XML_TAG_PRODUCT_COUNTRY, movie_info->productionCountry); + //if(!strcmp(xam1->GetType(), MI_XML_TAG_PRODUCT_COUNTRY)) if(xam1->GetData() != NULL)strncpy(movie_info->productionCountry, xam1->GetData(),4); + XML_GET_DATA_INT(xam1, MI_XML_TAG_PRODUCT_DATE, movie_info->productionDate); + XML_GET_DATA_INT(xam1, MI_XML_TAG_QUALITY, movie_info->quality); + XML_GET_DATA_INT(xam1, MI_XML_TAG_PARENTAL_LOCKAGE, movie_info->parentalLockAge); + XML_GET_DATA_INT(xam1, MI_XML_TAG_DATE_OF_LAST_PLAY, movie_info->dateOfLastPlay); + + if (!strcmp(xam1->GetType(), MI_XML_TAG_BOOKMARK)) { + for (XMLTreeNode * xam2 = xam1->GetChild(); xam2; xam2 = xam2->GetNext()) { + XML_GET_DATA_INT(xam2, MI_XML_TAG_BOOKMARK_START, movie_info->bookmarks.start); + XML_GET_DATA_INT(xam2, MI_XML_TAG_BOOKMARK_END, movie_info->bookmarks.end); + XML_GET_DATA_INT(xam2, MI_XML_TAG_BOOKMARK_LAST, movie_info->bookmarks.lastPlayStop); + } + } + /*****************************************************/ + } + } + } + + delete parser; + strReplace(movie_info->epgTitle, """, "\""); + strReplace(movie_info->epgInfo1, """, "\""); + strReplace(movie_info->epgTitle, "'", "'"); + strReplace(movie_info->epgInfo1, "'", "'"); + if (movie_info->epgInfo2 == "") { + movie_info->epgInfo2 = movie_info->epgInfo1; + //movie_info->epgInfo1 = ""; + } else { + strReplace(movie_info->epgInfo2, """, "\""); + strReplace(movie_info->epgInfo2, "'", "'"); + } +#endif /* XMLTREE_LIB */ + return (true); +} + +/************************************************************************ + +************************************************************************/ +void CMovieInfo::showMovieInfo(MI_MOVIE_INFO & movie_info) +{ + std::string print_buffer; + tm *date_tm; + char date_char[100]; + // prepare print buffer + print_buffer = movie_info.epgInfo1; + print_buffer += "\n"; + print_buffer += movie_info.epgInfo2; + + if (movie_info.productionCountry.size() != 0 || movie_info.productionDate != 0) { + print_buffer += "\n"; + print_buffer += movie_info.productionCountry; + print_buffer += " "; + snprintf(date_char, 12, "%4d", movie_info.productionDate + 1900); + print_buffer += date_char; + } + + if (!movie_info.serieName.empty()) { + print_buffer += "\n\n"; + print_buffer += g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_SERIE); + print_buffer += ": "; + print_buffer += movie_info.serieName; + } + if (!movie_info.epgChannel.empty()) { + print_buffer += "\n\n"; + print_buffer += g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_CHANNEL); + print_buffer += ": "; + print_buffer += movie_info.epgChannel; + } + if (movie_info.quality != 0) { + print_buffer += "\n"; + print_buffer += g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_QUALITY); + print_buffer += ": "; + snprintf(date_char, 12, "%2d", movie_info.quality); + print_buffer += date_char; + } + if (movie_info.parentalLockAge != 0) { + print_buffer += "\n"; + print_buffer += g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_PARENTAL_LOCKAGE); + print_buffer += ": "; + snprintf(date_char, 12, "%2d", movie_info.parentalLockAge); + print_buffer += date_char; + print_buffer += " Jahre"; + } + if (movie_info.length != 0) { + print_buffer += "\n"; + print_buffer += g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_LENGTH); + print_buffer += ": "; + snprintf(date_char, 12, "%3d", movie_info.length); + print_buffer += date_char; + } + if (movie_info.audioPids.size() != 0) { + print_buffer += "\n"; + print_buffer += g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_AUDIO); + print_buffer += ": "; + for (unsigned int i = 0; i < movie_info.audioPids.size(); i++) { + print_buffer += movie_info.audioPids[i].epgAudioPidName; + print_buffer += ", "; + } + } + + print_buffer += "\n\n"; + print_buffer += g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_PREVPLAYDATE); + print_buffer += ": "; + date_tm = localtime(&movie_info.dateOfLastPlay); + snprintf(date_char, 12, "%02d.%02d.%04d", date_tm->tm_mday, date_tm->tm_mon + 1, date_tm->tm_year + 1900); + print_buffer += date_char; + print_buffer += "\n"; + print_buffer += g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_RECORDDATE); + print_buffer += ": "; + date_tm = localtime(&movie_info.file.Time); + snprintf(date_char, 12, "%02d.%02d.%04d", date_tm->tm_mday, date_tm->tm_mon + 1, date_tm->tm_year + 1900); + print_buffer += date_char; + if (movie_info.file.Size != 0) { + print_buffer += "\n"; + print_buffer += g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_SIZE); + print_buffer += ": "; + //snprintf(date_char, 12,"%4llu",movie_info.file.Size>>20); + sprintf(date_char, "%llu", movie_info.file.Size >> 20); + print_buffer += date_char; + //print_buffer += "\n"; + } + print_buffer += "\n"; + print_buffer += g_Locale->getText(LOCALE_MOVIEBROWSER_INFO_PATH); + print_buffer += ": "; + print_buffer += movie_info.file.Name; + print_buffer += "\n"; + + ShowMsg2UTF(movie_info.epgTitle.empty()? movie_info.file.getFileName().c_str() : movie_info.epgTitle.c_str(), print_buffer.c_str(), CMsgBox::mbrBack, CMsgBox::mbBack); // UTF-8*/ + +} + +/************************************************************************ + +************************************************************************/ +void CMovieInfo::printDebugMovieInfo(MI_MOVIE_INFO & movie_info) +{ + TRACE(" FileName: %s", movie_info.file.Name.c_str()); + //TRACE(" FilePath: %s", movie_info.file.GetFilePath ); + //TRACE(" FileLength: %d", movie_info.file.GetLength ); + //TRACE(" FileStatus: %d", movie_info.file.GetStatus ); + + TRACE(" ********** Movie Data ***********\r\n"); // (date, month, year) + TRACE(" dateOfLastPlay: \t%d\r\n", (int)movie_info.dateOfLastPlay); // (date, month, year) + TRACE(" dirItNr: \t\t%d\r\n", movie_info.dirItNr); // + TRACE(" genreMajor: \t\t%d\r\n", movie_info.genreMajor); //genreMajor; + TRACE(" genreMinor: \t\t%d\r\n", movie_info.genreMinor); //genreMinor; + TRACE(" length: \t\t%d\r\n", movie_info.length); // (minutes) + TRACE(" quality: \t\t%d\r\n", movie_info.quality); // (3 stars: classics, 2 stars: very good, 1 star: good, 0 stars: OK) + TRACE(" productionCount:\t>%s<\r\n", movie_info.productionCountry.c_str()); + TRACE(" productionDate: \t%d\r\n", movie_info.productionDate); // (Year) years since 1900 + TRACE(" parentalLockAge: \t\t\t%d\r\n", movie_info.parentalLockAge); // MI_PARENTAL_LOCKAGE (0,6,12,16,18) + TRACE(" format: \t\t%d\r\n", movie_info.format); // MI_VIDEO_FORMAT(16:9, 4:3) + TRACE(" audio: \t\t%d\r\n", movie_info.audio); // MI_AUDIO (AC3, Deutsch, Englisch) + TRACE(" epgId: \t\t%d\r\n", (int)movie_info.epgId); + TRACE(" epgEpgId: \t\t%llu\r\n", movie_info.epgEpgId); + TRACE(" epgMode: \t\t%d\r\n", movie_info.epgMode); + TRACE(" epgVideoPid: \t\t%d\r\n", movie_info.epgVideoPid); + TRACE(" epgVTXPID: \t\t%d\r\n", movie_info.epgVTXPID); + TRACE(" Size: \t\t%d\r\n", (int)movie_info.file.Size >> 20); + TRACE(" Date: \t\t%d\r\n", (int)movie_info.file.Time); + + for (unsigned int i = 0; i < movie_info.audioPids.size(); i++) { + TRACE(" audioPid (%d): \t\t%d\r\n", i, movie_info.audioPids[i].epgAudioPid); + TRACE(" audioName(%d): \t\t>%s<\r\n", i, movie_info.audioPids[i].epgAudioPidName.c_str()); + } + + TRACE(" epgTitle: \t\t>%s<\r\n", movie_info.epgTitle.c_str()); + TRACE(" epgInfo1:\t\t>%s<\r\n", movie_info.epgInfo1.c_str()); //epgInfo1 + TRACE(" epgInfo2:\t\t\t>%s<\r\n", movie_info.epgInfo2.c_str()); //epgInfo2 + TRACE(" epgChannel:\t\t>%s<\r\n", movie_info.epgChannel.c_str()); + TRACE(" serieName:\t\t>%s<\r\n", movie_info.serieName.c_str()); // (name e.g. 'StarWars) + + TRACE(" bookmarks start: \t%d\r\n", movie_info.bookmarks.start); + TRACE(" bookmarks end: \t%d\r\n", movie_info.bookmarks.end); + TRACE(" bookmarks lastPlayStop: %d\r\n", movie_info.bookmarks.lastPlayStop); + + for (int i = 0; i < MI_MOVIE_BOOK_USER_MAX; i++) { + if (movie_info.bookmarks.user[i].pos != 0 || i == 0) { + TRACE(" bookmarks user, pos:%d, type:%d, name: >%s<\r\n", movie_info.bookmarks.user[i].pos, movie_info.bookmarks.user[i].length, movie_info.bookmarks.user[i].name.c_str()); + } + } +} + +/************************************************************************ + +************************************************************************/ +int find_next_char(char to_find, char *text, int start_pos, int end_pos) +{ + while (start_pos < end_pos) { + if (text[start_pos] == to_find) { + return (start_pos); + } + start_pos++; + } + return (-1); +} + +#define GET_XML_DATA_STRING(_text_,_pos_,_tag_,_dest_)\ + if(strncmp(&_text_[_pos_],_tag_,sizeof(_tag_)-1) == 0)\ + {\ + _pos_ += sizeof(_tag_) ;\ + int pos_prev = _pos_;\ + while(_pos_ < bytes && _text_[_pos_] != '<' ) _pos_++;\ + _dest_ = "";\ + _dest_.append(&_text_[pos_prev],_pos_ - pos_prev );\ + _pos_ += sizeof(_tag_);\ + continue;\ + } + +#define GET_XML_DATA_INT(_text_,_pos_,_tag_,_dest_)\ + if(strncmp(&_text_[pos],_tag_,sizeof(_tag_)-1) == 0)\ + {\ + _pos_ += sizeof(_tag_) ;\ + int pos_prev = _pos_;\ + while(_pos_ < bytes && _text_[_pos_] != '<' ) pos++;\ + _dest_ = atoi(&_text_[pos_prev]);\ + continue;\ + } +#define GET_XML_DATA_LONG(_text_,_pos_,_tag_,_dest_)\ + if(strncmp(&_text_[pos],_tag_,sizeof(_tag_)-1) == 0)\ + {\ + _pos_ += sizeof(_tag_) ;\ + int pos_prev = _pos_;\ + while(_pos_ < bytes && _text_[_pos_] != '<' ) pos++;\ + _dest_ = atoll(&_text_[pos_prev]);\ + continue;\ + } + +//void CMovieInfo::strReplace(std::string& orig, const char* fstr, const std::string rstr) +void strReplace(std::string & orig, const char *fstr, const std::string rstr) +{ +// replace all occurrence of fstr with rstr and, and returns a reference to itself + unsigned int index = 0; + unsigned int fstrlen = strlen(fstr); + int rstrlen = rstr.size(); + + while ((index = orig.find(fstr, index)) != std::string::npos) { + orig.replace(index, fstrlen, rstr); + index += rstrlen; + } +} + + /************************************************************************ +************************************************************************/ +bool CMovieInfo::parseXmlQuickFix(char *text, MI_MOVIE_INFO * movie_info) +{ +#ifndef XMLTREE_LIB + int bookmark_nr = 0; + movie_info->dateOfLastPlay = 0; //100*366*24*60*60; // (date, month, year) + //bool result = false; + + int bytes = strlen(text); + /** search ****/ + int pos = 0; + + EPG_AUDIO_PIDS audio_pids; + + while ((pos = find_next_char('<', text, pos, bytes)) != -1) { + pos++; + GET_XML_DATA_STRING(text, pos, MI_XML_TAG_CHANNELNAME, movie_info->epgChannel) + GET_XML_DATA_STRING(text, pos, MI_XML_TAG_EPGTITLE, movie_info->epgTitle) + GET_XML_DATA_LONG(text, pos, MI_XML_TAG_ID, movie_info->epgId) + GET_XML_DATA_STRING(text, pos, MI_XML_TAG_INFO1, movie_info->epgInfo1) + GET_XML_DATA_STRING(text, pos, MI_XML_TAG_INFO2, movie_info->epgInfo2) + GET_XML_DATA_LONG(text, pos, MI_XML_TAG_EPGID, movie_info->epgEpgId) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_MODE, movie_info->epgMode) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_VIDEOPID, movie_info->epgVideoPid) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_VIDEOTYPE, movie_info->VideoType) + GET_XML_DATA_STRING(text, pos, MI_XML_TAG_NAME, movie_info->epgChannel) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_VTXTPID, movie_info->epgVTXPID) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_GENRE_MAJOR, movie_info->genreMajor) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_GENRE_MINOR, movie_info->genreMinor) + GET_XML_DATA_STRING(text, pos, MI_XML_TAG_SERIE_NAME, movie_info->serieName) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_LENGTH, movie_info->length) + GET_XML_DATA_STRING(text, pos, MI_XML_TAG_PRODUCT_COUNTRY, movie_info->productionCountry) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_PRODUCT_DATE, movie_info->productionDate) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_PARENTAL_LOCKAGE, movie_info->parentalLockAge) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_QUALITY, movie_info->quality) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_DATE_OF_LAST_PLAY, movie_info->dateOfLastPlay) + if (strncmp(&text[pos], MI_XML_TAG_AUDIOPIDS, sizeof(MI_XML_TAG_AUDIOPIDS) - 1) == 0) + pos += sizeof(MI_XML_TAG_AUDIOPIDS); + + /* parse audio pids */ + if (strncmp(&text[pos], MI_XML_TAG_AUDIO, sizeof(MI_XML_TAG_AUDIO) - 1) == 0) { + pos += sizeof(MI_XML_TAG_AUDIO); + + int pos2; + char *ptr; + + pos2 = -1; + ptr = strstr(&text[pos], MI_XML_TAG_PID); + if (ptr) + pos2 = (int)ptr - (int)&text[pos]; + //pos2 = strcspn(&text[pos],MI_XML_TAG_PID); + if (pos2 >= 0) { + pos2 += sizeof(MI_XML_TAG_PID); + while (text[pos + pos2] != '\"' && text[pos + pos2] != 0 && text[pos + pos2] != '/') + pos2++; + if (text[pos + pos2] == '\"') + audio_pids.epgAudioPid = atoi(&text[pos + pos2 + 1]); + } else + audio_pids.epgAudioPid = 0; + + audio_pids.atype = 0; + pos2 = -1; + ptr = strstr(&text[pos], MI_XML_TAG_ATYPE); + if (ptr) + pos2 = (int)ptr - (int)&text[pos]; + //pos2 = strcspn(&text[pos],MI_XML_TAG_ATYPE); + if (pos2 >= 0) { + pos2 += sizeof(MI_XML_TAG_ATYPE); + while (text[pos + pos2] != '\"' && text[pos + pos2] != 0 && text[pos + pos2] != '/') + pos2++; + if (text[pos + pos2] == '\"') + audio_pids.atype = atoi(&text[pos + pos2 + 1]); + } + + audio_pids.selected = 0; + pos2 = -1; + ptr = strstr(&text[pos], MI_XML_TAG_SELECTED); + if (ptr) + pos2 = (int)ptr - (int)&text[pos]; + //pos2 = strcspn(&text[pos],MI_XML_TAG_SELECTED); + if (pos2 >= 0) { + pos2 += sizeof(MI_XML_TAG_SELECTED); + while (text[pos + pos2] != '\"' && text[pos + pos2] != 0 && text[pos + pos2] != '/') + pos2++; + if (text[pos + pos2] == '\"') + audio_pids.selected = atoi(&text[pos + pos2 + 1]); + } + + audio_pids.epgAudioPidName = ""; + //pos2 = strcspn(&text[pos],MI_XML_TAG_NAME); + pos2 = -1; + ptr = strstr(&text[pos], MI_XML_TAG_NAME); + if (ptr) + pos2 = (int)ptr - (int)&text[pos]; + if (pos2 >= 0) { + pos2 += sizeof(MI_XML_TAG_PID); + while (text[pos + pos2] != '\"' && text[pos + pos2] != 0 && text[pos + pos2] != '/') + pos2++; + if (text[pos + pos2] == '\"') { + int pos3 = pos2 + 1; + while (text[pos + pos3] != '\"' && text[pos + pos3] != 0 && text[pos + pos3] != '/') + pos3++; + if (text[pos + pos3] == '\"') + audio_pids.epgAudioPidName.append(&text[pos + pos2 + 1], pos3 - pos2 - 1); + } + } + printf("MOVIE INFO: apid %d type %d name %s selected %d\n", audio_pids.epgAudioPid, audio_pids.atype, audio_pids.epgAudioPidName.c_str(), audio_pids.selected); + movie_info->audioPids.push_back(audio_pids); + } + /* parse bookmarks */ + GET_XML_DATA_INT(text, pos, MI_XML_TAG_BOOKMARK_START, movie_info->bookmarks.start) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_BOOKMARK_END, movie_info->bookmarks.end) + GET_XML_DATA_INT(text, pos, MI_XML_TAG_BOOKMARK_LAST, movie_info->bookmarks.lastPlayStop) + + if (bookmark_nr < MI_MOVIE_BOOK_USER_MAX) { + if (strncmp(&text[pos], MI_XML_TAG_BOOKMARK_USER, sizeof(MI_XML_TAG_BOOKMARK_USER) - 1) == 0) { + pos += sizeof(MI_XML_TAG_BOOKMARK_USER); + //int pos2 = strcspn(&text[pos],MI_XML_TAG_BOOKMARK_USER_POS); + if (strcspn(&text[pos], MI_XML_TAG_BOOKMARK_USER_POS) == 0) { + int pos2 = 0; + pos2 += sizeof(MI_XML_TAG_BOOKMARK_USER_POS); + while (text[pos + pos2] != '\"' && text[pos + pos2] != 0 && text[pos + pos2] != '/') + pos2++; + if (text[pos + pos2] == '\"') { + movie_info->bookmarks.user[bookmark_nr].pos = atoi(&text[pos + pos2 + 1]); + + //pos2 = strcspn(&text[pos],MI_XML_TAG_BOOKMARK_USER_TYPE); + pos++; + while (text[pos + pos2] == ' ') + pos++; + if (strcspn(&text[pos], MI_XML_TAG_BOOKMARK_USER_TYPE) == 0) { + pos2 += sizeof(MI_XML_TAG_BOOKMARK_USER_TYPE); + while (text[pos + pos2] != '\"' && text[pos + pos2] != 0 && text[pos + pos2] != '/') + pos2++; + if (text[pos + pos2] == '\"') { + movie_info->bookmarks.user[bookmark_nr].length = atoi(&text[pos + pos2 + 1]); + + movie_info->bookmarks.user[bookmark_nr].name = ""; + //pos2 = ; + if (strcspn(&text[pos], MI_XML_TAG_BOOKMARK_USER_NAME) == 0) { + pos2 += sizeof(MI_XML_TAG_BOOKMARK_USER_NAME); + while (text[pos + pos2] != '\"' && text[pos + pos2] != 0 && text[pos + pos2] != '/') + pos2++; + if (text[pos + pos2] == '\"') { + int pos3 = pos2 + 1; + while (text[pos + pos3] != '\"' && text[pos + pos3] != 0 && text[pos + pos3] != '/') + pos3++; + if (text[pos + pos3] == '\"') + movie_info->bookmarks.user[bookmark_nr].name.append(&text[pos + pos2 + 1], pos3 - pos2 - 1); + } + } + } + } else + movie_info->bookmarks.user[bookmark_nr].length = 0; + } + bookmark_nr++; + } else + movie_info->bookmarks.user[bookmark_nr].pos = 0; + } + } + } + + strReplace(movie_info->epgTitle, """, "\""); + strReplace(movie_info->epgInfo1, """, "\""); + strReplace(movie_info->epgTitle, "'", "'"); + strReplace(movie_info->epgInfo1, "'", "'"); + if (movie_info->epgInfo2 == "") { + movie_info->epgInfo2 = movie_info->epgInfo1; + //movie_info->epgInfo1 = ""; + } else { + strReplace(movie_info->epgInfo2, """, "\""); + strReplace(movie_info->epgInfo2, "'", "'"); + } + + return (true); +#endif + return (false); +} + +/************************************************************************ + +************************************************************************/ +bool CMovieInfo::addNewBookmark(MI_MOVIE_INFO * movie_info, MI_BOOKMARK & new_bookmark) +{ + TRACE("[mi] addNewBookmark\r\n"); + bool result = false; + if (movie_info != NULL) { + // search for free entry + bool loop = true; + for (int i = 0; i < MI_MOVIE_BOOK_USER_MAX && loop == true; i++) { + if (movie_info->bookmarks.user[i].pos == 0) { + // empty entry found + result = true; + loop = false; + movie_info->bookmarks.user[i].pos = new_bookmark.pos; + movie_info->bookmarks.user[i].length = new_bookmark.length; + //if(movie_info->bookmarks.user[i].name.empty()) + if (movie_info->bookmarks.user[i].name.size() == 0) { + if (new_bookmark.length == 0) + movie_info->bookmarks.user[i].name = g_Locale->getText(LOCALE_MOVIEBROWSER_BOOK_NEW); + if (new_bookmark.length < 0) + movie_info->bookmarks.user[i].name = g_Locale->getText(LOCALE_MOVIEBROWSER_BOOK_TYPE_BACKWARD); + if (new_bookmark.length > 0) + movie_info->bookmarks.user[i].name = g_Locale->getText(LOCALE_MOVIEBROWSER_BOOK_TYPE_FORWARD); + } else { + movie_info->bookmarks.user[i].name = new_bookmark.name; + } + } + } + } + return (result); +} + +/************************************************************************ + +************************************************************************/ +void CMovieInfo::clearMovieInfo(MI_MOVIE_INFO * movie_info) +{ + //TRACE("[mi]->clearMovieInfo \r\n"); + tm timePlay; + timePlay.tm_hour = 0; + timePlay.tm_min = 0; + timePlay.tm_sec = 0; + timePlay.tm_year = 100; + timePlay.tm_mday = 0; + timePlay.tm_mon = 1; + + movie_info->file.Name = ""; + movie_info->file.Size = 0; // Megabytes + movie_info->file.Time = mktime(&timePlay); + movie_info->dateOfLastPlay = mktime(&timePlay); // (date, month, year) + movie_info->dirItNr = 0; // + movie_info->genreMajor = 0; //genreMajor; + movie_info->genreMinor = 0; //genreMinor; + movie_info->length = 0; // (minutes) + movie_info->quality = 0; // (3 stars: classics, 2 stars: very good, 1 star: good, 0 stars: OK) + movie_info->productionDate = 0; // (Year) years since 1900 + movie_info->parentalLockAge = 0; // MI_PARENTAL_LOCKAGE (0,6,12,16,18) + movie_info->format = 0; // MI_VIDEO_FORMAT(16:9, 4:3) + movie_info->audio = 0; // MI_AUDIO (AC3, Deutsch, Englisch) + + movie_info->epgId = 0; + movie_info->epgEpgId = 0; + movie_info->epgMode = 0; + movie_info->epgVideoPid = 0; + movie_info->VideoType = 0; + movie_info->epgVTXPID = 0; + + movie_info->audioPids.clear(); + + movie_info->productionCountry = ""; + movie_info->epgTitle = ""; + movie_info->epgInfo1 = ""; //epgInfo1 + movie_info->epgInfo2 = ""; //epgInfo2 + movie_info->epgChannel = ""; + movie_info->serieName = ""; // (name e.g. 'StarWars) + movie_info->bookmarks.end = 0; + movie_info->bookmarks.start = 0; + movie_info->bookmarks.lastPlayStop = 0; + for (int i = 0; i < MI_MOVIE_BOOK_USER_MAX; i++) { + movie_info->bookmarks.user[i].pos = 0; + movie_info->bookmarks.user[i].length = 0; + movie_info->bookmarks.user[i].name = ""; + } +} + +/************************************************************************ + +************************************************************************/ +bool CMovieInfo::loadFile(CFile & file, char *buffer, int buffer_size) +{ + bool result = false; + if (strncmp(file.getFileName().c_str(), VLC_URI, strlen(VLC_URI)) == 0) { + result = loadFile_vlc(file, buffer, buffer_size); + } else { + result = loadFile_std(file, buffer, buffer_size); + } + return (result); +} + +bool CMovieInfo::loadFile_std(CFile & file, char *buffer, int buffer_size) +{ + bool result = true; + + int fd = open(file.Name.c_str(), O_RDONLY); + if (fd == -1) // cannot open file, return!!!!! + { + TRACE("[mi] loadXml: cannot open (%s)\r\n", file.getFileName().c_str()); + return false; + } + //TRACE( "show_ts_info: File found (%s)\r\n" ,filename->c_str()); + // read file content to buffer + int bytes = read(fd, buffer, buffer_size - 1); + if (bytes <= 0) // cannot read file into buffer, return!!!! + { + TRACE("[mi] loadXml: cannot read (%s)\r\n", file.getFileName().c_str()); + return false; + } + close(fd); + buffer[bytes] = 0; // terminate string + return (result); +} + +bool CMovieInfo::loadFile_vlc(CFile & file, char *buffer, int buffer_size) +{ + bool result = false; + return (result); +} + +/************************************************************************ + +************************************************************************/ +bool CMovieInfo::saveFile(const CFile & file, const char *text, const int text_size) +{ + bool result = false; + if (strncmp(file.getFileName().c_str(), VLC_URI, strlen(VLC_URI)) == 0) { + result = saveFile_vlc(file, text, text_size); + } else { + result = saveFile_std(file, text, text_size); + } + return (result); +} + +bool CMovieInfo::saveFile_std(const CFile & file, const char *text, const int text_size) +{ + bool result = false; + int fd; + if ((fd = open(file.Name.c_str(), O_SYNC | O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) { + int nr; + nr = write(fd, text, text_size); + //fdatasync(fd); + close(fd); + result = true; + //TRACE("[mi] saved (%d)\r\n",nr); + } else { + TRACE("[mi] ERROR: cannot open\r\n"); + } + return (result); +} + +bool CMovieInfo::saveFile_vlc(const CFile & file, const char *text, const int text_size) +{ + bool result = false; + return (result); +} + +/* char buf[2048]; + + int done; + do + { + unsigned int len=fread(buf, 1, sizeof(buf), in); + done=lenParse(buf, len, 1)) + { + TRACE("parse error: %s at line %d \r\n", parser->ErrorString(parser->GetErrorCode()), parser->GetCurrentLineNumber()); + fclose(in); + delete parser; + return (false); + } + } while (!done); + fclose(in); + * + * */ + +void CMovieInfo::copy(MI_MOVIE_INFO * src, MI_MOVIE_INFO * dst) +{ + //TRACE("[mi]->clearMovieInfo \r\n"); + + dst->file.Name = src->file.Name; + dst->file.Size = src->file.Size; + dst->file.Time = src->file.Time; + dst->dateOfLastPlay = src->dateOfLastPlay; + dst->dirItNr = src->dirItNr; + dst->genreMajor = src->genreMajor; + dst->genreMinor = src->genreMinor; + dst->length = src->length; + dst->quality = src->quality; + dst->productionDate = src->productionDate; + dst->parentalLockAge = src->parentalLockAge; + dst->format = src->format; + dst->audio = src->audio; + + dst->epgId = src->epgId; + dst->epgEpgId = src->epgEpgId; + dst->epgMode = src->epgMode; + dst->epgVideoPid = src->epgVideoPid; + dst->VideoType = src->VideoType; + dst->epgVTXPID = src->epgVTXPID; + + dst->productionCountry = src->productionCountry; + dst->epgTitle = src->epgTitle; + dst->epgInfo1 = src->epgInfo1; + dst->epgInfo2 = src->epgInfo2; + dst->epgChannel = src->epgChannel; + dst->serieName = src->serieName; + dst->bookmarks.end = src->bookmarks.end; + dst->bookmarks.start = src->bookmarks.start; + dst->bookmarks.lastPlayStop = src->bookmarks.lastPlayStop; + + for (int i = 0; i < MI_MOVIE_BOOK_USER_MAX; i++) { + dst->bookmarks.user[i].pos = src->bookmarks.user[i].pos; + dst->bookmarks.user[i].length = src->bookmarks.user[i].length; + dst->bookmarks.user[i].name = src->bookmarks.user[i].name; + } + + for (unsigned int i = 0; i < src->audioPids.size(); i++) { + EPG_AUDIO_PIDS audio_pids; + audio_pids.epgAudioPid = src->audioPids[i].epgAudioPid; + audio_pids.epgAudioPidName = src->audioPids[i].epgAudioPidName; + audio_pids.atype = src->audioPids[i].atype; + dst->audioPids.push_back(audio_pids); + } +} diff --git a/src/gui/movieinfo.h b/src/gui/movieinfo.h new file mode 100644 index 000000000..4fb907407 --- /dev/null +++ b/src/gui/movieinfo.h @@ -0,0 +1,204 @@ +/*************************************************************************** + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + *********************************************************** + + Module Name: movieinfo.h . + + Description: implementation of the CMovieInfo class + + Date: Nov 2005 + + Author: Günther@tuxbox.berlios.org + + Revision History: + Date Author Change Description + Nov 2005 Günther initial start + +****************************************************************************/ + +#ifndef MOVIEINFO_H_ +#define MOVIEINFO_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "driver/file.h" + +/************************************************************************/ +/************************************************************************/ +/***************** CMovieInfo ********************************/ +/************************************************************************/ + + +/* XML tags for xml file*/ +#define MI_XML_TAG_NEUTRINO "neutrino" +#define MI_XML_TAG_RECORD "record" + +#define MI_XML_TAG_CHANNELNAME "channelname" +#define MI_XML_TAG_EPGTITLE "epgtitle" +#define MI_XML_TAG_ID "id" +#define MI_XML_TAG_INFO1 "info1" +#define MI_XML_TAG_INFO2 "info2" +#define MI_XML_TAG_EPGID "epgid" +#define MI_XML_TAG_MODE "mode" +#define MI_XML_TAG_VIDEOPID "videopid" +#define MI_XML_TAG_VIDEOTYPE "videotype" +#define MI_XML_TAG_AUDIOPIDS "audiopids" +#define MI_XML_TAG_AUDIO "audio" +#define MI_XML_TAG_PID "pid" +#define MI_XML_TAG_NAME "name" +#define MI_XML_TAG_ATYPE "audiotype" +#define MI_XML_TAG_SELECTED "selected" +#define MI_XML_TAG_VTXTPID "vtxtpid" +#define MI_XML_TAG_GENRE_MAJOR "genremajor" +#define MI_XML_TAG_GENRE_MINOR "genreminor" +#define MI_XML_TAG_SERIE_NAME "seriename" +#define MI_XML_TAG_LENGTH "length" +#define MI_XML_TAG_PRODUCT_COUNTRY "productioncountry" +#define MI_XML_TAG_PRODUCT_DATE "productiondate" +#define MI_XML_TAG_QUALITY "qualitiy" +#define MI_XML_TAG_PARENTAL_LOCKAGE "parentallockage" +#define MI_XML_TAG_BOOKMARK "bookmark" +#define MI_XML_TAG_BOOKMARK_START "bookmarkstart" +#define MI_XML_TAG_BOOKMARK_END "bookmarkend" +#define MI_XML_TAG_BOOKMARK_LAST "bookmarklast" +#define MI_XML_TAG_BOOKMARK_USER "bookmarkuser" +#define MI_XML_TAG_BOOKMARK_USER_POS "bookmarkuserpos" +#define MI_XML_TAG_BOOKMARK_USER_TYPE "bookmarkusertype" +#define MI_XML_TAG_BOOKMARK_USER_NAME "bookmarkusername" +#define MI_XML_TAG_DATE_OF_LAST_PLAY "dateoflastplay" + + +#define MI_MAX_AUDIO_PIDS 4 // just to avoid the buffer is filled endless, might be increased later on , but 4 audio pids might be enough +#define MI_MOVIE_BOOK_USER_MAX 20 // just to avoid the buffer is filled endless, might be increased later on. Make sure to increase the bookmark menu as well + +typedef enum +{ + MI_PARENTAL_OVER0 = 0, + MI_PARENTAL_OVER6 = 6, + MI_PARENTAL_OVER12 = 12, + MI_PARENTAL_OVER16 = 16, + MI_PARENTAL_OVER18 = 18, + MI_PARENTAL_ALWAYS = 99, + MI_PARENTAL_MAX_NUMBER = 100 +}MI_PARENTAL_LOCKAGE; + +typedef struct +{ + int pos; // position in seconds from file start + int length; // bookmark type, 0: just a bookmark, < 0 jump back (seconds), > 0 jump forward (seconds) + std::string name; // bookmark name to be displayed +}MI_BOOKMARK; + +typedef struct +{ + int start; // movie start in seconds from file start + int end; // movie end in seconds from file start + int lastPlayStop; // position of last play stop in seconds from file start + MI_BOOKMARK user[MI_MOVIE_BOOK_USER_MAX]; // other user defined bookmarks +}MI_MOVIE_BOOKMARKS; + +typedef struct +{ + int atype; + int selected; + int epgAudioPid; // epg audio pid nr, usually filled by VCR + std::string epgAudioPidName; // epg audio pid name, usually filled by VCR +}EPG_AUDIO_PIDS; + +/************************************************************************/ +/************************************************************************/ + +typedef struct +{ + CFile file; // not stored in xml + std::string productionCountry; // user defined Country (not from EPG yet, but might be possible) + std::string epgTitle; // plain movie name, usually filled by EPG + std::string epgInfo1; // used for Genre (Premiere) or second title, usually filled by EPG + std::string epgInfo2; // detailed movie content, usually filled by EPG + std::string epgChannel; // Channel name, usually filled by EPG + std::string serieName; // user defines series name + + time_t dateOfLastPlay; // last play date of movie in seconds since 1970 + char dirItNr; // handle for quick directory path access only, this is not saved in xml, might be used by the owner of the movie info struct + int genreMajor; // see showEPG class for more info, usually filled by EPG + char genreMinor; // genreMinor not used so far + int length; // movie length in minutes, usually filled by EPG + int quality; // user classification (3 stars: classics, 2 stars: very good, 1 star: good, 0 stars: OK) + int productionDate; // user defined Country (not from EPG yet, but might be possible) + int parentalLockAge; // used for age rating(0:never,6,12,16,18 years,99:always), usually filled by EPG (if available) + char format; // currently not used + char audio; // currently not used + MI_MOVIE_BOOKMARKS bookmarks; // bookmark collecton for this movie + std::vector audioPids; // available AudioPids, usually filled by VCR. Note: Vectors are easy to is also using the heap (memory fragmentation), might be changed to array [MI_MAX_AUDIO_PIDS] + + uint64_t epgId; // currently not used, we just do not want to loose this info if movie info is saved backed + uint64_t epgEpgId; // off_t currently not used, we just do not want to loose this info if movie info is saved backed + int epgMode; // currently not used, we just do not want to loose this info if movie info is saved backed + int epgVideoPid; // currently not used, we just do not want to loose this info if movie info is saved backed + int VideoType; + int epgVTXPID; // currently not used, we just do not want to loose this info if movie info is saved backed +}MI_MOVIE_INFO; + + +class CMovieInfo +{ + public: // Functions + CMovieInfo(); + ~CMovieInfo(); + bool convertTs2XmlName(std::string* filename); // convert a ts file name in .xml file name + bool convertTs2XmlName(char* filename,int size); // convert a ts file name in .xml file name + bool loadMovieInfo(MI_MOVIE_INFO* movie_info, CFile* file = NULL ); // load movie information for the given .xml filename. If there is no filename, the filename (ts) from movie_info is converted to xml and used instead + bool encodeMovieInfoXml(std::string* extMessage, MI_MOVIE_INFO * movie_info); // encode the movie_info structure to xml string + bool saveMovieInfo(MI_MOVIE_INFO& movie_info, CFile* file = NULL ); // encode the movie_info structure to xml and save it to the given .xml filename. If there is no filename, the filename (ts) from movie_info is converted to xml and used instead + void showMovieInfo(MI_MOVIE_INFO& movie_info); // open a Hintbox and show the movie info + void printDebugMovieInfo(MI_MOVIE_INFO& movie_info); // print movie info on debug channel (RS232) + void clearMovieInfo(MI_MOVIE_INFO* movie_info); // Set movie info structure to initial values + bool addNewBookmark(MI_MOVIE_INFO* movie_info,MI_BOOKMARK &new_bookmark); // add a new bookmark to the given movie info. If there is no space false is returned + void copy(MI_MOVIE_INFO* src, MI_MOVIE_INFO* dst); + + private:// Functions + bool parseXmlTree (char* text, MI_MOVIE_INFO* movie_info); // this is the 'good' function, but it needs the xmllib which is not currently linked within neutrino. Might be to slow as well. If used, add bookmark parsing + bool parseXmlQuickFix(char* text, MI_MOVIE_INFO* movie_info); // OK, this is very quick an dirty. It does not waist execution time nor flash (this is QUICK). But, do not play to much with the xml files (e.g. with MS Notepad) since small changes in the structure could cause the parser to fail (this it DIRTY). + bool loadFile_std(CFile& file,char* buffer, int buffer_size); + bool loadFile_vlc(CFile& file,char* buffer, int buffer_size); + bool loadFile(CFile& file,char* buffer, int buffer_size); + bool saveFile_std(const CFile& file, const char* text, const int text_size); + bool saveFile_vlc(const CFile& file, const char* text, const int text_sizet); + bool saveFile(const CFile& file, const char* text, const int text_size); + //void CMovieInfo::strReplace(std::string& orig, const char* fstr, const std::string rstr); + private:// variables +}; + +#endif /*MOVIEINFO_H_*/ + diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp new file mode 100644 index 000000000..52cf58d84 --- /dev/null +++ b/src/gui/movieplayer.cpp @@ -0,0 +1,1339 @@ +/* + Neutrino-GUI - DBoxII-Project + + Movieplayer (c) 2003, 2004 by gagga + Based on code by Dirch, obi and the Metzler Bros. Thanks. + + $Id: movieplayer.cpp,v 1.97 2004/07/18 00:54:52 thegoodguy Exp $ + + Homepage: http://www.giggo.de/dbox2/movieplayer.html + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +int dvbsub_start(int pid); +int dvbsub_pause(); + +extern cVideo * videoDecoder; +static cPlayback *playback; + +extern CRemoteControl *g_RemoteControl; /* neutrino.cpp */ +void strReplace(std::string & orig, const char *fstr, const std::string rstr); +#define MOVIE_HINT_BOX_TIMER 5 // time to show bookmark hints in seconds +extern CPlugins *g_PluginList; +extern CInfoClock *InfoClock; + +#define MINUTEOFFSET 117*262072 +#define MP_TS_SIZE 262072 // ~0.5 sec + +extern char rec_filename[512]; +extern off64_t glob_limit; +extern int glob_splits; + +static CMoviePlayerGui::state playstate; +static bool isBookmark; +static bool isMovieBrowser = false; +int speed = 1; +int slow = 0; +static off64_t fullposition; // cur. position including all parts played +//static off64_t fulllength = 0; // len of all parts +int startposition; +int timeshift; +off64_t minuteoffset; +off64_t secondoffset; + +int file_prozent; + +#ifndef __USE_FILE_OFFSET64 +#error not using 64 bit file offsets +#endif /* __USE_FILE__OFFSET64 */ + +int streamingrunning; +CHintBox *hintBox; +std::string startfilename; +std::string skipvalue; + +int jumpminutes = 1; +static int g_jumpseconds = 0; +int buffer_time = 0; +unsigned short g_apids[10]; +unsigned short g_ac3flags[10]; +unsigned short g_numpida = 0; +unsigned short g_vpid = 0; +unsigned short g_vtype = 0; +std::string g_language[10]; + +unsigned int g_currentapid = 0, g_currentac3 = 0, apidchanged = 0; +std::string g_file_epg; +std::string g_file_epg1; +bool showaudioselectdialog = false; + +void checkAspectRatio(int vdec, bool init); + +bool get_movie_info_apid_name(int apid, MI_MOVIE_INFO * movie_info, std::string * apidtitle) +{ + if (movie_info == NULL || apidtitle == NULL) + return false; + + for (int i = 0; i < (int)movie_info->audioPids.size(); i++) { + if (movie_info->audioPids[i].epgAudioPid == apid && !movie_info->audioPids[i].epgAudioPidName.empty()) { + *apidtitle = movie_info->audioPids[i].epgAudioPidName; + return true; + } + } + return false; +} + +int CAPIDSelectExec::exec(CMenuTarget * parent, const std::string & actionKey) +{ + apidchanged = 0; + unsigned int sel = atoi(actionKey.c_str()); + if (g_currentapid != g_apids[sel - 1]) { + g_currentapid = g_apids[sel - 1]; + g_currentac3 = g_ac3flags[sel - 1]; + apidchanged = 1; + printf("[movieplayer] apid changed to %d\n", g_apids[sel - 1]); + } + return menu_return::RETURN_EXIT; +} + +CMoviePlayerGui::CMoviePlayerGui() +{ + Init(); +} + +void CMoviePlayerGui::Init(void) +{ + stopped = false; + hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_MOVIEPLAYER_PLEASEWAIT)); // UTF-8 + + frameBuffer = CFrameBuffer::getInstance(); + + if (strlen(g_settings.network_nfs_moviedir) != 0) + Path_local = g_settings.network_nfs_moviedir; + else + Path_local = "/"; + Path_vlc = "vlc://"; + Path_vlc += g_settings.streaming_server_startdir; + Path_vlc_settings = g_settings.streaming_server_startdir; + + if (g_settings.filebrowser_denydirectoryleave) + filebrowser = new CFileBrowser(Path_local.c_str()); + else + filebrowser = new CFileBrowser(); + + filebrowser->Multi_Select = false; + filebrowser->Dirs_Selectable = false; + filebrowser->Hide_records = true; + playback = new cPlayback(3); + moviebrowser = new CMovieBrowser(); + bookmarkmanager = 0; + + tsfilefilter.addFilter("ts"); + tsfilefilter.addFilter("avi"); + tsfilefilter.addFilter("mkv"); + tsfilefilter.addFilter("wav"); + tsfilefilter.addFilter("asf"); + tsfilefilter.addFilter("aiff"); + tsfilefilter.addFilter("mpg"); + tsfilefilter.addFilter("mpeg"); + tsfilefilter.addFilter("m2p"); + tsfilefilter.addFilter("mpv"); + tsfilefilter.addFilter("vob"); + tsfilefilter.addFilter("m2ts"); + + + vlcfilefilter.addFilter("mpg"); + vlcfilefilter.addFilter("mpeg"); + vlcfilefilter.addFilter("m2p"); + vlcfilefilter.addFilter("avi"); + vlcfilefilter.addFilter("vob"); + pesfilefilter.addFilter("mpv"); + filebrowser->Filter = &tsfilefilter; + rct = 0; +} + +CMoviePlayerGui::~CMoviePlayerGui() +{ +#if 0 + delete filebrowser; + if (moviebrowser) + delete moviebrowser; + delete hintBox; + if (bookmarkmanager) + delete bookmarkmanager; + g_Zapit->setStandby(false); + g_Sectionsd->setPauseScanning(false); +#endif + delete playback; +} + +void CMoviePlayerGui::cutNeutrino() +{ + if (stopped) + return; + + g_Zapit->setStandby(true); + g_Sectionsd->setPauseScanning(true); + + CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE, NeutrinoMessages::mode_ts); + m_LastMode = (CNeutrinoApp::getInstance()->getLastMode() | NeutrinoMessages::norezap); + + stopped = true; +} + +void CMoviePlayerGui::restoreNeutrino() +{ + if (!stopped) + return; + + g_Zapit->setStandby(false); + g_Sectionsd->setPauseScanning(false); + + CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE, m_LastMode); + //CVFD::getInstance()->showServicename(g_RemoteControl->getCurrentChannelName()); + + stopped = false; +} + +int CMoviePlayerGui::exec(CMenuTarget * parent, const std::string & actionKey) +{ + printf("[movieplayer] actionKey=%s\n", actionKey.c_str()); + + if (Path_vlc_settings != g_settings.streaming_server_startdir) { + Path_vlc = "vlc://"; + Path_vlc += g_settings.streaming_server_startdir; + Path_vlc_settings = g_settings.streaming_server_startdir; + } + bookmarkmanager = new CBookmarkManager(); + + dvbsub_pause(); + + if (parent) { + parent->hide(); + } + + bool usedBackground = frameBuffer->getuseBackground(); + if (usedBackground) { + frameBuffer->saveBackgroundImage(); + frameBuffer->ClearFrameBuffer(); + } + + const CBookmark *theBookmark = NULL; + if (actionKey == "bookmarkplayback") { + isBookmark = true; + theBookmark = bookmarkmanager->getBookmark(NULL); + if (theBookmark == NULL) { + bookmarkmanager->flush(); + return menu_return::RETURN_REPAINT; + } + } + + isBookmark = false; + startfilename = ""; + startposition = 0; + + isMovieBrowser = false; + minuteoffset = MINUTEOFFSET; + secondoffset = minuteoffset / 60; +#if 0 + if (actionKey == "fileplayback") { + cutNeutrino(); + PlayStream(STREAMTYPE_FILE); + } else if (actionKey == "dvdplayback") { + cutNeutrino(); + PlayStream(STREAMTYPE_DVD); + } else if (actionKey == "vcdplayback") { + cutNeutrino(); + PlayStream(STREAMTYPE_SVCD); + } else if (actionKey == "tsplayback") { + timeshift = 0; + PlayFile(); + } else +#endif + if (actionKey == "tsmoviebrowser") { + isMovieBrowser = true;// TESTTTTTTTTTTTTTTT + timeshift = 0; + PlayFile(); + } + else if (actionKey == "fileplayback") { + isMovieBrowser = false; + timeshift = 0; + PlayFile(); + } + else if (actionKey == "timeshift") { + cutNeutrino(); + timeshift = 1; + PlayFile(); + } + else if (actionKey == "ptimeshift") { + cutNeutrino(); + timeshift = 2; + PlayFile(); + } + else if (actionKey == "rtimeshift") { + cutNeutrino(); + timeshift = 3; + PlayFile(); + } +#if 0 + else if (actionKey == "bookmarkplayback") { + isBookmark = true; + if (theBookmark != NULL) { + cutNeutrino(); + startfilename = theBookmark->getUrl(); + sscanf(theBookmark->getTime(), "%lld", &startposition); + int vlcpos = startfilename.rfind("vlc://"); + if (vlcpos == 0) { + PlayStream(STREAMTYPE_FILE); + } else { + timeshift = 0; + PlayFile(); + } + } + } +#endif + + bookmarkmanager->flush(); + // Restore previous background + if (usedBackground) { + frameBuffer->restoreBackgroundImage(); + frameBuffer->useBackground(true); + frameBuffer->paintBackground(); + } + + restoreNeutrino(); + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + //g_RCInput->postMsg(NeutrinoMessages::SHOW_INFOBAR, 0); + //dvbsub_start(0); + + if (bookmarkmanager) + delete bookmarkmanager; + if (timeshift) { + timeshift = 0; + return menu_return::RETURN_EXIT_ALL; + } + return menu_return::RETURN_REPAINT; + //return menu_return::RETURN_EXIT_ALL; +} + +void updateLcd(const std::string & sel_filename) +{ + char tmp[20]; + std::string lcd; + + switch (playstate) { + case CMoviePlayerGui::PAUSE: + lcd = "|| "; + lcd += sel_filename; + //lcd += ')'; + break; + case CMoviePlayerGui::REW: + sprintf(tmp, "%dx<< ", speed); + lcd = tmp; + lcd += sel_filename; + break; + case CMoviePlayerGui::FF: + sprintf(tmp, "%dx>> ", speed); + lcd = tmp; + lcd += sel_filename; + break; +#if 0 + case CMoviePlayerGui::JF: + sprintf(tmp, "%ds>> ", speed); + lcd = tmp; + lcd += sel_filename; + break; +#endif + default: + if (slow) { + sprintf(tmp, "%ds||> ", slow); + lcd = tmp; + } else + lcd = "> "; + lcd += sel_filename; + break; + } + + //CVFD::getInstance()->showServicename(lcd); + CVFD::getInstance()->showMenuText(0, lcd.c_str(), -1, true); +} + +extern bool has_hdd; +#define TIMESHIFT_SECONDS 3 +void CMoviePlayerGui::PlayFile(void) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + int position = 0, duration = 0; + bool timeshift_paused = false; + + std::string sel_filename; + CTimeOSD FileTime; + bool update_lcd = true, open_filebrowser = true, start_play = false, exit = false; + bool timesh = timeshift; + bool was_file = false; + bool time_forced = false; + playstate = CMoviePlayerGui::STOPPED; + bool is_file_player = false; + //unsigned short apid = 0, vpid = 0; + //int vtype = 0, atype = 0; + + if (has_hdd) + system("(rm /hdd/.wakeup; touch /hdd/.wakeup; sync) > /dev/null 2> /dev/null &"); + + timeb current_time; + CMovieInfo cMovieInfo; // funktions to save and load movie info + MI_MOVIE_INFO *p_movie_info = NULL; // movie info handle which comes from the MovieBrowser, if not NULL MoviePla yer is able to save new bookmarks + + int width = 280; + int height = 65; + int x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + //int y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - height) / 2; + int y = frameBuffer->getScreenY() + frameBuffer->getScreenHeight() - height - 20; + + CBox boxposition(x, y, width, height); // window position for the hint boxes + + CTextBox endHintBox(g_Locale->getText(LOCALE_MOVIEBROWSER_HINT_MOVIEEND), NULL, CTextBox::CENTER /*CTextBox::AUTO_WIDTH | CTextBox::AUTO_HIGH */ , &boxposition); + CTextBox comHintBox(g_Locale->getText(LOCALE_MOVIEBROWSER_HINT_JUMPFORWARD), NULL, CTextBox::CENTER /*CTextBox::AUTO_WIDTH | CTextBox::AUTO_HIGH */ , &boxposition); + CTextBox loopHintBox(g_Locale->getText(LOCALE_MOVIEBROWSER_HINT_JUMPBACKWARD), NULL, CTextBox::CENTER /*CTextBox::AUTO_WIDTH | CTextBox::AUTO_HIGH */ , &boxposition); + CTextBox newLoopHintBox(g_Locale->getText(LOCALE_MOVIEBROWSER_HINT_NEWBOOK_BACKWARD), NULL, CTextBox::CENTER /*CTextBox::AUTO_WIDTH | CTextBox::AUTO_HIGH */ , &boxposition); + CTextBox newComHintBox(g_Locale->getText(LOCALE_MOVIEBROWSER_HINT_NEWBOOK_FORWARD), NULL, CTextBox::CENTER /*CTextBox::AUTO_WIDTH | CTextBox::AUTO_HIGH */ , &boxposition); + + bool showEndHintBox = false; // flag to check whether the box shall be painted + bool showComHintBox = false; // flag to check whether the box shall be painted + bool showLoopHintBox = false; // flag to check whether the box shall be painted + int jump_not_until = 0; // any jump shall be avoided until this time (in seconds from moviestart) + MI_BOOKMARK new_bookmark; // used for new movie info bookmarks created from the movieplayer + new_bookmark.pos = 0; // clear , since this is used as flag for bookmark activity + new_bookmark.length = 0; + + // very dirty usage of the menue, but it works and I already spent to much time with it, feel free to make it better ;-) +#define BOOKMARK_START_MENU_MAX_ITEMS 6 + CSelectedMenu cSelectedMenuBookStart[BOOKMARK_START_MENU_MAX_ITEMS]; + + CMenuWidget bookStartMenu(LOCALE_MOVIEBROWSER_BOOK_NEW, "streaming.raw"); + bookStartMenu.addItem(GenericMenuSeparator); + bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEPLAYER_HEAD, true, NULL, &cSelectedMenuBookStart[0])); + bookStartMenu.addItem(GenericMenuSeparatorLine); + bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_HEAD, true, NULL, &cSelectedMenuBookStart[1])); + bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_TYPE_FORWARD, true, NULL, &cSelectedMenuBookStart[2])); + bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_TYPE_BACKWARD, true, NULL, &cSelectedMenuBookStart[3])); + bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIESTART, true, NULL, &cSelectedMenuBookStart[4])); + bookStartMenu.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_BOOK_MOVIEEND, true, NULL, &cSelectedMenuBookStart[5])); + + rct = 0; + + go_repeat: + do { + + if (exit) { + exit = false; + printf("[movieplayer] stop\n"); + playstate = CMoviePlayerGui::STOPPED; + break; + } + + if (timesh) { + char fname[255]; + int cnt = 10 * 1000000; + while (!strlen(rec_filename)) { + usleep(1000); + cnt -= 1000; + if (!cnt) + break; + } + if (!strlen(rec_filename)) + return; + + sprintf(fname, "%s.ts", rec_filename); + filename = fname; + sel_filename = std::string(rindex(filename, '/') + 1); + printf("Timeshift: %s\n", sel_filename.c_str()); + + update_lcd = true; + start_play = true; + open_filebrowser = false; + isBookmark = false; + timesh = false; + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + FileTime.SetMode(CTimeOSD::MODE_DESC); + FileTime.show(position / 1000); + FileTime.updatePos(file_prozent); + } + + if (isBookmark) { + open_filebrowser = false; + filename = startfilename.c_str(); + sel_filename = startfilename; + update_lcd = true; + start_play = true; + isBookmark = false; + timeshift = false; + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8); + } + + if (isMovieBrowser == true) { + // do all moviebrowser stuff here ( like commercial jump ect.) + if (playstate == CMoviePlayerGui::PLAY) { + playback->GetPosition(position, duration); + int play_sec = position / 1000; // get current seconds from moviestart + //TRACE(" %6ds\r\n",play_sec); + + if (play_sec + 10 < jump_not_until || play_sec > jump_not_until + 10) + jump_not_until = 0; // check if !jump is stale (e.g. if user jumped forward or backward) + if (new_bookmark.pos == 0) // do bookmark activities only, if there is no new bookmark started + { + if (p_movie_info != NULL) // process bookmarks if we have any movie info + { + if (p_movie_info->bookmarks.end != 0) { + // *********** Check for stop position ******************************* + if (play_sec >= p_movie_info->bookmarks.end - MOVIE_HINT_BOX_TIMER && play_sec < p_movie_info->bookmarks.end && play_sec > jump_not_until) { + if (showEndHintBox == false) { + endHintBox.paint(); // we are 5 sec before the end postition, show warning + showEndHintBox = true; + TRACE("[mp] user stop in 5 sec...\r\n"); + } + } else { + if (showEndHintBox == true) { + endHintBox.hide(); // if we showed the warning before, hide the box again + showEndHintBox = false; + } + } + + if (play_sec >= p_movie_info->bookmarks.end && play_sec <= p_movie_info->bookmarks.end + 2 && play_sec > jump_not_until) // stop playing + { + // *********** we ARE close behind the stop position, stop playing ******************************* + TRACE("[mp] user stop\r\n"); + playstate = CMoviePlayerGui::STOPPED; + } + } + // ************* Check for bookmark jumps ******************************* + int loop = true; + showLoopHintBox = false; + showComHintBox = false; + for (int book_nr = 0; book_nr < MI_MOVIE_BOOK_USER_MAX && loop == true; book_nr++) { + if (p_movie_info->bookmarks.user[book_nr].pos != 0 && p_movie_info->bookmarks.user[book_nr].length != 0) { + // valid bookmark found, now check if we are close before or after it + if (play_sec >= p_movie_info->bookmarks.user[book_nr].pos - MOVIE_HINT_BOX_TIMER && play_sec < p_movie_info->bookmarks.user[book_nr].pos && play_sec > jump_not_until) { + if (p_movie_info->bookmarks.user[book_nr].length < 0) + showLoopHintBox = true; // we are 5 sec before , show warning + else if (p_movie_info->bookmarks.user[book_nr].length > 0) + showComHintBox = true; // we are 5 sec before, show warning + //else // TODO should we show a plain bookmark infomation as well? + } + + if (play_sec >= p_movie_info->bookmarks.user[book_nr].pos && play_sec <= p_movie_info->bookmarks.user[book_nr].pos + 2 && play_sec > jump_not_until) // + { + //for plain bookmark, the following calc shall result in 0 (no jump) + g_jumpseconds = p_movie_info->bookmarks.user[book_nr].length; + + // we are close behind the bookmark, do bookmark activity (if any) + if (p_movie_info->bookmarks.user[book_nr].length < 0) { + // if the jump back time is to less, it does sometimes cause problems (it does probably jump only 5 sec which will cause the next jump, and so on) + if (g_jumpseconds > -15) + g_jumpseconds = -15; + + g_jumpseconds = g_jumpseconds + p_movie_info->bookmarks.user[book_nr].pos; + //playstate = CMoviePlayerGui::JPOS; // bookmark is of type loop, jump backward + playback->SetPosition(g_jumpseconds * 1000); + } else if (p_movie_info->bookmarks.user[book_nr].length > 0) { + // jump at least 15 seconds + if (g_jumpseconds < 15) + g_jumpseconds = 15; + g_jumpseconds = g_jumpseconds + p_movie_info->bookmarks.user[book_nr].pos; + + //playstate = CMoviePlayerGui::JPOS; // bookmark is of type loop, jump backward + playback->SetPosition(g_jumpseconds * 1000); + } + TRACE("[mp] do jump %d sec\r\n", g_jumpseconds); + update_lcd = true; + loop = false; // do no further bookmark checks + } + } + } + // check if we shall show the commercial warning + if (showComHintBox == true) { + comHintBox.paint(); + TRACE("[mp] com jump in 5 sec...\r\n"); + } else + comHintBox.hide(); + + // check if we shall show the loop warning + if (showLoopHintBox == true) { + loopHintBox.paint(); + TRACE("[mp] loop jump in 5 sec...\r\n"); + } else + loopHintBox.hide(); + } + } + } + } // isMovieBrowser == true + + if (open_filebrowser) { + open_filebrowser = false; + timeshift = false; + FileTime.hide(); + /*clear audipopids */ + for (int i = 0; i < g_numpida; i++) { + g_apids[i] = 0; + g_ac3flags[i] = 0; + g_language[i].clear(); + } + g_numpida = 0; g_currentapid = 0; + + if (isMovieBrowser == true) { + // start the moviebrowser instead of the filebrowser + if (moviebrowser->exec(Path_local.c_str())) { + // get the current path and file name + Path_local = moviebrowser->getCurrentDir(); + CFile *file; + + if ((file = moviebrowser->getSelectedFile()) != NULL) { + CFile::FileType ftype; + ftype = file->getType(); + + if(ftype == CFile::FILE_AVI || ftype == CFile::FILE_MKV) { + is_file_player = true; // Movie player AVI/MKV + } else { + is_file_player = false; // Movie player AVI/MKV + } + filename = file->Name.c_str(); + sel_filename = file->getFileName(); + + // get the movie info handle (to be used for e.g. bookmark handling) + p_movie_info = moviebrowser->getCurrentMovieInfo(); + bool recfile = CNeutrinoApp::getInstance()->recordingstatus && !strncmp(rec_filename, filename, strlen(rec_filename)); + if (!recfile && p_movie_info->length) { + minuteoffset = file->Size / p_movie_info->length; + minuteoffset = (minuteoffset / MP_TS_SIZE) * MP_TS_SIZE; + if (minuteoffset < 5000000 || minuteoffset > 190000000) + minuteoffset = MINUTEOFFSET; + secondoffset = minuteoffset / 60; + } + + if(!p_movie_info->audioPids.empty()) { + g_currentapid = p_movie_info->audioPids[0].epgAudioPid; //FIXME + g_currentac3 = p_movie_info->audioPids[0].atype; + } + for (int i = 0; i < (int)p_movie_info->audioPids.size(); i++) { + g_apids[i] = p_movie_info->audioPids[i].epgAudioPid; + g_ac3flags[i] = p_movie_info->audioPids[i].atype; + g_numpida++; + if (p_movie_info->audioPids[i].selected) { + g_currentapid = p_movie_info->audioPids[i].epgAudioPid; //FIXME + g_currentac3 = p_movie_info->audioPids[i].atype; + //break; + } + } + g_vpid = p_movie_info->epgVideoPid; + g_vtype = p_movie_info->VideoType; + printf("CMoviePlayerGui::PlayFile: file %s apid %X atype %d vpid %x vtype %d\n", filename, g_currentapid, g_currentac3, g_vpid, g_vtype); + printf("Bytes per minute: %lld\n", minuteoffset); + // get the start position for the movie + startposition = 1000 * moviebrowser->getCurrentStartPos(); + //TRACE("[mp] start pos %llu, %d s Name: %s\r\n", startposition, moviebrowser->getCurrentStartPos(), filename); + + update_lcd = true; + start_play = true; + was_file = true; + } + } else if (playstate == CMoviePlayerGui::STOPPED) { + was_file = false; + break; + } + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8); + } else { + filebrowser->Filter = &tsfilefilter; + + if (filebrowser->exec(Path_local.c_str()) == true) { + Path_local = filebrowser->getCurrentDir(); + CFile *file; + if ((file = filebrowser->getSelectedFile()) != NULL) { + + CFile::FileType ftype; + ftype = file->getType(); + + is_file_player = true; +#if 0 + if(ftype == CFile::FILE_AVI || ftype == CFile::FILE_MKV || ftype == CFile::FILE_WAV || ftype == CFile::FILE_ASF) { + + is_file_player = true; // Movie player AVI/MKV + + } else { + is_file_player = false; // Movie player AVI/MKV + } +#endif + + filename = file->Name.c_str(); + update_lcd = true; + start_play = true; + was_file = true; + sel_filename = filebrowser->getSelectedFile()->getFileName(); + //playstate = CMoviePlayerGui::PLAY; + } + } else if (playstate == CMoviePlayerGui::STOPPED) { + was_file = false; + break; + } + + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8); + } + } + + if (update_lcd) { + update_lcd = false; + if (isMovieBrowser && strlen(p_movie_info->epgTitle.c_str()) && strncmp(p_movie_info->epgTitle.c_str(), "not", 3)) + updateLcd(p_movie_info->epgTitle); + else + updateLcd(sel_filename); + } + + if (showaudioselectdialog) { + CMenuWidget APIDSelector(LOCALE_APIDSELECTOR_HEAD, "audio.raw", 300); + APIDSelector.addItem(GenericMenuSeparator); + CAPIDSelectExec *APIDChanger = new CAPIDSelectExec; + bool enabled; + bool defpid; + if(is_file_player && !g_numpida){ + playback->FindAllPids(g_apids, g_ac3flags, &g_numpida, g_language); + } + for (unsigned int count = 0; count < g_numpida; count++) { + bool name_ok; + char apidnumber[10]; + sprintf(apidnumber, "%d %X", count + 1, g_apids[count]); + enabled = true; + defpid = g_currentapid ? (g_currentapid == g_apids[count]) : (count == 0); + std::string apidtitle = "Stream "; + if(!is_file_player){ + name_ok = get_movie_info_apid_name(g_apids[count], p_movie_info, &apidtitle); + } + else if (!g_language[count].empty()){ + apidtitle = g_language[count]; + name_ok = true; + } + if (!name_ok) + apidtitle = "Stream "; + + switch(g_ac3flags[count]) + { + case 1: /*AC3,EAC3*/ + if (apidtitle.find("AC3") < 0 || is_file_player) + apidtitle.append(" (AC3)"); + break; + case 2: /*teletext*/ + apidtitle.append(" (Teletext)"); + enabled = false; + break; + case 3: /*MP2*/ + apidtitle.append(" (MP2)"); + break; + case 4: /*MP3*/ + apidtitle.append(" (MP3)"); + break; + case 5: /*AAC*/ + apidtitle.append(" (AAC)"); + break; + case 6: /*DTS*/ + apidtitle.append(" (DTS)"); + enabled = false; + break; + case 7: /*MLP*/ + apidtitle.append(" (MLP)"); + break; + default: + break; + } + if (!name_ok) + apidtitle.append(apidnumber); + + APIDSelector.addItem(new CMenuForwarderNonLocalized(apidtitle.c_str(), enabled, NULL, APIDChanger, apidnumber, CRCInput::convertDigitToKey(count + 1)), defpid); + } + + apidchanged = 0; + APIDSelector.exec(NULL, ""); + if (apidchanged) { + if (g_currentapid == 0) { + g_currentapid = g_apids[0]; + g_currentac3 = g_ac3flags[0]; + } + playback->SetAPid(g_currentapid, g_currentac3); + apidchanged = 0; + } + delete APIDChanger; + showaudioselectdialog = false; + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8); + update_lcd = true; + } + + if (FileTime.IsVisible() /*FIXME && playstate == CMoviePlayerGui::PLAY */ ) { + if (FileTime.GetMode() == CTimeOSD::MODE_ASC) { + FileTime.update(position / 1000); + } else { + FileTime.update((duration - position) / 1000); + } + FileTime.updatePos(file_prozent); + } + + if (start_play) { + printf("Startplay at %d seconds\n", startposition/1000); + start_play = false; + if (playstate >= CMoviePlayerGui::PLAY) { + playstate = CMoviePlayerGui::STOPPED; + playback->Close(); + } + + cutNeutrino(); + playback->Open(is_file_player ? PLAYMODE_FILE : PLAYMODE_TS); + + printf("IS FILE PLAYER: %s\n", is_file_player ? "true": "false" ); + + if(!playback->Start((char *)filename, g_vpid, g_vtype, g_currentapid, g_currentac3)) { + playback->Close(); + restoreNeutrino(); + } else { + playstate = CMoviePlayerGui::PLAY; + CVFD::getInstance()->ShowIcon(VFD_ICON_PLAY, true); + if(timeshift) { + timeshift_paused = true; + startposition = -1; + int i; + int towait = (timeshift == 1) ? TIMESHIFT_SECONDS+1 : TIMESHIFT_SECONDS; + for(i = 0; i < 500; i++) { + playback->GetPosition(position, duration); + startposition = (duration - position); + + //printf("CMoviePlayerGui::PlayFile: waiting for data, position %d duration %d (%d)\n", position, duration, towait); + if(startposition > towait*1000) + break; + //sleep(1); + usleep(20000); + } + if(timeshift == 3) { + startposition = duration; + } else { + if(g_settings.timeshift_pause) + playstate = CMoviePlayerGui::PAUSE; + if(timeshift == 1) + startposition = 0; + else + startposition = duration - TIMESHIFT_SECONDS*1000; + } + printf("******************* Timeshift %d, position %d, seek to %d seconds\n", timeshift, position, startposition/1000); + } + if(!is_file_player && startposition >= 0)//FIXME no jump for file at start yet + playback->SetPosition(startposition, true); + + if(timeshift == 3) { + playback->SetSpeed(-1); + } else if(!timeshift || !g_settings.timeshift_pause) { + playback->SetSpeed(1); + } + } + } + + g_RCInput->getMsg(&msg, &data, 10); // 1 secs.. + + if(timeshift && g_settings.timeshift_pause) { + if(!timeshift_paused && !videoDecoder->getBlank()) { + playback->SetSpeed(0); + timeshift_paused = true; + playstate = CMoviePlayerGui::PAUSE; + } + } + if ((playstate >= CMoviePlayerGui::PLAY) && (timeshift || (playstate != CMoviePlayerGui::PAUSE))) { + if(playback->GetPosition(position, duration)) { + if(duration > 100) + file_prozent = (unsigned char) (position / (duration / 100)); + playback->GetSpeed(speed); + printf("CMoviePlayerGui::PlayFile: speed %d position %d duration %d (%d, %d%%)\n", speed, position, duration, duration-position, file_prozent); + } + } + + if (msg == (neutrino_msg_t) g_settings.mpkey_plugin) { + //g_PluginList->start_plugin_by_name (g_settings.movieplayer_plugin.c_str (), pidt); + } else if (msg == (neutrino_msg_t) g_settings.mpkey_stop) { + //exit play + playstate = CMoviePlayerGui::STOPPED; + if (isMovieBrowser == true && p_movie_info != NULL) { + // if we have a movie information, try to save the stop position + ftime(¤t_time); + p_movie_info->dateOfLastPlay = current_time.time; + current_time.time = time(NULL); + p_movie_info->bookmarks.lastPlayStop = position / 1000; + + cMovieInfo.saveMovieInfo(*p_movie_info); + //p_movie_info->fileInfoStale(); //TODO: we might to tell the Moviebrowser that the movie info has changed, but this could cause long reload times when reentering the Moviebrowser + } + + if (!was_file) + exit = true; + } else if (msg == (neutrino_msg_t) g_settings.mpkey_play) { + if (playstate >= CMoviePlayerGui::PLAY) { + update_lcd = true; + playstate = CMoviePlayerGui::PLAY; + speed = 1; + playback->SetSpeed(speed); + } else if (!timeshift) { + open_filebrowser = true; + } + if (time_forced) { + time_forced = false; + if (g_settings.mode_clock) + InfoClock->StopClock(); + FileTime.hide(); + } + } else if (msg == (neutrino_msg_t) g_settings.mpkey_pause) { + update_lcd = true; + if (playstate == CMoviePlayerGui::PAUSE) { + playstate = CMoviePlayerGui::PLAY; + //CVFD::getInstance()->ShowIcon(VFD_ICON_PAUSE, false); + speed = 1; + playback->SetSpeed(speed); + } else { + playstate = CMoviePlayerGui::PAUSE; + //CVFD::getInstance()->ShowIcon(VFD_ICON_PAUSE, true); + speed = 0; + playback->SetSpeed(speed); + } + } else if (msg == (neutrino_msg_t) g_settings.mpkey_bookmark) { + // is there already a bookmark activity? + if (isMovieBrowser != true) { + if (bookmarkmanager->getBookmarkCount() < bookmarkmanager->getMaxBookmarkCount()) { + char timerstring[200]; + fprintf(stderr, "fileposition: %lld\n", fullposition); + sprintf(timerstring, "%lld", fullposition); + fprintf(stderr, "timerstring: %s\n", timerstring); + std::string bookmarktime = ""; + bookmarktime.append(timerstring); + fprintf(stderr, "bookmarktime: %s\n", bookmarktime.c_str()); + bookmarkmanager->createBookmark(filename, bookmarktime); + fprintf(stderr, "bookmark done\n"); + } else { + fprintf(stderr, "too many bookmarks\n"); + DisplayErrorMessage(g_Locale->getText(LOCALE_MOVIEPLAYER_TOOMANYBOOKMARKS)); // UTF-8 + } + } else { + int pos_sec = position / 1000; + if (newComHintBox.isPainted() == true) { + // yes, let's get the end pos of the jump forward + new_bookmark.length = pos_sec - new_bookmark.pos; + TRACE("[mp] commercial length: %d\r\n", new_bookmark.length); + if (cMovieInfo.addNewBookmark(p_movie_info, new_bookmark) == true) { + cMovieInfo.saveMovieInfo(*p_movie_info); /* save immediately in xml file */ + } + new_bookmark.pos = 0; // clear again, since this is used as flag for bookmark activity + newComHintBox.hide(); + } else if (newLoopHintBox.isPainted() == true) { + // yes, let's get the end pos of the jump backward + new_bookmark.length = new_bookmark.pos - pos_sec; + new_bookmark.pos = pos_sec; + TRACE("[mp] loop length: %d\r\n", new_bookmark.length); + if (cMovieInfo.addNewBookmark(p_movie_info, new_bookmark) == true) { + cMovieInfo.saveMovieInfo(*p_movie_info); /* save immediately in xml file */ + jump_not_until = pos_sec + 5; // avoid jumping for this time + } + new_bookmark.pos = 0; // clear again, since this is used as flag for bookmark activity + newLoopHintBox.hide(); + } else { + // no, nothing else to do, we open a new bookmark menu + new_bookmark.name = ""; // use default name + new_bookmark.pos = 0; + new_bookmark.length = 0; + + // next seems return menu_return::RETURN_EXIT, if something selected + bookStartMenu.exec(NULL, "none"); + if (cSelectedMenuBookStart[0].selected == true) { + /* Movieplayer bookmark */ + if (bookmarkmanager->getBookmarkCount() < bookmarkmanager->getMaxBookmarkCount()) { + char timerstring[200]; + fprintf(stderr, "fileposition: %lld\n", fullposition); + sprintf(timerstring, "%lld", fullposition); + fprintf(stderr, "timerstring: %s\n", timerstring); + std::string bookmarktime = ""; + bookmarktime.append(timerstring); + fprintf(stderr, "bookmarktime: %s\n", bookmarktime.c_str()); + bookmarkmanager->createBookmark(filename, bookmarktime); + } else { + fprintf(stderr, "too many bookmarks\n"); + DisplayErrorMessage(g_Locale->getText(LOCALE_MOVIEPLAYER_TOOMANYBOOKMARKS)); // UTF-8 + } + cSelectedMenuBookStart[0].selected = false; // clear for next bookmark menu + } else if (cSelectedMenuBookStart[1].selected == true) { + /* Moviebrowser plain bookmark */ + new_bookmark.pos = pos_sec; + new_bookmark.length = 0; + if (cMovieInfo.addNewBookmark(p_movie_info, new_bookmark) == true) + cMovieInfo.saveMovieInfo(*p_movie_info); /* save immediately in xml file */ + new_bookmark.pos = 0; // clear again, since this is used as flag for bookmark activity + cSelectedMenuBookStart[1].selected = false; // clear for next bookmark menu + } else if (cSelectedMenuBookStart[2].selected == true) { + /* Moviebrowser jump forward bookmark */ + new_bookmark.pos = pos_sec; + TRACE("[mp] new bookmark 1. pos: %d\r\n", new_bookmark.pos); + newComHintBox.paint(); + + cSelectedMenuBookStart[2].selected = false; // clear for next bookmark menu + } else if (cSelectedMenuBookStart[3].selected == true) { + /* Moviebrowser jump backward bookmark */ + new_bookmark.pos = pos_sec; + TRACE("[mp] new bookmark 1. pos: %d\r\n", new_bookmark.pos); + newLoopHintBox.paint(); + cSelectedMenuBookStart[3].selected = false; // clear for next bookmark menu + } else if (cSelectedMenuBookStart[4].selected == true) { + /* Moviebrowser movie start bookmark */ + p_movie_info->bookmarks.start = pos_sec; + TRACE("[mp] New movie start pos: %d\r\n", p_movie_info->bookmarks.start); + cMovieInfo.saveMovieInfo(*p_movie_info); /* save immediately in xml file */ + cSelectedMenuBookStart[4].selected = false; // clear for next bookmark menu + } else if (cSelectedMenuBookStart[5].selected == true) { + /* Moviebrowser movie end bookmark */ + p_movie_info->bookmarks.end = pos_sec; + TRACE("[mp] New movie end pos: %d\r\n", p_movie_info->bookmarks.start); + cMovieInfo.saveMovieInfo(*p_movie_info); /* save immediately in xml file */ + cSelectedMenuBookStart[5].selected = false; // clear for next bookmark menu + } + } + } + } else if (msg == (neutrino_msg_t) g_settings.mpkey_audio) { + showaudioselectdialog = true; + } else if (msg == CRCInput::RC_help) { + if (timeshift) + g_InfoViewer->showTitle(CNeutrinoApp::getInstance()->channelList->getActiveChannelNumber(), CNeutrinoApp::getInstance()->channelList->getActiveChannelName(), CNeutrinoApp::getInstance()->channelList->getActiveSatellitePosition(), CNeutrinoApp::getInstance()->channelList->getActiveChannel_ChannelID()); // UTF-8 + + else { + if (isMovieBrowser) { + g_file_epg = p_movie_info->epgTitle; + g_file_epg1 = p_movie_info->epgInfo1; + g_InfoViewer->showTitle(0, p_movie_info->epgChannel.c_str(), 0, 0); // UTF-8 + + } else { + char temp_name[255]; + char *slash = strrchr(filename, '/'); + if (slash) { + slash++; + int len = strlen(slash); + for (int i = 0; i < len; i++) { + if (slash[i] == '_') + temp_name[i] = ' '; + else + temp_name[i] = slash[i]; + } + temp_name[len] = 0; + } + g_file_epg = ""; + g_file_epg1 = ""; + g_InfoViewer->showTitle(0, temp_name, 0, 0); // UTF-8 + } + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8); + update_lcd = true; + //showHelpTS(); + } + } else if (msg == (neutrino_msg_t) g_settings.mpkey_time) { + if (FileTime.IsVisible()) { + if (FileTime.GetMode() == CTimeOSD::MODE_ASC) { + FileTime.SetMode(CTimeOSD::MODE_DESC); + FileTime.update((duration - position) / 1000); + FileTime.updatePos(file_prozent); + } else { + if (g_settings.mode_clock) + InfoClock->StopClock(); + FileTime.hide(); + } + } else { + if (g_settings.mode_clock) + InfoClock->StartClock(); + FileTime.SetMode(CTimeOSD::MODE_ASC); + FileTime.show(position / 1000); + FileTime.updatePos(file_prozent); + } + } else if (msg == (neutrino_msg_t) g_settings.mpkey_rewind) { // rewind + if (speed >= 0) + speed = -1; + else + speed --; + + playback->SetSpeed(speed); + playstate = CMoviePlayerGui::REW; + update_lcd = true; + if (!FileTime.IsVisible()) { + if (g_settings.mode_clock) + InfoClock->StartClock(); + FileTime.SetMode(CTimeOSD::MODE_ASC); + FileTime.show(position / 1000); + FileTime.updatePos(file_prozent); + time_forced = true; + } + } else if (msg == (neutrino_msg_t) g_settings.mpkey_forward) { // fast-forward + if (speed <= 0) + speed = 2; + else + speed ++; + + playback->SetSpeed(speed); + + update_lcd = true; + playstate = CMoviePlayerGui::FF; + + if (!FileTime.IsVisible()) { + if (g_settings.mode_clock) + InfoClock->StartClock(); + FileTime.SetMode(CTimeOSD::MODE_ASC); + FileTime.show(position / 1000); + FileTime.updatePos(file_prozent); + time_forced = true; + } + } else if (msg == CRCInput::RC_1) { // Jump Backwards 1 minute + //update_lcd = true; + playback->SetPosition(-60 * 1000); + } else if (msg == CRCInput::RC_3) { // Jump Forward 1 minute + //update_lcd = true; + playback->SetPosition(60 * 1000); + } else if (msg == CRCInput::RC_4) { // Jump Backwards 5 minutes + playback->SetPosition(-5 * 60 * 1000); + } else if (msg == CRCInput::RC_6) { // Jump Forward 5 minutes + playback->SetPosition(5 * 60 * 1000); + } else if (msg == CRCInput::RC_7) { // Jump Backwards 10 minutes + playback->SetPosition(-10 * 60 * 1000); + } else if (msg == CRCInput::RC_9) { // Jump Forward 10 minutes + playback->SetPosition(10 * 60 * 1000); + } else if (msg == CRCInput::RC_2) { // goto start + playback->SetPosition(0, true); + } else if (msg == CRCInput::RC_5) { // goto middle + playback->SetPosition(duration/2, true); + } else if (msg == CRCInput::RC_8) { // goto end + playback->SetPosition(duration - 60 * 1000, true); + } else if (msg == CRCInput::RC_page_up) { + playback->SetPosition(10 * 1000); + } else if (msg == CRCInput::RC_page_down) { + playback->SetPosition(-10 * 1000); + } else if (msg == CRCInput::RC_0) { // cancel bookmark jump + if (isMovieBrowser == true) { + if (new_bookmark.pos != 0) { + new_bookmark.pos = 0; // stop current bookmark activity, TODO: might bemoved to another key + newLoopHintBox.hide(); // hide hint box if any + newComHintBox.hide(); + } + jump_not_until = (position / 1000) + 10; // avoid bookmark jumping for the next 10 seconds, , TODO: might be moved to another key + } else if (playstate != CMoviePlayerGui::PAUSE) + playstate = CMoviePlayerGui::SOFTRESET; + } else if (msg == CRCInput::RC_up || msg == CRCInput::RC_down) { + if (msg == CRCInput::RC_up) { + if (slow == 2) + slow = 0; + if (slow > 0) + slow--; + } else if (msg == CRCInput::RC_down) { + if (slow == 0) + slow++; + slow++; + } + //set_slow (slow); + update_lcd = true; + } else if (msg == CRCInput::RC_radio) { + if (isMovieBrowser == true && p_movie_info != NULL) { + std::string fname = p_movie_info->file.Name; + strReplace(fname, ".ts", ".bmp"); + CVCRControl::getInstance()->Screenshot(0, (char *)fname.c_str()); + } + } +#if 0 + else if (msg == CRCInput::RC_shift_radio) { + if (isMovieBrowser == true && p_movie_info != NULL) { + time_t t = time(NULL); + char filename[512]; + sprintf(filename, "%s", p_movie_info->file.Name.c_str()); + int pos = strlen(filename); + strftime(&(filename[pos - 3]), sizeof(filename) - pos - 1, "%Y%m%d_%H%M%S", localtime(&t)); + strcat(filename, ".bmp"); + CVCRControl::getInstance()->Screenshot(0, filename); + } + } +#endif + else if (msg == CRCInput::RC_timeout) { + // nothing + } else if ((msg == NeutrinoMessages::ANNOUNCE_RECORD) || msg == NeutrinoMessages::RECORD_START || msg == NeutrinoMessages::ZAPTO || msg == NeutrinoMessages::STANDBY_ON || msg == NeutrinoMessages::SHUTDOWN || msg == NeutrinoMessages::SLEEPTIMER) { // Exit for Record/Zapto Timers + exit = true; + g_RCInput->postMsg(msg, data); + } else { + if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) + exit = true; + else if ( msg <= CRCInput::RC_MaxRC ) { + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8); + update_lcd = true; + } + } + + if (exit) { + if (isMovieBrowser == true && p_movie_info != NULL) { + // if we have a movie information, try to save the stop position + ftime(¤t_time); + p_movie_info->dateOfLastPlay = current_time.time; + current_time.time = time(NULL); + p_movie_info->bookmarks.lastPlayStop = position / 1000; + + cMovieInfo.saveMovieInfo(*p_movie_info); + //p_movie_info->fileInfoStale(); //TODO: we might to tell the Moviebrowser that the movie info has changed, but this could cause long reload times when reentering the Moviebrowser + } + } + } while (playstate >= CMoviePlayerGui::PLAY); + + FileTime.hide(); + + playback->SetSpeed(1); + playback->Close(); + + CVFD::getInstance()->ShowIcon(VFD_ICON_PLAY, false); + CVFD::getInstance()->ShowIcon(VFD_ICON_PAUSE, false); + + if (was_file) { + restoreNeutrino(); + open_filebrowser = true; + start_play = true; + goto go_repeat; + } + + if (g_settings.mode_clock) + InfoClock->StartClock(); +} + +// checks if AR has changed an sets cropping mode accordingly (only video mode auto) +static short archeck; +void checkAspectRatio(int vdec, bool init) +{ + static time_t last_check = 0; + + // only necessary for auto mode, check each 5 sec. max + if (g_settings.video_Format != 0 || (!init && time(NULL) <= last_check + archeck)) + return; +#if 0 + char aspectRatio = 2; + if (init) { + aspectRatio = g_Controld->getAspectRatio(); + last_check = 0; + archeck = 1; + return; + } else { + char newRatio = g_Controld->getAspectRatio(); + if (newRatio != aspectRatio) { + printf("[movieplayer] AR change detected in auto mode, adjusting display format\n"); + video_displayformat_t vdt; + if (newRatio == 2) + vdt = VIDEO_LETTER_BOX; + else + vdt = VIDEO_CENTER_CUT_OUT; + if (ioctl(vdec, VIDEO_SET_DISPLAY_FORMAT, vdt)) + perror("[movieplayer] VIDEO_SET_DISPLAY_FORMAT"); + aspectRatio = newRatio; + archeck = 5; + } + last_check = time(NULL); + } +#endif +} + +void CMoviePlayerGui::showHelpTS() +{ + Helpbox helpbox; + helpbox.addLine(NEUTRINO_ICON_BUTTON_RED, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP1)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_GREEN, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP2)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_YELLOW, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP3)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_BLUE, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP4)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_DBOX, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP5)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_1, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP6)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_3, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP7)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_4, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP8)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_6, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP9)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_7, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP10)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_9, g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP11)); + helpbox.addLine(g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP12)); + helpbox.addLine("Version: $Revision: 1.97 $"); + helpbox.addLine("Movieplayer (c) 2003, 2004 by gagga"); + hide(); + helpbox.show(LOCALE_MESSAGEBOX_INFO); +} + +void CMoviePlayerGui::showHelpVLC() +{ + Helpbox helpbox; + helpbox.addLine(NEUTRINO_ICON_BUTTON_RED, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP1)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_GREEN, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP2)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_YELLOW, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP3)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_BLUE, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP4)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_DBOX, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP5)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_1, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP6)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_3, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP7)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_4, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP8)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_6, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP9)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_7, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP10)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_9, g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP11)); + helpbox.addLine(g_Locale->getText(LOCALE_MOVIEPLAYER_VLCHELP12)); + helpbox.addLine("Version: $Revision: 1.97 $"); + helpbox.addLine("Movieplayer (c) 2003, 2004 by gagga"); + hide(); + helpbox.show(LOCALE_MESSAGEBOX_INFO); +} diff --git a/src/gui/movieplayer.h b/src/gui/movieplayer.h new file mode 100644 index 000000000..21e65c3cd --- /dev/null +++ b/src/gui/movieplayer.h @@ -0,0 +1,117 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2003,2004 gagga + Homepage: http://www.giggo.de/dbox + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __movieplayergui__ +#define __movieplayergui__ + +#include +#include +#if HAVE_DVB_API_VERSION >= 1 +#include "driver/framebuffer.h" +#include "gui/filebrowser.h" +#include "gui/bookmarkmanager.h" +#include "gui/widget/menue.h" +#include "gui/moviebrowser.h" +#include "gui/movieinfo.h" + +extern "C" { + #include +} +#include + +#include +#include + +class CMoviePlayerGui : public CMenuTarget +{ + public: + enum state + { + STOPPED = 0, + PREPARING = 1, + STREAMERROR = 2, + PLAY = 3, + PAUSE = 4, + FF = 5, + REW = 6, + RESYNC = 7, + JPOS = 8, // jump to absolute position + JF = 9, + JB = 10, + SKIP = 11, + AUDIOSELECT = 12, + SOFTRESET = 99 + }; + + private: + void Init(void); + pthread_t rct; + CFrameBuffer * frameBuffer; + int m_LastMode; + const char *filename; + bool stopped; + + std::string Path_local; + std::string Path_vlc; + std::string Path_vlc_settings; + + CFileBrowser * filebrowser; + CMovieBrowser* moviebrowser; + + CBookmarkManager * bookmarkmanager; + + void PlayStream(int streamtype); + void PlayFile(); + void cutNeutrino(); + void restoreNeutrino(); + + CFileFilter tsfilefilter; + CFileFilter pesfilefilter; + CFileFilter vlcfilefilter; + void showHelpTS(void); + void showHelpVLC(void); + + public: + CMoviePlayerGui(); + ~CMoviePlayerGui(); + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + + +class CAPIDSelectExec : public CMenuTarget +{ + public: + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + +#endif + +#endif diff --git a/src/gui/nfs.cpp b/src/gui/nfs.cpp new file mode 100644 index 000000000..aa926700d --- /dev/null +++ b/src/gui/nfs.cpp @@ -0,0 +1,406 @@ +/* + Neutrino-GUI - DBoxII-Project + + NFSMount/Umount GUI by Zwen + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include + +class CNFSMountGuiNotifier : public CChangeObserver +{ +private: + CMenuForwarder *m_opt1,*m_opt2, *m_user, *m_pass; + int *m_type; +public: + CNFSMountGuiNotifier( CMenuForwarder* a3, CMenuForwarder* a4 , int* type) + { + m_user = a3; + m_pass = a4; + m_type = type; + } + bool changeNotify(const neutrino_locale_t OptionName, void *) + { + if(*m_type == (int)CFSMounter::NFS) + { + m_user->setActive (false); + m_pass->setActive (false); + } + else + { + m_user->setActive (true); + m_pass->setActive (true); + } + return true; + } +}; + +CNFSMountGui::CNFSMountGui() +{ +#warning move probing from exec() to fsmounter + m_nfs_sup = CFSMounter::FS_UNPROBED; + m_cifs_sup = CFSMounter::FS_UNPROBED; + m_lufs_sup = CFSMounter::FS_UNPROBED; + +} + + +const char * nfs_entry_printf_string[3] = +{ + "NFS %s:%s -> %s auto: %4s", + "CIFS //%s/%s -> %s auto: %4s", + "FTPFS %s/%s -> %s auto: %4s" +}; + + +int CNFSMountGui::exec( CMenuTarget* parent, const std::string & actionKey ) +{ + //printf("exec: %s\n", actionKey.c_str()); + int returnval = menu_return::RETURN_REPAINT; + + if (m_nfs_sup == CFSMounter::FS_UNPROBED) + m_nfs_sup = CFSMounter::fsSupported(CFSMounter::NFS); + + if (m_cifs_sup == CFSMounter::FS_UNPROBED) + m_cifs_sup = CFSMounter::fsSupported(CFSMounter::CIFS); + + if (m_lufs_sup == CFSMounter::FS_UNPROBED) + m_lufs_sup = CFSMounter::fsSupported(CFSMounter::LUFS); + + printf("SUPPORT: NFS: %d, CIFS: %d, LUFS: %d\n", m_nfs_sup, m_cifs_sup, m_lufs_sup); + + if (actionKey.empty()) + { + parent->hide(); + for(int i=0 ; i < NETWORK_NFS_NR_OF_ENTRIES; i++) + { + sprintf(m_entry[i], + nfs_entry_printf_string[(g_settings.network_nfs_type[i] == (int) CFSMounter::NFS) ? 0 : ((g_settings.network_nfs_type[i] == (int) CFSMounter::CIFS) ? 1 : 2)], + g_settings.network_nfs_ip[i].c_str(), + FILESYSTEM_ENCODING_TO_UTF8(g_settings.network_nfs_dir[i]), + FILESYSTEM_ENCODING_TO_UTF8(g_settings.network_nfs_local_dir[i]), + g_Locale->getText(g_settings.network_nfs_automount[i] ? LOCALE_MESSAGEBOX_YES : LOCALE_MESSAGEBOX_NO)); + } + returnval = menu(); + } + else if(actionKey.substr(0,10)=="mountentry") + { + parent->hide(); + returnval = menuEntry(actionKey[10]-'0'); + for(int i=0 ; i < NETWORK_NFS_NR_OF_ENTRIES; i++) + { + sprintf(m_entry[i], + nfs_entry_printf_string[(g_settings.network_nfs_type[i] == (int) CFSMounter::NFS) ? 0 : ((g_settings.network_nfs_type[i] == (int) CFSMounter::CIFS) ? 1 : 2)], + g_settings.network_nfs_ip[i].c_str(), + FILESYSTEM_ENCODING_TO_UTF8(g_settings.network_nfs_dir[i]), + FILESYSTEM_ENCODING_TO_UTF8(g_settings.network_nfs_local_dir[i]), + g_Locale->getText(g_settings.network_nfs_automount[i] ? LOCALE_MESSAGEBOX_YES : LOCALE_MESSAGEBOX_NO)); + sprintf(ISO_8859_1_entry[i],ZapitTools::UTF8_to_Latin1(m_entry[i]).c_str()); + } + } + else if(actionKey.substr(0,7)=="domount") + { + int nr=atoi(actionKey.substr(7,1).c_str()); + CFSMounter::mount(g_settings.network_nfs_ip[nr].c_str(), g_settings.network_nfs_dir[nr], + g_settings.network_nfs_local_dir[nr], (CFSMounter::FSType) g_settings.network_nfs_type[nr], + g_settings.network_nfs_username[nr], g_settings.network_nfs_password[nr], + g_settings.network_nfs_mount_options1[nr], g_settings.network_nfs_mount_options2[nr]); + // TODO show msg in case of error + returnval = menu_return::RETURN_EXIT; + } + else if(actionKey.substr(0,3)=="dir") + { + parent->hide(); + int nr=atoi(actionKey.substr(3,1).c_str()); + CFileBrowser b; + b.Dir_Mode=true; + + if (b.exec(g_settings.network_nfs_local_dir[nr])) + strcpy(g_settings.network_nfs_local_dir[nr], b.getSelectedFile()->Name.c_str()); + + returnval = menu_return::RETURN_REPAINT; + } + return returnval; +} + +int CNFSMountGui::menu() +{ + CMenuWidget mountMenuW(LOCALE_NFS_MOUNT, "network.raw", 720); + mountMenuW.addItem(GenericMenuSeparator); + mountMenuW.addItem(GenericMenuBack); + mountMenuW.addItem(GenericMenuSeparatorLine); + char s2[12]; + + for(int i=0 ; i < NETWORK_NFS_NR_OF_ENTRIES ; i++) + { + sprintf(s2,"mountentry%d",i); + sprintf(ISO_8859_1_entry[i],ZapitTools::UTF8_to_Latin1(m_entry[i]).c_str()); + CMenuForwarderNonLocalized *forwarder = new CMenuForwarderNonLocalized("", true, ISO_8859_1_entry[i], this, s2); + if (CFSMounter::isMounted(g_settings.network_nfs_local_dir[i])) + { + forwarder->iconName = NEUTRINO_ICON_MOUNTED; + } else + { + forwarder->iconName = NEUTRINO_ICON_NOT_MOUNTED; + } + mountMenuW.addItem(forwarder); + } + int ret=mountMenuW.exec(this,""); + return ret; +} + +#warning MESSAGEBOX_NO_YES_XXX is defined in neutrino.cpp, too! +#define MESSAGEBOX_NO_YES_OPTION_COUNT 2 +const CMenuOptionChooser::keyval MESSAGEBOX_NO_YES_OPTIONS[MESSAGEBOX_NO_YES_OPTION_COUNT] = +{ + { 0, LOCALE_MESSAGEBOX_NO }, + { 1, LOCALE_MESSAGEBOX_YES } +}; + +#define NFS_TYPE_OPTION_COUNT 3 +const CMenuOptionChooser::keyval NFS_TYPE_OPTIONS[NFS_TYPE_OPTION_COUNT] = +{ + { CFSMounter::NFS , LOCALE_NFS_TYPE_NFS }, + { CFSMounter::CIFS, LOCALE_NFS_TYPE_CIFS } /*, + { CFSMounter::LUFS, LOCALE_NFS_TYPE_LUFS } */ +}; + +int CNFSMountGui::menuEntry(int nr) +{ + char *dir,*local_dir, *username, *password, *options1, *options2, *mac; + int* automount; + int* type; + char cmd[9]; + char cmd2[9]; + + dir = g_settings.network_nfs_dir[nr]; + local_dir = g_settings.network_nfs_local_dir[nr]; + username = g_settings.network_nfs_username[nr]; + password = g_settings.network_nfs_password[nr]; + automount = &g_settings.network_nfs_automount[nr]; + type = &g_settings.network_nfs_type[nr]; + options1 = g_settings.network_nfs_mount_options1[nr]; + options2 = g_settings.network_nfs_mount_options2[nr]; + mac = g_settings.network_nfs_mac[nr]; + + sprintf(cmd,"domount%d",nr); + sprintf(cmd2,"dir%d",nr); + + /* rewrite fstype in new entries */ + if(strlen(local_dir)==0) + { + if(m_cifs_sup != CFSMounter::FS_UNSUPPORTED && m_nfs_sup == CFSMounter::FS_UNSUPPORTED && m_lufs_sup == CFSMounter::FS_UNSUPPORTED) + *type = (int) CFSMounter::CIFS; + + else if(m_lufs_sup != CFSMounter::FS_UNSUPPORTED && m_cifs_sup == CFSMounter::FS_UNSUPPORTED && m_nfs_sup == CFSMounter::FS_UNSUPPORTED) + *type = (int) CFSMounter::LUFS; + } + bool typeEnabled = (m_cifs_sup != CFSMounter::FS_UNSUPPORTED && m_nfs_sup != CFSMounter::FS_UNSUPPORTED && m_lufs_sup != CFSMounter::FS_UNSUPPORTED) || + (m_cifs_sup != CFSMounter::FS_UNSUPPORTED && *type != (int)CFSMounter::CIFS) || + (m_nfs_sup != CFSMounter::FS_UNSUPPORTED && *type != (int)CFSMounter::NFS) || + (m_lufs_sup != CFSMounter::FS_UNSUPPORTED && *type != (int)CFSMounter::LUFS); + + CMenuWidget mountMenuEntryW(LOCALE_NFS_MOUNT, "network.raw",720); + mountMenuEntryW.addItem(GenericMenuSeparator); + mountMenuEntryW.addItem(GenericMenuBack); + mountMenuEntryW.addItem(GenericMenuSeparatorLine); + CIPInput ipInput(LOCALE_NFS_IP, g_settings.network_nfs_ip[nr], LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CStringInputSMS dirInput(LOCALE_NFS_DIR, dir, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE,"abcdefghijklmnopqrstuvwxyz0123456789-_.,:|!?/ "); + CMenuOptionChooser *automountInput= new CMenuOptionChooser(LOCALE_NFS_AUTOMOUNT, automount, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); + CStringInputSMS options1Input(LOCALE_NFS_MOUNT_OPTIONS, options1, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-_=.,:|!?/ "); + CMenuForwarder *options1_fwd = new CMenuForwarder(LOCALE_NFS_MOUNT_OPTIONS, true, options1, &options1Input); + CStringInputSMS options2Input(LOCALE_NFS_MOUNT_OPTIONS, options2, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-_=.,:|!?/ "); + CMenuForwarder *options2_fwd = new CMenuForwarder(LOCALE_NFS_MOUNT_OPTIONS, true, options2, &options2Input); + CStringInputSMS userInput(LOCALE_NFS_USERNAME, username, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-_.,:|!?/ "); + CMenuForwarder *username_fwd = new CMenuForwarder(LOCALE_NFS_USERNAME, (*type==CFSMounter::CIFS || CFSMounter::LUFS), username, &userInput); + CStringInputSMS passInput(LOCALE_NFS_PASSWORD, password, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-_.,:|!?/ "); + CMenuForwarder *password_fwd = new CMenuForwarder(LOCALE_NFS_PASSWORD, (*type==CFSMounter::CIFS || CFSMounter::LUFS), NULL, &passInput); + CMACInput * macInput = new CMACInput(LOCALE_RECORDINGMENU_SERVER_MAC, g_settings.network_nfs_mac[nr], LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CMenuForwarder * macInput_fwd = new CMenuForwarder(LOCALE_RECORDINGMENU_SERVER_MAC, true, g_settings.network_nfs_mac[nr], macInput); + + CNFSMountGuiNotifier notifier(username_fwd, password_fwd, type); + + mountMenuEntryW.addItem(new CMenuOptionChooser(LOCALE_NFS_TYPE, type, NFS_TYPE_OPTIONS, NFS_TYPE_OPTION_COUNT, typeEnabled, ¬ifier)); + mountMenuEntryW.addItem(new CMenuForwarder(LOCALE_NFS_IP , true, g_settings.network_nfs_ip[nr], &ipInput )); + mountMenuEntryW.addItem(new CMenuForwarder(LOCALE_NFS_DIR , true, dir , &dirInput )); + mountMenuEntryW.addItem(new CMenuForwarder(LOCALE_NFS_LOCALDIR, true, local_dir , this , cmd2)); + mountMenuEntryW.addItem(automountInput); + mountMenuEntryW.addItem(options1_fwd); + mountMenuEntryW.addItem(options2_fwd); + mountMenuEntryW.addItem(username_fwd); + mountMenuEntryW.addItem(password_fwd); + mountMenuEntryW.addItem(macInput_fwd); + mountMenuEntryW.addItem(new CMenuForwarder(LOCALE_NFS_MOUNTNOW, true, NULL , this , cmd )); + + int ret = mountMenuEntryW.exec(this,""); + return ret; +} + +int CNFSUmountGui::exec( CMenuTarget* parent, const std::string & actionKey ) +{ + // printf("ac: %s\n", actionKey.c_str()); + int returnval; + + if (actionKey.empty()) + { + parent->hide(); + returnval = menu(); + } + else if(actionKey.substr(0,8)=="doumount") + { + CFSMounter::umount((actionKey.substr(9)).c_str()); + returnval = menu_return::RETURN_EXIT; + } + else + returnval = menu_return::RETURN_REPAINT; + + return returnval; +} +int CNFSUmountGui::menu() +{ + int count = 0; + CFSMounter::MountInfos infos; + CMenuWidget umountMenu(LOCALE_NFS_UMOUNT, "network.raw",720); + umountMenu.addItem(GenericMenuSeparator); + umountMenu.addItem(GenericMenuBack); + umountMenu.addItem(GenericMenuSeparatorLine); + CFSMounter::getMountedFS(infos); + for (CFSMounter::MountInfos::const_iterator it = infos.begin(); + it != infos.end();it++) + { + if(it->type == "nfs" || it->type == "cifs" || it->type == "lufs") + { + count++; + std::string s1 = it->device; + s1 += " -> "; + s1 += it->mountPoint; + std::string s2 = "doumount "; + s2 += it->mountPoint; + CMenuForwarder *forwarder = new CMenuForwarderNonLocalized(s1.c_str(), true, NULL, this, s2.c_str()); + forwarder->iconName = NEUTRINO_ICON_MOUNTED; + umountMenu.addItem(forwarder); + } + } + if(infos.size() > 0) + return umountMenu.exec(this,""); + else + return menu_return::RETURN_REPAINT; +} + + + +int CNFSSmallMenu::exec( CMenuTarget* parent, const std::string & actionKey ) +{ + if (actionKey.empty()) + { + CMenuWidget menu(LOCALE_NFSMENU_HEAD, "network.raw"); + CNFSMountGui mountGui; + CNFSUmountGui umountGui; + menu.addItem(GenericMenuSeparator); + menu.addItem(GenericMenuBack); + menu.addItem(GenericMenuSeparatorLine); + menu.addItem(new CMenuForwarder(LOCALE_NFS_REMOUNT, true, NULL, this, "remount")); + menu.addItem(new CMenuForwarder(LOCALE_NFS_MOUNT , true, NULL, & mountGui)); + menu.addItem(new CMenuForwarder(LOCALE_NFS_UMOUNT, true, NULL, &umountGui)); + return menu.exec(parent, actionKey); + } + else if(actionKey.substr(0,7) == "remount") + { + //umount automount dirs + for(int i = 0; i < NETWORK_NFS_NR_OF_ENTRIES; i++) + { + if(g_settings.network_nfs_automount[i]) + umount2(g_settings.network_nfs_local_dir[i],MNT_FORCE); + } + CFSMounter::automount(); + return menu_return::RETURN_REPAINT; + } + return menu_return::RETURN_REPAINT; +} + +const char * mntRes2Str(CFSMounter::MountRes res) +{ + switch(res) + { + case CFSMounter::MRES_FS_NOT_SUPPORTED: + return g_Locale->getText(LOCALE_NFS_MOUNTERROR_NOTSUP); + break; + case CFSMounter::MRES_FS_ALREADY_MOUNTED: + return g_Locale->getText(LOCALE_NFS_ALREADYMOUNTED); + break; + case CFSMounter::MRES_TIMEOUT: + return g_Locale->getText(LOCALE_NFS_MOUNTTIMEOUT); + break; + case CFSMounter::MRES_UNKNOWN: + return g_Locale->getText(LOCALE_NFS_MOUNTERROR); + break; + case CFSMounter::MRES_OK: + return g_Locale->getText(LOCALE_NFS_MOUNTOK); + break; + default: + return g_Locale->getText(NONEXISTANT_LOCALE); + break; + } +} + +const char * mntRes2Str(CFSMounter::UMountRes res) +{ + switch(res) + { + case CFSMounter::UMRES_ERR: + return g_Locale->getText(LOCALE_NFS_UMOUNTERROR); + break; + case CFSMounter::UMRES_OK: + return g_Locale->getText(NONEXISTANT_LOCALE); + break; + default: + return g_Locale->getText(NONEXISTANT_LOCALE); + break; + } +} diff --git a/src/gui/nfs.h b/src/gui/nfs.h new file mode 100644 index 000000000..97726e097 --- /dev/null +++ b/src/gui/nfs.h @@ -0,0 +1,86 @@ +/* + Neutrino-GUI - DBoxII-Project + + NFS Mount/Umount GUI by Zwen + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __neutrino_nfs_gui__ +#define __neutrino_nfs_gui__ + +#include +#include +#include + + +class CNFSMountGui : public CMenuTarget +{ + + private: + int menu(); + int menuEntry(int nr); + + char m_entry[NETWORK_NFS_NR_OF_ENTRIES][200]; + char ISO_8859_1_entry[NETWORK_NFS_NR_OF_ENTRIES][200]; + + CFSMounter::FS_Support m_nfs_sup; + CFSMounter::FS_Support m_cifs_sup; + CFSMounter::FS_Support m_lufs_sup; + + public: + CNFSMountGui(); + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + +class CNFSUmountGui : public CMenuTarget +{ + private: + + int menu(); + + public: + CNFSUmountGui(){}; + ~CNFSUmountGui(){}; + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + +class CNFSSmallMenu : public CMenuTarget +{ + private: + + public: + CNFSSmallMenu(){}; + ~CNFSSmallMenu(){}; + int exec( CMenuTarget* parent, const std::string & actionKey ); +}; + +const char * mntRes2Str(CFSMounter::MountRes res); +const char * mntRes2Str(CFSMounter::UMountRes res); + + +#endif diff --git a/src/gui/pictureviewer.cpp b/src/gui/pictureviewer.cpp new file mode 100644 index 000000000..71129b028 --- /dev/null +++ b/src/gui/pictureviewer.cpp @@ -0,0 +1,720 @@ +/* + Neutrino-GUI - DBoxII-Project + + MP3Player by Dirch + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +// remove this +#include + +#include +#include + +#include + +#include +#include +#include + +#define ROUND_RADIUS 9 + +//------------------------------------------------------------------------ +bool comparePictureByDate (const CPicture& a, const CPicture& b) +{ + return a.Date < b.Date ; +} +//------------------------------------------------------------------------ +extern bool comparetolower(const char a, const char b); /* filebrowser.cpp */ +//------------------------------------------------------------------------ +bool comparePictureByFilename (const CPicture& a, const CPicture& b) +{ + return std::lexicographical_compare(a.Filename.begin(), a.Filename.end(), b.Filename.begin(), b.Filename.end(), comparetolower); +} +//------------------------------------------------------------------------ + +CPictureViewerGui::CPictureViewerGui() +{ + frameBuffer = CFrameBuffer::getInstance(); + + visible = false; + selected = 0; + m_sort = FILENAME; + m_viewer = new CPictureViewer(); + if(strlen(g_settings.network_nfs_picturedir)!=0) + Path = g_settings.network_nfs_picturedir; + else + Path = "/"; + + picture_filter.addFilter("png"); + picture_filter.addFilter("bmp"); + picture_filter.addFilter("jpg"); + picture_filter.addFilter("jpeg"); + picture_filter.addFilter("gif"); + picture_filter.addFilter("crw"); +} + +//------------------------------------------------------------------------ + +CPictureViewerGui::~CPictureViewerGui() +{ + playlist.clear(); + delete m_viewer; +} + +//------------------------------------------------------------------------ +int CPictureViewerGui::exec(CMenuTarget* parent, const std::string & actionKey) +{ + selected = 0; + width = 710; + height = 570; + + if((g_settings.screen_EndX- g_settings.screen_StartX) < width) + width=(g_settings.screen_EndX- g_settings.screen_StartX); + if((g_settings.screen_EndY- g_settings.screen_StartY) < height) + height=(g_settings.screen_EndY- g_settings.screen_StartY); + + sheight = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight(); + buttonHeight = std::min(25, sheight); + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + listmaxshow = (height-theight-2*buttonHeight)/(fheight); + height = theight+2*buttonHeight+listmaxshow*fheight; // recalc height + + x=(((g_settings.screen_EndX- g_settings.screen_StartX)-width) / 2) + g_settings.screen_StartX; + y=(((g_settings.screen_EndY- g_settings.screen_StartY)-height)/ 2) + g_settings.screen_StartY; + + m_viewer->SetScaling((CPictureViewer::ScalingMode)g_settings.picviewer_scaling); + m_viewer->SetVisible(g_settings.screen_StartX, g_settings.screen_EndX, g_settings.screen_StartY, g_settings.screen_EndY); + + if(g_settings.video_Format == 3) + m_viewer->SetAspectRatio(16.0/9); + else + m_viewer->SetAspectRatio(4.0/3); + + if(parent) + parent->hide(); + + // tell neutrino we're in pic_mode + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , NeutrinoMessages::mode_pic ); + // remember last mode + m_LastMode=(CNeutrinoApp::getInstance()->getLastMode() | NeutrinoMessages::norezap); + + g_Sectionsd->setPauseScanning(true); + + show(); + + // free picviewer mem + m_viewer->Cleanup(); + + // Start Sectionsd + g_Sectionsd->setPauseScanning(false); + + // Restore last mode + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , m_LastMode ); + + // always exit all + return menu_return::RETURN_REPAINT; +} + +//------------------------------------------------------------------------ + +int CPictureViewerGui::show() +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = -1; + + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, g_Locale->getText(LOCALE_PICTUREVIEWER_HEAD)); + m_state=MENU; + + int timeout; + + bool loop=true; + bool update=true; + + while(loop) + { + if(update) + { + hide(); + update=false; + paint(); + } + + if(m_state!=SLIDESHOW) + timeout=50; // egal + else + { + timeout=(m_time+atoi(g_settings.picviewer_slide_time)-(long)time(NULL))*10; + if(timeout <0 ) + timeout=1; + } + g_RCInput->getMsg( &msg, &data, timeout ); + + if( msg == CRCInput::RC_home) + { //Exit after cancel key + if(m_state!=MENU) + { + endView(); + update=true; + } + else + loop=false; + } + else if (msg == CRCInput::RC_timeout) + { + if(m_state == SLIDESHOW) + { + m_time=(long)time(NULL); + unsigned int next = selected + 1; + if (next >= playlist.size()) + next = 0; + view(next); + } + } + else if (msg == CRCInput::RC_left) + { + if (!playlist.empty()) + { + if (m_state == MENU) + { + if (selected < listmaxshow) + selected=playlist.size()-1; + else + selected -= listmaxshow; + liststart = (selected/listmaxshow)*listmaxshow; + paint(); + } + else + { + view((selected == 0) ? (playlist.size() - 1) : (selected - 1)); + } + } + } + else if (msg == CRCInput::RC_right) + { + if (!playlist.empty()) + { + if (m_state == MENU) + { + selected += listmaxshow; + if (selected >= playlist.size()) { + if (((playlist.size() / listmaxshow) + 1) * listmaxshow == playlist.size() + listmaxshow) + selected=0; + else + selected = selected < (((playlist.size() / listmaxshow) + 1) * listmaxshow) ? (playlist.size() - 1) : 0; + } + liststart = (selected/listmaxshow)*listmaxshow; + paint(); + } + else + { + unsigned int next = selected + 1; + if (next >= playlist.size()) + next = 0; + view(next); + } + } + } + else if (msg == CRCInput::RC_up) + { + if ((m_state == MENU) && (!playlist.empty())) + { + int prevselected=selected; + if(selected==0) + { + selected = playlist.size()-1; + } + else + selected--; + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + update=true; + } + else + { + paintItem(selected - liststart); + } + } + } + else if (msg == CRCInput::RC_down) + { + if ((m_state == MENU) && (!playlist.empty())) + { + int prevselected=selected; + selected = (selected+1)%playlist.size(); + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + update=true; + } + else + { + paintItem(selected - liststart); + } + } + } + else if (msg == CRCInput::RC_ok) + { + if (!playlist.empty()) + view(selected); + } + else if (msg == CRCInput::RC_red) + { + if (m_state == MENU) + { + if (!playlist.empty()) + { + CViewList::iterator p = playlist.begin()+selected; + playlist.erase(p); + if (selected >= playlist.size()) + selected = playlist.size()-1; + update = true; + } + } + } + else if(msg==CRCInput::RC_green) + { + if (m_state == MENU) + { + CFileBrowser filebrowser((g_settings.filebrowser_denydirectoryleave) ? g_settings.network_nfs_picturedir : ""); + + filebrowser.Multi_Select = true; + filebrowser.Dirs_Selectable = true; + filebrowser.Filter = &picture_filter; + + hide(); + + if (filebrowser.exec(Path.c_str())) + { + Path = filebrowser.getCurrentDir(); + CFileList::const_iterator files = filebrowser.getSelectedFiles().begin(); + for(; files != filebrowser.getSelectedFiles().end();files++) + { + if(files->getType() == CFile::FILE_PICTURE) + { + CPicture pic; + pic.Filename = files->Name; + std::string tmp = files->Name.substr(files->Name.rfind('/')+1); + pic.Name = tmp.substr(0,tmp.rfind('.')); + pic.Type = tmp.substr(tmp.rfind('.')+1); + struct stat statbuf; + if(stat(pic.Filename.c_str(),&statbuf) != 0) + printf("stat error"); + pic.Date = statbuf.st_mtime; + playlist.push_back(pic); + } + else + printf("Wrong Filetype %s:%d\n",files->Name.c_str(), files->getType()); + } + if (m_sort == FILENAME) + std::sort(playlist.begin(), playlist.end(), comparePictureByFilename); + else if (m_sort == DATE) + std::sort(playlist.begin(), playlist.end(), comparePictureByDate); + } + update=true; + } + } + else if(msg==CRCInput::RC_yellow) + { + if (m_state == MENU && !playlist.empty()) + { + playlist.clear(); + selected=0; + update=true; + } + } + else if(msg==CRCInput::RC_blue) + { + if ((m_state == MENU) && (!playlist.empty())) + { + m_time=(long)time(NULL); + view(selected); + m_state=SLIDESHOW; + } else { + if(m_state == SLIDESHOW) + m_state = VIEW; + else + m_state = SLIDESHOW; + } + } + else if(msg==CRCInput::RC_help) + { + if (m_state == MENU) + { + showHelp(); + paint(); + } + } + else if( msg == CRCInput::RC_1 ) + { + if (m_state != MENU) + { + m_viewer->Zoom(2.0/3); + } + + } + else if( msg == CRCInput::RC_2 ) + { + if (m_state != MENU) + { + m_viewer->Move(0,-50); + } + } + else if( msg == CRCInput::RC_3 ) + { + if (m_state != MENU) + { + m_viewer->Zoom(1.5); + } + + } + else if( msg == CRCInput::RC_4 ) + { + if (m_state != MENU) + { + m_viewer->Move(-50,0); + } + } + else if ( msg == CRCInput::RC_5 ) + { + if(m_state==MENU) + { + if (!playlist.empty()) + { + if(m_sort==FILENAME) + { + m_sort=DATE; + std::sort(playlist.begin(),playlist.end(),comparePictureByDate); + } + else if(m_sort==DATE) + { + m_sort=FILENAME; + std::sort(playlist.begin(),playlist.end(),comparePictureByFilename); + } + update=true; + } + } + } + else if( msg == CRCInput::RC_6 ) + { + if (m_state != MENU && playlist.empty()) + { + m_viewer->Move(50,0); + } + } + else if( msg == CRCInput::RC_8 ) + { + if (m_state != MENU && playlist.empty()) + { + m_viewer->Move(0,50); + } + } + else if(msg==CRCInput::RC_0) + { + if (!playlist.empty()) + view(selected, true); + } + else if(msg==CRCInput::RC_setup) + { + if(m_state==MENU) + { + CNFSSmallMenu nfsMenu; + nfsMenu.exec(this, ""); + update=true; + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, g_Locale->getText(LOCALE_PICTUREVIEWER_HEAD)); + } + } + else if(msg == NeutrinoMessages::CHANGEMODE) + { + if((data & NeutrinoMessages::mode_mask) !=NeutrinoMessages::mode_pic) + { + loop = false; + m_LastMode=data; + } + } + else if(msg == NeutrinoMessages::RECORD_START || + msg == NeutrinoMessages::ZAPTO || + msg == NeutrinoMessages::STANDBY_ON || + msg == NeutrinoMessages::SHUTDOWN || + msg == NeutrinoMessages::SLEEPTIMER) + { + // Exit for Record/Zapto Timers + if (m_state != MENU) + endView(); + loop = false; + g_RCInput->postMsg(msg, data); + } + else if((msg == CRCInput::RC_sat) || (msg == CRCInput::RC_favorites)) { + } + else + { + if( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + } + } + } + hide(); + + return(res); +} + +//------------------------------------------------------------------------ + +void CPictureViewerGui::hide() +{ + if(visible) { + frameBuffer->paintBackground(); + visible = false; + } +} + +//------------------------------------------------------------------------ + +void CPictureViewerGui::paintItem(int pos) +{ +// printf("paintItem{\n"); + int ypos = y+ theight + 0 + pos*fheight; + + uint8_t color; + fb_pixel_t bgcolor; + + if ((liststart+pos < playlist.size()) && (pos & 1) ) + { + color = COL_MENUCONTENTDARK; + bgcolor = COL_MENUCONTENTDARK_PLUS_0; + } + else + { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + } + + if (liststart+pos == selected) + { + frameBuffer->paintBoxRel(x,ypos, width-15, fheight, bgcolor); + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + + frameBuffer->paintBoxRel(x,ypos, width-15, fheight, bgcolor, liststart+pos == selected ? ROUND_RADIUS : 0, 3); + if(liststart+posgetRenderWidth(timestring); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10,ypos+fheight, width-30 - w, tmp, color, fheight, true); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+width-20-w,ypos+fheight, w, timestring, color, fheight); + + } +// printf("paintItem}\n"); +} + +//------------------------------------------------------------------------ + +void CPictureViewerGui::paintHead() +{ +// printf("paintHead{\n"); + std::string strCaption = g_Locale->getText(LOCALE_PICTUREVIEWER_HEAD); + frameBuffer->paintBoxRel(x,y, width,theight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + frameBuffer->paintIcon("mp3.raw",x+7,y+10); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+35,y+theight+0, width- 45, strCaption, COL_MENUHEAD, 0, true); // UTF-8 + int ypos=y+0; + if(theight > 26) + ypos = (theight-26) / 2 + y ; + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, x+ width- 60, ypos ); + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DBOX, x+ width- 30, ypos ); +// printf("paintHead}\n"); +} + +//------------------------------------------------------------------------ +const struct button_label PictureViewerButtons[4] = +{ + { NEUTRINO_ICON_BUTTON_RED , LOCALE_AUDIOPLAYER_DELETE }, + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_AUDIOPLAYER_ADD }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_DELETEALL }, + { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_PICTUREVIEWER_SLIDESHOW } +}; + +void CPictureViewerGui::paintFoot() +{ +// printf("paintFoot{\n"); + int ButtonWidth = (width-20) / 4; + int ButtonWidth2 = (width-50) / 2; + frameBuffer->paintBoxRel(x,y+(height-2*buttonHeight), width,2*buttonHeight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2); + frameBuffer->paintHLine(x, x+width, y+(height-2*buttonHeight), COL_INFOBAR_SHADOW_PLUS_0); + + if (!playlist.empty()) + { + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, x + 1* ButtonWidth2 + 25, y+(height-buttonHeight)-3); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x + 1 * ButtonWidth2 + 53 , y+(height-buttonHeight)+24 - 4, ButtonWidth2- 28, g_Locale->getText(LOCALE_PICTUREVIEWER_SHOW), COL_INFOBAR, 0, true); // UTF-8 + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_5, x+ 0* ButtonWidth2 + 25, y+(height-buttonHeight)-3); + std::string tmp = g_Locale->getText(LOCALE_PICTUREVIEWER_SORTORDER); + tmp += ' '; + if(m_sort==FILENAME) + tmp += g_Locale->getText(LOCALE_PICTUREVIEWER_SORTORDER_DATE); + else if(m_sort==DATE) + tmp += g_Locale->getText(LOCALE_PICTUREVIEWER_SORTORDER_FILENAME); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+ 0* ButtonWidth2 +53 , y+(height-buttonHeight)+24 - 4, ButtonWidth2- 28, tmp, COL_INFOBAR, 0, true); // UTF-8 + + + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 10, y + (height - 2 * buttonHeight) + 4, ButtonWidth, 4, PictureViewerButtons); + } + else + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + ButtonWidth + 10, y + (height - 2 * buttonHeight) + 4, ButtonWidth, 1, &(PictureViewerButtons[1])); +// printf("paintFoot}\n"); +} +//------------------------------------------------------------------------ +void CPictureViewerGui::paintInfo() +{ +} +//------------------------------------------------------------------------ + +void CPictureViewerGui::paint() +{ + liststart = (selected/listmaxshow)*listmaxshow; + + paintHead(); + for(unsigned int count=0;countpaintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((playlist.size()- 1)/ listmaxshow)+ 1; + float sbh= (sb- 4)/ sbc; + int sbs= (selected/listmaxshow); + + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ int(sbs* sbh) , 11, int(sbh), COL_MENUCONTENT_PLUS_3); + + paintFoot(); + paintInfo(); + + visible = true; +} + +void CPictureViewerGui::view(unsigned int index, bool unscaled) +{ + selected=index; + + CVFD::getInstance()->showMenuText(0, playlist[index].Name.c_str()); + char timestring[19]; + strftime(timestring, 18, "%d-%m-%Y %H:%M", gmtime(&playlist[index].Date)); + //CVFD::getInstance()->showMenuText(1, timestring); //FIXME + + if(unscaled) + m_viewer->DecodeImage(playlist[index].Filename, true, unscaled); + m_viewer->ShowImage(playlist[index].Filename, unscaled); + + //Decode next + unsigned int next=selected+1; + if(next > playlist.size()-1) + next=0; + if(m_state==MENU) + m_state=VIEW; + if(m_state==VIEW) + m_viewer->DecodeImage(playlist[next].Filename,true); + else + m_viewer->DecodeImage(playlist[next].Filename,false); +} + +void CPictureViewerGui::endView() +{ + if(m_state != MENU) + m_state=MENU; +} + +void CPictureViewerGui::showHelp() +{ + Helpbox helpbox; + helpbox.addLine(g_Locale->getText(LOCALE_PICTUREVIEWER_HELP1)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_OKAY, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP2)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_5, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP3)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_0, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP4)); + helpbox.addPagebreak(); + helpbox.addLine(g_Locale->getText(LOCALE_PICTUREVIEWER_HELP5)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_LEFT, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP6)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_RIGHT, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP7)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_5, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP8)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_HOME, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP9)); + helpbox.addPagebreak(); + helpbox.addLine(g_Locale->getText(LOCALE_PICTUREVIEWER_HELP10)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_OKAY, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP11)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_LEFT, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP12)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_RIGHT, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP13)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_1, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP14)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_3, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP15)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_2, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP16)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_4, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP17)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_6, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP18)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_8, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP19)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_5, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP20)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_0, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP21)); + helpbox.addLine(NEUTRINO_ICON_BUTTON_HOME, g_Locale->getText(LOCALE_PICTUREVIEWER_HELP22)); + + helpbox.addLine("Version: $Revision: 1.57 $"); + hide(); + helpbox.show(LOCALE_MESSAGEBOX_INFO); +} diff --git a/src/gui/pictureviewer.h b/src/gui/pictureviewer.h new file mode 100644 index 000000000..a9175c2a8 --- /dev/null +++ b/src/gui/pictureviewer.h @@ -0,0 +1,120 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __pictureviewergui__ +#define __pictureviewergui__ + + +#include "driver/framebuffer.h" +#include "driver/pictureviewer/pictureviewer.h" +#include "gui/widget/menue.h" +#include "gui/filebrowser.h" + +#include + +class CPicture +{ +public: + std::string Filename; + std::string Name; + std::string Type; + time_t Date; +}; + +typedef std::vector CViewList; + + +class CPictureViewerGui : public CMenuTarget +{ + public: + enum State + { + VIEW=0, + MENU, + SLIDESHOW + }; + enum SortOrder + { + DATE=0, + FILENAME, + NAME + }; + private: + CFrameBuffer *frameBuffer; + CPictureViewer *m_viewer; + unsigned int selected; + unsigned int liststart; + unsigned int listmaxshow; + int fheight; // Fonthoehe Playlist-Inhalt + int theight; // Fonthoehe Playlist-Titel + int sheight; // Fonthoehe MP Info + int buttonHeight; + bool visible; + State m_state; + SortOrder m_sort; + + CViewList playlist; + std::string Path; + + int width; + int height; + int x; + int y; + int m_title_w; + long m_time; + + int m_LastMode; + + void paintItem(int pos); + void paint(); + void paintHead(); + void paintFoot(); + void paintInfo(); + void paintLCD(); + void hide(); + + CFileFilter picture_filter; + void view(unsigned int nr, bool unscaled=false); + void endView(); + int show(); + + void showHelp(); + + public: + CPictureViewerGui(); + ~CPictureViewerGui(); + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + + +#endif + + diff --git a/src/gui/pluginlist.cpp b/src/gui/pluginlist.cpp new file mode 100644 index 000000000..ff30c1cdb --- /dev/null +++ b/src/gui/pluginlist.cpp @@ -0,0 +1,371 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* for alexW images with old drivers: + * #define USE_VBI_INTERFACE 1 + */ + +#ifdef USE_VBI_INTERFACE + #define AVIA_VBI_START_VTXT 1 + #define AVIA_VBI_STOP_VTXT 2 +#endif + +#include +extern CPlugins * g_PluginList; /* neutrino.cpp */ +extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ + +CPluginList::CPluginList(const neutrino_locale_t Name, const uint32_t listtype) +{ + frameBuffer = CFrameBuffer::getInstance(); + name = Name; + pluginlisttype = listtype; + selected = 0; + width = 500; + if(width>(g_settings.screen_EndX-g_settings.screen_StartX)) + width=(g_settings.screen_EndX-g_settings.screen_StartX); + height = 526; + if((height+50)>(g_settings.screen_EndY-g_settings.screen_StartY)) + height=(g_settings.screen_EndY-g_settings.screen_StartY) - 50; // 2*25 pixel frei + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + // + fheight1 = g_Font[SNeutrinoSettings::FONT_TYPE_GAMELIST_ITEMLARGE]->getHeight(); + fheight2 = g_Font[SNeutrinoSettings::FONT_TYPE_GAMELIST_ITEMSMALL]->getHeight(); + fheight = fheight1 + fheight2 + 2; + // + listmaxshow = (height-theight-0)/fheight; + height = theight+0+listmaxshow*fheight; // recalc height + x=(((g_settings.screen_EndX- g_settings.screen_StartX)-width) / 2) + g_settings.screen_StartX; + y=(((g_settings.screen_EndY- g_settings.screen_StartY)-height) / 2) + g_settings.screen_StartY; + liststart = 0; +} + +CPluginList::~CPluginList() +{ + for(unsigned int count=0;counthide(); + } + + //scan4plugins here! + for(unsigned int count=0;countname = g_Locale->getText(LOCALE_MENU_BACK); + pluginlist.push_back(tmp); + + for(unsigned int count=0;count < (unsigned int)g_PluginList->getNumberOfPlugins();count++) + { + if ((g_PluginList->getType(count) & pluginlisttype) && !g_PluginList->isHidden(count)) + { + tmp = new pluginitem(); + tmp->number = count; + tmp->name = g_PluginList->getName(count); + tmp->desc = g_PluginList->getDescription(count); + pluginlist.push_back(tmp); + } + } + + paint(); + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings::TIMING_MENU]); + + bool loop=true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings::TIMING_MENU]); + + if ( ( msg == CRCInput::RC_timeout ) || + ( msg == (neutrino_msg_t)g_settings.key_channelList_cancel ) ) + { + loop=false; + } + else if ( msg == (neutrino_msg_t)g_settings.key_channelList_pageup ) + { + if ((int(selected)-int(listmaxshow))<0) + selected=0; + else + selected -= listmaxshow; + liststart = (selected/listmaxshow)*listmaxshow; + paintItems(); + } + else if ( msg == (neutrino_msg_t)g_settings.key_channelList_pagedown ) + { + selected+=listmaxshow; + if (selected>pluginlist.size()-1) + selected=pluginlist.size()-1; + liststart = (selected/listmaxshow)*listmaxshow; + paintItems(); + } + else if ( msg == CRCInput::RC_up ) + { + int prevselected=selected; + if(selected==0) + { + selected = pluginlist.size()-1; + } + else + selected--; + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paintItems(); + } + else + { + paintItem(selected - liststart); + } + } + else if ( msg == CRCInput::RC_down ) + { + int prevselected=selected; + selected = (selected+1)%pluginlist.size(); + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paintItems(); + } + else + { + paintItem(selected - liststart); + } + } + else if ( msg == CRCInput::RC_ok ) + { + if(selected==0) + { + loop=false; + } + else + {//exec the plugin :)) + if (pluginSelected() == close) + { + loop=false; + } + } + } + else if( (msg== CRCInput::RC_red) || + (msg==CRCInput::RC_green) || + (msg==CRCInput::RC_yellow) || + (msg==CRCInput::RC_blue) || + (CRCInput::isNumeric(msg)) ) + { + g_RCInput->postMsg(msg, data); + loop=false; + } + else if ( CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + hide(); + return res; +} + +void CPluginList::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width+15,height); +} + +void CPluginList::paintItem(int pos) +{ + int ypos = (y+theight) + pos*fheight; + int itemheight = fheight; + + uint8_t color = COL_MENUCONTENT; + fb_pixel_t bgcolor = COL_MENUCONTENT_PLUS_0; + if (liststart+pos==selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + + if(liststart+pos==0) + { //back is half-height... + itemheight = (fheight / 2) + 3; + frameBuffer->paintBoxRel(x , ypos + itemheight , width , 15, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintBoxRel(x + 10, ypos + itemheight + 5, width - 20, 1, COL_MENUCONTENT_PLUS_5); + frameBuffer->paintBoxRel(x + 10, ypos + itemheight + 6, width - 20, 1, COL_MENUCONTENT_PLUS_2); + } + else if(liststart==0) + { + ypos -= (fheight / 2) - 15; + if(pos==(int)listmaxshow-1) + frameBuffer->paintBoxRel(x,ypos+itemheight, width, (fheight / 2)-15, COL_MENUCONTENT_PLUS_0); + + } + frameBuffer->paintBoxRel(x, ypos, width, itemheight, bgcolor); + + + if(liststart+posRenderString(x+10, ypos+fheight1+3, width-20, actplugin->name, color, 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_GAMELIST_ITEMSMALL]->RenderString(x+20, ypos+fheight, width-20, actplugin->desc, color, 0, true); // UTF-8 + } +} + +void CPluginList::paintHead() +{ + if(listmaxshow > pluginlist.size()+1) + frameBuffer->paintBoxRel(x,y, width,theight, COL_MENUHEAD_PLUS_0); + else + frameBuffer->paintBoxRel(x,y, width+15,theight, COL_MENUHEAD_PLUS_0); + + if(pluginlisttype == CPlugins::P_TYPE_GAME) + { + frameBuffer->paintIcon(NEUTRINO_ICON_GAMES,x+8,y+5); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+38,y+theight+1, width, g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + } else if (pluginlisttype == CPlugins::P_TYPE_SCRIPT) + { + frameBuffer->paintIcon(NEUTRINO_ICON_SHELL,x+8,y+5); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+38,y+theight+1, width, g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + } else + { + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+8,y+theight+1, width, g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + } +} + +void CPluginList::paint() +{ + hide(); + width = 500; + if(width>(g_settings.screen_EndX-g_settings.screen_StartX)) + width=(g_settings.screen_EndX-g_settings.screen_StartX); + height = 526; + if((height+50)>(g_settings.screen_EndY-g_settings.screen_StartY)) + height=(g_settings.screen_EndY-g_settings.screen_StartY) - 50; // 2*25 pixel frei + listmaxshow = (height-theight-0)/fheight; + height = theight+0+listmaxshow*fheight; // recalc height + x=(((g_settings.screen_EndX- g_settings.screen_StartX)-width) / 2) + g_settings.screen_StartX; + y=(((g_settings.screen_EndY- g_settings.screen_StartY)-height) / 2) + g_settings.screen_StartY; + + liststart = (selected/listmaxshow)*listmaxshow; + + paintHead(); + paintItems(); +} + +void CPluginList::paintItems() +{ + if(listmaxshow <= pluginlist.size()+1) + { + // Scrollbar + int nrOfPages = ((pluginlist.size()-1) / listmaxshow)+1; + int currPage = (liststart/listmaxshow) +1; + float blockHeight = (height-theight-4)/nrOfPages; + frameBuffer->paintBoxRel(x+width, y+theight, 15, height-theight, COL_MENUCONTENT_PLUS_1); + frameBuffer->paintBoxRel(x+ width +2, y+theight+2+int((currPage-1)*blockHeight) , 11, int(blockHeight), COL_MENUCONTENT_PLUS_3); + } + + for(unsigned int count=0;countstartPlugin(pluginlist[selected]->number,0); + if (!g_PluginList->getScriptOutput().empty()) + { + hide(); + //ShowMsgUTF(LOCALE_PLUGINS_RESULT, Latin1_to_UTF8(g_PluginList->getScriptOutput()), CMessageBox::mbrBack,CMessageBox::mbBack,NEUTRINO_ICON_SHELL); + ShowMsgUTF(LOCALE_PLUGINS_RESULT, g_PluginList->getScriptOutput(), CMessageBox::mbrBack,CMessageBox::mbBack,NEUTRINO_ICON_SHELL); + } + paint(); + return resume; +} + +CPluginChooser::CPluginChooser(const neutrino_locale_t Name, const uint32_t listtype, char* pluginname) + : CPluginList(Name, listtype), selected_plugin(pluginname) +{ +} + +CPluginList::result_ CPluginChooser::pluginSelected() +{ + strcpy(selected_plugin,g_PluginList->getFileName(pluginlist[selected]->number)); + return CPluginList::close; +} + diff --git a/src/gui/pluginlist.h b/src/gui/pluginlist.h new file mode 100644 index 000000000..0bc4e1465 --- /dev/null +++ b/src/gui/pluginlist.h @@ -0,0 +1,113 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __pluginlist__ +#define __pluginlist__ + +#include + +#include +#include + +#include +#include + +class CPluginList : public CMenuTarget +{ + + public: + enum result_ + { + close = 0, + resume = 1, + } result; + + private: + + CFrameBuffer *frameBuffer; + + struct pluginitem + { + int number; + std::string name; // UTF-8 encoded + std::string desc; // UTF-8 encoded + }; + + unsigned int liststart; + unsigned int listmaxshow; + int key; + neutrino_locale_t name; + uint32_t pluginlisttype; + + int fheight; // Fonthoehe Channellist-Inhalt + int theight; // Fonthoehe Channellist-Titel + + int fheight1,fheight2; + + int width; + int height; + int x; + int y; + + void paintItem(int pos); + void paintItems(); + void paint(); + void paintHead(); + + protected: + + unsigned int selected; + std::vector pluginlist; + + virtual CPluginList::result_ pluginSelected(); + + public: + + CPluginList(const neutrino_locale_t Name, const uint32_t listtype); + virtual ~CPluginList(); + + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + +class CPluginChooser : public CPluginList +{ + private: + char* selected_plugin; + protected: + + CPluginList::result_ pluginSelected(); + + public: + CPluginChooser(const neutrino_locale_t Name, const uint32_t listtype, char* pluginname); +}; + +#endif diff --git a/src/gui/plugins.cpp b/src/gui/plugins.cpp new file mode 100644 index 000000000..8cf39feb4 --- /dev/null +++ b/src/gui/plugins.cpp @@ -0,0 +1,618 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +/* for alexW images with old drivers: + * #define USE_VBI_INTERFACE 1 + */ + +#ifdef USE_VBI_INTERFACE + #define AVIA_VBI_START_VTXT 1 + #define AVIA_VBI_STOP_VTXT 2 +#endif + +#include +extern CPlugins * g_PluginList; /* neutrino.cpp */ +extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ + +#define PLUGINDIR_VAR "/var/tuxbox/plugins" +#define PLUGINDIR_HDD "/hdd/tuxbox/plugins" +#define PLUGINDIR_USB "/mnt/usb/tuxbox/plugins" + +bool CPlugins::plugin_exists(const std::string & filename) +{ + return (find_plugin(filename) >= 0); +} + +int CPlugins::find_plugin(const std::string & filename) +{ + for(int i = 0; i < (int) plugin_list.size();i++) + { + if( (filename.compare(plugin_list[i].filename) == 0) || (filename.compare(plugin_list[i].filename + ".cfg") == 0) ) + return i; + } + return -1; +} + +bool CPlugins::pluginfile_exists(const std::string & filename) +{ + FILE *file = fopen(filename.c_str(),"r"); + if (file != NULL) + { + fclose(file); + return true; + } else + { + return false; + } +} + +void CPlugins::scanDir(const char *dir) +{ + struct dirent **namelist; + std::string fname; + + int number_of_files = scandir(dir, &namelist, 0, alphasort); + + for (int i = 0; i < number_of_files; i++) + { + std::string filename; + + filename = namelist[i]->d_name; + int pos = filename.find(".cfg"); + if (pos > -1) + { + plugin new_plugin; + new_plugin.filename = filename.substr(0, pos); + fname = dir; + fname += '/'; + new_plugin.cfgfile = fname.append(new_plugin.filename); + new_plugin.cfgfile.append(".cfg"); + parseCfg(&new_plugin); + bool plugin_ok = parseCfg(&new_plugin); + if (plugin_ok) { + new_plugin.pluginfile = fname; + if (new_plugin.type == CPlugins::P_TYPE_SCRIPT) + { + new_plugin.pluginfile.append(".sh"); + } else { + new_plugin.pluginfile.append(".so"); + } + // We do not check if new_plugin.pluginfile exists since .cfg in + // PLUGINDIR_VAR can overwrite settings in read only dir + // PLUGINDIR. This needs PLUGINDIR_VAR to be scanned at + // first -> .cfg in PLUGINDIR will be skipped since plugin + // already exists in the list. + // This behavior is used to make sure plugins can be disabled + // by creating a .cfg in PLUGINDIR_VAR (PLUGINDIR often is read only). + + if(!plugin_exists(new_plugin.filename)) + { + plugin_list.push_back(new_plugin); + number_of_plugins++; + } + } + } + } +} + +void CPlugins::loadPlugins() +{ + frameBuffer = CFrameBuffer::getInstance(); + number_of_plugins = 0; + plugin_list.clear(); + + scanDir(PLUGINDIR_HDD); + scanDir(PLUGINDIR_USB); + scanDir(PLUGINDIR_VAR); + scanDir(PLUGINDIR); + sort(plugin_list.begin(), plugin_list.end()); +} + +CPlugins::~CPlugins() +{ + plugin_list.clear(); +} + +bool CPlugins::parseCfg(plugin *plugin_data) +{ +// FILE *fd; + + std::ifstream inFile; + std::string line[20]; + int linecount = 0; + bool reject = false; + + inFile.open(plugin_data->cfgfile.c_str()); + + while(linecount < 20 && getline(inFile, line[linecount++])); + + plugin_data->fb = false; + plugin_data->rc = false; + plugin_data->lcd = false; + plugin_data->vtxtpid = false; + plugin_data->showpig = false; + plugin_data->needoffset = false; + plugin_data->hide = false; + plugin_data->type = CPlugins::P_TYPE_DISABLED; + + for (int i = 0; i < linecount; i++) + { + std::istringstream iss(line[i]); + std::string cmd; + std::string parm; + + getline(iss, cmd, '='); + getline(iss, parm, '='); + + if (cmd == "pluginversion") + { + plugin_data->version = atoi(parm.c_str()); + } + else if (cmd == "name") + { + plugin_data->name = parm; + } + else if (cmd == "desc") + { + plugin_data->description = parm; + } + else if (cmd == "depend") + { + plugin_data->depend = parm; + } + else if (cmd == "type") + { + plugin_data->type = getPluginType(atoi(parm.c_str())); + } + else if (cmd == "needfb") + { + plugin_data->fb = ((parm == "1")?true:false); + } + else if (cmd == "needrc") + { + plugin_data->rc = ((parm == "1")?true:false); + } + else if (cmd == "needlcd") + { + plugin_data->lcd = ((parm == "1")?true:false); + } + else if (cmd == "needvtxtpid") + { + plugin_data->vtxtpid = ((parm == "1")?true:false); + } + else if (cmd == "pigon") + { + plugin_data->showpig = ((parm == "1")?true:false); + } + else if (cmd == "needoffsets") + { + plugin_data->needoffset = ((parm == "1")?true:false); + } + else if (cmd == "hide") + { + plugin_data->hide = ((parm == "1")?true:false); + } + else if (cmd == "needenigma") + { + reject = ((parm == "1")?true:false); + } + + } + + inFile.close(); + return !reject; +} + +PluginParam * CPlugins::makeParam(const char * const id, const char * const value, PluginParam * const next) +{ + PluginParam * startparam = new PluginParam; + + startparam->next = next; + startparam->id = id; + startparam->val = strdup(value); + + return startparam; +} + +PluginParam * CPlugins::makeParam(const char * const id, const int value, PluginParam * const next) +{ + char aval[10]; + + sprintf(aval, "%d", value); + + return makeParam(id, aval, next); +} + +void CPlugins::start_plugin_by_name(const std::string & filename,int param) +{ + for(int i = 0; i < (int) plugin_list.size();i++) + { + if(filename.compare(g_PluginList->getName(i))==0) + { + startPlugin(i,param); + return; + } + } +} + +void CPlugins::startPlugin(const char * const name) +{ + int pluginnr = find_plugin(name); + if (pluginnr > -1) + startPlugin(pluginnr,0); + else + printf("[CPlugins] could not find %s\n", name); + +} + +void CPlugins::startScriptPlugin(int number) +{ + const char *script = plugin_list[number].pluginfile.c_str(); + printf("[CPlugins] executing script %s\n",script); + if (!pluginfile_exists(plugin_list[number].pluginfile)) + { + printf("[CPlugins] could not find %s,\nperhaps wrong plugin type in %s\n", + script, plugin_list[number].cfgfile.c_str()); + return; + } + + FILE *f = popen(script,"r"); + if (f != NULL) + { + char output[1024]; + while (fgets(output,1024,f)) + { + scriptOutput += output; + } + pclose(f); + } + else + { + printf("[CPlugins] can't execute %s\n",script); + } +} + +int mysystem(char * cmd, char * arg1, char * arg2); +void CPlugins::startPlugin(int number,int param) +{ + // always delete old output + delScriptOutput(); + + //bool ispip = strncmp(plugin_list[number].pluginfile.c_str(), "pip", 3) ? false : true; + bool ispip = strstr(plugin_list[number].pluginfile.c_str(), "pip") != 0; +//printf("exec: %s pip: %d\n", plugin_list[number].pluginfile.c_str(), ispip); + if(ispip && !g_RemoteControl->is_video_started) + return; + if (plugin_list[number].type == CPlugins::P_TYPE_SCRIPT) + { + startScriptPlugin(number); + return; + } + if (!pluginfile_exists(plugin_list[number].pluginfile)) + { + printf("[CPlugins] could not find %s,\nperhaps wrong plugin type in %s\n", + plugin_list[number].pluginfile.c_str(), plugin_list[number].cfgfile.c_str()); + return; + } + + PluginExec execPlugin; + char depstring[129]; + char *argv[20]; + void *libhandle[20]; + int argc = 0, i = 0, lcd_fd=-1; + char *p; + char *np; + void *handle; + char * error; + int vtpid = 0; + PluginParam * startparam = 0; + + g_RCInput->clearRCMsg(); +#if 0 + if (plugin_list[number].fb) + { + startparam = makeParam(P_ID_FBUFFER , frameBuffer->getFileHandle() , startparam); + } + if (plugin_list[number].rc) + { + startparam = makeParam(P_ID_RCINPUT , g_RCInput->getFileHandle() , startparam); + startparam = makeParam(P_ID_RCBLK_ANF, g_settings.repeat_genericblocker, startparam); + startparam = makeParam(P_ID_RCBLK_REP, g_settings.repeat_blocker , startparam); + } + else + { + g_RCInput->stopInput(); + } + if (plugin_list[number].lcd) + { + CLCD::getInstance()->pause(); + + lcd_fd = open("/dev/dbox/lcd0", O_RDWR); + + startparam = makeParam(P_ID_LCD , lcd_fd , startparam); + } + if (plugin_list[number].vtxtpid) + { + vtpid = g_RemoteControl->current_PIDs.PIDs.vtxtpid; +#ifdef USE_VBI_INTERFACE + int fd = open("/dev/dbox/vbi0", O_RDWR); + if (fd > 0) + { + ioctl(fd, AVIA_VBI_STOP_VTXT, 0); + close(fd); + } +#endif + if(param>0) + vtpid=param; + startparam = makeParam(P_ID_VTXTPID, vtpid, startparam); + } + if (plugin_list[number].needoffset) + { + startparam = makeParam(P_ID_VFORMAT , g_settings.video_Format , startparam); + startparam = makeParam(P_ID_OFF_X , g_settings.screen_StartX , startparam); + startparam = makeParam(P_ID_OFF_Y , g_settings.screen_StartY , startparam); + startparam = makeParam(P_ID_END_X , g_settings.screen_EndX , startparam); + startparam = makeParam(P_ID_END_Y , g_settings.screen_EndY , startparam); + } + + PluginParam *par = startparam; + for( ; par; par=par->next ) + { + printf("[CPlugins] (id,val):(%s,%s)\n", par->id, par->val); + } + std::string pluginname = plugin_list[number].filename; + + strcpy(depstring, plugin_list[number].depend.c_str()); + + argc=0; + if ( depstring[0] ) + { + p=depstring; + while( 1 ) + { + argv[ argc ] = p; + argc++; + np = strchr(p,','); + if ( !np ) + break; + + *np=0; + p=np+1; + if ( argc == 20 ) // mehr nicht ! + break; + } + } + for( i=0; isetPauseScanning (true); + g_Zapit->setEventMode(false); +#if 0 + //g_Controld->setEventMode(false); +#endif + if(g_Zapit->isPlayBackActive()) { + if(!CNeutrinoApp::getInstance()->recordingstatus) + g_Zapit->setRecordMode(true); + } else { + /* no playback, we playing file ? zap to channel */ + t_channel_id current_channel = g_Zapit->getCurrentServiceID(); + g_Zapit->zapTo_serviceID(current_channel); + } + } + g_RCInput->close_click(); +#ifndef FB_USE_PALETTE + if (plugin_list[number].fb) { + frameBuffer->setMode(720, 576, 8); + frameBuffer->paletteSet(); + } +#endif + execPlugin(startparam); + dlclose(handle); + printf("[CPlugins] exec done...\n"); + g_RCInput->open_click(); + } + } + //restore framebuffer... +//#if 0 +// g_RCInput->open_click(); +//#endif + + //if (!plugin_list[number].rc) + g_RCInput->restartInput(); + g_RCInput->clearRCMsg(); + + if (plugin_list[number].lcd) + { + if(lcd_fd != -1) + close(lcd_fd); + CLCD::getInstance()->resume(); + } + + if (plugin_list[number].fb) + { +#ifdef FB_USE_PALETTE + frameBuffer->paletteSet(); +#else + frameBuffer->setMode(720, 576, 8 * sizeof(fb_pixel_t)); +#endif + } + frameBuffer->paintBackgroundBox(0,0,720,576); + if(ispip) { + if(!CNeutrinoApp::getInstance()->recordingstatus) { + g_Zapit->setRecordMode(false); + } +#if 0 + //g_Controld->setEventMode(true); +#endif + g_Zapit->setEventMode(true); + g_Sectionsd->setPauseScanning (false); + } + +#ifdef USE_VBI_INTERFACE + if (plugin_list[number].vtxtpid) + { + if (vtpid != 0) + { + // versuche, den gtx/enx_vbi wieder zu starten + int fd = open("/dev/dbox/vbi0", O_RDWR); + if (fd > 0) + { + ioctl(fd, AVIA_VBI_START_VTXT, vtpid); + close(fd); + } + } + } +#endif + } + + /* unload shared libs */ + for( i=0; iid, since it is the original */ + free(par->val); + PluginParam * tmp = par; + par = par->next; + delete tmp; + } + g_RCInput->clearRCMsg(); +#else + g_RCInput->clearRCMsg(); + g_RCInput->stopInput(); + //frameBuffer->setMode(720, 576, 8 * sizeof(fb_pixel_t)); +printf("Starting %s\n", plugin_list[number].pluginfile.c_str()); + mysystem((char *) plugin_list[number].pluginfile.c_str(), NULL, NULL); + //frameBuffer->setMode(720, 576, 8 * sizeof(fb_pixel_t)); + frameBuffer->paintBackground(); + g_RCInput->restartInput(); + g_RCInput->clearRCMsg(); +#endif +} + +bool CPlugins::hasPlugin(CPlugins::p_type_t type) +{ + for (std::vector::iterator it=plugin_list.begin(); + it!=plugin_list.end();it++) + { + if (it->type == type && !it->hide) + return true; + } + return false; +} + +const std::string& CPlugins::getScriptOutput() const +{ + return scriptOutput; +} + +void CPlugins::delScriptOutput() +{ + scriptOutput.clear(); +} + +CPlugins::p_type_t CPlugins::getPluginType(int type) +{ + switch (type) + { + case PLUGIN_TYPE_DISABLED: + return P_TYPE_DISABLED; + break; + case PLUGIN_TYPE_GAME: + return P_TYPE_GAME; + break; + case PLUGIN_TYPE_TOOL: + return P_TYPE_TOOL; + break; + case PLUGIN_TYPE_SCRIPT: + return P_TYPE_SCRIPT; + break; + default: + return P_TYPE_DISABLED; + } +} + + diff --git a/src/gui/plugins.h b/src/gui/plugins.h new file mode 100644 index 000000000..532857736 --- /dev/null +++ b/src/gui/plugins.h @@ -0,0 +1,131 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __plugins__ +#define __plugins__ + +#include + +#include +#include + +#include + +#include +#include + +class CPlugins +{ + + public: + typedef enum p_type + { + P_TYPE_DISABLED = 0x1, + P_TYPE_GAME = 0x2, + P_TYPE_TOOL = 0x4, + P_TYPE_SCRIPT = 0x8, + } + p_type_t; + + + private: + + CFrameBuffer *frameBuffer; + + struct plugin + { + std::string filename; + std::string cfgfile; + std::string pluginfile; + int version; + std::string name; // UTF-8 encoded + std::string description; // UTF-8 encoded + std::string depend; + CPlugins::p_type_t type; + + bool fb; + bool rc; + bool lcd; + bool vtxtpid; + int posx, posy, sizex, sizey; + bool showpig; + bool needoffset; + bool hide; + bool operator< (const plugin& a) const + { + return this->filename < a.filename ; + } + }; + + int fb, rc, lcd, pid; + int number_of_plugins; + + std::vector plugin_list; + std::string plugin_dir; + std::string scriptOutput; + + bool parseCfg(plugin *plugin_data); + void scanDir(const char *dir); + bool plugin_exists(const std::string & filename); + int find_plugin(const std::string & filename); + bool pluginfile_exists(const std::string & filename); + CPlugins::p_type_t getPluginType(int type); + public: + + ~CPlugins(); + + void loadPlugins(); + + void setPluginDir(const std::string & dir) { plugin_dir = dir; } + + PluginParam * makeParam(const char * const id, const char * const value, PluginParam * const next); + PluginParam * makeParam(const char * const id, const int value, PluginParam * const next); + + inline int getNumberOfPlugins (void ) const { return plugin_list.size() ; } + inline const char * getName (const int number) const { return plugin_list[number].name.c_str() ; } + inline const char * getPluginFile (const int number) const { return plugin_list[number].pluginfile.c_str(); } + inline const char * getFileName (const int number) const { return plugin_list[number].filename.c_str() ; } + inline const std::string & getDescription (const int number) const { return plugin_list[number].description ; } + inline int getType (const int number) const { return plugin_list[number].type ; } + inline bool isHidden (const int number) const { return plugin_list[number].hide ; } + + void startPlugin(int number,int param); + void start_plugin_by_name(const std::string & filename,int param);// start plugins by "name=" in .cfg + void startScriptPlugin(int number); + + void startPlugin(const char * const filename); // start plugins also by name + bool hasPlugin(CPlugins::p_type_t type); + + const std::string& getScriptOutput() const; + void delScriptOutput(); +}; + +#endif diff --git a/src/gui/rc_lock.cpp b/src/gui/rc_lock.cpp new file mode 100644 index 000000000..901de331f --- /dev/null +++ b/src/gui/rc_lock.cpp @@ -0,0 +1,104 @@ +/* + Neutrino-GUI - DBoxII-Project + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include +#include +#include + +const std::string CRCLock::NO_USER_INPUT = "noUserInput"; + +// -- Menue Handler Interface +// -- Infinite Loop to lock remote control (until release lock key pressed) +// -- 2003-12-01 rasc + +int CRCLock::exec(CMenuTarget* parent, const std::string &actionKey) +{ + if (parent) + parent->hide(); + + bool no_input = (actionKey == NO_USER_INPUT); + if (ShowLocalizedMessage(LOCALE_RCLOCK_TITLE, LOCALE_RCLOCK_LOCKMSG, + CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbCancel, + NEUTRINO_ICON_INFO,450,no_input ? 5 : -1,no_input) == CMessageBox::mbrCancel) + return menu_return::RETURN_EXIT_ALL; + + // -- Lockup Box + lockBox(); + + ShowLocalizedMessage(LOCALE_RCLOCK_TITLE, LOCALE_RCLOCK_UNLOCKMSG, CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO,450, no_input ? 5 : -1); + return menu_return::RETURN_EXIT_ALL; +} + +void CRCLock::lockBox() +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + unsigned long long timeoutEnd; + + // -- Loop until release key pressed + // -- Key sequence: within 5 secs + while (1) { + + timeoutEnd = CRCInput::calcTimeoutEnd(9999999); + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd); + + if (msg == NeutrinoMessages::UNLOCK_RC) + break; + + if (msg == CRCInput::RC_red) { + timeoutEnd = CRCInput::calcTimeoutEnd(5); + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd); + + //if (msg == CRCInput::RC_setup) break; + if (msg == (neutrino_msg_t) g_settings.key_unlock) break; + } + + if (msg == CRCInput::RC_timeout) continue; + + // -- Zwen told me: Eating only RC events would be nice + // -- so be it... + + if (msg > CRCInput::RC_MaxRC) { + CNeutrinoApp::getInstance()->handleMsg(msg, data); + } else { + CVFD::getInstance()->showRCLock(); + // Since showRCLock blocks 2secs for each key we eat all + // messages created during this time. Hopefully this ok... + g_RCInput->clearRCMsg(); + } + } + return; +} diff --git a/src/gui/rc_lock.h b/src/gui/rc_lock.h new file mode 100644 index 000000000..4e6ea758c --- /dev/null +++ b/src/gui/rc_lock.h @@ -0,0 +1,47 @@ +/* + Neutrino-GUI - DBoxII-Project + + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef _remoteLock_ +#define _remoteLock_ + +#include + +#include + + +// +// -- Implements RemoteControl Locking... +// -- ... usefull, if you want to protect your box against unintented zapping +// -- 2003-12-01 rasc +// +class CRCLock: public CMenuTarget +{ + +public: + static const std::string NO_USER_INPUT; + int exec(CMenuTarget* parent, const std::string & actionKey); + void lockBox(); +}; + + +#endif diff --git a/src/gui/ringbuffer.c b/src/gui/ringbuffer.c new file mode 100755 index 000000000..7e12cf76d --- /dev/null +++ b/src/gui/ringbuffer.c @@ -0,0 +1,308 @@ +/* + Copyright (C) 2000 Paul Davis + Copyright (C) 2003 Rohan Drape + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ISO/POSIX C version of Paul Davis's lock free ringbuffer C++ code. + This is safe for the case of one read thread and one write thread. +*/ + +#include +#include +#include +#include "ringbuffer.h" + +/* Create a new ringbuffer to hold at least `sz' bytes of data. The + actual buffer size is rounded up to the next power of two. */ + +ringbuffer_t * +ringbuffer_create (int sz) +{ + int power_of_two; + ringbuffer_t *rb; + + rb = malloc (sizeof (ringbuffer_t)); + + for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++); + + rb->size = 1 << power_of_two; + rb->size_mask = rb->size; + rb->size_mask -= 1; + rb->write_ptr = 0; + rb->read_ptr = 0; + rb->buf = malloc (rb->size); + rb->mlocked = 0; +printf("[ringbuffer] size %d\n", rb->size); + return rb; +} + +/* Free all data associated with the ringbuffer `rb'. */ + +void +ringbuffer_free (ringbuffer_t * rb) +{ + if (rb->mlocked) { + munlock (rb->buf, rb->size); + } + free (rb->buf); + free (rb); +} + +/* Lock the data block of `rb' using the system call 'mlock'. */ + +int +ringbuffer_mlock (ringbuffer_t * rb) +{ + if (mlock (rb->buf, rb->size)) { + return -1; + } + rb->mlocked = 1; + return 0; +} + +/* Reset the read and write pointers to zero. This is not thread + safe. */ + +void +ringbuffer_reset (ringbuffer_t * rb) +{ + rb->read_ptr = 0; + rb->write_ptr = 0; +} + +/* Return the number of bytes available for reading. This is the + number of bytes in front of the read pointer and behind the write + pointer. */ + +size_t +ringbuffer_read_space (ringbuffer_t * rb) +{ + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + return w - r; + } else { + return (w - r + rb->size) & rb->size_mask; + } +} + +/* Return the number of bytes available for writing. This is the + number of bytes in front of the write pointer and behind the read + pointer. */ + +size_t +ringbuffer_write_space (ringbuffer_t * rb) +{ + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + return ((r - w + rb->size) & rb->size_mask) - 1; + } else if (w < r) { + return (r - w) - 1; + } else { + return rb->size - 1; + } +} + +/* The copying data reader. Copy at most `cnt' bytes from `rb' to + `dest'. Returns the actual number of bytes copied. */ + +size_t +ringbuffer_read (ringbuffer_t * rb, char *dest, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + + if ((free_cnt = ringbuffer_read_space (rb)) == 0) { + return 0; + } + + to_read = cnt > free_cnt ? free_cnt : cnt; + + cnt2 = rb->read_ptr + to_read; + + if (cnt2 > rb->size) { + n1 = rb->size - rb->read_ptr; + n2 = cnt2 & rb->size_mask; + } else { + n1 = to_read; + n2 = 0; + } + + memcpy (dest, &(rb->buf[rb->read_ptr]), n1); + rb->read_ptr += n1; + rb->read_ptr &= rb->size_mask; + + if (n2) { + memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2); + rb->read_ptr += n2; + rb->read_ptr &= rb->size_mask; + } + + return to_read; +} + +/* The copying data writer. Copy at most `cnt' bytes to `rb' from + `src'. Returns the actual number of bytes copied. */ + +size_t +ringbuffer_write (ringbuffer_t * rb, char *src, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_write; + size_t n1, n2; + + if ((free_cnt = ringbuffer_write_space (rb)) == 0) { + return 0; + } + + to_write = cnt > free_cnt ? free_cnt : cnt; + + cnt2 = rb->write_ptr + to_write; + + if (cnt2 > rb->size) { + n1 = rb->size - rb->write_ptr; + n2 = cnt2 & rb->size_mask; + } else { + n1 = to_write; + n2 = 0; + } + + memcpy (&(rb->buf[rb->write_ptr]), src, n1); + rb->write_ptr += n1; + rb->write_ptr &= rb->size_mask; + + if (n2) { + memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2); + rb->write_ptr += n2; + rb->write_ptr &= rb->size_mask; + } + + return to_write; +} + +/* Advance the read pointer `cnt' places. */ + +void +ringbuffer_read_advance (ringbuffer_t * rb, size_t cnt) +{ + rb->read_ptr += cnt; + rb->read_ptr &= rb->size_mask; +} + +/* Advance the write pointer `cnt' places. */ + +void +ringbuffer_write_advance (ringbuffer_t * rb, size_t cnt) +{ + rb->write_ptr += cnt; + rb->write_ptr &= rb->size_mask; +} + +/* The non-copying data reader. `vec' is an array of two places. Set + the values at `vec' to hold the current readable data at `rb'. If + the readable data is in one segment the second segment has zero + length. */ + +void +ringbuffer_get_read_vector (ringbuffer_t * rb, + ringbuffer_data_t * vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + free_cnt = w - r; + } else { + free_cnt = (w - r + rb->size) & rb->size_mask; + } + + cnt2 = r + free_cnt; + + if (cnt2 > rb->size) { + + /* Two part vector: the rest of the buffer after the current write + ptr, plus some from the start of the buffer. */ + + vec[0].buf = &(rb->buf[r]); + vec[0].len = rb->size - r; + vec[1].buf = rb->buf; + vec[1].len = cnt2 & rb->size_mask; + + } else { + + /* Single part vector: just the rest of the buffer */ + + vec[0].buf = &(rb->buf[r]); + vec[0].len = free_cnt; + vec[1].len = 0; + } +} + +/* The non-copying data writer. `vec' is an array of two places. Set + the values at `vec' to hold the current writeable data at `rb'. If + the writeable data is in one segment the second segment has zero + length. */ + +void +ringbuffer_get_write_vector (ringbuffer_t * rb, + ringbuffer_data_t * vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + free_cnt = ((r - w + rb->size) & rb->size_mask) - 1; + } else if (w < r) { + free_cnt = (r - w) - 1; + } else { + free_cnt = rb->size - 1; + } + + cnt2 = w + free_cnt; + + if (cnt2 > rb->size) { + + /* Two part vector: the rest of the buffer after the current write + ptr, plus some from the start of the buffer. */ + + vec[0].buf = &(rb->buf[w]); + vec[0].len = rb->size - w; + vec[1].buf = rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } else { + vec[0].buf = &(rb->buf[w]); + vec[0].len = free_cnt; + vec[1].len = 0; + } +} diff --git a/src/gui/scale.cpp b/src/gui/scale.cpp new file mode 100644 index 000000000..432de0310 --- /dev/null +++ b/src/gui/scale.cpp @@ -0,0 +1,129 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define RED_BAR 40 +#define YELLOW_BAR 70 +#define GREEN_BAR 100 + +#define BAR_BORDER 1 +#define BARW 2 +#define BARWW 2 + +#define ITEMW 4 +#define POINT 2 + +#define RED 0xFF0000 +#define GREEN 0x00FF00 +#define YELLOW 0xFFFF00 + +inline unsigned int make16color(__u32 rgb) +{ + return 0xFF000000 | rgb; +} + +CScale::CScale (int w, int h, int r, int g, int b, bool inv) +{ + double div; +//printf("new SCALE, w %d h %d size %d\n", w, h, sizeof(CScale)); fflush(stdout); + frameBuffer = CFrameBuffer::getInstance (); + width = w; + height = h; + inverse = inv; + + div = (double) 100 / (double) width; + red = (double) r / (double) div / (double) ITEMW; + green = (double) g / (double) div / (double) ITEMW; + yellow = (double) b / (double) div / (double) ITEMW; + percent = 255; +} + +void CScale::paint (int x, int y, int pcr) +{ + int i, j, siglen; + int posx, posy; + int xpos, ypos; + int hcnt = height / ITEMW; + double div; + uint32_t rgb; + + fb_pixel_t color; + int b = 0; + + i = 0; + xpos = x; + ypos = y; +//printf("CScale::paint: old %d new %d x %d y %d\n", percent, pcr, x, y); fflush(stdout); + if (pcr != percent) { + if(percent == 255) percent = 0; + div = (double) 100 / (double) width; + siglen = (double) pcr / (double) div; + posx = xpos; + posy = ypos; + int maxi = siglen / ITEMW; + int total = width / ITEMW; + int step = 255/total; + if (pcr > percent) { + + for (i = 0; (i < red) && (i < maxi); i++) { + step = 255/red; + if(inverse) rgb = GREEN + ((unsigned char)(step*i) << 16); // adding red + else rgb = RED + ((unsigned char)(step*i) << 8); // adding green + color = make16color(rgb); + for(j = 0; j <= hcnt; j++ ) { + frameBuffer->paintBoxRel (posx + i*ITEMW, posy + j*ITEMW, POINT, POINT, color); + } + } +//printf("hcnt %d yellow %d i %d\n", hcnt, yellow, i); fflush(stdout); + for (; (i < yellow) && (i < maxi); i++) { + step = 255/yellow/2; + if(inverse) rgb = YELLOW - (((unsigned char)step*(b++)) << 8); // removing green + else rgb = YELLOW - ((unsigned char)(step*(b++)) << 16); // removing red + color = make16color(rgb); +//printf("YELLOW: or %08X diff %08X result %08X\n", YELLOW, ((unsigned char)(step*(b-1)) << 16), color); + for(j = 0; j <= hcnt; j++ ) { + frameBuffer->paintBoxRel (posx + i*ITEMW, posy + j*ITEMW, POINT, POINT, color); + } + } + for (; (i < green) && (i < maxi); i++) { + step = 255/green; + if(inverse) rgb = YELLOW - ((unsigned char) (step*(b++)) << 8); // removing green + else rgb = YELLOW - ((unsigned char) (step*(b++)) << 16); // removing red + color = make16color(rgb); + for(j = 0; j <= hcnt; j++ ) { + frameBuffer->paintBoxRel (posx + i*ITEMW, posy + j*ITEMW, POINT, POINT, color); + } + } + } + for(i = maxi; i < total; i++) { + for(j = 0; j <= hcnt; j++ ) { + frameBuffer->paintBoxRel (posx + i*ITEMW, posy + j*ITEMW, POINT, POINT, COL_INFOBAR_PLUS_3);//fill passive + } + } + percent = pcr; + } +} + +void CScale::reset () +{ + percent = 255; +} + +void CScale::hide () +{ +} diff --git a/src/gui/scale.h b/src/gui/scale.h new file mode 100644 index 000000000..97b4f5dd4 --- /dev/null +++ b/src/gui/scale.h @@ -0,0 +1,22 @@ +#ifndef __scale_ +#define __scale_ + +#include + +class CScale +{ + private: + CFrameBuffer * frameBuffer; + short width; + short height; + char percent; + short red, green, yellow; + bool inverse; + public: + CScale(int w, int h, int r, int g, int b, bool inv = false); + void paint(int x, int y, int pcr); + void hide(); + void reset(); + int getPercent() { return percent; }; +}; +#endif diff --git a/src/gui/scan.cpp b/src/gui/scan.cpp new file mode 100644 index 000000000..93cb3218c --- /dev/null +++ b/src/gui/scan.cpp @@ -0,0 +1,505 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +extern cVideo * videoDecoder; +extern CFrontend * frontend; + +#define NEUTRINO_SCAN_START_SCRIPT CONFIGDIR "/scan.start" +#define NEUTRINO_SCAN_STOP_SCRIPT CONFIGDIR "/scan.stop" +#define NEUTRINO_SCAN_SETTINGS_FILE CONFIGDIR "/scan.conf" +TP_params TP; + +#define RED_BAR 40 +#define YELLOW_BAR 70 +#define GREEN_BAR 100 +#define BAR_BORDER 2 +#define BAR_WIDTH 150 +#define BAR_HEIGHT 16//(13 + BAR_BORDER*2) + +#define ROUND_RADIUS 9 + +CScanTs::CScanTs() +{ + frameBuffer = CFrameBuffer::getInstance(); + radar = 0; + total = done = 0; + freqready = 0; + + sigscale = new CScale(BAR_WIDTH, BAR_HEIGHT, RED_BAR, GREEN_BAR, YELLOW_BAR); + snrscale = new CScale(BAR_WIDTH, BAR_HEIGHT, RED_BAR, GREEN_BAR, YELLOW_BAR); + +} + +extern int scan_pids; +#define get_set CNeutrinoApp::getInstance()->getScanSettings() +int CScanTs::exec(CMenuTarget* parent, const std::string & actionKey) +{ + diseqc_t diseqcType = NO_DISEQC; + neutrino_msg_t msg; + neutrino_msg_data_t data; + //bool manual = (get_set.scan_mode == 2); + int scan_mode = get_set.scan_mode; + sat_iterator_t sit; + bool scan_all = actionKey == "all"; + bool test = actionKey == "test"; + bool manual = (actionKey == "manual") || test; + CZapitClient::ScanSatelliteList satList; + CZapitClient::commandSetScanSatelliteList sat; + int _scan_pids = scan_pids; + + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + width = w_max(550, 0); + height = h_max(hheight + (10 * mheight), 0); //9 lines + x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - height) / 2; + xpos_radar = x + 470; + ypos_radar = y + hheight + (mheight >> 1); + xpos1 = x + 10; + + if(scan_all) + scan_mode |= 0xFF00; + + sigscale->reset(); + snrscale->reset(); + + if (!frameBuffer->getActive()) + return menu_return::RETURN_EXIT_ALL; + + g_Zapit->stopPlayBack(); + frameBuffer->paintBackground(); + videoDecoder->ShowPicture(DATADIR "/neutrino/icons/scan.jpg"); + g_Sectionsd->setPauseScanning(true); + + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8); + +//printf("[neutrino] scan_mode %d TP_freq %s TP_rate %s TP_fec %d TP_pol %d\n", get_set.scan_mode, get_set.TP_freq, get_set.TP_rate, get_set.TP_fec, get_set.TP_pol); + + if(manual) { + scan_pids = true; + TP.scan_mode = get_set.scan_mode; + TP.feparams.frequency = atoi(get_set.TP_freq); + if(g_info.delivery_system == DVB_S) { + TP.feparams.u.qpsk.symbol_rate = atoi(get_set.TP_rate); + TP.feparams.u.qpsk.fec_inner = (fe_code_rate_t) get_set.TP_fec; + TP.polarization = get_set.TP_pol; + } else { + TP.feparams.u.qam.symbol_rate = atoi(get_set.TP_rate); + TP.feparams.u.qam.fec_inner = (fe_code_rate_t)get_set.TP_fec; + TP.feparams.u.qam.modulation = (fe_modulation_t) get_set.TP_mod; + } + //printf("[neutrino] freq %d rate %d fec %d pol %d\n", TP.feparams.frequency, TP.feparams.u.qpsk.symbol_rate, TP.feparams.u.qpsk.fec_inner, TP.polarization); + } + satList.clear(); + if(manual || !scan_all) { + for(sit = satellitePositions.begin(); sit != satellitePositions.end(); sit++) { + if(!strcmp(sit->second.name.c_str(),get_set.satNameNoDiseqc)) { + sat.position = sit->first; + strncpy(sat.satName, get_set.satNameNoDiseqc, 50); + satList.push_back(sat); + break; + } + } + } else { + for(sit = satellitePositions.begin(); sit != satellitePositions.end(); sit++) { + if(sit->second.use_in_scan) { + sat.position = sit->first; + strncpy(sat.satName, sit->second.name.c_str(), 50); + satList.push_back(sat); + } + } + } + success = false; + + if(!manual) { + g_RCInput->close_click(); + if (system(NEUTRINO_SCAN_START_SCRIPT) != 0) + perror(NEUTRINO_SCAN_START_SCRIPT " failed"); + } + + /* send diseqc type to zapit */ + diseqcType = (diseqc_t) CNeutrinoApp::getInstance()->getScanSettings().diseqcMode; + g_Zapit->setDiseqcType(diseqcType); + + /* send diseqc repeat to zapit */ + g_Zapit->setDiseqcRepeat( CNeutrinoApp::getInstance()->getScanSettings().diseqcRepeat); + g_Zapit->setScanBouquetMode( (CZapitClient::bouquetMode)CNeutrinoApp::getInstance()->getScanSettings().bouquetMode); + + /* send satellite list to zapit */ + g_Zapit->setScanSatelliteList( satList); + + /* send scantype to zapit */ + g_Zapit->setScanType((CZapitClient::scanType) CNeutrinoApp::getInstance()->getScanSettings().scanType ); + + paint(test); + /* go */ + if(test) { + int w = x + width - xpos2; + char buffer[128]; + char * f, *s, *m; + if(frontend->getInfo()->type == FE_QPSK) { + frontend->getDelSys(get_set.TP_fec, dvbs_get_modulation((fe_code_rate_t)get_set.TP_fec), f, s, m); + sprintf(buffer, "%u %c %d %s %s %s", atoi(get_set.TP_freq)/1000, get_set.TP_pol == 0 ? 'H' : 'V', atoi(get_set.TP_rate)/1000, f, s, m); + } else if(frontend->getInfo()->type == FE_QAM) { + frontend->getDelSys(get_set.TP_fec, get_set.TP_mod, f, s, m); + sprintf(buffer, "%u %d %s %s %s", atoi(get_set.TP_freq)/1000, atoi(get_set.TP_rate)/1000, f, s, m); + } + paintLine(xpos2, ypos_cur_satellite, w - 95, get_set.satNameNoDiseqc); + paintLine(xpos2, ypos_frequency, w, buffer); + success = g_Zapit->tune_TP(TP); + } else if(manual) + success = g_Zapit->scan_TP(TP); + else + success = g_Zapit->startScan(scan_mode); + + //paint(); + + /* poll for messages */ + istheend = !success; + while (!istheend) { + paintRadar(); + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd_MS( 250 ); + + do { + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd); + if (test && (msg <= CRCInput::RC_MaxRC)) { + istheend = true; + msg = CRCInput::RC_timeout; + } + else if(msg == CRCInput::RC_home) { + if(manual && get_set.scan_mode) + continue; + if (ShowLocalizedMessage(LOCALE_SCANTS_ABORT_HEADER, LOCALE_SCANTS_ABORT_BODY, CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo) == CMessageBox::mbrYes) { + g_Zapit->stopScan(); + } + } + else + msg = handleMsg(msg, data); + } + while (!(msg == CRCInput::RC_timeout)); + showSNR(); // FIXME commented until scan slowdown will be solved + } + + if(!manual) { + if (system(NEUTRINO_SCAN_STOP_SCRIPT) != 0) + perror(NEUTRINO_SCAN_STOP_SCRIPT " failed"); + g_RCInput->open_click(); + } + if(!test) { + //ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, success ? LOCALE_SCANTS_FINISHED : LOCALE_SCANTS_FAILED, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + + const char * text = g_Locale->getText(success ? LOCALE_SCANTS_FINISHED : LOCALE_SCANTS_FAILED); + //paintLine(xpos2, ypos_frequency, xpos_frequency, text); + frameBuffer->paintBoxRel(x, y, width, hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(xpos1, y + hheight, width, text, COL_MENUHEAD, 0, true); // UTF-8 + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(0xFFFF); + do { + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd); + if ( msg <= CRCInput::RC_MaxRC ) + msg = CRCInput::RC_timeout; + else + CNeutrinoApp::getInstance()->handleMsg( msg, data ); + } while (!(msg == CRCInput::RC_timeout)); + } + + hide(); + + scan_pids = _scan_pids; + videoDecoder->StopPicture(); + frameBuffer->ClearFrameBuffer(); + g_Sectionsd->setPauseScanning(false); + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + + return menu_return::RETURN_REPAINT; +} + +int CScanTs::handleMsg(neutrino_msg_t msg, neutrino_msg_data_t data) +{ + int w = x + width - xpos2; +//printf("CScanTs::handleMsg: x %d xpos2 %d width %d w %d\n", x, xpos2, width, w); + char buffer[128]; + char str[256]; + switch (msg) { + case NeutrinoMessages::EVT_SCAN_SATELLITE: + paintLine(xpos2, ypos_cur_satellite, w - 95, (char *)data); + break; + + case NeutrinoMessages::EVT_SCAN_NUM_TRANSPONDERS: + sprintf(buffer, "%d", data); + paintLine(xpos2, ypos_transponder, w - 95, buffer); + total = data; + snprintf(str, 255, "scan: %d/%d", done, total); + CVFD::getInstance()->showMenuText(0, str, -1, true); + break; + + case NeutrinoMessages::EVT_SCAN_REPORT_NUM_SCANNED_TRANSPONDERS: + if (total == 0) data = 0; + done = data; + sprintf(buffer, "%d/%d", done, total); + paintLine(xpos2, ypos_transponder, w - 95, buffer); + snprintf(str, 255, "scan %d/%d", done, total); + CVFD::getInstance()->showMenuText(0, str, -1, true); + break; + + case NeutrinoMessages::EVT_SCAN_REPORT_FREQUENCY: + freqready = 1; + sprintf(buffer, "%u", data); + xpos_frequency = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(buffer, true); + paintLine(xpos2, ypos_frequency, xpos_frequency, buffer); + break; + + case NeutrinoMessages::EVT_SCAN_REPORT_FREQUENCYP: + { + int pol = data & 0xFF; + int fec = (data >> 8) & 0xFF; + int rate = data >> 16; + char * f, *s, *m; + frontend->getDelSys(fec, (fe_modulation_t)0, f, s, m); // FIXME + sprintf(buffer, " %c %d %s %s %s", pol == 0 ? 'H' : 'V', rate, f, s, m); + //(pol == 0) ? sprintf(buffer, "-H") : sprintf(buffer, "-V"); + paintLine(xpos2 + xpos_frequency, ypos_frequency, w - xpos_frequency - 80, buffer); + } + break; + + case NeutrinoMessages::EVT_SCAN_PROVIDER: + paintLine(xpos2, ypos_provider, w, (char*)data); // UTF-8 + break; + + case NeutrinoMessages::EVT_SCAN_SERVICENAME: + paintLine(xpos2, ypos_channel, w, (char *)data); // UTF-8 + break; + + case NeutrinoMessages::EVT_SCAN_NUM_CHANNELS: + sprintf(buffer, " = %d", data); + paintLine(xpos1 + 3 * 72, ypos_service_numbers + mheight, width - 3 * 72 - 10, buffer); + break; + + case NeutrinoMessages::EVT_SCAN_FOUND_TV_CHAN: + sprintf(buffer, "%d", data); + paintLine(xpos1, ypos_service_numbers + mheight, 72, buffer); + break; + + case NeutrinoMessages::EVT_SCAN_FOUND_RADIO_CHAN: + sprintf(buffer, "%d", data); + paintLine(xpos1 + 72, ypos_service_numbers + mheight, 72, buffer); + break; + + case NeutrinoMessages::EVT_SCAN_FOUND_DATA_CHAN: + sprintf(buffer, "%d", data); + paintLine(xpos1 + 2 * 72, ypos_service_numbers + mheight, 72, buffer); + break; + + case NeutrinoMessages::EVT_SCAN_COMPLETE: + case NeutrinoMessages::EVT_SCAN_FAILED: + success = (msg == NeutrinoMessages::EVT_SCAN_COMPLETE); + istheend = true; + msg = CRCInput::RC_timeout; + break; + case CRCInput::RC_plus: + case CRCInput::RC_minus: + case CRCInput::RC_left: + case CRCInput::RC_right: + CNeutrinoApp::getInstance()->setVolume(msg, true, true); + break; + default: + if ((msg >= CRCInput::RC_WithData) && (msg < CRCInput::RC_WithData + 0x10000000)) + delete (unsigned char*) data; + break; + } + return msg; +} + +void CScanTs::paintRadar(void) +{ + char filename[30]; + + sprintf(filename, "radar%d.raw", radar); + radar = (radar + 1) % 10; + frameBuffer->paintIcon8(filename, xpos_radar, ypos_radar, 17); +} + +void CScanTs::hide() +{ + //frameBuffer->loadPal("radiomode.pal", 18, COL_MAXFREE); + //frameBuffer->paintBackgroundBoxRel(0, 0, 720, 576); + frameBuffer->paintBackground(); + freqready = 0; +} + +void CScanTs::paintLineLocale(int x, int * y, int width, const neutrino_locale_t l) +{ + frameBuffer->paintBoxRel(x, *y, width, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x, *y + mheight, width, g_Locale->getText(l), COL_MENUCONTENTINACTIVE, 0, true); // UTF-8 + *y += mheight; +} + +void CScanTs::paintLine(int x, int y, int w, const char * const txt) +{ +//printf("CScanTs::paintLine x %d y %d w %d width %d xpos2 %d: %s\n", x, y, w, width, xpos2, txt); + frameBuffer->paintBoxRel(x, y, w, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x, y + mheight, w, txt, COL_MENUCONTENT, 0, true); // UTF-8 +} + +void CScanTs::paint(bool fortest) +{ + int ypos; + + ypos = y; + + //frameBuffer->paintBoxRel(x, ypos, width, hheight, COL_MENUHEAD_PLUS_0); + frameBuffer->paintBoxRel(x, ypos, width, hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(xpos1, ypos + hheight, width, fortest ? g_Locale->getText(LOCALE_SCANTS_TEST) : g_Locale->getText(LOCALE_SCANTS_HEAD), COL_MENUHEAD, 0, true); // UTF-8 + //frameBuffer->paintBoxRel(x, ypos + hheight, width, height - hheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintBoxRel(x, ypos + hheight, width, height - hheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2); + + frameBuffer->loadPal("radar.pal", 17, 37); + + ypos = y + hheight + (mheight >> 1); + + ypos_cur_satellite = ypos; + + if (g_info.delivery_system == DVB_S) + { //sat + paintLineLocale(xpos1, &ypos, width - xpos1, LOCALE_SCANTS_ACTSATELLITE); + xpos2 = xpos1 + 10 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(g_Locale->getText(LOCALE_SCANTS_ACTSATELLITE), true); // UTF-8 + } + if (g_info.delivery_system == DVB_C) + { //cable + paintLineLocale(xpos1, &ypos, width - xpos1, LOCALE_SCANTS_ACTCABLE); + xpos2 = xpos1 + 10 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(g_Locale->getText(LOCALE_SCANTS_ACTCABLE), true); // UTF-8 + } + + ypos_transponder = ypos; + paintLineLocale(xpos1, &ypos, width - xpos1, LOCALE_SCANTS_TRANSPONDERS); + xpos2 = greater_xpos(xpos2, LOCALE_SCANTS_TRANSPONDERS); + + ypos_frequency = ypos; + paintLineLocale(xpos1, &ypos, width - xpos1, LOCALE_SCANTS_FREQDATA); + xpos2 = greater_xpos(xpos2, LOCALE_SCANTS_FREQDATA); + + ypos += mheight >> 1; // 1/2 blank line + + ypos_provider = ypos; + paintLineLocale(xpos1, &ypos, width - xpos1, LOCALE_SCANTS_PROVIDER); + xpos2 = greater_xpos(xpos2, LOCALE_SCANTS_PROVIDER); + + ypos_channel = ypos; + paintLineLocale(xpos1, &ypos, width - xpos1, LOCALE_SCANTS_CHANNEL); + xpos2 = greater_xpos(xpos2, LOCALE_SCANTS_CHANNEL); + + ypos += mheight >> 1; // 1/2 blank line + + ypos_service_numbers = ypos; paintLineLocale(xpos1 , &ypos, 72 , LOCALE_SCANTS_NUMBEROFTVSERVICES ); + ypos = ypos_service_numbers; paintLineLocale(xpos1 + 72, &ypos, 72 , LOCALE_SCANTS_NUMBEROFRADIOSERVICES); + ypos = ypos_service_numbers; paintLineLocale(xpos1 + 2 * 72, &ypos, 72 , LOCALE_SCANTS_NUMBEROFDATASERVICES ); + ypos = ypos_service_numbers; paintLineLocale(xpos1 + 3 * 72, &ypos, width - 3 * 72 - 10, LOCALE_SCANTS_NUMBEROFTOTALSERVICES); +} + +int CScanTs::greater_xpos(int xpos, const neutrino_locale_t txt) +{ + int txt_xpos = xpos1 + 10 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(g_Locale->getText(txt), true); // UTF-8 + if (txt_xpos > xpos) + return txt_xpos; + else + return xpos; +} + +void CScanTs::showSNR () +{ + char percent[10]; + int barwidth = 150; + uint16_t ssig, ssnr; + int sig, snr; + int posx, posy; + int sw; + + ssig = frontend->getSignalStrength(); + ssnr = frontend->getSignalNoiseRatio(); + + snr = (ssnr & 0xFFFF) * 100 / 65535; + sig = (ssig & 0xFFFF) * 100 / 65535; + + posy = y + height - mheight - 5; + + if(sigscale->getPercent() != sig) { + posx = x + 20; + sprintf(percent, "%d%% SIG", sig); + sw = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth ("100% SIG"); + + sigscale->paint(posx - 1, posy+2, sig); + + posx = posx + barwidth + 3; + sw = x + 247 - posx; + frameBuffer->paintBoxRel(posx, posy - 2, sw, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString (posx+2, posy + mheight, sw, percent, COL_MENUCONTENT); + } + if(snrscale->getPercent() != snr) { + posx = x + 20 + 260; + sprintf(percent, "%d%% SNR", snr); + sw = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth ("100% SNR"); + snrscale->paint(posx - 1, posy+2, snr); + + posx = posx + barwidth + 3; + sw = x + width - posx; + frameBuffer->paintBoxRel(posx, posy - 2, sw, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString (posx+2, posy + mheight, sw, percent, COL_MENUCONTENT); + } +} diff --git a/src/gui/scan.h b/src/gui/scan.h new file mode 100644 index 000000000..05a90d8b7 --- /dev/null +++ b/src/gui/scan.h @@ -0,0 +1,83 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __scants__ +#define __scants__ + +#include +#include +#include +#include +#include + + +class CScanTs : public CMenuTarget +{ + private: + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hheight, mheight; // head/menu font height + int xpos1; //x position for first column + int xpos2; //x position for second column + int radar; + int xpos_radar; + int ypos_radar; + int ypos_cur_satellite; + int ypos_transponder; + int ypos_frequency; + int xpos_frequency; + int ypos_provider; + int ypos_channel; + int ypos_service_numbers; + bool success; + bool istheend; + uint32_t total; + uint32_t done; + CScale * snrscale, * sigscale; + + void paint(bool fortest = false); + void paintLineLocale(int x, int * y, int width, const neutrino_locale_t l); + void paintLine(int x, int y, int width, const char * const txt); + void paintRadar(void); + int handleMsg(neutrino_msg_t msg, neutrino_msg_data_t data); + int greater_xpos(int xpos, const neutrino_locale_t txt); + bool freqready; + void showSNR(); + + public: + CScanTs(); + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); +}; +#endif diff --git a/src/gui/screensetup.cpp b/src/gui/screensetup.cpp new file mode 100644 index 000000000..5c1e7679e --- /dev/null +++ b/src/gui/screensetup.cpp @@ -0,0 +1,305 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +int x=15*5; +int y=15*25; +int BoxHeight=15*4; +int BoxWidth=15*23; + +CScreenSetup::CScreenSetup() +{ + frameBuffer = CFrameBuffer::getInstance(); +} + +int CScreenSetup::exec(CMenuTarget* parent, const std::string &) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = menu_return::RETURN_REPAINT; + + if (parent) + { + parent->hide(); + } + + x_coord[0] = g_settings.screen_StartX; + x_coord[1] = g_settings.screen_EndX; + y_coord[0] = g_settings.screen_StartY; + y_coord[1] = g_settings.screen_EndY; + + paint(); + + selected = 0; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + bool loop=true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd, true ); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + switch ( msg ) + { + case CRCInput::RC_ok: + // abspeichern + g_settings.screen_StartX = x_coord[0]; + g_settings.screen_EndX = x_coord[1]; + g_settings.screen_StartY = y_coord[0]; + g_settings.screen_EndY = y_coord[1]; + loop = false; + break; + + case CRCInput::RC_home: + if ( ( ( g_settings.screen_StartX != x_coord[0] ) || + ( g_settings.screen_EndX != x_coord[1] ) || + ( g_settings.screen_StartY != y_coord[0] ) || + ( g_settings.screen_EndY != y_coord[1] ) ) && + (ShowLocalizedMessage(LOCALE_VIDEOMENU_SCREENSETUP, LOCALE_MESSAGEBOX_DISCARD, CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbCancel) == CMessageBox::mbrCancel)) + break; + + case CRCInput::RC_timeout: + loop = false; + break; + + case CRCInput::RC_red: + case CRCInput::RC_green: + { + selected = ( msg == CRCInput::RC_green ) ? 1 : 0 ; + + frameBuffer->paintBoxRel(x,y, BoxWidth,BoxHeight/2, (selected==0)? COL_MENUCONTENTSELECTED_PLUS_0:COL_MENUCONTENT_PLUS_0); + frameBuffer->paintBoxRel(x,y+BoxHeight/2, BoxWidth,BoxHeight/2, (selected==1)? COL_MENUCONTENTSELECTED_PLUS_0:COL_MENUCONTENT_PLUS_0); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+30,y+BoxHeight/2, BoxWidth, g_Locale->getText(LOCALE_SCREENSETUP_UPPERLEFT ), (selected == 0)?COL_MENUCONTENTSELECTED:COL_MENUCONTENT, 0, true); // UTF-8 + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+30,y+BoxHeight, BoxWidth, g_Locale->getText(LOCALE_SCREENSETUP_LOWERRIGHT), (selected == 1)?COL_MENUCONTENTSELECTED:COL_MENUCONTENT, 0, true); // UTF-8 + + paintIcons(); + break; + } + case CRCInput::RC_up: + { + y_coord[selected]--; + + int min = ( selected == 0 ) ? 0 : 400; + if ( y_coord[selected] < min ) + y_coord[selected] = min ; + else + paintBorder( selected ); + break; + } + case CRCInput::RC_down: + { + y_coord[selected]++; + + //int max = ( selected == 0 ) ? 200 : 575; + int max = ( selected == 0 ) ? 200 : frameBuffer->getScreenHeight(true)-1; +printf("selected %d y %d max %d\n", selected, y_coord[selected], max); + if ( y_coord[selected] > max ) + y_coord[selected] = max ; + else + paintBorder( selected ); + break; + } + case CRCInput::RC_left: + { + x_coord[selected]--; + + int min = ( selected == 0 ) ? 0 : 400; + if ( x_coord[selected] < min ) + x_coord[selected] = min ; + else + paintBorder( selected ); + break; + } + case CRCInput::RC_right: + { + x_coord[selected]++; + + //int max = ( selected == 0 ) ? 200 : 719; + int max = ( selected == 0 ) ? 200 : frameBuffer->getScreenWidth(true)-1; + if ( y_coord[selected] > max ) + y_coord[selected] = max ; + else + paintBorder( selected ); + break; + } + case CRCInput::RC_favorites: + case CRCInput::RC_sat: + break; + + default: + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + + } + + hide(); + return res; +} + +void CScreenSetup::hide() +{ + int w = (int) frameBuffer->getScreenWidth(true); + int h = (int) frameBuffer->getScreenHeight(true); + frameBuffer->paintBackgroundBox(0, 0, w, h); +} + +void CScreenSetup::paintBorder( int selected ) +{ + if ( selected == 0 ) + paintBorderUL(); + else + paintBorderLR(); + + paintCoords(); +} + +void CScreenSetup::paintIcons() +{ + frameBuffer->paintIcon("rot.raw", x+6, y+8); + frameBuffer->paintIcon("gruen.raw", x+6, y+36 ); +} + +void CScreenSetup::paintBorderUL() +{ + frameBuffer->paintIcon( "border_ul.raw", x_coord[0], y_coord[0] ); +} + +void CScreenSetup::paintBorderLR() +{ + frameBuffer->paintIcon("border_lr.raw", x_coord[1]- 96, y_coord[1]- 96 ); +} + +void CScreenSetup::paintCoords() +{ + int w = 15*9; + int h = 15*6; + + //int x=15*19; + //int y=15*16; + int x = (frameBuffer->getScreenWidth(true) - w) / 2; + int y = (frameBuffer->getScreenHeight(true) - h) / 2; + + frameBuffer->paintBoxRel(x,y, 15*9,15*6, COL_MENUCONTENT_PLUS_0); + + char xpos[30]; + char ypos[30]; + char xepos[30]; + char yepos[30]; + + sprintf((char*) &xpos, "SX: %d",x_coord[0] ); + sprintf((char*) &ypos, "SY: %d", y_coord[0] ); + sprintf((char*) &xepos, "EX: %d", x_coord[1] ); + sprintf((char*) &yepos, "EY: %d", y_coord[1] ); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10,y+30, 200, xpos, COL_MENUCONTENT); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10,y+50, 200, ypos, COL_MENUCONTENT); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10,y+70, 200, xepos, COL_MENUCONTENT); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10,y+90, 200, yepos, COL_MENUCONTENT); +} + +inline unsigned int make16color(__u32 rgb) +{ + return 0xFF000000 | rgb; +} + +void CScreenSetup::paint() +{ + if (!frameBuffer->getActive()) + return; + + int w = (int) frameBuffer->getScreenWidth(true); + int h = (int) frameBuffer->getScreenHeight(true); + + frameBuffer->paintBox(0,0, w, h, make16color(0xA0A0A0)); + + for(int count = 0; count < h; count += 15) + frameBuffer->paintHLine(0, w-1, count, make16color(0x505050) ); + + for(int count = 0; count < w; count += 15) + frameBuffer->paintVLine(count, 0, h-1, make16color(0x505050) ); + + //frameBuffer->paintBox(0,0, 15*15,15*15, make16color(0xA0A0A0)); + //frameBuffer->paintBox(32*15+1, 23*15+1, 719,575, make16color(0xA0A0A0)); + frameBuffer->paintBox(0, 0, w/3, h/3, make16color(0xA0A0A0)); + frameBuffer->paintBox(w-w/3, h-h/3, w-1, h-1, make16color(0xA0A0A0)); +//new + //frameBuffer->paintBoxRel(225, 89, 496, 3, COL_MENUCONTENT_PLUS_0); //upper letterbox marker + //frameBuffer->paintBoxRel(0, 495, 481, 3, COL_MENUCONTENT_PLUS_0); //lower letterbox marker + + frameBuffer->paintBoxRel(x, y, BoxWidth, BoxHeight/2, COL_MENUCONTENTSELECTED_PLUS_0); //upper selected box + frameBuffer->paintBoxRel(x, y+BoxHeight/2, BoxWidth, BoxHeight/2, COL_MENUCONTENT_PLUS_0); //lower selected box + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+30, y+BoxHeight/2, BoxWidth, + g_Locale->getText(LOCALE_SCREENSETUP_UPPERLEFT ), COL_MENUCONTENTSELECTED , 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+30, y+BoxHeight, BoxWidth, + g_Locale->getText(LOCALE_SCREENSETUP_LOWERRIGHT), COL_MENUCONTENT, 0, true); // UTF-8 +//new end +#if 0 // old + int x=15*5; + int y=15*24; + frameBuffer->paintBoxRel(x,y, 15*23,15*4, COL_MENUCONTENT_PLUS_0); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+30,y+29, 15*23, g_Locale->getText(LOCALE_SCREENSETUP_UPPERLEFT ), COL_MENUHEAD , 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+30,y+49, 15*23, g_Locale->getText(LOCALE_SCREENSETUP_LOWERRIGHT), COL_MENUCONTENT, 0, true); // UTF-8 +#endif + + paintIcons(); + paintBorderUL(); + paintBorderLR(); + paintCoords(); +} diff --git a/src/gui/screensetup.h b/src/gui/screensetup.h new file mode 100644 index 000000000..6ab3c90a3 --- /dev/null +++ b/src/gui/screensetup.h @@ -0,0 +1,66 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __screensetup__ +#define __screensetup__ + +#include + +#include + +#include + + +class CScreenSetup : public CMenuTarget +{ + private: + CFrameBuffer * frameBuffer; + int selected; + int x_coord[2]; + int y_coord[2]; + + void paint(); + void paintBorderUL(); + void paintBorderLR(); + void paintCoords(); + void paintBorder(int selected); + void paintIcons(); + + public: + CScreenSetup(); + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); + +}; + + +#endif diff --git a/src/gui/sleeptimer.cpp b/src/gui/sleeptimer.cpp new file mode 100644 index 000000000..749158746 --- /dev/null +++ b/src/gui/sleeptimer.cpp @@ -0,0 +1,94 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include + +#include +#include + +extern CRemoteControl * g_RemoteControl; /* neutrino.cpp */ + +#include + +int CSleepTimerWidget::exec(CMenuTarget* parent, const std::string &) +{ + int res = menu_return::RETURN_EXIT_ALL; + int shutdown_min = 0; + char value[16]; + CStringInput *inbox; + + if (parent) + parent->hide(); + + shutdown_min = g_Timerd->getSleepTimerRemaining(); // remaining shutdown time? + sprintf(value,"%03d", shutdown_min); + CSectionsdClient::CurrentNextInfo info_CurrentNext; + g_InfoViewer->getEPG(g_RemoteControl->current_channel_id, info_CurrentNext); + if ( info_CurrentNext.flags & CSectionsdClient::epgflags::has_current) { + time_t jetzt=time(NULL); + int current_epg_zeit_dauer_rest = (info_CurrentNext.current_zeit.dauer+150 - (jetzt - info_CurrentNext.current_zeit.startzeit ))/60 ; + if(shutdown_min == 0 && current_epg_zeit_dauer_rest > 0 && current_epg_zeit_dauer_rest < 1000) + { + sprintf(value,"%03d",current_epg_zeit_dauer_rest); + } + } + + inbox = new CStringInput(LOCALE_SLEEPTIMERBOX_TITLE, value, 3, LOCALE_SLEEPTIMERBOX_HINT1, LOCALE_SLEEPTIMERBOX_HINT2, "0123456789 "); + inbox->exec (NULL, ""); + inbox->hide (); + + delete inbox; + + int new_val = atoi(value); + if(shutdown_min != new_val) { + shutdown_min = new_val; + printf("sleeptimer min: %d\n",shutdown_min); + if (shutdown_min == 0) // if set to zero remove existing sleeptimer + { + if(g_Timerd->getSleeptimerID() > 0) { + g_Timerd->removeTimerEvent(g_Timerd->getSleeptimerID()); + } + } + else // set the sleeptimer to actual time + shutdown mins and announce 1 min before + g_Timerd->setSleeptimer(time(NULL) + ((shutdown_min -1) * 60),time(NULL) + shutdown_min * 60,0); + } + return res; +} diff --git a/src/gui/sleeptimer.h b/src/gui/sleeptimer.h new file mode 100644 index 000000000..8215c34d2 --- /dev/null +++ b/src/gui/sleeptimer.h @@ -0,0 +1,35 @@ +/* + Neutrino-GUI - DBoxII-Project + + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __sleeptimer__ +#define __sleeptimer__ + +#include + +class CSleepTimerWidget: public CMenuTarget +{ + public: + int exec(CMenuTarget* parent, const std::string & actionKey); +}; + + +#endif diff --git a/src/gui/streaminfo2.cpp b/src/gui/streaminfo2.cpp new file mode 100644 index 000000000..1bde46205 --- /dev/null +++ b/src/gui/streaminfo2.cpp @@ -0,0 +1,807 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define SCREEN_X 720 +#define SCREEN_Y 572 + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern CFrontend * frontend; +extern cVideo * videoDecoder; +extern cAudio * audioDecoder; + +extern CRemoteControl *g_RemoteControl; /* neutrino.cpp */ +extern CZapitClient::SatelliteList satList; + +#if 0 +extern CPipSetup * g_Pip0; +#endif +CStreamInfo2::CStreamInfo2 () +{ + frameBuffer = CFrameBuffer::getInstance (); + + font_head = SNeutrinoSettings::FONT_TYPE_MENU_TITLE; + font_info = SNeutrinoSettings::FONT_TYPE_MENU; + font_small = SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL; + + hheight = g_Font[font_head]->getHeight (); + iheight = g_Font[font_info]->getHeight (); + sheight = g_Font[font_small]->getHeight (); + + //max_height = SCREEN_Y - 1; + //max_width = SCREEN_X - 1; + + max_width = frameBuffer->getScreenWidth(true); + max_height = frameBuffer->getScreenHeight(true); + + width = frameBuffer->getScreenWidth(); + height = frameBuffer->getScreenHeight(); + x = frameBuffer->getScreenX(); + y = frameBuffer->getScreenY(); + + //x = (((g_settings.screen_EndX - g_settings.screen_StartX) - width) / 2) + g_settings.screen_StartX; + //y = (((g_settings.screen_EndY - g_settings.screen_StartY) - height) / 2) + g_settings.screen_StartY; + + sigBox_pos = 0; + paint_mode = 0; + + b_total = 0; + bit_s = 0; + abit_s = 0; + + signal.max_sig = 0; + signal.max_snr = 0; + signal.max_ber = 0; + + signal.min_sig = 0; + signal.min_snr = 0; + signal.min_ber = 0; + + rate.short_average = 0; + rate.max_short_average = 0; + rate.min_short_average = 0; + +} + +CStreamInfo2::~CStreamInfo2 () +{ + videoDecoder->Pig(-1, -1, -1, -1); +} + +int CStreamInfo2::exec() +{ + paint(paint_mode); + doSignalStrengthLoop(); + hide(); + + return menu_return::RETURN_EXIT_ALL; +} + +int CStreamInfo2::exec (CMenuTarget * parent, const std::string &) +{ + + if (parent) + parent->hide (); + + paint (paint_mode); + doSignalStrengthLoop (); + hide (); + return menu_return::RETURN_EXIT_ALL; +} + +int CStreamInfo2::doSignalStrengthLoop () +{ +#define RED_BAR 40 +#define YELLOW_BAR 70 +#define GREEN_BAR 100 +#define BAR_WIDTH 150 +#define BAR_HEIGHT 12 + + sigscale = new CScale(BAR_WIDTH, BAR_HEIGHT, RED_BAR, GREEN_BAR, YELLOW_BAR); + snrscale = new CScale(BAR_WIDTH, BAR_HEIGHT, RED_BAR, GREEN_BAR, YELLOW_BAR); + + neutrino_msg_t msg; + unsigned long long maxb, minb, lastb, tmp_rate; + int cnt = 0,i=0; + uint16_t ssig, ssnr; + uint32_t ber; + char tmp_str[150]; + int offset_tmp = 0; + int offset = g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_BITRATE)); + int sw = g_Font[font_info]->getRenderWidth ("99999.999"); + int mm = g_Font[font_info]->getRenderWidth ("Max");//max min lenght + maxb = minb = lastb = 0; + ts_setup (); + while (1) { + neutrino_msg_data_t data; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd_MS (100); + g_RCInput->getMsgAbsoluteTimeout (&msg, &data, &timeoutEnd); + + ssig = frontend->getSignalStrength(); + ssnr = frontend->getSignalNoiseRatio(); + ber = frontend->getBitErrorRate(); + + signal.sig = ssig & 0xFFFF; + signal.snr = ssnr & 0xFFFF; + signal.ber = ber; + + int ret = update_rate (); + if (paint_mode == 0) { + char currate[150]; + if (cnt < 12) + cnt++; + int dheight = g_Font[font_info]->getHeight (); + int dx1 = x + 10; + int dy = y+ height - dheight - 5; + if (ret && (lastb != bit_s)) { + lastb = bit_s; + + if (maxb < bit_s) + rate.max_short_average = maxb = bit_s; + if ((cnt > 10) && ((minb == 0) || (minb > bit_s))) + rate.min_short_average = minb = bit_s; + + for(i = 0; i < 3; i++){ + switch (i) { + case 0: + tmp_rate = bit_s; + sprintf(tmp_str, "%s", g_Locale->getText(LOCALE_STREAMINFO_BITRATE)); + offset_tmp = 0; + break; + case 1: + tmp_rate = minb; + sprintf(tmp_str, "%s", "Min"); + offset_tmp = offset+5; + break; + case 2: + tmp_rate = maxb; + sprintf(tmp_str, "%s", "Max"); + offset_tmp = offset+5+mm; + break; + } + g_Font[font_info]->RenderString (dx1+offset_tmp+((sw)*i), yypos+(dheight*4), offset, tmp_str, COL_MENUCONTENTDARK, 0, true); + sprintf(currate, "%5llu.%03llu", tmp_rate / 1000ULL, tmp_rate % 1000ULL); + frameBuffer->paintBoxRel (dx1+offset+5+((sw+mm)*i), yypos+(dheight*3), sw, dheight, COL_MENUHEAD_PLUS_0); + g_Font[font_info]->RenderString (dx1+offset+10+((sw+mm)*i), yypos+(dheight*4), sw - 10, currate, COL_MENUCONTENTDARK); + } + } + if(snrscale && sigscale) + showSNR (); + } + rate.short_average = abit_s; + if (signal.max_ber < signal.ber) { + signal.max_ber = signal.ber; + } + if (signal.max_sig < signal.sig) { + signal.max_sig = signal.sig; + } + if (signal.max_snr < signal.snr) { + signal.max_snr = signal.snr; + } + + if ((signal.min_ber == 0) || (signal.min_ber > signal.ber)) { + signal.min_ber = signal.ber; + } + if ((signal.min_sig == 0) || (signal.min_sig > signal.sig)) { + signal.min_sig = signal.sig; + } + if ((signal.min_snr == 0) || (signal.min_snr > signal.snr)) { + signal.min_snr = signal.snr; + } + + paint_signal_fe(rate, signal); + signal.old_sig = signal.sig; + signal.old_snr = signal.snr; + signal.old_ber = signal.ber; + + // switch paint mode + if (msg == CRCInput::RC_red || msg == CRCInput::RC_blue || msg == CRCInput::RC_green || msg == CRCInput::RC_yellow) { + hide (); + if(sigscale) + sigscale->reset(); + if(snrscale) + snrscale->reset(); + paint_mode = ++paint_mode % 2; + paint (paint_mode); + continue; + } + // -- any key --> abort + if (msg <= CRCInput::RC_MaxRC) { + break; + } + // -- push other events + if (msg > CRCInput::RC_MaxRC && msg != CRCInput::RC_timeout) { + CNeutrinoApp::getInstance ()->handleMsg (msg, data); + } + } + if(sigscale){ + delete sigscale; + sigscale = NULL; + } + if(snrscale){ + delete snrscale; + snrscale = NULL; + } + ts_close (); + return msg; +} + +void CStreamInfo2::hide () +{ + videoDecoder->Pig(-1, -1, -1, -1); + frameBuffer->paintBackgroundBoxRel (0, 0, max_width, max_height); +} + +void CStreamInfo2::paint_pig (int x, int y, int w, int h) +{ + frameBuffer->paintBackgroundBoxRel (x, y, w, h); +printf("CStreamInfo2::paint_pig x %d y %d w %d h %d\n", x, y, w, h); + videoDecoder->Pig(x, y, w, h, frameBuffer->getScreenWidth(true), frameBuffer->getScreenHeight(true)); +} + +void CStreamInfo2::paint_signal_fe_box(int _x, int _y, int w, int h) +{ + int y1, y2; + int xd = w/4; + + g_Font[font_small]->RenderString(_x, _y+iheight+15, width-10, g_Locale->getText(LOCALE_STREAMINFO_SIGNAL), COL_MENUCONTENTDARK, 0, true); + + sigBox_x = _x; + sigBox_y = _y+iheight+15; + sigBox_w = w; + sigBox_h = h-iheight*3; + frameBuffer->paintBoxRel(sigBox_x,sigBox_y,sigBox_w+2,sigBox_h, COL_BLACK); + + y1 = _y + h + iheight + iheight+iheight-8; + y2 = _y + h - sheight+8; + + frameBuffer->paintBoxRel(_x+xd*0,y2- 12,16,2, COL_RED); //red + g_Font[font_small]->RenderString(_x+20+xd*0, y2, 50, "BER", COL_MENUCONTENTDARK, 0, true); + + frameBuffer->paintBoxRel(_x+xd*1,y2- 12,16,2,COL_BLUE); //blue + g_Font[font_small]->RenderString(_x+20+xd*1, y2, 50, "SNR", COL_MENUCONTENTDARK, 0, true); + + frameBuffer->paintBoxRel(_x+8+xd*2,y2- 12,16,2, COL_GREEN); //green + g_Font[font_small]->RenderString(_x+28+xd*2, y2, 50, "SIG", COL_MENUCONTENTDARK, 0, true); + + frameBuffer->paintBoxRel(_x+xd*3,y2- 12,16,2,COL_YELLOW); // near yellow + g_Font[font_small]->RenderString(_x+20+xd*3, y2, 50, "Bitrate", COL_MENUCONTENTDARK, 0, true); + + sig_text_y = y1 - iheight; + sig_text_ber_x = _x + xd * 0; + sig_text_snr_x = _x + 5 + xd * 1; + sig_text_sig_x = _x + 5 + xd * 2; + sig_text_rate_x = _x + 10 + xd * 3; + + int maxmin_x; // x-position of min and max + if (paint_mode == 0) { + maxmin_x = sig_text_ber_x-40; + } + else { + maxmin_x = _x + 40 + xd * 3 + 45; + } + g_Font[font_small]->RenderString(maxmin_x, y1 - sheight - sheight - sheight, 50, "max", COL_MENUCONTENTDARK, 0, true); + g_Font[font_small]->RenderString(maxmin_x, y1 - sheight, 50, "min", COL_MENUCONTENTDARK, 0, true); + + + sigBox_pos = 0; + + signal.old_sig = 1; + signal.old_snr = 1; + signal.old_ber = 1; + + feSignal s = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +// paint_signal_fe(rate, signal); +} + +void CStreamInfo2::paint_signal_fe(struct bitrate br, struct feSignal s) +{ + int x_now = sigBox_pos; + int yt = sig_text_y; + int yd; + static int old_x=0,old_y=0; + sigBox_pos = (++sigBox_pos) % sigBox_w; + + frameBuffer->paintVLine(sigBox_x+sigBox_pos, sigBox_y, sigBox_y+sigBox_h, COL_WHITE); + frameBuffer->paintVLine(sigBox_x+x_now, sigBox_y, sigBox_y+sigBox_h+1, COL_BLACK); + + long value = (long) (br.short_average / 1000ULL); + + SignalRenderStr(value, sig_text_rate_x, yt - sheight); + SignalRenderStr(br.max_short_average/ 1000ULL, sig_text_rate_x, yt - sheight - sheight); + SignalRenderStr(br.min_short_average/ 1000ULL, sig_text_rate_x, yt); + if ( g_RemoteControl->current_PIDs.PIDs.vpid > 0 ){ + yd = y_signal_fe (value, 15000, sigBox_h);// Video + Audio + } else { + yd = y_signal_fe (value, 512, sigBox_h); // Audio only + } + if ((old_x == 0 && old_y == 0) || sigBox_pos == 1) { + old_x = sigBox_x+x_now; + old_y = sigBox_y+sigBox_h-yd; + } else { + frameBuffer->paintLine(old_x, old_y, sigBox_x+x_now, sigBox_y+sigBox_h-yd, COL_YELLOW); //yellow + old_x = sigBox_x+x_now; + old_y = sigBox_y+sigBox_h-yd; + } + + if (s.ber != s.old_ber) { + SignalRenderStr(s.ber, sig_text_ber_x, yt - sheight); + SignalRenderStr(s.max_ber, sig_text_ber_x, yt - sheight - sheight); + SignalRenderStr(s.min_ber, sig_text_ber_x, yt); + } + yd = y_signal_fe (s.ber, 4000, sigBox_h); + frameBuffer->paintPixel(sigBox_x+x_now, sigBox_y+sigBox_h-yd, COL_RED); //red + + + if (s.sig != s.old_sig) { + SignalRenderStr(s.sig, sig_text_sig_x, yt - sheight); + SignalRenderStr(s.max_sig, sig_text_sig_x, yt - sheight - sheight); + SignalRenderStr(s.min_sig, sig_text_sig_x, yt); + } + yd = y_signal_fe (s.sig, 65000, sigBox_h); + frameBuffer->paintPixel(sigBox_x+x_now, sigBox_y+sigBox_h-yd, COL_GREEN); //green + + + if (s.snr != s.old_snr) { + SignalRenderStr(s.snr, sig_text_snr_x, yt - sheight); + SignalRenderStr(s.max_snr, sig_text_snr_x, yt - sheight - sheight); + SignalRenderStr(s.min_snr, sig_text_snr_x, yt); + } + yd = y_signal_fe (s.snr, 65000, sigBox_h); + frameBuffer->paintPixel(sigBox_x+x_now, sigBox_y+sigBox_h-yd, COL_BLUE); //blue +} + +// -- calc y from max_range and max_y +int CStreamInfo2::y_signal_fe (unsigned long value, unsigned long max_value, int max_y) +{ + long l; + + if (!max_value) + max_value = 1; + + l = ((long) max_y * (long) value) / (long) max_value; + if (l > max_y) + l = max_y; + + return (int) l; +} + +void CStreamInfo2::SignalRenderStr(unsigned int value, int _x, int _y) +{ + char str[30]; + + frameBuffer->paintBoxRel(_x, _y - sheight + 5, 60, sheight - 1, COL_MENUHEAD_PLUS_0); + sprintf(str,"%6u",value); + g_Font[font_small]->RenderString(_x, _y + 5, 60, str, COL_MENUCONTENTDARK, 0, true); +} + +void CStreamInfo2::paint (int mode) +{ + const char *head_string; + + width = frameBuffer->getScreenWidth(); + height = frameBuffer->getScreenHeight(); + x = frameBuffer->getScreenX(); + y = frameBuffer->getScreenY(); + int ypos = y + 5; + int xpos = x + 10; + + if (paint_mode == 0) { + + // -- tech Infos, PIG, small signal graph + head_string = g_Locale->getText (LOCALE_STREAMINFO_HEAD); + CVFD::getInstance ()->setMode (CVFD::MODE_MENU_UTF8, head_string); + + // paint backround, title pig, etc. + frameBuffer->paintBoxRel (0, 0, max_width, max_height, COL_MENUHEAD_PLUS_0); + g_Font[font_head]->RenderString (xpos, ypos + hheight + 1, width, head_string, COL_MENUHEAD, 0, true); // UTF-8 + ypos += hheight; + + // paint PIG + //paint_pig (width - 240, y + 10, 240, 190); + paint_pig (width - width/3 - 10, y + 10, width/3, height/3); + + // Info Output + //ypos += (iheight >> 1); + //ypos += iheight; + paint_techinfo (xpos, ypos); + + //paint_signal_fe_box (width - 240, (y + 190 + hheight), 240, 190); + paint_signal_fe_box (width - width/3 - 10, (y + 10 + height/3 + hheight), width/3, height/3 + hheight); + } else { + // -- small PIG, small signal graph + // -- paint backround, title pig, etc. + frameBuffer->paintBoxRel (0, 0, max_width, max_height, COL_MENUHEAD_PLUS_0); + + // -- paint large signal graph + paint_signal_fe_box (x, y, width, height-100); + + } + +} + +void CStreamInfo2::paint_techinfo(int xpos, int ypos) +{ + char buf[100], buf2[100]; + int xres, yres, aspectRatio, framerate; + // paint labels + int spaceoffset = 0,i = 0; + int array[4]={g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_RESOLUTION)), + g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_ARATIO)), + g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_FRAMERATE)), + g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_AUDIOTYPE))}; + for(i=0 ; i<4; i++) + { + if(spaceoffset < array[i]) + spaceoffset = array[i]; + } + spaceoffset+=4; + + videoDecoder->getPictureInfo(xres, yres, framerate); + aspectRatio = videoDecoder->getAspectRatio(); + //Video RESOLUTION + ypos += iheight; + sprintf ((char *) buf, "%s:",g_Locale->getText (LOCALE_STREAMINFO_RESOLUTION)); + g_Font[font_info]->RenderString (xpos, ypos, width*2/3 - 10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + sprintf ((char *) buf, "%dx%d", xres, yres); + g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, width*2/3 - 10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + +#if 0 + ypos += iheight; + sprintf ((char *) buf, "%s: %d bits/sec", g_Locale->getText (LOCALE_STREAMINFO_BITRATE), (int) bitInfo[4] * 50); + g_Font[font_info]->RenderString (xpos, ypos, width*2/3 - 10, buf, COL_MENUCONTENT, 0, true); // UTF-8 + +#endif + //audio rate + ypos += iheight; + sprintf ((char *) buf, "%s:",g_Locale->getText (LOCALE_STREAMINFO_ARATIO)); + g_Font[font_info]->RenderString (xpos, ypos, width*2/3 - 10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + switch (aspectRatio) { + case 1: + sprintf ((char *) buf, "4:3"); + break; + case 2: + sprintf ((char *) buf, "14:9"); + break; + case 3: + sprintf ((char *) buf, "16:9"); + break; + case 4: + sprintf ((char *) buf, "20:9"); + break; + default: + strncpy (buf, g_Locale->getText (LOCALE_STREAMINFO_ARATIO_UNKNOWN), sizeof (buf)); + } + g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, width*2/3 - 10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + //Video FRAMERATE + ypos += iheight; + sprintf ((char *) buf, "%s:", g_Locale->getText (LOCALE_STREAMINFO_FRAMERATE)); + g_Font[font_info]->RenderString (xpos, ypos, width*2/3 - 10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + switch (framerate) { + case 2: + sprintf ((char *) buf, "25fps"); + break; + case 5: + sprintf ((char *) buf, "50fps"); + break; + default: + strncpy (buf, g_Locale->getText (LOCALE_STREAMINFO_FRAMERATE_UNKNOWN), sizeof (buf)); + } + g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, width*2/3 - 10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + //AUDIOTYPE + ypos += iheight; + int type, layer, freq, mode, bitrate; + audioDecoder->getAudioInfo(type, layer, freq, bitrate, mode); +#if 0 + const char *layernames[4] = { "res", "III", "II", "I" }; + const char *sampfreqnames[4] = { "44,1k", "48k", "32k", "res" }; + const char *modenames[4] = { "stereo", "joint_st", "dual_ch", "single_ch" }; + + sprintf ((char *) buf, "%s: %s (%s/%s) %s", g_Locale->getText (LOCALE_STREAMINFO_AUDIOTYPE), modenames[stereo], sampfreqnames[sampfreq], layernames[layer], copy ? "c" : ""); + } +#endif + const char *mpegmodes[4] = { "stereo", "joint_st", "dual_ch", "single_ch" }; + const char *ddmodes[8] = { "CH1/CH2", "C", "L/R", "L/C/R", "L/R/S", "L/C/R/S", "L/R/SL/SR", "L/C/R/SL/SR" }; + + sprintf ((char *) buf, "%s:", g_Locale->getText (LOCALE_STREAMINFO_AUDIOTYPE)); + g_Font[font_info]->RenderString (xpos, ypos, width*2/3 - 10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + if(type == 0) { + sprintf ((char *) buf, "MPEG %s (%d)", mpegmodes[mode], freq); + } else { + sprintf ((char *) buf, "DD %s (%d)", ddmodes[mode], freq); + } + g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, width*2/3 - 10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + //satellite + t_satellite_position satellitePosition = CNeutrinoApp::getInstance ()->channelList->getActiveSatellitePosition (); + sat_iterator_t sit = satellitePositions.find(satellitePosition); + if(sit != satellitePositions.end()) { + ypos += iheight; + sprintf ((char *) buf, "%s:",g_Locale->getText (LOCALE_SATSETUP_SATELLITE));//swiped locale + g_Font[font_info]->RenderString(xpos, ypos, width*2/3-10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + sprintf ((char *) buf, "%s", sit->second.name.c_str()); + g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, width*2/3-10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + } + CChannelList *channelList = CNeutrinoApp::getInstance ()->channelList; + int curnum = channelList->getActiveChannelNumber(); + CZapitChannel * channel = channelList->getChannel(curnum); + CZapitClient::CCurrentServiceInfo si = g_Zapit->getCurrentServiceInfo (); + + //channel + ypos += iheight; + sprintf ((char *) buf, "%s:",g_Locale->getText (LOCALE_TIMERLIST_CHANNEL));//swiped locale + g_Font[font_info]->RenderString(xpos, ypos, width*2/3-10, buf , COL_MENUCONTENTDARK, 0, true); // UTF-8 + sprintf((char*) buf, "%s" ,channelList->getActiveChannelName().c_str()); + g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, width*2/3 - 10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + //tsfrequenz + ypos += iheight; + char * f=NULL, *s=NULL, *m=NULL; + if(frontend->getInfo()->type == FE_QPSK) { + frontend->getDelSys((fe_code_rate_t)si.fec, dvbs_get_modulation((fe_code_rate_t)si.fec), f, s, m); + sprintf ((char *) buf,"%d.%d (%c) %d %s %s %s", si.tsfrequency / 1000, si.tsfrequency % 1000, si.polarisation ? 'V' : 'H', si.rate / 1000,f,m,s=="DVB-S2"?"S2":"S1"); + g_Font[font_info]->RenderString(xpos, ypos, width*2/3-10, "Tp. Freq.:" , COL_MENUCONTENTDARK, 0, true); // UTF-8 + g_Font[font_info]->RenderString(xpos+spaceoffset, ypos, width*2/3-10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + } + // paint labels + spaceoffset = 68; + + //onid + ypos+= sheight; + sprintf((char*) buf, "0x%04x (%i)", si.onid, si.onid); + g_Font[font_small]->RenderString(xpos, ypos, width*2/3-10, "ONid:" , COL_MENUCONTENTDARK, 0, true); // UTF-8 + g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, width*2/3-10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + //sid + ypos+= sheight; + sprintf((char*) buf, "0x%04x (%i)", si.sid, si.sid); + g_Font[font_small]->RenderString(xpos, ypos, width*2/3-10, "Sid:" , COL_MENUCONTENTDARK, 0, true); // UTF-8 + g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, width*2/3-10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + //tsid + ypos+= sheight; + sprintf((char*) buf, "0x%04x (%i)", si.tsid, si.tsid); + g_Font[font_small]->RenderString(xpos, ypos, width*2/3-10, "TSid:" , COL_MENUCONTENTDARK, 0, true); // UTF-8 + g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, width*2/3-10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + //pmtpid + ypos+= sheight; + sprintf((char*) buf, "0x%04x (%i)", si.pmtpid, si.pmtpid); + g_Font[font_small]->RenderString(xpos, ypos, width*2/3-10, "PMTpid:", COL_MENUCONTENTDARK, 0, true); // UTF-8 + g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, width*2/3-10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + //vpid + ypos+= sheight; + if ( g_RemoteControl->current_PIDs.PIDs.vpid > 0 ){ + sprintf((char*) buf, "0x%04x (%i)", g_RemoteControl->current_PIDs.PIDs.vpid, g_RemoteControl->current_PIDs.PIDs.vpid ); + } else { + sprintf((char*) buf, "%s", g_Locale->getText(LOCALE_STREAMINFO_NOT_AVAILABLE)); + } + g_Font[font_small]->RenderString(xpos, ypos, width*2/3-10, "Vpid:" , COL_MENUCONTENTDARK, 0, true); // UTF-8 + g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, width*2/3-10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + //apid + ypos+= sheight; + g_Font[font_small]->RenderString(xpos, ypos, width*2/3-10, "Apid(s):" , COL_MENUCONTENTDARK, 0, true); // UTF-8 + if (g_RemoteControl->current_PIDs.APIDs.empty()){ + sprintf((char*) buf, "%s", g_Locale->getText(LOCALE_STREAMINFO_NOT_AVAILABLE)); + } else { + unsigned int i=0,j=0,sw=spaceoffset; + for (i= 0; (icurrent_PIDs.APIDs.size()) && (i<10); i++) + { + sprintf((char*) buf, "0x%04x (%i)", g_RemoteControl->current_PIDs.APIDs[i].pid, g_RemoteControl->current_PIDs.APIDs[i].pid ); + if (i == g_RemoteControl->current_PIDs.PIDs.selected_apid){ + g_Font[font_small]->RenderString(xpos+sw, ypos, width*2/3-10, buf, COL_MENUHEAD, 0, true); // UTF-8 + } + else{ + g_Font[font_small]->RenderString(xpos+sw, ypos, width*2/3-10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + } + sw = g_Font[font_small]->getRenderWidth(buf)+sw+10; + if (((i+1)%3 == 0) &&(g_RemoteControl->current_PIDs.APIDs.size()-1 > i)){ // if we have lots of apids, put "intermediate" line with pids + ypos+= sheight; + sw=spaceoffset; + } + } + } + + //vtxtpid + ypos += sheight; + if ( g_RemoteControl->current_PIDs.PIDs.vtxtpid == 0 ) + sprintf((char*) buf, "%s", g_Locale->getText(LOCALE_STREAMINFO_NOT_AVAILABLE)); + else + sprintf((char*) buf, "0x%04x (%i)", g_RemoteControl->current_PIDs.PIDs.vtxtpid, g_RemoteControl->current_PIDs.PIDs.vtxtpid ); + g_Font[font_small]->RenderString(xpos, ypos, width*2/3-10, "VTXTpid:" , COL_MENUCONTENTDARK, 0, true); // UTF-8 + g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, width*2/3-10, buf, COL_MENUCONTENTDARK, 0, true); // UTF-8 + + yypos = ypos; +} + +int CStreamInfo2Handler::exec(CMenuTarget* parent, const std::string &actionkey) +{ + int res = menu_return::RETURN_EXIT_ALL; + if (parent){ + parent->hide(); + } + CStreamInfo2 *e = new CStreamInfo2; + e->exec(); + delete e; + return res; +} + +/* + * some definition + */ +#define TS_LEN 188 +#define TS_BUF_SIZE (TS_LEN * 2048) /* fix dmx buffer size */ + +static unsigned long timeval_to_ms (const struct timeval *tv) +{ + return (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000); +} + +long delta_time_ms (struct timeval *tv, struct timeval *last_tv) +{ + return timeval_to_ms (tv) - timeval_to_ms (last_tv); +} + +unsigned long long b_total; +static cDemux * dmx; + +int CStreamInfo2::ts_setup () +{ + if (g_RemoteControl->current_PIDs.PIDs.vpid == 0) + return -1; + + dmx = new cDemux(1); + + dmx->Open(DMX_TP_CHANNEL, NULL, 3008 * 62); + dmx->pesFilter(g_RemoteControl->current_PIDs.PIDs.vpid); + dmx->Start(); + + gettimeofday (&first_tv, NULL); + last_tv.tv_sec = first_tv.tv_sec; + last_tv.tv_usec = first_tv.tv_usec; + b_total = 0; + return 0; +} + +int CStreamInfo2::update_rate () +{ + unsigned char buf[TS_BUF_SIZE]; + long b; + + int ret = 0; + int b_len, b_start; + int timeout = 100; + + if(!dmx) + return 0; + + b_len = 0; + b_start = 0; + + b_len = dmx->Read(buf, sizeof (buf), timeout); + //printf("ts: read %d\n", b_len); + + b = b_len; + if (b <= 0) + return 0; + + gettimeofday (&tv, NULL); + + b_total += b; + + long d_tim_ms; + + d_tim_ms = delta_time_ms (&tv, &last_tv); + if (d_tim_ms <= 0) + d_tim_ms = 1; // ignore usecs + + bit_s = (((unsigned long long) b * 8000ULL) + ((unsigned long long) d_tim_ms / 2ULL)) + / (unsigned long long) d_tim_ms; + + d_tim_ms = delta_time_ms (&tv, &first_tv); + if (d_tim_ms <= 0) + d_tim_ms = 1; // ignore usecs + + abit_s = ((b_total * 8000ULL) + ((unsigned long long) d_tim_ms / 2ULL)) + / (unsigned long long) d_tim_ms; + + last_tv.tv_sec = tv.tv_sec; + last_tv.tv_usec = tv.tv_usec; + ret = 1; + return ret; +} + +int CStreamInfo2::ts_close () +{ + if(dmx) + delete dmx; + dmx = NULL; + return 0; +} + +void CStreamInfo2::showSNR () +{ + char percent[10]; + int barwidth = 150; + uint16_t ssig, ssnr; + int sig, snr; + int posx, posy; + int sw; + + snr = (signal.snr & 0xFFFF) * 100 / 65535; + sig = (signal.sig & 0xFFFF) * 100 / 65535; + + int mheight = g_Font[font_info]->getHeight(); + if(sigscale->getPercent() != sig) { + posy = yypos + (mheight/2); + posx = x + 10; + sprintf(percent, "%d%% SIG", sig); + sw = g_Font[font_info]->getRenderWidth (percent); + sigscale->paint(posx - 1, posy, sig); + + posx = posx + barwidth + 3; + frameBuffer->paintBoxRel(posx, posy -1, sw, mheight-8, COL_MENUHEAD_PLUS_0); + g_Font[font_info]->RenderString (posx+2, posy + mheight-5, sw, percent, COL_MENUCONTENTDARK); + } + if(snrscale->getPercent() != snr) { + posy = yypos + mheight + 4; + posx = x + 10; + sprintf(percent, "%d%% SNR", snr); + sw = g_Font[font_info]->getRenderWidth (percent); + snrscale->paint(posx - 1, posy+2, snr); + + posx = posx + barwidth + 3; + frameBuffer->paintBoxRel(posx, posy - 1, sw, mheight-8, COL_MENUHEAD_PLUS_0, 0, true); + g_Font[font_info]->RenderString (posx + 2, posy + mheight-5, sw, percent, COL_MENUCONTENTDARK, 0, true); + } +} diff --git a/src/gui/streaminfo2.h b/src/gui/streaminfo2.h new file mode 100644 index 000000000..e85706659 --- /dev/null +++ b/src/gui/streaminfo2.h @@ -0,0 +1,114 @@ +/* + Neutrino-GUI - DBoxII-Project + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __streaminfo2__ +#define __streaminfo2__ + +#include + +#include +#include +#include + + +class CStreamInfo2 : public CMenuTarget +{ + private: + + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hheight,iheight,sheight; // head/info/small font height + + int max_height; // Frambuffer 0.. max + int max_width; + + int yypos; + int paint_mode; + + int font_head; + int font_info; + int font_small; + + int sigBox_x; + int sigBox_y; + int sigBox_w; + int sigBox_h; + int sigBox_pos; + int sig_text_y; + int sig_text_ber_x; + int sig_text_sig_x; + int sig_text_snr_x; + int sig_text_rate_x; + + struct feSignal { + unsigned long ber, old_ber, max_ber, min_ber; + unsigned long sig, old_sig, max_sig, min_sig; + unsigned long snr, old_snr, max_snr, min_snr; + } signal; + + struct bitrate { + unsigned int short_average, max_short_average, min_short_average; + } rate; + + int doSignalStrengthLoop(); + + int dvrfd, dmxfd; + struct timeval tv, last_tv, first_tv; + unsigned long long bit_s; + unsigned long long abit_s; + unsigned long long b_total; + + int update_rate(); + int ts_setup(); + int ts_close(); + + void paint(int mode); + void paint_pig(int x, int y, int w, int h); + void paint_techinfo(int x, int y); + void paint_signal_fe_box(int x, int y, int w, int h); + void paint_signal_fe(struct bitrate rate, struct feSignal s); + int y_signal_fe(unsigned long value, unsigned long max_range, int max_y); + void SignalRenderStr (unsigned int value, int x, int y); + CScale *sigscale; + CScale *snrscale; + void showSNR (); + + public: + + CStreamInfo2(); + ~CStreamInfo2(); + int exec(); + + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); + +}; +class CStreamInfo2Handler : public CMenuTarget +{ + public: + int exec( CMenuTarget* parent, const std::string &actionKey); +}; +#endif + diff --git a/src/gui/timeosd.cpp b/src/gui/timeosd.cpp new file mode 100644 index 000000000..6f2e3c814 --- /dev/null +++ b/src/gui/timeosd.cpp @@ -0,0 +1,137 @@ +/* + Neutrino-GUI - DBoxII-Project + + Timerliste by Zwen + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +static CScale * timescale; + +#define TIMEOSD_FONT SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME +#define TIMEBARH 38 +#define BARLEN 200 +CTimeOSD::CTimeOSD() +{ + frameBuffer = CFrameBuffer::getInstance(); + visible=false; + m_mode=MODE_ASC; + GetDimensions(); + if(!timescale) + timescale = new CScale(200, 32, 40, 100, 70, true); +} + +CTimeOSD::~CTimeOSD() +{ + hide(); + if(timescale) { + delete timescale; + timescale = 0; + } +} + +void CTimeOSD::show(time_t time_show) +{ + GetDimensions(); + visible = true; + m_time_dis = time(NULL); + m_time_show = time_show; + frameBuffer->paintBoxRel(m_xstart-2, m_y, 2+BARLEN+2, TIMEBARH, COL_INFOBAR_SHADOW_PLUS_0); //border + timescale->reset(); + update(); +} + +void CTimeOSD::GetDimensions() +{ + m_xstart = g_settings.screen_StartX + 10; + m_xend = g_settings.screen_EndX - 10; + m_height = g_Font[TIMEOSD_FONT]->getHeight(); + m_y = g_settings.screen_StartY + 10; + m_width = g_Font[TIMEOSD_FONT]->getRenderWidth("00:00:00"); + if(g_settings.mode_clock) { + int x1 = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->getRenderWidth(widest_number); + int x2 = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME]->getRenderWidth(":"); + twidth = x1*6 + x2*2; + m_xend = m_xend - twidth - 45; + } +} + +void CTimeOSD::update(time_t time_show) +{ + time_t tDisplayTime; + static time_t oldDisplayTime = 0; + char cDisplayTime[8+1]; + fb_pixel_t color1, color2; + +//printf("CTimeOSD::update time %ld\n", time_show); + if(!visible) + return; + if(m_mode == MODE_ASC) { + color1 = COL_MENUCONTENT_PLUS_0; + color2 = COL_MENUCONTENT; + } else { + color1 = COL_MENUCONTENTSELECTED_PLUS_0; + color2 = COL_MENUCONTENTSELECTED; + if(!time_show) time_show = 1; + } + if(time_show) { + m_time_show = time_show; + tDisplayTime = m_time_show; + } else { + if(m_mode == MODE_ASC) { + tDisplayTime = m_time_show + (time(NULL) - m_time_dis); + } else { + tDisplayTime = m_time_show + (m_time_dis - time(NULL)); + } + } + if(tDisplayTime < 0) + tDisplayTime=0; + if(tDisplayTime != oldDisplayTime) { + oldDisplayTime = tDisplayTime; + strftime(cDisplayTime, 9, "%T", gmtime(&tDisplayTime)); + frameBuffer->paintBoxRel(m_xend - m_width - 10, m_y, m_width + 10, m_height, color1); + g_Font[TIMEOSD_FONT]->RenderString(m_xend - m_width - 5, m_y + m_height, m_width +5, cDisplayTime, color2); + } +} + +void CTimeOSD::updatePos(short runningPercent) +{ + timescale->paint(m_xstart, m_y, runningPercent); +} + +void CTimeOSD::hide() +{ + GetDimensions(); +printf("CTimeOSD::hide: x %d y %d xend %d yend %d\n", m_xstart, m_y , m_xend - (g_settings.mode_clock ? 35 : 0), m_height + 15); + if(!visible) + return; + //frameBuffer->paintBackgroundBoxRel(m_xstart-10, m_y - 10 , m_xend - (g_settings.mode_clock ? 35 : 0), m_height + 15); + frameBuffer->paintBackgroundBoxRel(m_xstart-2, m_y , m_xend - (g_settings.mode_clock ? 35 : 0), m_height + 15); + visible=false; + timescale->reset(); +} diff --git a/src/gui/timeosd.h b/src/gui/timeosd.h new file mode 100644 index 000000000..284b07de6 --- /dev/null +++ b/src/gui/timeosd.h @@ -0,0 +1,60 @@ +/* + Neutrino-GUI - DBoxII-Project + + TimeOSD by Zwen + + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __timeosd__ +#define __timeosd__ + +#include +#include + +class CTimeOSD +{ + public: + enum mode + { + MODE_ASC, + MODE_DESC + }; + + private: + CFrameBuffer *frameBuffer; + time_t m_time_dis; + time_t m_time_show; + bool visible; + int m_xstart,m_xend,m_y,m_height, m_width, twidth; + mode m_mode; + void GetDimensions(); + + public: + CTimeOSD(); + ~CTimeOSD(); + void show(time_t time_show); + void update(time_t time_show = 0); + void updatePos(short runningPercent); + void hide(); + bool IsVisible() {return visible;} + void SetMode(mode m) { m_mode = m;} + mode GetMode() { return m_mode;} +}; +#endif diff --git a/src/gui/timerlist.cpp b/src/gui/timerlist.cpp new file mode 100644 index 000000000..e26c3ed40 --- /dev/null +++ b/src/gui/timerlist.cpp @@ -0,0 +1,1179 @@ +/* + Neutrino-GUI - DBoxII-Project + + Timerliste by Zwen + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +extern CBouquetManager *g_bouquetManager; + +#include + +#define info_height 60 +#define ROUND_RADIUS 9 + +class CTimerListNewNotifier : public CChangeObserver +{ +private: + CMenuItem* m1; + CMenuItem* m2; + CMenuItem* m3; + CMenuItem* m4; + CMenuItem* m5; + CMenuItem* m6; + char* display; + int* iType; + time_t* stopTime; +public: + CTimerListNewNotifier( int* Type, time_t* time,CMenuItem* a1, CMenuItem* a2, + CMenuItem* a3, CMenuItem* a4, CMenuItem* a5, CMenuItem* a6,char* d) + { + m1 = a1; + m2 = a2; + m3 = a3; + m4 = a4; + m5 = a5; + m6 = a6; + display=d; + iType=Type; + stopTime=time; + } + bool changeNotify(const neutrino_locale_t OptionName, void *) + { + CTimerd::CTimerEventTypes type = (CTimerd::CTimerEventTypes) *iType; + if(type == CTimerd::TIMER_RECORD) + { + *stopTime=(time(NULL)/60)*60; + struct tm *tmTime2 = localtime(stopTime); + sprintf( display, "%02d.%02d.%04d %02d:%02d", tmTime2->tm_mday, tmTime2->tm_mon+1, + tmTime2->tm_year+1900, + tmTime2->tm_hour, tmTime2->tm_min); + m1->setActive(true); + m6->setActive((g_settings.recording_type == RECORDING_FILE)); + } + else + { + *stopTime=0; + strcpy(display," "); + m1->setActive (false); + m6->setActive(false); + } + if(type == CTimerd::TIMER_RECORD || + type == CTimerd::TIMER_ZAPTO || + type == CTimerd::TIMER_NEXTPROGRAM) + { + m2->setActive(true); + } + else + { + m2->setActive(false); + } + if(type == CTimerd::TIMER_STANDBY) + m3->setActive(true); + else + m3->setActive(false); + if(type == CTimerd::TIMER_REMIND) + m4->setActive(true); + else + m4->setActive(false); + if(type == CTimerd::TIMER_EXEC_PLUGIN) + m5->setActive(true); + else + m5->setActive(false); + return true; + } +}; + +class CTimerListRepeatNotifier : public CChangeObserver +{ +private: + CMenuForwarder* m1; + CMenuForwarder* m2; + + int* iRepeat; +public: + CTimerListRepeatNotifier( int* repeat, CMenuForwarder* a1, CMenuForwarder *a2) + { + m1 = a1; + m2 = a2; + iRepeat=repeat; + } + + bool changeNotify(const neutrino_locale_t OptionName, void *) + { + if(*iRepeat >= (int)CTimerd::TIMERREPEAT_WEEKDAYS) + m1->setActive (true); + else + m1->setActive (false); + if (*iRepeat != (int)CTimerd::TIMERREPEAT_ONCE) + m2->setActive(true); + else + m2->setActive(false); + return true; + } +}; + +class CTimerListApidNotifier : public CChangeObserver +{ +private: + int* o_dflt; + int* o_std; + int* o_alt; + int* o_ac3; + CMenuItem* m_dflt; + CMenuItem* m_std; + CMenuItem* m_alt; + CMenuItem* m_ac3; +public: + CTimerListApidNotifier( int* o1, int* o2, int* o3, int* o4) + { + o_dflt=o1; + o_std=o2; + o_alt=o3; + o_ac3=o4; + } + + void setItems(CMenuItem* m1, CMenuItem* m2, CMenuItem* m3, CMenuItem* m4) + { + m_dflt=m1; + m_std=m2; + m_alt=m3; + m_ac3=m4; + } + + bool changeNotify(const neutrino_locale_t OptionName, void *) + { + if(OptionName == LOCALE_TIMERLIST_APIDS_DFLT) + { + if(*o_dflt==0) + { + m_std->setActive(true); + m_alt->setActive(true); + m_ac3->setActive(true); + } + else + { + m_std->setActive(false); + m_alt->setActive(false); + m_ac3->setActive(false); + *o_std=0; + *o_alt=0; + *o_ac3=0; + } + } + else + { + if(*o_std || *o_alt || *o_ac3) + *o_dflt=0; + } + return true; + } +}; + + +CTimerList::CTimerList() +{ + frameBuffer = CFrameBuffer::getInstance(); + visible = false; + selected = 0; + liststart = 0; + Timer = new CTimerdClient(); + skipEventID=0; + buttonHeight = 25; +} + +CTimerList::~CTimerList() +{ + timerlist.clear(); + delete Timer; +} + +int CTimerList::exec(CMenuTarget* parent, const std::string & actionKey) +{ + const char * key = actionKey.c_str(); + + if (strcmp(key, "modifytimer") == 0) + { + timerlist[selected].announceTime = timerlist[selected].alarmTime -60; + if(timerlist[selected].eventRepeat >= CTimerd::TIMERREPEAT_WEEKDAYS) + Timer->getWeekdaysFromStr(&timerlist[selected].eventRepeat, m_weekdaysStr); + if(timerlist[selected].eventType == CTimerd::TIMER_RECORD) + { + timerlist[selected].announceTime -= 120; // 2 more mins for rec timer + if (timer_apids_dflt) + timerlist[selected].apids = TIMERD_APIDS_CONF; + else + timerlist[selected].apids = (timer_apids_std * TIMERD_APIDS_STD) | (timer_apids_ac3 * TIMERD_APIDS_AC3) | + (timer_apids_alt * TIMERD_APIDS_ALT); + Timer->modifyTimerAPid(timerlist[selected].eventID,timerlist[selected].apids); + Timer->modifyRecordTimerEvent(timerlist[selected].eventID, timerlist[selected].announceTime, + timerlist[selected].alarmTime, + timerlist[selected].stopTime, timerlist[selected].eventRepeat, + timerlist[selected].repeatCount,timerlist[selected].recordingDir); + } else + { + Timer->modifyTimerEvent(timerlist[selected].eventID, timerlist[selected].announceTime, + timerlist[selected].alarmTime, + timerlist[selected].stopTime, timerlist[selected].eventRepeat, + timerlist[selected].repeatCount); + } + return menu_return::RETURN_EXIT; + } + else if (strcmp(key, "newtimer") == 0) + { + timerNew.announceTime=timerNew.alarmTime-60; + CTimerd::EventInfo eventinfo; + CTimerd::RecordingInfo recinfo; + eventinfo.epgID=0; + eventinfo.epg_starttime=0; + eventinfo.channel_id=timerNew.channel_id; + eventinfo.apids = TIMERD_APIDS_CONF; + eventinfo.recordingSafety = false; + timerNew.standby_on = (timerNew_standby_on == 1); + void *data=NULL; + if(timerNew.eventType == CTimerd::TIMER_STANDBY) + data=&(timerNew.standby_on); + else if(timerNew.eventType==CTimerd::TIMER_NEXTPROGRAM || + timerNew.eventType==CTimerd::TIMER_ZAPTO || + timerNew.eventType==CTimerd::TIMER_RECORD) + { + if (strcmp(timerNew_channel_name, "---")==0) + return menu_return::RETURN_REPAINT; + if (timerNew.eventType==CTimerd::TIMER_RECORD) + { + recinfo.epgID=0; + recinfo.epg_starttime=0; + recinfo.channel_id=timerNew.channel_id; + recinfo.apids=TIMERD_APIDS_CONF; + recinfo.recordingSafety = false; + + timerNew.announceTime-= 120; // 2 more mins for rec timer + strncpy(recinfo.recordingDir,timerNew.recordingDir,sizeof(recinfo.recordingDir)); + data = &recinfo; + } else + data= &eventinfo; + } + else if(timerNew.eventType==CTimerd::TIMER_REMIND) + data= timerNew.message; + else if (timerNew.eventType==CTimerd::TIMER_EXEC_PLUGIN) + { + if (strcmp(timerNew.pluginName, "---") == 0) + return menu_return::RETURN_REPAINT; + data= timerNew.pluginName; + } + if(timerNew.eventRepeat >= CTimerd::TIMERREPEAT_WEEKDAYS) + Timer->getWeekdaysFromStr(&timerNew.eventRepeat, m_weekdaysStr); + + if (Timer->addTimerEvent(timerNew.eventType,data,timerNew.announceTime,timerNew.alarmTime, + timerNew.stopTime,timerNew.eventRepeat,timerNew.repeatCount,false) == -1) + { + bool forceAdd = askUserOnTimerConflict(timerNew.announceTime,timerNew.stopTime); + + if (forceAdd) + { + Timer->addTimerEvent(timerNew.eventType,data,timerNew.announceTime,timerNew.alarmTime, + timerNew.stopTime, timerNew.eventRepeat,timerNew.repeatCount,true); + } + } + return menu_return::RETURN_EXIT; + } + else if (strncmp(key, "SC:", 3) == 0) + { + int delta; + sscanf(&(key[3]), + SCANF_CHANNEL_ID_TYPE + "%n", + &timerNew.channel_id, + &delta); + strncpy(timerNew_channel_name, &(key[3 + delta + 1]), 30); + g_RCInput->postMsg(CRCInput::RC_timeout, 0); // leave underlying menu also + g_RCInput->postMsg(CRCInput::RC_timeout, 0); // leave underlying menu also + return menu_return::RETURN_EXIT; + } + + if(parent) + { + parent->hide(); + } + + int ret = show(); + + return ret; +/* + if( ret > -1) + { + return menu_return::RETURN_REPAINT; + } + else if( ret == -1) + { + // -1 bedeutet nur REPAINT + return menu_return::RETURN_REPAINT; + } + else + { + // -2 bedeutet EXIT_ALL + return menu_return::RETURN_EXIT_ALL; + }*/ +} + +void CTimerList::updateEvents(void) +{ + timerlist.clear(); + Timer->getTimerList (timerlist); + //Remove last deleted event from List + CTimerd::TimerList::iterator timer = timerlist.begin(); + for(; timer != timerlist.end();timer++) + { + if(timer->eventID==skipEventID) + { + timerlist.erase(timer); + break; + } + } + sort(timerlist.begin(), timerlist.end()); + + width = w_max(720, 0); + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + + height = frameBuffer->getScreenHeight() - (info_height+50); + + listmaxshow = (height-theight-0)/(fheight*2); + height = theight+0+listmaxshow*fheight*2; // recalc height + if(timerlist.size() < listmaxshow) + { + listmaxshow=timerlist.size(); + height = theight+0+listmaxshow*fheight*2; // recalc height + } + if(selected==timerlist.size() && !(timerlist.empty())) + { + selected=timerlist.size()-1; + liststart = (selected/listmaxshow)*listmaxshow; + } + x = frameBuffer->getScreenX() + (frameBuffer->getScreenWidth() - width) / 2; + y = frameBuffer->getScreenY() + (frameBuffer->getScreenHeight() - (height+ info_height)) / 2; +} + + +int CTimerList::show() +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = menu_return::RETURN_REPAINT; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + bool loop=true; + bool update=true; + while(loop) + { + if(update) + { + hide(); + updateEvents(); + update=false; + paint(); + } + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + if( ( msg == CRCInput::RC_timeout ) || + ( msg == CRCInput::RC_home) ) + { //Exit after timeout or cancel key + loop=false; + } + else if ((msg == CRCInput::RC_up) && !(timerlist.empty())) + { + int prevselected=selected; + if(selected==0) + { + selected = timerlist.size()-1; + } + else + selected--; + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paint(); + } + else + { + paintItem(selected - liststart); + } + } + else if ((msg == CRCInput::RC_down) && !(timerlist.empty())) + { + int prevselected=selected; + selected = (selected+1)%timerlist.size(); + paintItem(prevselected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + { + paint(); + } + else + { + paintItem(selected - liststart); + } + } + else if ((msg == CRCInput::RC_ok) && !(timerlist.empty())) + { + if (modifyTimer()==menu_return::RETURN_EXIT_ALL) + { + res=menu_return::RETURN_EXIT_ALL; + loop=false; + } + else + update=true; + } + else if((msg == CRCInput::RC_red) && !(timerlist.empty())) + { + Timer->removeTimerEvent(timerlist[selected].eventID); + skipEventID=timerlist[selected].eventID; + update=true; + } + else if(msg==CRCInput::RC_green) + { + if (newTimer()==menu_return::RETURN_EXIT_ALL) + { + res=menu_return::RETURN_EXIT_ALL; + loop=false; + } + else + update=true; + } + else if(msg==CRCInput::RC_yellow) + { + update=true; + } + else if((msg==CRCInput::RC_blue)|| + (CRCInput::isNumeric(msg)) ) + { + //pushback key if... + g_RCInput->postMsg( msg, data ); + loop=false; + } + else if(msg==CRCInput::RC_setup) + { + res=menu_return::RETURN_EXIT_ALL; + loop=false; + } + else if( msg == CRCInput::RC_help || msg == CRCInput::RC_info) + { + CTimerd::responseGetTimer* timer=&timerlist[selected]; + if(timer!=NULL) + { + if(timer->eventType == CTimerd::TIMER_RECORD || timer->eventType == CTimerd::TIMER_ZAPTO) + { + hide(); + res = g_EpgData->show(timer->channel_id, timer->epgID, &timer->epg_starttime); + if(res==menu_return::RETURN_EXIT_ALL) + loop=false; + else + paint(); + } + } + // help key + } + else if (msg == CRCInput::RC_sat || msg == CRCInput::RC_favorites) { + g_RCInput->postMsg (msg, 0); + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + else + { + if( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + hide(); + + return(res); +} + +void CTimerList::hide() +{ + if(visible) + { + frameBuffer->paintBackgroundBoxRel(x, y, width, height+ info_height+ 5); + visible = false; + } +} + +bool sectionsd_getEPGid(const event_id_t epgID, const time_t startzeit, CEPGData * epgdata); +void CTimerList::paintItem(int pos) +{ + int ypos = y+ theight+0 + pos*fheight*2; + + uint8_t color; + fb_pixel_t bgcolor; + + if (pos & 1) + { + color = COL_MENUCONTENTDARK; + bgcolor = COL_MENUCONTENTDARK_PLUS_0; + } + else + { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + } + + if (liststart + pos == selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + + int real_width=width; + if(timerlist.size()>listmaxshow) + { + real_width-=15; //scrollbar + } + + frameBuffer->paintBoxRel(x,ypos, real_width, 2*fheight, bgcolor); + if(liststart+posRenderString(x+10,ypos+fheight, 150, zAlarmTime, color, fheight, true); // UTF-8 + if(timer.stopTime != 0) + { + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10,ypos+2*fheight, 150, zStopTime, color, fheight, true); // UTF-8 + } + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+160,ypos+fheight, (real_width-160)/2-5, convertTimerRepeat2String(timer.eventRepeat), color, fheight, true); // UTF-8 + + if (timer.eventRepeat != CTimerd::TIMERREPEAT_ONCE) + { + char srepeatcount[25] = {0}; + if (timer.repeatCount == 0) +// Unicode 8734 (hex: 221E) not available in all fonts +// sprintf(srepeatcount,"∞"); + sprintf(srepeatcount,"00"); + else + sprintf(srepeatcount,"%ux",timer.repeatCount); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+160+(real_width-300)/2,ypos+fheight, (real_width-160)/2-5, srepeatcount, color, fheight, true); // UTF-8 + } + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+160+(real_width-160)/2,ypos+fheight, (real_width-160)/2-5, convertTimerType2String(timer.eventType), color, fheight, true); // UTF-8 + std::string zAddData(""); + switch(timer.eventType) + { + case CTimerd::TIMER_NEXTPROGRAM : + case CTimerd::TIMER_ZAPTO : + case CTimerd::TIMER_RECORD : + { + zAddData = convertChannelId2String(timer.channel_id); // UTF-8 + if(timer.apids != TIMERD_APIDS_CONF) + { + std::string sep = ""; + zAddData += " ("; + if(timer.apids & TIMERD_APIDS_STD) + { + zAddData += "STD"; + sep = "/"; + } + if(timer.apids & TIMERD_APIDS_ALT) + { + zAddData += sep; + zAddData += "ALT"; + sep = "/"; + } + if(timer.apids & TIMERD_APIDS_AC3) + { + zAddData += sep; + zAddData += "AC3"; + sep = "/"; + } + zAddData += ')'; + } + if(timer.epgID!=0) + { + CEPGData epgdata; + //if (g_Sectionsd->getEPGid(timer.epgID, timer.epg_starttime, &epgdata)) + if (sectionsd_getEPGid(timer.epgID, timer.epg_starttime, &epgdata)) + { + zAddData += " : "; + zAddData += epgdata.title; + } + else if(strlen(timer.epgTitle)!=0) + { + zAddData += " : "; + zAddData += timer.epgTitle; + } + } + else if(strlen(timer.epgTitle)!=0) + { + zAddData += " : "; + zAddData += timer.epgTitle; + } + } + break; + case CTimerd::TIMER_STANDBY: + { + zAddData = g_Locale->getText(timer.standby_on ? LOCALE_TIMERLIST_STANDBY_ON : LOCALE_TIMERLIST_STANDBY_OFF); + break; + } + case CTimerd::TIMER_REMIND : + { + zAddData = timer.message; // must be UTF-8 encoded ! + } + break; + case CTimerd::TIMER_EXEC_PLUGIN : + { + zAddData = timer.pluginName; + } + break; + default:{} + } + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+160,ypos+2*fheight, real_width-165, zAddData, color, fheight, true); // UTF-8 + // LCD Display + if(liststart+pos==selected) + { + std::string line1 = convertTimerType2String(timer.eventType); // UTF-8 + std::string line2 = zAlarmTime; + switch(timer.eventType) + { + case CTimerd::TIMER_RECORD : + line2+= " -"; + line2+= zStopTime+6; + case CTimerd::TIMER_NEXTPROGRAM : + case CTimerd::TIMER_ZAPTO : + { + line1 += ' '; + line1 += convertChannelId2String(timer.channel_id); // UTF-8 + } + break; + case CTimerd::TIMER_STANDBY : + { + if(timer.standby_on) + line1+=" ON"; + else + line1+=" OFF"; + } + break; + default:; + } + CVFD::getInstance()->showMenuText(0, line1.c_str(), -1, true); // UTF-8 + //CVFD::getInstance()->showMenuText(1, line2.c_str(), -1, true); // UTF-8 + } + } +} + +void CTimerList::paintHead() +{ + frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + frameBuffer->paintIcon("timer.raw",x+5,y+4); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+35,y+theight+0, width- 45, g_Locale->getText(LOCALE_TIMERLIST_NAME), COL_MENUHEAD, 0, true); // UTF-8 + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, x+ width- 30, y+ 5 ); +/* if (bouquetList!=NULL) + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DBOX, x+ width- 60, y+ 5 );*/ +} + +const struct button_label TimerListButtons[3] = +{ + { NEUTRINO_ICON_BUTTON_RED , LOCALE_TIMERLIST_DELETE }, + { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_TIMERLIST_NEW }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_TIMERLIST_RELOAD } +}; + +void CTimerList::paintFoot() +{ + int ButtonWidth = (width - 20) / 4; + frameBuffer->paintBoxRel(x,y+height, width,buttonHeight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2); + //frameBuffer->paintHLine(x, x+width, y, COL_INFOBAR_SHADOW_PLUS_0); + + if (timerlist.empty()) + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + ButtonWidth + 10, y + height + 4, ButtonWidth, 2, &(TimerListButtons[1])); + else + { + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 10, y + height + 4, ButtonWidth, 3, TimerListButtons); + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, x+width- 1* ButtonWidth + 10, y+height); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+width-1 * ButtonWidth + 38, y+height+24 - 2, ButtonWidth- 28, g_Locale->getText(LOCALE_TIMERLIST_MODIFY), COL_INFOBAR, 0, true); // UTF-8 + } +} + +void CTimerList::paint() +{ + unsigned int page_nr = (listmaxshow == 0) ? 0 : (selected / listmaxshow); + liststart = page_nr * listmaxshow; + + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, g_Locale->getText(LOCALE_TIMERLIST_NAME)); + + paintHead(); + for(unsigned int count=0;countlistmaxshow) + { + int ypos = y+ theight; + int sb = 2*fheight* listmaxshow; + frameBuffer->paintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((timerlist.size()- 1)/ listmaxshow)+ 1; + float sbh= (sb- 4)/ sbc; + + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ int(page_nr * sbh) , 11, int(sbh), COL_MENUCONTENT_PLUS_3); + } + + paintFoot(); + visible = true; +} + +const char * CTimerList::convertTimerType2String(const CTimerd::CTimerEventTypes type) // UTF-8 +{ + switch(type) + { + case CTimerd::TIMER_SHUTDOWN : return g_Locale->getText(LOCALE_TIMERLIST_TYPE_SHUTDOWN ); + case CTimerd::TIMER_NEXTPROGRAM : return g_Locale->getText(LOCALE_TIMERLIST_TYPE_NEXTPROGRAM); + case CTimerd::TIMER_ZAPTO : return g_Locale->getText(LOCALE_TIMERLIST_TYPE_ZAPTO ); + case CTimerd::TIMER_STANDBY : return g_Locale->getText(LOCALE_TIMERLIST_TYPE_STANDBY ); + case CTimerd::TIMER_RECORD : return g_Locale->getText(LOCALE_TIMERLIST_TYPE_RECORD ); + case CTimerd::TIMER_REMIND : return g_Locale->getText(LOCALE_TIMERLIST_TYPE_REMIND ); + case CTimerd::TIMER_SLEEPTIMER : return g_Locale->getText(LOCALE_TIMERLIST_TYPE_SLEEPTIMER ); + case CTimerd::TIMER_EXEC_PLUGIN : return g_Locale->getText(LOCALE_TIMERLIST_TYPE_EXECPLUGIN ); + default : return g_Locale->getText(LOCALE_TIMERLIST_TYPE_UNKNOWN ); + } +} + +std::string CTimerList::convertTimerRepeat2String(const CTimerd::CTimerEventRepeat rep) // UTF-8 +{ + switch(rep) + { + case CTimerd::TIMERREPEAT_ONCE : return g_Locale->getText(LOCALE_TIMERLIST_REPEAT_ONCE ); + case CTimerd::TIMERREPEAT_DAILY : return g_Locale->getText(LOCALE_TIMERLIST_REPEAT_DAILY ); + case CTimerd::TIMERREPEAT_WEEKLY : return g_Locale->getText(LOCALE_TIMERLIST_REPEAT_WEEKLY ); + case CTimerd::TIMERREPEAT_BIWEEKLY : return g_Locale->getText(LOCALE_TIMERLIST_REPEAT_BIWEEKLY ); + case CTimerd::TIMERREPEAT_FOURWEEKLY : return g_Locale->getText(LOCALE_TIMERLIST_REPEAT_FOURWEEKLY ); + case CTimerd::TIMERREPEAT_MONTHLY : return g_Locale->getText(LOCALE_TIMERLIST_REPEAT_MONTHLY ); + case CTimerd::TIMERREPEAT_BYEVENTDESCRIPTION : return g_Locale->getText(LOCALE_TIMERLIST_REPEAT_BYEVENTDESCRIPTION); + default: + if(rep >=CTimerd::TIMERREPEAT_WEEKDAYS) + { + int weekdays = (((int)rep) >> 9); + std::string weekdayStr=""; + if(weekdays & 1) + weekdayStr+= g_Locale->getText(LOCALE_TIMERLIST_REPEAT_MONDAY); + weekdays >>= 1; + if(weekdays & 1) + weekdayStr+= g_Locale->getText(LOCALE_TIMERLIST_REPEAT_TUESDAY); + weekdays >>= 1; + if(weekdays & 1) + weekdayStr+= g_Locale->getText(LOCALE_TIMERLIST_REPEAT_WEDNESDAY); + weekdays >>= 1; + if(weekdays & 1) + weekdayStr+= g_Locale->getText(LOCALE_TIMERLIST_REPEAT_THURSDAY); + weekdays >>= 1; + if(weekdays & 1) + weekdayStr+= g_Locale->getText(LOCALE_TIMERLIST_REPEAT_FRIDAY); + weekdays >>= 1; + if(weekdays & 1) + weekdayStr+= g_Locale->getText(LOCALE_TIMERLIST_REPEAT_SATURDAY); + weekdays >>= 1; + if(weekdays & 1) + weekdayStr+= g_Locale->getText(LOCALE_TIMERLIST_REPEAT_SUNDAY); + return weekdayStr; + } + else + return g_Locale->getText(LOCALE_TIMERLIST_REPEAT_UNKNOWN); + } +} + +std::string CTimerList::convertChannelId2String(const t_channel_id id) // UTF-8 +{ + //CZapitClient Zapit; + std::string name = g_Zapit->getChannelName(id); // UTF-8 + if (name.empty()) + name = g_Locale->getText(LOCALE_TIMERLIST_PROGRAM_UNKNOWN); + + return name; +} + +#define TIMERLIST_REPEAT_OPTION_COUNT 7 +const CMenuOptionChooser::keyval TIMERLIST_REPEAT_OPTIONS[TIMERLIST_REPEAT_OPTION_COUNT] = +{ + { CTimerd::TIMERREPEAT_ONCE , LOCALE_TIMERLIST_REPEAT_ONCE }, + { CTimerd::TIMERREPEAT_DAILY , LOCALE_TIMERLIST_REPEAT_DAILY }, + { CTimerd::TIMERREPEAT_WEEKLY , LOCALE_TIMERLIST_REPEAT_WEEKLY }, + { CTimerd::TIMERREPEAT_BIWEEKLY , LOCALE_TIMERLIST_REPEAT_BIWEEKLY }, + { CTimerd::TIMERREPEAT_FOURWEEKLY , LOCALE_TIMERLIST_REPEAT_FOURWEEKLY }, + { CTimerd::TIMERREPEAT_MONTHLY , LOCALE_TIMERLIST_REPEAT_MONTHLY }, + { CTimerd::TIMERREPEAT_WEEKDAYS , LOCALE_TIMERLIST_REPEAT_WEEKDAYS } +}; + +#define TIMERLIST_STANDBY_OPTION_COUNT 2 +const CMenuOptionChooser::keyval TIMERLIST_STANDBY_OPTIONS[TIMERLIST_STANDBY_OPTION_COUNT] = +{ + { 0 , LOCALE_TIMERLIST_STANDBY_OFF }, + { 1 , LOCALE_TIMERLIST_STANDBY_ON } +}; + +#if 1 +#define TIMERLIST_TYPE_OPTION_COUNT 7 +#else +#define TIMERLIST_TYPE_OPTION_COUNT 8 +#endif +const CMenuOptionChooser::keyval TIMERLIST_TYPE_OPTIONS[TIMERLIST_TYPE_OPTION_COUNT] = +{ + { CTimerd::TIMER_SHUTDOWN , LOCALE_TIMERLIST_TYPE_SHUTDOWN }, +#if 0 + { CTimerd::TIMER_NEXTPROGRAM, LOCALE_TIMERLIST_TYPE_NEXTPROGRAM }, +#endif + { CTimerd::TIMER_ZAPTO , LOCALE_TIMERLIST_TYPE_ZAPTO }, + { CTimerd::TIMER_STANDBY , LOCALE_TIMERLIST_TYPE_STANDBY }, + { CTimerd::TIMER_RECORD , LOCALE_TIMERLIST_TYPE_RECORD }, + { CTimerd::TIMER_SLEEPTIMER , LOCALE_TIMERLIST_TYPE_SLEEPTIMER }, + { CTimerd::TIMER_REMIND , LOCALE_TIMERLIST_TYPE_REMIND }, + { CTimerd::TIMER_EXEC_PLUGIN, LOCALE_TIMERLIST_TYPE_EXECPLUGIN } +}; + +#define MESSAGEBOX_NO_YES_OPTION_COUNT 2 +const CMenuOptionChooser::keyval MESSAGEBOX_NO_YES_OPTIONS[MESSAGEBOX_NO_YES_OPTION_COUNT] = +{ + { 0, LOCALE_MESSAGEBOX_NO }, + { 1, LOCALE_MESSAGEBOX_YES } +}; + +int CTimerList::modifyTimer() +{ + CTimerd::responseGetTimer* timer=&timerlist[selected]; + CMenuWidget timerSettings(LOCALE_TIMERLIST_MENUMODIFY, NEUTRINO_ICON_SETTINGS); + timerSettings.addItem(GenericMenuSeparator); + timerSettings.addItem(GenericMenuBack); + timerSettings.addItem(GenericMenuSeparatorLine); + timerSettings.addItem(new CMenuForwarder(LOCALE_TIMERLIST_SAVE, true, NULL, this, "modifytimer", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + timerSettings.addItem(GenericMenuSeparatorLine); + + char type[80]; + strcpy(type, convertTimerType2String(timer->eventType)); // UTF + CMenuForwarder *m0 = new CMenuForwarder(LOCALE_TIMERLIST_TYPE, false, type); + timerSettings.addItem( m0); + + CDateInput timerSettings_alarmTime(LOCALE_TIMERLIST_ALARMTIME, &timer->alarmTime , LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CMenuForwarder *m1 = new CMenuForwarder(LOCALE_TIMERLIST_ALARMTIME, true, timerSettings_alarmTime.getValue (), &timerSettings_alarmTime ); + timerSettings.addItem( m1); + + CDateInput timerSettings_stopTime(LOCALE_TIMERLIST_STOPTIME, &timer->stopTime , LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + if(timer->stopTime != 0) + { + CMenuForwarder *m2 = new CMenuForwarder(LOCALE_TIMERLIST_STOPTIME, true, timerSettings_stopTime.getValue (), &timerSettings_stopTime ); + timerSettings.addItem( m2); + } + + Timer->setWeekdaysToStr(timer->eventRepeat, m_weekdaysStr); + timer->eventRepeat = (CTimerd::CTimerEventRepeat)(((int)timer->eventRepeat) & 0x1FF); + CStringInput timerSettings_weekdays(LOCALE_TIMERLIST_WEEKDAYS, m_weekdaysStr, 7, LOCALE_TIMERLIST_WEEKDAYS_HINT_1, LOCALE_TIMERLIST_WEEKDAYS_HINT_2, "-X"); + CMenuForwarder *m4 = new CMenuForwarder(LOCALE_TIMERLIST_WEEKDAYS, ((int)timer->eventRepeat) >= (int)CTimerd::TIMERREPEAT_WEEKDAYS, m_weekdaysStr, &timerSettings_weekdays ); + CIntInput timerSettings_repeatCount(LOCALE_TIMERLIST_REPEATCOUNT, (int&)timer->repeatCount,3, LOCALE_TIMERLIST_REPEATCOUNT_HELP1, LOCALE_TIMERLIST_REPEATCOUNT_HELP2); + + CMenuForwarder *m5 = new CMenuForwarder(LOCALE_TIMERLIST_REPEATCOUNT, timer->eventRepeat != (int)CTimerd::TIMERREPEAT_ONCE ,timerSettings_repeatCount.getValue() , &timerSettings_repeatCount); + + CTimerListRepeatNotifier notifier((int *)&timer->eventRepeat,m4,m5); + CMenuOptionChooser* m3 = new CMenuOptionChooser(LOCALE_TIMERLIST_REPEAT, (int *)&timer->eventRepeat, TIMERLIST_REPEAT_OPTIONS, TIMERLIST_REPEAT_OPTION_COUNT, true, ¬ifier); + +//printf("TIMER: rec dir %s len %s\n", timer->recordingDir, strlen(timer->recordingDir)); + + if(!strlen(timer->recordingDir)) + strncpy(timer->recordingDir,g_settings.network_nfs_recordingdir,sizeof(timer->recordingDir)); + + CMountChooser recDirs(LOCALE_TIMERLIST_RECORDING_DIR,NEUTRINO_ICON_SETTINGS,NULL, + timer->recordingDir, g_settings.network_nfs_recordingdir); + if (!recDirs.hasItem()) + { + printf("[CTimerList] warning: no network devices available\n"); + } + bool recDirEnabled = recDirs.hasItem() && (timer->eventType == CTimerd::TIMER_RECORD) && (g_settings.recording_type == RECORDING_FILE); + CMenuForwarder* m6 = new CMenuForwarder(LOCALE_TIMERLIST_RECORDING_DIR,recDirEnabled,timer->recordingDir, &recDirs); + + timerSettings.addItem(GenericMenuSeparatorLine); + timerSettings.addItem(m3); + timerSettings.addItem(m4); + timerSettings.addItem(m5); + timerSettings.addItem(GenericMenuSeparatorLine); + timerSettings.addItem(m6); + + CMenuWidget timerSettings_apids(LOCALE_TIMERLIST_APIDS, NEUTRINO_ICON_SETTINGS); + CTimerListApidNotifier apid_notifier(&timer_apids_dflt, &timer_apids_std, &timer_apids_ac3, &timer_apids_alt); + timer_apids_dflt = (timer->apids == 0) ? 1 : 0 ; + timer_apids_std = (timer->apids & TIMERD_APIDS_STD) ? 1 : 0 ; + timer_apids_ac3 = (timer->apids & TIMERD_APIDS_AC3) ? 1 : 0 ; + timer_apids_alt = (timer->apids & TIMERD_APIDS_ALT) ? 1 : 0 ; + timerSettings_apids.addItem(GenericMenuSeparator); + timerSettings_apids.addItem(GenericMenuBack); + timerSettings_apids.addItem(GenericMenuSeparatorLine); + CMenuOptionChooser* ma1 = new CMenuOptionChooser(LOCALE_TIMERLIST_APIDS_DFLT, &timer_apids_dflt, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true, &apid_notifier); + timerSettings_apids.addItem(ma1); + CMenuOptionChooser* ma2 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_APIDS_STD, &timer_apids_std, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true, &apid_notifier); + timerSettings_apids.addItem(ma2); + CMenuOptionChooser* ma3 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_APIDS_ALT, &timer_apids_alt, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true, &apid_notifier); + timerSettings_apids.addItem(ma3); + CMenuOptionChooser* ma4 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_APIDS_AC3, &timer_apids_ac3, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true, &apid_notifier); + timerSettings_apids.addItem(ma4); + apid_notifier.setItems(ma1,ma2,ma3,ma4); + if(timer->eventType == CTimerd::TIMER_RECORD) + { + timerSettings.addItem( new CMenuForwarder(LOCALE_TIMERLIST_APIDS, true, NULL, &timerSettings_apids )); + } + + return timerSettings.exec(this,""); +} + +int CTimerList::newTimer() +{ + std::vector toDelete; + // Defaults + timerNew.eventType = CTimerd::TIMER_RECORD ; + timerNew.eventRepeat = CTimerd::TIMERREPEAT_ONCE ; + timerNew.repeatCount = 0; + timerNew.alarmTime = (time(NULL)/60)*60; + timerNew.stopTime = (time(NULL)/60)*60; + timerNew.channel_id = 0; + strcpy(timerNew.message, ""); + timerNew_standby_on =false; + strncpy(timerNew.recordingDir,g_settings.network_nfs_recordingdir,sizeof(timerNew.recordingDir)); + + + CMenuWidget timerSettings(LOCALE_TIMERLIST_MENUNEW, NEUTRINO_ICON_SETTINGS); + timerSettings.addItem(GenericMenuSeparator); + timerSettings.addItem(GenericMenuBack); + timerSettings.addItem(GenericMenuSeparatorLine); + timerSettings.addItem(new CMenuForwarder(LOCALE_TIMERLIST_SAVE, true, NULL, this, "newtimer", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + timerSettings.addItem(GenericMenuSeparatorLine); + + CDateInput timerSettings_alarmTime(LOCALE_TIMERLIST_ALARMTIME, &(timerNew.alarmTime) , LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CMenuForwarder *m1 = new CMenuForwarder(LOCALE_TIMERLIST_ALARMTIME, true, timerSettings_alarmTime.getValue (), &timerSettings_alarmTime ); + + CDateInput timerSettings_stopTime(LOCALE_TIMERLIST_STOPTIME, &(timerNew.stopTime) , LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CMenuForwarder *m2 = new CMenuForwarder(LOCALE_TIMERLIST_STOPTIME, true, timerSettings_stopTime.getValue (), &timerSettings_stopTime ); + + CStringInput timerSettings_weekdays(LOCALE_TIMERLIST_WEEKDAYS, m_weekdaysStr, 7, LOCALE_TIMERLIST_WEEKDAYS_HINT_1, LOCALE_TIMERLIST_WEEKDAYS_HINT_2, "-X"); + CMenuForwarder *m4 = new CMenuForwarder(LOCALE_TIMERLIST_WEEKDAYS, false, m_weekdaysStr, &timerSettings_weekdays); + + CIntInput timerSettings_repeatCount(LOCALE_TIMERLIST_REPEATCOUNT, (int&)timerNew.repeatCount,3, LOCALE_TIMERLIST_REPEATCOUNT_HELP1, LOCALE_TIMERLIST_REPEATCOUNT_HELP2); + CMenuForwarder *m5 = new CMenuForwarder(LOCALE_TIMERLIST_REPEATCOUNT, false,timerSettings_repeatCount.getValue() , &timerSettings_repeatCount); + + CTimerListRepeatNotifier notifier((int *)&timerNew.eventRepeat,m4,m5); + strcpy(m_weekdaysStr,"-------"); + CMenuOptionChooser* m3 = new CMenuOptionChooser(LOCALE_TIMERLIST_REPEAT, (int *)&timerNew.eventRepeat, TIMERLIST_REPEAT_OPTIONS, TIMERLIST_REPEAT_OPTION_COUNT, true, ¬ifier); + + + CMenuWidget mctv(LOCALE_TIMERLIST_BOUQUETSELECT, NEUTRINO_ICON_SETTINGS); + CMenuWidget mcradio(LOCALE_TIMERLIST_BOUQUETSELECT, NEUTRINO_ICON_SETTINGS); + + for (int i = 0; i < (int) g_bouquetManager->Bouquets.size(); i++) { + if (!g_bouquetManager->Bouquets[i]->bHidden) { + CMenuWidget* mwtv = new CMenuWidget(LOCALE_TIMERLIST_CHANNELSELECT, NEUTRINO_ICON_SETTINGS); + toDelete.push_back(mwtv); + CMenuWidget* mwradio = new CMenuWidget(LOCALE_TIMERLIST_CHANNELSELECT, NEUTRINO_ICON_SETTINGS); + toDelete.push_back(mwradio); + + ZapitChannelList* channels = &(g_bouquetManager->Bouquets[i]->tvChannels); + for(int j = 0; j < (int) channels->size(); j++) { + char cChannelId[3+16+1+1]; + sprintf(cChannelId, "SC:" PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS ",", (*channels)[j]->channel_id); + mwtv->addItem(new CMenuForwarderNonLocalized((*channels)[j]->getName().c_str(), true, NULL, this, (std::string(cChannelId) + (*channels)[j]->getName()).c_str())); + } + if (!channels->empty()) + mctv.addItem(new CMenuForwarderNonLocalized(g_bouquetManager->Bouquets[i]->Name.c_str(), true, NULL, mwtv)); + + + channels = &(g_bouquetManager->Bouquets[i]->radioChannels); + for(int j = 0; j < (int) channels->size(); j++) { + char cChannelId[3+16+1+1]; + sprintf(cChannelId, "SC:" PRINTF_CHANNEL_ID_TYPE_NO_LEADING_ZEROS ",", (*channels)[j]->channel_id); + mwradio->addItem(new CMenuForwarderNonLocalized((*channels)[j]->getName().c_str(), true, NULL, this, (std::string(cChannelId) + (*channels)[j]->getName()).c_str())); + } + if (!channels->empty()) + mcradio.addItem(new CMenuForwarderNonLocalized(g_bouquetManager->Bouquets[i]->Name.c_str(), true, NULL, mwtv)); + } + } + + CMenuWidget mm(LOCALE_TIMERLIST_MODESELECT, NEUTRINO_ICON_SETTINGS); + mm.addItem(new CMenuForwarder(LOCALE_TIMERLIST_MODETV, true, NULL, &mctv)); + mm.addItem(new CMenuForwarder(LOCALE_TIMERLIST_MODERADIO, true, NULL, &mcradio)); + strcpy(timerNew_channel_name,"---"); + CMenuForwarder* m6 = new CMenuForwarder(LOCALE_TIMERLIST_CHANNEL, true, timerNew_channel_name, &mm); + + CMountChooser recDirs(LOCALE_TIMERLIST_RECORDING_DIR,NEUTRINO_ICON_SETTINGS,NULL,timerNew.recordingDir,g_settings.network_nfs_recordingdir); + if (!recDirs.hasItem()) + { + printf("[CTimerList] warning: no network devices available\n"); + } + CMenuForwarder* m7 = new CMenuForwarder(LOCALE_TIMERLIST_RECORDING_DIR, recDirs.hasItem(),timerNew.recordingDir, &recDirs); + + CMenuOptionChooser* m8 = new CMenuOptionChooser(LOCALE_TIMERLIST_STANDBY, &timerNew_standby_on, TIMERLIST_STANDBY_OPTIONS, TIMERLIST_STANDBY_OPTION_COUNT, false); + + CStringInputSMS timerSettings_msg(LOCALE_TIMERLIST_MESSAGE, timerNew.message, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789-.,:!?/ "); + CMenuForwarder *m9 = new CMenuForwarder(LOCALE_TIMERLIST_MESSAGE, false, timerNew.message, &timerSettings_msg ); + + strcpy(timerNew.pluginName,"---"); + CPluginChooser plugin_chooser(LOCALE_TIMERLIST_PLUGIN, CPlugins::P_TYPE_SCRIPT | CPlugins::P_TYPE_TOOL, timerNew.pluginName); + CMenuForwarder *m10 = new CMenuForwarder(LOCALE_TIMERLIST_PLUGIN, false, timerNew.pluginName, &plugin_chooser); + + + CTimerListNewNotifier notifier2((int *)&timerNew.eventType, + &timerNew.stopTime,m2,m6,m8,m9,m10,m7, + timerSettings_stopTime.getValue()); + CMenuOptionChooser* m0 = new CMenuOptionChooser(LOCALE_TIMERLIST_TYPE, (int *)&timerNew.eventType, TIMERLIST_TYPE_OPTIONS, TIMERLIST_TYPE_OPTION_COUNT, true, ¬ifier2); + + timerSettings.addItem( m0); + timerSettings.addItem( m1); + timerSettings.addItem( m2); + timerSettings.addItem(GenericMenuSeparatorLine); + timerSettings.addItem( m3); + timerSettings.addItem( m4); + timerSettings.addItem( m5); + timerSettings.addItem(GenericMenuSeparatorLine); + timerSettings.addItem( m6); + timerSettings.addItem( m7); + timerSettings.addItem( m8); + timerSettings.addItem( m9); + timerSettings.addItem( m10); + + int ret=timerSettings.exec(this,""); + + // delete dynamic created objects + for(unsigned int count=0;countgetText(LOCALE_TIMERLIST_OVERLAPPING_TIMER); + timerbuf += "\n"; + for (CTimerd::TimerList::iterator it = overlappingTimers.begin(); + it != overlappingTimers.end();it++) + { + timerbuf += CTimerList::convertTimerType2String(it->eventType); + timerbuf += " ("; + timerbuf += CTimerList::convertChannelId2String(it->channel_id); // UTF-8 + if(it->epgID != 0) + { + CEPGData epgdata; + //if (g_Sectionsd->getEPGid(it->epgID, it->epg_starttime, &epgdata)) + if (sectionsd_getEPGid(it->epgID, it->epg_starttime, &epgdata)) + { + timerbuf += ":"; + timerbuf += epgdata.title; + } + else if(strlen(it->epgTitle)!=0) + { + timerbuf += ":"; + timerbuf += it->epgTitle; + } + } + timerbuf += ")"; + + timerbuf += ":\n"; + char at[25] = {0}; + struct tm *annTime = localtime(&(it->announceTime)); + strftime(at,20,"%d.%m. %H:%M",annTime); + timerbuf += at; + timerbuf += " - "; + + char st[25] = {0}; + struct tm *sTime = localtime(&(it->stopTime)); + strftime(st,20,"%d.%m. %H:%M",sTime); + timerbuf += st; + timerbuf += "\n"; + //printf("%d\t%d\t%d\n",it->announceTime,it->alarmTime,it->stopTime); + } + //printf("message:\n%s\n",timerbuf.c_str()); + // todo: localize message + //g_Locale->getText(TIMERLIST_OVERLAPPING_MESSAGE); + + return (ShowMsgUTF(LOCALE_MESSAGEBOX_INFO,timerbuf,CMessageBox::mbrNo,CMessageBox::mbNo|CMessageBox::mbYes) == CMessageBox::mbrYes); +} diff --git a/src/gui/timerlist.h b/src/gui/timerlist.h new file mode 100644 index 000000000..037e043c0 --- /dev/null +++ b/src/gui/timerlist.h @@ -0,0 +1,98 @@ +/* + Neutrino-GUI - DBoxII-Project + + Timerliste by Zwen + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __timerlist__ +#define __timerlist__ + +#include + +#include + +#include + +#include + + +class CTimerList : public CMenuTarget +{ + private: + CFrameBuffer *frameBuffer; + unsigned int selected; + unsigned int liststart; + unsigned int listmaxshow; + int fheight; // Fonthoehe Timerlist-Inhalt + int theight; // Fonthoehe Timerlist-Titel + int buttonHeight; + bool visible; + + CTimerdClient *Timer; + CTimerd::TimerList timerlist; // List of timers + CTimerd::responseGetTimer timerNew; + int timerNew_standby_on; + char timerNew_channel_name[30]; + char m_weekdaysStr[8]; + + int timer_apids_dflt; + int timer_apids_std; + int timer_apids_ac3; + int timer_apids_alt; + + int width; + int height; + int x; + int y; + + int skipEventID; + + void paintItem(int pos); + void paint(); + void paintHead(); + void paintFoot(); + void hide(); + int modifyTimer(); + int newTimer(); + + public: + CTimerList(); + ~CTimerList(); + void updateEvents(void); + int show(); + int exec(CMenuTarget* parent, const std::string & actionKey); + static const char * convertTimerType2String(const CTimerd::CTimerEventTypes type); // UTF-8 + static std::string convertTimerRepeat2String(const CTimerd::CTimerEventRepeat rep); // UTF-8 + static std::string convertChannelId2String(const t_channel_id id); // UTF-8 +}; + +bool askUserOnTimerConflict(time_t announceTime, time_t stopTime); + + +#endif diff --git a/src/gui/update.cpp b/src/gui/update.cpp new file mode 100644 index 000000000..aab010e91 --- /dev/null +++ b/src/gui/update.cpp @@ -0,0 +1,647 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#define SQUASHFS + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +extern int allow_flash; + +#define gTmpPath "/var/update/" +#define gUserAgent "neutrino/softupdater 1.0" + +#define LIST_OF_UPDATES_LOCAL_FILENAME "coolstream.list" +#define UPDATE_LOCAL_FILENAME "update.img" +#define RELEASE_CYCLE "1.0" +#define FILEBROWSER_UPDATE_FILTER "img" + +#define MTD_OF_WHOLE_IMAGE 0 +#define MTD_DEVICE_OF_UPDATE_PART "/dev/mtd2" + +CFlashUpdate::CFlashUpdate() + :CProgressWindow() +{ + setTitle(LOCALE_FLASHUPDATE_HEAD); +} + + + +class CUpdateMenuTarget : public CMenuTarget +{ + int myID; + int * myselectedID; + +public: + CUpdateMenuTarget(const int id, int * const selectedID) + { + myID = id; + myselectedID = selectedID; + } + + virtual int exec(CMenuTarget *, const std::string &) + { + *myselectedID = myID; + return menu_return::RETURN_EXIT_ALL; + } +}; + + +class CNonLocalizedMenuSeparator : public CMenuSeparator +{ + const char * the_text; + +public: + CNonLocalizedMenuSeparator(const char * text, const neutrino_locale_t Text) : CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, Text) + { + the_text = text; + } + + virtual const char * getString(void) + { + return the_text; + } +}; +//#define DEBUG +bool CFlashUpdate::selectHttpImage(void) +{ + CHTTPTool httpTool; + std::string url; + std::string name; + std::string version; + std::string md5; + std::vector updates_lists, urls, names, versions, descriptions, md5s; + char fileTypes[128]; + int selected = -1; + + httpTool.setStatusViewer(this); + showStatusMessageUTF(g_Locale->getText(LOCALE_FLASHUPDATE_GETINFOFILE)); // UTF-8 + + CMenuWidget SelectionWidget(LOCALE_FLASHUPDATE_SELECTIMAGE, "softupdate.raw", 600); + SelectionWidget.addItem(GenericMenuSeparator); + SelectionWidget.addItem(GenericMenuBack); + + std::ifstream urlFile(g_settings.softupdate_url_file); +#ifdef DEBUG +printf("[update] file %s\n", g_settings.softupdate_url_file); +#endif + + unsigned int i = 0; + while (urlFile >> url) + { + std::string::size_type startpos, endpos; +#ifdef DEBUG +printf("[update] url %s\n", url.c_str()); +#endif + + /* extract domain name */ + startpos = url.find("//"); + if (startpos == std::string::npos) + { + startpos = 0; + endpos = std::string::npos; + updates_lists.push_back(url.substr(startpos, endpos - startpos)); + } + else + { + //startpos += 2; + //endpos = url.find('/', startpos); + startpos = url.find('/', startpos+2)+1; + endpos = std::string::npos; + updates_lists.push_back(url.substr(startpos, endpos - startpos)); + } + //updates_lists.push_back(url.substr(startpos, endpos - startpos)); + + SelectionWidget.addItem(new CNonLocalizedMenuSeparator(updates_lists.rbegin()->c_str(), LOCALE_FLASHUPDATE_SELECTIMAGE)); + if (httpTool.downloadFile(url, gTmpPath LIST_OF_UPDATES_LOCAL_FILENAME, 20)) + { + std::ifstream in(gTmpPath LIST_OF_UPDATES_LOCAL_FILENAME); + bool enabled; + while (in >> url >> version >> md5 >> std::ws) + { + urls.push_back(url); + versions.push_back(version); + std::getline(in, name); + names.push_back(name); + //std::getline(in, md5); + md5s.push_back(md5); + enabled = true; +#ifdef DEBUG +printf("[update] url %s version %s md5 %s name %s\n", url.c_str(), version.c_str(), md5.c_str(), name.c_str()); +#endif + + CFlashVersionInfo versionInfo(versions[i]); + + if(!allow_flash && (versionInfo.snapshot < '3')) + enabled = false; + fileTypes[i] = versionInfo.snapshot; + std::string description = versionInfo.getType(); + description += ' '; + description += versionInfo.getDate(); + description += ' '; + description += versionInfo.getTime(); + + descriptions.push_back(description); /* workaround since CMenuForwarder does not store the Option String itself */ + + SelectionWidget.addItem(new CMenuForwarderNonLocalized(names[i].c_str(), enabled, descriptions[i].c_str(), new CUpdateMenuTarget(i, &selected))); + i++; + } + } + } + + hide(); + + if (urls.empty()) + { + ShowHintUTF(LOCALE_MESSAGEBOX_ERROR, g_Locale->getText(LOCALE_FLASHUPDATE_GETINFOFILEERROR)); // UTF-8 + return false; + } + + SelectionWidget.exec(NULL, ""); + + if (selected == -1) + return false; + + filename = urls[selected]; + newVersion = versions[selected]; + file_md5 = md5s[selected]; + fileType = fileTypes[selected]; +#ifdef DEBUG +printf("[update] filename %s type %c newVersion %s md5 %s\n", filename.c_str(), fileType, newVersion.c_str(), file_md5.c_str()); +#endif + + return true; +} + +bool CFlashUpdate::getUpdateImage(const std::string & version) +{ + CHTTPTool httpTool; + char * fname, dest_name[100]; + httpTool.setStatusViewer(this); + + fname = rindex(filename.c_str(), '/'); + if(fname != NULL) fname++; + else return false; + + sprintf(dest_name, "%s/%s", g_settings.update_dir, fname); + showStatusMessageUTF(std::string(g_Locale->getText(LOCALE_FLASHUPDATE_GETUPDATEFILE)) + ' ' + version); // UTF-8 + + printf("get update (url): %s - %s\n", filename.c_str(), dest_name); + return httpTool.downloadFile(filename, dest_name, 40 ); + //return httpTool.downloadFile(filename, gTmpPath UPDATE_LOCAL_FILENAME, 40 ); +} + +bool CFlashUpdate::checkVersion4Update() +{ + char msg[400]; + CFlashVersionInfo * versionInfo; + neutrino_locale_t msg_body; +#ifdef DEBUG +printf("[update] mode is %d\n", g_settings.softupdate_mode); +#endif + if(g_settings.softupdate_mode==1) //internet-update + { + if(!selectHttpImage()) + return false; + + showLocalStatus(100); + showGlobalStatus(20); + showStatusMessageUTF(g_Locale->getText(LOCALE_FLASHUPDATE_VERSIONCHECK)); // UTF-8 + + printf("internet version: %s\n", newVersion.c_str()); + + showLocalStatus(100); + showGlobalStatus(20); + hide(); + + msg_body = LOCALE_FLASHUPDATE_MSGBOX; +#ifdef SQUASHFS + versionInfo = new CFlashVersionInfo(newVersion);//Memory leak: versionInfo + sprintf(msg, g_Locale->getText(msg_body), versionInfo->getDate(), versionInfo->getTime(), versionInfo->getReleaseCycle(), versionInfo->getType()); + + if(fileType < '3') + { + if ((strncmp(RELEASE_CYCLE, versionInfo->getReleaseCycle(), 2) != 0) && + (ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_FLASHUPDATE_WRONGBASE), CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbNo, "softupdate.raw") != CMessageBox::mbrYes)) + { + delete versionInfo; + //ShowHintUTF(LOCALE_MESSAGEBOX_ERROR, g_Locale->getText(LOCALE_FLASHUPDATE_WRONGBASE)); // UTF-8 + return false; + } + + if ((strcmp("Release", versionInfo->getType()) != 0) && + //(ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_FLASHUPDATE_EXPERIMENTALIMAGE), CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbNo, "softupdate.raw") != CMessageBox::mbrYes)) // UTF-8 + (ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_FLASHUPDATE_EXPERIMENTALIMAGE, CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbNo, "softupdate.raw") != CMessageBox::mbrYes)) + { + delete versionInfo; + return false; + } + } + + delete versionInfo; +#endif + } + else + { + CFileBrowser UpdatesBrowser; + + CFileFilter UpdatesFilter; + if(allow_flash) UpdatesFilter.addFilter(FILEBROWSER_UPDATE_FILTER); + UpdatesFilter.addFilter("bin"); + UpdatesFilter.addFilter("txt"); + + UpdatesBrowser.Filter = &UpdatesFilter; + + CFile * CFileSelected = NULL; + if (!(UpdatesBrowser.exec(g_settings.update_dir))) + return false; + + CFileSelected = UpdatesBrowser.getSelectedFile(); + + if (CFileSelected == NULL) + return false; + + filename = CFileSelected->Name; + + FILE* fd = fopen(filename.c_str(), "r"); + if(fd) + fclose(fd); + else { + hide(); + printf("flash-file not found: %s\n", filename.c_str()); + ShowHintUTF(LOCALE_MESSAGEBOX_ERROR, g_Locale->getText(LOCALE_FLASHUPDATE_CANTOPENFILE)); // UTF-8 + return false; + } + hide(); + char * ptr = rindex(filename.c_str(), '.'); + if(ptr) { + ptr++; + if(!strcmp(ptr, "bin")) fileType = 'A'; + else if(!strcmp(ptr, "txt")) fileType = 'T'; + else if(!allow_flash) return false; + else fileType = 0; +#ifdef DEBUG + printf("[update] manual file type: %s %c\n", ptr, fileType); +#endif + } + + strcpy(msg, g_Locale->getText(LOCALE_FLASHUPDATE_SQUASHFS_NOVERSION)); + msg_body = LOCALE_FLASHUPDATE_MSGBOX_MANUAL; + } + return (ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, msg, CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbNo, "softupdate.raw") == CMessageBox::mbrYes); // UTF-8 +} + +int CFlashUpdate::exec(CMenuTarget* parent, const std::string &) +{ + if(parent) + parent->hide(); + + paint(); + + if(!checkVersion4Update()) { + hide(); + return menu_return::RETURN_REPAINT; + } + +#ifdef VFD_UPDATE + CVFD::getInstance()->showProgressBar2(0,"checking",0,"Update Neutrino"); + CVFD::getInstance()->setMode(CLCD::MODE_PROGRESSBAR2); +#endif // VFD_UPDATE + + showGlobalStatus(19); + paint(); + showGlobalStatus(20); + + if(g_settings.softupdate_mode==1) //internet-update + { + char * fname = rindex(filename.c_str(), '/') +1; + char fullname[255]; + + if(!getUpdateImage(newVersion)) { + hide(); + ShowHintUTF(LOCALE_MESSAGEBOX_ERROR, g_Locale->getText(LOCALE_FLASHUPDATE_GETUPDATEFILEERROR)); // UTF-8 + return menu_return::RETURN_REPAINT; + } + sprintf(fullname, "%s/%s", g_settings.update_dir, fname); + filename = std::string(fullname); + } + + showGlobalStatus(40); + + CFlashTool ft; + ft.setMTDDevice(MTD_DEVICE_OF_UPDATE_PART); + ft.setStatusViewer(this); + + showStatusMessageUTF(g_Locale->getText(LOCALE_FLASHUPDATE_MD5CHECK)); // UTF-8 + if((g_settings.softupdate_mode==1) && !ft.check_md5(filename, file_md5)) { + hide(); + ShowHintUTF(LOCALE_MESSAGEBOX_ERROR, g_Locale->getText(LOCALE_FLASHUPDATE_MD5SUMERROR)); // UTF-8 + return menu_return::RETURN_REPAINT; + } + if(g_settings.softupdate_mode==1) { //internet-update + if ( ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, (fileType < '3') ? "Flash downloaded image ?" : "Install downloaded pack ?", CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbNo, "softupdate.raw") != CMessageBox::mbrYes) // UTF-8 + { + hide(); + return menu_return::RETURN_REPAINT; + } + } + + showGlobalStatus(60); + +#ifdef DEBUG + printf("[update] flash/install filename %s type %c\n", filename.c_str(), fileType); +#endif + if(fileType < '3') { + CNeutrinoApp::getInstance()->exec(NULL, "savesettings"); + sleep(2); + //flash it... +#ifdef DEBUG1 + if(1) +#else + if(!ft.program(filename, 80, 100)) +#endif + { + hide(); + ShowHintUTF(LOCALE_MESSAGEBOX_ERROR, ft.getErrorMessage().c_str()); // UTF-8 + return menu_return::RETURN_REPAINT; + } + + //status anzeigen + showGlobalStatus(100); + showStatusMessageUTF(g_Locale->getText(LOCALE_FLASHUPDATE_READY)); // UTF-8 + + hide(); + + // Unmount all NFS & CIFS volumes + nfs_mounted_once = false; /* needed by update.cpp to prevent removal of modules after flashing a new cramfs, since rmmod (busybox) might no longer be available */ + CFSMounter::umount(); + + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_FLASHUPDATE_FLASHREADYREBOOT)); // UTF-8 + //system("/etc/init.d/rcK"); + ft.reboot(); + sleep(20000); + } + else if(fileType == 'T') // display file contents + { + FILE* fd = fopen(filename.c_str(), "r"); + if(fd) { + char * buffer; + off_t filesize = lseek(fileno(fd), 0, SEEK_END); + lseek(fileno(fd), 0, SEEK_SET); + buffer =(char *) malloc(filesize+1); + fread(buffer, filesize, 1, fd); + fclose(fd); + buffer[filesize] = 0; + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, buffer, CMessageBox::mbrBack, CMessageBox::mbBack); // UTF-8 + free(buffer); + } + } + else // not image, install + { + char cmd[100]; + sprintf(cmd, "install.sh %s %s", g_settings.update_dir, filename.c_str()); +#ifdef DEBUG1 + printf("[update] calling %s\n", cmd); +#else + printf("[update] calling %s\n", cmd); + system(cmd); +#endif + showGlobalStatus(100); + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_FLASHUPDATE_READY)); // UTF-8 + } + hide(); + return menu_return::RETURN_REPAINT; +} + + +//-------------------------------------------------------------------------------------------------------------- + + +CFlashExpert::CFlashExpert() + :CProgressWindow() +{ + selectedMTD = -1; +} + +void CFlashExpert::readmtd(int readmtd) +{ + char tmp[10]; + sprintf(tmp, "%d", readmtd); + std::string filename = "/tmp/mtd"; + filename += tmp; + filename += ".img"; // US-ASCII (subset of UTF-8 and ISO8859-1) + + if (readmtd == -1) { + filename = "/tmp/flashimage.img"; // US-ASCII (subset of UTF-8 and ISO8859-1) + readmtd = MTD_OF_WHOLE_IMAGE; + } + setTitle(LOCALE_FLASHUPDATE_TITLEREADFLASH); + paint(); + showGlobalStatus(0); + showStatusMessageUTF((std::string(g_Locale->getText(LOCALE_FLASHUPDATE_ACTIONREADFLASH)) + " (" + CMTDInfo::getInstance()->getMTDName(readmtd) + ')')); // UTF-8 + CFlashTool ft; + ft.setStatusViewer( this ); + ft.setMTDDevice(CMTDInfo::getInstance()->getMTDFileName(readmtd)); + + if(!ft.readFromMTD(filename, 100)) { + showStatusMessageUTF(ft.getErrorMessage()); // UTF-8 + sleep(10); + } else { + showGlobalStatus(100); + showStatusMessageUTF(g_Locale->getText(LOCALE_FLASHUPDATE_READY)); // UTF-8 + char message[500]; + sprintf(message, g_Locale->getText(LOCALE_FLASHUPDATE_SAVESUCCESS), filename.c_str()); + sleep(1); + hide(); + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, message); + } +} + +void CFlashExpert::writemtd(const std::string & filename, int mtdNumber) +{ + char message[500]; + + sprintf(message, + g_Locale->getText(LOCALE_FLASHUPDATE_REALLYFLASHMTD), + FILESYSTEM_ENCODING_TO_UTF8_STRING(filename).c_str(), + CMTDInfo::getInstance()->getMTDName(mtdNumber).c_str()); + + if (ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, message, CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo, "softupdate.raw") != CMessageBox::mbrYes) // UTF-8 + return; +#ifdef VFD_UPDATE + CVFD::getInstance()->showProgressBar2(0,"checking",0,"Update Neutrino"); + CVFD::getInstance()->setMode(CLCD::MODE_PROGRESSBAR2); +#endif // VFD_UPDATE + + setTitle(LOCALE_FLASHUPDATE_TITLEWRITEFLASH); + paint(); + showGlobalStatus(0); + CFlashTool ft; + ft.setStatusViewer( this ); + ft.setMTDDevice( CMTDInfo::getInstance()->getMTDFileName(mtdNumber) ); + if(!ft.program( "/tmp/" + filename, 50, 100)) { + showStatusMessageUTF(ft.getErrorMessage()); // UTF-8 + sleep(10); + } else { + showGlobalStatus(100); + showStatusMessageUTF(g_Locale->getText(LOCALE_FLASHUPDATE_READY)); // UTF-8 + sleep(1); + hide(); + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_FLASHUPDATE_FLASHREADYREBOOT)); // UTF-8 + ft.reboot(); + } +} + +void CFlashExpert::showMTDSelector(const std::string & actionkey) +{ + //mtd-selector erzeugen + CMenuWidget* mtdselector = new CMenuWidget(LOCALE_FLASHUPDATE_MTDSELECTOR, "softupdate.raw"); + mtdselector->addItem(GenericMenuSeparator); + mtdselector->addItem(new CMenuForwarder(LOCALE_MESSAGEBOX_CANCEL)); + mtdselector->addItem(GenericMenuSeparatorLine); + CMTDInfo* mtdInfo =CMTDInfo::getInstance(); + for(int x=0;xgetMTDCount();x++) { + char sActionKey[20]; + sprintf(sActionKey, "%s%d", actionkey.c_str(), x); + mtdselector->addItem(new CMenuForwarderNonLocalized(mtdInfo->getMTDName(x).c_str(), true, NULL, this, sActionKey)); + } + mtdselector->exec(NULL,""); + delete mtdselector; +} + +void CFlashExpert::showFileSelector(const std::string & actionkey) +{ + CMenuWidget* fileselector = new CMenuWidget(LOCALE_FLASHUPDATE_FILESELECTOR, "softupdate.raw"); + fileselector->addItem(GenericMenuSeparator); + fileselector->addItem(new CMenuForwarder(LOCALE_MESSAGEBOX_CANCEL)); + fileselector->addItem(GenericMenuSeparatorLine); + struct dirent **namelist; + int n = scandir("/tmp", &namelist, 0, alphasort); + if (n < 0) + { + perror("no flashimages available"); + //should be available... + } + else + { + for(int count=0;countd_name; + int pos = filen.find(".img"); + if(pos!=-1) + { + fileselector->addItem(new CMenuForwarderNonLocalized(filen.c_str(), true, NULL, this, (actionkey + filen).c_str())); +#warning TODO: make sure filen is UTF-8 encoded + } + free(namelist[count]); + } + free(namelist); + } + fileselector->exec(NULL,""); + delete fileselector; +} + +int CFlashExpert::exec(CMenuTarget* parent, const std::string & actionKey) +{ + if(parent) + parent->hide(); + + if(actionKey=="readflash") { + readmtd(-1); + } + else if(actionKey=="writeflash") { + showFileSelector(""); + } + else if(actionKey=="readflashmtd") { + showMTDSelector("readmtd"); + } + else if(actionKey=="writeflashmtd") { + showMTDSelector("writemtd"); + } + else { + int iReadmtd = -1; + int iWritemtd = -1; + sscanf(actionKey.c_str(), "readmtd%d", &iReadmtd); + sscanf(actionKey.c_str(), "writemtd%d", &iWritemtd); + if(iReadmtd!=-1) { + readmtd(iReadmtd); + } + else if(iWritemtd!=-1) { + printf("mtd-write\n\n"); + selectedMTD = iWritemtd; + showFileSelector(""); + } else { + if(selectedMTD==-1) { + writemtd(actionKey, MTD_OF_WHOLE_IMAGE); + } else { + writemtd(actionKey, selectedMTD); + selectedMTD=-1; + } + } + hide(); + return menu_return::RETURN_EXIT_ALL; + } + + hide(); + return menu_return::RETURN_REPAINT; +} diff --git a/src/gui/update.h b/src/gui/update.h new file mode 100644 index 000000000..9728b1cbb --- /dev/null +++ b/src/gui/update.h @@ -0,0 +1,82 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __update__ +#define __update__ + +#include +#include +#include + +#include + +#include + +class CFlashUpdate : public CProgressWindow +{ + private: + std::string filename; + std::string file_md5; + char fileType; + + std::string installedVersion; + std::string newVersion; + + bool selectHttpImage(void); + bool getUpdateImage(const std::string & version); + bool checkVersion4Update(); + + public: + CFlashUpdate(); + int exec( CMenuTarget* parent, const std::string & actionKey ); + +}; + +class CFlashExpert : public CProgressWindow +{ + private: + int selectedMTD; + + void showMTDSelector(const std::string & actionkey); + void showFileSelector(const std::string & actionkey); + + void readmtd(int readmtd); + void writemtd(const std::string & filename, int mtdNumber); + + public: + CFlashExpert(); + int exec(CMenuTarget* parent, const std::string & actionKey); + +}; + + +#endif diff --git a/src/gui/upnpbrowser.cpp b/src/gui/upnpbrowser.cpp new file mode 100644 index 000000000..d0ac791e7 --- /dev/null +++ b/src/gui/upnpbrowser.cpp @@ -0,0 +1,1382 @@ +/* + Neutrino-GUI - DBoxII-Project + + UPnP Browser (c) 2007 by Jochen Friedrich + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +extern cVideo * videoDecoder; + +#ifdef ConnectLineBox_Width +#undef ConnectLineBox_Width +#endif +#define ConnectLineBox_Width 15 + +const struct button_label RescanButton = {NEUTRINO_ICON_BUTTON_BLUE , LOCALE_UPNPBROWSER_RESCAN}; +const struct button_label StopButton = {NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_STOP}; +const struct button_label PUpButton = {NEUTRINO_ICON_BUTTON_RED , LOCALE_FILEBROWSER_NEXTPAGE}; +const struct button_label PDownButton = {NEUTRINO_ICON_BUTTON_GREEN , LOCALE_FILEBROWSER_PREVPAGE}; + +//------------------------------------------------------------------------ + +CUpnpBrowserGui::CUpnpBrowserGui() +{ + m_socket = new CUPnPSocket(); + m_frameBuffer = CFrameBuffer::getInstance(); + m_playing_entry_is_shown = false; +} + +//------------------------------------------------------------------------ + +CUpnpBrowserGui::~CUpnpBrowserGui() +{ + delete m_socket; +} + +//------------------------------------------------------------------------ + +int CUpnpBrowserGui::exec(CMenuTarget* parent, const std::string & /*actionKey*/) +{ + + CAudioPlayer::getInstance()->init(); + + if(parent) + { + parent->hide(); + } + + g_Zapit->stopPlayBack(); + + videoDecoder->ShowPicture(DATADIR "/neutrino/icons/mp3.jpg"); + + // tell neutrino we're in audio mode + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , NeutrinoMessages::mode_audio ); + // remember last mode +#if 0 + CZapitClient::responseGetLastChannel firstchannel; + g_Zapit->getLastChannel(firstchannel.channelNumber, firstchannel.mode); + if ((firstchannel.mode == 'r') ? + (CNeutrinoApp::getInstance()->zapto_radio_on_init_done) : + (CNeutrinoApp::getInstance()->zapto_tv_on_init_done)) + m_LastMode=(CNeutrinoApp::getInstance()->getLastMode() | NeutrinoMessages::norezap); + else + m_LastMode=(CNeutrinoApp::getInstance()->getLastMode()); +#endif + m_LastMode=(CNeutrinoApp::getInstance()->getLastMode()); + + m_width=(g_settings.screen_EndX - g_settings.screen_StartX) - ConnectLineBox_Width; + m_height = (g_settings.screen_EndY - g_settings.screen_StartY); + + m_sheight = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight(); + m_buttonHeight = std::min(25, m_sheight); + m_theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + m_mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + m_fheight = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getHeight(); + m_title_height = m_mheight*2 + 20 + m_sheight + 4; + m_info_height = m_mheight*2; + m_listmaxshow = (m_height - m_info_height - m_title_height - m_theight - 2*m_buttonHeight) / (m_fheight); + m_height = m_theight + m_info_height + m_title_height + 2*m_buttonHeight + m_listmaxshow * m_fheight; // recalc height + + m_x = (((g_settings.screen_EndX - g_settings.screen_StartX) - (m_width + ConnectLineBox_Width)) / 2) + + g_settings.screen_StartX + ConnectLineBox_Width; + m_y = (((g_settings.screen_EndY- g_settings.screen_StartY) - m_height)/ 2) + g_settings.screen_StartY; + + // Stop sectionsd + g_Sectionsd->setPauseScanning(true); + + m_indexdevice=0; + m_selecteddevice=0; + + selectDevice(); + + if(CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) + CAudioPlayer::getInstance()->stop(); + + //g_Zapit->setStandby(false); + + // Start Sectionsd + g_Sectionsd->setPauseScanning(false); + videoDecoder->StopPicture(); + + CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , m_LastMode ); + g_RCInput->postMsg( NeutrinoMessages::SHOW_INFOBAR, 0 ); + + return menu_return::RETURN_EXIT_ALL; +} + +//------------------------------------------------------------------------ + +void CUpnpBrowserGui::splitProtocol(std::string &protocol, std::string &prot, std::string &network, std::string &mime, std::string &additional) +{ + std::string::size_type pos; + std::string::size_type startpos = 0; + + pos = protocol.find(":", startpos); + if (pos != std::string::npos) + { + prot = protocol.substr(startpos, pos-startpos); + startpos = pos + 1; + + pos = protocol.find(":", startpos); + if (pos != std::string::npos) + { + network = protocol.substr(startpos, pos-startpos); + startpos = pos + 1; + + pos = protocol.find(":", startpos); + if (pos != std::string::npos) + { + mime = protocol.substr(startpos, pos-startpos); + startpos = pos + 1; + + pos = protocol.find(":", startpos); + if (pos != std::string::npos) + { + additional = protocol.substr(startpos, pos-startpos); + } + } + } + } +//printf("%s -> %s - %s - %s - %s\n", protocol.c_str(), prot.c_str(), network.c_str(), mime.c_str(), additional.c_str()); +} + +//------------------------------------------------------------------------ + +std::vector *CUpnpBrowserGui::decodeResult(std::string result) +{ + XMLTreeParser *parser; + XMLTreeNode *root, *node, *snode; + std::vector *entries; + + parser = new XMLTreeParser("UTF-8"); + parser->Parse(result.c_str(), result.size(), 1); + root=parser->RootNode(); + if (!root){ + delete parser; + return NULL; + } + entries = new std::vector; + + for (node=root->GetChild(); node; node=node->GetNext()) + { + bool isdir; + std::string title, artist = "", album = "", id, children; + char *type, *p; + + if (!strcmp(node->GetType(), "container")) + { + std::vector resources; + isdir=true; + for (snode=node->GetChild(); snode; snode=snode->GetNext()) + { + type=snode->GetType(); + p = strchr(type,':'); + if (p) + type=p+1; + if (!strcmp(type,"title")) + { + p=snode->GetData(); + if (!p) + p=(char *) ""; + title=std::string(p); + } + } + p = node->GetAttributeValue((char *) "id"); + if (!p) + p=(char *) ""; + id=std::string(p); + + p = node->GetAttributeValue((char *) "childCount"); + if (!p) + p=(char *) ""; + children=std::string(p); + + UPnPEntry entry={id, isdir, title, artist, album, children, resources, -1}; + entries->push_back(entry); + } + if (!strcmp(node->GetType(), "item")) + { + std::vector resources; + int preferred = -1; + std::string protocol, prot, network, mime, additional; + isdir=false; + for (snode=node->GetChild(); snode; snode=snode->GetNext()) + { + std::string duration, url, size; + unsigned int i; + type=snode->GetType(); + p = strchr(type,':'); + if (p) + type=p+1; + + if (!strcmp(type,"title")) + { + p=snode->GetData(); + if (!p) + p=(char *) ""; + title=std::string(p); + } + else if (!strcmp(type,"artist")) + { + p=snode->GetData(); + if (!p) + p=(char *) ""; + artist=std::string(p); + } + else if (!strcmp(type,"album")) + { + p=snode->GetData(); + if (!p) + p=(char *) ""; + album=std::string(p); + } + else if (!strcmp(type,"res")) + { + p = snode->GetData(); + if (!p) + p=(char *) ""; + url=std::string(p); + p = snode->GetAttributeValue((char *) "size"); + if (!p) + p=(char *) "0"; + size=std::string(p); + p = snode->GetAttributeValue((char *) "duration"); + if (!p) + p=(char *) ""; + duration=std::string(p); + p = snode->GetAttributeValue((char *) "protocolInfo"); + if (!p) + p=(char *) ""; + protocol=std::string(p); + UPnPResource resource = {url, protocol, size, duration}; + resources.push_back(resource); + } + int pref=0; + preferred=-1; + for (i=0; iGetAttributeValue((char *) "id"); + if (!p) + p=(char *) ""; + id=std::string(p); + + p = node->GetAttributeValue((char *) "childCount"); + if (!p) + p=(char *) ""; + children=std::string(p); + + UPnPEntry entry={id, isdir, title, artist, album, children, resources, preferred}; + + entries->push_back(entry); + } + } + delete parser; + return entries; +} + +//------------------------------------------------------------------------ + +void CUpnpBrowserGui::selectDevice() +{ + bool loop = true; + bool changed = true; + neutrino_msg_t msg; + neutrino_msg_data_t data; + + CHintBox *scanBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_UPNPBROWSER_SCANNING)); // UTF-8 + scanBox->paint(); +#if 0 + try { + m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); + } + catch (std::runtime_error error) + { + delete scanBox; + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + return; + } +#endif + m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); + scanBox->hide(); + + if (!m_devices.size()) + { + ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_UPNPBROWSER_NOSERVERS, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + delete scanBox; + return; + } + + while (loop) + { + if (changed) + { + paintDevice(); + changed=false; + } + + g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display + neutrino_msg_t msg_repeatok = msg & ~CRCInput::RC_Repeat; + + if( msg == CRCInput::RC_timeout) + { + // nothing + } + + else if( msg == CRCInput::RC_home) + { + loop=false; + } + + else if (msg_repeatok == CRCInput::RC_up && m_selecteddevice > 0) + { + m_selecteddevice--; + if (m_selecteddevice < m_indexdevice) + m_indexdevice-=m_listmaxshow; + changed=true; + } + + else if (msg_repeatok == CRCInput::RC_down && m_selecteddevice + 1 < m_devices.size()) + { + m_selecteddevice++; + if (m_selecteddevice + 1 > m_indexdevice + m_listmaxshow) + m_indexdevice+=m_listmaxshow; + changed=true; + } + + else if( msg == CRCInput::RC_right || msg == CRCInput::RC_ok) + { + m_folderplay = false; + selectItem("0"); + changed=true; + } + + else if( msg == CRCInput::RC_blue) + { + scanBox->paint(); +#if 0 + try { + m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); + } + catch (std::runtime_error error) + { + delete scanBox; + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + return; + } +#endif + m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); + scanBox->hide(); + if (!m_devices.size()) + { + ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_UPNPBROWSER_NOSERVERS, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + delete scanBox; + return; + } + changed=true; + } + + else if(msg == NeutrinoMessages::RECORD_START || + msg == NeutrinoMessages::ZAPTO || + msg == NeutrinoMessages::STANDBY_ON || + msg == NeutrinoMessages::SHUTDOWN || + msg == NeutrinoMessages::SLEEPTIMER) + { + loop=false; + g_RCInput->postMsg(msg, data); + } + + else if(msg == NeutrinoMessages::EVT_TIMER) + { + CNeutrinoApp::getInstance()->handleMsg( msg, data ); + } + + else + { + if( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + loop = false; + changed=true; + } + } + delete scanBox; +} + +//------------------------------------------------------------------------ + +void CUpnpBrowserGui::playnext(void) +{ + while (true) + { + std::listattribs; + std::listresults; + std::list::iterator i; + std::stringstream sindex; + std::vector *entries = NULL; + bool rfound = false; + bool nfound = false; + bool tfound = false; + + sindex << m_playid; + attribs.push_back(UPnPAttribute("ObjectID", m_playfolder)); + attribs.push_back(UPnPAttribute("BrowseFlag", "BrowseDirectChildren")); + attribs.push_back(UPnPAttribute("Filter", "*")); + attribs.push_back(UPnPAttribute("StartingIndex", sindex.str())); + attribs.push_back(UPnPAttribute("RequestedCount", "1")); + attribs.push_back(UPnPAttribute("SortCriteria", "")); + +#if 0 + try + { + results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); + } + catch (std::runtime_error error) + { + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + m_folderplay = false; + return; + } +#endif + results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); + for (i=results.begin(); i!=results.end(); i++) + { + if (i->first=="NumberReturned") + { + if (atoi(i->second.c_str()) != 1) + { + m_folderplay = false; + return; + } + nfound=true; + } + if (i->first=="TotalMatches") + { + tfound=true; + } + if (i->first=="Result") + { + entries=decodeResult(i->second); + rfound=true; + } + } + m_playid++; + if ((entries != NULL) && (!(*entries)[0].isdir)) + { + int preferred=(*entries)[0].preferred; + if (preferred != -1) + { + std::string protocol, prot, network, mime, additional; + protocol=(*entries)[0].resources[preferred].protocol; + splitProtocol(protocol, prot, network, mime, additional); + if (mime == "audio/mpeg") + { + m_playing_entry = (*entries)[0]; + m_playing_entry_is_shown = false; + CAudiofile mp3((*entries)[0].resources[preferred].url, CFile::FILE_MP3); + CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); + return; + } + else if (mime == "audio/x-vorbis+ogg") + { + m_playing_entry = (*entries)[0]; + m_playing_entry_is_shown = false; + CAudiofile mp3((*entries)[0].resources[preferred].url, CFile::FILE_OGG); + CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); + return; + } + } + } else { + neutrino_msg_t msg; + neutrino_msg_data_t data; + g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display + + if( msg == CRCInput::RC_home) + { + m_folderplay = false; + break; + } + } + } +} + +//------------------------------------------------------------------------ + +bool CUpnpBrowserGui::selectItem(std::string id) +{ + bool loop = true; + bool endall = false; + bool changed = true; + bool rchanged = true; + neutrino_msg_t msg; + neutrino_msg_data_t data; + std::vector *entries; + unsigned int index, selected, dirnum; + + index=0; + selected=0; + dirnum=0; + entries=NULL; + + while (loop) + { + updateTimes(); + if (rchanged) + { + if (entries) + delete entries; + entries=NULL; + + std::listattribs; + std::listresults; + std::list::iterator i; + std::stringstream sindex; + std::stringstream scount; + unsigned int returned = 0; + + bool rfound = false; + bool nfound = false; + bool tfound = false; + + sindex << index; + scount << m_listmaxshow; + + attribs.push_back(UPnPAttribute("ObjectID", id)); + attribs.push_back(UPnPAttribute("BrowseFlag", "BrowseDirectChildren")); + attribs.push_back(UPnPAttribute("Filter", "*")); + attribs.push_back(UPnPAttribute("StartingIndex", sindex.str())); + attribs.push_back(UPnPAttribute("RequestedCount", scount.str())); + attribs.push_back(UPnPAttribute("SortCriteria", "")); +#if 0 + try + { + results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); + } + catch (std::runtime_error error) + { + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + if (entries) + delete entries; + return endall; + } +#endif + results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); + for (i=results.begin(); i!=results.end(); i++) + { + if (i->first=="NumberReturned") + { + returned=atoi(i->second.c_str()); + nfound=true; + } + if (i->first=="TotalMatches") + { + dirnum=atoi(i->second.c_str()); + tfound=true; + } + if (i->first=="Result") + { + entries=decodeResult(i->second); + rfound=true; + } + } + if (!entries) + return endall; + if (!nfound || !tfound || !rfound) + { + delete entries; + return endall; + } + if (returned != entries->size()) + { + delete entries; + return endall; + } + + if (returned == 0) + { + delete entries; + return endall; + } + rchanged=false; + changed=true; + } + + if (changed) + { + paintItem(entries, selected - index, dirnum - index, index); + changed=false; + } + + g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display + neutrino_msg_t msg_repeatok = msg & ~CRCInput::RC_Repeat; + + if( msg == CRCInput::RC_timeout) + { + // nothing + } + else if(msg == CRCInput::RC_home) + { + loop=false; + endall=true; + } + else if(msg == CRCInput::RC_left) + { + loop=false; + } + + else if (msg_repeatok == CRCInput::RC_up && selected > 0) + { + selected--; + if (selected < index) + { + index-=m_listmaxshow; + rchanged=true; + } + changed=true; + } + + else if(msg == CRCInput::RC_green && selected > 0) + { + if (index > 0) + { + index-=m_listmaxshow; + selected-=m_listmaxshow; + rchanged=true; + } + else + selected=0; + changed=true; + } + + else if (msg_repeatok == CRCInput::RC_down && selected + 1 < dirnum) + { + selected++; + if (selected + 1 > index + m_listmaxshow) + { + index+=m_listmaxshow; + rchanged=true; + } + changed=true; + } + + else if(msg == CRCInput::RC_red && selected + 1 < dirnum) + { + if (index < ((dirnum - 1) / m_listmaxshow) * m_listmaxshow) + { + index+=m_listmaxshow; + selected+=m_listmaxshow; + if (selected + 1 >= dirnum) + selected=dirnum - 1; + rchanged=true; + } + else + selected=dirnum - 1; + changed=true; + } + + else if(msg == CRCInput::RC_right) + { + if ((*entries)[selected - index].isdir) + { + endall=selectItem((*entries)[selected - index].id); + if (endall) + loop=false; + } + changed=true; + } + else if(msg == CRCInput::RC_ok) + { + if (!(*entries)[selected - index].isdir) + { + m_folderplay = false; + int preferred=(*entries)[selected - index].preferred; + if (preferred != -1) + { + std::string protocol, prot, network, mime, additional; + protocol=(*entries)[selected - index].resources[preferred].protocol; + splitProtocol(protocol, prot, network, mime, additional); + if (mime == "audio/mpeg") + { + CAudiofile mp3((*entries)[selected - index].resources[preferred].url, CFile::FILE_MP3); + CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); + } + else if (mime == "audio/x-vorbis+ogg") + { + CAudiofile mp3((*entries)[selected - index].resources[preferred].url, CFile::FILE_OGG); + CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); + } + m_playing_entry = (*entries)[selected - index]; +#if 0 +// #ifdef ENABLE_PICTUREVIEWER + else if ((mime == "image/gif") || (mime == "image/jpeg")) + { + CPictureViewer *viewer = new CPictureViewer(); + bool loop=true; + viewer->SetScaling((CPictureViewer::ScalingMode)g_settings.picviewer_scaling); + viewer->SetVisible(g_settings.screen_StartX, g_settings.screen_EndX, g_settings.screen_StartY, g_settings.screen_EndY); + + if(g_settings.video_Format==1) + viewer->SetAspectRatio(16.0/9); + else if(g_settings.video_Format==0) + { + CControldClient cdc; + cdc.setVideoFormat(CControldClient::VIDEOFORMAT_4_3); + viewer->SetAspectRatio(4.0/3); + } + else + viewer->SetAspectRatio(4.0/3); + + m_frameBuffer->setMode(720, 576, 16); + m_frameBuffer->setTransparency(0); + viewer->ShowImage((*entries)[selected - index].resources[preferred].url, true); + while (loop) + { + g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display + + if( msg == CRCInput::RC_home) + loop=false; + } + m_frameBuffer->setMode(720, 576, 8 * sizeof(fb_pixel_t)); + m_frameBuffer->setBlendLevel(g_settings.gtx_alpha1, g_settings.gtx_alpha2); + m_frameBuffer->ClearFrameBuffer(); + delete viewer; + } +// #endif +#endif + } + + } else { + m_folderplay = true; + m_playfolder = (*entries)[selected - index].id; + m_playid = 0; + playnext(); + } + changed=true; + } + else if( msg == CRCInput::RC_yellow) + { + if(CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) + CAudioPlayer::getInstance()->stop(); + m_folderplay = false; + } + + else if(msg == NeutrinoMessages::RECORD_START || + msg == NeutrinoMessages::ZAPTO || + msg == NeutrinoMessages::STANDBY_ON || + msg == NeutrinoMessages::SHUTDOWN || + msg == NeutrinoMessages::SLEEPTIMER) + { + loop = false; + g_RCInput->postMsg(msg, data); + } + + else if(msg == NeutrinoMessages::EVT_TIMER) + { + CNeutrinoApp::getInstance()->handleMsg( msg, data ); + } + + else + { + if( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + loop = false; + changed=true; + } + + if (m_folderplay && (CAudioPlayer::getInstance()->getState() == CBaseDec::STOP)) + playnext(); + } + if (entries) + delete entries; + return endall; +} + +//------------------------------------------------------------------------ + +void CUpnpBrowserGui::paintDevicePos(unsigned int pos) +{ + int ypos = m_y + m_title_height + m_theight + pos*m_fheight; + uint8_t color; + fb_pixel_t bgcolor; + + if (pos == m_selecteddevice) + { + color = COL_MENUCONTENT + 2; + bgcolor = COL_MENUCONTENT_PLUS_2; + } + else + { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + } + m_frameBuffer->paintBoxRel(m_x, ypos, m_width - 15, m_fheight, bgcolor); + + if (pos + m_indexdevice >= m_devices.size()) + return; + + char sNr[20]; + sprintf(sNr, "%2d", pos + 1); + std::string num = sNr; + + std::string name = m_devices[pos + m_indexdevice].friendlyname; + + int w = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getRenderWidth(name) + 5; + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 10, ypos + m_fheight, m_width - 30 - w, + num, color, m_fheight, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + m_width - 15 - w, ypos + m_fheight, + w, name, color, m_fheight, true); // UTF-8 +} + +//------------------------------------------------------------------------ + +void CUpnpBrowserGui::paintItemPos(std::vector *entry, unsigned int pos, unsigned int selected) +{ + int ypos = m_y + m_title_height + m_theight + pos*m_fheight; + uint8_t color; + fb_pixel_t bgcolor; + + if (pos == selected) + { + color = COL_MENUCONTENT + 2; + bgcolor = COL_MENUCONTENT_PLUS_2; + paintDetails(entry, pos); + if ((*entry)[pos].isdir) + paintItem2DetailsLine (-1, pos); // clear it + else + paintItem2DetailsLine (pos, pos); + } + else + { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + } + m_frameBuffer->paintBoxRel(m_x, ypos, m_width - 15, m_fheight, bgcolor); + + if (pos >= entry->size()) + return; + + int preferred=(*entry)[pos].preferred; + std::string info; + std::string fileicon; + if ((*entry)[pos].isdir) + { + info = "

"; + fileicon = "folder.raw"; + } + else + { + if (preferred != -1) + { + info = (*entry)[pos].resources[preferred].duration; + fileicon = "mp3.raw"; + } + else + { + info = "(none)"; + fileicon = "file.raw"; + } + } + + std::string name = (*entry)[pos].title; + char tmp_time[] = "00:00:00.0"; + int w = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getRenderWidth(tmp_time); + + m_frameBuffer->paintIcon(fileicon, m_x + 5 , ypos + (m_fheight - 16) / 2); + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + m_width - 15 - w, ypos + m_fheight, + w, info, color, m_fheight); + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 30, ypos + m_fheight, m_width - 50 - w, + name, color, m_fheight, true); // UTF-8 + +} + +//------------------------------------------------------------------------ + +void CUpnpBrowserGui::paintDevice() +{ + std::string tmp; + int w, xstart, ypos, top; + int c_rad_mid = RADIUS_MID; + + // LCD + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, "Select UPnP Device"); + CVFD::getInstance()->showMenuText(0, m_devices[m_selecteddevice].friendlyname.c_str(), -1, true); + + // Info + m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10, COL_MENUCONTENT_PLUS_6, c_rad_mid); + m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2, m_width - 4, m_title_height - 14, COL_MENUCONTENTSELECTED_PLUS_0, c_rad_mid); + + // first line + tmp = m_devices[m_selecteddevice].manufacturer + " " + + m_devices[m_selecteddevice].manufacturerurl; + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + xstart = (m_width - w) / 2; + if(xstart < 10) + xstart = 10; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 1*m_mheight, m_width - 20, + tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + + // second line + tmp = m_devices[m_selecteddevice].modelname + " " + + m_devices[m_selecteddevice].modelnumber + " " + + m_devices[m_selecteddevice].modeldescription; + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + xstart = (m_width - w) / 2; + if(xstart < 10) + xstart = 10; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 2*m_mheight, m_width - 20, + tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + // third line + tmp = m_devices[m_selecteddevice].modelurl; + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + xstart = (m_width - w) / 2; + if(xstart < 10) + xstart = 10; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 3*m_mheight, m_width - 20, + tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + + // Head + tmp = g_Locale->getText(LOCALE_UPNPBROWSER_HEAD); + m_frameBuffer->paintBoxRel(m_x, m_y + m_title_height, m_width, m_theight, COL_MENUHEAD_PLUS_0, c_rad_mid, CORNER_TOP); + m_frameBuffer->paintIcon(NEUTRINO_ICON_UPNP, m_x + 7, m_y + m_title_height + 6); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(m_x + 35, m_y + m_theight + m_title_height + 0, + m_width - 45, tmp, COL_MENUHEAD, 0, true); // UTF-8 + ypos = m_y + m_title_height; + if(m_theight > 26) + ypos = (m_theight - 26) / 2 + m_y + m_title_height; + m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DBOX, m_x + m_width - 30, ypos); +#if 0 + if( CNeutrinoApp::getInstance()->isMuted() ) + { + xpos = m_x + m_width - 75; + ypos = m_y + m_title_height; + if(m_theight > 32) + ypos = (m_theight - 32) / 2 + m_y + m_title_height; + m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MUTE, xpos, ypos); + } +#endif + + // Items + for (unsigned int count=0;countpaintBoxRel(m_x + m_width - 15, ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc = ((m_devices.size() - 1) / m_listmaxshow) + 1; + int sbs = ((m_selecteddevice) / m_listmaxshow); + + m_frameBuffer->paintBoxRel(m_x + m_width - 13, ypos + 2 + sbs*(sb-4)/sbc, 11, (sb-4)/sbc, COL_MENUCONTENT_PLUS_3); + + // Foot + top = m_y + (m_height - m_info_height - 2 * m_buttonHeight); + + int ButtonWidth = (m_width - 20) / 4; + m_frameBuffer->paintBoxRel(m_x, top, m_width, 1 * m_buttonHeight, COL_MENUHEAD_PLUS_0, c_rad_mid, CORNER_BOTTOM); + m_frameBuffer->paintHLine(m_x, m_x + m_width, top, COL_INFOBAR_SHADOW_PLUS_0); + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + 10, top + 4, ButtonWidth, 1, &RescanButton); + + clearItem2DetailsLine(); // clear it +} + +//------------------------------------------------------------------------ + +void CUpnpBrowserGui::paintItem(std::vector *entry, unsigned int selected, unsigned int max, unsigned int offset) +{ + std::string tmp; + std::stringstream ts; + int w, xstart, ypos, top; + int preferred=(*entry)[selected].preferred; + + // LCD + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, "Select UPnP Entry"); + CVFD::getInstance()->showMenuText(0, (*entry)[selected].title.c_str(), -1, true); + + // Info + m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10, COL_MENUCONTENT_PLUS_6); + m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2, m_width - 4, m_title_height - 14, COL_MENUCONTENTSELECTED_PLUS_0); + + // first line + ts << "Resources: " << (*entry)[selected].resources.size() << " Selected: " << preferred+1 << " "; + tmp = ts.str(); + + if (preferred != -1) + tmp = tmp + "Duration: " + (*entry)[selected].resources[preferred].duration; + else + tmp = tmp + "No resource for Item"; + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + if (w > m_width - 20) + w = m_width - 20; + xstart = (m_width - w) / 2; + if(xstart < 10) + xstart = 10; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 1*m_mheight, m_width - 20, + tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + + // second line + if ((*entry)[selected].isdir) + tmp = "Directory"; + else + { + tmp = ""; + if (preferred != -1) + { + std::string proto, network, mime, info; + splitProtocol((*entry)[selected].resources[preferred].protocol, proto, network, mime, info); + tmp = "Protocol: " + proto + ", MIME-Type: " + mime; + } + + } + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + if (w > m_width - 20) + w = m_width - 20; + xstart = (m_width - w) / 2; + if(xstart < 10) + xstart = 10; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 2*m_mheight, m_width - 20, + tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + + //third line + tmp = ""; + if (!(*entry)[selected].isdir) + { + if (preferred != -1) + { + tmp = "URL: " + (*entry)[selected].resources[preferred].url; + } + + } + w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 + if (w > m_width - 20) + w = m_width - 20; + xstart = (m_width - w) / 2; + if(xstart < 10) + xstart = 10; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 3*m_mheight, m_width - 20, + tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + + + // Head + tmp = g_Locale->getText(LOCALE_UPNPBROWSER_HEAD); + m_frameBuffer->paintBoxRel(m_x, m_y + m_title_height, m_width, m_theight, COL_MENUHEAD_PLUS_0); + m_frameBuffer->paintIcon(NEUTRINO_ICON_UPNP, m_x + 7, m_y + m_title_height + 6); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(m_x + 35, m_y + m_theight + m_title_height + 0, + m_width - 45, tmp, COL_MENUHEAD, 0, true); // UTF-8 + ypos = m_y + m_title_height; + if(m_theight > 26) + ypos = (m_theight - 26) / 2 + m_y + m_title_height; + m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DBOX, m_x + m_width - 30, ypos); +#if 0 + if( CNeutrinoApp::getInstance()->isMuted() ) + { + xpos = m_x + m_width - 75; + ypos = m_y + m_title_height; + if(m_theight > 32) + ypos = (m_theight - 32) / 2 + m_y + m_title_height; + m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MUTE, xpos, ypos); + } +#endif + + // Items + for (unsigned int count=0;countpaintBoxRel(m_x + m_width - 15, ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc = ((max + offset - 1) / m_listmaxshow) + 1; + int sbs = ((selected + offset) / m_listmaxshow); + + int sbh = 0; + if ((sbc > 0) && (sbc > sb-4)) + sbh = 2; + m_frameBuffer->paintBoxRel(m_x + m_width - 13, ypos + 2 + sbs*((sb-4)/sbc+sbh), 11, (sb-4)/sbc + sbh, COL_MENUCONTENT_PLUS_3); + + // Foot buttons + top = m_y + (m_height - m_info_height - 2 * m_buttonHeight); + int ButtonWidth = (m_width - 20) / 4; + m_frameBuffer->paintBoxRel(m_x, top, m_width, 1 * m_buttonHeight+2, COL_MENUHEAD_PLUS_0); + m_frameBuffer->paintHLine(m_x, m_x + m_width, top, COL_INFOBAR_SHADOW_PLUS_0); + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + 10, top + 4, ButtonWidth, 1, &StopButton); + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + ButtonWidth + 10, top + 4, ButtonWidth, 1, &PUpButton); + ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, + m_x + 2 * ButtonWidth + 10, top + 4, ButtonWidth, 1, &PDownButton); + + m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, m_x + 3 * ButtonWidth + 10, top + 1); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(m_x + 3 * ButtonWidth + 40, + top + 19 + 4, ButtonWidth - 40, + g_Locale->getText(LOCALE_AUDIOPLAYER_PLAY), COL_INFOBAR, 0, true); // UTF-8 +} + + +//------------------------------------------------------------------------ + +void CUpnpBrowserGui::paintDetails(std::vector *entry, unsigned int index, bool use_playing) +{ + // Foot info + int top = m_y + (m_height - m_info_height - 1 * m_buttonHeight) + 2; + + if ((!use_playing) && ((*entry)[index].isdir)) + { + m_frameBuffer->paintBackgroundBoxRel(m_x, top + 2, m_width, 2 * m_buttonHeight); + } + else + { +// char cNoch[50]; // UTF-8 +// char cSeit[50]; // UTF-8 + + if (use_playing) { + if (!m_playing_entry_is_shown) { + m_frameBuffer->paintBoxRel(m_x, top + 2, m_width-2, 2 * m_buttonHeight, COL_MENUCONTENTDARK_PLUS_0); + m_playing_entry_is_shown = true; + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 4, + top + 1 * m_buttonHeight + 4, m_x + m_width - 8, m_playing_entry.title + " - " + + m_playing_entry.artist, COL_INFOBAR, 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 4, + top + 2 * m_buttonHeight + 4, m_x + m_width - 8, m_playing_entry.album, COL_INFOBAR, 0, true); // UTF-8 + } + } else { + if (entry == NULL) return; + m_frameBuffer->paintBoxRel(m_x, top + 2, m_width-2, 2 * m_buttonHeight, COL_MENUCONTENTDARK_PLUS_0); + m_playing_entry_is_shown = false; + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 4, + top + 1 * m_buttonHeight + 4, m_x + m_width - 8, (*entry)[index].title + " - " + + (*entry)[index].artist, COL_INFOBAR, 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 4, + top + 2 * m_buttonHeight + 4, m_x + m_width - 8, (*entry)[index].album, COL_INFOBAR, 0, true); // UTF-8 + } +//// printf("title = %s\n", (*entry)[selected].title.c_str()); +// printf("artist = %s\n", (*entry)[selected].artist.c_str()); +// printf("album = %s\n", (*entry)[selected].album.c_str()); +// printf("children = %s\n", (*entry)[selected].children.c_str()); +// printf("id = %s\n", (*entry)[selected].id.c_str()); +#if 0 + struct tm *pStartZeit = localtime(&chanlist[index]->currentEvent.startTime); + unsigned seit = ( time(NULL) - chanlist[index]->currentEvent.startTime ) / 60; + sprintf( cSeit, g_Locale->getText(LOCALE_CHANNELLIST_SINCE), pStartZeit->tm_hour, pStartZeit->tm_min); //, seit ); + int seit_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth(cSeit, true); // UTF-8 + + int noch = ( chanlist[index]->currentEvent.startTime + chanlist[index]->currentEvent.duration - time(NULL) ) / 60; + if ( (noch< 0) || (noch>=10000) ) + noch= 0; + sprintf( cNoch, "(%d / %d min)", seit, noch ); + int noch_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(cNoch, true); // UTF-8 + + std::string text1= chanlist[index]->currentEvent.description; + std::string text2= chanlist[index]->currentEvent.text; + + int xstart = 10; + if (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1) > (width - 30 - seit_len) ) + { + // zu breit, Umbruch versuchen... + int pos; + do + { + pos = text1.find_last_of("[ -.]+"); + if ( pos!=-1 ) + text1 = text1.substr( 0, pos ); + } while ( ( pos != -1 ) && (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1) > (width - 30 - seit_len) ) ); + + std::string text3= chanlist[index]->currentEvent.description.substr(text1.length()+ 1); + if (!(text2.empty())) + text3 += " . "; + + xstart += g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text3); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ 2* fheight, width - 30- noch_len, text3, COL_MENUCONTENTDARK); + } + + if (!(text2.empty())) + { + while ( text2.find_first_of("[ -.+*#?=!$%&/]+") == 0 ) + text2 = text2.substr( 1 ); + text2 = text2.substr( 0, text2.find('\n') ); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ xstart, y+ height+ 5+ 2* fheight, width- xstart- 20- noch_len, text2, COL_MENUCONTENTDARK); + } + + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ fheight, width - 30 - seit_len, text1, COL_MENUCONTENTDARK); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString (x+ width- 10- seit_len, y+ height+ 5+ fheight , seit_len, cSeit, COL_MENUCONTENTDARK, 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(x+ width- 10- noch_len, y+ height+ 5+ 2* fheight- 2, noch_len, cNoch, COL_MENUCONTENTDARK, 0, true); // UTF-8 +#endif + + } +} + +//------------------------------------------------------------------------ + +// +// -- Decoreline to connect ChannelDisplayLine with ChannelDetail display +// -- 2002-03-17 rasc +// + +void CUpnpBrowserGui::clearItem2DetailsLine () +{ + paintItem2DetailsLine (-1, 0); +} + +//------------------------------------------------------------------------ + +void CUpnpBrowserGui::paintItem2DetailsLine (int pos, unsigned int /*ch_index*/) +{ + int xpos = m_x - ConnectLineBox_Width; + int ypos1 = m_y + m_title_height+0 + m_theight + pos*m_fheight; + int ypos2 = m_y + (m_height - m_info_height - 1 * m_buttonHeight) + 2; + + int ypos1a = ypos1 + (m_fheight/2)-2; + int ypos2a = ypos2 + (m_info_height/2)-2; + fb_pixel_t col1 = COL_MENUCONTENT_PLUS_6; + fb_pixel_t col2 = COL_MENUCONTENT_PLUS_1; + + // Clear + m_frameBuffer->paintBackgroundBoxRel(xpos, m_y + m_title_height, ConnectLineBox_Width, m_height+m_info_height-(m_y + m_title_height)); + if (pos < 0) { + m_frameBuffer->paintBackgroundBoxRel(m_x, m_y + (m_height - m_info_height - 1 * m_buttonHeight) + 2, m_width, m_info_height); + } + // paint Line if detail info (and not valid list pos) + if (pos >= 0) + { + // 1. col thick line + m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos1, 4, m_fheight, col1); + m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos2, 4, m_info_height, col1); + + m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 4, ypos2a-ypos1a, col1); + + m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 12, 4, col1); + m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos2a, 12, 4, col1); + + // 2. col small line + m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos1, 1, m_fheight, col2); + m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos2, 1, m_info_height, col2); + + m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 1, ypos2a-ypos1a+4, col2); + + m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 12, 1, col2); + m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-12, ypos2a, 8, 1, col2); + + // -- small Frame around infobox + m_frameBuffer->paintBoxRel(m_x , ypos2, 2, m_info_height, col1); + m_frameBuffer->paintBoxRel(m_x+m_width-2, ypos2, 2, m_info_height, col1); + m_frameBuffer->paintBoxRel(m_x , ypos2, m_width-2, 2, col1); + m_frameBuffer->paintBoxRel(m_x , ypos2+m_info_height-2, m_width-2, 2, col1); + } +} + +//------------------------------------------------------------------------ + +void CUpnpBrowserGui::updateTimes(const bool force) +{ + int top; + if(CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) + { + bool updatePlayed = force; + + if ((m_time_played != CAudioPlayer::getInstance()->getTimePlayed())) + { + m_time_played = CAudioPlayer::getInstance()->getTimePlayed(); + updatePlayed = true; + } + char play_time[8]; + snprintf(play_time, 7, "%ld:%02ld", m_time_played / 60, m_time_played % 60); + char tmp_time[] = "000:00"; + int w = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getRenderWidth(tmp_time); + + if (updatePlayed) + { + paintDetails(NULL, 0, true); + top = m_y + (m_height - m_info_height - 1 * m_buttonHeight) + m_buttonHeight + 4; + m_frameBuffer->paintBoxRel(m_x + m_width - w - 15, top + 1, w + 4, m_buttonHeight, + COL_MENUCONTENTDARK_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(m_x + m_width - w - 11, top + 1 + m_buttonHeight, w, play_time, COL_MENUHEAD); + } + } +} + diff --git a/src/gui/upnpbrowser.h b/src/gui/upnpbrowser.h new file mode 100644 index 000000000..03b6cc7b8 --- /dev/null +++ b/src/gui/upnpbrowser.h @@ -0,0 +1,115 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __upnpplayergui__ +#define __upnpplayergui__ + +#include "driver/framebuffer.h" +#include "driver/audiofile.h" +#include "driver/pictureviewer/pictureviewer.h" +#include "gui/filebrowser.h" +#include "gui/widget/menue.h" + +#include +#include +#include + +struct UPnPResource +{ + std::string url; + std::string protocol; + std::string size; + std::string duration; +}; + +struct UPnPEntry +{ + std::string id; + bool isdir; + std::string title; + std::string artist; + std::string album; + std::string children; + std::vector resources; + int preferred; +}; + +class CUpnpBrowserGui : public CMenuTarget +{ + public: + CUpnpBrowserGui(); + ~CUpnpBrowserGui(); + int exec(CMenuTarget* parent, const std::string & actionKey); + + private: + std::vector m_devices; + UPnPEntry m_playing_entry; + CUPnPSocket * m_socket; + CFrameBuffer * m_frameBuffer; + bool m_vol_ost; + int m_LastMode; + int m_width; + int m_height; + int m_x; + int m_y; + unsigned int m_listmaxshow; + unsigned int m_indexdevice; + unsigned int m_selecteddevice; + int m_fheight; // Fonthoehe Inhalt + int m_theight; // Fonthoehe Titel + int m_mheight; // Fonthoehe Info + int m_sheight; // Fonthoehe Status + int m_buttonHeight; + int m_title_height; + int m_info_height; + bool m_folderplay; + std::string m_playfolder; + int m_playid; + time_t m_time_played; + bool m_playing_entry_is_shown; + + void selectDevice(); + bool selectItem(std::string); + void paintItem(std::vector *entry, unsigned int selected, unsigned int max, unsigned int offset); + void paintDevice(); + std::vector *decodeResult(std::string); + void playnext(); + void splitProtocol(std::string &protocol, std::string &prot, std::string &network, std::string &mime, std::string &additional); + void paintItemPos (std::vector *entry, unsigned int pos, unsigned int selected); + void paintDevicePos(unsigned int pos); + void paintDetails(std::vector *entry, unsigned int index, bool use_playing = false); + void clearItem2DetailsLine (void); + void paintItem2DetailsLine (int pos,unsigned int ch_index); + + void updateTimes(const bool force = false); +}; + +#endif diff --git a/src/gui/widget/Makefile.am b/src/gui/widget/Makefile.am new file mode 100644 index 000000000..0f43cd31e --- /dev/null +++ b/src/gui/widget/Makefile.am @@ -0,0 +1,24 @@ +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/lib/libnet \ + -I$(top_srcdir)/lib/libconfigfile \ + -I$(top_srcdir)/lib/libcoolstream \ + @FREETYPE_CFLAGS@ + +noinst_LIBRARIES = libneutrino_gui_widget.a libneutrino_gui_widget2.a + +libneutrino_gui_widget_a_SOURCES = \ + buttons.cpp \ + colorchooser.cpp keychooser.cpp \ + menue.cpp stringinput.cpp stringinput_ext.cpp \ + messagebox.cpp hintbox.cpp listbox.cpp listbox_legacy.cpp \ + rgbcsynccontroler.cpp \ + drawable.cpp hintboxext.cpp helpbox.cpp mountchooser.cpp \ + listframe.cpp msgbox.cpp textbox.cpp + +libneutrino_gui_widget2_a_SOURCES = \ + progresswindow.cpp vfdcontroler.cpp diff --git a/src/gui/widget/buttons.cpp b/src/gui/widget/buttons.cpp new file mode 100644 index 000000000..37c7c75e5 --- /dev/null +++ b/src/gui/widget/buttons.cpp @@ -0,0 +1,37 @@ +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/gui/widget/buttons.cpp,v 1.2 2004/03/14 22:20:05 thegoodguy Exp $ + * + * (C) 2003 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +void paintButtons(CFrameBuffer * const frameBuffer, Font * const font, const CLocaleManager * const localemanager, const int x, const int y, const unsigned int buttonwidth, const unsigned int count, const struct button_label * const content) +{ + for (unsigned int i = 0; i < count; i++) + { + frameBuffer->paintIcon(content[i].button, x + i * buttonwidth, y); + font->RenderString(x + i * buttonwidth + 20, y + 19, buttonwidth - 20, localemanager->getText(content[i].locale), COL_INFOBAR, 0, true); // UTF-8 + } +} diff --git a/src/gui/widget/buttons.h b/src/gui/widget/buttons.h new file mode 100644 index 000000000..96e241cfd --- /dev/null +++ b/src/gui/widget/buttons.h @@ -0,0 +1,37 @@ +#ifndef __gui_widget_buttons_h__ +#define __gui_widget_buttons_h__ + +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/gui/widget/buttons.h,v 1.2 2004/05/25 07:44:16 thegoodguy Exp $ + * + * (C) 2003 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include + +typedef struct button_label +{ + const char * button; + neutrino_locale_t locale; +} button_label_struct; + +void paintButtons(CFrameBuffer * const frameBuffer, Font * const font, const CLocaleManager * const localemanager, const int x, const int y, const unsigned int buttonwidth, const unsigned int count, const struct button_label * const content); + +#endif /* __gui_widget_buttons_h__ */ diff --git a/src/gui/widget/colorchooser.cpp b/src/gui/widget/colorchooser.cpp new file mode 100644 index 000000000..5065a05d7 --- /dev/null +++ b/src/gui/widget/colorchooser.cpp @@ -0,0 +1,256 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#define ROUND_RADIUS 8 + +#define VALUE_R 0 +#define VALUE_G 1 +#define VALUE_B 2 +#define VALUE_ALPHA 3 + +static const char * const iconnames[4] = { + "volumeslider2red.raw", + "volumeslider2green.raw", + "volumeslider2blue.raw", + "volumeslider2alpha.raw" +}; + +static const neutrino_locale_t colorchooser_names[4] = +{ + LOCALE_COLORCHOOSER_RED , + LOCALE_COLORCHOOSER_GREEN, + LOCALE_COLORCHOOSER_BLUE , + LOCALE_COLORCHOOSER_ALPHA +}; + +CColorChooser::CColorChooser(const neutrino_locale_t Name, unsigned char *R, unsigned char *G, unsigned char *B, unsigned char* Alpha, CChangeObserver* Observer) // UTF-8 +{ + frameBuffer = CFrameBuffer::getInstance(); + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + observer = Observer; + name = Name; + width = w_max(360, 0); + height = h_max(hheight+ mheight* 4, 0); + + x = frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth()-width) >> 1); + y = frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight()-height)>>1); + + value[VALUE_R] = R; + value[VALUE_G] = G; + value[VALUE_B] = B; + value[VALUE_ALPHA] = Alpha; +} + +void CColorChooser::setColor() +{ + int color = convertSetupColor2RGB(*(value[VALUE_R]), *(value[VALUE_G]), *(value[VALUE_B])); + int tAlpha = (value[VALUE_ALPHA]) ? (convertSetupAlpha2Alpha(*(value[VALUE_ALPHA]))) : 0; + + if(!value[VALUE_ALPHA]) tAlpha = 0xFF; + + fb_pixel_t col = ((tAlpha << 24) & 0xFF000000) | color; + //((tAlpha << 24) & 0xFF000000) | ((color << 16) & 0x00FF0000) | (color & 0x0000FF00) | ((color >> 16) & 0xFF); + frameBuffer->paintBoxRel(x+222,y+hheight+2+5, mheight*4-4 ,mheight*4-4-10, col); +} + +int CColorChooser::exec(CMenuTarget* parent, const std::string &) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = menu_return::RETURN_REPAINT; + if (parent) + parent->hide(); + + unsigned char r_alt= *value[VALUE_R]; + unsigned char g_alt= *value[VALUE_G]; + unsigned char b_alt= *value[VALUE_B]; + unsigned char a_alt = (value[VALUE_ALPHA]) ? (*(value[VALUE_ALPHA])) : 0; + + paint(); + setColor(); + + int selected = 0; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings + ::TIMING_MENU]); + + bool loop=true; + while (loop) { + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd, true); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings + ::TIMING_MENU]); + + switch ( msg ) { + case CRCInput::RC_down: + { + if (selected < ((value[VALUE_ALPHA]) ? 3 : 2)) + { + paintSlider(x + 10, y + hheight + mheight * selected, value[selected], colorchooser_names[selected], iconnames[selected], false); + selected++; + paintSlider(x + 10, y + hheight + mheight * selected, value[selected], colorchooser_names[selected], iconnames[selected], true); + } else { + paintSlider(x + 10, y + hheight + mheight * selected, value[selected], colorchooser_names[selected], iconnames[selected], false); + selected = 0; + paintSlider(x + 10, y + hheight + mheight * selected, value[selected], colorchooser_names[selected], iconnames[selected], true); + } + break; + + } + case CRCInput::RC_up: + { + if (selected > 0) + { + paintSlider(x + 10, y + hheight + mheight * selected, value[selected], colorchooser_names[selected], iconnames[selected], false); + selected--; + paintSlider(x + 10, y + hheight + mheight * selected, value[selected], colorchooser_names[selected], iconnames[selected], true); + } else { + paintSlider(x + 10, y + hheight + mheight * selected, value[selected], colorchooser_names[selected], iconnames[selected], false); + selected = ((value[VALUE_ALPHA]) ? 3 : 2); + paintSlider(x + 10, y + hheight + mheight * selected, value[selected], colorchooser_names[selected], iconnames[selected], true); + } + break; + } + case CRCInput::RC_right: + { + if ((*value[selected]) < 100) + { + if ((*value[selected]) < 98) + (*value[selected]) += 2; + else + (*value[selected]) = 100; + + paintSlider(x + 10, y + hheight + mheight * selected, value[selected], colorchooser_names[selected], iconnames[selected], true); + setColor(); + } + break; + } + case CRCInput::RC_left: + { + if ((*value[selected]) > 0) + { + if ((*value[selected]) > 2) + (*value[selected]) -= 2; + else + (*value[selected]) = 0; + + paintSlider(x + 10, y + hheight + mheight * selected, value[selected], colorchooser_names[selected], iconnames[selected], true); + setColor(); + } + break; + } + case CRCInput::RC_home: + if (((*value[VALUE_R] != r_alt) || (*value[VALUE_G] != g_alt) || (*value[VALUE_B] != b_alt) || ((value[VALUE_ALPHA]) && (*(value[VALUE_ALPHA]) != a_alt))) && + (ShowLocalizedMessage(name, LOCALE_MESSAGEBOX_DISCARD, CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbCancel) == CMessageBox::mbrCancel)) + break; + + // sonst abbruch... + *value[VALUE_R] = r_alt; + *value[VALUE_G] = g_alt; + *value[VALUE_B] = b_alt; + if (value[VALUE_ALPHA]) + *value[VALUE_ALPHA] = a_alt; + + case CRCInput::RC_sat: + case CRCInput::RC_favorites: + break; + case CRCInput::RC_timeout: + case CRCInput::RC_ok: + loop = false; + break; + + default: + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + + hide(); + + if(observer) + observer->changeNotify(name, NULL); + + return res; +} + +void CColorChooser::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height); +} + +void CColorChooser::paint() +{ + //frameBuffer->paintBoxRel(x,y, width,hheight, COL_MENUHEAD_PLUS_0); + frameBuffer->paintBoxRel(x,y, width,hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); //round + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10,y+hheight, width, g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + //frameBuffer->paintBoxRel(x,y+hheight, width,height-hheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintBoxRel(x,y+hheight, width,height-hheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2);//round + + for (int i = 0; i < 4; i++) + paintSlider(x + 10, y + hheight + mheight * i, value[i], colorchooser_names[i], iconnames[i], (i == 0)); + + //color preview + frameBuffer->paintBoxRel(x+220,y+hheight+5, mheight*4, mheight*4-10, COL_MENUHEAD_PLUS_0); + frameBuffer->paintBoxRel(x+222,y+hheight+2+5, mheight*4-4 ,mheight*4-4-10, 254); +} + +void CColorChooser::paintSlider(int x, int y, unsigned char *spos, const neutrino_locale_t text, const char * const iconname, const bool selected) +{ + if (!spos) + return; + frameBuffer->paintBoxRel(x+70,y,120,mheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintIcon("volumebody.raw",x+70,y+2+mheight/4); + frameBuffer->paintIcon(selected ? iconname : "volumeslider2.raw",x+73+(*spos),y+mheight/4); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x,y+mheight, width, g_Locale->getText(text), COL_MENUCONTENT, 0, true); // UTF-8 +} diff --git a/src/gui/widget/colorchooser.h b/src/gui/widget/colorchooser.h new file mode 100644 index 000000000..fda66b089 --- /dev/null +++ b/src/gui/widget/colorchooser.h @@ -0,0 +1,73 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __colorchooser__ +#define __colorchooser__ + +#include +#include +#include + +#include + +class CColorChooser : public CMenuTarget +{ + private: + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hheight,mheight; // head/menu font height + + unsigned char * value[4]; // r, g, b, alpha + + neutrino_locale_t name; + + CChangeObserver* observer; + + void paint(); + void setColor(); + void paintSlider(int x, int y, unsigned char *spos, const neutrino_locale_t text, const char * const iconname, const bool selected); + + public: + + CColorChooser(const neutrino_locale_t Name, unsigned char *R, unsigned char *G, unsigned char *B, unsigned char* Alpha, CChangeObserver* Observer = NULL); // UTF-8 + + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); + +}; + + +#endif + diff --git a/src/gui/widget/drawable.cpp b/src/gui/widget/drawable.cpp new file mode 100644 index 000000000..a337e635d --- /dev/null +++ b/src/gui/widget/drawable.cpp @@ -0,0 +1,150 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +Drawable::Drawable() +{ +} + +Drawable::~Drawable() +{ +} + +int Drawable::getWidth(void) +{ + return m_width; +} + +int Drawable::getHeight(void) +{ + return m_height; +} + +Drawable::DType Drawable::getType(void) +{ + return Drawable::DTYPE_DRAWABLE; +} + + +// ------------------------------------------------------------------------------ +DText::DText(std::string& text) +{ + m_text = text; + init(); +} + +DText::DText(const char *text) +{ + m_text = std::string(text); + init(); +} + +void DText::init() +{ + m_width = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getRenderWidth(m_text, true); // UTF-8 + m_height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); +} + + +void DText::draw(CFBWindow *window, int x, int y, int width) +{ + window->RenderString(g_Font[SNeutrinoSettings::FONT_TYPE_MENU], x, y + m_height, width, + m_text.c_str(), (CFBWindow::color_t)COL_MENUCONTENT, 0, true); // UTF-8 +} + +void DText::print(void) +{ + std::cout << " text: " << m_text; +} + +// ------------------------------------------------------------------------------ +DIcon::DIcon(std::string& icon) +{ + m_icon = icon; + init(); +} + +DIcon::DIcon(const char *icon) +{ + m_icon = std::string(icon); + init(); +} + +void DIcon::init() +{ + m_height = 16; + m_width = 16; +} + +void DIcon::draw(CFBWindow *window, int x, int y, int width) +{ + window->paintIcon(m_icon.c_str(), x, y); +} + +void DIcon::print(void) +{ + std::cout << " icon: " << m_icon; +} + +// ------------------------------------------------------------------------------ +DPagebreak::DPagebreak() +{ + m_height = 0; + m_width = 0; +} + +void DPagebreak::draw(CFBWindow *window, int x, int y, int width) +{ +// window->RenderString(g_Font[SNeutrinoSettings::FONT_TYPE_MENU], +// x, y + m_height, width, "", +// (CFBWindow::color_t)COL_MENUCONTENT, 0, true); // UTF-8 +} + +void DPagebreak::print(void) +{ + std::cout << ""; +} + +Drawable::DType DPagebreak::getType(void) +{ + return Drawable::DTYPE_PAGEBREAK; +} diff --git a/src/gui/widget/drawable.h b/src/gui/widget/drawable.h new file mode 100644 index 000000000..744f4446e --- /dev/null +++ b/src/gui/widget/drawable.h @@ -0,0 +1,164 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __drawable__ +#define __drawable__ + +#include +#include + +#include +#include + +class Drawable; + +typedef std::vector > ContentLines; + + +/** + * The base class for items which can be drawn on a CFBWindow. + */ +class Drawable +{ +public: + + enum DType { + DTYPE_DRAWABLE, + DTYPE_PAGEBREAK + }; + + virtual ~Drawable(); + + /** + * Overwrite this method in subclasses to draw on the window + * + * @param window the window to draw on + * @param x x component of the top left corner + * @param y y component of the top left corner + */ + virtual void draw(CFBWindow *window, int x, int y, int width) = 0; + + virtual int getWidth(void); + + virtual int getHeight(void); + + /** + * Overwrite this method in subclasses to print some info + * about the content. Mainly used for debuging ;) + */ + virtual void print(void) = 0; + + /** + * Returns the type of this drawable. Used to distinguish between + * drawing objects and control objects like pagebreaks. + * @return the type of this drawable. + */ + virtual DType getType(); + +protected: + + Drawable(); + + int m_height; + + int m_width; + +private: + +}; + +/** + * This class draws a given string. + */ +class DText : public Drawable +{ +public: + DText(std::string& text); + + DText(const char *text); + + void init(); + + void draw(CFBWindow *window, int x, int y, int width); + + void print(); + +protected: + + std::string m_text; + +}; + + +/** + * This class draws a given icon. + */ +class DIcon : public Drawable +{ +public: + DIcon(std::string& icon); + + DIcon(const char *icon); + + void init(); + + void draw(CFBWindow *window, int x, int y, int width); + + void print(); + +protected: + + std::string m_icon; +}; + +/** + * This class is used as a control object and forces a new page + * in scrollable windows. + */ +class DPagebreak : public Drawable +{ +public: + DPagebreak(); + + void draw(CFBWindow *window, int x, int y, int width); + + void print(); + + DType getType(); + +protected: + +private: + +}; + +#endif diff --git a/src/gui/widget/helpbox.cpp b/src/gui/widget/helpbox.cpp new file mode 100644 index 000000000..05f4d56e6 --- /dev/null +++ b/src/gui/widget/helpbox.cpp @@ -0,0 +1,111 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +Helpbox::Helpbox() +{ +} + +Helpbox::~Helpbox() +{ + for (ContentLines::iterator it = m_lines.begin(); + it != m_lines.end(); it++) + { + for (std::vector::iterator it2 = it->begin(); + it2 != it->end(); it2++) + { + delete *it2; + } + } +} + +void Helpbox::show(const neutrino_locale_t Caption, const int Width, int timeout) +{ + + CMessageBox msgBox(Caption, m_lines, Width, NEUTRINO_ICON_INFO, CMessageBox::mbrBack,CMessageBox::mbBack); + msgBox.exec(timeout); +} + +void Helpbox::addLine(const char *text) +{ + std::vector v; + Drawable *d = new DText(text); + v.push_back(d); + m_lines.push_back(v); +} + +void Helpbox::addLine(std::string& text) +{ + std::vector v; + Drawable *d = new DText(text); + v.push_back(d); + m_lines.push_back(v); +} + +void Helpbox::addLine(const char *icon, const char *text) +{ + std::vector v; + Drawable *di = new DIcon(icon); + Drawable *dt = new DText(text); + v.push_back(di); + v.push_back(dt); + m_lines.push_back(v); +} + +void Helpbox::addLine(std::string& icon, std::string& text) +{ + std::vector v; + Drawable *di = new DIcon(icon); + Drawable *dt = new DText(text); + v.push_back(di); + v.push_back(dt); + m_lines.push_back(v); +} + +void Helpbox::addPagebreak(void) +{ + std::vector v; + Drawable *p = new DPagebreak(); + v.push_back(p); + m_lines.push_back(v); +} + diff --git a/src/gui/widget/helpbox.h b/src/gui/widget/helpbox.h new file mode 100644 index 000000000..a1d4d3c22 --- /dev/null +++ b/src/gui/widget/helpbox.h @@ -0,0 +1,64 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __helpbox__ +#define __helpbox__ + +#include + +#include + +#include +#include + +class Helpbox +{ +public: + + Helpbox(); + ~Helpbox(); + + void show(const neutrino_locale_t Caption, const int Width = 450, int timeout = -1); + + void addLine(std::string& text); + void addLine(const char *text); + void addLine(std::string& icon, std::string& text); + void addLine(const char *icon, const char *text); + void addPagebreak(); +protected: + +private: + + ContentLines m_lines; +}; + +#endif diff --git a/src/gui/widget/hintbox.cpp b/src/gui/widget/hintbox.cpp new file mode 100644 index 000000000..8c2c57210 --- /dev/null +++ b/src/gui/widget/hintbox.cpp @@ -0,0 +1,279 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#define borderwidth 4 + +#define ROUND_RADIUS 9 + +#define HINTBOX_MAX_HEIGHT 420 + +CHintBox::CHintBox(const neutrino_locale_t Caption, const char * const Text, const int Width, const char * const Icon) +{ + char * begin; + char * pos; + int nw; + + message = strdup(Text); + + width = Width; + + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + height = theight + fheight; + + caption = Caption; + + begin = message; + + while (true) + { + height += fheight; + if (height > HINTBOX_MAX_HEIGHT) + height -= fheight; + + line.push_back(begin); + pos = strchr(begin, '\n'); + if (pos != NULL) + { + *pos = 0; + begin = pos + 1; + } + else + break; + } + entries_per_page = ((height - theight) / fheight) - 1; + current_page = 0; + + unsigned int additional_width; + + if (entries_per_page < line.size()) + additional_width = 20 + 15; + else + additional_width = 20 + 0; + + if (Icon != NULL) + { + iconfile = Icon; + additional_width += 30; + } + else + iconfile = ""; + + nw = additional_width + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getRenderWidth(g_Locale->getText(caption), true); // UTF-8 + + if (nw > width) + width = nw; + + for (std::vector::const_iterator it = line.begin(); it != line.end(); it++) + { + nw = additional_width + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(*it, true); // UTF-8 + if (nw > width) + width = nw; + } + window = NULL; +} + +CHintBox::~CHintBox(void) +{ + if (window != NULL) + { + delete window; + window = NULL; + } + free(message); +} + +void CHintBox::paint(void) +{ + if (window != NULL) + { + /* + * do not paint stuff twice: + * => thread safety needed by movieplayer.cpp: + * one thread calls our paint method, the other one our hide method + * => no memory leaks + */ + return; + } + + CFrameBuffer* frameBuffer = CFrameBuffer::getInstance(); + window = new CFBWindow(frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth() - width ) >> 1), + frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight() - height) >> 2), + width + borderwidth, + height + borderwidth); + refresh(); +} + +void CHintBox::refresh(void) +{ + if (window == NULL) + { + return; + } + + //window->paintBoxRel(borderwidth, height, width, borderwidth, COL_INFOBAR_SHADOW_PLUS_0); + //window->paintBoxRel(width, borderwidth, borderwidth, height - borderwidth, COL_INFOBAR_SHADOW_PLUS_0); + window->paintBoxRel(width-20, borderwidth, borderwidth+20, height - borderwidth, COL_INFOBAR_SHADOW_PLUS_0, ROUND_RADIUS, 1); // right + window->paintBoxRel(borderwidth, height-20, width, borderwidth+20, COL_INFOBAR_SHADOW_PLUS_0, ROUND_RADIUS, 2); // bottom + + //window->paintBoxRel(0, 0, width, theight, (CFBWindow::color_t)COL_MENUHEAD_PLUS_0); + window->paintBoxRel(0, 0, width, theight, (CFBWindow::color_t)COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1);//round + + if (!iconfile.empty()) + { + window->paintIcon(iconfile.c_str(), 8, 5); + window->RenderString(g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE], 40, theight, width - 40, g_Locale->getText(caption), (CFBWindow::color_t)COL_MENUHEAD, 0, true); // UTF-8 + } + else + window->RenderString(g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE], 10, theight, width - 10, g_Locale->getText(caption), (CFBWindow::color_t)COL_MENUHEAD, 0, true); // UTF-8 + + //window->paintBoxRel(0, theight, width, (entries_per_page + 1) * fheight, (CFBWindow::color_t)COL_MENUCONTENT_PLUS_0); + window->paintBoxRel(0, theight, width, (entries_per_page + 1) * fheight, (CFBWindow::color_t)COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2);//round + + int count = entries_per_page; + int ypos = theight + (fheight >> 1); + + for (std::vector::const_iterator it = line.begin() + (entries_per_page * current_page); ((it != line.end()) && (count > 0)); it++, count--) + window->RenderString(g_Font[SNeutrinoSettings::FONT_TYPE_MENU], 10, (ypos += fheight), width, *it, (CFBWindow::color_t)COL_MENUCONTENT, 0, true); // UTF-8 + + if (entries_per_page < line.size()) + { + ypos = theight + (fheight >> 1); + window->paintBoxRel(width - 15, ypos , 15, entries_per_page * fheight, COL_MENUCONTENT_PLUS_1); + unsigned int marker_size = (entries_per_page * fheight) / ((line.size() + entries_per_page - 1) / entries_per_page); + window->paintBoxRel(width - 13, ypos + current_page * marker_size, 11, marker_size , COL_MENUCONTENT_PLUS_3); + } +} + +bool CHintBox::has_scrollbar(void) +{ + return (entries_per_page < line.size()); +} + +void CHintBox::scroll_up(void) +{ + if (current_page > 0) + { + current_page--; + refresh(); + } +} + +void CHintBox::scroll_down(void) +{ + if ((entries_per_page * (current_page + 1)) <= line.size()) + { + current_page++; + refresh(); + } +} + +void CHintBox::hide(void) +{ + if (window != NULL) + { + delete window; + window = NULL; + } +} + +int ShowHintUTF(const neutrino_locale_t Caption, const char * const Text, const int Width, int timeout, const char * const Icon) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + CHintBox * hintBox = new CHintBox(Caption, Text, Width, Icon); + hintBox->paint(); + + if ( timeout == -1 ) + timeout = 5; /// default timeout 5 sec + //timeout = g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR]; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd( timeout ); + + int res = messages_return::none; + + while ( ! ( res & ( messages_return::cancel_info | messages_return::cancel_all ) ) ) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if ((msg == CRCInput::RC_timeout) || + (msg == CRCInput::RC_home ) || + (msg == CRCInput::RC_ok )) + { + res = messages_return::cancel_info; + } + else if ((hintBox->has_scrollbar()) && ((msg == CRCInput::RC_up) || (msg == CRCInput::RC_down))) + { + if (msg == CRCInput::RC_up) + hintBox->scroll_up(); + else + hintBox->scroll_down(); + } + else if((msg == CRCInput::RC_sat) || (msg == CRCInput::RC_favorites)) { + } + else if((msg == CRCInput::RC_mode) || (msg == CRCInput::RC_next) || (msg == CRCInput::RC_prev)) { + res = messages_return::cancel_info; + g_RCInput->postMsg(msg, data); + } + else + { + res = CNeutrinoApp::getInstance()->handleMsg(msg, data); + if (res & messages_return::unhandled) + { + + // raus hier und darüber behandeln... + g_RCInput->postMsg(msg, data); + res = messages_return::cancel_info; + } + } + } + + hintBox->hide(); + delete hintBox; + return 1; +} + +int ShowLocalizedHint(const neutrino_locale_t Caption, const neutrino_locale_t Text, const int Width, int timeout, const char * const Icon) +{ + return ShowHintUTF(Caption, g_Locale->getText(Text),Width,timeout,Icon); +} + diff --git a/src/gui/widget/hintbox.h b/src/gui/widget/hintbox.h new file mode 100644 index 000000000..c291aa683 --- /dev/null +++ b/src/gui/widget/hintbox.h @@ -0,0 +1,82 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __hintbox__ +#define __hintbox__ + +#include +#include +#include + +#include +#include + +class CHintBox +{ + protected: + + CFBWindow * window; + + unsigned int entries_per_page; + unsigned int current_page; + + int width; + int height; + + int fheight; + int theight; + neutrino_locale_t caption; + char * message; + std::vector line; + std::string iconfile; + + void refresh(void); + + public: + // Text is UTF-8 encoded + CHintBox(const neutrino_locale_t Caption, const char * const Text, const int Width = 450, const char * const Icon = "info.raw"); + ~CHintBox(void); + + bool has_scrollbar(void); + void scroll_up(void); + void scroll_down(void); + + void paint(void); + void hide(void); +}; + +// Text is UTF-8 encoded +int ShowHintUTF(const neutrino_locale_t Caption, const char * const Text, const int Width = 450, int timeout = -1, const char * const Icon = NEUTRINO_ICON_INFO); +int ShowLocalizedHint(const neutrino_locale_t Caption, const neutrino_locale_t Text, const int Width = 450, int timeout = -1, const char * const Icon = NEUTRINO_ICON_INFO); + + +#endif diff --git a/src/gui/widget/hintboxext.cpp b/src/gui/widget/hintboxext.cpp new file mode 100644 index 000000000..2346dc5e6 --- /dev/null +++ b/src/gui/widget/hintboxext.cpp @@ -0,0 +1,314 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include + +#define ROUND_RADIUS 9 + +#define borderwidth 4 + +#define HINTBOXEXT_MAX_HEIGHT 420 + +CHintBoxExt::CHintBoxExt(const neutrino_locale_t Caption, const char * const Text, const int Width, const char * const Icon) +{ + m_message = strdup(Text); + + char *begin = m_message; + + begin = strtok(m_message, "\n"); + while (begin != NULL) + { + std::vector oneLine; + std::string s(begin); + DText *d = new DText(s); + oneLine.push_back(d); + m_lines.push_back(oneLine); + begin = strtok(NULL, "\n"); + } + init(Caption, Width, Icon); +} + + +CHintBoxExt::CHintBoxExt(const neutrino_locale_t Caption, ContentLines& lines, const int Width, const char * const Icon) +{ + m_message = NULL; + m_lines = lines; + init(Caption, Width, Icon); +} + +CHintBoxExt::~CHintBoxExt(void) +{ + if (m_window != NULL) + { + delete m_window; + m_window = NULL; + } + if (m_message != NULL) { + free(m_message); + + // content has been set using "m_message" so we are responsible to + // delete it + for (ContentLines::iterator it = m_lines.begin(); + it != m_lines.end(); it++) + { + for (std::vector::iterator it2 = it->begin(); + it2 != it->end(); it2++) + { + //(*it2)->print(); + delete *it2; + } + } + } +} + +void CHintBoxExt::init(const neutrino_locale_t Caption, const int Width, const char * const Icon) +{ + m_width = Width; + int nw = 0; + m_theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + m_fheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + m_height = m_theight + m_fheight; + m_maxEntriesPerPage = 0; + + m_caption = Caption; + + int page = 0; + int line = 0; + int maxWidth = m_width > 0 ? m_width : 0; + int maxOverallHeight = 0; + m_startEntryOfPage.push_back(0); + for (ContentLines::iterator it = m_lines.begin(); it!=m_lines.end(); it++) + { + bool pagebreak = false; + int maxHeight = 0; + int lineWidth = 0; + for (std::vector::iterator item = it->begin(); + item != it->end(); item++) { + if ((*item)->getHeight() > maxHeight) + maxHeight = (*item)->getHeight(); + lineWidth += (*item)->getWidth(); + if ((*item)->getType() == Drawable::DTYPE_PAGEBREAK) + pagebreak = true; + } + if (lineWidth > maxWidth) + maxWidth = lineWidth; + m_height += maxHeight; + if (m_height > HINTBOXEXT_MAX_HEIGHT || pagebreak) { + if (m_height-maxHeight > maxOverallHeight) + maxOverallHeight = m_height - maxHeight; + m_height = m_theight + m_fheight + maxHeight; + if (pagebreak) + m_startEntryOfPage.push_back(line+1); + else + m_startEntryOfPage.push_back(line); + page++; + if (m_maxEntriesPerPage < (m_startEntryOfPage[page] - m_startEntryOfPage[page-1])) + { + m_maxEntriesPerPage = m_startEntryOfPage[page] - m_startEntryOfPage[page-1]; + } + } + line++; + } + + // if there is only one page m_height is already correct + // but m_maxEntries has not been set + if (m_startEntryOfPage.size() > 1) + { + m_height = maxOverallHeight; + } else { + m_maxEntriesPerPage = line; + } + + m_startEntryOfPage.push_back(line+1); // needed to calculate amount of items on last page + +// for (std::vector::iterator it=m_startEntryOfPage.begin(); +// it!=m_startEntryOfPage.end();it++) +// printf("startentryofpage: %d\n",*it); +// printf("pages: %d, startEntryVec: %d\n",page+1,m_startEntryOfPage.size()-1); +// printf("maxEntries: %d\n", m_maxEntriesPerPage); + + m_width = w_max(maxWidth,borderwidth); + m_currentPage = 0; + m_pages = page + 1; + unsigned int additional_width; + + if (m_startEntryOfPage.size() > 1) + additional_width = 20 + 15; + else + additional_width = 20 + 0; + + if (Icon != NULL) + { + m_iconfile = Icon; + additional_width += 30; + } + else + m_iconfile = ""; + + nw = additional_width + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getRenderWidth(g_Locale->getText(m_caption), true); // UTF-8 + + if (nw > m_width) + m_width = nw; + + m_window = NULL; +} + +void CHintBoxExt::paint(bool toround) +{ + if (m_window != NULL) + { + /* + * do not paint stuff twice: + * => thread safety needed by movieplayer.cpp: + * one thread calls our paint method, the other one our hide method + * => no memory leaks + */ + return; + } + + CFrameBuffer* frameBuffer = CFrameBuffer::getInstance(); + m_window = new CFBWindow(frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth() - m_width ) >> 1), + frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight() - m_height) >> 2), + m_width + borderwidth, + m_height + borderwidth); + + refresh(toround); +} + +void CHintBoxExt::refresh(bool toround) +{ + if (m_window == NULL) + { + return; + } + // bottom, right shadow + //m_window->paintBoxRel(borderwidth, m_height, m_width, borderwidth, COL_INFOBAR_SHADOW_PLUS_0); + //m_window->paintBoxRel(m_width, borderwidth, borderwidth, m_height - borderwidth, COL_INFOBAR_SHADOW_PLUS_0); + m_window->paintBoxRel(m_width-20, borderwidth, borderwidth+20, m_height - borderwidth, COL_INFOBAR_SHADOW_PLUS_0, ROUND_RADIUS, 1);//round + //m_window->paintBoxRel(borderwidth, m_height-20, m_width, borderwidth+20, COL_INFOBAR_SHADOW_PLUS_0, toround ? ROUND_RADIUS : 0, 2);//round + m_window->paintBoxRel(borderwidth, m_height-20, m_width, borderwidth+20, COL_INFOBAR_SHADOW_PLUS_0, ROUND_RADIUS, 2);//round + + // title + //m_window->paintBoxRel(0, 0, m_width, m_theight, (CFBWindow::color_t)COL_MENUHEAD_PLUS_0); + m_window->paintBoxRel(0, 0, m_width, m_theight, (CFBWindow::color_t)COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1);//round + + if (!m_iconfile.empty()) + { + m_window->paintIcon(m_iconfile.c_str(), 8, 5); + m_window->RenderString(g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE], 40, m_theight, m_width - 40, g_Locale->getText(m_caption), (CFBWindow::color_t)COL_MENUHEAD, 0, true); // UTF-8 + } + else + m_window->RenderString(g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE], 10, m_theight, m_width - 10, g_Locale->getText(m_caption), (CFBWindow::color_t)COL_MENUHEAD, 0, true); // UTF-8 + + // background of text panel + //m_window->paintBoxRel(0, m_theight, m_width, (m_maxEntriesPerPage + 1) * m_fheight, (CFBWindow::color_t)COL_MENUCONTENT_PLUS_0); + m_window->paintBoxRel(0, m_theight, m_width, (m_maxEntriesPerPage + 1) * m_fheight, (CFBWindow::color_t)COL_MENUCONTENT_PLUS_0, toround ? ROUND_RADIUS : 0, 2);//round + + int yPos = m_theight + (m_fheight >> 1); + +// for(std::vector::iterator it = m_startEntryOfPage.begin(); +// it != m_startEntryOfPage.end();it++) { +// printf(" %d",*it); +// } +// printf("\n current page: %d",m_currentPage); +// printf("von %d bis %d\n",m_startEntryOfPage[m_currentPage],m_startEntryOfPage[m_currentPage+1]-1); + + for (ContentLines::iterator it = m_lines.begin() + m_startEntryOfPage[m_currentPage]; + it != m_lines.begin() + m_startEntryOfPage[m_currentPage+1] + && it != m_lines.end(); it++) + { + int xPos = 10; + int maxHeight = 0; + for (std::vector::iterator d = it->begin();d!=it->end();d++) + { +// (*d)->print(); +// printf("\n"); + //(*d)->draw(m_window,xPos,yPos,m_width); + (*d)->draw(m_window,xPos,yPos,m_width-20); + xPos += (*d)->getWidth() + 20; + if ((*d)->getHeight() > maxHeight) + maxHeight = (*d)->getHeight(); + } + yPos += maxHeight; + } + + if (has_scrollbar()) + { +// yPos = m_theight + (m_fheight >> 1); + yPos = m_theight; + m_window->paintBoxRel(m_width - 15, yPos, 15, m_maxEntriesPerPage * m_fheight, COL_MENUCONTENT_PLUS_1); + unsigned int marker_size = (m_maxEntriesPerPage * m_fheight) / m_pages; + m_window->paintBoxRel(m_width - 13, yPos + m_currentPage * marker_size, 11, marker_size, COL_MENUCONTENT_PLUS_3); + } +} + +bool CHintBoxExt::has_scrollbar(void) +{ + return (m_startEntryOfPage.size() > 2); +} + +void CHintBoxExt::scroll_up(void) +{ + if (m_currentPage > 0) + { + m_currentPage--; + refresh(); + } +} + +void CHintBoxExt::scroll_down(void) +{ + if (m_currentPage +1 < m_startEntryOfPage.size()-1) + { + m_currentPage++; + refresh(); + } +} + +void CHintBoxExt::hide(void) +{ + if (m_window != NULL) + { + delete m_window; + m_window = NULL; + } +} diff --git a/src/gui/widget/hintboxext.h b/src/gui/widget/hintboxext.h new file mode 100644 index 000000000..9c19af80f --- /dev/null +++ b/src/gui/widget/hintboxext.h @@ -0,0 +1,84 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __hintboxext__ +#define __hintboxext__ + +#include +#include + +#include + +#include +#include + +class CHintBoxExt +{ + protected: + + CFBWindow * m_window; + + unsigned int m_currentPage; + std::vector m_startEntryOfPage; + int m_maxEntriesPerPage; + int m_pages; + + int m_width; + int m_height; + + int m_fheight; + int m_theight; + neutrino_locale_t m_caption; + char * m_message; + ContentLines m_lines; + std::string m_iconfile; + + void refresh(bool toround = 1); + + public: + CHintBoxExt(const neutrino_locale_t Caption, const char * const Text, const int Width, const char * const Icon); + + CHintBoxExt(const neutrino_locale_t Caption, ContentLines& lines, const int Width = 450, const char * const Icon = "info.raw"); + + ~CHintBoxExt(void); + + void init(const neutrino_locale_t Caption, const int Width, const char * const Icon); + + bool has_scrollbar(void); + void scroll_up(void); + void scroll_down(void); + + void paint(bool toround = 1); + void hide(void); +}; + +#endif diff --git a/src/gui/widget/icons.h b/src/gui/widget/icons.h new file mode 100644 index 000000000..707441e23 --- /dev/null +++ b/src/gui/widget/icons.h @@ -0,0 +1,97 @@ +#ifndef __gui_widget_icons_h__ +#define __gui_widget_icons_h__ + +/* + * $Header: /cvs/tuxbox/apps/tuxbox/neutrino/src/gui/widget/icons.h,v 1.18 2009/10/13 19:08:12 dbt Exp $ + * + * (C) 2003 by thegoodguy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* icon files */ + +#define NEUTRINO_ICON_BUTTON_BLUE "blau.raw" +#define NEUTRINO_ICON_BUTTON_GREEN "gruen.raw" +#define NEUTRINO_ICON_BUTTON_RED "rot.raw" +#define NEUTRINO_ICON_BUTTON_YELLOW "gelb.raw" + +#define NEUTRINO_ICON_BUTTON_DBOX "dbox.raw" +#define NEUTRINO_ICON_BUTTON_DBOX_SMALL "dbox_small.raw" +#define NEUTRINO_ICON_BUTTON_HELP "help.raw" +#define NEUTRINO_ICON_BUTTON_HELP_SMALL "help_small.raw" +#define NEUTRINO_ICON_BUTTON_HOME "home.raw" +#define NEUTRINO_ICON_BUTTON_MUTE "mute.raw" +#define NEUTRINO_ICON_BUTTON_MUTE_SMALL "mute_small.raw" +#define NEUTRINO_ICON_BUTTON_POWER "power.raw" + +#define NEUTRINO_ICON_BUTTON_OKAY "ok.raw" +#define NEUTRINO_ICON_BUTTON_OKAY_SMALL "ok_small.raw" + +#define NEUTRINO_ICON_BUTTON_0 "0.raw" +#define NEUTRINO_ICON_BUTTON_1 "1.raw" +#define NEUTRINO_ICON_BUTTON_2 "2.raw" +#define NEUTRINO_ICON_BUTTON_3 "3.raw" +#define NEUTRINO_ICON_BUTTON_4 "4.raw" +#define NEUTRINO_ICON_BUTTON_5 "5.raw" +#define NEUTRINO_ICON_BUTTON_6 "6.raw" +#define NEUTRINO_ICON_BUTTON_7 "7.raw" +#define NEUTRINO_ICON_BUTTON_8 "8.raw" +#define NEUTRINO_ICON_BUTTON_9 "9.raw" + +#define NEUTRINO_ICON_BUTTON_TOP "up.raw" +#define NEUTRINO_ICON_BUTTON_TOP_SMALL "up_small.raw" +#define NEUTRINO_ICON_BUTTON_RIGHT "right.raw" +#define NEUTRINO_ICON_BUTTON_DOWN "down.raw" +#define NEUTRINO_ICON_BUTTON_DOWN_SMALL "down_small.raw" +#define NEUTRINO_ICON_BUTTON_LEFT "left.raw" + +#define NEUTRINO_ICON_BUTTON_PLUS "plus.raw" +#define NEUTRINO_ICON_BUTTON_MINUS "minus.raw" + +#define NEUTRINO_ICON_ERROR "error.raw" +#define NEUTRINO_ICON_FILE "file.raw" +#define NEUTRINO_ICON_GAMES "games.raw" +#define NEUTRINO_ICON_INFO "info.raw" +#define NEUTRINO_ICON_MOUNTED "mounted.raw" +#define NEUTRINO_ICON_NOT_MOUNTED "not_mounted.raw" +#define NEUTRINO_ICON_RECORDING "recording.raw" +#define NEUTRINO_ICON_SETTINGS "settings.raw" +#define NEUTRINO_ICON_SHELL "shell.raw" +#define NEUTRINO_ICON_UPNP "upnp.raw" +#define NEUTRINO_ICON_PROTECTING "protecting.raw" +#define NEUTRINO_ICON_EPGINFO "epginfo.raw" +#define NEUTRINO_ICON_UPDATE "softupdate.raw" +#define NEUTRINO_ICON_FEATURES "features.raw" + +#define DUMMY_ICON "dummy.raw" + + +/* icon widths */ + +#define NEUTRINO_ICON_BUTTON_BLUE_WIDTH 16 +#define NEUTRINO_ICON_BUTTON_GREEN_WIDTH 16 +#define NEUTRINO_ICON_BUTTON_RED_WIDTH 16 +#define NEUTRINO_ICON_BUTTON_YELLOW_WIDTH 16 + +#define NEUTRINO_ICON_BUTTON_MUTE_ZAP_ACTIVE "mute_zap_green.raw" +#define NEUTRINO_ICON_BUTTON_MUTE_ZAP_INACTIVE "mute_zap_gray.raw" + +/* misc */ + +#define NEUTRINO_ICON_VARPATH "/var/share/tuxbox/neutrino/icons/" //alternatively path for user-defined icons + +#endif /* __gui_widget_icons_h__ */ diff --git a/src/gui/widget/keychooser.cpp b/src/gui/widget/keychooser.cpp new file mode 100644 index 000000000..4aee5ef17 --- /dev/null +++ b/src/gui/widget/keychooser.cpp @@ -0,0 +1,169 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include + +#define ROUND_RADIUS 9 + +class CKeyValue : public CMenuSeparator +{ + std::string the_text; +public: + int keyvalue; + + CKeyValue() : CMenuSeparator(CMenuSeparator::STRING, LOCALE_KEYCHOOSERMENU_CURRENTKEY) + { + }; + + virtual const char * getString(void) + { + the_text = g_Locale->getText(LOCALE_KEYCHOOSERMENU_CURRENTKEY); + the_text += ": "; + the_text += CRCInput::getKeyName(keyvalue); + return the_text.c_str(); + }; +}; + + + +CKeyChooser::CKeyChooser(int * const Key, const neutrino_locale_t title, const std::string & Icon) : CMenuWidget(title, Icon) +{ + frameBuffer = CFrameBuffer::getInstance(); + key = Key; + keyChooser = new CKeyChooserItem(LOCALE_KEYCHOOSER_HEAD, key); + keyDeleter = new CKeyChooserItemNoKey(key); + + addItem(new CKeyValue()); + addItem(GenericMenuSeparatorLine); + addItem(GenericMenuBack); + addItem(GenericMenuSeparatorLine); + addItem(new CMenuForwarder(LOCALE_KEYCHOOSERMENU_SETNEW , true, NULL, keyChooser)); + addItem(new CMenuForwarder(LOCALE_KEYCHOOSERMENU_SETNONE, true, NULL, keyDeleter)); +} + + +CKeyChooser::~CKeyChooser() +{ + delete keyChooser; + delete keyDeleter; +} + + +void CKeyChooser::paint() +{ + (((CKeyValue *)(items[0]))->keyvalue) = *key; + + CMenuWidget::paint(); +} + +//***************************** +CKeyChooserItem::CKeyChooserItem(const neutrino_locale_t Name, int * Key) +{ + name = Name; + key = Key; + x = y = width = height = 0; +} + + +int CKeyChooserItem::exec(CMenuTarget* parent, const std::string &) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + unsigned long long timeoutEnd; + + int res = menu_return::RETURN_REPAINT; + + if (parent) + parent->hide(); + + paint(); + + g_RCInput->clearRCMsg(); + + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + get_Message: + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if (msg != CRCInput::RC_timeout) + { + if ((msg >= 0) && (msg <= CRCInput::RC_MaxRC)) + *key = msg; + else if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) + res = menu_return::RETURN_EXIT_ALL; + else + goto get_Message; + } + + hide(); + return res; +} + +void CKeyChooserItem::hide() +{ + CFrameBuffer::getInstance()->paintBackgroundBoxRel(x, y, width, height); +} + +void CKeyChooserItem::paint() +{ + int hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + int mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + + CFrameBuffer * frameBuffer = CFrameBuffer::getInstance(); + + width = w_max(350, 0); + height = h_max(hheight + 2 * mheight, 0); + x = frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth()-width) >> 1); + y = frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight()-height) >> 1); + + //frameBuffer->paintBoxRel(x, y , width, hheight , COL_MENUHEAD_PLUS_0 ); + //frameBuffer->paintBoxRel(x, y + hheight, width, height - hheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintBoxRel(x, y , width, hheight , COL_MENUHEAD_PLUS_0 , ROUND_RADIUS, 1);//round + frameBuffer->paintBoxRel(x, y + hheight, width, height - hheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2);//round + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+ 10, y+ hheight, width, g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + + //paint msg... + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+ 10, y+ hheight+ mheight, width, g_Locale->getText(LOCALE_KEYCHOOSER_TEXT1), COL_MENUCONTENT, 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+ 10, y+ hheight+ mheight* 2, width, g_Locale->getText(LOCALE_KEYCHOOSER_TEXT2), COL_MENUCONTENT, 0, true); // UTF-8 +} diff --git a/src/gui/widget/keychooser.h b/src/gui/widget/keychooser.h new file mode 100644 index 000000000..b7162d3b8 --- /dev/null +++ b/src/gui/widget/keychooser.h @@ -0,0 +1,106 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __keychooser__ +#define __keychooser__ + +#include + +#include +#include +#include +#include + +#include "menue.h" + + +class CKeyChooserItem; +class CKeyChooserItemNoKey; +class CKeyChooser : public CMenuWidget +{ + private: + CFrameBuffer *frameBuffer; + int* key; + CKeyChooserItem *keyChooser; + CKeyChooserItemNoKey *keyDeleter; + + public: + CKeyChooser(int * const Key, const neutrino_locale_t title, const std::string & Icon = ""); + ~CKeyChooser(); + + void paint(); +}; + +class CKeyChooserItem : public CMenuTarget +{ + private: + + int x; + int y; + int width; + int height; + + neutrino_locale_t name; + int * key; + + void paint(); + + public: + + CKeyChooserItem(const neutrino_locale_t Name, int *Key); + + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); + +}; + +class CKeyChooserItemNoKey : public CMenuTarget +{ + int *key; + + public: + + CKeyChooserItemNoKey(int *Key) + { + key=Key; + }; + + int exec(CMenuTarget* parent, const std::string & actionKey) + { + *key=CRCInput::RC_nokey; + return menu_return::RETURN_REPAINT; + } + +}; + + +#endif diff --git a/src/gui/widget/lcdcontroler.cpp b/src/gui/widget/lcdcontroler.cpp new file mode 100644 index 000000000..8b9b23ce6 --- /dev/null +++ b/src/gui/widget/lcdcontroler.cpp @@ -0,0 +1,336 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#define BRIGHTNESSFACTOR 2.55 +#define CONTRASTFACTOR 0.63 + +#define ROUND_RADIUS 9 + +CLcdControler::CLcdControler(const neutrino_locale_t Name, CChangeObserver* Observer) +{ + frameBuffer = CFrameBuffer::getInstance(); + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + observer = Observer; + name = Name; + width = w_max(390, 0); + height = h_max(hheight+ mheight* 4+ +mheight/2, 0); + x = frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth()-width) >> 1); + y = frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight()-height)>>1); + + contrast = CLCD::getInstance()->getContrast(); + brightness = CLCD::getInstance()->getBrightness(); + brightnessstandby = CLCD::getInstance()->getBrightnessStandby(); +} + +void CLcdControler::setLcd() +{ +// printf("contrast: %d brightness: %d brightness standby: %d\n", contrast, brightness, brightnessstandby); + CLCD::getInstance()->setBrightness(brightness); + CLCD::getInstance()->setBrightnessStandby(brightnessstandby); + CLCD::getInstance()->setContrast(contrast); +} + +int CLcdControler::exec(CMenuTarget* parent, const std::string &) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int selected, res = menu_return::RETURN_REPAINT; + unsigned int contrast_alt, brightness_alt, brightnessstandby_alt, autodimm_alt; + + if (parent) + { + parent->hide(); + } + contrast_alt = CLCD::getInstance()->getContrast(); + brightness_alt = CLCD::getInstance()->getBrightness(); + brightnessstandby_alt = CLCD::getInstance()->getBrightnessStandby(); + autodimm_alt = CLCD::getInstance()->getAutoDimm(); + selected = 0; + + setLcd(); + CLCD::getInstance()->setAutoDimm(0); // autodimm deactivated to control and see the real settings + paint(); + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU]); + + bool loop=true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd, true ); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU]); + + switch ( msg ) + { + case CRCInput::RC_down: + if(selected < 3) // max entries + { + paintSlider(x + 10, y + hheight , contrast , CONTRASTFACTOR , LOCALE_LCDCONTROLER_CONTRAST , false); + paintSlider(x + 10, y + hheight + mheight , brightness , BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS , false); + paintSlider(x + 10, y + hheight + mheight * 2, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, false); + selected++; + switch (selected) + { + case 0: + paintSlider(x+ 10, y+ hheight, contrast, CONTRASTFACTOR, LOCALE_LCDCONTROLER_CONTRAST, true); + break; + case 1: + paintSlider(x+ 10, y+ hheight+ mheight, brightness, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS, true); + break; + case 2: + paintSlider(x+ 10, y+ hheight+ mheight* 2, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, true); + CLCD::getInstance()->setMode(CLCD::MODE_STANDBY); + break; + case 3: + frameBuffer->paintBoxRel(x, y+hheight+mheight*3+mheight/2, width, mheight, COL_MENUCONTENTSELECTED_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10, y+hheight+mheight*4+mheight/2, width, g_Locale->getText(LOCALE_OPTIONS_DEFAULT), COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + break; + } + } + break; + + case CRCInput::RC_up: + if (selected > 0) + { + paintSlider(x + 10, y + hheight , contrast , CONTRASTFACTOR , LOCALE_LCDCONTROLER_CONTRAST , false); + paintSlider(x + 10, y + hheight + mheight , brightness , BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS , false); + paintSlider(x + 10, y + hheight + mheight * 2, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, false); + selected--; + switch (selected) + { + case 0: + paintSlider(x+ 10, y+ hheight, contrast, CONTRASTFACTOR, LOCALE_LCDCONTROLER_CONTRAST, true); + break; + case 1: + paintSlider(x+ 10, y+ hheight+ mheight, brightness, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS, true); + CLCD::getInstance()->setMode(CLCD::MODE_TVRADIO); + break; + case 2: + paintSlider(x+10, y+hheight+mheight*2, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, true); + CLCD::getInstance()->setMode(CLCD::MODE_STANDBY); + frameBuffer->paintBoxRel(x, y+hheight+mheight*3+mheight/2, width, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10, y+hheight+mheight*4+mheight/2, width, g_Locale->getText(LOCALE_OPTIONS_DEFAULT), COL_MENUCONTENT, 0, true); // UTF-8 + break; + case 3: + break; + } + } + break; + + case CRCInput::RC_right: + switch (selected) + { + case 0: + if (contrast < 63) + { + int val = lrint(::log(contrast+1)); + + if (contrast + val < 63) + contrast += val; + else + contrast = 63; + + paintSlider(x+10, y+hheight, contrast, CONTRASTFACTOR, LOCALE_LCDCONTROLER_CONTRAST, true); + setLcd(); + } + break; + case 1: + if (brightness < 255) + { + if (brightness < 250) + brightness += 5; + else + brightness = 255; + + paintSlider(x+10, y+hheight+mheight, brightness, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS, true); + setLcd(); + } + break; + case 2: + if (brightnessstandby < 255) + { + if (brightnessstandby < 250) + brightnessstandby += 5; + else + brightnessstandby = 255; + + paintSlider(x+10, y+hheight+mheight*2, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, true); + setLcd(); + } + break; + } + break; + + case CRCInput::RC_left: + switch (selected) + { + case 0: + if (contrast > 0) + { + contrast -= lrint(::log(contrast)); + + paintSlider(x+10, y+hheight, contrast, CONTRASTFACTOR, LOCALE_LCDCONTROLER_CONTRAST, true); + setLcd(); + } + break; + case 1: + if (brightness > 0) + { + if (brightness > 5) + brightness -= 5; + else + brightness = 0; + + paintSlider(x+10, y+hheight+mheight, brightness, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS, true); + setLcd(); + } + break; + case 2: + if (brightnessstandby > 0) + { + if (brightnessstandby > 5) + brightnessstandby -= 5; + else + brightnessstandby = 0; + + paintSlider(x+10, y+hheight+mheight*2, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, true); + setLcd(); + } + break; + } + break; + + case CRCInput::RC_home: + if ( ( (contrast != contrast_alt) || (brightness != brightness_alt) || (brightnessstandby != brightnessstandby_alt) ) && + (ShowLocalizedMessage(name, LOCALE_MESSAGEBOX_DISCARD, CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbCancel) == CMessageBox::mbrCancel)) + break; + + // sonst abbruch... + contrast = contrast_alt; + brightness = brightness_alt; + brightnessstandby = brightnessstandby_alt; + setLcd(); + loop = false; + break; + + case CRCInput::RC_ok: + if (selected==3) // default Werte benutzen + { + brightness = DEFAULT_LCD_BRIGHTNESS; + brightnessstandby = DEFAULT_LCD_STANDBYBRIGHTNESS; + contrast = DEFAULT_LCD_CONTRAST; + selected = 0; + setLcd(); + paint(); + break; + } + + case CRCInput::RC_timeout: + loop = false; + break; + + default: + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + + CLCD::getInstance()->setAutoDimm(autodimm_alt); + hide(); + + if(observer) + observer->changeNotify(name, NULL); + + return res; +} + +void CLcdControler::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height); +} + +void CLcdControler::paint() +{ + CLCD::getInstance()->setMode(CLCD::MODE_TVRADIO); + + //frameBuffer->paintBoxRel(x,y, width,hheight, COL_MENUHEAD_PLUS_0); + //frameBuffer->paintBoxRel(x,y+hheight, width,height-hheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintBoxRel(x,y, width,hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1);//round + frameBuffer->paintBoxRel(x,y+hheight, width,height-hheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2);//round + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10,y+hheight, width, g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + + paintSlider(x+10, y+hheight, contrast, CONTRASTFACTOR, LOCALE_LCDCONTROLER_CONTRAST, true); + paintSlider(x+10, y+hheight+mheight, brightness, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS, false); + paintSlider(x+10, y+hheight+mheight*2, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, false); + + frameBuffer->paintHLineRel(x+10, width-20, y+hheight+mheight*3+mheight/4, COL_MENUCONTENT_PLUS_3); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10, y+hheight+mheight*4+mheight/2, width, g_Locale->getText(LOCALE_OPTIONS_DEFAULT), COL_MENUCONTENT, 0, true); // UTF-8 +} + +void CLcdControler::paintSlider(int x, int y, unsigned int spos, float factor, const neutrino_locale_t text, bool selected) +{ + int startx = 200; + char wert[5]; + + frameBuffer->paintBoxRel(x + startx, y, 120, mheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintIcon("volumebody.raw", x + startx, y+2+mheight/4); + frameBuffer->paintIcon(selected ? "volumeslider2blue.raw" : "volumeslider2.raw", (int)(x + (startx+3)+(spos / factor)), y+mheight/4); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x, y+mheight, width, g_Locale->getText(text), COL_MENUCONTENT, 0, true); // UTF-8 + sprintf(wert, "%3d", spos); // UTF-8 encoded + frameBuffer->paintBoxRel(x + startx + 120 + 10, y, 50, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x + startx + 120 + 10, y+mheight, width, wert, COL_MENUCONTENT, 0, true); // UTF-8 +} diff --git a/src/gui/widget/lcdcontroler.h b/src/gui/widget/lcdcontroler.h new file mode 100644 index 000000000..2c7c80c79 --- /dev/null +++ b/src/gui/widget/lcdcontroler.h @@ -0,0 +1,75 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __lcdcontroler__ +#define __lcdcontroler__ + +#include +#include + +#include "menue.h" + +#include + +class CLcdControler : public CMenuTarget +{ + private: + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hheight,mheight; // head/menu font height + + unsigned char contrast; + unsigned char brightness; + unsigned char brightnessstandby; + + neutrino_locale_t name; + + CChangeObserver* observer; + + void paint(); + void setLcd(); + void paintSlider(int x, int y, unsigned int spos, float factor, const neutrino_locale_t text, bool selected); + + public: + + CLcdControler(const neutrino_locale_t Name, CChangeObserver* Observer = NULL); + + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); + +}; + + +#endif diff --git a/src/gui/widget/listbox.cpp b/src/gui/widget/listbox.cpp new file mode 100644 index 000000000..93d5162b5 --- /dev/null +++ b/src/gui/widget/listbox.cpp @@ -0,0 +1,255 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#define ROUND_RADIUS 9 + +CListBox::CListBox(const char * const Caption) +{ + frameBuffer = CFrameBuffer::getInstance(); + caption = Caption; + liststart = 0; + selected = 0; + width = 400; + height = 420; + ButtonHeight = 25; + modified = false; + theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + fheight = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getHeight(); + listmaxshow = (height-theight-0)/fheight; + height = theight+0+listmaxshow*fheight; // recalc height + + x=frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth() - width) / 2); + y=frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight() - height) / 2); +} + +void CListBox::setModified(void) +{ + modified = true; +} + +void CListBox::paint() +{ + liststart = (selected/listmaxshow)*listmaxshow; + + for(unsigned int count=0;countpaintBoxRel(x+ width- 15,ypos, 15, sb, COL_MENUCONTENT_PLUS_1); + + int sbc= ((getItemCount()- 1)/ listmaxshow)+ 1; + float sbh= (sb- 4)/ sbc; + int sbs= (selected/listmaxshow); + + frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ int(sbs* sbh) , 11, int(sbh), COL_MENUCONTENT_PLUS_3); +} + +void CListBox::paintHead() +{ + //frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0); + frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1);//round + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10,y+theight+0, width, caption.c_str() , COL_MENUHEAD, 0, true); +} + +void CListBox::paintFoot() +{ + int ButtonWidth = width / 4; + //frameBuffer->paintBoxRel(x,y+height, width,ButtonHeight, COL_MENUHEAD_PLUS_0); + frameBuffer->paintBoxRel(x,y+height, width,ButtonHeight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2);//round + frameBuffer->paintHLine(x, x+width, y, COL_INFOBAR_SHADOW_PLUS_0); + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, x+width- 4* ButtonWidth+ 8, y+height+1); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+width- 4* ButtonWidth+ 38, y+height+24 - 2, width, "edit", COL_INFOBAR); + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_GREEN, x+width- 3* ButtonWidth+ 8, y+height+4); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+width- 3* ButtonWidth+ 29, y+height+24 - 2, width- 26, "add", COL_INFOBAR); + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_RED, x+width- 2* ButtonWidth+ 8, y+height+4); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+width- 2* ButtonWidth+ 29, y+height+24 - 2, width- 26, "remove", COL_INFOBAR); + + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HOME, x+width - ButtonWidth+ 8, y+height+1); + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x+width - ButtonWidth+ 38, y+height+24 - 2, width, "ready", COL_INFOBAR); +} + +void CListBox::paintItem(int pos) +{ + paintItem(liststart+pos, pos, (liststart+pos==selected) ); +} + +void CListBox::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height+ButtonHeight); +} + +unsigned int CListBox::getItemCount() +{ + return 10; +} + +int CListBox::getItemHeight() +{ + return fheight; +} + +void CListBox::paintItem(unsigned int itemNr, int paintNr, bool selected) +{ + int ypos = y+ theight + paintNr*getItemHeight(); + + uint8_t color; + fb_pixel_t bgcolor; + + if (selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + else + { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + } + + frameBuffer->paintBoxRel(x,ypos, width- 15, getItemHeight(), bgcolor); + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x + 10, ypos+ fheight, width-20, "demo", color); +} + +int CListBox::exec(CMenuTarget* parent, const std::string & actionKey) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = menu_return::RETURN_REPAINT; + selected=0; + + if (parent) + { + parent->hide(); + } + + paintHead(); + paint(); + paintFoot(); + + bool loop=true; + modified = false; + while (loop) + { + g_RCInput->getMsg(&msg, &data, g_settings.timing[SNeutrinoSettings::TIMING_EPG]); + + if (( msg == (neutrino_msg_t)g_settings.key_channelList_cancel) || + ( msg == CRCInput::RC_home)) + { + loop = false; + } + else if (msg == CRCInput::RC_up || (int) msg == g_settings.key_channelList_pageup) + { + if(getItemCount()!=0) { + int step = 0; + int prev_selected = selected; + + step = ((int) msg == g_settings.key_channelList_pageup) ? listmaxshow : 1; // browse or step 1 + selected -= step; + if((prev_selected-step) < 0) // because of uint + selected = getItemCount() - 1; + + paintItem(prev_selected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + + if(oldliststart!=liststart) + paint(); + else + paintItem(selected - liststart); + } + } + else if (msg == CRCInput::RC_down || (int) msg == g_settings.key_channelList_pagedown) + { + if(getItemCount()!=0) { + unsigned int step = 0; + int prev_selected = selected; + + step = ((int) msg == g_settings.key_channelList_pagedown) ? listmaxshow : 1; // browse or step 1 + selected += step; + + if(selected >= getItemCount()) { + if (((getItemCount() / listmaxshow) + 1) * listmaxshow == getItemCount() + listmaxshow) // last page has full entries + selected = 0; + else + selected = ((step == listmaxshow) && (selected < (((getItemCount() / listmaxshow) + 1) * listmaxshow))) ? (getItemCount() - 1) : 0; + } + + paintItem(prev_selected - liststart); + unsigned int oldliststart = liststart; + liststart = (selected/listmaxshow)*listmaxshow; + if(oldliststart!=liststart) + paint(); + else + paintItem(selected - liststart); + } + } + else if( msg ==CRCInput::RC_ok) + { + onOkKeyPressed(); + } + else if ( msg ==CRCInput::RC_red) + { + onRedKeyPressed(); + } + else if ( msg ==CRCInput::RC_green) + { + onGreenKeyPressed(); + } + else if ( msg ==CRCInput::RC_yellow) + { + onYellowKeyPressed(); + } + else if ( msg ==CRCInput::RC_blue) + { + onBlueKeyPressed(); + } + else if ((msg ==CRCInput::RC_sat) || (msg == CRCInput::RC_favorites)) + { + } + else + { + CNeutrinoApp::getInstance()->handleMsg( msg, data ); + // kein canceling... + } + } + + hide(); + return res; +} diff --git a/src/gui/widget/listbox.h b/src/gui/widget/listbox.h new file mode 100644 index 000000000..8c1565a09 --- /dev/null +++ b/src/gui/widget/listbox.h @@ -0,0 +1,89 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __listbox__ +#define __listbox__ + +#include "menue.h" + +#include + +#include + +class CListBox : public CMenuWidget +{ + protected: + CFrameBuffer* frameBuffer; + bool modified; + std::string caption; + int width; + int height; + int x; + int y; + + int fheight; + int theight; + + unsigned int selected; + unsigned int liststart; + unsigned int listmaxshow; + + int ButtonHeight; + + //---------------------------- + + virtual void paintItem(int pos); + virtual void paint(); + virtual void paintHead(); + virtual void paintFoot(); + virtual void hide(); + + + //------hier Methoden überschreiben------- + + //------Fernbedienungsevents-------------- + virtual void onRedKeyPressed(){}; + virtual void onGreenKeyPressed(){}; + virtual void onYellowKeyPressed(){}; + virtual void onBlueKeyPressed(){}; + virtual void onOkKeyPressed(){}; + virtual void onOtherKeyPressed( int key ){}; + + //------gibt die Anzahl der Listenitems--- + virtual unsigned int getItemCount(); + + //------malen der Items------------------- + virtual int getItemHeight(); + virtual void paintItem(uint32_t itemNr, int paintNr, bool selected); + + //------Benutzung von setModified--------- + void setModified(void); + + public: + CListBox(const char * const Caption); + virtual int exec(CMenuTarget* parent, const std::string & actionKey); +}; + + +#endif diff --git a/src/gui/widget/listbox_legacy.cpp b/src/gui/widget/listbox_legacy.cpp new file mode 100644 index 000000000..0c00ea0fe --- /dev/null +++ b/src/gui/widget/listbox_legacy.cpp @@ -0,0 +1,58 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2003 thegoodguy + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "listbox_legacy.h" + +#include + +CListBoxExt::CListBoxExt(void) : CListBox("") +{ + saveBoxCaption = NONEXISTANT_LOCALE; + saveBoxText = NULL; +} + +void CListBoxExt::setTitle(const char * const title) +{ + caption = title ? title : ""; +} + +void CListBoxExt::hide() +{ + //want2save? + if ((modified) && (saveBoxCaption != NONEXISTANT_LOCALE) && (saveBoxText != NULL)) + { + if (ShowMsgUTF(saveBoxCaption, saveBoxText, CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo) == CMessageBox::mbrYes) // UTF-8 + onSaveData(); + } + + CListBox::hide(); +} + +void CListBoxExt::setSaveDialogText(const neutrino_locale_t title, const char * const text) +{ + saveBoxCaption = title; + saveBoxText = text; +} diff --git a/src/gui/widget/listbox_legacy.h b/src/gui/widget/listbox_legacy.h new file mode 100644 index 000000000..14b729374 --- /dev/null +++ b/src/gui/widget/listbox_legacy.h @@ -0,0 +1,46 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2003 thegoodguy + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __listbox_legacy__ +#define __listbox_legacy__ + +#include "listbox.h" + +class CListBoxExt : public CListBox +{ + protected: + neutrino_locale_t saveBoxCaption; + const char * saveBoxText; + + void setTitle(const char * const title); + + virtual void hide(); + void setSaveDialogText(const neutrino_locale_t title, const char * const text); + virtual void onSaveData(){}; + + public: + CListBoxExt(void); +}; + + +#endif diff --git a/src/gui/widget/listframe.cpp b/src/gui/widget/listframe.cpp new file mode 100644 index 000000000..5130c43e0 --- /dev/null +++ b/src/gui/widget/listframe.cpp @@ -0,0 +1,679 @@ +/*************************************************************************** + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + *********************************************************** + + Module Name: listframe.cpp . + + Description: Implementation of the CListFrame class + This class provides a plain Listbox with numerous rows and lines. + + Date: Nov 2005 + + Author: Günther@tuxbox.berlios.org + based on code of Steffen Hehn 'McClean' + + Revision History: + Date Author Change Description + Nov 2005 Günther initial implementation + +****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define ROUND_RADIUS 9 + +#include "stdlib.h" +#include "listframe.h" +#include + +#define TEXT_BORDER_WIDTH 8 +#define ROW_BORDER_WIDTH 4 +#define SCROLL_FRAME_WIDTH 10 +#define SCROLL_MARKER_BORDER 2 + +#define MAX_WINDOW_WIDTH (frameBuffer->getScreenWidth() - 40) +#define MAX_WINDOW_HEIGHT (frameBuffer->getScreenHeight() - 40) + +#define MIN_WINDOW_WIDTH (frameBuffer->getScreenWidth() >> 1) +#define MIN_WINDOW_HEIGHT 40 + +#define TITLE_BACKGROUND_COLOR ((CFBWindow::color_t)COL_MENUHEAD_PLUS_0) +#define HEADER_LIST_BACKGROUND_COLOR ((CFBWindow::color_t)COL_MENUCONTENT_PLUS_0) +#define LIST_BACKGROUND_COLOR ((CFBWindow::color_t)COL_MENUCONTENT_PLUS_0) +//#define LIST_BACKGROUND_COLOR_SELECTED ((CFBWindow::color_t)COL_MENUCONTENT_PLUS_1) +#define LIST_BACKGROUND_COLOR_SELECTED ((CFBWindow::color_t)COL_MENUCONTENTSELECTED_PLUS_0) + +#define TITLE_FONT_COLOR COL_MENUHEAD +#define HEADER_LIST_FONT_COLOR COL_MENUCONTENT +#define LIST_FONT_COLOR COL_MENUCONTENT +//#define LIST_FONT_COLOR_SELECTED COL_MENUCONTENT +#define LIST_FONT_COLOR_SELECTED COL_MENUCONTENTSELECTED + +#define FONT_LIST g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO2] +#define FONT_HEADER_LIST g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1] +#define FONT_TITLE g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CListFrame::CListFrame( LF_LINES* lines, Font* font_text, const int mode, + const CBox* position, const char* textTitle, Font* font_title) +{ + //TRACE("[CListFrame] new\r\n"); + initVar(); + + if(lines != NULL) { + m_pLines = lines; + m_nNrOfRows = lines->rows; + if(m_nNrOfRows > LF_MAX_ROWS) + m_nNrOfRows = LF_MAX_ROWS; + } + if(font_text != NULL) m_pcFontList = font_text; + if(font_text != NULL) m_pcFontHeaderList = font_text; + if(position != NULL) { + m_cFrame = *position; + m_nMaxHeight = m_cFrame.iHeight; + m_nMaxWidth = m_cFrame.iWidth; + } + + m_nMode = mode; + +#if 0 + TRACE(" Mode: "); + if(mode & SCROLL) TRACE("SCROLL "); + if(mode & AUTO_WIDTH) TRACE("AUTO_WIDTH "); + if(mode & AUTO_HIGH) TRACE("AUTO_HIGH"); + TRACE("\r\n"); +#endif + + if(font_title != NULL) + m_pcFontTitle = font_title; + + if( textTitle != NULL) + m_textTitle = textTitle; + + m_nFontListHeight = m_pcFontList->getHeight(); + m_nFontHeaderListHeight = m_pcFontHeaderList->getHeight(); + m_nFontTitleHeight = m_pcFontTitle->getHeight(); + + //TRACE(" CListFrame::m_nFontTextHeight: %d\t\r\n",m_nFontListHeight); + + /* Initialise the window frames first */ + initFramesRel(); + + // than refresh text line array + onNewLineArray(); +} + +CListFrame::CListFrame( LF_LINES* lines) +{ + //TRACE("[CListFrame] new\r\n"); + initVar(); + + if(lines != NULL) + { + m_pLines = lines; + m_nNrOfRows = lines->rows; + if(m_nNrOfRows > LF_MAX_ROWS) + m_nNrOfRows = LF_MAX_ROWS; + } + + /* Initialise the window frames first */ + initFramesRel(); + + // than refresh text line array + onNewLineArray(); +} + +CListFrame::CListFrame() +{ + //TRACE("[CListFrame] new\r\n"); + initVar(); + initFramesRel(); + + m_pLines = NULL; +} + +CListFrame::~CListFrame() +{ + //TRACE("[CListFrame] del\r\n"); + hide(); +} + +void CListFrame::initVar(void) +{ + frameBuffer = CFrameBuffer::getInstance(); + //TRACE("[CListFrame]->InitVar\r\n"); + m_nMode = SCROLL; + + m_showSelection = true; + + m_pcFontList = FONT_LIST ; + m_nFontListHeight = m_pcFontList->getHeight(); + + m_pcFontHeaderList = FONT_HEADER_LIST ; + m_nFontHeaderListHeight = m_pcFontHeaderList->getHeight(); + + m_pcFontTitle = FONT_TITLE; + m_textTitle = "MovieBrowser"; + m_nFontTitleHeight = m_pcFontTitle->getHeight(); + + m_nNrOfPages = 1; + m_nNrOfLines = 0; + m_nNrOfRows = 1; + m_nLinesPerPage = 0; + m_nCurrentLine = 0; + m_nCurrentPage = 0; + m_nSelectedLine = 0; + + m_cFrame.iX = frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth() - MIN_WINDOW_WIDTH) >>1); + m_cFrame.iWidth = MIN_WINDOW_WIDTH; + m_cFrame.iY = frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight() - MIN_WINDOW_HEIGHT) >>1); + m_cFrame.iHeight = MIN_WINDOW_HEIGHT; + + m_nMaxHeight = MAX_WINDOW_HEIGHT; + m_nMaxWidth = MAX_WINDOW_WIDTH; + frameBuffer = NULL; +} + +void CListFrame::reSizeMainFrameWidth(int textWidth) +{ + //TRACE("[CListFrame]->ReSizeMainFrameWidth: %d, current: %d\r\n",textWidth,m_cFrameListRel.iWidth); + + int iNewWindowWidth = textWidth + m_cFrameScrollRel.iWidth + 2*TEXT_BORDER_WIDTH; + + if( iNewWindowWidth > m_nMaxWidth) iNewWindowWidth = m_nMaxWidth; + if((unsigned int) iNewWindowWidth < MIN_WINDOW_WIDTH) iNewWindowWidth = MIN_WINDOW_WIDTH; + + m_cFrame.iWidth = iNewWindowWidth; + + /* Re-Init the children frames due to new main window */ + initFramesRel(); +} + +void CListFrame::reSizeMainFrameHeight(int textHeight) +{ + //TRACE("[CListFrame]->ReSizeMainFrameHeight: %d, current: %d\r\n",textHeight,m_cFrameListRel.iHeight); + + int iNewWindowHeight = textHeight + 2*TEXT_BORDER_WIDTH; + + if( iNewWindowHeight > m_nMaxHeight) iNewWindowHeight = m_nMaxHeight; + if( iNewWindowHeight < MIN_WINDOW_HEIGHT) iNewWindowHeight = MIN_WINDOW_HEIGHT; + + m_cFrame.iHeight = iNewWindowHeight; + + /* Re-Init the children frames due to new main window */ + initFramesRel(); +} + +void CListFrame::initFramesRel(void) +{ + //TRACE("-[CListFrame]->InitFramesRel\r\n"); + + if(m_nMode & TITLE) + { + m_cFrameTitleRel.iX = 0; + m_cFrameTitleRel.iY = 0; + m_cFrameTitleRel.iHeight = m_nFontTitleHeight +2 ; + m_cFrameTitleRel.iWidth = m_cFrame.iWidth ; + } + else + { + m_cFrameTitleRel.iX = 0; + m_cFrameTitleRel.iY = 0; + m_cFrameTitleRel.iHeight= 0; + m_cFrameTitleRel.iWidth = 0; + } + + if(m_nMode & HEADER_LINE) + { + m_cFrameHeaderListRel.iX = 0; + m_cFrameHeaderListRel.iY = 0 + m_cFrameTitleRel.iHeight; + m_cFrameHeaderListRel.iHeight = m_nFontHeaderListHeight ; + } + else + { + m_cFrameHeaderListRel.iX = 0; + m_cFrameHeaderListRel.iY = 0; + m_cFrameHeaderListRel.iHeight = 0; + m_cFrameHeaderListRel.iWidth = 0; + } + + m_cFrameListRel.iX = 0; + m_cFrameListRel.iY = m_cFrameHeaderListRel.iHeight + m_cFrameTitleRel.iHeight; + m_cFrameListRel.iHeight = m_cFrame.iHeight - m_cFrameHeaderListRel.iHeight - m_cFrameTitleRel.iHeight; + + if(m_nMode & SCROLL) + { + m_cFrameScrollRel.iX = m_cFrame.iWidth - SCROLL_FRAME_WIDTH; + m_cFrameScrollRel.iY = m_cFrameTitleRel.iHeight; + m_cFrameScrollRel.iWidth = SCROLL_FRAME_WIDTH; + m_cFrameScrollRel.iHeight = m_cFrameListRel.iHeight + m_cFrameHeaderListRel.iHeight; + } + else + { + m_cFrameScrollRel.iX = 0; + m_cFrameScrollRel.iY = 0; + m_cFrameScrollRel.iHeight = 0; + m_cFrameScrollRel.iWidth = 0; + } + + m_cFrameListRel.iWidth = m_cFrame.iWidth - m_cFrameScrollRel.iWidth; + + if(m_nMode & HEADER_LINE) + { + m_cFrameHeaderListRel.iWidth = m_cFrame.iWidth - m_cFrameScrollRel.iWidth; + } + + m_nLinesPerPage = (m_cFrameListRel.iHeight - (2*TEXT_BORDER_WIDTH)) / m_nFontListHeight; +} + +void CListFrame::onNewLineArray(void) +{ + //TRACE("[CListFrame]->onNewLineArray \r\n"); + int maxTextWidth = 0; + + maxTextWidth = 300; // TODO + m_nNrOfLines = m_pLines->lineArray[0].size(); + if(m_nNrOfLines > 0 ) + { + /* check if we have to recalculate the window frame size, due to auto width and auto height */ + if( m_nMode & AUTO_WIDTH) + { + reSizeMainFrameWidth(maxTextWidth); + } + + if(m_nMode & AUTO_HIGH) + { + reSizeMainFrameHeight(m_nNrOfLines * m_nFontListHeight); + } + m_nLinesPerPage = (m_cFrameListRel.iHeight - (2*TEXT_BORDER_WIDTH)) / m_nFontListHeight; + + if(m_nLinesPerPage <= 0) + m_nLinesPerPage = 1; + + m_nNrOfPages = ((m_nNrOfLines-1) / m_nLinesPerPage) + 1; + + if(m_nCurrentLine >= m_nNrOfLines) + { + m_nCurrentPage = m_nNrOfPages - 1; + m_nCurrentLine = m_nCurrentPage * m_nLinesPerPage; + } + if(m_nSelectedLine >= m_nNrOfLines) + { + m_nSelectedLine = m_nCurrentLine; + } + } + else + { + m_nNrOfLines = 0; + m_nCurrentLine = 0; + m_nSelectedLine = 0; + m_nLinesPerPage = 1; + m_nNrOfPages = 0; + } + +// TRACE_1(" m_nNrOfPages: %d\r\n",m_nNrOfPages); +// TRACE_1(" m_nNrOfLines: %d\r\n",m_nNrOfLines); +// TRACE_1(" maxTextWidth: %d\r\n",maxTextWidth); +// TRACE_1(" m_nLinesPerPage: %d\r\n",m_nLinesPerPage); +// TRACE_1(" m_nFontTextHeight:%d\r\n",m_nFontListHeight); + //TRACE_1(" m_nCurrentPage: %d\r\n",m_nCurrentPage); + //TRACE_1(" m_nCurrentLine: %d\r\n",m_nCurrentLine); +} + +void CListFrame::refreshTitle(void) +{ + //TRACE("[CListFrame]->refreshHeaderList \r\n"); + if( frameBuffer == NULL) return; + + frameBuffer->paintBoxRel(m_cFrameTitleRel.iX+m_cFrame.iX, m_cFrameTitleRel.iY+m_cFrame.iY, + m_cFrameTitleRel.iWidth, m_cFrameTitleRel.iHeight, TITLE_BACKGROUND_COLOR); + + m_pcFontTitle->RenderString(m_cFrameTitleRel.iX + TEXT_BORDER_WIDTH + m_cFrame.iX, + m_cFrameTitleRel.iY + m_cFrameTitleRel.iHeight + m_cFrame.iY, + m_cFrameTitleRel.iWidth - (TEXT_BORDER_WIDTH << 1), + m_textTitle.c_str(), TITLE_FONT_COLOR, 0, true); // UTF-8 +} + +void CListFrame::refreshScroll(void) +{ + //TRACE("[CListFrame]->refreshScroll\r\n"); + if( frameBuffer == NULL) return; + if(!(m_nMode & SCROLL)) return; + + if (m_nNrOfPages > 1) + { + frameBuffer->paintBoxRel(m_cFrameScrollRel.iX+m_cFrame.iX, m_cFrameScrollRel.iY+m_cFrame.iY, + m_cFrameScrollRel.iWidth, m_cFrameScrollRel.iHeight, COL_MENUCONTENT_PLUS_1); + unsigned int marker_size = m_cFrameScrollRel.iHeight / m_nNrOfPages; + frameBuffer->paintBoxRel(m_cFrameScrollRel.iX + SCROLL_MARKER_BORDER+m_cFrame.iX, + m_cFrameScrollRel.iY + m_nCurrentPage * marker_size +m_cFrame.iY, + m_cFrameScrollRel.iWidth - (2*SCROLL_MARKER_BORDER), + marker_size, COL_MENUCONTENT_PLUS_3); + } + else + { + frameBuffer->paintBoxRel(m_cFrameScrollRel.iX+m_cFrame.iX, m_cFrameScrollRel.iY+m_cFrame.iY, + m_cFrameScrollRel.iWidth, m_cFrameScrollRel.iHeight, COL_MENUCONTENT_PLUS_0); + } +} + +void CListFrame::refreshList(void) +{ + //TRACE("[CListFrame]->refreshList: %d\r\n",m_nCurrentLine); + if( frameBuffer == NULL) return; + frameBuffer->paintBoxRel(m_cFrameListRel.iX+m_cFrame.iX, m_cFrameListRel.iY+m_cFrame.iY, + m_cFrameListRel.iWidth, m_cFrameListRel.iHeight, LIST_BACKGROUND_COLOR); + + if( m_nNrOfLines <= 0) + return; + + int y = m_cFrameListRel.iY + TEXT_BORDER_WIDTH ; + for(int line = m_nCurrentLine; + line < m_nNrOfLines && line < m_nCurrentLine + m_nLinesPerPage; + line++) + { + int color = LIST_FONT_COLOR; + // draw line + if(line == m_nSelectedLine && m_showSelection == true) + { + color = LIST_FONT_COLOR_SELECTED; + frameBuffer->paintBoxRel(m_cFrameListRel.iX+m_cFrame.iX, + y+m_cFrame.iY, m_cFrameListRel.iWidth, + m_nFontListHeight, LIST_BACKGROUND_COLOR_SELECTED, + ROUND_RADIUS, 3); + } + int width; + int x = m_cFrameListRel.iX + TEXT_BORDER_WIDTH; + y += m_nFontListHeight; + for(int row = 0; row < m_pLines->rows; row++) + { + width = m_pLines->rowWidth[row] ; + if(width > m_cFrameListRel.iWidth - x + m_cFrameListRel.iX - TEXT_BORDER_WIDTH) + { + width = m_cFrameListRel.iWidth - x + m_cFrameListRel.iX - TEXT_BORDER_WIDTH; + //TRACE(" normalize width to %d , x:%d \r\n",width,x); + } + m_pcFontList->RenderString(x+m_cFrame.iX, y+m_cFrame.iY, + width, m_pLines->lineArray[row][line].c_str(), + color, 0, true); // UTF-8 + x += m_pLines->rowWidth[row] + ROW_BORDER_WIDTH; + } + } +} + +void CListFrame::refreshLine(int line) +{ + if( frameBuffer == NULL) return; + if( m_nNrOfLines <= 0) return; + + if((line < m_nCurrentLine) && (line > m_nCurrentLine + m_nLinesPerPage)) + return; + + uint8_t color; + int rel_line = line - m_nCurrentLine; + int y = m_cFrameListRel.iY + TEXT_BORDER_WIDTH + (rel_line*m_nFontListHeight); + + if(line == m_nSelectedLine && m_showSelection == true) + { + color = LIST_FONT_COLOR_SELECTED; + frameBuffer->paintBoxRel(m_cFrameListRel.iX+m_cFrame.iX, y+m_cFrame.iY, + m_cFrameListRel.iWidth, m_nFontListHeight, LIST_BACKGROUND_COLOR_SELECTED, + ROUND_RADIUS, 3); + } + else + { + color = LIST_FONT_COLOR; + frameBuffer->paintBoxRel(m_cFrameListRel.iX+m_cFrame.iX, y+m_cFrame.iY, + m_cFrameListRel.iWidth, m_nFontListHeight, LIST_BACKGROUND_COLOR); + } + int width; + int x = m_cFrameListRel.iX + TEXT_BORDER_WIDTH; + y += m_nFontListHeight; + for(int row = 0; row < m_pLines->rows; row++) + { + width = m_pLines->rowWidth[row] ; + if(width > m_cFrameListRel.iWidth - x + m_cFrameListRel.iX - 2*TEXT_BORDER_WIDTH) + { + width = m_cFrameListRel.iWidth - x + m_cFrameListRel.iX - 2*TEXT_BORDER_WIDTH; + //TRACE(" normalize to %d,x:%d\r\n",width,x); + } + m_pcFontList->RenderString(x+m_cFrame.iX, y+m_cFrame.iY, + width, m_pLines->lineArray[row][line].c_str(), + color, 0, true); // UTF-8 + x += m_pLines->rowWidth[row] + ROW_BORDER_WIDTH; + } +} + +void CListFrame::refreshHeaderList(void) +{ + //TRACE("[CListFrame]->refreshHeaderList \r\n"); + if( frameBuffer == NULL) return; + if(!(m_nMode & HEADER_LINE))return; + + frameBuffer->paintBoxRel(m_cFrameHeaderListRel.iX+m_cFrame.iX, m_cFrameHeaderListRel.iY+m_cFrame.iY, + m_cFrameHeaderListRel.iWidth, m_cFrameHeaderListRel.iHeight, HEADER_LIST_BACKGROUND_COLOR); + + int width; + int x = m_cFrameHeaderListRel.iX + TEXT_BORDER_WIDTH; + int y = m_cFrameHeaderListRel.iY + m_nFontHeaderListHeight + 2; + bool loop = true; + for(int row = 0; row < m_pLines->rows && loop == true; row++) + { + width = m_pLines->rowWidth[row] ; + if(width > m_cFrameHeaderListRel.iWidth - x + m_cFrameHeaderListRel.iX - 2*TEXT_BORDER_WIDTH) + { + width = m_cFrameHeaderListRel.iWidth - x + m_cFrameHeaderListRel.iX - 2*TEXT_BORDER_WIDTH; + //TRACE(" normalize width to %d , x:%d \r\n",width,x); + loop = false; + } + m_pcFontHeaderList->RenderString(x+m_cFrame.iX, y+m_cFrame.iY, + width, m_pLines->lineHeader[row].c_str(), + HEADER_LIST_FONT_COLOR, 0, true); // UTF-8 + x += m_pLines->rowWidth[row] + ROW_BORDER_WIDTH; + } +} + +void CListFrame::scrollLineDown(const int lines) +{ + //TRACE("[CListFrame]->scrollLineDown \r\n"); + + if( !(m_nMode & SCROLL)) return; + if( m_nNrOfLines <= 1) return; + + if(m_nSelectedLine < m_nNrOfLines - 1) { + m_nSelectedLine++; + // check if the cursor moves out of the window + if(m_nSelectedLine - m_nCurrentLine > m_nLinesPerPage-1) { + // yes, scroll to next page + //TRACE("[CListFrame] m_nSelectedLine: %d, \r\n",m_nSelectedLine); + scrollPageDown(1); + } else { + refreshLine(m_nSelectedLine-lines); + refreshLine(m_nSelectedLine); + } + } else { + m_nCurrentPage = 0; + m_nCurrentLine = m_nSelectedLine = 0; + refreshList(); + } + +} + +void CListFrame::scrollLineUp(const int lines) +{ + //TRACE("[CListFrame]->scrollLineUp \r\n"); + if( !(m_nMode & SCROLL)) return; + if( m_nNrOfLines <= 1) return; + + if(m_nSelectedLine > 0) { + m_nSelectedLine--; + // check if the cursor moves out of the window + if(m_nSelectedLine < m_nCurrentLine ) { + // yes, scroll to next page + //TRACE("[CListFrame] m_nSelectedLine: %d, \r\n",m_nSelectedLine); + scrollPageUp(1); + } else { + refreshLine(m_nSelectedLine+lines); + refreshLine(m_nSelectedLine); + } + } else if(m_nSelectedLine == 0) { + //m_nCurrentPage = m_nNrOfPages - 1; + //m_nCurrentLine = m_nSelectedLine = m_nNrOfLines - 1; + //refresh(); + setSelectedLine(m_nNrOfLines - 1); + } +} + +void CListFrame::scrollPageDown(const int pages) +{ + //TRACE("[CListFrame]->ScrollPageDown \r\n"); + + if( !(m_nMode & SCROLL)) return; + if( m_nNrOfLines <= 1) return; + + if(m_nCurrentPage + pages < m_nNrOfPages) + { + m_nCurrentPage += pages; + } + else + { + m_nCurrentPage = m_nNrOfPages - 1; + } + m_nCurrentLine = m_nCurrentPage * m_nLinesPerPage; + if(m_nSelectedLine < m_nCurrentLine || m_nSelectedLine -m_nCurrentLine >= m_nLinesPerPage ) + { + m_nSelectedLine = m_nCurrentLine; + } + //TRACE("[CListFrame] m_nCurrentLine: %d, m_nCurrentPage: %d \r\n",m_nCurrentLine,m_nCurrentPage); + refresh(); +}; + +void CListFrame::scrollPageUp(const int pages) +{ + //TRACE("[CListFrame]->ScrollPageUp \r\n"); + + if( !(m_nMode & SCROLL)) return; + if( m_nNrOfLines <= 1) return; + + if(m_nCurrentPage - pages > 0) + { + m_nCurrentPage -= pages; + } + else + { + m_nCurrentPage = 0; + } + m_nCurrentLine = m_nCurrentPage * m_nLinesPerPage; + if(m_nSelectedLine < m_nCurrentLine || m_nSelectedLine - m_nCurrentLine >= m_nLinesPerPage ) + { + m_nSelectedLine = m_nCurrentLine; + } + //TRACE("[CListFrame] m_nCurrentLine: %d, m_nCurrentPage: %d \r\n",m_nCurrentLine,m_nCurrentPage); + refresh(); +} + +void CListFrame::refresh(void) +{ + //TRACE("[CListFrame]->Refresh\r\n"); + if( frameBuffer == NULL) return; + + refreshTitle(); + refreshScroll(); + refreshHeaderList(); + refreshList(); +} + +bool CListFrame::setLines(LF_LINES* lines) +{ + if(lines == NULL) + return(false); + //TRACE("[CListFrame]->setLines \r\n"); + + m_pLines = lines; + m_nNrOfRows = lines->rows; + + if(m_nNrOfRows > LF_MAX_ROWS) + m_nNrOfRows = LF_MAX_ROWS; + onNewLineArray(); + refresh(); + + return(true); +} + +bool CListFrame::setTitle(char* title) +{ + //TRACE("[CListFrame]->setTitle \r\n"); + if(!(m_nMode & TITLE)) return(false); + if(title == NULL) return(false); + + m_textTitle = title; + refreshTitle(); + + return(true); +} + +bool CListFrame::setSelectedLine(int selection) +{ + //TRACE("[CListFrame]->setSelectedLine %d \r\n",selection); + bool result = false; + if(selection >= 0 && selection < m_nNrOfLines) + { + m_nSelectedLine = selection; + m_nCurrentPage = selection / m_nLinesPerPage; + m_nCurrentLine = m_nCurrentPage * m_nLinesPerPage; + refreshList(); + refreshScroll(); //NEW + result = true; + //TRACE(" selected line: %d,%d,%d \r\n",m_nSelectedLine,m_nCurrentPage,m_nCurrentLine); + } + + return (result); +} + +void CListFrame::hide(void) +{ + if(frameBuffer == NULL) return; + TRACE("[CListFrame]->hide %s\n", m_textTitle.c_str()); + + frameBuffer->paintBackgroundBoxRel(m_cFrame.iX, m_cFrame.iY, m_cFrame.iWidth, m_cFrame.iHeight); + frameBuffer = NULL; +} + +void CListFrame::paint(void) +{ + TRACE("[CListFrame]->paint %s\n", m_textTitle.c_str()); + frameBuffer = CFrameBuffer::getInstance(); + refresh(); +} diff --git a/src/gui/widget/listframe.h b/src/gui/widget/listframe.h new file mode 100644 index 000000000..bbabc1b59 --- /dev/null +++ b/src/gui/widget/listframe.h @@ -0,0 +1,164 @@ + +/*************************************************************************** + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + *********************************************************** + + Module Name: listframe.h . + + Description: interface of the CTextBox class + + Date: Nov 2005 + + Author: Günther@tuxbox.berlios.org + based on code of Steffen Hehn 'McClean' + + Revision History: + Date Author Change Description + Nov 2005 Günther initial implementation +****************************************************************************/ + +#if !defined(LISTFRAME_H_) +#define LISTFRAME_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#define LF_MAX_ROWS 6 +typedef struct +{ + int rows; + std::string lineHeader[LF_MAX_ROWS]; + std::vector lineArray[LF_MAX_ROWS]; + int rowWidth[LF_MAX_ROWS]; +}LF_LINES; + +class CListFrame +{ + private: + /* Functions */ + void onNewLineArray(void); + void initVar(void); + void initFramesRel(void); + void refreshTitle(void); + void refreshScroll(void); + void refreshList(void); + void refreshHeaderList(void); + void reSizeMainFrameWidth(int maxTextWidth); + void reSizeMainFrameHeight(int maxTextHeight); + + /* Variables */ + LF_LINES* m_pLines; + + CBox m_cFrame; + CBox m_cFrameTitleRel; + CBox m_cFrameListRel; + CBox m_cFrameScrollRel; + CBox m_cFrameHeaderListRel; + + int m_nMaxHeight; + int m_nMaxWidth; + + int m_nMode; + + int m_nNrOfPages; + int m_nNrOfLines; + int m_nNrOfRows; + int m_nMaxLineWidth; + int m_nLinesPerPage; + int m_nCurrentLine; + int m_nCurrentPage; + int m_nSelectedLine; + + bool m_showSelection; + + Font* m_pcFontTitle; + std::string m_textTitle; + int m_nFontTitleHeight; + + Font* m_pcFontList; + int m_nFontListHeight; + + Font* m_pcFontHeaderList; + int m_nFontHeaderListHeight; + + CFrameBuffer * frameBuffer; + public: + /* Constructor */ + CListFrame(); + CListFrame( LF_LINES* lines); + CListFrame( LF_LINES* lines, + Font* font_text, + const int mode, + const CBox* position, + const char* textTitle = NULL, + Font* font_title = NULL); + + virtual ~CListFrame(); + + /* Functions */ + void refresh(void); + void refreshLine(int line); + void scrollPageDown(const int pages); + void scrollPageUp(const int pages); + void scrollLineDown(const int lines); + void scrollLineUp(const int lines); + bool setLines(LF_LINES* lines); + bool setTitle(char* title); + bool setSelectedLine(int selection); + void hide(void); + void paint(void); + +inline CBox getWindowsPos(void) {return(m_cFrame);}; +inline int getMaxLineWidth(void) {return(m_nMaxLineWidth);}; +inline int getSelectedLine(void) {return(m_nSelectedLine);}; +inline int getLines(void) {return(m_nNrOfLines);}; +inline int getPages(void) {return(m_nNrOfPages);}; +inline void showSelection(bool show) {m_showSelection = show;refreshLine(m_nSelectedLine);}; +inline void movePosition(int x, int y){m_cFrame.iX = x; m_cFrame.iY = y;}; + + + /* Variables */ + typedef enum mode_ + { + AUTO_WIDTH = 0x01, + AUTO_HIGH = 0x02, + SCROLL = 0x04, + TITLE = 0x08, + HEADER_LINE = 0x80 + }mode; +}; + +#endif /*LISTFRAME_H_*/ diff --git a/src/gui/widget/menue.cpp b/src/gui/widget/menue.cpp new file mode 100644 index 000000000..983b77dec --- /dev/null +++ b/src/gui/widget/menue.cpp @@ -0,0 +1,1331 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include + +#include +#include +#include + + +#include + +#define ROUND_RADIUS 9 + +/* the following generic menu items are integrated into multiple menus at the same time */ +CMenuSeparator CGenericMenuSeparator; +CMenuSeparator CGenericMenuSeparatorLine(CMenuSeparator::LINE); +CMenuForwarder CGenericMenuBack(LOCALE_MENU_BACK); +CMenuSeparator * const GenericMenuSeparator = &CGenericMenuSeparator; +CMenuSeparator * const GenericMenuSeparatorLine = &CGenericMenuSeparatorLine; +CMenuForwarder * const GenericMenuBack = &CGenericMenuBack; + +void CMenuItem::init(const int X, const int Y, const int DX, const int OFFX) +{ + x = X; + y = Y; + dx = DX; + offx = OFFX; +} + +void CMenuItem::setActive(const bool Active) +{ + active = Active; + if (x != -1) + paint(); +} + +CMenuWidget::CMenuWidget() +{ + nameString = g_Locale->getText(NONEXISTANT_LOCALE); + name = NONEXISTANT_LOCALE; + iconfile = ""; + selected = -1; + iconOffset = 0; + offx = offy = 0; +} + +CMenuWidget::CMenuWidget(const neutrino_locale_t Name, const std::string & Icon, const int mwidth, const int mheight) +{ + name = Name; + nameString = g_Locale->getText(NONEXISTANT_LOCALE); + + Init(Icon, mwidth, mheight); +} + +CMenuWidget::CMenuWidget(const char* Name, const std::string & Icon, const int mwidth, const int mheight) +{ + name = NONEXISTANT_LOCALE; + nameString = Name; + + Init(Icon, mwidth, mheight); +} + +void CMenuWidget::Init(const std::string & Icon, const int mwidth, const int mheight) +{ + frameBuffer = CFrameBuffer::getInstance(); + iconfile = Icon; + selected = -1; + width = mwidth; + if(width > (int) frameBuffer->getScreenWidth()) + width = frameBuffer->getScreenWidth(); + height = mheight; + wanted_height=mheight; + current_page=0; + offx = offy = 0; +} + +void CMenuWidget::move(int xoff, int yoff) +{ + offx = xoff; + offy = yoff; +} + +CMenuWidget::~CMenuWidget() +{ + for(unsigned int count=0;counthide(); + + + bool fadeIn = g_settings.widget_fade; + bool fadeOut = false; + int fadeValue; + uint32_t fadeTimer = 0; + if ( fadeIn ) { + fadeValue = 0x10; + frameBuffer->setBlendLevel(fadeValue, fadeValue); + } + else + fadeValue = g_settings.gtx_alpha1; + + paint(); + int retval = menu_return::RETURN_REPAINT; + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings::TIMING_MENU]); + + if ( fadeIn ) + fadeTimer = g_RCInput->addTimer( FADE_TIME, false ); + do { + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd); + + if ( msg <= CRCInput::RC_MaxRC ) { + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + } + int handled= false; + + for (unsigned int i= 0; i< items.size(); i++) { + CMenuItem* titem = items[i]; + if ((titem->directKey != CRCInput::RC_nokey) && (titem->directKey == msg)) { + if (titem->isSelectable()) { + items[selected]->paint( false, (i == items.size()-1) ); + selected= i; + msg= CRCInput::RC_ok; + } else { + // swallow-key... + handled= true; + } + break; + } + } + + if (!handled) { + switch (msg) { + case (NeutrinoMessages::EVT_TIMER): + if(data == fadeTimer) { + if (fadeOut) { // disappear + fadeValue -= 0x10; + if (fadeValue <= 0x10) { + fadeValue = g_settings.gtx_alpha1; + g_RCInput->killTimer (fadeTimer); + msg = CRCInput::RC_timeout; + } else + frameBuffer->setBlendLevel(fadeValue, fadeValue); + } else { // appears + fadeValue += 0x10; + if (fadeValue >= g_settings.gtx_alpha1) { + fadeValue = g_settings.gtx_alpha1; + g_RCInput->killTimer (fadeTimer); + fadeIn = false; + frameBuffer->setBlendLevel(g_settings.gtx_alpha1, g_settings.gtx_alpha2); + } else + frameBuffer->setBlendLevel(fadeValue, fadeValue); + } + + + } else { + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) { + retval = menu_return::RETURN_EXIT_ALL; + msg = CRCInput::RC_timeout; + } + } + break; + case (CRCInput::RC_page_up) : + case (CRCInput::RC_page_down) : + if(msg==CRCInput::RC_page_up) { + if(current_page) { + pos = (int) page_start[current_page] - 1; + for (unsigned int count=pos ; count > 0; count--) { + CMenuItem* item = items[pos]; + if ( item->isSelectable() ) { + if ((pos < (int)page_start[current_page + 1]) && (pos >= (int)page_start[current_page])) { + items[selected]->paint( false, (pos == (int) items.size()-1) ); + item->paint( true , (count == items.size()-1)); + selected = pos; + } else { + selected=pos; + paintItems(); + } + break; + } + pos--; + } + } else { + pos = 0; + for (unsigned int count=0; count < items.size(); count++) { + CMenuItem* item = items[pos]; + if ( item->isSelectable() ) { + if ((pos < (int)page_start[current_page + 1]) && (pos >= (int)page_start[current_page])) { + items[selected]->paint( false, (count == items.size()-1) ); + item->paint( true, (count == items.size()-1) ); + selected = pos; + } else { + selected=pos; + paintItems(); + } + break; + } + pos++; + } + } + } + else if(msg==CRCInput::RC_page_down) { + pos = (int) page_start[current_page + 1];// - 1; + if(pos >= (int) items.size()) + pos = items.size()-1; + for (unsigned int count=pos ; count < items.size(); count++) { + CMenuItem* item = items[pos]; + if ( item->isSelectable() ) { + if ((pos < (int)page_start[current_page + 1]) && (pos >= (int)page_start[current_page])) { + items[selected]->paint( false ); + item->paint( true ); + selected = pos; + } else { + selected=pos; + paintItems(); + } + break; + } + pos++; + } + } + break; + case (CRCInput::RC_up) : + case (CRCInput::RC_down) : + { + //search next / prev selectable item + for (unsigned int count=1; count< items.size(); count++) { + if (msg==CRCInput::RC_up) { + pos = selected - count; + if ( pos < 0 ) + pos += items.size(); + } + else if(msg==CRCInput::RC_down) { + pos = (selected+ count)%items.size(); + } + + CMenuItem* item = items[pos]; + + if ( item->isSelectable() ) { + if ((pos < (int)page_start[current_page + 1]) && (pos >= (int)page_start[current_page])) + { // Item is currently on screen + //clear prev. selected + items[selected]->paint( false, (selected == (int) (page_start[current_page + 1]-1)) ); + //select new + item->paint( true ); + selected = pos; + } else { + selected=pos; + paintItems(); + } + break; + } + } + } + break; + case (CRCInput::RC_left): + if(!(items[selected]->can_arrow) || g_settings.menu_left_exit) { + msg = CRCInput::RC_timeout; + break; + } + case (CRCInput::RC_right): + case (CRCInput::RC_ok): + { + if(hasItem()) { + //exec this item... + CMenuItem* item = items[selected]; + item->msg = msg; + if ( fadeIn ) { + g_RCInput->killTimer(fadeTimer); + frameBuffer->setBlendLevel(g_settings.gtx_alpha1, g_settings.gtx_alpha2); + fadeIn = false; + } + int rv = item->exec( this ); + switch ( rv ) { + case menu_return::RETURN_EXIT_ALL: + retval = menu_return::RETURN_EXIT_ALL; + case menu_return::RETURN_EXIT: + msg = CRCInput::RC_timeout; + break; + case menu_return::RETURN_REPAINT: + paint(); + break; + } + } else + msg = CRCInput::RC_timeout; + } + break; + + case (CRCInput::RC_home): + exit_pressed = true; + msg = CRCInput::RC_timeout; + break; + case (CRCInput::RC_timeout): + break; + + case (CRCInput::RC_sat): + case (CRCInput::RC_favorites): + g_RCInput->postMsg (msg, 0); + //close any menue on dbox-key + case (CRCInput::RC_setup): + { + msg = CRCInput::RC_timeout; + retval = menu_return::RETURN_EXIT_ALL; + } + break; + + default: + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) { + retval = menu_return::RETURN_EXIT_ALL; + msg = CRCInput::RC_timeout; + } + } + if(msg == CRCInput::RC_timeout) { + if ( fadeIn ) { + g_RCInput->killTimer(fadeTimer); + fadeIn = false; + } + if ((!fadeOut) && g_settings.widget_fade) { + fadeOut = true; + fadeTimer = g_RCInput->addTimer( FADE_TIME, false ); + timeoutEnd = CRCInput::calcTimeoutEnd( 1 ); + msg = 0; + continue; + } + } + + if ( msg <= CRCInput::RC_MaxRC ) + { + // recalculate timeout für RC-Tasten + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + } + } + } + while ( msg!=CRCInput::RC_timeout ); + hide(); + + if ( fadeIn || fadeOut ) { + g_RCInput->killTimer(fadeTimer); + frameBuffer->setBlendLevel(g_settings.gtx_alpha1, g_settings.gtx_alpha2); + } + + if(!parent) + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + + for (unsigned int count = 0; count < items.size(); count++) { + CMenuItem* item = items[count]; + item->init(-1, 0, 0, 0); + } + return retval; +} + +void CMenuWidget::hide() +{ + frameBuffer->paintBackgroundBoxRel(x, y, width+15,height+10 ); +} + +void CMenuWidget::paint() +{ + const char * l_name; + if(name == NONEXISTANT_LOCALE) + l_name = nameString.c_str(); + else + l_name = g_Locale->getText(name); + + CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8 /*, l_name*/); //FIXME menu name + + height=wanted_height; + + if(height > ((int)frameBuffer->getScreenHeight() - 10)) + height = frameBuffer->getScreenHeight() - 10; + + int neededWidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getRenderWidth(l_name, true); // UTF-8 + if (neededWidth > width-48) { + width= neededWidth+ 49; + if(width > (int)frameBuffer->getScreenWidth()) + width = frameBuffer->getScreenWidth(); + } + int hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + int itemHeightTotal=0; + int heightCurrPage=0; + page_start.clear(); + page_start.push_back(0); + total_pages=1; + for (unsigned int i= 0; i< items.size(); i++) { + int item_height=items[i]->getHeight(); + itemHeightTotal+=item_height; + heightCurrPage+=item_height; + if(heightCurrPage > (height-hheight)) { + page_start.push_back(i); + total_pages++; + heightCurrPage=item_height; + } + } + page_start.push_back(items.size()); + + iconOffset= 0; + for (unsigned int i= 0; i< items.size(); i++) { + if ((!(items[i]->iconName.empty())) || CRCInput::isNumeric(items[i]->directKey)) + { + iconOffset = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + break; + } + } + + // shrink menu if less items + if(hheight+itemHeightTotal < height) + height=hheight+itemHeightTotal; + + x = offx + frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth() - width ) >> 1 ); + y = offy + frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight() - height) >> 1 ); + + int sb_width; + if(total_pages > 1) + sb_width=15; + else + sb_width=0; + + //frameBuffer->paintBoxRel(x,y, width+sb_width,hheight, COL_MENUHEAD_PLUS_0); + frameBuffer->paintBoxRel(x, y, width+sb_width, hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); //FIXME rounded + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+38,y+hheight+1, width-40, l_name, COL_MENUHEAD, 0, true); // UTF-8 + frameBuffer->paintIcon(iconfile, x + 8, y + 5); + + item_start_y = y+hheight; + paintItems(); +} + +void CMenuWidget::paintItems() +{ + int item_height=height-(item_start_y-y); + + //Item not currently on screen + if (selected >= 0) + { + while(selected < (int)page_start[current_page]) + current_page--; + while(selected >= (int)page_start[current_page + 1]) + current_page++; + } + + // Scrollbar + if(total_pages>1) + { + int sbh= ((item_height-4) / total_pages); + // items box + frameBuffer->paintBoxRel(x,item_start_y, width+15,item_height+10, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2); + // scrollbar + frameBuffer->paintBoxRel(x+ width,item_start_y, 15, item_height, COL_MENUCONTENT_PLUS_1); + frameBuffer->paintBoxRel(x+ width +2, item_start_y+ 2+ current_page* sbh, 11, sbh, COL_MENUCONTENT_PLUS_3); + } else + frameBuffer->paintBoxRel(x,item_start_y, width,item_height, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2);//FIXME round + + int ypos=item_start_y; + for (unsigned int count = 0; count < items.size(); count++) { + CMenuItem* item = items[count]; + + if ((count >= page_start[current_page]) && (count < page_start[current_page + 1])) { + item->init(x, ypos, width, iconOffset); + if( (item->isSelectable()) && (selected==-1) ) { + ypos = item->paint(true); + selected = count; + } else { + //ypos = item->paint(selected==((signed int) count), (count == items.size()-1)); + ypos = item->paint(selected==((signed int) count), (count == (page_start[current_page + 1]-1))); + } + } else { + /* x = -1 is a marker which prevents the item from being painted on setActive changes */ + item->init(-1, 0, 0, 0); + } + } +} + +//------------------------------------------------------------------------------------------------------------------------------- +CMenuOptionNumberChooser::CMenuOptionNumberChooser(const neutrino_locale_t name, int * const OptionValue, const bool Active, const int min_value, const int max_value, CChangeObserver * const Observ, const int print_offset, const int special_value, const neutrino_locale_t special_value_name, const char * non_localized_name) +{ + height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + optionName = name; + active = Active; + optionValue = OptionValue; + + lower_bound = min_value; + upper_bound = max_value; + + display_offset = print_offset; + + localized_value = special_value; + localized_value_name = special_value_name; + + optionString = non_localized_name; + can_arrow = true; + observ = Observ; +} + +int CMenuOptionNumberChooser::exec(CMenuTarget*) +{ + if(msg == CRCInput::RC_left) { + if (((*optionValue) > upper_bound) || ((*optionValue) <= lower_bound)) + *optionValue = upper_bound; + else + (*optionValue)--; + } else { + if (((*optionValue) >= upper_bound) || ((*optionValue) < lower_bound)) + *optionValue = lower_bound; + else + (*optionValue)++; + } + paint(true); + if(observ) + observ->changeNotify(optionName, optionValue); + + return menu_return::RETURN_NONE; +} + +int CMenuOptionNumberChooser::paint(bool selected, bool last) +{ + CFrameBuffer * frameBuffer = CFrameBuffer::getInstance(); + + unsigned char color = COL_MENUCONTENT; + fb_pixel_t bgcolor = COL_MENUCONTENT_PLUS_0; + if (selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + if (!active) + { + color = COL_MENUCONTENTINACTIVE; + bgcolor = COL_MENUCONTENTINACTIVE_PLUS_0; + } + + if(selected) + frameBuffer->paintBoxRel(x, y, dx, height, bgcolor, ROUND_RADIUS, 3); //FIXME + else if(last) + frameBuffer->paintBoxRel(x, y, dx, height, bgcolor, ROUND_RADIUS, 2); //FIXME + else + frameBuffer->paintBoxRel(x, y, dx, height, bgcolor); + + const char * l_option; + char option_value[11]; + + if ((localized_value_name == NONEXISTANT_LOCALE) || ((*optionValue) != localized_value)) + { + sprintf(option_value, "%d", ((*optionValue) + display_offset)); + l_option = option_value; + } + else + l_option = g_Locale->getText(localized_value_name); + + int stringwidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(l_option, true); // UTF-8 + int stringstartposName = x + offx + 10; + int stringstartposOption = x + dx - stringwidth - 10; //+ offx + + const char * l_optionName = (optionString != NULL) ? optionString : g_Locale->getText(optionName); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposName, y+height,dx- (stringstartposName - x), l_optionName, color, 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposOption, y+height,dx- (stringstartposOption - x), l_option, color, 0, true); // UTF-8 + + if (selected) + { + char str[256]; + snprintf(str, 255, "%s %s", l_optionName, l_option); + CVFD::getInstance()->showMenuText(0, str, -1, true); + //CVFD::getInstance()->showMenuText(0, l_optionName, -1, true); // UTF-8 + //CVFD::getInstance()->showMenuText(1, l_option, -1, true); // UTF-8 + } + + return y+height; +} + +CMenuOptionChooser::CMenuOptionChooser(const neutrino_locale_t OptionName, int * const OptionValue, const struct keyval * const Options, const unsigned Number_Of_Options, const bool Active, CChangeObserver * const Observ, const neutrino_msg_t DirectKey, const std::string & IconName, bool Pulldown) +{ + height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + optionNameString = g_Locale->getText(OptionName); + optionName = OptionName; + options = Options; + active = Active; + optionValue = OptionValue; + number_of_options = Number_Of_Options; + observ = Observ; + directKey = DirectKey; + iconName = IconName; + can_arrow = true; + pulldown = Pulldown; +} + +CMenuOptionChooser::CMenuOptionChooser(const char* OptionName, int * const OptionValue, const struct keyval * const Options, const unsigned Number_Of_Options, const bool Active, CChangeObserver * const Observ, const neutrino_msg_t DirectKey, const std::string & IconName, bool Pulldown) +{ + height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + optionNameString = OptionName; + optionName = NONEXISTANT_LOCALE; + options = Options; + active = Active; + optionValue = OptionValue; + number_of_options = Number_Of_Options; + observ = Observ; + directKey = DirectKey; + iconName = IconName; + can_arrow = true; + pulldown = Pulldown; +} + +void CMenuOptionChooser::setOptionValue(const int newvalue) +{ + *optionValue = newvalue; +} + +int CMenuOptionChooser::getOptionValue(void) const +{ + return *optionValue; +} + + +int CMenuOptionChooser::exec(CMenuTarget*) +{ + bool wantsRepaint = false; + int ret = menu_return::RETURN_NONE; + + if((msg == CRCInput::RC_ok) && pulldown) { + int select = -1; + char cnt[5]; + CMenuWidget* menu = new CMenuWidget(optionNameString.c_str(), NEUTRINO_ICON_SETTINGS); + menu->move(20, 0); + CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select); + for(unsigned int count = 0; count < number_of_options; count++) { + bool selected = false; + const char * l_option; + if (options[count].key == (*optionValue)) + selected = true; + + if(options[count].valname != 0) + l_option = options[count].valname; + else + l_option = g_Locale->getText(options[count].value); + sprintf(cnt, "%d", count); + menu->addItem(new CMenuForwarderNonLocalized(l_option, true, NULL, selector, cnt), selected); + } + menu->exec(NULL, ""); + ret = menu_return::RETURN_REPAINT;; + if(select >= 0) { + *optionValue = options[select].key; + } + delete menu; + delete selector; + } else { + for(unsigned int count = 0; count < number_of_options; count++) { + if (options[count].key == (*optionValue)) { + if(msg == CRCInput::RC_left) { + if(count > 0) + *optionValue = options[(count-1) % number_of_options].key; + else + *optionValue = options[number_of_options-1].key; + } else + *optionValue = options[(count+1) % number_of_options].key; + break; + } + } + } + paint(true); + if(observ) + wantsRepaint = observ->changeNotify(optionName, optionValue); + + if ( wantsRepaint ) + ret = menu_return::RETURN_REPAINT; + + return ret; +} + +int CMenuOptionChooser::paint( bool selected , bool last) +{ + CFrameBuffer * frameBuffer = CFrameBuffer::getInstance(); + + unsigned char color = COL_MENUCONTENT; + fb_pixel_t bgcolor = COL_MENUCONTENT_PLUS_0; + if (selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + if (!active) + { + color = COL_MENUCONTENTINACTIVE; + bgcolor = COL_MENUCONTENTINACTIVE_PLUS_0; + } + + if(selected) + frameBuffer->paintBoxRel(x, y, dx, height, bgcolor, ROUND_RADIUS, 3); //FIXME + else if(last) + frameBuffer->paintBoxRel(x, y, dx, height, bgcolor, ROUND_RADIUS, 2); //FIXME + else + frameBuffer->paintBoxRel(x, y, dx, height, bgcolor); + + neutrino_locale_t option = NONEXISTANT_LOCALE; + const char * l_option = NULL; + + for(unsigned int count = 0 ; count < number_of_options; count++) { + if (options[count].key == *optionValue) { + option = options[count].value; + if(options[count].valname != 0) + l_option = options[count].valname; + else + l_option = g_Locale->getText(option); + break; + } + } + if(l_option == NULL) { + *optionValue = options[0].key; + option = options[0].value; + if(options[0].valname != 0) + l_option = options[0].valname; + else + l_option = g_Locale->getText(option); + } + + if (!(iconName.empty())) + { + frameBuffer->paintIcon(iconName, x + 10, y + ((height - 20) >> 1)); + } + else if (CRCInput::isNumeric(directKey)) + { +#if 0 + std::string newicon = CRCInput::getKeyName(directKey) + ".raw"; + //printf("MENU: newicon %s\n", newicon); + if(!frameBuffer->paintIcon(newicon, x + 10, y + ((height - 20) >> 1))) +#endif + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(x + 15, y+ height, height, CRCInput::getKeyName(directKey), color, height); + } + + + + int stringwidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(l_option, true); // UTF-8 + int stringstartposName = x + offx + 10; + int stringstartposOption = x + dx - stringwidth - 10; //+ offx + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposName, y+height,dx- (stringstartposName - x), optionNameString.c_str(), color, 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposOption, y+height,dx- (stringstartposOption - x), l_option, color, 0, true); // UTF-8 + + if (selected) + { + char str[256]; + snprintf(str, 255, "%s %s", optionNameString.c_str(), l_option); + CVFD::getInstance()->showMenuText(0, str, -1, true); + //CVFD::getInstance()->showMenuText(0, optionNameString.c_str(), -1, true); // UTF-8 + //CVFD::getInstance()->showMenuText(1, l_option, -1, true); // UTF-8 + } + + return y+height; +} + + +//------------------------------------------------------------------------------------------------------------------------------- + +CMenuOptionStringChooser::CMenuOptionStringChooser(const neutrino_locale_t OptionName, char* OptionValue, bool Active, CChangeObserver* Observ, const neutrino_msg_t DirectKey, const std::string & IconName, bool Pulldown) +{ + height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + optionName = OptionName; + active = Active; + optionValue = OptionValue; + observ = Observ; + + directKey = DirectKey; + iconName = IconName; + can_arrow = true; + pulldown = Pulldown; +} + + +CMenuOptionStringChooser::~CMenuOptionStringChooser() +{ + options.clear(); +} + +void CMenuOptionStringChooser::addOption(const char * const value) +{ + options.push_back(std::string(value)); +} + +int CMenuOptionStringChooser::exec(CMenuTarget* parent) +{ + bool wantsRepaint = false; + int ret = menu_return::RETURN_NONE; + + if (parent) + parent->hide(); + + if((!parent || msg == CRCInput::RC_ok) && pulldown) { + int select = -1; + char cnt[5]; + + CMenuWidget* menu = new CMenuWidget(optionName, NEUTRINO_ICON_SETTINGS); + //if(parent) menu->move(20, 0); + CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select); + for(unsigned int count = 0; count < options.size(); count++) { + bool selected = false; + if (strcmp(options[count].c_str(), optionValue) == 0) + selected = true; + sprintf(cnt, "%d", count); + menu->addItem(new CMenuForwarderNonLocalized(options[count].c_str(), true, NULL, selector, cnt), selected); + } + menu->exec(NULL, ""); + ret = menu_return::RETURN_REPAINT; + if(select >= 0) + strcpy(optionValue, options[select].c_str()); + delete menu; + delete selector; + } else { + //select next value + for(unsigned int count = 0; count < options.size(); count++) { + if (strcmp(options[count].c_str(), optionValue) == 0) { + if(msg == CRCInput::RC_left) { + if(count > 0) + strcpy(optionValue, options[(count - 1) % options.size()].c_str()); + else + strcpy(optionValue, options[options.size() - 1].c_str()); + } else + strcpy(optionValue, options[(count + 1) % options.size()].c_str()); + wantsRepaint = true; + break; + } + } + } + + if(parent) + paint(true); + if(observ) { + wantsRepaint = observ->changeNotify(optionName, optionValue); + } + if (wantsRepaint) + ret = menu_return::RETURN_REPAINT; + + return ret; +} + +int CMenuOptionStringChooser::paint( bool selected, bool last ) +{ + unsigned char color = COL_MENUCONTENT; + fb_pixel_t bgcolor = COL_MENUCONTENT_PLUS_0; + if (selected) { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + if (!active) { + color = COL_MENUCONTENTINACTIVE; + bgcolor = COL_MENUCONTENTINACTIVE_PLUS_0; + } + + if(selected) + CFrameBuffer::getInstance()->paintBoxRel(x, y, dx, height, bgcolor, ROUND_RADIUS, 3); //FIXME + else if(last) + CFrameBuffer::getInstance()->paintBoxRel(x, y, dx, height, bgcolor, ROUND_RADIUS, 2); //FIXME + else + CFrameBuffer::getInstance()->paintBoxRel(x, y, dx, height, bgcolor); + + + const char * l_optionName = g_Locale->getText(optionName); + int optionwidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(l_optionName, true); + //int stringwidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(optionValue, true); + int stringstartposName = x + offx + 10; + //int stringstartposOption = x + dx - stringwidth - 10; //+ offx + int stringstartposOption = x + offx + 10 + 10 + optionwidth; + + if (!(iconName.empty())) + { + CFrameBuffer::getInstance()->paintIcon(iconName, x + 10, y + ((height - 20) >> 1)); + } + else if (CRCInput::isNumeric(directKey)) + { + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(x + 15, y+ height, height, CRCInput::getKeyName(directKey), color, height); + } + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposName, y+height, dx- (stringstartposName - x), l_optionName, color, 0, true); // UTF-8 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposOption, y+height, dx- (stringstartposOption - x), optionValue, color, 0, true); + + if (selected) + { + char str[256]; + snprintf(str, 255, "%s %s", l_optionName, optionValue); + CVFD::getInstance()->showMenuText(0, str, -1, true); + //CVFD::getInstance()->showMenuText(0, l_optionName, -1, true); // UTF-8 + //CVFD::getInstance()->showMenuText(1, optionValue); + } + + return y+height; +} + +//------------------------------------------------------------------------------------------------------------------------------- + +CMenuOptionLanguageChooser::CMenuOptionLanguageChooser(char* OptionValue, CChangeObserver* Observ, const char * const IconName) +{ + height = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + optionValue = OptionValue; + observ = Observ; + + directKey = CRCInput::RC_nokey; + iconName = IconName ? IconName : ""; +} + + +CMenuOptionLanguageChooser::~CMenuOptionLanguageChooser() +{ + options.clear(); +} + +void CMenuOptionLanguageChooser::addOption(const char * const value) +{ + options.push_back(std::string(value)); +} + +int CMenuOptionLanguageChooser::exec(CMenuTarget*) +{ + bool wantsRepaint = false; + + //select value + for(unsigned int count = 0; count < options.size(); count++) + { + if (strcmp(options[count].c_str(), optionValue) == 0) + { + strcpy(g_settings.language, options[(count + 1) % options.size()].c_str()); + break; + } + } + + paint(true); + if(observ) + { + wantsRepaint = observ->changeNotify(LOCALE_LANGUAGESETUP_SELECT, optionValue); + } + return menu_return::RETURN_EXIT; + if ( wantsRepaint ) + return menu_return::RETURN_REPAINT; + else + return menu_return::RETURN_NONE; +} + +int CMenuOptionLanguageChooser::paint( bool selected, bool last ) +{ + unsigned char color = COL_MENUCONTENT; + fb_pixel_t bgcolor = COL_MENUCONTENT_PLUS_0; + if (selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + + if(selected) + CFrameBuffer::getInstance()->paintBoxRel(x, y, dx, height, bgcolor, ROUND_RADIUS, 3); //FIXME + else if(last) + CFrameBuffer::getInstance()->paintBoxRel(x, y, dx, height, bgcolor, ROUND_RADIUS, 2); //FIXME + else + CFrameBuffer::getInstance()->paintBoxRel(x, y, dx, height, bgcolor); + + if (!(iconName.empty())) + { + CFrameBuffer::getInstance()->paintIcon(iconName, x + 10, y + ((height - 11) >> 1)); + } + + //int stringwidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(optionValue); + int stringstartposOption = x + offx + 10; + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposOption, y+height,dx- (stringstartposOption - x), optionValue, color); + + if (selected) + { + CVFD::getInstance()->showMenuText(1, optionValue); + } + + return y+height; +} + + + +//------------------------------------------------------------------------------------------------------------------------------- +CMenuForwarder::CMenuForwarder(const neutrino_locale_t Text, const bool Active, const char * const Option, CMenuTarget* Target, const char * const ActionKey, neutrino_msg_t DirectKey, const char * const IconName) +{ + option = Option; + option_string = NULL; + text=Text; + active = Active; + jumpTarget = Target; + actionKey = ActionKey ? ActionKey : ""; + directKey = DirectKey; + iconName = IconName ? IconName : ""; +} + +CMenuForwarder::CMenuForwarder(const neutrino_locale_t Text, const bool Active, const std::string &Option, CMenuTarget* Target, const char * const ActionKey, neutrino_msg_t DirectKey, const char * const IconName) +{ + option = NULL; + option_string = &Option; + text=Text; + active = Active; + jumpTarget = Target; + actionKey = ActionKey ? ActionKey : ""; + directKey = DirectKey; + iconName = IconName ? IconName : ""; +} + +int CMenuForwarder::getHeight(void) const +{ + return g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); +} + +int CMenuForwarder::getWidth(void) const +{ + int tw = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(g_Locale->getText(text), true); + const char * option_text = NULL; + + if (option) + option_text = option; + else if (option_string) + option_text = option_string->c_str(); + + + if (option_text != NULL) + tw += 10 + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(option_text, true); + + return tw; +} + +int CMenuForwarder::exec(CMenuTarget* parent) +{ + if(jumpTarget) + { + return jumpTarget->exec(parent, actionKey); + } + else + { + return menu_return::RETURN_EXIT; + } +} + +const char * CMenuForwarder::getOption(void) +{ + if (option) + return option; + else + if (option_string) + return option_string->c_str(); + else + return NULL; +} + +const char * CMenuForwarder::getName(void) +{ + return g_Locale->getText(text); +} + +int CMenuForwarder::paint(bool selected, bool last) +{ + CFrameBuffer * frameBuffer = CFrameBuffer::getInstance(); + int height = getHeight(); + const char * l_text = getName(); + int stringstartposX = x + offx + 10; + + const char * option_text = getOption(); + + if (selected) + { + char str[256]; + + if (option_text != NULL) { + snprintf(str, 255, "%s %s", l_text, option_text); + CVFD::getInstance()->showMenuText(0, str, -1, true); + } else + CVFD::getInstance()->showMenuText(0, l_text, -1, true); + } + + unsigned char color = COL_MENUCONTENT; + fb_pixel_t bgcolor = COL_MENUCONTENT_PLUS_0; + if (selected) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + else if (!active) + { + color = COL_MENUCONTENTINACTIVE; + bgcolor = COL_MENUCONTENTINACTIVE_PLUS_0; + } + + if(selected) + frameBuffer->paintBoxRel(x, y, dx, height, bgcolor, ROUND_RADIUS, 3); //FIXME + else if(last) + frameBuffer->paintBoxRel(x, y, dx, height, bgcolor, ROUND_RADIUS, 2); //FIXME + else + frameBuffer->paintBoxRel(x, y, dx, height, bgcolor); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposX, y+ height, dx- (stringstartposX - x), l_text, color, 0, true); // UTF-8 + + if (!iconName.empty()) + { + frameBuffer->paintIcon(iconName, x + 10, y+ ((height- 20)>>1) ); + } + else if (CRCInput::isNumeric(directKey)) + { +#if 0 +printf("MENU: key %s\n", CRCInput::getKeyName(directKey).c_str()); fflush(stdout); + std::string newicon = CRCInput::getKeyName(directKey) + ".raw"; +printf("MENU: newicon %s\n", newicon.c_str()); fflush(stdout); + if(!frameBuffer->paintIcon(newicon, x + 10, y + ((height - 20) >> 1))) +#endif + g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(x + 15, y+ height, height, CRCInput::getKeyName(directKey), color, height); + } + + if (option_text != NULL) + { + int stringwidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(option_text, true); + int stringstartposOption = std::max(stringstartposX + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(l_text, true) + 10, + x + dx - stringwidth - 10); //+ offx + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposOption, y+height,dx- (stringstartposOption- x), option_text, color, 0, true); + } + + return y+ height; +} + + +//------------------------------------------------------------------------------------------------------------------------------- +const char * CMenuForwarderNonLocalized::getName(void) +{ + return the_text.c_str(); +} + +CMenuForwarderNonLocalized::CMenuForwarderNonLocalized(const char * const Text, const bool Active, const char * const Option, CMenuTarget* Target, const char * const ActionKey, neutrino_msg_t DirectKey, const char * const IconName) : CMenuForwarder(NONEXISTANT_LOCALE, Active, Option, Target, ActionKey, DirectKey, IconName) +{ + the_text = Text; +} + +CMenuForwarderNonLocalized::CMenuForwarderNonLocalized(const char * const Text, const bool Active, const std::string &Option, CMenuTarget* Target, const char * const ActionKey, neutrino_msg_t DirectKey, const char * const IconName) : CMenuForwarder(NONEXISTANT_LOCALE, Active, Option, Target, ActionKey, DirectKey, IconName) +{ + the_text = Text; +} + +//------------------------------------------------------------------------------------------------------------------------------- +CMenuSeparator::CMenuSeparator(const int Type, const neutrino_locale_t Text) +{ + directKey = CRCInput::RC_nokey; + iconName = ""; + type = Type; + text = Text; +} + + +int CMenuSeparator::getHeight(void) const +{ + return (text == NONEXISTANT_LOCALE) ? 10 : g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); +} + +int CMenuSeparator::getWidth(void) const +{ + return 0; +} + +const char * CMenuSeparator::getString(void) +{ + return g_Locale->getText(text); +} + +int CMenuSeparator::paint(bool selected, bool last) +{ + int height; + CFrameBuffer * frameBuffer = CFrameBuffer::getInstance(); + height = getHeight(); + + frameBuffer->paintBoxRel(x,y, dx, height, COL_MENUCONTENT_PLUS_0); + if ((type & LINE)) + { + frameBuffer->paintHLineRel(x+10,dx-20,y+(height>>1), COL_MENUCONTENT_PLUS_3); + frameBuffer->paintHLineRel(x+10,dx-20,y+(height>>1)+1, COL_MENUCONTENT_PLUS_1); + } + if ((type & STRING)) + { + + if (text != NONEXISTANT_LOCALE) + { + int stringstartposX; + + const char * l_text = getString(); + int stringwidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(l_text, true); // UTF-8 + + /* if no alignment is specified, align centered */ + if (type & ALIGN_LEFT) + stringstartposX = x + 20; + else if (type & ALIGN_RIGHT) + stringstartposX = x + dx - stringwidth - 20; + else /* ALIGN_CENTER */ + stringstartposX = x + (dx >> 1) - (stringwidth >> 1); + + frameBuffer->paintBoxRel(stringstartposX-5, y, stringwidth+10, height, COL_MENUCONTENT_PLUS_0); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(stringstartposX, y+height,dx- (stringstartposX- x) , l_text, COL_MENUCONTENTINACTIVE, 0, true); // UTF-8 + + if (selected) + { + CVFD::getInstance()->showMenuText(0, l_text, -1, true); // UTF-8 + //CVFD::getInstance()->showMenuText(1, "", -1, true); // UTF-8 + } + } + } + return y+ height; +} + +bool CPINProtection::check() +{ + char cPIN[4]; + neutrino_locale_t hint = NONEXISTANT_LOCALE; + do + { + cPIN[0] = 0; + CPINInput* PINInput = new CPINInput(LOCALE_PINPROTECTION_HEAD, cPIN, 4, hint); + PINInput->exec( getParent(), ""); + delete PINInput; + hint = LOCALE_PINPROTECTION_WRONGCODE; + } while ((strncmp(cPIN,validPIN,4) != 0) && (cPIN[0] != 0)); + return ( strncmp(cPIN,validPIN,4) == 0); +} + + +bool CZapProtection::check() +{ + + int res; + char cPIN[5]; + neutrino_locale_t hint2 = NONEXISTANT_LOCALE; + do + { + cPIN[0] = 0; + + CPLPINInput* PINInput = new CPLPINInput(LOCALE_PARENTALLOCK_HEAD, cPIN, 4, hint2, fsk); + + res = PINInput->exec(getParent(), ""); + delete PINInput; + + hint2 = LOCALE_PINPROTECTION_WRONGCODE; + } while ( (strncmp(cPIN,validPIN,4) != 0) && + (cPIN[0] != 0) && + ( res == menu_return::RETURN_REPAINT ) && + ( fsk >= g_settings.parentallock_lockage ) ); + return ( ( strncmp(cPIN,validPIN,4) == 0 ) || + ( fsk < g_settings.parentallock_lockage ) ); +} + +int CLockedMenuForwarder::exec(CMenuTarget* parent) +{ + Parent = parent; + if( (g_settings.parentallock_prompt != PARENTALLOCK_PROMPT_NEVER) || AlwaysAsk ) + if (!check()) + { + Parent = NULL; + return menu_return::RETURN_REPAINT; + } + + Parent = NULL; + return CMenuForwarder::exec(parent); +} + +int CMenuSelectorTarget::exec(CMenuTarget* parent, const std::string & actionKey) +{ + if (actionKey != "") + *m_select = atoi(actionKey.c_str()); + else + *m_select = -1; + return menu_return::RETURN_EXIT; +} + diff --git a/src/gui/widget/menue.h b/src/gui/widget/menue.h new file mode 100644 index 000000000..c03c696b6 --- /dev/null +++ b/src/gui/widget/menue.h @@ -0,0 +1,399 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __MENU__ +#define __MENU__ + +#include +#include +#include + +#include +#include + +struct menu_return +{ + enum + { + RETURN_NONE = 0, + RETURN_REPAINT = 1, + RETURN_EXIT = 2, + RETURN_EXIT_ALL = 4 + }; +}; + +class CChangeObserver +{ + public: + virtual ~CChangeObserver(){} + virtual bool changeNotify(const neutrino_locale_t OptionName, void *Data) + { + return false; + } +}; + +class CMenuTarget +{ + public: + + CMenuTarget(){} + virtual ~CMenuTarget(){} + virtual void hide(){} + virtual int exec(CMenuTarget* parent, const std::string & actionKey) = 0; +}; + + +class CMenuItem +{ + protected: + int x, y, dx, offx; + public: + bool active; + neutrino_msg_t directKey; + neutrino_msg_t msg; + bool can_arrow; + std::string iconName; + + CMenuItem() + { + x = -1; + directKey = CRCInput::RC_nokey; + iconName = ""; + can_arrow = false; + } + virtual ~CMenuItem(){} + + virtual void init(const int X, const int Y, const int DX, const int OFFX); + + virtual int paint (bool selected = false, bool last = false) = 0; + + virtual int getHeight(void) const = 0; + virtual int getWidth(void) const + { + return 0; + } + + virtual bool isSelectable(void) const + { + return false; + } + + virtual int exec(CMenuTarget* parent) + { + return 0; + } + virtual void setActive(const bool Active); +}; + +class CMenuSeparator : public CMenuItem +{ + int type; + + public: + neutrino_locale_t text; + + enum + { + EMPTY = 0, + LINE = 1, + STRING = 2, + ALIGN_CENTER = 4, + ALIGN_LEFT = 8, + ALIGN_RIGHT = 16 + }; + + + CMenuSeparator(const int Type = 0, const neutrino_locale_t Text = NONEXISTANT_LOCALE); + + int paint(bool selected=false, bool last = false); + int getHeight(void) const; + int getWidth(void) const; + + virtual const char * getString(void); +}; + +class CMenuForwarder : public CMenuItem +{ + const char * option; + const std::string * option_string; + CMenuTarget * jumpTarget; + std::string actionKey; + + protected: + neutrino_locale_t text; + + virtual const char * getOption(void); + virtual const char * getName(void); + + public: + + CMenuForwarder(const neutrino_locale_t Text, const bool Active=true, const char * const Option=NULL, CMenuTarget* Target=NULL, const char * const ActionKey = NULL, const neutrino_msg_t DirectKey = CRCInput::RC_nokey, const char * const IconName = NULL); + CMenuForwarder(const neutrino_locale_t Text, const bool Active, const std::string &Option, CMenuTarget* Target=NULL, const char * const ActionKey = NULL, const neutrino_msg_t DirectKey = CRCInput::RC_nokey, const char * const IconName = NULL); + int paint(bool selected=false, bool last = false); + int getHeight(void) const; + int getWidth(void) const; + int exec(CMenuTarget* parent); + bool isSelectable(void) const + { + return active; + } +}; + +class CMenuForwarderNonLocalized : public CMenuForwarder +{ + protected: + std::string the_text; + virtual const char * getName(void); + public: + // Text must be UTF-8 encoded: + CMenuForwarderNonLocalized(const char * const Text, const bool Active=true, const char * const Option=NULL, CMenuTarget* Target=NULL, const char * const ActionKey = NULL, const neutrino_msg_t DirectKey = CRCInput::RC_nokey, const char * const IconName = NULL); + CMenuForwarderNonLocalized(const char * const Text, const bool Active, const std::string &Option, CMenuTarget* Target=NULL, const char * const ActionKey = NULL, const neutrino_msg_t DirectKey = CRCInput::RC_nokey, const char * const IconName = NULL); + +}; + +class CAbstractMenuOptionChooser : public CMenuItem +{ + protected: + neutrino_locale_t optionName; + int height; + int * optionValue; + + int getHeight(void) const + { + return height; + } + + bool isSelectable(void) const + { + return active; + } +}; + +class CMenuOptionNumberChooser : public CAbstractMenuOptionChooser +{ + const char * optionString; + + int lower_bound; + int upper_bound; + + int display_offset; + + int localized_value; + neutrino_locale_t localized_value_name; + private: + CChangeObserver * observ; + + public: + CMenuOptionNumberChooser(const neutrino_locale_t name, int * const OptionValue, const bool Active, const int min_value, const int max_value, CChangeObserver * const Observ = NULL, const int print_offset = 0, const int special_value = 0, const neutrino_locale_t special_value_name = NONEXISTANT_LOCALE, const char * non_localized_name = NULL); + + int paint(bool selected, bool last = false); + + int exec(CMenuTarget* parent); +}; + +class CMenuOptionChooser : public CAbstractMenuOptionChooser +{ + public: + struct keyval + { + const int key; + const neutrino_locale_t value; + const char * valname; + }; + + private: + const struct keyval * options; + unsigned number_of_options; + CChangeObserver * observ; + std::string optionNameString; + bool pulldown; + + public: + CMenuOptionChooser(const neutrino_locale_t OptionName, int * const OptionValue, const struct keyval * const Options, const unsigned Number_Of_Options, const bool Active = false, CChangeObserver * const Observ = NULL, const neutrino_msg_t DirectKey = CRCInput::RC_nokey, const std::string & IconName= "", bool Pulldown = false); + CMenuOptionChooser(const char* OptionName, int * const OptionValue, const struct keyval * const Options, const unsigned Number_Of_Options, const bool Active = false, CChangeObserver * const Observ = NULL, const neutrino_msg_t DirectKey = CRCInput::RC_nokey, const std::string & IconName= "", bool Pulldown = false); + + void setOptionValue(const int newvalue); + int getOptionValue(void) const; + + int paint(bool selected, bool last = 0); + + int exec(CMenuTarget* parent); +}; + +class CMenuOptionStringChooser : public CMenuItem +{ + neutrino_locale_t optionName; + int height; + char * optionValue; + std::vector options; + CChangeObserver * observ; + bool pulldown; + + public: + CMenuOptionStringChooser(const neutrino_locale_t OptionName, char* OptionValue, bool Active = false, CChangeObserver* Observ = NULL, const neutrino_msg_t DirectKey = CRCInput::RC_nokey, const std::string & IconName= "", bool Pulldown = false); + ~CMenuOptionStringChooser(); + + void addOption(const char * value); + int paint(bool selected, bool last = 0); + int getHeight(void) const + { + return height; + } + bool isSelectable(void) const + { + return active; + } + + int exec(CMenuTarget* parent); +}; + +class CMenuOptionLanguageChooser : public CMenuItem +{ + int height; + char * optionValue; + std::vector options; + CChangeObserver * observ; + + public: + CMenuOptionLanguageChooser(char* OptionValue, CChangeObserver* Observ = NULL, const char * const IconName = NULL); + ~CMenuOptionLanguageChooser(); + + void addOption(const char * value); + int paint(bool selected, bool last = 0); + int getHeight(void) const + { + return height; + } + bool isSelectable(void) const + { + return true; + } + + int exec(CMenuTarget* parent); +}; + +class CMenuWidget : public CMenuTarget +{ + protected: + std::string nameString; + neutrino_locale_t name; + CFrameBuffer *frameBuffer; + std::vector items; + std::vector page_start; + std::string iconfile; + + int width; + int height; + int wanted_height; + int x; + int y; + int offx, offy; + int selected; + int iconOffset; + unsigned int item_start_y; + unsigned int current_page; + unsigned int total_pages; + bool exit_pressed; + void Init(const std::string & Icon, const int mwidth, const int mheight); + virtual void paintItems(); + + public: + CMenuWidget(); + CMenuWidget(const char* Name, const std::string & Icon = "", const int mwidth = 400, const int mheight = 576); + CMenuWidget(const neutrino_locale_t Name, const std::string & Icon = "", const int mwidth = 400, const int mheight = 576); + ~CMenuWidget(); + + virtual void addItem(CMenuItem* menuItem, const bool defaultselected = false); + bool hasItem(); + virtual void paint(); + virtual void hide(); + virtual int exec(CMenuTarget* parent, const std::string & actionKey); + void setSelected(unsigned int _new) { if(_new <= items.size()) selected = _new; }; + int getSelected() { return selected; }; + void move(int xoff, int yoff); + int getSelectedLine(void){return exit_pressed ? -1 : selected;}; +}; + +class CPINProtection +{ + protected: + char* validPIN; + bool check(); + virtual CMenuTarget* getParent() = 0; + public: + CPINProtection( char* validpin){ validPIN = validpin;}; +}; + +class CZapProtection : public CPINProtection +{ + protected: + virtual CMenuTarget* getParent() { return( NULL);}; + public: + int fsk; + + CZapProtection( char* validpin, int FSK ) : CPINProtection(validpin){ fsk= FSK; }; + bool check(); +}; + +class CLockedMenuForwarder : public CMenuForwarder, public CPINProtection +{ + CMenuTarget* Parent; + bool AlwaysAsk; + + protected: + virtual CMenuTarget* getParent(){ return Parent;}; + public: + CLockedMenuForwarder(const neutrino_locale_t Text, char* validPIN, bool alwaysAsk=false, const bool Active=true, char *Option=NULL, + CMenuTarget* Target=NULL, const char * const ActionKey = NULL, + neutrino_msg_t DirectKey = CRCInput::RC_nokey, const char * const IconName = NULL) + + : CMenuForwarder(Text, Active, Option, Target, ActionKey, DirectKey, IconName) , + CPINProtection( validPIN){AlwaysAsk = alwaysAsk;}; + + virtual int exec(CMenuTarget* parent); +}; + +class CMenuSelectorTarget : public CMenuTarget +{ + public: + CMenuSelectorTarget(int *select) {m_select = select;}; + int exec(CMenuTarget* parent, const std::string & actionKey); + + private: + int *m_select; +}; + +extern CMenuSeparator * const GenericMenuSeparator; +extern CMenuSeparator * const GenericMenuSeparatorLine; +extern CMenuForwarder * const GenericMenuBack; + +#endif diff --git a/src/gui/widget/messagebox.cpp b/src/gui/widget/messagebox.cpp new file mode 100644 index 000000000..d08d8de7b --- /dev/null +++ b/src/gui/widget/messagebox.cpp @@ -0,0 +1,301 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#define ROUND_RADIUS 9 + +CMessageBox::CMessageBox(const neutrino_locale_t Caption, const char * const Text, const int Width, const char * const Icon, const CMessageBox::result_ Default, const uint32_t ShowButtons) : CHintBoxExt(Caption, Text, Width, Icon) +{ + returnDefaultOnTimeout = false; + + m_height += (m_fheight << 1); + + result = Default; + + showbuttons = ShowButtons; + + int MaxButtonTextWidth = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getRenderWidth(g_Locale->getText(LOCALE_MESSAGEBOX_CANCEL), true); // UTF-8 + int ButtonWidth = 20 + 33 + MaxButtonTextWidth + 5; + int num = 0; + if (showbuttons & mbYes) + num++; + if (showbuttons & mbNo) + num++; + if (showbuttons & (mbCancel | mbBack)) + num++; + int new_width = 15 + num*ButtonWidth; + if(new_width > m_width) + m_width = new_width; +} + +CMessageBox::CMessageBox(const neutrino_locale_t Caption, ContentLines& Lines, const int Width, const char * const Icon, const CMessageBox::result_ Default, const uint32_t ShowButtons) : CHintBoxExt(Caption, Lines, Width, Icon) +{ + returnDefaultOnTimeout = false; + + m_height += (m_fheight << 1); + + result = Default; + + showbuttons = ShowButtons; + int MaxButtonTextWidth = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getRenderWidth(g_Locale->getText(LOCALE_MESSAGEBOX_CANCEL), true); // UTF-8 + int ButtonWidth = 20 + 33 + MaxButtonTextWidth + 5; + int num = 0; + if (showbuttons & mbYes) + num++; + if (showbuttons & mbNo) + num++; + if (showbuttons & (mbCancel | mbBack)) + num++; + int new_width = 15 + num*ButtonWidth; + if(new_width > m_width) + m_width = new_width; +} + +void CMessageBox::returnDefaultValueOnTimeout(bool returnDefault) +{ + returnDefaultOnTimeout = returnDefault; +} + +void CMessageBox::paintButtons() +{ + uint8_t color; + fb_pixel_t bgcolor; + + //m_window->paintBoxRel(0, m_height - (m_fheight << 1), m_width, (m_fheight << 1), (CFBWindow::color_t)COL_MENUCONTENT_PLUS_0); + m_window->paintBoxRel(0, m_height - (m_fheight << 1), m_width, (m_fheight << 1), (CFBWindow::color_t)COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2); + + //irgendwann alle vergleichen - aber cancel ist sicher der längste + int MaxButtonTextWidth = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getRenderWidth(g_Locale->getText(LOCALE_MESSAGEBOX_CANCEL), true); // UTF-8 + + int ButtonWidth = 20 + 33 + MaxButtonTextWidth; + +// int ButtonSpacing = 40; +// int startpos = (m_width - ((ButtonWidth*3)+(ButtonSpacing*2))) / 2; + + int ButtonSpacing = (m_width - 20 - (ButtonWidth * 3)) / 2; + if(ButtonSpacing <= 5) ButtonSpacing = 5; + + int xpos = 10; + + if (showbuttons & mbYes) + { + if (result == mbrYes) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + else + { + color = COL_INFOBAR_SHADOW; + bgcolor = COL_INFOBAR_SHADOW_PLUS_0; + } + //m_window->paintBoxRel(xpos, m_height - m_fheight - 20, ButtonWidth, m_fheight, (CFBWindow::color_t)bgcolor); + m_window->paintBoxRel(xpos, m_height - m_fheight - 20, ButtonWidth, m_fheight, (CFBWindow::color_t)bgcolor, ROUND_RADIUS, 3);//round + m_window->paintIcon(NEUTRINO_ICON_BUTTON_RED, xpos + 14, m_height - m_fheight - 15); + m_window->RenderString(g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], xpos + 43, m_height-m_fheight+4, ButtonWidth- 53, g_Locale->getText(LOCALE_MESSAGEBOX_YES), (CFBWindow::color_t)color, 0, true); // UTF-8 + xpos += ButtonWidth + ButtonSpacing; + } + + + if (showbuttons & mbNo) + { + if (result == mbrNo) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + else + { + color = COL_INFOBAR_SHADOW; + bgcolor = COL_INFOBAR_SHADOW_PLUS_0; + } + + //m_window->paintBoxRel(xpos, m_height-m_fheight-20, ButtonWidth, m_fheight, (CFBWindow::color_t)bgcolor); + m_window->paintBoxRel(xpos, m_height-m_fheight-20, ButtonWidth, m_fheight, (CFBWindow::color_t)bgcolor, ROUND_RADIUS, 3);//round + m_window->paintIcon(NEUTRINO_ICON_BUTTON_GREEN, xpos+14, m_height-m_fheight-15); + m_window->RenderString(g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], xpos + 43, m_height-m_fheight+4, ButtonWidth- 53, g_Locale->getText(LOCALE_MESSAGEBOX_NO), (CFBWindow::color_t)color, 0, true); // UTF-8 + xpos += ButtonWidth + ButtonSpacing; + } + + + if (showbuttons & (mbCancel | mbBack)) + { + if (result >= mbrCancel) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + else + { + color = COL_INFOBAR_SHADOW; + bgcolor = COL_INFOBAR_SHADOW_PLUS_0; + } + + //m_window->paintBoxRel(xpos, m_height-m_fheight-20, ButtonWidth, m_fheight, (CFBWindow::color_t)bgcolor); + m_window->paintBoxRel(xpos, m_height-m_fheight-20, ButtonWidth, m_fheight, (CFBWindow::color_t)bgcolor, ROUND_RADIUS, 3);//round + m_window->paintIcon(NEUTRINO_ICON_BUTTON_HOME, xpos+10, m_height-m_fheight-19); + m_window->RenderString(g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], xpos + 43, m_height-m_fheight+4, ButtonWidth- 53, g_Locale->getText((showbuttons & mbCancel) ? LOCALE_MESSAGEBOX_CANCEL : LOCALE_MESSAGEBOX_BACK), (CFBWindow::color_t)color, 0, true); // UTF-8 + } +} + +int CMessageBox::exec(int timeout) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = menu_return::RETURN_REPAINT; + + CHintBoxExt::paint(0); + + if (m_window == NULL) + { + return res; /* out of memory */ + } + + paintButtons(); + + if ( timeout == -1 ) + timeout = g_settings.timing[SNeutrinoSettings::TIMING_EPG]; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd( timeout ); + + bool loop=true; + while (loop) + { + + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + if (msg == CRCInput::RC_timeout && returnDefaultOnTimeout) + { + // return default + loop = false; + } + else if (((msg == CRCInput::RC_timeout) || + (msg == (neutrino_msg_t)g_settings.key_channelList_cancel)) && + (showbuttons & (mbCancel | mbBack))) + { + result = (showbuttons & mbCancel) ? mbrCancel : mbrBack; + loop = false; + } + else if ((msg == CRCInput::RC_green) && (showbuttons & mbNo)) + { + result = mbrNo; + loop = false; + } + else if ((msg == CRCInput::RC_red) && (showbuttons & mbYes)) + { + result = mbrYes; + loop = false; + } + else if(msg==CRCInput::RC_right) + { + bool ok = false; + while (!ok) + { + result = (CMessageBox::result_)((result + 1) & 3); + ok = showbuttons & (1 << result); + } + + paintButtons(); + } + else if (has_scrollbar() && ((msg == CRCInput::RC_up) || (msg == CRCInput::RC_down))) + { + if (msg == CRCInput::RC_up) + scroll_up(); + else + scroll_down(); + } + else if(msg==CRCInput::RC_left) + { + bool ok = false; + while (!ok) + { + result = (CMessageBox::result_)((result - 1) & 3); + ok = showbuttons & (1 << result); + } + + paintButtons(); + + } + else if(msg == CRCInput::RC_ok) + { + loop = false; + } + else if((msg == CRCInput::RC_sat) || (msg == CRCInput::RC_favorites)) + { + } + else if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) + { + res = menu_return::RETURN_EXIT_ALL; + loop = false; + } + + } + + hide(); + + return res; +} + +int ShowMsgUTF(const neutrino_locale_t Caption, const char * const Text, const CMessageBox::result_ Default, const uint32_t ShowButtons, const char * const Icon, const int Width, const int timeout, bool returnDefaultOnTimeout) +{ + CMessageBox* messageBox = new CMessageBox(Caption, Text, Width, Icon, Default, ShowButtons); + messageBox->returnDefaultValueOnTimeout(returnDefaultOnTimeout); + messageBox->exec(timeout); + int res = messageBox->result; + delete messageBox; + + return res; +} + +int ShowLocalizedMessage(const neutrino_locale_t Caption, const neutrino_locale_t Text, const CMessageBox::result_ Default, const uint32_t ShowButtons, const char * const Icon, const int Width, const int timeout, bool returnDefaultOnTimeout) +{ + return ShowMsgUTF(Caption, g_Locale->getText(Text), Default, ShowButtons, Icon, Width, timeout,returnDefaultOnTimeout); +} + +int ShowMsgUTF(const neutrino_locale_t Caption, const std::string & Text, const CMessageBox::result_ Default, const uint32_t ShowButtons, const char * const Icon, const int Width, const int timeout, bool returnDefaultOnTimeout) +{ + return ShowMsgUTF(Caption, Text.c_str(), Default, ShowButtons, Icon, Width, timeout,returnDefaultOnTimeout); +} + +void DisplayErrorMessage(const char * const ErrorMsg) +{ + ShowMsgUTF(LOCALE_MESSAGEBOX_ERROR, ErrorMsg, CMessageBox::mbrCancel, CMessageBox::mbCancel, "error.raw"); +} diff --git a/src/gui/widget/messagebox.h b/src/gui/widget/messagebox.h new file mode 100644 index 000000000..a5bf8390d --- /dev/null +++ b/src/gui/widget/messagebox.h @@ -0,0 +1,84 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __messagebox__ +#define __messagebox__ + +#include + +#include + + +class CMessageBox : public CHintBoxExt +{ + private: + + int showbuttons; + bool returnDefaultOnTimeout; + + void paintButtons(); + + public: + enum result_ + { + mbrYes = 0, + mbrNo = 1, + mbrCancel = 2, + mbrBack = 3 + } result; + + enum buttons_ + { + mbYes= 0x01, + mbNo = 0x02, + mbCancel = 0x04, + mbAll = 0x07, + mbBack = 0x08 + } buttons; + + // Text & Caption are always UTF-8 encoded + CMessageBox(const neutrino_locale_t Caption, const char * const Text, const int Width = 500, const char * const Icon = NULL, const CMessageBox::result_ Default = mbrYes, const uint32_t ShowButtons = mbAll); + + CMessageBox(const neutrino_locale_t Caption, ContentLines& Lines, const int Width = 500, const char * const Icon = NULL, const CMessageBox::result_ Default = mbrYes, const uint32_t ShowButtons = mbAll); + + int exec(int timeout = -1); + void returnDefaultValueOnTimeout(bool returnDefault); +}; + +// Text is always UTF-8 encoded +int ShowLocalizedMessage(const neutrino_locale_t Caption, const neutrino_locale_t Text, const CMessageBox::result_ Default, const uint32_t ShowButtons, const char * const Icon = NULL, const int Width = 450, const int timeout = -1, bool returnDefaultOnTimeout = false); +int ShowMsgUTF(const neutrino_locale_t Caption, const char * const Text, const CMessageBox::result_ Default, const uint32_t ShowButtons, const char * const Icon = NULL, const int Width = 450, const int timeout = -1, bool returnDefaultOnTimeout = false); // UTF-8 +int ShowMsgUTF(const neutrino_locale_t Caption, const std::string & Text, const CMessageBox::result_ Default, const uint32_t ShowButtons, const char * const Icon = NULL, const int Width = 450, const int timeout = -1, bool returnDefaultOnTimeout = false); // UTF-8 + +void DisplayErrorMessage(const char * const ErrorMsg); // UTF-8 + +#endif diff --git a/src/gui/widget/mountchooser.cpp b/src/gui/widget/mountchooser.cpp new file mode 100644 index 000000000..d71a7988d --- /dev/null +++ b/src/gui/widget/mountchooser.cpp @@ -0,0 +1,98 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include +#include + +CMountChooser::CMountChooser(const neutrino_locale_t Name, const std::string & Icon, int * chosenIndex, char * chosenLocalDir, const char * const selectedLocalDir, const int mwidth, const int mheight) + : CMenuWidget(Name, Icon,mwidth,mheight), index(chosenIndex), localDir(chosenLocalDir) +{ + char indexStr[2]; + for(int i=0 ; i < NETWORK_NFS_NR_OF_ENTRIES ; i++) + { + if (g_settings.network_nfs_local_dir[i] != NULL && + strcmp(g_settings.network_nfs_local_dir[i],"") != 0 && + (strstr(g_settings.network_nfs_mount_options1[i],"rw") != NULL || + strstr(g_settings.network_nfs_mount_options2[i],"rw") != NULL)) + { + std::string s(g_settings.network_nfs_local_dir[i]); + s += " ("; + s += g_settings.network_nfs_ip[i]; + s += ":"; + s += g_settings.network_nfs_dir[i]; + s +=")"; + snprintf(indexStr,2,"%d",i); + addItem(new CMenuForwarderNonLocalized(s.c_str(),true,NULL,this,(std::string("MID:") + std::string(indexStr)).c_str()), + (strcmp(selectedLocalDir,g_settings.network_nfs_local_dir[i]) == 0)); + } + } +} + + +int CMountChooser::exec(CMenuTarget* parent, const std::string & actionKey) +{ + + const char * key = actionKey.c_str(); + if (strncmp(key, "MID:",4) == 0) + { + int mount_id = -1; + sscanf(&key[4],"%d",&mount_id); + if ((mount_id > -1) && (mount_id < NETWORK_NFS_NR_OF_ENTRIES)) + { + if (index) + *index = mount_id; + if (localDir) + strcpy(localDir,g_settings.network_nfs_local_dir[mount_id]); + } + hide(); + return menu_return::RETURN_EXIT; + } else + { + return CMenuWidget::exec(parent, actionKey); + } +} + +void CMountChooser::setSelectedItem(int selection) +{ + selected = selection; +} + + + diff --git a/src/gui/widget/mountchooser.h b/src/gui/widget/mountchooser.h new file mode 100644 index 000000000..da7a030d5 --- /dev/null +++ b/src/gui/widget/mountchooser.h @@ -0,0 +1,67 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __mountchooser__ +#define __mountchooser__ + +#include +#include +#include + +#include + +/* +class CMountChooserTarget : CMenuTarget +{ +public: + + int CMountChooser::exec(CMenuTarget* parent, const std::string & actionKey); +}; +*/ + +class CMountChooser : public CMenuWidget +{ + private: + int * index; + char * localDir; + + public: + + CMountChooser(const neutrino_locale_t Name, const std::string & Icon = "", int * chosenIndex = NULL, char * chosenLocalDir = NULL, const char * const selectedLocalDir = "", const int mwidth = 400, const int mheight = 576); + int exec(CMenuTarget* parent, const std::string & actionKey); + void setSelectedItem(int selection); + +}; + + +#endif + diff --git a/src/gui/widget/msgbox.cpp b/src/gui/widget/msgbox.cpp new file mode 100644 index 000000000..df93882dd --- /dev/null +++ b/src/gui/widget/msgbox.cpp @@ -0,0 +1,860 @@ +/* + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + *********************************************************** + + Module Name: msgbox.cpp: . + + Description: Implementation of the CMsgBox class + This class provides a message box using CTextBox. + + Date: Nov 2005 + + Author: Gnther@tuxbox.berlios.org + based on code of Steffen Hehn 'McClean' + + Revision History: + Date Author Change Description + Nov 2005 Gnther initial implementation +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "msgbox.h" + +#include +#include + +#define WINDOW_FRAME_BORDER_WIDTH 4 +#define ADD_FOOT_HEIGHT 20 +#define TEXT_BORDER_WIDTH 8 +#define TITLE_ICON_WIDTH (40 - TEXT_BORDER_WIDTH) + +#define MAX_WINDOW_WIDTH (g_settings.screen_EndX - g_settings.screen_StartX ) +#define MAX_WINDOW_HEIGHT (g_settings.screen_EndY - g_settings.screen_StartY - 40) + +#define MIN_WINDOW_WIDTH (MAX_WINDOW_WIDTH>>1) +#define MIN_WINDOW_HEIGHT 40 + +#define DEFAULT_TITLE_FONT g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE] +#define DEFAULT_FOOT_FONT g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL] + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////// +// Function Name: CMsgBox +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +CMsgBox::CMsgBox( const char * text, + Font* fontText, + const int _mode, + const CBox* position, + const char * title, + Font* fontTitle, + const char * icon, + int return_button , + const result_ default_result) +{ + //TRACE("->CMsgBox::CMsgBox\r\n"); + initVar(); + + if(title != NULL) m_cTitle = title; + if(fontTitle != NULL) m_pcFontTitle = fontTitle; + if(icon != NULL) m_cIcon = icon; + if(position != NULL) m_cBoxFrame = *position; + m_nMode = _mode; + //TRACE(" CMsgBox::cText: %d ,m_cTitle %d,m_nMode %d\t\r\n",strlen(text),m_cTitle.size(),m_nMode); + + if(m_nMode & BORDER) + m_nWindowFrameBorderWidth = WINDOW_FRAME_BORDER_WIDTH; + else + m_nWindowFrameBorderWidth = 0; + + //TRACE(" Mode: "); + //if(_mode & BORDER) TRACE("BORDER "); + //if(_mode & TITLE) TRACE("TITLE "); + //if(_mode & FOOT) TRACE("FOOT "); + //if(_mode & CENTER) TRACE("CENTER"); + //TRACE("\r\n"); + + //TRACE_1(" m_nWindowFrameBorderWidth: \t%d\r\n",m_nWindowFrameBorderWidth); + + + /* Initialise the window frames first */ + initFramesRel(); + + m_pcTextBox = new CTextBox( text, + fontText, + _mode, + &m_cBoxFrameText); + + if(_mode & AUTO_WIDTH || _mode & AUTO_HIGH) + { + /* window might changed in size ...*/ + m_cBoxFrameText = m_pcTextBox->getWindowsPos(); + + m_cBoxFrame.iWidth = m_cBoxFrameText.iWidth + m_nWindowFrameBorderWidth; + m_cBoxFrame.iHeight = m_cBoxFrameText.iHeight + m_cBoxFrameFootRel.iHeight + m_cBoxFrameTitleRel.iHeight + m_nWindowFrameBorderWidth; + + initFramesRel(); + } + + if(_mode & CENTER) + { + m_cBoxFrame.iX = g_settings.screen_StartX + ((g_settings.screen_EndX - g_settings.screen_StartX - m_cBoxFrame.iWidth) >>1); + m_cBoxFrame.iY = g_settings.screen_StartY + ((g_settings.screen_EndY - g_settings.screen_StartY - m_cBoxFrame.iHeight) >>2); + } + + m_nResult = default_result; + m_nFootButtons = return_button; +} + +////////////////////////////////////////////////////////////////////// +// Function Name: CMsgBox +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +CMsgBox::CMsgBox(const char * text) +{ + initVar(); + + m_pcTextBox = new CTextBox( text); + /* Initialise the window frames first */ + initFramesRel(); +} + +////////////////////////////////////////////////////////////////////// +// Function Name: CMsgBox +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +CMsgBox::CMsgBox() +{ + m_pcTextBox = NULL; + + initVar(); + initFramesRel(); +} + +////////////////////////////////////////////////////////////////////// +// Function Name: ~CMsgBox +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +CMsgBox::~CMsgBox() +{ + if (m_pcWindow != NULL) + { + delete m_pcWindow; + m_pcWindow = NULL; + } + + if (m_pcTextBox != NULL) + { + delete m_pcTextBox; + m_pcTextBox = NULL; + } + +} + +////////////////////////////////////////////////////////////////////// +// Function Name: InitVar +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +void CMsgBox::initVar(void) +{ + //TRACE("->CMsgBox::InitVar\r\n"); + m_cTitle = ""; + m_cIcon = ""; + m_nMode = SCROLL | TITLE | BORDER ; + + // set the title varianles + m_pcFontTitle = DEFAULT_TITLE_FONT; + m_nFontTitleHeight = m_pcFontTitle->getHeight(); + + // set the foot variables + m_pcFontFoot = DEFAULT_FOOT_FONT; + m_nFontFootHeight = m_pcFontFoot->getHeight(); + m_nFootButtons = 0; + + // set the main frame border width + if(m_nMode & BORDER) + m_nWindowFrameBorderWidth = WINDOW_FRAME_BORDER_WIDTH; + else + m_nWindowFrameBorderWidth = 0; + + // set the main frame to default + m_cBoxFrame.iX = g_settings.screen_StartX + ((g_settings.screen_EndX - g_settings.screen_StartX - MIN_WINDOW_WIDTH) >>1); + m_cBoxFrame.iWidth = MIN_WINDOW_WIDTH; + m_cBoxFrame.iY = g_settings.screen_StartY + ((g_settings.screen_EndY - g_settings.screen_StartY - MIN_WINDOW_HEIGHT) >>2); + m_cBoxFrame.iHeight = MIN_WINDOW_HEIGHT; + + m_pcWindow = NULL; + + //TRACE_1(" m_nWindowFrameBorderWidth: \t%d\r\n",m_nWindowFrameBorderWidth); +} + +////////////////////////////////////////////////////////////////////// +// Function Name: InitFramesRel +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +void CMsgBox::initFramesRel(void) +{ + //TRACE("->CMsgBox::InitFramesRel\r\n"); + // init the title frame + if(m_nMode & TITLE) + { + m_cBoxFrameTitleRel.iX = 0; + m_cBoxFrameTitleRel.iY = 0; + m_cBoxFrameTitleRel.iWidth = m_cBoxFrame.iWidth - m_nWindowFrameBorderWidth; + m_cBoxFrameTitleRel.iHeight = m_nFontTitleHeight + 2; + } + else + { + m_cBoxFrameTitleRel.iX = 0; + m_cBoxFrameTitleRel.iY = 0; + m_cBoxFrameTitleRel.iHeight = 0; + m_cBoxFrameTitleRel.iWidth = 0; + } + + // init the foot frame + if(m_nMode & FOOT) + { + m_cBoxFrameFootRel.iX = 0; + m_cBoxFrameFootRel.iY = m_cBoxFrame.iHeight - m_nFontFootHeight - m_nWindowFrameBorderWidth - ADD_FOOT_HEIGHT; + m_cBoxFrameFootRel.iWidth = m_cBoxFrame.iWidth - m_nWindowFrameBorderWidth; + m_cBoxFrameFootRel.iHeight = m_nFontFootHeight + ADD_FOOT_HEIGHT; + } + else + { + m_cBoxFrameFootRel.iX = 0; + m_cBoxFrameFootRel.iY = 0; + m_cBoxFrameFootRel.iHeight = 0; + m_cBoxFrameFootRel.iWidth = 0; + } + + // init the text frame + m_cBoxFrameText.iY = m_cBoxFrame.iY + m_cBoxFrameTitleRel.iY + m_cBoxFrameTitleRel.iHeight; + m_cBoxFrameText.iX = m_cBoxFrame.iX + m_cBoxFrameTitleRel.iX; + m_cBoxFrameText.iHeight = m_cBoxFrame.iHeight - m_cBoxFrameTitleRel.iHeight - m_cBoxFrameFootRel.iHeight - m_nWindowFrameBorderWidth; + m_cBoxFrameText.iWidth = m_cBoxFrame.iWidth - m_nWindowFrameBorderWidth; +#if 0 + TRACE_1("Frames\r\n\tScren:\t%3d,%3d,%3d,%3d\r\n\tMain:\t%3d,%3d,%3d,%3d\r\n\tText:\t%3d,%3d,%3d,%3d \r\n\tTitle:\t%3d,%3d,%3d,%3d \r\n\tFoot:\t%3d,%3d,%3d,%3d\r\n\r\n", + g_settings.screen_StartX, + g_settings.screen_StartY, + g_settings.screen_EndX, + g_settings.screen_EndY, + m_cBoxFrame.iX, + m_cBoxFrame.iY, + m_cBoxFrame.iWidth, + m_cBoxFrame.iHeight, + m_cBoxFrameText.iX, + m_cBoxFrameText.iY, + m_cBoxFrameText.iWidth, + m_cBoxFrameText.iHeight, + m_cBoxFrameTitleRel.iX, + m_cBoxFrameTitleRel.iY, + m_cBoxFrameTitleRel.iWidth, + m_cBoxFrameTitleRel.iHeight, + m_cBoxFrameFootRel.iX, + m_cBoxFrameFootRel.iY, + m_cBoxFrameFootRel.iWidth, + m_cBoxFrameFootRel.iHeight + ); +#endif +} + +////////////////////////////////////////////////////////////////////// +// Function Name: RefreshFoot +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +void CMsgBox::refreshFoot(void) +{ + int color,bgcolor; + if( !(m_nMode & FOOT)) return; + + // draw the background first + m_pcWindow->paintBoxRel( m_cBoxFrameFootRel.iX+m_cBoxFrame.iX, + m_cBoxFrameFootRel.iY+m_cBoxFrame.iY, + m_cBoxFrameFootRel.iWidth, + m_cBoxFrameFootRel.iHeight, + (CFBWindow::color_t)COL_MENUHEAD_PLUS_0); + + //const char* text; + + int MaxButtonTextWidth = m_pcFontFoot->getRenderWidth(g_Locale->getText(LOCALE_MESSAGEBOX_CANCEL), true); // UTF-8 + int ButtonWidth = 20 + 33 + MaxButtonTextWidth; + int ButtonSpacing = (m_cBoxFrameFootRel.iWidth - 20- (ButtonWidth*3) ) / 2; + int xpos = m_cBoxFrameFootRel.iX; + + // draw Button mbYes + if (m_nFootButtons & mbYes) + { + if (m_nResult == mbrYes) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + else + { + color = COL_INFOBAR_SHADOW; + bgcolor = COL_INFOBAR_SHADOW_PLUS_0; + } + m_pcWindow->paintBoxRel(xpos+m_cBoxFrame.iX, m_cBoxFrameFootRel.iY + (ADD_FOOT_HEIGHT>>1)+m_cBoxFrame.iY, ButtonWidth, m_nFontFootHeight + 4, (CFBWindow::color_t)bgcolor); + m_pcWindow->paintIcon(NEUTRINO_ICON_BUTTON_RED, xpos + 14+m_cBoxFrame.iX, m_cBoxFrameFootRel.iY + (ADD_FOOT_HEIGHT>>1)+m_cBoxFrame.iY); + /*m_pcWindow->RenderString(*/ + m_pcFontFoot->RenderString(xpos + 43+m_cBoxFrame.iX, m_cBoxFrameFootRel.iY + m_nFontFootHeight + 4 + (ADD_FOOT_HEIGHT>>1)+m_cBoxFrame.iY, ButtonWidth - 53, g_Locale->getText(LOCALE_MESSAGEBOX_YES), (CFBWindow::color_t)color, 0, true); // UTF-8 + } + + xpos += ButtonWidth + ButtonSpacing; + + // draw Button mbNo + if (m_nFootButtons & mbNo) + { + if (m_nResult == mbrNo) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + else + { + color = COL_INFOBAR_SHADOW; + bgcolor = COL_INFOBAR_SHADOW_PLUS_0; + } + + m_pcWindow->paintBoxRel(xpos+m_cBoxFrame.iX, m_cBoxFrameFootRel.iY + (ADD_FOOT_HEIGHT>>1)+m_cBoxFrame.iY, ButtonWidth, m_nFontFootHeight + 4, (CFBWindow::color_t)bgcolor); + m_pcWindow->paintIcon(NEUTRINO_ICON_BUTTON_GREEN, xpos + 14+m_cBoxFrame.iX, m_cBoxFrameFootRel.iY + (ADD_FOOT_HEIGHT>>1)+m_cBoxFrame.iY); + /*m_pcWindow->RenderString(*/ + m_pcFontFoot->RenderString(xpos + 43+m_cBoxFrame.iX, m_cBoxFrameFootRel.iY + m_nFontFootHeight + 4 + (ADD_FOOT_HEIGHT>>1)+m_cBoxFrame.iY, ButtonWidth- 53, g_Locale->getText(LOCALE_MESSAGEBOX_NO), (CFBWindow::color_t)color, 0, true); // UTF-8 + } + + xpos += ButtonWidth + ButtonSpacing; + + // draw Button mbCancel + if (m_nFootButtons & (mbCancel | mbBack)) + { + if (m_nResult >= mbrCancel) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + else + { + color = COL_INFOBAR_SHADOW; + bgcolor = COL_INFOBAR_SHADOW_PLUS_0; + } + + m_pcWindow->paintBoxRel(xpos+m_cBoxFrame.iX, m_cBoxFrameFootRel.iY + (ADD_FOOT_HEIGHT>>1)+m_cBoxFrame.iY, ButtonWidth, m_nFontFootHeight + 4, (CFBWindow::color_t)bgcolor); + m_pcWindow->paintIcon(NEUTRINO_ICON_BUTTON_HOME, xpos+10+m_cBoxFrame.iX, m_cBoxFrameFootRel.iY + (ADD_FOOT_HEIGHT>>1)+m_cBoxFrame.iY); + /*m_pcWindow->RenderString(*/ + m_pcFontFoot->RenderString(xpos + 43+m_cBoxFrame.iX, m_cBoxFrameFootRel.iY + m_nFontFootHeight + 2 + (ADD_FOOT_HEIGHT>>1)+m_cBoxFrame.iY, ButtonWidth- 53, g_Locale->getText((m_nFootButtons & mbCancel) ? LOCALE_MESSAGEBOX_CANCEL : LOCALE_MESSAGEBOX_BACK), (CFBWindow::color_t)color, 0, true); // UTF-8 + } +} + +////////////////////////////////////////////////////////////////////// +// Function Name: RefreshTitle +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +void CMsgBox::refreshTitle(void) +{ + // first check if title is configured + if( !(m_nMode & TITLE)) return; + + // draw the background + m_pcWindow->paintBoxRel( m_cBoxFrameTitleRel.iX+m_cBoxFrame.iX, + m_cBoxFrameTitleRel.iY+m_cBoxFrame.iY, + m_cBoxFrameTitleRel.iWidth, + m_cBoxFrameTitleRel.iHeight, + (CFBWindow::color_t)COL_MENUHEAD_PLUS_0); + + if (!m_cIcon.empty()) + { + // draw icon and title text + m_pcWindow->paintIcon(m_cIcon.c_str(), m_cBoxFrameTitleRel.iX + 8+m_cBoxFrame.iX, m_cBoxFrameTitleRel.iY + 5+m_cBoxFrame.iY); + /*m_pcWindow->RenderString(*/ + m_pcFontTitle->RenderString( + m_cBoxFrameTitleRel.iX + TITLE_ICON_WIDTH + TEXT_BORDER_WIDTH+m_cBoxFrame.iX, + m_cBoxFrameTitleRel.iHeight+3+m_cBoxFrame.iY, + m_cBoxFrameTitleRel.iWidth - TITLE_ICON_WIDTH + TEXT_BORDER_WIDTH, + m_cTitle.c_str(), + (CFBWindow::color_t)COL_MENUHEAD, + 0, + true); // UTF-8 + } + else + { + // no icon available, just draw the title text + /*m_pcWindow->RenderString(*/ + m_pcFontTitle->RenderString( + m_cBoxFrameTitleRel.iX + TEXT_BORDER_WIDTH+m_cBoxFrame.iX, + m_cBoxFrameTitleRel.iHeight+3+m_cBoxFrame.iY, + m_cBoxFrameTitleRel.iWidth - TEXT_BORDER_WIDTH, + m_cTitle.c_str(), + (CFBWindow::color_t)COL_MENUHEAD, + 0, + true); // UTF-8 + } +} + +////////////////////////////////////////////////////////////////////// +// Function Name: RefreshBorder +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +void CMsgBox::refreshBorder(void) +{ + if( !(m_nMode & BORDER && m_nWindowFrameBorderWidth > 0)) return; + + //draw bottom shadow + m_pcWindow->paintBoxRel( m_nWindowFrameBorderWidth+m_cBoxFrame.iX, + m_cBoxFrame.iHeight - m_nWindowFrameBorderWidth+m_cBoxFrame.iY, + m_cBoxFrame.iWidth - m_nWindowFrameBorderWidth, + m_nWindowFrameBorderWidth, + COL_INFOBAR_SHADOW_PLUS_0); + + //draw right shadow + m_pcWindow->paintBoxRel( m_cBoxFrame.iWidth - m_nWindowFrameBorderWidth+m_cBoxFrame.iX, + m_nWindowFrameBorderWidth+m_cBoxFrame.iY, + m_nWindowFrameBorderWidth, + m_cBoxFrame.iHeight - m_nWindowFrameBorderWidth, + COL_INFOBAR_SHADOW_PLUS_0); +} + +////////////////////////////////////////////////////////////////////// +// global Functions +////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////// +// Function Name: Hide +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +bool CMsgBox::hide(void) +{ + //TRACE("->CMsgBox::Hide\r\n"); + + if (m_pcWindow == NULL) + { + TRACE(" return -> window does not exists\r\n"); + return (false); + } + if(m_pcTextBox != NULL) + { + m_pcTextBox->hide(); + } + + // delete window + // delete m_pcWindow; + m_pcWindow->paintBackgroundBoxRel(m_cBoxFrame.iX, m_cBoxFrame.iY, m_cBoxFrame.iWidth, m_cBoxFrame.iHeight); + m_pcWindow = NULL; + return (true); +} + +////////////////////////////////////////////////////////////////////// +// Function Name: ScrollPageDown +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +void CMsgBox::scrollPageDown(const int pages) +{ + // send scroll up event to text box if there is one + if(m_pcTextBox != NULL) + { + m_pcTextBox->scrollPageDown(pages); + } + +}; + +////////////////////////////////////////////////////////////////////// +// Function Name: ScrollPageUp +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +void CMsgBox::scrollPageUp(const int pages) +{ + // send scroll up event to text box if there is one + if(m_pcTextBox != NULL) + { + m_pcTextBox->scrollPageUp(pages); + } +}; + +////////////////////////////////////////////////////////////////////// +// Function Name: Paint +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +bool CMsgBox::paint(void) +{ + /* + * do not paint stuff twice: + * => thread safety needed by movieplayer.cpp: + * one thread calls our paint method, the other one our hide method + * => no memory leaks + */ + //TRACE("->CMsgBox::Paint\r\n"); + + if (m_pcWindow != NULL) + { + TRACE(" return -> window already exists\r\n"); + return (false); + } + + // create new window + //m_pcWindow = new CFBWindow( m_cBoxFrame.iX, m_cBoxFrame.iY, m_cBoxFrame.iWidth, m_cBoxFrame.iHeight); + m_pcWindow = CFrameBuffer::getInstance(); + if(m_pcTextBox != NULL) + { + m_pcTextBox->paint(); + } + refresh(); + return (true); +} + +////////////////////////////////////////////////////////////////////// +// Function Name: Refresh +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +void CMsgBox::refresh(void) +{ + //TRACE("->CMsgBox::Refresh\r\n"); + + if (m_pcWindow == NULL) + { + TRACE(" return -> no window\r\n"); + return; + } + + //re-draw message box window + refreshTitle(); + refreshFoot(); + refreshBorder(); + + // rep-draw textbox if there is one + if(m_pcTextBox != NULL) + { + //m_pcTextBox->refresh(); + } +} + +////////////////////////////////////////////////////////////////////// +// Function Name: Exec +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +int CMsgBox::exec( int timeout, int returnDefaultOnTimeout) +{ + //TRACE("->CMsgBox::exec\r\n"); +#ifdef VC + int res = 1; + +#else + neutrino_msg_t msg; + neutrino_msg_data_t data; + int return_button = m_nFootButtons; + int res = menu_return::RETURN_REPAINT; + + // show message box + paint(); + if (m_pcWindow == NULL) + { + return res; /* out of memory */ + } + + if ( timeout == -1 ) + timeout = g_settings.timing[SNeutrinoSettings::TIMING_EPG]; + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd( timeout ); + + bool loop=true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd ); + + if (msg == CRCInput::RC_timeout && returnDefaultOnTimeout) + { + // return default + loop = false; + } + else if ( ((msg == CRCInput::RC_timeout) || + (msg == (neutrino_msg_t)g_settings.key_channelList_cancel)) && + (return_button & (mbCancel | mbBack))) + { + m_nResult = (return_button & mbCancel) ? mbrCancel : mbrBack; + loop = false; + } + else if ((msg == CRCInput::RC_green) && (return_button & mbNo)) + { + m_nResult = mbrNo; + loop = false; + } + else if ((msg == CRCInput::RC_red) && (return_button & mbYes)) + { + m_nResult = mbrYes; + loop = false; + } + else if(msg==CRCInput::RC_right) + { + bool ok = false; + while (!ok) + { + m_nResult = (CMsgBox::result_)((m_nResult + 1) & 3); + ok = m_nFootButtons & (1 << m_nResult); + } + + refreshFoot(); + } + else if (msg == CRCInput::RC_up ) + { + scrollPageUp(1); + } + else if (msg == CRCInput::RC_down) + { + scrollPageDown(1); + } + else if(msg==CRCInput::RC_left) + { + bool ok = false; + while (!ok) + { + m_nResult = (CMsgBox::result_)((m_nResult - 1) & 3); + ok = return_button & (1 << m_nResult); + } + + refreshFoot(); + } + else if(msg == CRCInput::RC_ok) + { + loop = false; + } + else if ((msg ==CRCInput::RC_sat) || (msg == CRCInput::RC_favorites)) + { + } + else if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all) + { + res = menu_return::RETURN_EXIT_ALL; + loop = false; + } + + } + + hide(); +#endif //VC + + return res; +} + +////////////////////////////////////////////////////////////////////// +// Function Name: SetText +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +bool CMsgBox::setText(const std::string* newText) +{ + bool result = false; + // update text in textbox if there is one + if(m_pcTextBox != NULL && newText != NULL) + { + result = m_pcTextBox->setText(newText); + if(m_nMode & AUTO_WIDTH || m_nMode & AUTO_HIGH) + { + /* window might changed in size ...*/ + m_cBoxFrameText = m_pcTextBox->getWindowsPos(); + + m_cBoxFrame.iWidth = m_cBoxFrameText.iWidth + m_nWindowFrameBorderWidth; + m_cBoxFrame.iHeight = m_cBoxFrameText.iHeight + m_cBoxFrameFootRel.iHeight + m_cBoxFrameTitleRel.iHeight + m_nWindowFrameBorderWidth; + + initFramesRel(); + + // since the frames size has changed, we have to recenter the window again */ + if(m_nMode & CENTER) + { + m_cBoxFrame.iX = g_settings.screen_StartX + ((g_settings.screen_EndX - g_settings.screen_StartX - m_cBoxFrame.iWidth) >>1); + m_cBoxFrame.iY = g_settings.screen_StartY + ((g_settings.screen_EndY - g_settings.screen_StartY - m_cBoxFrame.iHeight) >>1); + } + } + } + + return(result); +}; + + +////////////////////////////////////////////////////////////////////// +// Function Name: SetText +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +int CMsgBox::result(void) +{ + return m_nResult; +} + +////////////////////////////////////////////////////////////////////// +// Function Name: ShowMsg2UTF +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +int ShowMsg2UTF( const neutrino_locale_t Caption, + const char * const Text, + const CMsgBox::result_ Default, + const uint32_t ShowButtons, + const char * const Icon, + const int Width, + const int timeout, + bool returnDefaultOnTimeout) +{ + //TRACE("->CMsgBox::ShowTextUTF \r\n"); + + int result = ShowMsg2UTF( g_Locale->getText(Caption), + Text, + Default, + ShowButtons, + Icon, + Width, + timeout, + returnDefaultOnTimeout); + + return (result); + +} + +////////////////////////////////////////////////////////////////////// +// Function Name: ShowMsg2UTF +// Description: +// Parameters: +// Data IN/OUT: +// Return: +// Notes: +////////////////////////////////////////////////////////////////////// +int ShowMsg2UTF( const char * const Title, + const char * const Text, + const CMsgBox::result_ Default, + const uint32_t ShowButtons, + const char * const Icon, + const int Width, + const int timeout, + bool returnDefaultOnTimeout) +{ + int mode = CMsgBox::SCROLL | + CMsgBox::TITLE | + CMsgBox::FOOT | + CMsgBox::BORDER;// | + //CMsgBox::NO_AUTO_LINEBREAK | + //CMsgBox::CENTER | + //CMsgBox::AUTO_WIDTH | + //CMsgBox::AUTO_HIGH; + CBox position ( g_settings.screen_StartX+30, + g_settings.screen_StartY+30, + g_settings.screen_EndX - g_settings.screen_StartX-60, + g_settings.screen_EndY - g_settings.screen_StartY-60); + + //TRACE("\r\n->ShowTextUTF %s\r\n",Text); + CMsgBox* msgBox = new CMsgBox( Text, + g_Font[SNeutrinoSettings::FONT_TYPE_MENU], + mode, + &position, + Title, + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE], + Icon, + ShowButtons, + Default); + + msgBox->exec( timeout, returnDefaultOnTimeout); + + int res = msgBox->result(); + + delete msgBox; + + return res; +} diff --git a/src/gui/widget/msgbox.h b/src/gui/widget/msgbox.h new file mode 100644 index 000000000..85905a4f0 --- /dev/null +++ b/src/gui/widget/msgbox.h @@ -0,0 +1,171 @@ +/* + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + *********************************************************** + + Module Name: msgbox.h . + + Description: interface of the CMsgBox class + + Date: Nov 2005 + + Author: Günther@tuxbox.berlios.org + based on code of Steffen Hehn 'McClean' + + Revision History: + Date Author Change Description + Nov 2005 Günther initial implementation + +*/ + +#if !defined(MSGBOX_H) +#define MSGBOX_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include "textbox.h" + +#include +#include + +class CMsgBox +{ + public: + /* enum definition */ + enum result_ + { + mbrYes = 0, + mbrNo = 1, + mbrCancel = 2, + mbrBack = 3 + }; + enum buttons_ + { + mbYes = 0x01, + mbNo = 0x02, + mbCancel = 0x04, + mbAll = 0x07, + mbBack = 0x08 + }; + enum mode_ + { + AUTO_WIDTH = 0x01, + AUTO_HIGH = 0x02, + SCROLL = 0x04, + TITLE = 0x08, + FOOT = 0x10, + BORDER = 0x20, + CENTER = 0x40, + NO_AUTO_LINEBREAK= 0x80 + }mode; + + private: + /* Functions */ + void initVar(void); + void initFramesRel(void); + void refreshFoot(void); + void refreshTitle(void); + void refreshText(void); + void refreshBorder(void); + + /* Variables */ + std::string m_cIcon; + std::string m_cTitle; + + CBox m_cBoxFrame; + CBox m_cBoxFrameText; + CBox m_cBoxFrameTitleRel; + CBox m_cBoxFrameFootRel; + + int m_nMode; + + int m_nWindowFrameBorderWidth; + + Font* m_pcFontTitle; + int m_nFontTitleHeight; + + Font* m_pcFontFoot; + int m_nFontFootHeight; + int m_nFootButtons; + + CTextBox* m_pcTextBox; + //CFBWindow* m_pcWindow; + CFrameBuffer * m_pcWindow; + + result_ m_nResult; + public: + /* Constructor */ + virtual ~CMsgBox(); + CMsgBox(); + CMsgBox(const char * text); + CMsgBox( const char * text, + Font* fontText, + const int mode, + const CBox* position, + const char * title, + Font* fontTitle, + const char * icon, + int return_button = mbCancel, + const result_ default_result = mbrCancel); + + /* Functions */ + bool paint(void); + bool hide(void); + int exec(int timeout,int returnDefaultOnTimeout = false); + void refresh(void); + void scrollPageDown(const int pages); + void scrollPageUp(const int pages); + int result(void); + + bool setText(const std::string* newText); +}; + +extern int ShowMsg2UTF( const neutrino_locale_t Caption, + const char * const Text, + const CMsgBox::result_ Default, + const uint32_t ShowButtons, + const char * const Icon = NULL, + const int Width = 450, + const int timeout = -1, + bool returnDefaultOnTimeout = false); // UTF-8 + +extern int ShowMsg2UTF( const char * const Title, + const char * const Text, + const CMsgBox::result_ Default, + const uint32_t ShowButtons, + const char * const Icon = NULL, + const int Width = 450, + const int timeout = -1, + bool returnDefaultOnTimeout = false); // UTF-8 + + +#endif diff --git a/src/gui/widget/progressstatus.h b/src/gui/widget/progressstatus.h new file mode 100644 index 000000000..1e2358ffb --- /dev/null +++ b/src/gui/widget/progressstatus.h @@ -0,0 +1,39 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA +*/ + + +#ifndef __progressstatus__ +#define __progressstatus__ + +#include + +class CProgress_StatusViewer +{ + public: + virtual void showGlobalStatus(const unsigned int prog) = 0; + virtual unsigned int getGlobalStatus(void) = 0; + virtual void showLocalStatus(const unsigned int prog) = 0; + virtual void showStatusMessageUTF(const std::string & text) = 0; +}; + +#endif diff --git a/src/gui/widget/progresswindow.cpp b/src/gui/widget/progresswindow.cpp new file mode 100644 index 000000000..24679f154 --- /dev/null +++ b/src/gui/widget/progresswindow.cpp @@ -0,0 +1,178 @@ +/* + $Id: progresswindow.cpp,v 1.16 2007/02/25 21:32:58 guenther Exp $ + + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "progresswindow.h" + +#include +#include + +#include +#include +#include + +#include + +#define ROUND_RADIUS 9 +CProgressWindow::CProgressWindow() +{ + frameBuffer = CFrameBuffer::getInstance(); + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + width = w_max (420, 0); + height = h_max(hheight+5*mheight, 20); + + global_progress = local_progress = 101; + statusText = ""; + + x = frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth() - width ) >> 1 ); + y = frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight() - height) >>1 ); + + caption = NONEXISTANT_LOCALE; +} + +void CProgressWindow::setTitle(const neutrino_locale_t title) +{ + caption = title; + +#ifdef VFD_UPDATE + CVFD::getInstance()->showProgressBar2(-1,NULL,-1,g_Locale->getText(caption)); // set global text in VFD +#endif // VFD_UPDATE +} + + +void CProgressWindow::showGlobalStatus(const unsigned int prog) +{ + if (global_progress == prog) + return; + + global_progress = prog; + + int pos = x + 10; + + if(global_progress != 0) + { + if (global_progress > 100) + global_progress = 100; + + pos += int( float(width-20)/100.0 * global_progress); + //vordergrund + frameBuffer->paintBox(x+10, globalstatusY,pos, globalstatusY+10, COL_MENUCONTENT_PLUS_7); + } + //hintergrund + frameBuffer->paintBox(pos, globalstatusY, x+width-10, globalstatusY+10, COL_MENUCONTENT_PLUS_2); + +#ifdef VFD_UPDATE + CVFD::getInstance()->showProgressBar2(-1,NULL,global_progress); +#endif // VFD_UPDATE +} + +void CProgressWindow::showLocalStatus(const unsigned int prog) +{ + if (local_progress == prog) + return; + + local_progress = prog; + + int pos = x + 10; + + if (local_progress != 0) + { + if (local_progress > 100) + local_progress = 100; + + pos += int( float(width-20)/100.0 * local_progress); + //vordergrund + frameBuffer->paintBox(x+10, localstatusY,pos, localstatusY+10, COL_MENUCONTENT_PLUS_7); + } + //hintergrund + frameBuffer->paintBox(pos, localstatusY, x+width-10, localstatusY+10, COL_MENUCONTENT_PLUS_2); + +#ifdef VFD_UPDATE + CVFD::getInstance()->showProgressBar2(local_progress); +#endif // VFD_UPDATE +} + +void CProgressWindow::showStatusMessageUTF(const std::string & text) +{ + statusText = text; + frameBuffer->paintBox(x, statusTextY-mheight, x+width, statusTextY, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10, statusTextY, width-20, text, COL_MENUCONTENT, 0, true); // UTF-8 + +#ifdef VFD_UPDATE + CVFD::getInstance()->showProgressBar2(-1,text.c_str()); // set local text in VFD +#endif // VFD_UPDATE +} + + +unsigned int CProgressWindow::getGlobalStatus(void) +{ + return global_progress; +} + + +void CProgressWindow::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height); +} + +void CProgressWindow::paint() +{ + int ypos=y; + frameBuffer->paintBoxRel(x, ypos, width, hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + if (caption != NONEXISTANT_LOCALE) + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10, ypos+ hheight, width- 10, g_Locale->getText(caption), COL_MENUHEAD, 0, true); // UTF-8 + frameBuffer->paintBoxRel(x, ypos+ hheight, width, height- hheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2); + + ypos+= hheight + (mheight >>1); + statusTextY = ypos+mheight; + showStatusMessageUTF(statusText); + + ypos+= mheight; + localstatusY = ypos+ mheight-20; + showLocalStatus(0); + ypos+= mheight+10; + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+ 10, ypos+ mheight, width- 10, g_Locale->getText(LOCALE_FLASHUPDATE_GLOBALPROGRESS), COL_MENUCONTENT, 0, true); // UTF-8 + ypos+= mheight; + + globalstatusY = ypos+ mheight-20; + ypos+= mheight >>1; + showGlobalStatus(global_progress); +} + +int CProgressWindow::exec(CMenuTarget* parent, const std::string & actionKey) +{ + if(parent) + { + parent->hide(); + } + paint(); + + return menu_return::RETURN_REPAINT; +} diff --git a/src/gui/widget/progresswindow.h b/src/gui/widget/progresswindow.h new file mode 100644 index 000000000..667920087 --- /dev/null +++ b/src/gui/widget/progresswindow.h @@ -0,0 +1,77 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __progresswindow__ +#define __progresswindow__ + +#include +#include + +#include "progressstatus.h" +#include "menue.h" + +#include + +class CProgressWindow : public CMenuTarget, public CProgress_StatusViewer +{ + protected: + + CFrameBuffer *frameBuffer; + neutrino_locale_t caption; + + int x; + int y; + int width; + int height; + int hheight; // head font height + int mheight; // menu font height + unsigned int global_progress; + unsigned int local_progress; + int globalstatusX; + int globalstatusY; + int localstatusY; + int statusTextY; + std::string statusText; + + + //---------------------------- + + virtual void paint(); + + public: + + CProgressWindow(); + void setTitle(const neutrino_locale_t title); + virtual void hide(); + + virtual int exec( CMenuTarget* parent, const std::string & actionKey ); + + virtual void showGlobalStatus(const unsigned int prog); + virtual unsigned int getGlobalStatus(void); + virtual void showLocalStatus(const unsigned int prog); + virtual void showStatusMessageUTF(const std::string & text); // UTF-8 +}; + + +#endif diff --git a/src/gui/widget/rgbcsynccontroler.cpp b/src/gui/widget/rgbcsynccontroler.cpp new file mode 100644 index 000000000..f74a48d49 --- /dev/null +++ b/src/gui/widget/rgbcsynccontroler.cpp @@ -0,0 +1,189 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +extern cVideo * videoDecoder; + + +#define CSYNCFACTOR 0.31 + + +CRGBCSyncControler::CRGBCSyncControler(const neutrino_locale_t Name, unsigned char* Csync, CChangeObserver* Observer) +{ + frameBuffer = CFrameBuffer::getInstance(); + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + observer = Observer; + name = Name; + width = w_max(390, 0); + height = h_max(hheight+ mheight* 1+ +mheight/2, 0); + x = frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth()-width) >> 1); + y = frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight()-height)>>1); + csync=Csync; +} + +void CRGBCSyncControler::setCSync() +{ +// printf("contrast: %d brightness: %d brightness standby: %d\n", contrast, brightness, brightnessstandby); + g_Controld->setRGBCsync(*csync); +} + +int CRGBCSyncControler::exec(CMenuTarget* parent, const std::string &) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = menu_return::RETURN_REPAINT; + unsigned char csync_alt; + + if (parent) + { + parent->hide(); + } + csync_alt = *csync; + + setCSync(); + paint(); + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU]); + + bool loop=true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd, true ); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU]); + + switch ( msg ) + { + case CRCInput::RC_right: + if (*csync < 31) + { + (*csync)++; + paintSlider(x+10, y+hheight, *csync, CSYNCFACTOR, LOCALE_VIDEOMENU_CSYNC, true); + setCSync(); + } + break; + + case CRCInput::RC_left: + if (*csync > 0) + { + (*csync)--; + paintSlider(x+10, y+hheight, *csync, CSYNCFACTOR, LOCALE_VIDEOMENU_CSYNC, true); + setCSync(); + } + break; + + case CRCInput::RC_home: + if ( ( (*csync != csync_alt) ) && + (ShowLocalizedMessage(name, LOCALE_MESSAGEBOX_DISCARD, CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbCancel) == CMessageBox::mbrCancel)) + break; + + // sonst abbruch... + *csync = csync_alt; + setCSync(); + loop = false; + break; + + case CRCInput::RC_ok: + loop = false; + break; + + case CRCInput::RC_timeout: + loop = false; + break; + + default: + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + + hide(); + + if(observer) + observer->changeNotify(name, NULL); + + return res; +} + +void CRGBCSyncControler::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height); +} + +void CRGBCSyncControler::paint() +{ + frameBuffer->paintBoxRel(x,y, width,hheight, COL_MENUHEAD_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10,y+hheight, width, g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + frameBuffer->paintBoxRel(x,y+hheight, width,height-hheight, COL_MENUCONTENT_PLUS_0); + + paintSlider(x+10, y+hheight, *csync, CSYNCFACTOR, LOCALE_VIDEOMENU_CSYNC, true); + +// frameBuffer->paintHLineRel(x+10, width-20, y+hheight+mheight*3+mheight/4, COL_MENUCONTENT_PLUS_3); +} + +void CRGBCSyncControler::paintSlider(int x, int y, unsigned int spos, float factor, const neutrino_locale_t text, bool selected) +{ + int startx = 200; + char wert[5]; + + frameBuffer->paintBoxRel(x + startx, y, 120, mheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintIcon("volumebody.raw", x + startx, y+2+mheight/4); + frameBuffer->paintIcon(selected ? "volumeslider2blue.raw" : "volumeslider2.raw", (int)(x + (startx+3)+(spos / factor)), y+mheight/4); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x, y+mheight, width, g_Locale->getText(text), COL_MENUCONTENT, 0, true); // UTF-8 + sprintf(wert, "%3d", spos); // UTF-8 encoded + frameBuffer->paintBoxRel(x + startx + 120 + 10, y, 50, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x + startx + 120 + 10, y+mheight, width, wert, COL_MENUCONTENT, 0, true); // UTF-8 +} diff --git a/src/gui/widget/rgbcsynccontroler.h b/src/gui/widget/rgbcsynccontroler.h new file mode 100644 index 000000000..ea3010482 --- /dev/null +++ b/src/gui/widget/rgbcsynccontroler.h @@ -0,0 +1,73 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __rgbcsynccontroler__ +#define __rgbcsynccontroler__ + +#include +#include + +#include "menue.h" + +#include + +class CRGBCSyncControler : public CMenuTarget +{ + private: + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hheight,mheight; // head/menu font height + + unsigned char* csync; + + neutrino_locale_t name; + + CChangeObserver* observer; + + void paint(); + void setCSync(); + void paintSlider(int x, int y, unsigned int spos, float factor, const neutrino_locale_t text, bool selected); + + public: + + CRGBCSyncControler(const neutrino_locale_t Name, unsigned char* Csync, CChangeObserver* Observer=NULL); // UTF-8 + + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); + +}; + + +#endif diff --git a/src/gui/widget/stringinput.cpp b/src/gui/widget/stringinput.cpp new file mode 100644 index 000000000..947bd6da3 --- /dev/null +++ b/src/gui/widget/stringinput.cpp @@ -0,0 +1,841 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#define ROUND_RADIUS 9 + +CStringInput::CStringInput(const neutrino_locale_t Name, char* Value, int Size, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, const char * const Valid_Chars, CChangeObserver* Observ, const char * const Icon) +{ + frameBuffer = CFrameBuffer::getInstance(); + name = Name; + head = NULL; + value = Value; + valueString = NULL; + size = Size; + + hint_1 = Hint_1; + hint_2 = Hint_2; + validchars = Valid_Chars; + iconfile = Icon ? Icon : ""; + + observ = Observ; + init(); +} + +CStringInput::CStringInput(const neutrino_locale_t Name, std::string* Value, int Size, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, const char * const Valid_Chars, CChangeObserver* Observ, const char * const Icon) +{ + frameBuffer = CFrameBuffer::getInstance(); + name = Name; + head = NULL; + value = new char[Size+1]; + value[Size] = '\0'; + strncpy(value,Value->c_str(),Size); + valueString = Value; + size = Size; + + hint_1 = Hint_1; + hint_2 = Hint_2; + validchars = Valid_Chars; + iconfile = Icon ? Icon : ""; + + observ = Observ; + init(); +} + +CStringInput::CStringInput(char * Head, char* Value, int Size, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, const char * const Valid_Chars, CChangeObserver* Observ, const char * const Icon) +{ + frameBuffer = CFrameBuffer::getInstance(); + head = strdup(Head); + value = Value; + valueString = NULL; + size = Size; + + hint_1 = Hint_1; + hint_2 = Hint_2; + validchars = Valid_Chars; + iconfile = Icon ? Icon : ""; + + observ = Observ; + init(); +} + +CStringInput::~CStringInput() +{ + if (valueString != NULL) + { + delete[] value; + } + if(head) { + free(head); + } +} + +void CStringInput::init() +{ + width = (size*20)+40; + + if (width<420) + width = 420; + + int neededWidth; + if(head) { + neededWidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getRenderWidth(head, true); // UTF-8 + } + else + neededWidth = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getRenderWidth(g_Locale->getText(name), true); // UTF-8 + + if (!(iconfile.empty())) + neededWidth += 28; + if (neededWidth+20> width) + width = neededWidth+20; + + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + iheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_INFO]->getHeight(); + + height = hheight+ mheight+ 50; + if (hint_1 != NONEXISTANT_LOCALE) + { + height += iheight; + if (hint_2 != NONEXISTANT_LOCALE) + height += iheight; + } + + x = frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth() - width)>>1); + y = frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight()-height)>>1); + selected = 0; +} + +void CStringInput::NormalKeyPressed(const neutrino_msg_t key) +{ + if (CRCInput::isNumeric(key)) + { + value[selected] = validchars[CRCInput::getNumericValue(key)]; + + if (selected < (size - 1)) + { + selected++; + paintChar(selected - 1); + } + + paintChar(selected); + } +} + +void CStringInput::keyBackspacePressed(void) +{ + if (selected > 0) + { + selected--; + for (int i = selected; i < size - 1; i++) + { + value[i] = value[i + 1]; + paintChar(i); + } + value[size - 1] = ' '; + paintChar(size - 1); + } +} + + +void CStringInput::keyRedPressed() +{ + if (index(validchars, ' ') != NULL) + { + value[selected] = ' '; + + if (selected < (size - 1)) + { + selected++; + paintChar(selected - 1); + } + + paintChar(selected); + } +} + +void CStringInput::keyYellowPressed() +{ + selected=0; + for(int i=0 ; i < size ; i++) + { + value[i]=' '; + paintChar(i); + } +} + +void CStringInput::keyBluePressed() +{ + if (((value[selected] | 32) >= 'a') && ((value[selected] | 32) <= 'z')) + { + char newValue = value[selected] ^ 32; + if (index(validchars, newValue) != NULL) + { + value[selected] = newValue; + paintChar(selected); + } + } +} + +void CStringInput::keyUpPressed() +{ + int npos = 0; + for(int count=0;count<(int)strlen(validchars);count++) + if(value[selected]==validchars[count]) + npos = count; + npos++; + if(npos>=(int)strlen(validchars)) + npos = 0; + value[selected]=validchars[npos]; + paintChar(selected); +} + +void CStringInput::keyDownPressed() +{ + int npos = 0; + for(int count=0;count<(int)strlen(validchars);count++) + if(value[selected]==validchars[count]) + npos = count; + npos--; + if(npos<0) + npos = strlen(validchars)-1; + value[selected]=validchars[npos]; + paintChar(selected); +} + +void CStringInput::keyLeftPressed() +{ + int old = selected; + if(selected>0) { + selected--; + } else { + selected = size - 1; + } + paintChar(old); + paintChar(selected); +} + +void CStringInput::keyRightPressed() +{ + int old = selected; + if (selected < (size - 1)) { + selected++; + } else + selected = 0; + paintChar(old); + paintChar(selected); +} + +void CStringInput::keyMinusPressed() +{ + int item = selected; + while (item < (size -1)) + { + value[item] = value[item+1]; + paintChar(item); + item++; + } + value[item] = ' '; + paintChar(item); +} + +void CStringInput::keyPlusPressed() +{ + int item = size -1; + while (item > selected) + { + value[item] = value[item-1]; + paintChar(item); + item--; + } + value[item] = ' '; + paintChar(item); +} + +int CStringInput::exec( CMenuTarget* parent, const std::string & ) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + int res = menu_return::RETURN_REPAINT; + + char oldval[size+1], dispval[size+1]; + oldval[size] = 0; + dispval[size] = 0; + + if (parent) + parent->hide(); + + for(int count=strlen(value)-1;countshowMenuText(1, value, selected+1); + strncpy(dispval, value, size); + } + + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd, true ); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + if (msg==CRCInput::RC_left) + { + keyLeftPressed(); + } + else if (msg==CRCInput::RC_right) + { + keyRightPressed(); + } + else if (CRCInput::getUnicodeValue(msg) != -1) + { + NormalKeyPressed(msg); + } + else if (msg==CRCInput::RC_backspace) + { + keyBackspacePressed(); + } + else if (msg==CRCInput::RC_red) + { + keyRedPressed(); + } + else if (msg==CRCInput::RC_yellow) + { + keyYellowPressed(); + } + else if ( (msg==CRCInput::RC_green) && (index(validchars, '.') != NULL)) + { + value[selected] = '.'; + + if (selected < (size - 1)) + { + selected++; + paintChar(selected - 1); + } + + paintChar(selected); + } + else if (msg== CRCInput::RC_blue) + { + keyBluePressed(); + } + else if (msg==CRCInput::RC_up) + { + keyUpPressed(); + } + else if (msg==CRCInput::RC_down) + { + keyDownPressed(); + } else if (msg==CRCInput::RC_plus) + { + keyPlusPressed(); + } else if (msg==CRCInput::RC_minus) + { + keyMinusPressed(); + } + else if (msg==CRCInput::RC_ok) + { + loop=false; + } + else if ( (msg==CRCInput::RC_home) || (msg==CRCInput::RC_timeout) ) + { + if ( ( strcmp(value, oldval) != 0) && + (ShowLocalizedMessage(name, LOCALE_MESSAGEBOX_DISCARD, CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbCancel) == CMessageBox::mbrCancel)) + continue; + + strncpy(value, oldval, size); + loop=false; + } + else if ((msg ==CRCInput::RC_sat) || (msg == CRCInput::RC_favorites)) + { + } + else + { + int r = handleOthers( msg, data ); + if (r & (messages_return::cancel_all | messages_return::cancel_info)) + { + res = (r & messages_return::cancel_all) ? menu_return::RETURN_EXIT_ALL : menu_return::RETURN_EXIT; + loop = false; + } + else if ( r & messages_return::unhandled ) + { + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + } + + hide(); + + for(int count=size-1;count>=0;count--) + { + if((value[count]==' ') || (value[count]==0)) + { + value[count]=0; + } + else + break; + } + value[size]=0; + + if (valueString != NULL) + { + *valueString = value; + } + + if ( (observ) && (msg==CRCInput::RC_ok) ) + { + observ->changeNotify(name, value); + } + + return res; +} + +int CStringInput::handleOthers(const neutrino_msg_t msg, const neutrino_msg_data_t data) +{ + return messages_return::unhandled; +} + +void CStringInput::hide() +{ + frameBuffer->paintBackgroundBoxRel(x, y, width, height); +} + +const char * CStringInput::getHint1(void) +{ + return g_Locale->getText(hint_1); +} + +void CStringInput::paint() +{ + int iconoffset; + + //frameBuffer->paintBoxRel(x, y, width, hheight, COL_MENUHEAD_PLUS_0); + //frameBuffer->paintBoxRel(x, y + hheight, width, height - hheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintBoxRel(x, y, width, hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); //round + frameBuffer->paintBoxRel(x, y + hheight, width, height - hheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2);//round + + if (!(iconfile.empty())) + { + frameBuffer->paintIcon(iconfile, x + 8, y + 5); + iconoffset = 28; + } + else + iconoffset = 0; + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+ 10+ iconoffset, y+ hheight, width- 10- iconoffset, head ? head : g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + + if (hint_1 != NONEXISTANT_LOCALE) + { + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_INFO]->RenderString(x+ 20, y+ hheight+ mheight+ iheight+ 40, width- 20, getHint1(), COL_MENUCONTENT, 0, true); // UTF-8 + if (hint_2 != NONEXISTANT_LOCALE) + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_INFO]->RenderString(x+ 20, y+ hheight+ mheight+ iheight* 2+ 40, width- 20, g_Locale->getText(hint_2), COL_MENUCONTENT, 0, true); // UTF-8 + } + + for (int count=0;countpaintBoxRel(xpos, ypos, xs, ys, COL_MENUCONTENT_PLUS_4); + frameBuffer->paintBoxRel(xpos+ 1, ypos+ 1, xs- 2, ys- 2, bgcolor); + + int xfpos = xpos + ((xs- g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(ch))>>1); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(xfpos,ypos+ys, width, ch, color); +} + +void CStringInput::paintChar(int pos) +{ + if(pos<(int)strlen(value)) + paintChar(pos, value[pos]); +} + +CStringInputSMS::CStringInputSMS(const neutrino_locale_t Name, std::string* Value, int Size, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, const char * const Valid_Chars, CChangeObserver* Observ, const char * const Icon) + : CStringInput(Name, Value, Size, Hint_1, Hint_2, Valid_Chars, Observ, Icon) +{ + initSMS(Valid_Chars); +} + +CStringInputSMS::CStringInputSMS(const neutrino_locale_t Name, char* Value, int Size, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, const char * const Valid_Chars, CChangeObserver* Observ, const char * const Icon) + : CStringInput(Name, Value, Size, Hint_1, Hint_2, Valid_Chars, Observ, Icon) + { + initSMS(Valid_Chars); +} + +void CStringInputSMS::initSMS(const char * const Valid_Chars) +{ + last_digit = -1; // no key pressed yet + const char CharList[10][11] = { "0 -_/()<>=", // 9 characters + "1+.,:!?\\", + "abc2ä", + "def3", + "ghi4", + "jkl5", + "mno6ö", + "pqrs7ß", + "tuv8ü", + "wxyz9" }; + + for (int i = 0; i < 10; i++) + { + int j = 0; + for (int k = 0; k < (int) strlen(CharList[i]); k++) + if (strchr(Valid_Chars, CharList[i][k]) != NULL) + Chars[i][j++] = CharList[i][k]; + if (j == 0) + Chars[i][j++] = ' '; // prevent empty char lists + arraySizes[i] = j; + } + + height+=260; + y = ((500-height)>>1); +} + + +void CStringInputSMS::NormalKeyPressed(const neutrino_msg_t key) +{ + if (CRCInput::isNumeric(key)) + { + int numericvalue = CRCInput::getNumericValue(key); + if (last_digit != numericvalue) + { + if ((last_digit != -1) && // there is a last key + (selected < (size- 1))) // we can shift the cursor one field to the right + { + selected++; + paintChar(selected - 1); + } + keyCounter = 0; + } + else + keyCounter = (keyCounter + 1) % arraySizes[numericvalue]; + value[selected] = Chars[numericvalue][keyCounter]; + last_digit = numericvalue; + paintChar(selected); + } + else + { + value[selected] = (char)CRCInput::getUnicodeValue(key); + keyRedPressed(); /* to lower, paintChar */ + keyRightPressed(); /* last_digit = -1, move to next position */ + } +} + +void CStringInputSMS::keyBackspacePressed(void) +{ + last_digit = -1; + CStringInput::keyBackspacePressed(); +} + +void CStringInputSMS::keyRedPressed() // switch between lower & uppercase +{ + if (((value[selected] | 32) >= 'a') && ((value[selected] | 32) <= 'z')) + value[selected] ^= 32; + + paintChar(selected); +} + +void CStringInputSMS::keyYellowPressed() // clear all +{ + last_digit = -1; + CStringInput::keyYellowPressed(); +} + +void CStringInputSMS::keyUpPressed() +{ + last_digit = -1; + + if (selected > 0) + { + int lastselected = selected; + selected = 0; + paintChar(lastselected); + paintChar(selected); + } +} + +void CStringInputSMS::keyDownPressed() +{ + last_digit = -1; + + int lastselected = selected; + + selected = size - 1; + + while (value[selected] == ' ') + { + selected--; + if (selected < 0) + break; + } + + if (selected < (size - 1)) + selected++; + + paintChar(lastselected); + paintChar(selected); +} + +void CStringInputSMS::keyLeftPressed() +{ + last_digit = -1; + CStringInput::keyLeftPressed(); +} + +void CStringInputSMS::keyRightPressed() +{ + last_digit = -1; + CStringInput::keyRightPressed(); +} + +const struct button_label CStringInputSMSButtons[2] = +{ + { NEUTRINO_ICON_BUTTON_RED , LOCALE_STRINGINPUT_CAPS }, +// { NEUTRINO_ICON_BUTTON_GREEN , LOCALE_XXX }, + { NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_STRINGINPUT_CLEAR } +// { NEUTRINO_ICON_BUTTON_BLUE , LOCALE_XXX } +}; + +void CStringInputSMS::paint() +{ + CStringInput::paint(); + + frameBuffer->paintIcon("numericpad.raw", x+20+140, y+ hheight+ mheight+ iheight* 3+ 30, COL_MENUCONTENT); + + frameBuffer->paintBoxRel(x,y+height-25, width,25, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 2); + frameBuffer->paintHLine(x, x+width, y+height-25, COL_INFOBAR_SHADOW_PLUS_0); + + ::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 8, y+height-25+1, 230, 2, CStringInputSMSButtons); +} + +void CPINInput::paintChar(int pos) +{ + CStringInput::paintChar(pos, (value[pos] == ' ') ? ' ' : '*'); +} + +int CPINInput::exec( CMenuTarget* parent, const std::string & ) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int res = menu_return::RETURN_REPAINT; + + if (parent) + parent->hide(); + + for(int count=strlen(value)-1;countgetMsg( &msg, &data, 300 ); + + if (msg==CRCInput::RC_left) + { + keyLeftPressed(); + } + else if (msg==CRCInput::RC_right) + { + keyRightPressed(); + } + else if (CRCInput::isNumeric(msg)) + { + int old_selected = selected; + NormalKeyPressed(msg); + if ( old_selected == ( size- 1 ) ) + loop=false; + } + else if ( (msg==CRCInput::RC_up) || + (msg==CRCInput::RC_down) ) + { + g_RCInput->postMsg( msg, data ); + res = menu_return::RETURN_EXIT; + loop=false; + } + else if ( (msg==CRCInput::RC_home) || (msg==CRCInput::RC_timeout) || (msg==CRCInput::RC_ok) ) + { + loop=false; + } + else + { + int r = handleOthers(msg, data); + if (r & (messages_return::cancel_all | messages_return::cancel_info)) + { + res = (r & messages_return::cancel_all) ? menu_return::RETURN_EXIT_ALL : menu_return::RETURN_EXIT; + loop = false; + } + else if ( r & messages_return::unhandled ) + { + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & ( messages_return::cancel_all | messages_return::cancel_info ) ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + + } + + hide(); + + for(int count=size-1;count>=0;count--) + { + if((value[count]==' ') || (value[count]==0)) + { + value[count]=0; + } + else + break; + } + value[size]=0; + + if ( (observ) && (msg==CRCInput::RC_ok) ) + { + observ->changeNotify(name, value); + } + + return res; +} + +int CPLPINInput::handleOthers(neutrino_msg_t msg, neutrino_msg_data_t data) +{ + int res = messages_return::unhandled; + + if ( msg == NeutrinoMessages::EVT_PROGRAMLOCKSTATUS ) + { + // trotzdem handlen + CNeutrinoApp::getInstance()->handleMsg(msg, data); + + if (data != (neutrino_msg_data_t) fsk) + res = messages_return::cancel_info; + } + + return res; +} + +const char * CPLPINInput::getHint1(void) +{ + if (fsk == 0x100) + { + hint_1 = LOCALE_PARENTALLOCK_LOCKEDCHANNEL; + return CStringInput::getHint1(); + } + else + { + sprintf(hint, g_Locale->getText(LOCALE_PARENTALLOCK_LOCKEDPROGRAM), fsk); + return hint; + } +} + +#define borderwidth 4 + +int CPLPINInput::exec( CMenuTarget* parent, const std::string & ) +{ + fb_pixel_t * pixbuf = new fb_pixel_t[(width+ 2* borderwidth) * (height+ 2* borderwidth)]; + + if (pixbuf != NULL) + frameBuffer->SaveScreen(x- borderwidth, y- borderwidth, width+ 2* borderwidth, height+ 2* borderwidth, pixbuf); + + // clear border + frameBuffer->paintBackgroundBoxRel(x- borderwidth, y- borderwidth, width+ 2* borderwidth, borderwidth); + frameBuffer->paintBackgroundBoxRel(x- borderwidth, y+ height, width+ 2* borderwidth, borderwidth); + frameBuffer->paintBackgroundBoxRel(x- borderwidth, y, borderwidth, height); + frameBuffer->paintBackgroundBoxRel(x+ width, y, borderwidth, height); + + int res = CPINInput::exec ( parent, "" ); + + if (pixbuf != NULL) + { + frameBuffer->RestoreScreen(x- borderwidth, y- borderwidth, width+ 2* borderwidth, height+ 2* borderwidth, pixbuf); + delete[] pixbuf;//Mismatching allocation and deallocation: pixbuf + } + + return ( res ); +} diff --git a/src/gui/widget/stringinput.h b/src/gui/widget/stringinput.h new file mode 100644 index 000000000..832ad19c0 --- /dev/null +++ b/src/gui/widget/stringinput.h @@ -0,0 +1,163 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __stringinput__ +#define __stringinput__ + +#include "menue.h" + +#include +#include + +#include + +class CStringInput : public CMenuTarget +{ + protected: + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hheight; // head font height + int mheight; // menu font height + int iheight; + + char * head; + neutrino_locale_t name; + neutrino_locale_t hint_1, hint_2; + std::string iconfile; + const char * validchars; + char * value; + std::string *valueString; + int size; + int selected; + CChangeObserver * observ; + + virtual void init(); + virtual const char * getHint1(void); + + virtual void paint(); + virtual void paintChar(int pos, char c); + virtual void paintChar(int pos); + + virtual void NormalKeyPressed(const neutrino_msg_t key); + virtual void keyBackspacePressed(void); + virtual void keyRedPressed(); + virtual void keyYellowPressed(); + virtual void keyBluePressed(); + virtual void keyUpPressed(); + virtual void keyDownPressed(); + virtual void keyLeftPressed(); + virtual void keyRightPressed(); + virtual void keyPlusPressed(); + virtual void keyMinusPressed(); + + virtual int handleOthers(const neutrino_msg_t msg, const neutrino_msg_data_t data); + + public: + + CStringInput(const neutrino_locale_t Name, char* Value, int Size, const neutrino_locale_t Hint_1 = NONEXISTANT_LOCALE, const neutrino_locale_t Hint_2 = NONEXISTANT_LOCALE, const char * const Valid_Chars= (const char *) "0123456789. ", CChangeObserver* Observ = NULL, const char * const Icon = NULL); + CStringInput(char * Head, char* Value, int Size, const neutrino_locale_t Hint_1 = NONEXISTANT_LOCALE, const neutrino_locale_t Hint_2 = NONEXISTANT_LOCALE, const char * const Valid_Chars= (const char *) "0123456789. ", CChangeObserver* Observ = NULL, const char * const Icon = NULL); + CStringInput(const neutrino_locale_t Name, std::string* Value, int Size, const neutrino_locale_t Hint_1 = NONEXISTANT_LOCALE, const neutrino_locale_t Hint_2 = NONEXISTANT_LOCALE, const char * const Valid_Chars= (const char *) "0123456789. ", CChangeObserver* Observ = NULL, const char * const Icon = NULL); + ~CStringInput(); + + void hide(); + int exec( CMenuTarget* parent, const std::string & actionKey ); + +}; + +class CStringInputSMS : public CStringInput +{ + bool capsMode; + int arraySizes[10]; + char Chars[10][9]; // maximal 9 character in one CharList entry! + + int keyCounter; + int last_digit; + + virtual void NormalKeyPressed(const neutrino_msg_t key); + virtual void keyBackspacePressed(void); + virtual void keyRedPressed(); + virtual void keyYellowPressed(); + virtual void keyUpPressed(); + virtual void keyDownPressed(); + virtual void keyLeftPressed(); + virtual void keyRightPressed(); + + virtual void paint(); + void initSMS(const char * const Valid_Chars); + + public: + CStringInputSMS(const neutrino_locale_t Name, char* Value, int Size, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, const char * const Valid_Chars, CChangeObserver* Observ = NULL, const char * const Icon = NULL); + CStringInputSMS(const neutrino_locale_t Name, std::string* Value, int Size, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, const char * const Valid_Chars, CChangeObserver* Observ = NULL, const char * const Icon = NULL); +}; + +class CPINInput : public CStringInput +{ + protected: + virtual void paintChar(int pos); + public: + CPINInput(const neutrino_locale_t Name, char* Value, int Size, const neutrino_locale_t Hint_1 = NONEXISTANT_LOCALE, const neutrino_locale_t Hint_2 = NONEXISTANT_LOCALE, const char * const Valid_Chars= (const char *)"0123456789", CChangeObserver* Observ = NULL) + : CStringInput(Name, (char *)Value, Size, Hint_1, Hint_2, Valid_Chars, Observ, (char *)"lock.raw") {}; + CPINInput(char * Head, char* Value, int Size, const neutrino_locale_t Hint_1 = NONEXISTANT_LOCALE, const neutrino_locale_t Hint_2 = NONEXISTANT_LOCALE, const char * const Valid_Chars= (const char *)"0123456789", CChangeObserver* Observ = NULL) + : CStringInput(Head, (char *)Value, Size, Hint_1, Hint_2, Valid_Chars, Observ, (char *)"lock.raw") {}; + + int exec( CMenuTarget* parent, const std::string & actionKey ); +}; + +class CPLPINInput : public CPINInput +{ + protected: + int fsk; + char hint[100]; + + virtual int handleOthers(const neutrino_msg_t msg, const neutrino_msg_data_t data); + + virtual const char * getHint1(void); + + public: + CPLPINInput(const neutrino_locale_t Name, char* Value, int Size, const neutrino_locale_t Hint_2, int FSK ) + : CPINInput(Name, (char *)Value, Size, NONEXISTANT_LOCALE, Hint_2) { fsk = FSK; }; + + int exec( CMenuTarget* parent, const std::string & actionKey ); +}; + +class CPINChangeWidget : public CStringInput +{ + public: + CPINChangeWidget(const neutrino_locale_t Name, char* Value, int Size, const neutrino_locale_t Hint_1, const char * const Valid_Chars= (const char *) "0123456789", CChangeObserver* Observ = NULL) + : CStringInput(Name, (char *)Value, Size, Hint_1, NONEXISTANT_LOCALE, Valid_Chars, Observ){}; +}; + + +#endif diff --git a/src/gui/widget/stringinput_ext.cpp b/src/gui/widget/stringinput_ext.cpp new file mode 100644 index 000000000..4e294c31d --- /dev/null +++ b/src/gui/widget/stringinput_ext.cpp @@ -0,0 +1,668 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include + +#include +#include + +#define ROUND_RADIUS 9 + +CExtendedInput::CExtendedInput(const neutrino_locale_t Name, char* Value, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ, bool* Cancel) +{ + name = Name; + value = Value; + cancel = Cancel; + + hint_1 = Hint_1; + hint_2 = Hint_2; + + observ = Observ; + Init(); +} + +void CExtendedInput::Init(void) +{ + + frameBuffer = CFrameBuffer::getInstance(); + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + iheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_INFO]->getHeight(); + + width = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getRenderWidth(g_Locale->getText(name), true) + 20; // UTF-8 + height = hheight+ mheight+ 20; + + if (hint_1 != NONEXISTANT_LOCALE) + height += iheight; + if (hint_2 != NONEXISTANT_LOCALE) + height += iheight; + + x = frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth() - width)>>1); + y = frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight() - height)>>1); +} + +CExtendedInput::~CExtendedInput() +{ + for (std::vector::iterator it = inputFields.begin(); it < inputFields.end(); it++) + delete *it; +} + +void CExtendedInput::addInputField( CExtendedInput_Item* fld ) +{ + inputFields.push_back(fld); +} + + +void CExtendedInput::calculateDialog() +{ + int ix = 0; + int iy = 0; + int maxX = 0; + int maxY = 0; + + selectedChar = -1; + for(unsigned int i=0; iinit( ix, iy); + inputFields[i]->setDataPointer( &value[i] ); + if ((selectedChar==-1) && (inputFields[i]->isSelectable())) + { + selectedChar = i; + } + maxX = ix > maxX ? ix : maxX; + maxY = iy > maxY ? iy : maxY; + } + + width = width > maxX+40 ? width : maxX+40; + height = height > maxY + hheight + mheight ? height : maxY + hheight + mheight; + + hintPosY = height -10; + + if (hint_1 != NONEXISTANT_LOCALE) + height += iheight; + if (hint_2 != NONEXISTANT_LOCALE) + height += iheight; + + x = ((frameBuffer->getScreenWidth() - width)>>1); + y = ((frameBuffer->getScreenHeight() - height)>>1); + + hintPosY += y; +} + + +int CExtendedInput::exec( CMenuTarget* parent, const std::string & ) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + onBeforeExec(); + int res = menu_return::RETURN_REPAINT; + char oldval[inputFields.size()+10], dispval[inputFields.size()+10]; + + if (parent) + { + parent->hide(); + } + + strcpy(oldval, value); + paint(); + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + bool loop=true; + while (loop) + { + if ( strcmp(value, dispval) != 0) + { + CVFD::getInstance()->showMenuText(1, value, selectedChar+1); + strcpy(dispval, value); + } + + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd, true ); + + if (msg==CRCInput::RC_left) { + bool found = false; + int oldSelectedChar = selectedChar; + if(selectedChar > 0) { + for(int i=selectedChar-1; i>=0;i--) { + if (inputFields[i]->isSelectable()) { + found = true; + selectedChar = i; + break; + } + } + } else { + for(int i = inputFields.size() - 1; i >= 0; i--) { + if(inputFields[i]->isSelectable()) { + found = true; + selectedChar = i; + break; + } + } + } + if(found) { + inputFields[oldSelectedChar]->paint( x+20, y+hheight +20, false ); + inputFields[selectedChar]->paint( x+20, y+hheight +20, true ); + CVFD::getInstance()->showMenuText(1, value, selectedChar+1); + } + } else if (msg==CRCInput::RC_right) { + bool found = false; + int oldSelectedChar = selectedChar; + if(selectedChar < (int) inputFields.size()-1) { + for(unsigned int i = selectedChar+1; i < inputFields.size();i++) { + if (inputFields[i]->isSelectable()) { + found = true; + selectedChar = i; + break; + } + } + } + if(!found) { + for(int i = 0; i < (int) inputFields.size(); i++) { +//printf("old %d sel %d size %d i %d\n", oldSelectedChar, selectedChar, inputFields.size(), i); + if(inputFields[i]->isSelectable()) { + found = true; + selectedChar = i; + break; + } + } + } + if(found) { + inputFields[oldSelectedChar]->paint( x+20, y+hheight +20, false ); + inputFields[selectedChar]->paint( x+20, y+hheight +20, true ); + CVFD::getInstance()->showMenuText(1, value, selectedChar+1); + } + } + else if ( (CRCInput::getUnicodeValue(msg) != -1) || (msg == CRCInput::RC_red) || (msg == CRCInput::RC_green) || (msg == CRCInput::RC_blue) || (msg == CRCInput::RC_yellow) + || (msg == CRCInput::RC_up) || (msg == CRCInput::RC_down)) + { + inputFields[selectedChar]->keyPressed(msg); + inputFields[selectedChar]->paint( x+20, y+hheight +20, true ); + } + else if (msg==CRCInput::RC_ok) + { + loop=false; + if(cancel != NULL) + *cancel = false; + } + else if ( (msg==CRCInput::RC_home) || (msg==CRCInput::RC_timeout) ) + { + if(strcmp(value, oldval)!= 0){ + int erg = ShowLocalizedMessage(name, LOCALE_MESSAGEBOX_DISCARD, CMessageBox::mbrYes, CMessageBox::mbNo | CMessageBox::mbYes | CMessageBox::mbCancel); + if(erg==CMessageBox::mbrYes){ + strcpy(value, oldval); + loop=false; + if(cancel != NULL) + *cancel = true; + } + else if(erg==CMessageBox::mbrNo){ + loop=false; + if(cancel != NULL) + *cancel = false; + } + else if(erg==CMessageBox::mbrCancel){ + } + } else { + //keine änderungen - beenden ok + loop=false; + if(cancel != NULL) + *cancel = true; + } + } + else if ((msg ==CRCInput::RC_sat) || (msg == CRCInput::RC_favorites)) + { + } + else if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + + hide(); + + onAfterExec(); + + if ((observ) && (msg == CRCInput::RC_ok)) + { + observ->changeNotify(name, value); + } + + return res; +} + +void CExtendedInput::hide() +{ + frameBuffer->paintBackgroundBoxRel(x, y, width, height); +} + +void CExtendedInput::paint() +{ + frameBuffer->paintBoxRel(x, y, width, hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1); + frameBuffer->paintBoxRel(x, y + hheight, width, height - hheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+ 10, y+ hheight, width- 10, g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + + if (hint_1 != NONEXISTANT_LOCALE) + { + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_INFO]->RenderString(x+ 20, hintPosY, width- 20, g_Locale->getText(hint_1), COL_MENUCONTENT, 0, true); // UTF-8 + if (hint_2 != NONEXISTANT_LOCALE) + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_INFO]->RenderString(x+ 20, hintPosY + iheight, width- 20, g_Locale->getText(hint_2), COL_MENUCONTENT, 0, true); // UTF-8 + } + + for(unsigned int i=0; ipaint( x+20, y+hheight +20, (i== (unsigned int) selectedChar) ); + } + + +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +CExtendedInput_Item_Char::CExtendedInput_Item_Char(const std::string & Chars, bool Selectable ) +{ + frameBuffer = CFrameBuffer::getInstance(); + idx = 20; + idy = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + allowedChars = Chars; + selectable = Selectable; +} + +void CExtendedInput_Item_Char::init(int &x, int &y) +{ + ix = x; + iy = y; + x += idx; +} + +void CExtendedInput_Item_Char::setAllowedChars( const std::string & ac ) +{ + allowedChars = ac; +} + +void CExtendedInput_Item_Char::paint(int x, int y, bool focusGained ) +{ + int startx = ix + x; + int starty = iy + y; + + uint8_t color; + fb_pixel_t bgcolor; + + if (focusGained) + { + color = COL_MENUCONTENTSELECTED; + bgcolor = COL_MENUCONTENTSELECTED_PLUS_0; + } + else + { + color = COL_MENUCONTENT; + bgcolor = COL_MENUCONTENT_PLUS_0; + } + + frameBuffer->paintBoxRel( startx, starty, idx, idy, COL_MENUCONTENT_PLUS_4); + frameBuffer->paintBoxRel( startx+1, starty+1, idx-2, idy-2, bgcolor); + + char text[2]; + text[0] = *data; + text[1] = 0; + int xfpos = startx + 1 + ((idx- g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth( text ))>>1); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(xfpos,starty+idy, idx, text, color); +} + +bool CExtendedInput_Item_Char::isAllowedChar( char ch ) +{ + return ( (int) allowedChars.find(ch) != -1); +} + +int CExtendedInput_Item_Char::getCharID( char ch ) +{ + return allowedChars.find(ch); +} + +void CExtendedInput_Item_Char::keyPressed(const int key) +{ + int value = CRCInput::getUnicodeValue(key); + if (value != -1) + { + if (isAllowedChar((char)value)) + { + *data = (char)value; + g_RCInput->postMsg( CRCInput::RC_right, 0 ); + } + } + else + { + unsigned int pos = getCharID( *data ); + if (key==CRCInput::RC_up) + { + if(pos0) + { + *data = allowedChars[pos-1]; + } + else + { + *data = allowedChars[allowedChars.size()-1]; + } + } + } +} + +//-----------------------------#################################------------------------------------------------------- + +CIPInput::CIPInput(const neutrino_locale_t Name, std::string & Value, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ) + : CExtendedInput(Name, IP, Hint_1, Hint_2, Observ) +{ + ip = &Value; + frameBuffer = CFrameBuffer::getInstance(); + addInputField( new CExtendedInput_Item_Char("012") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Spacer(20) ); + addInputField( new CExtendedInput_Item_Char("012") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Spacer(20) ); + addInputField( new CExtendedInput_Item_Char("012") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Spacer(20) ); + addInputField( new CExtendedInput_Item_Char("012") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_newLiner(30) ); + calculateDialog(); +} + +void CIPInput::onBeforeExec() +{ + if (ip->empty()) + { + strcpy(value, "000.000.000.000"); + //printf("[neutrino] value-before(2): %s\n", value); + return; + } + unsigned char _ip[4]; + sscanf(ip->c_str(), "%hhu.%hhu.%hhu.%hhu", &_ip[0], &_ip[1], &_ip[2], &_ip[3]); + sprintf( value, "%03hhu.%03hhu.%03hhu.%03hhu", _ip[0], _ip[1], _ip[2], _ip[3]); +} + +void CIPInput::onAfterExec() +{ + int _ip[4]; + sscanf( value, "%3d.%3d.%3d.%3d", &_ip[0], &_ip[1], &_ip[2], &_ip[3] ); + sprintf( value, "%d.%d.%d.%d", _ip[0], _ip[1], _ip[2], _ip[3]); + if(strcmp(value,"0.0.0.0")==0) + { + (*ip) = ""; + } + else + (*ip) = value; +} + +//-----------------------------#################################------------------------------------------------------- +CDateInput::CDateInput(const neutrino_locale_t Name, time_t* Time, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ) + : CExtendedInput(Name, (char *) "", Hint_1, Hint_2, Observ) +{ + time=Time; + value= new char[20]; + struct tm *tmTime = localtime(time); + sprintf( value, "%02d.%02d.%04d %02d:%02d", tmTime->tm_mday, tmTime->tm_mon+1, + tmTime->tm_year+1900, + tmTime->tm_hour, tmTime->tm_min); + + frameBuffer = CFrameBuffer::getInstance(); + addInputField( new CExtendedInput_Item_Char("0123") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char(".",false) ); + addInputField( new CExtendedInput_Item_Char("01") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char(".",false) ); + addInputField( new CExtendedInput_Item_Char("2",false) ); + addInputField( new CExtendedInput_Item_Char("0",false) ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Spacer(20) ); + addInputField( new CExtendedInput_Item_Char("012") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char(":",false) ); + addInputField( new CExtendedInput_Item_Char("012345") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_newLiner(30) ); + calculateDialog(); +} +CDateInput::~CDateInput() +{ + delete value; +} +void CDateInput::onBeforeExec() +{ + struct tm *tmTime = localtime(time); + sprintf( value, "%02d.%02d.%04d %02d:%02d", tmTime->tm_mday, tmTime->tm_mon+1, + tmTime->tm_year+1900, + tmTime->tm_hour, tmTime->tm_min); + dst = tmTime->tm_isdst; +} + +void CDateInput::onAfterExec() +{ + struct tm tmTime; + sscanf( value, "%02d.%02d.%04d %02d:%02d", &tmTime.tm_mday, &tmTime.tm_mon, + &tmTime.tm_year, + &tmTime.tm_hour, &tmTime.tm_min); + tmTime.tm_mon-=1; + tmTime.tm_year-=1900; + tmTime.tm_sec=0; + tmTime.tm_isdst=dst; + + if(tmTime.tm_year>129) + tmTime.tm_year=129; + if(tmTime.tm_year<0) + tmTime.tm_year=0; + if(tmTime.tm_mon>11) + tmTime.tm_mon=11; + if(tmTime.tm_mon<0) + tmTime.tm_mon=0; + if(tmTime.tm_mday>31) //-> eine etwas laxe pruefung, aber mktime biegt das wieder grade + tmTime.tm_mday=31; + if(tmTime.tm_mday<1) + tmTime.tm_mday=1; + if(tmTime.tm_hour>23) + tmTime.tm_hour=23; + if(tmTime.tm_hour<0) + tmTime.tm_hour=0; + if(tmTime.tm_min>59) + tmTime.tm_min=59; + if(tmTime.tm_min<0) + tmTime.tm_min=0; + if(tmTime.tm_sec>59) + tmTime.tm_sec=59; + if(tmTime.tm_sec<0) + tmTime.tm_sec=0; + *time=mktime(&tmTime); + struct tm *tmTime2 = localtime(time); + sprintf( value, "%02d.%02d.%04d %02d:%02d", tmTime2->tm_mday, tmTime2->tm_mon+1, + tmTime2->tm_year+1900, + tmTime2->tm_hour, tmTime2->tm_min); +} +//-----------------------------#################################------------------------------------------------------- + +CMACInput::CMACInput(const neutrino_locale_t Name, char* Value, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ) + : CExtendedInput(Name, Value, Hint_1, Hint_2, Observ) +{ + frameBuffer = CFrameBuffer::getInstance(); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Spacer(20) ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Spacer(20) ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Spacer(20) ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Spacer(20) ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Spacer(20) ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_Char("0123456789ABCDEF") ); + addInputField( new CExtendedInput_Item_newLiner(30) ); + calculateDialog(); +} + +void CMACInput::onBeforeExec() +{ + if (value[0] == 0) /* strcmp(value, "") == 0 */ + { + strcpy(value, "00:00:00:00:00:00"); + printf("[neutrino] value-before(2): %s\n", value); + return; + } + int _mac[6]; + sscanf( value, "%x:%x:%x:%x:%x:%x", &_mac[0], &_mac[1], &_mac[2], &_mac[3], &_mac[4], &_mac[5] ); + sprintf( value, "%02x:%02x:%02x:%02x:%02x:%02x", _mac[0], _mac[1], _mac[2], _mac[3], _mac[4], _mac[5]); +} + +void CMACInput::onAfterExec() +{ + int _mac[6]; + sscanf( value, "%x:%x:%x:%x:%x:%x", &_mac[0], &_mac[1], &_mac[2], &_mac[3], &_mac[4], &_mac[5] ); + sprintf( value, "%02x:%02x:%02x:%02x:%02x:%02x", _mac[0], _mac[1], _mac[2], _mac[3], _mac[4], _mac[5]); + if(strcmp(value,"00:00:00:00:00:00")==0) + value[0] = 0; /* strcpy(value, ""); */ +} + +//-----------------------------#################################------------------------------------------------------- + +CTimeInput::CTimeInput(const neutrino_locale_t Name, char* Value, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ, bool* Cancel) + : CExtendedInput(Name, Value, Hint_1, Hint_2, Observ, Cancel) +{ + frameBuffer = CFrameBuffer::getInstance(); + addInputField( new CExtendedInput_Item_Char("=+-") ); + addInputField( new CExtendedInput_Item_Spacer(20) ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char(":",false) ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char(":",false) ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_Char("0123456789") ); + addInputField( new CExtendedInput_Item_newLiner(30) ); + calculateDialog(); +} + +void CTimeInput::onBeforeExec() +{ + strcpy(value, "= 00:00:00"); +} + +void CTimeInput::onAfterExec() +{ + char tmp[10+1]; + strcpy(tmp, value); + strcpy(value+1, tmp+2); +} +//-----------------------------#################################------------------------------------------------------- + +CIntInput::CIntInput(const neutrino_locale_t Name, int& Value, const unsigned int Size, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ) + : CExtendedInput(Name, myValueStringInput, Hint_1, Hint_2, Observ) +{ + myValue = &Value; + + if (Size +#include + +#include +#include + +class CExtendedInput_Item; +class CExtendedInput : public CMenuTarget +{ + protected: + void Init(void); + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hintPosY; + int hheight; // head font height + int mheight; // menu font height + int iheight; + + std::vector inputFields; + int selectedChar; + + neutrino_locale_t name; + neutrino_locale_t hint_1; + neutrino_locale_t hint_2; + + char* value; + CChangeObserver* observ; + bool* cancel; + + virtual void paint(); + virtual void onBeforeExec(){}; + virtual void onAfterExec(){}; + + public: + + CExtendedInput(const neutrino_locale_t Name, char* Value, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ = NULL, bool* cancel = NULL); + ~CExtendedInput(); + + void hide(); + int exec( CMenuTarget* parent, const std::string & actionKey ); + void calculateDialog(); + + void addInputField( CExtendedInput_Item* ); +}; + + +class CExtendedInput_Item +{ + protected: + CFrameBuffer *frameBuffer; + int ix, iy, idx, idy; + char* data; + + public: + + virtual void setDataPointer(char* Data){data=Data;}; + virtual void init(int &x, int &y){}; + virtual void paint(int x, int y, bool focusGained){}; + virtual bool isSelectable(){return true;}; + + virtual void keyPressed( int key ){}; +}; + +class CExtendedInput_Item_Spacer : public CExtendedInput_Item +{ + protected: + int mSpacingX; + int mSpacingY; + public: + CExtendedInput_Item_Spacer(){}; + CExtendedInput_Item_Spacer(int spaceX, int spaceY=0){mSpacingX=spaceX;mSpacingY=spaceY;}; + virtual void init(int &x, int &y){x+=mSpacingX;y+=mSpacingY;}; + virtual bool isSelectable(){return false;}; +}; + +class CExtendedInput_Item_newLiner : public CExtendedInput_Item +{ + protected: + int mSpacingY; + public: + CExtendedInput_Item_newLiner(){}; + CExtendedInput_Item_newLiner(int spaceY){mSpacingY=spaceY;}; + virtual void init(int &x, int &y){x=0;y+=mSpacingY;}; + virtual bool isSelectable(){return false;}; +}; + + +class CExtendedInput_Item_Char : public CExtendedInput_Item +{ + protected: + std::string allowedChars; + bool selectable; + + bool isAllowedChar( char ); + int getCharID( char ); + + public: + CExtendedInput_Item_Char(const std::string & Chars="", bool Selectable=true ); + virtual ~CExtendedInput_Item_Char(){}; + void setAllowedChars( const std::string & ); + virtual void init(int &x, int &y); + virtual void paint(int x, int y, bool focusGained); + + virtual void keyPressed( int key ); + virtual bool isSelectable(){return selectable;}; +}; + +//---------------------------------------------------------------------------------------------------- + +class CIPInput : public CExtendedInput +{ + char IP[16]; + std::string * ip; + + protected: + virtual void onBeforeExec(); + virtual void onAfterExec(); + + public: + CIPInput(const neutrino_locale_t Name, std::string & Value, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ = NULL); +}; + +//---------------------------------------------------------------------------------------------------- + +class CDateInput : public CExtendedInput +{ + private: + time_t* time; + int dst; + + protected: + virtual void onBeforeExec(); + virtual void onAfterExec(); + + public: + CDateInput(const neutrino_locale_t Name, time_t* Time, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ = NULL); + ~CDateInput(); + char* getValue() {return value;} +}; + +//---------------------------------------------------------------------------------------------------- + +class CMACInput : public CExtendedInput +{ + protected: + virtual void onBeforeExec(); + virtual void onAfterExec(); + + public: + CMACInput(const neutrino_locale_t Name, char* Value, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ = NULL); +}; + +//---------------------------------------------------------------------------------------------------- + +class CTimeInput : public CExtendedInput +{ + protected: + virtual void onBeforeExec(); + virtual void onAfterExec(); + + public: + CTimeInput(const neutrino_locale_t Name, char* Value, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ = NULL, bool* cancel=NULL); +}; + +//---------------------------------------------------------------------------------------------------- + +class CIntInput : public CExtendedInput +{ +#define MAX_CINTINPUT_SIZE 16 + + char myValueStringInput[MAX_CINTINPUT_SIZE]; + char myValueStringOutput[MAX_CINTINPUT_SIZE]; + + int* myValue; + unsigned int m_size; + protected: + virtual void onBeforeExec(); + virtual void onAfterExec(); + + public: + /** + *@param Size how many digits can be entered + */ + CIntInput(const neutrino_locale_t Name, int& Value, const unsigned int Size, const neutrino_locale_t Hint_1, const neutrino_locale_t Hint_2, CChangeObserver* Observ = NULL); + char* getValue() { + return myValueStringOutput; + } +}; + + + +#endif diff --git a/src/gui/widget/textbox.cpp b/src/gui/widget/textbox.cpp new file mode 100644 index 000000000..4463091c3 --- /dev/null +++ b/src/gui/widget/textbox.cpp @@ -0,0 +1,533 @@ +/*************************************************************************** + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + *********************************************************** + + Module Name: textbox.cpp: . + + Description: implementation of the CTextBox class + This class provides a plain textbox with selectable features: + - Foot, Title + - Scroll bar + - Frame shadow + - Auto line break + - fixed position or auto width and auto height (later not tested yet) + - Center Text + + Date: Nov 2005 + + Author: Günther@tuxbox.berlios.org + based on code of Steffen Hehn 'McClean' + + Revision History: + Date Author Change Description + Nov 2005 Günther initial implementation + +****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "textbox.h" +#include + +#define TEXT_BORDER_WIDTH 8 +#define SCROLL_FRAME_WIDTH 10 +#define SCROLL_MARKER_BORDER 2 + +#define MAX_WINDOW_WIDTH (g_settings.screen_EndX - g_settings.screen_StartX - 40) +#define MAX_WINDOW_HEIGHT (g_settings.screen_EndY - g_settings.screen_StartY - 40) + +#define MIN_WINDOW_WIDTH ((g_settings.screen_EndX - g_settings.screen_StartX)>>1) +#define MIN_WINDOW_HEIGHT 40 + +CTextBox::CTextBox(const char * text, Font* font_text, const int mode, + const CBox* position, CFBWindow::color_t textBackgroundColor) +{ + //TRACE("[CTextBox] new\r\n"); + initVar(); + + frameBuffer = NULL; + max_width = 0; + + if(text != NULL) m_cText = text; + if(font_text != NULL) m_pcFontText = font_text; + if(position != NULL) + { + m_cFrame = *position; + m_nMaxHeight = m_cFrame.iHeight; + m_nMaxWidth = m_cFrame.iWidth; + } + + m_nMode = mode; + + /* in case of auto line break, we do no support auto width yet */ + if( !(mode & NO_AUTO_LINEBREAK)) + { + m_nMode = m_nMode & ~AUTO_WIDTH; /* delete any AUTO_WIDTH*/ + } + +#if 0 + TRACE(" Mode: "); + if(mode & SCROLL) TRACE("SCROLL "); + if(mode & NO_AUTO_LINEBREAK) TRACE("NO_AUTO_LINEBREAK "); + if(mode & AUTO_WIDTH) TRACE("AUTO_WIDTH "); + if(mode & AUTO_HIGH) TRACE("AUTO_HIGH"); + TRACE("\r\n"); + +#endif + //TRACE(" CTextBox::m_cText: %d, m_nMode %d\t\r\n",m_cText.size(),m_nMode); + + m_textBackgroundColor = textBackgroundColor; + m_nFontTextHeight = m_pcFontText->getHeight(); + //TRACE(" CTextBox::m_nFontTextHeight: %d\t\r\n",m_nFontTextHeight); + + /* Initialise the window frames first */ + initFramesRel(); + + // than refresh text line array + refreshTextLineArray(); +} + +CTextBox::CTextBox(const char * text) +{ + //TRACE("[CTextBox] new\r\n"); + initVar(); + + frameBuffer = NULL; + if(text != NULL) m_cText = *text; + + /* Initialise the window frames first */ + initFramesRel(); + + // than refresh text line array + refreshTextLineArray(); +} + +CTextBox::CTextBox() +{ + //TRACE("[CTextBox] new\r\n"); + initVar(); + initFramesRel(); + + frameBuffer = NULL; +} + +CTextBox::~CTextBox() +{ + //TRACE("[CTextBox] del\r\n"); + m_cLineArray.clear(); + hide(); + +} + +void CTextBox::initVar(void) +{ + //TRACE("[CTextBox]->InitVar\r\n"); + m_cText = ""; + m_nMode = SCROLL; + + m_pcFontText = NULL; + m_pcFontText = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1]; + m_nFontTextHeight = m_pcFontText->getHeight(); + + m_nNrOfPages = 1; + m_nNrOfLines = 0; + m_nLinesPerPage = 0; + m_nCurrentLine = 0; + m_nCurrentPage = 0; + + m_cFrame.iX = g_settings.screen_StartX + ((g_settings.screen_EndX - g_settings.screen_StartX - MIN_WINDOW_WIDTH) >>1); + m_cFrame.iWidth = MIN_WINDOW_WIDTH; + m_cFrame.iY = g_settings.screen_StartY + ((g_settings.screen_EndY - g_settings.screen_StartY - MIN_WINDOW_HEIGHT) >>1); + m_cFrame.iHeight = MIN_WINDOW_HEIGHT; + + m_nMaxHeight = MAX_WINDOW_HEIGHT; + m_nMaxWidth = MAX_WINDOW_WIDTH; + + m_textBackgroundColor = COL_MENUCONTENT_PLUS_0; + + m_cLineArray.clear(); +} + +void CTextBox::reSizeMainFrameWidth(int textWidth) +{ + //TRACE("[CTextBox]->ReSizeMainFrameWidth: %d, current: %d\r\n",textWidth,m_cFrameTextRel.iWidth); + + int iNewWindowWidth = textWidth + m_cFrameScrollRel.iWidth + 2*TEXT_BORDER_WIDTH; + + if( iNewWindowWidth > m_nMaxWidth) iNewWindowWidth = m_nMaxWidth; + if( iNewWindowWidth < MIN_WINDOW_WIDTH) iNewWindowWidth = MIN_WINDOW_WIDTH; + + m_cFrame.iWidth = iNewWindowWidth; + + /* Re-Init the children frames due to new main window */ + initFramesRel(); +} + +void CTextBox::reSizeMainFrameHeight(int textHeight) +{ + TRACE("[CTextBox]->ReSizeMainFrameHeight: %d, current: %d\r\n",textHeight,m_cFrameTextRel.iHeight); + + int iNewWindowHeight = textHeight + + 2*TEXT_BORDER_WIDTH; + + if( iNewWindowHeight > m_nMaxHeight) iNewWindowHeight = m_nMaxHeight; + if( iNewWindowHeight < MIN_WINDOW_HEIGHT) iNewWindowHeight = MIN_WINDOW_HEIGHT; + + m_cFrame.iHeight = iNewWindowHeight; + + /* Re-Init the children frames due to new main window */ + initFramesRel(); +} + +void CTextBox::initFramesRel(void) +{ + //TRACE("[CTextBox]->InitFramesRel\r\n"); + + m_cFrameTextRel.iX = 0; + m_cFrameTextRel.iY = 0; + m_cFrameTextRel.iHeight = m_cFrame.iHeight ; + + if(m_nMode & SCROLL) + { + m_cFrameScrollRel.iX = m_cFrame.iWidth - SCROLL_FRAME_WIDTH; + m_cFrameScrollRel.iY = m_cFrameTextRel.iY; + m_cFrameScrollRel.iWidth = SCROLL_FRAME_WIDTH; + m_cFrameScrollRel.iHeight = m_cFrameTextRel.iHeight; + } + else + { + m_cFrameScrollRel.iX = 0; + m_cFrameScrollRel.iY = 0; + m_cFrameScrollRel.iHeight = 0; + m_cFrameScrollRel.iWidth = 0; + } + + m_cFrameTextRel.iWidth = m_cFrame.iWidth - m_cFrameScrollRel.iWidth; + + m_nLinesPerPage = (m_cFrameTextRel.iHeight - (2*TEXT_BORDER_WIDTH)) / m_nFontTextHeight; + +#if 0 + TRACE_1("Frames\r\n\tScren:\t%3d,%3d,%3d,%3d\r\n\tMain:\t%3d,%3d,%3d,%3d\r\n\tText:\t%3d,%3d,%3d,%3d \r\n\tScroll:\t%3d,%3d,%3d,%3d \r\n", + g_settings.screen_StartX, + g_settings.screen_StartY, + g_settings.screen_EndX, + g_settings.screen_EndY, + m_cFrame.iX, + m_cFrame.iY, + m_cFrame.iWidth, + m_cFrame.iHeight, + m_cFrameTextRel.iX, + m_cFrameTextRel.iY, + m_cFrameTextRel.iWidth, + m_cFrameTextRel.iHeight, + m_cFrameScrollRel.iX, + m_cFrameScrollRel.iY, + m_cFrameScrollRel.iWidth, + m_cFrameScrollRel.iHeight + ); +#endif +} + +void CTextBox::refreshTextLineArray(void) +{ + //TRACE("[CTextBox]->RefreshLineArray \r\n"); + int loop = true; + int pos_prev = 0; + int pos = 0; + int aktWidth = 0; + int aktWordWidth = 0; + int lineBreakWidth; + int maxTextWidth = 0; + + m_nNrOfNewLine = 0; + + std::string aktLine = ""; + std::string aktWord = ""; + + /* clear current line vector */ + m_cLineArray.clear(); + m_nNrOfLines = 0; + + if( m_nMode & AUTO_WIDTH) + { + /* In case of autowidth, we calculate the max allowed width of the textbox */ + lineBreakWidth = MAX_WINDOW_WIDTH - m_cFrameScrollRel.iWidth - 2*TEXT_BORDER_WIDTH; + } + else + { + /* If not autowidth, we just take the actuall textframe width */ + lineBreakWidth = m_cFrameTextRel.iWidth - 2*TEXT_BORDER_WIDTH; + } + if(max_width) + lineBreakWidth = max_width; + //printf("TextBox: lineBreakWidth %d\n", lineBreakWidth); + int TextChars = m_cText.size(); + // do not parse, if text is empty + if(TextChars > 0) + { + while(loop) + { + if(m_nMode & NO_AUTO_LINEBREAK) + { + pos = m_cText.find_first_of("\n",pos_prev); + } + else + { + pos = m_cText.find_first_of("\n-. ",pos_prev); + } + + //TRACE_1(" pos: %d pos_prev: %d\r\n",pos,pos_prev); + + if(pos == -1) + { + pos = TextChars+1; + loop = false; // note, this is not 100% correct. if the last characters does not fit in one line, the characters after are cut + //TRACE_1(" Textend found\r\n"); + } + + aktWord = m_cText.substr(pos_prev, pos - pos_prev + 1); + aktWordWidth = m_pcFontText->getRenderWidth(aktWord, true); + pos_prev = pos + 1; + //if(aktWord.find(""") == ) + if(1) + { + //TRACE_1(" aktWord: >%s< pos:%d\r\n",aktWord.c_str(),pos); + + if( aktWidth + aktWordWidth > lineBreakWidth && + !(m_nMode & NO_AUTO_LINEBREAK)) + { + /* we need a new line before we can continue */ + m_cLineArray.push_back(aktLine); + //TRACE_1(" end line: %s\r\n", aktLine.c_str()); + m_nNrOfLines++; + aktLine = ""; + aktWidth = 0; + + if(pos_prev >= TextChars) loop = false; + } + + aktLine += aktWord; + aktWidth += aktWordWidth; + if (aktWidth > maxTextWidth) maxTextWidth = aktWidth; + //TRACE_1(" aktLine : %s\r\n",aktLine.c_str()); + //TRACE_1(" aktWidth: %d aktWordWidth:%d\r\n",aktWidth,aktWordWidth); + + if( m_cText[pos] == '\n' || + loop == false) + { + // current line ends with an carriage return, make new line + if (m_cText[pos] == '\n') + aktLine.erase(aktLine.size() - 1,1); + m_cLineArray.push_back(aktLine); + m_nNrOfLines++; + aktLine = ""; + aktWidth = 0; + m_nNrOfNewLine++; + if(pos_prev >= TextChars) loop = false; + } + } + } + + + /* check if we have to recalculate the window frame size, due to auto width and auto height */ + if( m_nMode & AUTO_WIDTH) + { + reSizeMainFrameWidth(maxTextWidth); + } + + if(m_nMode & AUTO_HIGH) + { + reSizeMainFrameHeight(m_nNrOfLines * m_nFontTextHeight); + } + + m_nLinesPerPage = (m_cFrameTextRel.iHeight - (2*TEXT_BORDER_WIDTH)) / m_nFontTextHeight; + m_nNrOfPages = ((m_nNrOfLines-1) / m_nLinesPerPage) + 1; + + if(m_nCurrentPage >= m_nNrOfPages) + { + m_nCurrentPage = m_nNrOfPages - 1; + m_nCurrentLine = m_nCurrentPage * m_nLinesPerPage; + } + } + else + { + m_nNrOfPages = 0; + m_nNrOfLines = 0; + m_nCurrentPage = 0; + m_nCurrentLine = 0; + m_nLinesPerPage = 1; + } +#if 0 + TRACE_1(" m_nNrOfPages: %d\r\n",m_nNrOfPages); + TRACE_1(" m_nNrOfLines: %d\r\n",m_nNrOfLines); + TRACE_1(" m_nNrOfNewLine: %d\r\n",m_nNrOfNewLine); + TRACE_1(" maxTextWidth: %d\r\n",maxTextWidth); + TRACE_1(" m_nLinesPerPage: %d\r\n",m_nLinesPerPage); + TRACE_1(" m_nFontTextHeight:%d\r\n",m_nFontTextHeight); + TRACE_1(" m_nCurrentPage: %d\r\n",m_nCurrentPage); + TRACE_1(" m_nCurrentLine: %d\r\n",m_nCurrentLine); +#endif +} + +void CTextBox::refreshScroll(void) +{ + if( !(m_nMode & SCROLL)) return; + if( frameBuffer == NULL) return; + + if (m_nNrOfPages > 1) + { + frameBuffer->paintBoxRel(m_cFrameScrollRel.iX+m_cFrame.iX, m_cFrameScrollRel.iY+m_cFrame.iY, + m_cFrameScrollRel.iWidth, m_cFrameScrollRel.iHeight, + COL_MENUCONTENT_PLUS_1); + unsigned int marker_size = m_cFrameScrollRel.iHeight / m_nNrOfPages; + frameBuffer->paintBoxRel(m_cFrameScrollRel.iX + SCROLL_MARKER_BORDER+m_cFrame.iX, + m_cFrameScrollRel.iY + m_nCurrentPage * marker_size+m_cFrame.iY, + m_cFrameScrollRel.iWidth - 2*SCROLL_MARKER_BORDER, + marker_size, COL_MENUCONTENT_PLUS_3); + } + else + { + frameBuffer->paintBoxRel(m_cFrameScrollRel.iX+m_cFrame.iX, m_cFrameScrollRel.iY+m_cFrame.iY, + m_cFrameScrollRel.iWidth, m_cFrameScrollRel.iHeight, + m_textBackgroundColor); + } +} + +void CTextBox::refreshText(void) +{ + if( frameBuffer == NULL) return; + //TRACE(" CTextBox::refreshText: %d,%s\r\n",m_nCurrentLine,m_cLineArray[m_nCurrentLine].c_str()); + //Paint Text Background + frameBuffer->paintBoxRel(m_cFrameTextRel.iX+m_cFrame.iX, m_cFrameTextRel.iY+m_cFrame.iY, + m_cFrameTextRel.iWidth, m_cFrameTextRel.iHeight, m_textBackgroundColor); + + if( m_nNrOfLines <= 0) return; + int y = m_cFrameTextRel.iY + TEXT_BORDER_WIDTH; + int i; + int x_center = 0; + + for(i = m_nCurrentLine; i < m_nNrOfLines && i < m_nCurrentLine + m_nLinesPerPage; i++) + { + y += m_nFontTextHeight; + + if( m_nMode & CENTER ) + { + x_center = (m_cFrameTextRel.iWidth - m_pcFontText->getRenderWidth(m_cLineArray[i], true))>>1; + } + + m_pcFontText->RenderString(m_cFrameTextRel.iX + TEXT_BORDER_WIDTH + x_center+m_cFrame.iX, + y+m_cFrame.iY, m_cFrameTextRel.iWidth, m_cLineArray[i].c_str(), + COL_MENUCONTENT, 0, true); // UTF-8 + } +} + +void CTextBox::scrollPageDown(const int pages) +{ + if( !(m_nMode & SCROLL)) return; + if( m_nNrOfLines <= 0) return; + TRACE("[CTextBox]->ScrollPageDown \r\n"); + + + if(m_nCurrentPage + pages < m_nNrOfPages) + { + m_nCurrentPage += pages; + } + else + { + m_nCurrentPage = m_nNrOfPages - 1; + } + m_nCurrentLine = m_nCurrentPage * m_nLinesPerPage; + refresh(); +} + +void CTextBox::scrollPageUp(const int pages) +{ + if( !(m_nMode & SCROLL)) return; + if( m_nNrOfLines <= 0) return; + TRACE("[CTextBox]->ScrollPageUp \r\n"); + + + if(m_nCurrentPage - pages > 0) + { + m_nCurrentPage -= pages; + } + else + { + m_nCurrentPage = 0; + } + m_nCurrentLine = m_nCurrentPage * m_nLinesPerPage; + refresh(); +} + +void CTextBox::refresh(void) +{ + if( frameBuffer == NULL) return; + //TRACE("[CTextBox]->Refresh\r\n"); +//printf("setText::refresh!\n"); + + //Paint text + refreshScroll(); + refreshText(); +} + +bool CTextBox::setText(const std::string* newText, int _max_width) +{ + //TRACE("[CTextBox]->SetText \r\n"); + bool result = false; + max_width = _max_width; +//printf("setText: _max_width %d max_width %d\n", _max_width, max_width); + if (newText != NULL) + { + m_cText = *newText; + //m_cText = *newText + "\n"; //FIXME test + refreshTextLineArray(); + refresh(); + result = true; + } + return(result); +}; + +void CTextBox::paint (void) +{ + if(frameBuffer != NULL) return; + //TRACE("[CTextBox]->paint \r\n"); + frameBuffer = CFrameBuffer::getInstance(); + refresh(); +} + +void CTextBox::hide (void) +{ + if(frameBuffer == NULL) return; + //TRACE("[CTextBox]->hide \r\n"); + frameBuffer->paintBackgroundBoxRel(m_cFrame.iX, m_cFrame.iY, m_cFrame.iWidth, m_cFrame.iHeight); + frameBuffer = NULL; +} diff --git a/src/gui/widget/textbox.h b/src/gui/widget/textbox.h new file mode 100644 index 000000000..7d70e7113 --- /dev/null +++ b/src/gui/widget/textbox.h @@ -0,0 +1,168 @@ + +/*************************************************************************** + Neutrino-GUI - DBoxII-Project + + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + *********************************************************** + + Module Name: textbox.h . + + Description: interface of the CTextBox class + + Date: Nov 2005 + + Author: Günther@tuxbox.berlios.org + based on code of Steffen Hehn 'McClean' + + Revision History: + Date Author Change Description + Nov 2005 Günther initial implementation + +****************************************************************************/ + +#if !defined(TEXTBOX_H) +#define TEXTBOX_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TRACE printf +#define TRACE_1 printf + +class CBox +{ + private: + + public: + /* Constructor */ + inline CBox(){;}; + inline CBox( const int _iX, const int _iY, const int _iWidth, const int _iHeight){iX=_iX; iY=_iY; iWidth=_iWidth; iHeight=_iHeight;}; + inline ~CBox(){;}; + /* Functions */ + /* Variables */ + int iX; + int iY; + int iWidth; + int iHeight; +}; + +class CTextBox +{ + private: + /* Functions */ + void refreshTextLineArray(void); + void initVar(void); + void initFramesRel(void); + void refreshScroll(void); + void refreshText(void); + void reSizeMainFrameWidth(int maxTextWidth); + void reSizeMainFrameHeight(int maxTextHeight); + + /* Variables */ + std::string m_cText; + std::vector m_cLineArray; + + bool m_showTextFrame; + + CBox m_cFrame; + CBox m_cFrameTextRel; + CBox m_cFrameScrollRel; + + int m_nMaxHeight; + int m_nMaxWidth; + + int m_nMode; + + int m_nNrOfPages; + int m_nNrOfLines; + int m_nNrOfNewLine; + int m_nMaxLineWidth; + int m_nLinesPerPage; + int m_nCurrentLine; + int m_nCurrentPage; + + Font* m_pcFontText; + int m_nFontTextHeight; + CFBWindow::color_t m_textBackgroundColor; + + CFrameBuffer * frameBuffer; + int max_width; + public: + /* Constructor */ + CTextBox(); + CTextBox( const char * text); + CTextBox( const char * text, + Font* font_text, + const int mode, + const CBox* position, + CFBWindow::color_t textBackgroundColor = COL_MENUCONTENT_PLUS_0); + + virtual ~CTextBox(); + + /* Functions */ + void refresh(void); + void scrollPageDown(const int pages); + void scrollPageUp(const int pages); + bool setText(const std::string* newText, int _max_width = 0); +inline bool isPainted(void){if( frameBuffer == NULL) return (false); else return (true);}; + +inline CBox getWindowsPos(void) {return(m_cFrame);}; +inline int getMaxLineWidth(void) {return(m_nMaxLineWidth);}; +inline int getLines(void) {return(m_nNrOfLines);}; +inline int getPages(void) {return(m_nNrOfPages);}; +inline void movePosition(int x, int y){m_cFrame.iX = x; m_cFrame.iY = y;}; + + void paint (void); + void hide (void); + + + /* Variables */ + typedef enum mode_ + { + AUTO_WIDTH = 0x01, + AUTO_HIGH = 0x02, + SCROLL = 0x04, + CENTER = 0x40, + NO_AUTO_LINEBREAK = 0x80 + }mode; +}; + + + +#endif // !defined(AFX_TEXTBOX_H__208DED01_ABEC_491C_A632_5B21057DC5D8__INCLUDED_) diff --git a/src/gui/widget/vfdcontroler.cpp b/src/gui/widget/vfdcontroler.cpp new file mode 100644 index 000000000..f0a75a797 --- /dev/null +++ b/src/gui/widget/vfdcontroler.cpp @@ -0,0 +1,270 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#define BRIGHTNESSFACTOR 0.15 // 0 - 15 + +#define ROUND_RADIUS 9 + +CVfdControler::CVfdControler(const neutrino_locale_t Name, CChangeObserver* Observer) +{ + frameBuffer = CFrameBuffer::getInstance(); + hheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); + mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + observer = Observer; + name = Name; + width = w_max(390, 0); + height = h_max(hheight+ mheight* 3+ +mheight/2, 0); + x = frameBuffer->getScreenX() + ((frameBuffer->getScreenWidth()-width) >> 1); + y = frameBuffer->getScreenY() + ((frameBuffer->getScreenHeight()-height)>>1); + + brightness = CVFD::getInstance()->getBrightness(); + brightnessstandby = CVFD::getInstance()->getBrightnessStandby(); +} + +void CVfdControler::setVfd() +{ + CVFD::getInstance()->setBrightness(brightness); + CVFD::getInstance()->setBrightnessStandby(brightnessstandby); +} + +int CVfdControler::exec(CMenuTarget* parent, const std::string &) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + int selected, res = menu_return::RETURN_REPAINT; + unsigned int brightness_alt, brightnessstandby_alt; + + if (parent) + { + parent->hide(); + } + brightness_alt = CVFD::getInstance()->getBrightness(); + brightnessstandby_alt = CVFD::getInstance()->getBrightnessStandby(); + selected = 0; + + setVfd(); + paint(); + + unsigned long long timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + bool loop=true; + while (loop) + { + g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd, true ); + + if ( msg <= CRCInput::RC_MaxRC ) + timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_MENU] == 0 ? 0xFFFF : g_settings.timing[SNeutrinoSettings +::TIMING_MENU]); + + switch ( msg ) + { + case CRCInput::RC_down: + if(selected < 2) // max entries + { + paintSlider(x + 10, y + hheight , brightness , BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS , false); + paintSlider(x + 10, y + hheight + mheight, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, false); + selected++; + switch (selected) { + case 0: + paintSlider(x+ 10, y+ hheight, brightness, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS, true); + break; + case 1: + paintSlider(x+ 10, y+ hheight+ mheight, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, true); + CVFD::getInstance()->setMode(CVFD::MODE_STANDBY); + break; + case 2: + frameBuffer->paintBoxRel(x, y+hheight+mheight*2+mheight/2, width, mheight, COL_MENUCONTENTSELECTED_PLUS_0, ROUND_RADIUS, 3); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10, y+hheight+mheight*3+mheight/2, width, g_Locale->getText(LOCALE_OPTIONS_DEFAULT), COL_MENUCONTENTSELECTED, 0, true); // UTF-8 + break; + } + } + break; + + case CRCInput::RC_up: + if (selected > 0) { + paintSlider(x + 10, y + hheight , brightness , BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS , false); + paintSlider(x + 10, y + hheight + mheight, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, false); + selected--; + switch (selected) { + case 0: + paintSlider(x+ 10, y+ hheight, brightness, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS, true); + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + break; + case 1: + paintSlider(x+10, y+hheight+mheight, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, true); + CVFD::getInstance()->setMode(CVFD::MODE_STANDBY); + frameBuffer->paintBoxRel(x, y+hheight+mheight*2+mheight/2, width, mheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10, y+hheight+mheight*3+mheight/2, width, g_Locale->getText(LOCALE_OPTIONS_DEFAULT), COL_MENUCONTENT, 0, true); // UTF-8 + break; + case 2: + break; + } + } + break; + + case CRCInput::RC_right: + switch (selected) { + case 0: + if (brightness < 15) { + brightness ++; + paintSlider(x+10, y+hheight, brightness, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS, true); + setVfd(); + } + break; + case 1: + if (brightnessstandby < 15) { + brightnessstandby ++; + paintSlider(x+10, y+hheight+mheight, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, true); + setVfd(); + } + break; + } + break; + + case CRCInput::RC_left: + switch (selected) { + case 0: + if (brightness > 0) { + brightness--; + paintSlider(x+10, y+hheight, brightness, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS, true); + setVfd(); + } + break; + case 1: + if (brightnessstandby > 0) { + brightnessstandby--; + paintSlider(x+10, y+hheight+mheight, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, true); + setVfd(); + } + break; + } + break; + + case CRCInput::RC_home: + if ( ((brightness != brightness_alt) || (brightnessstandby != brightnessstandby_alt) ) && + (ShowLocalizedMessage(name, LOCALE_MESSAGEBOX_DISCARD, CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbCancel) == CMessageBox::mbrCancel)) + break; + + brightness = brightness_alt; + brightnessstandby = brightnessstandby_alt; + setVfd(); + loop = false; + break; + + case CRCInput::RC_ok: + if (selected==2) { + brightness = DEFAULT_VFD_BRIGHTNESS; + brightnessstandby = DEFAULT_VFD_STANDBYBRIGHTNESS; + selected = 0; + setVfd(); + paint(); + break; + } + + case CRCInput::RC_timeout: + loop = false; + break; + + case CRCInput::RC_sat: + case CRCInput::RC_favorites: + break; + default: + if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) + { + loop = false; + res = menu_return::RETURN_EXIT_ALL; + } + } + } + + hide(); + + if(observer) + observer->changeNotify(name, NULL); + + return res; +} + +void CVfdControler::hide() +{ + frameBuffer->paintBackgroundBoxRel(x,y, width,height); +} + +void CVfdControler::paint() +{ + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + + frameBuffer->paintBoxRel(x,y, width,hheight, COL_MENUHEAD_PLUS_0, ROUND_RADIUS, 1);//round + frameBuffer->paintBoxRel(x,y+hheight, width,height-hheight, COL_MENUCONTENT_PLUS_0, ROUND_RADIUS, 2);//round + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(x+10,y+hheight, width, g_Locale->getText(name), COL_MENUHEAD, 0, true); // UTF-8 + + paintSlider(x+10, y+hheight, brightness, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESS, true); + paintSlider(x+10, y+hheight+mheight, brightnessstandby, BRIGHTNESSFACTOR, LOCALE_LCDCONTROLER_BRIGHTNESSSTANDBY, false); + + frameBuffer->paintHLineRel(x+10, width-20, y+hheight+mheight*2+mheight/4, COL_MENUCONTENT_PLUS_3); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x+10, y+hheight+mheight*3+mheight/2, width, g_Locale->getText(LOCALE_OPTIONS_DEFAULT), COL_MENUCONTENT, 0, true); // UTF-8 +} + +void CVfdControler::paintSlider(int x, int y, unsigned int spos, float factor, const neutrino_locale_t text, bool selected) +{ + int startx = 200; + char wert[5]; + + frameBuffer->paintBoxRel(x + startx, y, 120, mheight, COL_MENUCONTENT_PLUS_0); + frameBuffer->paintIcon("volumebody.raw", x + startx, y+2+mheight/4); + frameBuffer->paintIcon(selected ? "volumeslider2blue.raw" : "volumeslider2.raw", (int)(x + (startx+3)+(spos / factor)), y+mheight/4); + + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x, y+mheight, width, g_Locale->getText(text), COL_MENUCONTENT, 0, true); // UTF-8 + sprintf(wert, "%3d", spos); // UTF-8 encoded + frameBuffer->paintBoxRel(x + startx + 120 + 10, y, 50, mheight, COL_MENUCONTENT_PLUS_0); + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x + startx + 120 + 10, y+mheight, width, wert, COL_MENUCONTENT, 0, true); // UTF-8 +} diff --git a/src/gui/widget/vfdcontroler.h b/src/gui/widget/vfdcontroler.h new file mode 100644 index 000000000..bb17a11d1 --- /dev/null +++ b/src/gui/widget/vfdcontroler.h @@ -0,0 +1,74 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __vfdcontroler__ +#define __vfdcontroler__ + +#include +#include + +#include "menue.h" + +#include + +class CVfdControler : public CMenuTarget +{ + private: + CFrameBuffer *frameBuffer; + int x; + int y; + int width; + int height; + int hheight,mheight; // head/menu font height + + unsigned char brightness; + unsigned char brightnessstandby; + + neutrino_locale_t name; + + CChangeObserver* observer; + + void paint(); + void setVfd(); + void paintSlider(int x, int y, unsigned int spos, float factor, const neutrino_locale_t text, bool selected); + + public: + + CVfdControler(const neutrino_locale_t Name, CChangeObserver* Observer = NULL); + + void hide(); + int exec(CMenuTarget* parent, const std::string & actionKey); + +}; + + +#endif diff --git a/src/lcddisplay/lcddisplay.h b/src/lcddisplay/lcddisplay.h new file mode 100644 index 000000000..1904076c8 --- /dev/null +++ b/src/lcddisplay/lcddisplay.h @@ -0,0 +1,77 @@ +#ifndef __lcddisplay__ +#define __lcddisplay__ +/* + LCD-Daemon - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + baseroutines by Shadow_ + Homepage: http://dbox.cyberphoria.org/ + + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +#include + +typedef unsigned char raw_display_t[LCD_ROWS*8][LCD_COLS]; + +class CLCDDisplay +{ + private: + raw_display_t raw; + unsigned char lcd[LCD_ROWS][LCD_COLS]; + int fd, paused; + std::string iconBasePath; + bool available; + + public: + enum + { + PIXEL_ON = LCD_PIXEL_ON, + PIXEL_OFF = LCD_PIXEL_OFF, + PIXEL_INV = LCD_PIXEL_INV + }; + + CLCDDisplay(); + ~CLCDDisplay(); + + void pause(); + void resume(); + + void convert_data(); + void setIconBasePath(std::string bp){iconBasePath=bp;}; + bool isAvailable(); + + void update(); + + void draw_point(const int x, const int y, const int state); + void draw_line(const int x1, const int y1, const int x2, const int y2, const int state); + void draw_fill_rect (int left,int top,int right,int bottom,int state); + void draw_rectangle (int left,int top, int right, int bottom, int linestate,int fillstate); + void draw_polygon(int num_vertices, int *vertices, int state); + + bool paintIcon(std::string filename, int x, int y, bool invert); + void dump_screen(raw_display_t *screen); + void load_screen(const raw_display_t * const screen); + bool load_png(const char * const filename); +}; + + +#endif diff --git a/src/mymenu.h b/src/mymenu.h new file mode 100644 index 000000000..d528f633c --- /dev/null +++ b/src/mymenu.h @@ -0,0 +1,63 @@ +#define SCANMODE_OPTION_COUNT 3 +const CMenuOptionChooser::keyval SCANMODE_OPTIONS[SCANMODE_OPTION_COUNT] = +{ + { 0, LOCALE_EXTRA_SCAN_FULL}, + { 1, LOCALE_EXTRA_SCAN_FAST}, + { 2, LOCALE_EXTRA_TPSCAN} +}; + +#define HDD_NOISE_OPTION_COUNT 4 +const CMenuOptionChooser::keyval HDD_NOISE_OPTIONS[HDD_NOISE_OPTION_COUNT] = +{ + {0, LOCALE_OPTIONS_OFF}, + {128, LOCALE_HDD_SLOW}, + {190, LOCALE_HDD_MIDDLE}, + {254, LOCALE_HDD_FAST} +}; +#define HDD_FILESYS_OPTION_COUNT 3 +const CMenuOptionChooser::keyval HDD_FILESYS_OPTIONS[HDD_FILESYS_OPTION_COUNT] = +{ + {0, LOCALE_HDD_EXT3}, + {1, LOCALE_HDD_REISER}, + {2, LOCALE_OPTIONS_OFF} +}; +#define HDD_SLEEP_OPTION_COUNT 7 +const CMenuOptionChooser::keyval HDD_SLEEP_OPTIONS[HDD_SLEEP_OPTION_COUNT] = +{ + {0, LOCALE_OPTIONS_OFF}, + {12, LOCALE_HDD_1MIN}, + {60, LOCALE_HDD_5MIN}, + {120, LOCALE_HDD_10MIN}, + {240, LOCALE_HDD_20MIN}, + {241, LOCALE_HDD_30MIN}, + {242, LOCALE_HDD_60MIN} +}; +#if 0 +#define LOGO_OPTION_COUNT 3 +const CMenuOptionChooser::keyval LOGO_OPTIONS[LOGO_OPTION_COUNT] = +{ + {1, LOCALE_EXTRA_LOGO1}, + {2, LOCALE_EXTRA_LOGO2}, + {3, LOCALE_EXTRA_LOGO3} +}; +#endif +#define RF_CARRIER_OPTION_COUNT 4 +const CMenuOptionChooser::keyval RF_CARRIER_OPTIONS[RF_CARRIER_OPTION_COUNT] = +{ + {0, LOCALE_RF_CARRIER_4500}, + {1, LOCALE_RF_CARRIER_5500}, + {2, LOCALE_RF_CARRIER_6000}, + {3, LOCALE_RF_CARRIER_6500} +}; +#define OPTIONS_SOUTH0_NORTH1_OPTION_COUNT 2 +const CMenuOptionChooser::keyval OPTIONS_SOUTH0_NORTH1_OPTIONS[OPTIONS_SOUTH0_NORTH1_OPTION_COUNT] = +{ + {0, LOCALE_EXTRA_SOUTH}, + {1, LOCALE_EXTRA_NORTH} +}; +#define OPTIONS_EAST0_WEST1_OPTION_COUNT 2 +const CMenuOptionChooser::keyval OPTIONS_EAST0_WEST1_OPTIONS[OPTIONS_EAST0_WEST1_OPTION_COUNT] = +{ + {0, LOCALE_EXTRA_EAST}, + {1, LOCALE_EXTRA_WEST} +}; diff --git a/src/neutrino.cpp b/src/neutrino.cpp new file mode 100644 index 000000000..c3ef00f0d --- /dev/null +++ b/src/neutrino.cpp @@ -0,0 +1,4711 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + and some other guys + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define NEUTRINO_CPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +#include "global.h" +#include "neutrino.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "gui/widget/colorchooser.h" +#include "gui/widget/menue.h" +#include "gui/widget/messagebox.h" +#include "gui/widget/hintbox.h" +#include "gui/widget/icons.h" +#include "gui/widget/lcdcontroler.h" +#include "gui/widget/vfdcontroler.h" +#include "gui/widget/rgbcsynccontroler.h" +#include "gui/widget/keychooser.h" +#include "gui/widget/stringinput.h" +#include "gui/widget/stringinput_ext.h" +#include "gui/widget/mountchooser.h" + +#include "gui/color.h" +#include "gui/customcolor.h" + +#include "gui/bedit/bouqueteditor_bouquets.h" +#include "gui/bouquetlist.h" +#include "gui/eventlist.h" +#include "gui/channellist.h" +#include "gui/screensetup.h" +#include "gui/pluginlist.h" +#include "gui/plugins.h" +#include "gui/infoviewer.h" +#include "gui/epgview.h" +#include "gui/epg_menu.h" +#include "gui/update.h" +#include "gui/scan.h" +#include "gui/favorites.h" +#include "gui/sleeptimer.h" +#include "gui/rc_lock.h" +#include "gui/timerlist.h" +#include "gui/alphasetup.h" +#include "gui/audioplayer.h" +#include "gui/imageinfo.h" +#include "gui/movieplayer.h" +#include "gui/nfs.h" +#include "gui/pictureviewer.h" +#include "gui/motorcontrol.h" +#include "gui/filebrowser.h" +#include "gui/scale.h" +#include "gui/cam_menu.h" +#include "gui/hdd_menu.h" +#include "gui/upnpbrowser.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +int old_b_id = -1; +CHintBox * reloadhintBox = 0; +uint32_t sec_timer; +int rf_dummy; +bool has_hdd; +#include "gui/infoclock.h" +#include "gui/dboxinfo.h" +CInfoClock *InfoClock; +int allow_flash = 1; +extern int was_record; +extern char current_timezone[50]; +Zapit_config zapitCfg; +char zapit_lat[20]; +char zapit_long[20]; +bool autoshift = false; +bool autoshift_delete = false; +uint32_t shift_timer; +uint32_t scrambled_timer; +char recDir[255]; +char timeshiftDir[255]; + +extern int tuxtxt_init(); +extern void tuxtxt_start(int tpid); +extern int tuxtxt_stop(); +extern void tuxtxt_close(); + +int dvbsub_init(); +int dvbsub_stop(); +int dvbsub_close(); +int dvbsub_start(int pid); +int dvbsub_pause(); + +//char current_volume; +extern int list_changed; + +static CScale * g_volscale; +//NEW +static pthread_t timer_thread; +void * timerd_main_thread(void *data); + +extern int streamts_stop; +void * streamts_main_thread(void *data); +static pthread_t stream_thread ; + +extern int zapit_ready; +static pthread_t zapit_thread ; +void * zapit_main_thread(void *data); +extern t_channel_id live_channel_id; //zapit +void setZapitConfig(Zapit_config * Cfg); +void getZapitConfig(Zapit_config *Cfg); + +void * nhttpd_main_thread(void *data); +static pthread_t nhttpd_thread ; + +//#define DISABLE_SECTIONSD //FIXME +extern int sectionsd_stop; +static pthread_t sections_thread; +void * sectionsd_main_thread(void *data); +//extern int sectionsd_scanning; // sectionsd.cpp +extern bool timeset; // sectionsd + +extern cVideo * videoDecoder; +extern cAudio * audioDecoder; +cPowerManager *powerManager; +cCpuFreqManager * cpuFreq; + +int prev_video_mode; + +int xres = 72; +int yres = 72; // TODO: no globals for that. + +void stop_daemons(bool stopall = true); +// uncomment if you want to have a "test" menue entry (rasc) + +#if HAVE_DVB_API_VERSION >= 3 +//#define __EXPERIMENTAL_CODE__ +#endif + +#ifdef __EXPERIMENTAL_CODE__ +#include "gui/ch_mosaic.h" +#endif + +#include "gui/audio_select.h" + +CAPIDChangeExec * APIDChanger; +CAudioSetupNotifier * audioSetupNotifier; +CBouquetList * bouquetList; // current list + +CBouquetList * TVbouquetList; +CBouquetList * TVsatList; +CBouquetList * TVfavList; +CBouquetList * TVallList; + +CBouquetList * RADIObouquetList; +CBouquetList * RADIOsatList; +CBouquetList * RADIOfavList; +CBouquetList * RADIOallList; + +CPlugins * g_PluginList; +CRemoteControl * g_RemoteControl; +SMSKeyInput * c_SMSKeyInput; +CMoviePlayerGui* moviePlayerGui; +CAudioSelectMenuHandler *audio_menu; +CPictureViewer * g_PicViewer; +CCAMMenuHandler * g_CamHandler; + +//int g_ChannelMode = LIST_MODE_PROV; + +// Globale Variablen - to use import global.h + +// I don't like globals, I would have hidden them in classes, +// but if you wanna do it so... ;) +bool parentallocked = false; +//static bool waitforshutdown = false; +static char **global_argv; + +//static CTimingSettingsNotifier timingsettingsnotifier; +CFontSizeNotifier fontsizenotifier; +CFanControlNotifier * funNotifier; + +extern const char * locale_real_names[]; /* #include */ +// USERMENU +const char* usermenu_button_def[SNeutrinoSettings::BUTTON_MAX]={"red","green","yellow","blue"}; + +CZapitClient::SatelliteList satList; + +CVCRControl::CDevice * recordingdevice = NULL; + +#if 0 +#define NEUTRINO_SETTINGS_FILE CONFIGDIR "/neutrino.conf" + +#define NEUTRINO_RECORDING_TIMER_SCRIPT CONFIGDIR "/recording.timer" +#define NEUTRINO_RECORDING_START_SCRIPT CONFIGDIR "/recording.start" +#define NEUTRINO_RECORDING_ENDED_SCRIPT CONFIGDIR "/recording.end" +#define NEUTRINO_ENTER_STANDBY_SCRIPT CONFIGDIR "/standby.on" +#define NEUTRINO_LEAVE_STANDBY_SCRIPT CONFIGDIR "/standby.off" + +#define NEUTRINO_SCAN_SETTINGS_FILE CONFIGDIR "/scan.conf" +#define NEUTRINO_PARENTALLOCKED_FILE DATADIR "/neutrino/.plocked" +#define NEUTRINO_SCAN_START_SCRIPT CONFIGDIR "/recording.start" +#endif + +int safe_mkdir(char * path) +{ + struct statfs s; + int ret = 0; + if(!strncmp(path, "/hdd", 4)) { + ret = statfs("/hdd", &s); + if((ret != 0) || (s.f_type == 0x72b6)) + ret = -1; + else + mkdir(path, 0755); + } else + mkdir(path, 0755); + return ret; +} + +static int check_dir(const char * newdir) +{ + if(strncmp(newdir, "/media/sda1/", 12) && strncmp(newdir, "/media/sdb1/", 12) && strncmp(newdir, "/mnt/", 5) && strncmp(newdir, "/tmp/", 5) && strncmp(newdir, "/media/", 7)) { + return 1; + } + + return 0; +} + +static void initGlobals(void) +{ + g_fontRenderer = NULL; + + g_RCInput = NULL; + //g_Controld = new CControldClient; + g_Timerd = NULL; + //g_Zapit = new CZapitClient; + g_RemoteControl = NULL; + + g_EpgData = NULL; + g_InfoViewer = NULL; + g_EventList = NULL; + + g_Locale = new CLocaleManager; + g_PluginList = NULL; + InfoClock = NULL; + g_CamHandler = NULL; +} + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ CNeutrinoApp - Constructor, initialize g_fontRenderer + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +CNeutrinoApp::CNeutrinoApp() +: configfile('\t') +{ + standby_pressed_at.tv_sec = 0; + + frameBuffer = CFrameBuffer::getInstance(); + frameBuffer->setIconBasePath(DATADIR "/neutrino/icons/"); + + SetupFrameBuffer(); + + mode = mode_unknown; + channelList = NULL; + TVchannelList = NULL; + RADIOchannelList = NULL; + nextRecordingInfo = NULL; + skipShutdownTimer=false; + current_muted = 0; +} + +/*------------------------------------------------------------------------------------- +- CNeutrinoApp - Destructor - +-------------------------------------------------------------------------------------*/ +CNeutrinoApp::~CNeutrinoApp() +{ + if (channelList) + delete channelList; +} + +CNeutrinoApp* CNeutrinoApp::getInstance() +{ + static CNeutrinoApp* neutrinoApp = NULL; + + if(!neutrinoApp) { + neutrinoApp = new CNeutrinoApp(); + dprintf(DEBUG_DEBUG, "NeutrinoApp Instance created\n"); + } + return neutrinoApp; +} + + +/************************************************************************************** +* CNeutrinoApp - setup Color Sheme (Neutrino) * +**************************************************************************************/ +void CNeutrinoApp::setupColors_neutrino() +{ + g_settings.menu_Head_alpha = 0x00; + g_settings.menu_Head_red = 0x00; + g_settings.menu_Head_green = 0x0A; + g_settings.menu_Head_blue = 0x19; + + g_settings.menu_Head_Text_alpha = 0x00; + g_settings.menu_Head_Text_red = 0x5f; + g_settings.menu_Head_Text_green = 0x46; + g_settings.menu_Head_Text_blue = 0x00; + + g_settings.menu_Content_alpha = 0x14; + g_settings.menu_Content_red = 0x00; + g_settings.menu_Content_green = 0x0f; + g_settings.menu_Content_blue = 0x23; + + g_settings.menu_Content_Text_alpha = 0x00; + g_settings.menu_Content_Text_red = 0x64; + g_settings.menu_Content_Text_green = 0x64; + g_settings.menu_Content_Text_blue = 0x64; + + g_settings.menu_Content_Selected_alpha = 0x14; + g_settings.menu_Content_Selected_red = 0x19; + g_settings.menu_Content_Selected_green = 0x37; + g_settings.menu_Content_Selected_blue = 0x64; + + g_settings.menu_Content_Selected_Text_alpha = 0x00; + g_settings.menu_Content_Selected_Text_red = 0x00; + g_settings.menu_Content_Selected_Text_green = 0x00; + g_settings.menu_Content_Selected_Text_blue = 0x00; + + g_settings.menu_Content_inactive_alpha = 0x14; + g_settings.menu_Content_inactive_red = 0x00; + g_settings.menu_Content_inactive_green = 0x0f; + g_settings.menu_Content_inactive_blue = 0x23; + + g_settings.menu_Content_inactive_Text_alpha = 0x00; + g_settings.menu_Content_inactive_Text_red = 55; + g_settings.menu_Content_inactive_Text_green = 70; + g_settings.menu_Content_inactive_Text_blue = 85; + + g_settings.infobar_alpha = 0x14; + g_settings.infobar_red = 0x00; + g_settings.infobar_green = 0x0e; + g_settings.infobar_blue = 0x23; + + g_settings.infobar_Text_alpha = 0x00; + g_settings.infobar_Text_red = 0x64; + g_settings.infobar_Text_green = 0x64; + g_settings.infobar_Text_blue = 0x64; +} + +/************************************************************************************** +* * +* CNeutrinoApp - setup Color Sheme (classic) * +* * +**************************************************************************************/ +void CNeutrinoApp::setupColors_classic() +{ + g_settings.menu_Head_alpha = 20; + g_settings.menu_Head_red = 5; + g_settings.menu_Head_green = 10; + g_settings.menu_Head_blue = 60; + + g_settings.menu_Head_Text_alpha = 0; + g_settings.menu_Head_Text_red = 100; + g_settings.menu_Head_Text_green = 100; + g_settings.menu_Head_Text_blue = 100; + + g_settings.menu_Content_alpha = 20; + g_settings.menu_Content_red = 50; + g_settings.menu_Content_green = 50; + g_settings.menu_Content_blue = 50; + + g_settings.menu_Content_Text_alpha = 0; + g_settings.menu_Content_Text_red = 100; + g_settings.menu_Content_Text_green = 100; + g_settings.menu_Content_Text_blue = 100; + + g_settings.menu_Content_Selected_alpha = 20; + g_settings.menu_Content_Selected_red = 5; + g_settings.menu_Content_Selected_green = 10; + g_settings.menu_Content_Selected_blue = 60; + + g_settings.menu_Content_Selected_Text_alpha = 0; + g_settings.menu_Content_Selected_Text_red = 100; + g_settings.menu_Content_Selected_Text_green = 100; + g_settings.menu_Content_Selected_Text_blue = 100; + + g_settings.menu_Content_inactive_alpha = 20; + g_settings.menu_Content_inactive_red = 50; + g_settings.menu_Content_inactive_green = 50; + g_settings.menu_Content_inactive_blue = 50; + + g_settings.menu_Content_inactive_Text_alpha = 0; + g_settings.menu_Content_inactive_Text_red = 80; + g_settings.menu_Content_inactive_Text_green = 80; + g_settings.menu_Content_inactive_Text_blue = 80; + + g_settings.infobar_alpha = 20; + g_settings.infobar_red = 5; + g_settings.infobar_green = 10; + g_settings.infobar_blue = 60; + + g_settings.infobar_Text_alpha = 0; + g_settings.infobar_Text_red = 100; + g_settings.infobar_Text_green = 100; + g_settings.infobar_Text_blue = 100; +} +void CNeutrinoApp::setupColors_ru() +{ + + g_settings.infobar_Text_alpha=0; + g_settings.infobar_Text_blue=100; + g_settings.infobar_Text_green=100; + g_settings.infobar_Text_red=100; + + g_settings.infobar_alpha=0; + g_settings.infobar_blue=40; + g_settings.infobar_green=29; + g_settings.infobar_red=25; + + g_settings.menu_Content_Selected_Text_alpha=0; + g_settings.menu_Content_Selected_Text_blue=0; + g_settings.menu_Content_Selected_Text_green=0; + g_settings.menu_Content_Selected_Text_red=0; + + g_settings.menu_Content_Selected_alpha=0; + g_settings.menu_Content_Selected_blue=70; + g_settings.menu_Content_Selected_green=65; + g_settings.menu_Content_Selected_red=65; + + g_settings.menu_Content_Text_alpha=0; + g_settings.menu_Content_Text_blue=100; + g_settings.menu_Content_Text_green=100; + g_settings.menu_Content_Text_red=100; + + g_settings.menu_Content_alpha=0; + g_settings.menu_Content_blue=40; + g_settings.menu_Content_green=30; + g_settings.menu_Content_red=25; +; + g_settings.menu_Content_inactive_Text_alpha=0; + g_settings.menu_Content_inactive_Text_blue=100; + g_settings.menu_Content_inactive_Text_green=100; + g_settings.menu_Content_inactive_Text_red=100; + + g_settings.menu_Content_inactive_alpha=0; + g_settings.menu_Content_inactive_blue=40; + g_settings.menu_Content_inactive_green=30; + g_settings.menu_Content_inactive_red=25; + + g_settings.menu_Head_Text_alpha=0; + g_settings.menu_Head_Text_blue=0; + g_settings.menu_Head_Text_green=70; + g_settings.menu_Head_Text_red=95; + + g_settings.menu_Head_alpha=0; + g_settings.menu_Head_blue=30; + g_settings.menu_Head_green=20; + g_settings.menu_Head_red=15; +} +void CNeutrinoApp::setupColors_red() +{ + g_settings.infobar_Text_alpha=0; + g_settings.infobar_Text_blue=100; + g_settings.infobar_Text_green=100; + g_settings.infobar_Text_red=100; + + g_settings.infobar_alpha=20; + g_settings.infobar_blue=0; + g_settings.infobar_green=14; + g_settings.infobar_red=40; + + g_settings.menu_Content_Selected_Text_alpha=0; + g_settings.menu_Content_Selected_Text_blue=0; + g_settings.menu_Content_Selected_Text_green=0; + g_settings.menu_Content_Selected_Text_red=0; + + g_settings.menu_Content_Selected_alpha=20; + g_settings.menu_Content_Selected_blue=100; + g_settings.menu_Content_Selected_green=100; + g_settings.menu_Content_Selected_red=100; + + g_settings.menu_Content_Text_alpha=0; + g_settings.menu_Content_Text_blue=100; + g_settings.menu_Content_Text_green=100; + g_settings.menu_Content_Text_red=100; + + g_settings.menu_Content_inactive_Text_alpha=0; + g_settings.menu_Content_inactive_Text_blue=35; + g_settings.menu_Content_inactive_Text_green=85; + g_settings.menu_Content_inactive_Text_red=85; + + g_settings.menu_Content_inactive_alpha=20; + g_settings.menu_Content_inactive_blue=0; + g_settings.menu_Content_inactive_green=15; + g_settings.menu_Content_inactive_red=35; + + g_settings.menu_Content_alpha=20; + g_settings.menu_Content_blue=0; + g_settings.menu_Content_green=15; + g_settings.menu_Content_red=40; + + g_settings.menu_Head_Text_alpha=0; + g_settings.menu_Head_Text_blue=0; + g_settings.menu_Head_Text_green=70; + g_settings.menu_Head_Text_red=95; + + g_settings.menu_Head_alpha=0; + g_settings.menu_Head_blue=0; + g_settings.menu_Head_green=10; + g_settings.menu_Head_red=40; +} + +/************************************************************************************** +* * +* CNeutrinoApp - setup Color Sheme (darkblue) * +* * +**************************************************************************************/ +void CNeutrinoApp::setupColors_dblue() +{ + g_settings.menu_Head_alpha = 0; + g_settings.menu_Head_red = 0; + g_settings.menu_Head_green = 0; + g_settings.menu_Head_blue = 50; + + g_settings.menu_Head_Text_alpha = 0; + g_settings.menu_Head_Text_red = 95; + g_settings.menu_Head_Text_green = 100; + g_settings.menu_Head_Text_blue = 100; + + g_settings.menu_Content_alpha = 20; + g_settings.menu_Content_red = 0; + g_settings.menu_Content_green = 0; + g_settings.menu_Content_blue = 20; + + g_settings.menu_Content_Text_alpha = 0; + g_settings.menu_Content_Text_red = 100; + g_settings.menu_Content_Text_green = 100; + g_settings.menu_Content_Text_blue = 100; + + g_settings.menu_Content_Selected_alpha = 15; + g_settings.menu_Content_Selected_red = 0; + g_settings.menu_Content_Selected_green = 65; + g_settings.menu_Content_Selected_blue = 0; + + g_settings.menu_Content_Selected_Text_alpha = 0; + g_settings.menu_Content_Selected_Text_red = 0; + g_settings.menu_Content_Selected_Text_green = 0; + g_settings.menu_Content_Selected_Text_blue = 0; + + g_settings.menu_Content_inactive_alpha = 20; + g_settings.menu_Content_inactive_red = 0; + g_settings.menu_Content_inactive_green = 0; + g_settings.menu_Content_inactive_blue = 15; + + g_settings.menu_Content_inactive_Text_alpha = 0; + g_settings.menu_Content_inactive_Text_red = 55; + g_settings.menu_Content_inactive_Text_green = 70; + g_settings.menu_Content_inactive_Text_blue = 85; + + g_settings.infobar_alpha = 20; + g_settings.infobar_red = 0; + g_settings.infobar_green = 0; + g_settings.infobar_blue = 20; + + g_settings.infobar_Text_alpha = 0; + g_settings.infobar_Text_red = 100; + g_settings.infobar_Text_green = 100; + g_settings.infobar_Text_blue = 100; +} + +/************************************************************************************** +* * +* CNeutrinoApp - setup Color Sheme (dvb2000) * +* * +**************************************************************************************/ +void CNeutrinoApp::setupColors_dvb2k() +{ + g_settings.menu_Head_alpha = 0; + g_settings.menu_Head_red = 25; + g_settings.menu_Head_green = 25; + g_settings.menu_Head_blue = 25; + + g_settings.menu_Head_Text_alpha = 0; + g_settings.menu_Head_Text_red = 100; + g_settings.menu_Head_Text_green = 100; + g_settings.menu_Head_Text_blue = 0; + + g_settings.menu_Content_alpha = 0; + g_settings.menu_Content_red = 0; + g_settings.menu_Content_green = 20; + g_settings.menu_Content_blue = 0; + + g_settings.menu_Content_Text_alpha = 0; + g_settings.menu_Content_Text_red = 100; + g_settings.menu_Content_Text_green = 100; + g_settings.menu_Content_Text_blue = 100; + + g_settings.menu_Content_Selected_alpha = 0; + g_settings.menu_Content_Selected_red = 100; + g_settings.menu_Content_Selected_green = 100; + g_settings.menu_Content_Selected_blue = 100; + + g_settings.menu_Content_Selected_Text_alpha = 0; + g_settings.menu_Content_Selected_Text_red = 0; + g_settings.menu_Content_Selected_Text_green = 0; + g_settings.menu_Content_Selected_Text_blue = 0; + + g_settings.menu_Content_inactive_alpha = 20; + g_settings.menu_Content_inactive_red = 0; + g_settings.menu_Content_inactive_green = 25; + g_settings.menu_Content_inactive_blue = 0; + + g_settings.menu_Content_inactive_Text_alpha = 0; + g_settings.menu_Content_inactive_Text_red = 100; + g_settings.menu_Content_inactive_Text_green = 100; + g_settings.menu_Content_inactive_Text_blue = 0; + + g_settings.infobar_alpha = 5; + g_settings.infobar_red = 0; + g_settings.infobar_green = 19; + g_settings.infobar_blue = 0; + + g_settings.infobar_Text_alpha = 0; + g_settings.infobar_Text_red = 100; + g_settings.infobar_Text_green = 100; + g_settings.infobar_Text_blue = 100; +} + +#define FONT_STYLE_REGULAR 0 +#define FONT_STYLE_BOLD 1 +#define FONT_STYLE_ITALIC 2 + +extern font_sizes_groups_struct font_sizes_groups[]; +extern font_sizes_struct neutrino_font[]; + +const font_sizes_struct signal_font = {LOCALE_FONTSIZE_INFOBAR_SMALL , 14, FONT_STYLE_REGULAR, 1}; + +typedef struct lcd_setting_t +{ + const char * const name; + const unsigned int default_value; +} lcd_setting_struct_t; + +const lcd_setting_struct_t lcd_setting[LCD_SETTING_COUNT] = +{ + {"lcd_brightness" , DEFAULT_VFD_BRIGHTNESS }, + {"lcd_standbybrightness", DEFAULT_VFD_STANDBYBRIGHTNESS}, + {"lcd_contrast" , DEFAULT_LCD_CONTRAST }, + {"lcd_power" , DEFAULT_LCD_POWER }, + {"lcd_inverse" , DEFAULT_LCD_INVERSE }, + {"lcd_show_volume" , DEFAULT_LCD_SHOW_VOLUME }, + {"lcd_autodimm" , DEFAULT_LCD_AUTODIMM } +}; + +/************************************************************************************** +* CNeutrinoApp - loadSetup, load the application-settings * +**************************************************************************************/ +int CNeutrinoApp::loadSetup(const char * fname) +{ + char cfg_key[81]; + int erg = 0; + + configfile.clear(); + //settings laden - und dabei Defaults setzen! + if(!configfile.loadConfig(fname)) { + //file existiert nicht + erg = 1; + } + std::ifstream checkParentallocked(NEUTRINO_PARENTALLOCKED_FILE); + if(checkParentallocked) { + parentallocked = true; + checkParentallocked.close(); + } + //video + g_settings.video_Mode = configfile.getInt32("video_Mode", 7); // default 720p/50HZ + prev_video_mode = g_settings.video_Mode; + g_settings.analog_mode1 = configfile.getInt32("analog_mode1", 0); // default RGB + g_settings.analog_mode2 = configfile.getInt32("analog_mode2", 0); // default RGB + + g_settings.video_Format = configfile.getInt32("video_Format", 3); + g_settings.video_43mode = configfile.getInt32("video_43mode", 0); + g_settings.current_volume = configfile.getInt32("current_volume", 100); + g_settings.channel_mode = configfile.getInt32("channel_mode", LIST_MODE_PROV); + g_settings.video_csync = configfile.getInt32( "video_csync", 0 ); + + g_settings.fan_speed = configfile.getInt32( "fan_speed", 1); + if(g_settings.fan_speed < 1) g_settings.fan_speed = 1;//FIXME disable OFF + + g_settings.srs_enable = configfile.getInt32( "srs_enable", 0); + g_settings.srs_algo = configfile.getInt32( "srs_algo", 1); + g_settings.srs_ref_volume = configfile.getInt32( "srs_ref_volume", 40);//FIXME + g_settings.srs_nmgr_enable = configfile.getInt32( "srs_nmgr_enable", 0); + g_settings.hdmi_dd = configfile.getInt32( "hdmi_dd", 0); + g_settings.spdif_dd = configfile.getInt32( "spdif_dd", 1); + g_settings.avsync = configfile.getInt32( "avsync", 1); + g_settings.clockrec = configfile.getInt32( "clockrec", 1); + g_settings.video_dbdr = configfile.getInt32("video_dbdr", 2); + + for(int i = 0; i < VIDEOMENU_VIDEOMODE_OPTION_COUNT; i++) { + sprintf(cfg_key, "enabled_video_mode_%d", i); + g_settings.enabled_video_modes[i] = configfile.getInt32(cfg_key, 1); + } + g_settings.cpufreq = configfile.getInt32("cpufreq", 0); + g_settings.standby_cpufreq = configfile.getInt32("standby_cpufreq", 100); + g_settings.rounded_corners = 1; //FIXME +//FIXME + g_settings.cpufreq = 0; + g_settings.standby_cpufreq = 50; + + g_settings.make_hd_list = configfile.getInt32("make_hd_list", 1); + //fb-alphawerte für gtx + g_settings.gtx_alpha1 = configfile.getInt32( "gtx_alpha1", 255); + g_settings.gtx_alpha2 = configfile.getInt32( "gtx_alpha2", 1); + + //misc + g_settings.power_standby = configfile.getInt32( "power_standby", 0); + g_settings.rotor_swap = configfile.getInt32( "rotor_swap", 0); + g_settings.emlog = configfile.getInt32( "emlog", 0); + + g_settings.hdd_fs = configfile.getInt32( "hdd_fs", 0); + g_settings.hdd_sleep = configfile.getInt32( "hdd_sleep", 120); + g_settings.hdd_noise = configfile.getInt32( "hdd_noise", 254); + g_settings.shutdown_real = configfile.getBool("shutdown_real" , false ); + g_settings.shutdown_real_rcdelay = configfile.getBool("shutdown_real_rcdelay", false ); + strcpy(g_settings.shutdown_count, configfile.getString("shutdown_count","0").c_str()); + g_settings.infobar_sat_display = configfile.getBool("infobar_sat_display" , true ); + g_settings.infobar_subchan_disp_pos = configfile.getInt32("infobar_subchan_disp_pos" , 0 ); + + //audio + g_settings.audio_AnalogMode = configfile.getInt32( "audio_AnalogMode", 0 ); + g_settings.audio_DolbyDigital = configfile.getBool("audio_DolbyDigital" , false); + + g_settings.audio_avs_Control = false; + g_settings.audio_english = configfile.getInt32( "audio_english", 0 ); + g_settings.zap_cycle = configfile.getInt32( "zap_cycle", 1 ); + g_settings.sms_channel = configfile.getInt32( "sms_channel", 0 ); + strcpy( g_settings.audio_PCMOffset, configfile.getString( "audio_PCMOffset", "0" ).c_str() ); + + //vcr + g_settings.vcr_AutoSwitch = configfile.getBool("vcr_AutoSwitch" , true ); + + //language + strcpy(g_settings.language, configfile.getString("language", "").c_str()); + strcpy(g_settings.timezone, configfile.getString("timezone", "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Vienna").c_str()); + //epg dir + g_settings.epg_cache = configfile.getString("epg_cache_time", "14"); + g_settings.epg_extendedcache = configfile.getString("epg_extendedcache_time", "360"); + g_settings.epg_old_events = configfile.getString("epg_old_events", "1"); + g_settings.epg_max_events = configfile.getString("epg_max_events", "30000"); + g_settings.epg_dir = configfile.getString("epg_dir", "/media/sda1/epg"); + // NTP-Server for sectionsd + g_settings.network_ntpserver = configfile.getString("network_ntpserver", "time.fu-berlin.de"); + g_settings.network_ntprefresh = configfile.getString("network_ntprefresh", "30" ); + g_settings.network_ntpenable = configfile.getBool("network_ntpenable", false); + + g_settings.epg_save = configfile.getBool("epg_save", false); + + //widget settings + //FIXME not work yet g_settings.widget_fade = configfile.getBool("widget_fade" , false ); + g_settings.widget_fade = false; + + //colors (neutrino defaultcolors) + g_settings.menu_Head_alpha = configfile.getInt32( "menu_Head_alpha", 0x00 ); + g_settings.menu_Head_red = configfile.getInt32( "menu_Head_red", 0x00 ); + g_settings.menu_Head_green = configfile.getInt32( "menu_Head_green", 0x0A ); + g_settings.menu_Head_blue = configfile.getInt32( "menu_Head_blue", 0x19 ); + + g_settings.menu_Head_Text_alpha = configfile.getInt32( "menu_Head_Text_alpha", 0x00 ); + g_settings.menu_Head_Text_red = configfile.getInt32( "menu_Head_Text_red", 0x5f ); + g_settings.menu_Head_Text_green = configfile.getInt32( "menu_Head_Text_green", 0x46 ); + g_settings.menu_Head_Text_blue = configfile.getInt32( "menu_Head_Text_blue", 0x00 ); + + g_settings.menu_Content_alpha = configfile.getInt32( "menu_Content_alpha", 0x14 ); + g_settings.menu_Content_red = configfile.getInt32( "menu_Content_red", 0x00 ); + g_settings.menu_Content_green = configfile.getInt32( "menu_Content_green", 0x0f ); + g_settings.menu_Content_blue = configfile.getInt32( "menu_Content_blue", 0x23 ); + g_settings.menu_Content_Text_alpha = configfile.getInt32( "menu_Content_Text_alpha", 0x00 ); + g_settings.menu_Content_Text_red = configfile.getInt32( "menu_Content_Text_red", 0x64 ); + g_settings.menu_Content_Text_green = configfile.getInt32( "menu_Content_Text_green", 0x64 ); + g_settings.menu_Content_Text_blue = configfile.getInt32( "menu_Content_Text_blue", 0x64 ); + + g_settings.menu_Content_Selected_alpha = configfile.getInt32( "menu_Content_Selected_alpha", 0x14 ); + g_settings.menu_Content_Selected_red = configfile.getInt32( "menu_Content_Selected_red", 0x19 ); + g_settings.menu_Content_Selected_green = configfile.getInt32( "menu_Content_Selected_green", 0x37 ); + g_settings.menu_Content_Selected_blue = configfile.getInt32( "menu_Content_Selected_blue", 0x64 ); + + g_settings.menu_Content_Selected_Text_alpha = configfile.getInt32( "menu_Content_Selected_Text_alpha", 0x00 ); + g_settings.menu_Content_Selected_Text_red = configfile.getInt32( "menu_Content_Selected_Text_red", 0x00 ); + g_settings.menu_Content_Selected_Text_green = configfile.getInt32( "menu_Content_Selected_Text_green", 0x00 ); + g_settings.menu_Content_Selected_Text_blue = configfile.getInt32( "menu_Content_Selected_Text_blue", 0x00 ); + + g_settings.menu_Content_inactive_alpha = configfile.getInt32( "menu_Content_inactive_alpha", 0x14 ); + g_settings.menu_Content_inactive_red = configfile.getInt32( "menu_Content_inactive_red", 0x00 ); + g_settings.menu_Content_inactive_green = configfile.getInt32( "menu_Content_inactive_green", 0x0f ); + g_settings.menu_Content_inactive_blue = configfile.getInt32( "menu_Content_inactive_blue", 0x23 ); + + g_settings.menu_Content_inactive_Text_alpha = configfile.getInt32( "menu_Content_inactive_Text_alpha", 0x00 ); + g_settings.menu_Content_inactive_Text_red = configfile.getInt32( "menu_Content_inactive_Text_red", 55 ); + g_settings.menu_Content_inactive_Text_green = configfile.getInt32( "menu_Content_inactive_Text_green", 70 ); + g_settings.menu_Content_inactive_Text_blue = configfile.getInt32( "menu_Content_inactive_Text_blue", 85 ); + + g_settings.infobar_alpha = configfile.getInt32( "infobar_alpha", 0x14 ); + g_settings.infobar_red = configfile.getInt32( "infobar_red", 0x00 ); + g_settings.infobar_green = configfile.getInt32( "infobar_green", 0x0e ); + g_settings.infobar_blue = configfile.getInt32( "infobar_blue", 0x23 ); + + g_settings.infobar_Text_alpha = configfile.getInt32( "infobar_Text_alpha", 0x00 ); + g_settings.infobar_Text_red = configfile.getInt32( "infobar_Text_red", 0x64 ); + g_settings.infobar_Text_green = configfile.getInt32( "infobar_Text_green", 0x64 ); + g_settings.infobar_Text_blue = configfile.getInt32( "infobar_Text_blue", 0x64 ); + + //network + for(int i=0 ; i < NETWORK_NFS_NR_OF_ENTRIES ; i++) { + sprintf(cfg_key, "network_nfs_ip_%d", i); + g_settings.network_nfs_ip[i] = configfile.getString(cfg_key, ""); + sprintf(cfg_key, "network_nfs_dir_%d", i); + strcpy( g_settings.network_nfs_dir[i], configfile.getString( cfg_key, "" ).c_str() ); + sprintf(cfg_key, "network_nfs_local_dir_%d", i); + strcpy( g_settings.network_nfs_local_dir[i], configfile.getString( cfg_key, "" ).c_str() ); + sprintf(cfg_key, "network_nfs_automount_%d", i); + g_settings.network_nfs_automount[i] = configfile.getInt32( cfg_key, 0); + sprintf(cfg_key, "network_nfs_type_%d", i); + g_settings.network_nfs_type[i] = configfile.getInt32( cfg_key, 0); + sprintf(cfg_key,"network_nfs_username_%d", i); + strcpy( g_settings.network_nfs_username[i], configfile.getString( cfg_key, "" ).c_str() ); + sprintf(cfg_key, "network_nfs_password_%d", i); + strcpy( g_settings.network_nfs_password[i], configfile.getString( cfg_key, "" ).c_str() ); + sprintf(cfg_key, "network_nfs_mount_options1_%d", i); + strcpy( g_settings.network_nfs_mount_options1[i], configfile.getString( cfg_key, "ro,soft,udp" ).c_str() ); + sprintf(cfg_key, "network_nfs_mount_options2_%d", i); + strcpy( g_settings.network_nfs_mount_options2[i], configfile.getString( cfg_key, "nolock,rsize=8192,wsize=8192" ).c_str() ); + sprintf(cfg_key, "network_nfs_mac_%d", i); + strcpy( g_settings.network_nfs_mac[i], configfile.getString( cfg_key, "11:22:33:44:55:66").c_str() ); + } + strcpy( g_settings.network_nfs_audioplayerdir, configfile.getString( "network_nfs_audioplayerdir", "/media/sda1/music" ).c_str() ); + strcpy( g_settings.network_nfs_picturedir, configfile.getString( "network_nfs_picturedir", "/media/sda1/pictures" ).c_str() ); + strcpy( g_settings.network_nfs_moviedir, configfile.getString( "network_nfs_moviedir", "/media/sda1/movies" ).c_str() ); + strcpy( g_settings.network_nfs_recordingdir, configfile.getString( "network_nfs_recordingdir", "/media/sda1/movies" ).c_str() ); + strcpy( g_settings.timeshiftdir, configfile.getString( "timeshiftdir", "" ).c_str() ); + + g_settings.temp_timeshift = configfile.getInt32( "temp_timeshift", 0 ); + g_settings.auto_timeshift = configfile.getInt32( "auto_timeshift", 0 ); + g_settings.auto_delete = configfile.getInt32( "auto_delete", 1 ); + + if(strlen(g_settings.timeshiftdir) == 0) { + sprintf(timeshiftDir, "%s/.timeshift", g_settings.network_nfs_recordingdir); + safe_mkdir(timeshiftDir); + } else { + if(strcmp(g_settings.timeshiftdir, g_settings.network_nfs_recordingdir)) + strncpy(timeshiftDir, g_settings.timeshiftdir, sizeof(timeshiftDir)); + else + sprintf(timeshiftDir, "%s/.timeshift", g_settings.network_nfs_recordingdir); + } +printf("***************************** rec dir %s timeshift dir %s\n", g_settings.network_nfs_recordingdir, timeshiftDir); + + if(g_settings.auto_delete) { + if(strcmp(g_settings.timeshiftdir, g_settings.network_nfs_recordingdir)) { + char buf[512]; + sprintf(buf, "rm -f %s/*_temp.ts %s/*_temp.xml &", timeshiftDir, timeshiftDir); + system(buf); + } + } + g_settings.record_hours = configfile.getInt32( "record_hours", 4 ); + g_settings.filesystem_is_utf8 = configfile.getBool("filesystem_is_utf8" , true ); + + //recording (server + vcr) + g_settings.recording_type = configfile.getInt32("recording_type", RECORDING_FILE); + g_settings.recording_stopplayback = configfile.getBool("recording_stopplayback" , false); + g_settings.recording_stopsectionsd = configfile.getBool("recording_stopsectionsd" , true ); + g_settings.recording_server_ip = configfile.getString("recording_server_ip", "127.0.0.1"); + strcpy( g_settings.recording_server_port, configfile.getString( "recording_server_port", "4000").c_str() ); + g_settings.recording_server_wakeup = configfile.getInt32( "recording_server_wakeup", 0 ); + strcpy( g_settings.recording_server_mac, configfile.getString( "recording_server_mac", "11:22:33:44:55:66").c_str() ); + g_settings.recording_vcr_no_scart = configfile.getInt32( "recording_vcr_no_scart", false); + strcpy( g_settings.recording_splitsize, configfile.getString( "recording_splitsize", "2048").c_str() ); + g_settings.recording_use_o_sync = configfile.getBool("recordingmenu.use_o_sync" , false); + g_settings.recording_use_fdatasync = configfile.getBool("recordingmenu.use_fdatasync" , false); + g_settings.recording_audio_pids_default = configfile.getInt32("recording_audio_pids_default", TIMERD_APIDS_STD | TIMERD_APIDS_AC3); + g_settings.recording_zap_on_announce = configfile.getBool("recording_zap_on_announce" , false); + + g_settings.recording_stream_vtxt_pid = configfile.getBool("recordingmenu.stream_vtxt_pid" , false); + g_settings.recording_stream_pmt_pid = configfile.getBool("recordingmenu.stream_pmt_pid" , false); + strcpy( g_settings.recording_ringbuffers, configfile.getString( "recordingmenu.ringbuffers", "20").c_str() ); + g_settings.recording_choose_direct_rec_dir = configfile.getInt32( "recording_choose_direct_rec_dir", 0 ); + g_settings.recording_epg_for_filename = configfile.getBool("recording_epg_for_filename" , true); + g_settings.recording_save_in_channeldir = configfile.getBool("recording_save_in_channeldir" , false); + g_settings.recording_in_spts_mode = true; + //streaming (server) + g_settings.streaming_type = configfile.getInt32( "streaming_type", 0 ); + g_settings.streaming_server_ip = configfile.getString("streaming_server_ip", "10.10.10.10"); + strcpy( g_settings.streaming_server_port, configfile.getString( "streaming_server_port", "8080").c_str() ); + strcpy( g_settings.streaming_server_cddrive, configfile.getString("streaming_server_cddrive", "D:").c_str() ); + strcpy( g_settings.streaming_videorate, configfile.getString("streaming_videorate", "1000").c_str() ); + strcpy( g_settings.streaming_audiorate, configfile.getString("streaming_audiorate", "192").c_str() ); + strcpy( g_settings.streaming_server_startdir, configfile.getString("streaming_server_startdir", "C:/Movies").c_str() ); + g_settings.streaming_transcode_audio = configfile.getInt32( "streaming_transcode_audio", 0 ); + g_settings.streaming_force_transcode_video = configfile.getInt32( "streaming_force_transcode_video", 0 ); + g_settings.streaming_transcode_video_codec = configfile.getInt32( "streaming_transcode_video_codec", 0 ); + g_settings.streaming_force_avi_rawaudio = configfile.getInt32( "streaming_force_avi_rawaudio", 0 ); + g_settings.streaming_resolution = configfile.getInt32( "streaming_resolution", 0 ); + + // default plugin for movieplayer + g_settings.movieplayer_plugin = configfile.getString( "movieplayer_plugin", "Teletext" ); + g_settings.onekey_plugin = configfile.getString( "onekey_plugin", "noplugin" ); + + //rc-key configuration + g_settings.key_tvradio_mode = configfile.getInt32( "key_tvradio_mode", CRCInput::RC_nokey ); + + g_settings.key_channelList_pageup = configfile.getInt32( "key_channelList_pageup", CRCInput::RC_page_up ); + g_settings.key_channelList_pagedown = configfile.getInt32( "key_channelList_pagedown", CRCInput::RC_page_down ); + g_settings.key_channelList_cancel = configfile.getInt32( "key_channelList_cancel", CRCInput::RC_home ); + g_settings.key_channelList_sort = configfile.getInt32( "key_channelList_sort", CRCInput::RC_blue ); + g_settings.key_channelList_addrecord = configfile.getInt32( "key_channelList_addrecord", CRCInput::RC_nokey ); + g_settings.key_channelList_addremind = configfile.getInt32( "key_channelList_addremind", CRCInput::RC_nokey ); + + g_settings.key_list_start = configfile.getInt32( "key_list_start", CRCInput::RC_nokey ); + g_settings.key_list_end = configfile.getInt32( "key_list_end", CRCInput::RC_nokey ); + g_settings.menu_left_exit = configfile.getInt32( "menu_left_exit", 0 ); + + g_settings.audio_run_player = configfile.getInt32( "audio_run_player", 1 ); + g_settings.key_click = configfile.getInt32( "key_click", 1 ); + g_settings.timeshift_pause = configfile.getInt32( "timeshift_pause", 1 ); + g_settings.mpkey_rewind = configfile.getInt32( "mpkey.rewind", CRCInput::RC_rewind ); + g_settings.mpkey_forward = configfile.getInt32( "mpkey.forward", CRCInput::RC_forward ); + g_settings.mpkey_pause = configfile.getInt32( "mpkey.pause", CRCInput::RC_pause ); + g_settings.mpkey_stop = configfile.getInt32( "mpkey.stop", CRCInput::RC_stop ); + g_settings.mpkey_play = configfile.getInt32( "mpkey.play", CRCInput::RC_play ); + g_settings.mpkey_audio = configfile.getInt32( "mpkey.audio", CRCInput::RC_green ); + g_settings.mpkey_time = configfile.getInt32( "mpkey.time", CRCInput::RC_setup ); + g_settings.mpkey_bookmark = configfile.getInt32( "mpkey.bookmark", CRCInput::RC_blue ); + g_settings.mpkey_plugin = configfile.getInt32( "mpkey.plugin", CRCInput::RC_red ); + g_settings.key_timeshift = configfile.getInt32( "key_timeshift", CRCInput::RC_pause ); + g_settings.key_plugin = configfile.getInt32( "key_plugin", CRCInput::RC_nokey ); + g_settings.key_unlock = configfile.getInt32( "key_unlock", CRCInput::RC_setup ); +//printf("get: key_unlock =============== %d\n", g_settings.key_unlock); + +//rfmod + g_settings.rf_subcarrier = configfile.getInt32( "rf_subcarrier", 1); + g_settings.rf_soundenable = configfile.getInt32( "rf_soundenable", 0); + g_settings.rf_channel = configfile.getInt32( "rf_channel", 36); + g_settings.rf_finetune = configfile.getInt32( "rf_finetune", 0); + g_settings.rf_standby = configfile.getInt32( "rf_standby", 0); + + g_settings.key_quickzap_up = configfile.getInt32( "key_quickzap_up", CRCInput::RC_up ); + g_settings.key_quickzap_down = configfile.getInt32( "key_quickzap_down", CRCInput::RC_down ); + g_settings.key_subchannel_up = configfile.getInt32( "key_subchannel_up", CRCInput::RC_right ); + g_settings.key_subchannel_down = configfile.getInt32( "key_subchannel_down", CRCInput::RC_left ); + g_settings.key_zaphistory = configfile.getInt32( "key_zaphistory", CRCInput::RC_home ); + g_settings.key_lastchannel = configfile.getInt32( "key_lastchannel", CRCInput::RC_0 ); + g_settings.cacheTXT = configfile.getInt32( "cacheTXT", 0); + g_settings.minimode = configfile.getInt32( "minimode", 0); + g_settings.mode_clock = configfile.getInt32( "mode_clock", 0); + g_settings.virtual_zap_mode = configfile.getBool("virtual_zap_mode" , false); + g_settings.spectrum = configfile.getBool("spectrum" , false); + g_settings.channellist_epgtext_align_right = configfile.getBool("channellist_epgtext_align_right" , false); + g_settings.channellist_extended = configfile.getBool("channellist_extended" , true); + //screen configuration + g_settings.screen_StartX = configfile.getInt32( "screen_StartX", 37 ); + g_settings.screen_StartY = configfile.getInt32( "screen_StartY", 23 ); + g_settings.screen_EndX = configfile.getInt32( "screen_EndX", 668 ); + g_settings.screen_EndY = configfile.getInt32( "screen_EndY", 555 ); + g_settings.screen_width = configfile.getInt32("screen_width", 0); + g_settings.screen_height = configfile.getInt32("screen_height", 0); + + g_settings.bigFonts = configfile.getInt32("bigFonts", 0); + + strcpy(g_settings.repeat_blocker, configfile.getString("repeat_blocker", "150").c_str()); + strcpy(g_settings.repeat_genericblocker, configfile.getString("repeat_genericblocker", "100").c_str()); + g_settings.key_bouquet_up = configfile.getInt32( "key_bouquet_up", CRCInput::RC_right); + g_settings.key_bouquet_down = configfile.getInt32( "key_bouquet_down", CRCInput::RC_left); + g_settings.audiochannel_up_down_enable = configfile.getBool("audiochannel_up_down_enable", false); + + //Software-update + g_settings.softupdate_mode = configfile.getInt32( "softupdate_mode", 1 ); + + strcpy(g_settings.softupdate_url_file, configfile.getString("softupdate_url_file", "/var/etc/update.urls").c_str()); + strcpy(g_settings.softupdate_proxyserver, configfile.getString("softupdate_proxyserver", "" ).c_str()); + strcpy(g_settings.softupdate_proxyusername, configfile.getString("softupdate_proxyusername", "" ).c_str()); + strcpy(g_settings.softupdate_proxypassword, configfile.getString("softupdate_proxypassword", "" ).c_str()); +// + strcpy( g_settings.font_file, configfile.getString( "font_file", FONTDIR"/neutrino.ttf" ).c_str() ); + strcpy( g_settings.update_dir, configfile.getString( "update_dir", "/tmp" ).c_str() ); + //BouquetHandling + g_settings.bouquetlist_mode = configfile.getInt32( "bouquetlist_mode", 0 ); + + // parentallock + if (!parentallocked) { + g_settings.parentallock_prompt = configfile.getInt32( "parentallock_prompt", 0 ); + g_settings.parentallock_lockage = configfile.getInt32( "parentallock_lockage", 12 ); + } else { + g_settings.parentallock_prompt = 3; + g_settings.parentallock_lockage = 18; + } + strcpy( g_settings.parentallock_pincode, configfile.getString( "parentallock_pincode", "0000" ).c_str() ); + + for (int i = 0; i < TIMING_SETTING_COUNT; i++) + g_settings.timing[i] = configfile.getInt32(locale_real_names[timing_setting_name[i]], default_timing[i]); + + for (int i = 0; i < LCD_SETTING_COUNT; i++) + g_settings.lcd_setting[i] = configfile.getInt32(lcd_setting[i].name, lcd_setting[i].default_value); + strcpy(g_settings.lcd_setting_dim_time, configfile.getString("lcd_dim_time","0").c_str()); + strcpy(g_settings.lcd_setting_dim_brightness, configfile.getString("lcd_dim_brightness","0").c_str()); + + //Picture-Viewer + strcpy( g_settings.picviewer_slide_time, configfile.getString( "picviewer_slide_time", "10" ).c_str() ); + g_settings.picviewer_scaling = configfile.getInt32("picviewer_scaling", 1 /*(int)CPictureViewer::SIMPLE*/); + g_settings.picviewer_decode_server_ip = configfile.getString("picviewer_decode_server_ip", ""); + + //Audio-Player + g_settings.audioplayer_display = configfile.getInt32("audioplayer_display",(int)CAudioPlayerGui::ARTIST_TITLE); + g_settings.audioplayer_follow = configfile.getInt32("audioplayer_follow",0); + strcpy( g_settings.audioplayer_screensaver, configfile.getString( "audioplayer_screensaver", "1" ).c_str() ); + g_settings.audioplayer_highprio = configfile.getInt32("audioplayer_highprio",0); + g_settings.audioplayer_select_title_by_name = configfile.getInt32("audioplayer_select_title_by_name",0); + g_settings.audioplayer_repeat_on = configfile.getInt32("audioplayer_repeat_on",0); + g_settings.audioplayer_show_playlist = configfile.getInt32("audioplayer_show_playlist",1); + g_settings.audioplayer_enable_sc_metadata = configfile.getInt32("audioplayer_enable_sc_metadata",1); + + //Filebrowser + g_settings.filebrowser_showrights = configfile.getInt32("filebrowser_showrights", 1); + g_settings.filebrowser_sortmethod = configfile.getInt32("filebrowser_sortmethod", 0); + if ((g_settings.filebrowser_sortmethod < 0) || (g_settings.filebrowser_sortmethod >= FILEBROWSER_NUMBER_OF_SORT_VARIANTS)) + g_settings.filebrowser_sortmethod = 0; + g_settings.filebrowser_denydirectoryleave = configfile.getBool("filebrowser_denydirectoryleave", false); + + // USERMENU -> in system/settings.h + //------------------------------------------- + // this is as the current neutrino usermen + const char* usermenu_default[SNeutrinoSettings::BUTTON_MAX]={ + "2,3,4,13", // RED + "6", // GREEN + "7", // YELLOW + "12,10,11,14,15" // BLUE + }; + char txt1[81]; + std::string txt2; + const char* txt2ptr; + for(int button = 0; button < SNeutrinoSettings::BUTTON_MAX; button++) + { + snprintf(txt1,80,"usermenu_tv_%s_text",usermenu_button_def[button]); + txt1[80] = 0; // terminate for sure + g_settings.usermenu_text[button] = configfile.getString(txt1, "" ); + + snprintf(txt1,80,"usermenu_tv_%s",usermenu_button_def[button]); + txt2 = configfile.getString(txt1,usermenu_default[button]); + txt2ptr = txt2.c_str(); + for( int pos = 0; pos < SNeutrinoSettings::ITEM_MAX; pos++) + { + // find next comma or end of string - if it's not the first round + if(pos != 0) + { + while(*txt2ptr != 0 && *txt2ptr != ',') + txt2ptr++; + if(*txt2ptr != 0) + txt2ptr++; + } + if(*txt2ptr != 0) + { + g_settings.usermenu[button][pos] = atoi(txt2ptr); // there is still a string + if(g_settings.usermenu[button][pos] >= SNeutrinoSettings::ITEM_MAX) + g_settings.usermenu[button][pos] = 0; + } + else + g_settings.usermenu[button][pos] = 0; // string empty, fill up with 0 + + } + } + + if(configfile.getUnknownKeyQueryedFlag() && (erg==0)) { + erg = 2; + } + +#if 0 + // uboot config file + if(fromflash) { + g_settings.uboot_console = 0; + g_settings.uboot_lcd_inverse = -1; + g_settings.uboot_lcd_contrast = -1; + + FILE* fd = fopen("/var/tuxbox/boot/boot.conf", "r"); + if(fd) { + char buffer[100]; + + while(fgets(buffer, 99, fd) != NULL) { + if(strncmp(buffer,"console=",8) == 0) { + if(strncmp(&buffer[8], "null", 4)==0) + g_settings.uboot_console = 0; + else if(strncmp(&buffer[8], "ttyS0", 5)==0) + g_settings.uboot_console = 1; + else if(strncmp(&buffer[8], "ttyCPM0", 5)==0) + g_settings.uboot_console = 1; + else if(strncmp(&buffer[8], "tty", 3)==0) + g_settings.uboot_console = 2; + } + else if(strncmp(buffer,"lcd_inverse=", 12) == 0) { + g_settings.uboot_lcd_inverse = atoi(&buffer[12]); + } + else if(strncmp(buffer,"lcd_contrast=", 13) == 0) { + g_settings.uboot_lcd_contrast = atoi(&buffer[13]); + } + else + printf("unknown entry found in boot.conf\n"); + } + + fclose(fd); + } + g_settings.uboot_console_bak = g_settings.uboot_console; + } +#endif +#define DEFAULT_X_OFF 85 +#define DEFAULT_Y_OFF 34 + if((g_settings.screen_width != (int) frameBuffer->getScreenWidth(true)) + || (g_settings.screen_height != (int) frameBuffer->getScreenHeight(true))) { + g_settings.screen_StartX = DEFAULT_X_OFF; + g_settings.screen_StartY = DEFAULT_Y_OFF; + g_settings.screen_EndX = frameBuffer->getScreenWidth(true) - DEFAULT_X_OFF; + g_settings.screen_EndY = frameBuffer->getScreenHeight(true) - DEFAULT_Y_OFF; + g_settings.screen_width = frameBuffer->getScreenWidth(true); + g_settings.screen_height = frameBuffer->getScreenHeight(true); + } + if(erg) + configfile.setModifiedFlag(true); + return erg; +} + +/************************************************************************************** +* CNeutrinoApp - saveSetup, save the application-settings * +**************************************************************************************/ +void CNeutrinoApp::saveSetup(const char * fname) +{ + char cfg_key[81]; + //uboot; write config only on changes +#if 0 + if (fromflash && + ((g_settings.uboot_console_bak != g_settings.uboot_console) || + (g_settings.uboot_lcd_inverse != g_settings.lcd_setting[SNeutrinoSettings::LCD_INVERSE]) || + (g_settings.uboot_lcd_contrast != g_settings.lcd_setting[SNeutrinoSettings::LCD_CONTRAST]))) + { + bool newkernel = 0; + FILE* fd = fopen("/proc/version", "r"); + if(fd != NULL) { + char buf[128]; + fgets(buf, 127, fd); + fclose(fd); + if(strstr(buf, "version 2.6")) + newkernel = 1; +//printf("new: %d kernel:: %s\n", newkernel, buf); + } + fd = fopen("/var/tuxbox/boot/boot.conf", "w"); + + if(fd != NULL) { + const char * buffer; + g_settings.uboot_console_bak = g_settings.uboot_console; + g_settings.uboot_lcd_inverse = g_settings.lcd_setting[SNeutrinoSettings::LCD_INVERSE]; + g_settings.uboot_lcd_contrast = g_settings.lcd_setting[SNeutrinoSettings::LCD_CONTRAST]; + + switch(g_settings.uboot_console) { + case 1: + buffer = newkernel ? "ttyCPM0" : "ttyS0"; + break; + case 2: + buffer = "tty"; + break; + default: + buffer = "null"; + break; + } + fprintf(fd, "console=%s\n" "lcd_inverse=%d\n" "lcd_contrast=%d\n", buffer, g_settings.uboot_lcd_inverse, g_settings.uboot_lcd_contrast); + fclose(fd); + } else { + dprintf(DEBUG_NORMAL, "unable to write file /var/tuxbox/boot/boot.conf\n"); + } + } +#endif + //scan settings + if(!scanSettings.saveSettings(NEUTRINO_SCAN_SETTINGS_FILE)) { + dprintf(DEBUG_NORMAL, "error while saving scan-settings!\n"); + } + + //video + configfile.setInt32( "video_Mode", g_settings.video_Mode ); + configfile.setInt32( "analog_mode1", g_settings.analog_mode1 ); + configfile.setInt32( "analog_mode2", g_settings.analog_mode2 ); + configfile.setInt32( "video_Format", g_settings.video_Format ); + configfile.setInt32( "video_43mode", g_settings.video_43mode ); + configfile.setInt32( "current_volume", g_settings.current_volume ); + configfile.setInt32( "channel_mode", g_settings.channel_mode ); + configfile.setInt32( "video_csync", g_settings.video_csync ); + + configfile.setInt32( "fan_speed", g_settings.fan_speed); + + configfile.setInt32( "srs_enable", g_settings.srs_enable); + configfile.setInt32( "srs_algo", g_settings.srs_algo); + configfile.setInt32( "srs_ref_volume", g_settings.srs_ref_volume); + configfile.setInt32( "srs_nmgr_enable", g_settings.srs_nmgr_enable); + configfile.setInt32( "hdmi_dd", g_settings.hdmi_dd); + configfile.setInt32( "spdif_dd", g_settings.spdif_dd); + configfile.setInt32( "avsync", g_settings.avsync); + configfile.setInt32( "clockrec", g_settings.clockrec); + configfile.setInt32( "video_dbdr", g_settings.video_dbdr); + for(int i = 0; i < VIDEOMENU_VIDEOMODE_OPTION_COUNT; i++) { + sprintf(cfg_key, "enabled_video_mode_%d", i); + configfile.setInt32(cfg_key, g_settings.enabled_video_modes[i]); + } + configfile.setInt32( "cpufreq", g_settings.cpufreq); + configfile.setInt32( "standby_cpufreq", g_settings.standby_cpufreq); + + configfile.setInt32( "make_hd_list", g_settings.make_hd_list); + //fb-alphawerte für gtx + configfile.setInt32( "gtx_alpha1", g_settings.gtx_alpha1 ); + configfile.setInt32( "gtx_alpha2", g_settings.gtx_alpha2 ); + + //misc + configfile.setInt32( "power_standby", g_settings.power_standby); + configfile.setInt32( "rotor_swap", g_settings.rotor_swap); + configfile.setInt32( "emlog", g_settings.emlog); + configfile.setInt32( "zap_cycle", g_settings.zap_cycle ); + configfile.setInt32( "sms_channel", g_settings.sms_channel ); + configfile.setInt32( "hdd_fs", g_settings.hdd_fs); + configfile.setInt32( "hdd_sleep", g_settings.hdd_sleep); + configfile.setInt32( "hdd_noise", g_settings.hdd_noise); + configfile.setBool("shutdown_real" , g_settings.shutdown_real ); + configfile.setBool("shutdown_real_rcdelay", g_settings.shutdown_real_rcdelay); + configfile.setString("shutdown_count" , g_settings.shutdown_count); + configfile.setBool("infobar_sat_display" , g_settings.infobar_sat_display ); + configfile.setInt32("infobar_subchan_disp_pos" , g_settings.infobar_subchan_disp_pos ); + + //audio + configfile.setInt32( "audio_AnalogMode", g_settings.audio_AnalogMode ); + configfile.setBool("audio_DolbyDigital" , g_settings.audio_DolbyDigital ); + configfile.setInt32( "audio_avs_Control", g_settings.audio_avs_Control ); + configfile.setInt32( "audio_english", g_settings.audio_english ); + configfile.setString( "audio_PCMOffset", g_settings.audio_PCMOffset ); + + //vcr + configfile.setBool("vcr_AutoSwitch" , g_settings.vcr_AutoSwitch ); + + //language + configfile.setString("language", g_settings.language); + configfile.setString("timezone", g_settings.timezone); + // epg + configfile.setBool("epg_save", g_settings.epg_save); + configfile.setString("epg_cache_time" ,g_settings.epg_cache ); + configfile.setString("epg_extendedcache_time" ,g_settings.epg_extendedcache); + configfile.setString("epg_old_events" ,g_settings.epg_old_events ); + configfile.setString("epg_max_events" ,g_settings.epg_max_events ); + configfile.setString("epg_dir" ,g_settings.epg_dir); + + // NTP-Server for sectionsd + configfile.setString( "network_ntpserver", g_settings.network_ntpserver); + configfile.setString( "network_ntprefresh", g_settings.network_ntprefresh); + configfile.setBool( "network_ntpenable", g_settings.network_ntpenable); + + //widget settings + configfile.setBool("widget_fade" , g_settings.widget_fade ); + + //colors + configfile.setInt32( "menu_Head_alpha", g_settings.menu_Head_alpha ); + configfile.setInt32( "menu_Head_red", g_settings.menu_Head_red ); + configfile.setInt32( "menu_Head_green", g_settings.menu_Head_green ); + configfile.setInt32( "menu_Head_blue", g_settings.menu_Head_blue ); + + configfile.setInt32( "menu_Head_Text_alpha", g_settings.menu_Head_Text_alpha ); + configfile.setInt32( "menu_Head_Text_red", g_settings.menu_Head_Text_red ); + configfile.setInt32( "menu_Head_Text_green", g_settings.menu_Head_Text_green ); + configfile.setInt32( "menu_Head_Text_blue", g_settings.menu_Head_Text_blue ); + + configfile.setInt32( "menu_Content_alpha", g_settings.menu_Content_alpha ); + configfile.setInt32( "menu_Content_red", g_settings.menu_Content_red ); + configfile.setInt32( "menu_Content_green", g_settings.menu_Content_green ); + configfile.setInt32( "menu_Content_blue", g_settings.menu_Content_blue ); + + configfile.setInt32( "menu_Content_Text_alpha", g_settings.menu_Content_Text_alpha ); + configfile.setInt32( "menu_Content_Text_red", g_settings.menu_Content_Text_red ); + configfile.setInt32( "menu_Content_Text_green", g_settings.menu_Content_Text_green ); + configfile.setInt32( "menu_Content_Text_blue", g_settings.menu_Content_Text_blue ); + + configfile.setInt32( "menu_Content_Selected_alpha", g_settings.menu_Content_Selected_alpha ); + configfile.setInt32( "menu_Content_Selected_red", g_settings.menu_Content_Selected_red ); + configfile.setInt32( "menu_Content_Selected_green", g_settings.menu_Content_Selected_green ); + configfile.setInt32( "menu_Content_Selected_blue", g_settings.menu_Content_Selected_blue ); + + configfile.setInt32( "menu_Content_Selected_Text_alpha", g_settings.menu_Content_Selected_Text_alpha ); + configfile.setInt32( "menu_Content_Selected_Text_red", g_settings.menu_Content_Selected_Text_red ); + configfile.setInt32( "menu_Content_Selected_Text_green", g_settings.menu_Content_Selected_Text_green ); + configfile.setInt32( "menu_Content_Selected_Text_blue", g_settings.menu_Content_Selected_Text_blue ); + + configfile.setInt32( "menu_Content_inactive_alpha", g_settings.menu_Content_inactive_alpha ); + configfile.setInt32( "menu_Content_inactive_red", g_settings.menu_Content_inactive_red ); + configfile.setInt32( "menu_Content_inactive_green", g_settings.menu_Content_inactive_green ); + configfile.setInt32( "menu_Content_inactive_blue", g_settings.menu_Content_inactive_blue ); + + configfile.setInt32( "menu_Content_inactive_Text_alpha", g_settings.menu_Content_inactive_Text_alpha ); + configfile.setInt32( "menu_Content_inactive_Text_red", g_settings.menu_Content_inactive_Text_red ); + configfile.setInt32( "menu_Content_inactive_Text_green", g_settings.menu_Content_inactive_Text_green ); + configfile.setInt32( "menu_Content_inactive_Text_blue", g_settings.menu_Content_inactive_Text_blue ); + + configfile.setInt32( "infobar_alpha", g_settings.infobar_alpha ); + configfile.setInt32( "infobar_red", g_settings.infobar_red ); + configfile.setInt32( "infobar_green", g_settings.infobar_green ); + configfile.setInt32( "infobar_blue", g_settings.infobar_blue ); + + configfile.setInt32( "infobar_Text_alpha", g_settings.infobar_Text_alpha ); + configfile.setInt32( "infobar_Text_red", g_settings.infobar_Text_red ); + configfile.setInt32( "infobar_Text_green", g_settings.infobar_Text_green ); + configfile.setInt32( "infobar_Text_blue", g_settings.infobar_Text_blue ); + + //network + for(int i=0 ; i < NETWORK_NFS_NR_OF_ENTRIES ; i++) { + sprintf(cfg_key, "network_nfs_ip_%d", i); + configfile.setString( cfg_key, g_settings.network_nfs_ip[i] ); + sprintf(cfg_key, "network_nfs_dir_%d", i); + configfile.setString( cfg_key, g_settings.network_nfs_dir[i] ); + sprintf(cfg_key, "network_nfs_local_dir_%d", i); + configfile.setString( cfg_key, g_settings.network_nfs_local_dir[i] ); + sprintf(cfg_key, "network_nfs_automount_%d", i); + configfile.setInt32( cfg_key, g_settings.network_nfs_automount[i]); + sprintf(cfg_key, "network_nfs_type_%d", i); + configfile.setInt32( cfg_key, g_settings.network_nfs_type[i]); + sprintf(cfg_key,"network_nfs_username_%d", i); + configfile.setString( cfg_key, g_settings.network_nfs_username[i] ); + sprintf(cfg_key, "network_nfs_password_%d", i); + configfile.setString( cfg_key, g_settings.network_nfs_password[i] ); + sprintf(cfg_key, "network_nfs_mount_options1_%d", i); + configfile.setString( cfg_key, g_settings.network_nfs_mount_options1[i]); + sprintf(cfg_key, "network_nfs_mount_options2_%d", i); + configfile.setString( cfg_key, g_settings.network_nfs_mount_options2[i]); + sprintf(cfg_key, "network_nfs_mac_%d", i); + configfile.setString( cfg_key, g_settings.network_nfs_mac[i]); + } + configfile.setString( "network_nfs_audioplayerdir", g_settings.network_nfs_audioplayerdir); + configfile.setString( "network_nfs_picturedir", g_settings.network_nfs_picturedir); + configfile.setString( "network_nfs_moviedir", g_settings.network_nfs_moviedir); + configfile.setString( "network_nfs_recordingdir", g_settings.network_nfs_recordingdir); + configfile.setString( "timeshiftdir", g_settings.timeshiftdir); + configfile.setBool ("filesystem_is_utf8" , g_settings.filesystem_is_utf8 ); + + //recording (server + vcr) + configfile.setInt32 ("recording_type", g_settings.recording_type); + configfile.setBool ("recording_stopplayback" , g_settings.recording_stopplayback ); + configfile.setBool ("recording_stopsectionsd" , g_settings.recording_stopsectionsd ); + configfile.setString("recording_server_ip", g_settings.recording_server_ip); + configfile.setString("recording_server_port", g_settings.recording_server_port); + configfile.setInt32 ("recording_server_wakeup", g_settings.recording_server_wakeup); + configfile.setString("recording_server_mac", g_settings.recording_server_mac); + configfile.setInt32 ("recording_vcr_no_scart", g_settings.recording_vcr_no_scart); + configfile.setString("recording_splitsize", g_settings.recording_splitsize); + configfile.setBool ("recordingmenu.use_o_sync" , g_settings.recording_use_o_sync ); + configfile.setBool ("recordingmenu.use_fdatasync" , g_settings.recording_use_fdatasync ); + + configfile.setInt32 ("recording_audio_pids_default" , g_settings.recording_audio_pids_default); + configfile.setBool ("recording_zap_on_announce" , g_settings.recording_zap_on_announce ); + + configfile.setBool ("recordingmenu.stream_vtxt_pid" , g_settings.recording_stream_vtxt_pid ); + configfile.setBool ("recordingmenu.stream_pmt_pid" , g_settings.recording_stream_pmt_pid ); + configfile.setString("recordingmenu.ringbuffers" , g_settings.recording_ringbuffers); + configfile.setInt32 ("recording_choose_direct_rec_dir" , g_settings.recording_choose_direct_rec_dir); + configfile.setBool ("recording_epg_for_filename" , g_settings.recording_epg_for_filename ); + configfile.setBool ("recording_save_in_channeldir" , g_settings.recording_save_in_channeldir ); + configfile.setBool ("recording_in_spts_mode" , g_settings.recording_in_spts_mode ); + + //streaming + configfile.setInt32 ( "streaming_type", g_settings.streaming_type ); + configfile.setString( "streaming_server_ip", g_settings.streaming_server_ip ); + configfile.setString( "streaming_server_port", g_settings.streaming_server_port ); + configfile.setString( "streaming_server_cddrive", g_settings.streaming_server_cddrive ); + configfile.setString ( "streaming_videorate", g_settings.streaming_videorate ); + configfile.setString ( "streaming_audiorate", g_settings.streaming_audiorate ); + configfile.setString( "streaming_server_startdir", g_settings.streaming_server_startdir ); + configfile.setInt32 ( "streaming_transcode_audio", g_settings.streaming_transcode_audio ); + configfile.setInt32 ( "streaming_force_avi_rawaudio", g_settings.streaming_force_avi_rawaudio ); + configfile.setInt32 ( "streaming_force_transcode_video", g_settings.streaming_force_transcode_video ); + configfile.setInt32 ( "streaming_transcode_video_codec", g_settings.streaming_transcode_video_codec ); + configfile.setInt32 ( "streaming_resolution", g_settings.streaming_resolution ); + + // default plugin for movieplayer + configfile.setString ( "movieplayer_plugin", g_settings.movieplayer_plugin ); + configfile.setString ( "onekey_plugin", g_settings.onekey_plugin ); + + configfile.setInt32 ( "streaming_resolution", g_settings.streaming_resolution ); + + configfile.setInt32( "rf_subcarrier", g_settings.rf_subcarrier); + configfile.setInt32( "rf_soundenable", g_settings.rf_soundenable); + configfile.setInt32( "rf_channel", g_settings.rf_channel); + configfile.setInt32( "rf_finetune", g_settings.rf_finetune); + configfile.setInt32( "rf_standby", g_settings.rf_standby); + + //rc-key configuration + configfile.setInt32( "key_tvradio_mode", g_settings.key_tvradio_mode ); + + configfile.setInt32( "key_channelList_pageup", g_settings.key_channelList_pageup ); + configfile.setInt32( "key_channelList_pagedown", g_settings.key_channelList_pagedown ); + configfile.setInt32( "key_channelList_cancel", g_settings.key_channelList_cancel ); + configfile.setInt32( "key_channelList_sort", g_settings.key_channelList_sort ); + configfile.setInt32( "key_channelList_addrecord", g_settings.key_channelList_addrecord ); + configfile.setInt32( "key_channelList_addremind", g_settings.key_channelList_addremind ); + + configfile.setInt32( "key_quickzap_up", g_settings.key_quickzap_up ); + configfile.setInt32( "key_quickzap_down", g_settings.key_quickzap_down ); + configfile.setInt32( "key_bouquet_up", g_settings.key_bouquet_up ); + configfile.setInt32( "key_bouquet_down", g_settings.key_bouquet_down ); + configfile.setInt32( "key_subchannel_up", g_settings.key_subchannel_up ); + configfile.setInt32( "key_subchannel_down", g_settings.key_subchannel_down ); + configfile.setInt32( "key_zaphistory", g_settings.key_zaphistory ); + configfile.setInt32( "key_lastchannel", g_settings.key_lastchannel ); + + configfile.setInt32( "key_list_start", g_settings.key_list_start ); + configfile.setInt32( "key_list_end", g_settings.key_list_end ); + configfile.setInt32( "menu_left_exit", g_settings.menu_left_exit ); + configfile.setInt32( "audio_run_player", g_settings.audio_run_player ); + configfile.setInt32( "key_click", g_settings.key_click ); + configfile.setInt32( "timeshift_pause", g_settings.timeshift_pause ); + configfile.setInt32( "temp_timeshift", g_settings.temp_timeshift ); + configfile.setInt32( "auto_timeshift", g_settings.auto_timeshift ); + configfile.setInt32( "auto_delete", g_settings.auto_delete ); + configfile.setInt32( "record_hours", g_settings.record_hours ); + configfile.setInt32( "mpkey.rewind", g_settings.mpkey_rewind ); + configfile.setInt32( "mpkey.forward", g_settings.mpkey_forward ); + configfile.setInt32( "mpkey.pause", g_settings.mpkey_pause ); + configfile.setInt32( "mpkey.stop", g_settings.mpkey_stop ); + configfile.setInt32( "mpkey.play", g_settings.mpkey_play ); + configfile.setInt32( "mpkey.audio", g_settings.mpkey_audio ); + configfile.setInt32( "mpkey.time", g_settings.mpkey_time ); + configfile.setInt32( "mpkey.bookmark", g_settings.mpkey_bookmark ); + configfile.setInt32( "mpkey.plugin", g_settings.mpkey_plugin ); + configfile.setInt32( "key_timeshift", g_settings.key_timeshift ); + configfile.setInt32( "key_plugin", g_settings.key_plugin ); + configfile.setInt32( "key_unlock", g_settings.key_unlock ); +//printf("set: key_unlock =============== %d\n", g_settings.key_unlock); + configfile.setInt32( "cacheTXT", g_settings.cacheTXT ); + configfile.setInt32( "minimode", g_settings.minimode ); + configfile.setInt32( "mode_clock", g_settings.mode_clock ); + configfile.setBool("virtual_zap_mode", g_settings.virtual_zap_mode); + configfile.setBool("spectrum", g_settings.spectrum); + configfile.setBool("channellist_epgtext_align_right", g_settings.channellist_epgtext_align_right); + configfile.setBool("channellist_extended" , g_settings.channellist_extended); + configfile.setString( "repeat_blocker", g_settings.repeat_blocker ); + configfile.setString( "repeat_genericblocker", g_settings.repeat_genericblocker ); + configfile.setBool ( "audiochannel_up_down_enable", g_settings.audiochannel_up_down_enable ); + + //screen configuration + configfile.setInt32( "screen_StartX", g_settings.screen_StartX ); + configfile.setInt32( "screen_StartY", g_settings.screen_StartY ); + configfile.setInt32( "screen_EndX", g_settings.screen_EndX ); + configfile.setInt32( "screen_EndY", g_settings.screen_EndY ); + configfile.setInt32( "screen_width", g_settings.screen_width); + configfile.setInt32( "screen_height", g_settings.screen_height); + + //Software-update + configfile.setInt32 ("softupdate_mode" , g_settings.softupdate_mode ); + configfile.setString("softupdate_url_file" , g_settings.softupdate_url_file ); +#if 1 //FIXME why was commented ?? + configfile.setString("softupdate_proxyserver" , g_settings.softupdate_proxyserver ); + configfile.setString("softupdate_proxyusername" , g_settings.softupdate_proxyusername ); + configfile.setString("softupdate_proxypassword" , g_settings.softupdate_proxypassword ); +#endif + configfile.setString("update_dir", g_settings.update_dir); + configfile.setString("font_file", g_settings.font_file); + //BouquetHandling + configfile.setInt32( "bouquetlist_mode", g_settings.bouquetlist_mode ); + + //parentallock + configfile.setInt32( "parentallock_prompt", g_settings.parentallock_prompt ); + configfile.setInt32( "parentallock_lockage", g_settings.parentallock_lockage ); + configfile.setString( "parentallock_pincode", g_settings.parentallock_pincode ); + + //timing + for (int i = 0; i < TIMING_SETTING_COUNT; i++) + configfile.setInt32(locale_real_names[timing_setting_name[i]], g_settings.timing[i]); + + for (int i = 0; i < LCD_SETTING_COUNT; i++) + configfile.setInt32(lcd_setting[i].name, g_settings.lcd_setting[i]); + configfile.setString("lcd_dim_time", g_settings.lcd_setting_dim_time); + configfile.setString("lcd_dim_brightness", g_settings.lcd_setting_dim_brightness); + + //Picture-Viewer + configfile.setString( "picviewer_slide_time", g_settings.picviewer_slide_time ); + configfile.setInt32( "picviewer_scaling", g_settings.picviewer_scaling ); + configfile.setString( "picviewer_decode_server_ip", g_settings.picviewer_decode_server_ip ); + configfile.setString( "picviewer_decode_server_port", g_settings.picviewer_decode_server_port); + + //Audio-Player + configfile.setInt32( "audioplayer_display", g_settings.audioplayer_display ); + configfile.setInt32( "audioplayer_follow", g_settings.audioplayer_follow ); + configfile.setString( "audioplayer_screensaver", g_settings.audioplayer_screensaver ); + configfile.setInt32( "audioplayer_highprio", g_settings.audioplayer_highprio ); + configfile.setInt32( "audioplayer_select_title_by_name", g_settings.audioplayer_select_title_by_name ); + configfile.setInt32( "audioplayer_repeat_on", g_settings.audioplayer_repeat_on ); + configfile.setInt32( "audioplayer_show_playlist", g_settings.audioplayer_show_playlist ); + configfile.setInt32( "audioplayer_enable_sc_metadata", g_settings.audioplayer_enable_sc_metadata ); + + //Filebrowser + configfile.setInt32("filebrowser_showrights", g_settings.filebrowser_showrights); + configfile.setInt32("filebrowser_sortmethod", g_settings.filebrowser_sortmethod); + configfile.setBool("filebrowser_denydirectoryleave", g_settings.filebrowser_denydirectoryleave); + + // USERMENU + //--------------------------------------- + char txt1[81]; + char txt2[81]; + for(int button = 0; button < SNeutrinoSettings::BUTTON_MAX; button++) { + snprintf(txt1,80,"usermenu_tv_%s_text",usermenu_button_def[button]); + txt1[80] = 0; // terminate for sure + configfile.setString(txt1,g_settings.usermenu_text[button]); + + char* txt2ptr = txt2; + snprintf(txt1,80,"usermenu_tv_%s",usermenu_button_def[button]); + for(int pos = 0; pos < SNeutrinoSettings::ITEM_MAX; pos++) { + if( g_settings.usermenu[button][pos] != 0) { + if(pos != 0) + *txt2ptr++ = ','; + txt2ptr += snprintf(txt2ptr,80,"%d",g_settings.usermenu[button][pos]); + } + } + configfile.setString(txt1,txt2); + } + + configfile.setInt32("bigFonts", g_settings.bigFonts); +#if 0 + configfile.setInt32("pip_x", g_settings.pip_x); + configfile.setInt32("pip_y", g_settings.pip_y); + configfile.setInt32("pip_width", g_settings.pip_width); + configfile.setInt32("pip_height", g_settings.pip_height); +#endif + if(strcmp(fname, NEUTRINO_SETTINGS_FILE)) + configfile.saveConfig(fname); + + else if (configfile.getModifiedFlag()) + { + configfile.saveConfig(fname); + configfile.setModifiedFlag(false); + } +} + +/************************************************************************************** +* CNeutrinoApp - firstChannel, get the initial channel * +**************************************************************************************/ +void CNeutrinoApp::firstChannel() +{ + g_Zapit->getLastChannel(firstchannel.channelNumber, firstchannel.mode); +} + +/************************************************************************************** +* CNeutrinoApp - channelsInit, get the Channellist from daemon * +**************************************************************************************/ +#include +#include + +#define TIMER_START() \ + struct timeval tv, tv2; \ + unsigned int msec; \ + gettimeofday(&tv, NULL) + +#define TIMER_STOP(label) \ + gettimeofday(&tv2, NULL); \ + msec = ((tv2.tv_sec - tv.tv_sec) * 1000) + ((tv2.tv_usec - tv.tv_usec) / 1000); \ + printf("%s: %u msec\n", label, msec) + +extern tallchans allchans; +extern CBouquetManager *g_bouquetManager; + +void CNeutrinoApp::channelsInit(bool bOnly) +{ + printf("[neutrino] Creating channels lists...\n"); + TIMER_START(); + +#if 1 + if(!reloadhintBox) + reloadhintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_SERVICEMENU_RELOAD_HINT)); + reloadhintBox->paint(); +#endif + + const char * fav_bouquetname = g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME); + if(g_bouquetManager->existsUBouquet(fav_bouquetname, true) == -1) + g_bouquetManager->addBouquet(fav_bouquetname, true, true); + + if(TVallList) delete TVallList; + if(RADIOallList) delete RADIOallList; + if(TVbouquetList) delete TVbouquetList; + if(TVsatList) delete TVsatList; + if(TVfavList) delete TVfavList; + if(RADIObouquetList) delete RADIObouquetList; + if(RADIOsatList) delete RADIOsatList; + if(RADIOfavList) delete RADIOfavList; + + if(TVchannelList) delete TVchannelList; + if(RADIOchannelList) delete RADIOchannelList; + + TVchannelList = new CChannelList(g_Locale->getText(LOCALE_CHANNELLIST_HEAD)); + RADIOchannelList = new CChannelList(g_Locale->getText(LOCALE_CHANNELLIST_HEAD)); + + TVbouquetList = new CBouquetList(g_Locale->getText(LOCALE_CHANNELLIST_PROVS)); + TVbouquetList->orgChannelList = TVchannelList; + TVsatList = new CBouquetList(g_Locale->getText(LOCALE_CHANNELLIST_SATS)); + TVsatList->orgChannelList = TVchannelList; + TVfavList = new CBouquetList(g_Locale->getText(LOCALE_CHANNELLIST_FAVS)); + TVfavList->orgChannelList = TVchannelList; + + RADIObouquetList = new CBouquetList(g_Locale->getText(LOCALE_CHANNELLIST_PROVS)); + RADIObouquetList->orgChannelList = RADIOchannelList; + RADIOsatList = new CBouquetList(g_Locale->getText(LOCALE_CHANNELLIST_SATS)); + RADIOsatList->orgChannelList = RADIOchannelList; + RADIOfavList = new CBouquetList(g_Locale->getText(LOCALE_CHANNELLIST_FAVS)); + RADIOfavList->orgChannelList = RADIOchannelList; + + uint32_t i; + i = 1; + + //CBouquet* tmp = TVfavList->addBouquet("HD");//FIXME locale + CBouquet* hdBouquet; + if(g_settings.make_hd_list) + hdBouquet = new CBouquet(0, (char *) "HD", 0); + + int tvi = 0, ri = 0, hi = 0; + for (tallchans_iterator it = allchans.begin(); it != allchans.end(); it++) { + if (it->second.getServiceType() == ST_DIGITAL_TELEVISION_SERVICE) { + TVchannelList->putChannel(&(it->second)); + tvi++; +#if 1 + if(g_settings.make_hd_list) + if(it->second.isHD()) { + //printf("HD channel: %d %s sid %x\n", it->second.getSatellitePosition(), it->second.getName().c_str(), it->second.getServiceId()); + hdBouquet->channelList->addChannel(&(it->second)); + hi++; + } +#endif + } + else if (it->second.getServiceType() == ST_DIGITAL_RADIO_SOUND_SERVICE) { + RADIOchannelList->putChannel(&(it->second)); + ri++; + } + } + if(hi) + hdBouquet->channelList->SortSat(); + + printf("[neutrino] got %d TV (%d is HD) and %d RADIO channels\n", tvi, hi, ri); fflush(stdout); + + CBouquet* tmp; + + TVallList = new CBouquetList(g_Locale->getText(LOCALE_CHANNELLIST_HEAD)); + tmp = TVallList->addBouquet(g_Locale->getText(LOCALE_CHANNELLIST_HEAD)); + *(tmp->channelList) = *TVchannelList; + tmp->channelList->SortAlpha(); + TVallList->orgChannelList = TVchannelList; + + RADIOallList = new CBouquetList(g_Locale->getText(LOCALE_CHANNELLIST_HEAD)); + tmp = RADIOallList->addBouquet(g_Locale->getText(LOCALE_CHANNELLIST_HEAD)); + *(tmp->channelList) = *RADIOchannelList; + tmp->channelList->SortAlpha(); + RADIOallList->orgChannelList = RADIOchannelList; + + int bnum; + sat_iterator_t sit; + for(sit = satellitePositions.begin(); sit != satellitePositions.end(); sit++) { + tvi = 0, ri = 0; + CBouquet* tmp1 = TVsatList->addBouquet(sit->second.name.c_str()); + CBouquet* tmp2 = RADIOsatList->addBouquet(sit->second.name.c_str()); + + for (tallchans_iterator it = allchans.begin(); it != allchans.end(); it++) { + if(it->second.getSatellitePosition() == sit->first) { + if (it->second.getServiceType() == ST_DIGITAL_TELEVISION_SERVICE) { + tmp1->channelList->addChannel(&(it->second)); + tvi++; + } + else if (it->second.getServiceType() == ST_DIGITAL_RADIO_SOUND_SERVICE) { + tmp2->channelList->addChannel(&(it->second)); + ri++; + } + } + } + if(tvi) + tmp1->channelList->SortAlpha(); + else + TVsatList->deleteBouquet(tmp1); + if(ri) + tmp2->channelList->SortAlpha(); + else + RADIOsatList->deleteBouquet(tmp2); + if(tvi || ri) + printf("[neutrino] created %s bouquet with %d TV and %d RADIO channels\n", sit->second.name.c_str(), tvi, ri); + } + + bnum = 0; + for (i = 0; i < g_bouquetManager->Bouquets.size(); i++) { + //if (!g_bouquetManager->Bouquets[i]->bHidden && (g_bouquetManager->Bouquets[i]->bUser || !g_bouquetManager->Bouquets[i]->tvChannels.empty() )) + if (!g_bouquetManager->Bouquets[i]->bHidden && !g_bouquetManager->Bouquets[i]->tvChannels.empty()) + { + CBouquet* tmp; + if(g_bouquetManager->Bouquets[i]->bUser) + tmp = TVfavList->addBouquet(g_bouquetManager->Bouquets[i]); + else + tmp = TVbouquetList->addBouquet(g_bouquetManager->Bouquets[i]); + + ZapitChannelList* channels = &(g_bouquetManager->Bouquets[i]->tvChannels); + tmp->channelList->setSize(channels->size()); + for(int j = 0; j < (int) channels->size(); j++) { + tmp->channelList->addChannel((*channels)[j]); + } + bnum++; + } + } + printf("[neutrino] got %d TV bouquets\n", bnum); fflush(stdout); + + if(g_settings.make_hd_list) + TVfavList->Bouquets.push_back(hdBouquet); + + bnum = 0; + for (i = 0; i < g_bouquetManager->Bouquets.size(); i++) { + //if (!g_bouquetManager->Bouquets[i]->bHidden && (g_bouquetManager->Bouquets[i]->bUser || !g_bouquetManager->Bouquets[i]->radioChannels.empty() )) + if (!g_bouquetManager->Bouquets[i]->bHidden && !g_bouquetManager->Bouquets[i]->radioChannels.empty() ) + { + CBouquet* tmp; + if(g_bouquetManager->Bouquets[i]->bUser) + tmp = RADIOfavList->addBouquet(g_bouquetManager->Bouquets[i]->Name.c_str(), i, g_bouquetManager->Bouquets[i]->bLocked); + else + tmp = RADIObouquetList->addBouquet(g_bouquetManager->Bouquets[i]->Name.c_str(), i, g_bouquetManager->Bouquets[i]->bLocked); + + ZapitChannelList* channels = &(g_bouquetManager->Bouquets[i]->radioChannels); + tmp->channelList->setSize(channels->size()); + for(int j = 0; j < (int) channels->size(); j++) { + tmp->channelList->addChannel((*channels)[j]); + } + bnum++; + } + } + printf("[neutrino] got %d RADIO bouquets\n", bnum); fflush(stdout); + TIMER_STOP("[neutrino] took"); + + SetChannelMode(g_settings.channel_mode); + + dprintf(DEBUG_DEBUG, "\nAll bouquets-channels received\n"); +#ifdef DEBUG + struct mallinfo myinfo = mallinfo(); + printf("[neutrino] total memory allocated by malloc, in bytes: %d (%dkb), chunks %d\n", + myinfo.arena, myinfo.arena / 1024, myinfo.uordblks); +#endif + + reloadhintBox->hide(); +} + +void CNeutrinoApp::SetChannelMode(int newmode) +{ +printf("CNeutrinoApp::SetChannelMode %d\n", newmode); + if(mode == mode_radio) + channelList = RADIOchannelList; + else + channelList = TVchannelList; + + switch(newmode) { + case LIST_MODE_FAV: + if(mode == mode_radio) { + bouquetList = RADIOfavList; + } else { + bouquetList = TVfavList; + } + break; + case LIST_MODE_SAT: + if(mode == mode_radio) { + bouquetList = RADIOsatList; + } else { + bouquetList = TVsatList; + } + break; + case LIST_MODE_ALL: + if(mode == mode_radio) { + bouquetList = RADIOallList; + } else { + bouquetList = TVallList; + } + break; + default: + case LIST_MODE_PROV: + if(mode == mode_radio) { + bouquetList = RADIObouquetList; + } else { + bouquetList = TVbouquetList; + } + break; + } + g_settings.channel_mode = newmode; +} + +/************************************************************************************** +* CNeutrinoApp - run, the main runloop * +**************************************************************************************/ +extern int cnxt_debug; +extern int sections_debug; +extern int zapit_debug; + +void CNeutrinoApp::CmdParser(int argc, char **argv) +{ + global_argv = new char *[argc+1]; + for (int i = 0; i < argc; i++) + global_argv[i] = argv[i]; + global_argv[argc] = NULL; + + softupdate = false; + fromflash = false; + + font.name = NULL; + + for(int x=1; xinit(); + if(frameBuffer->setMode(720, 576, 8 * sizeof(fb_pixel_t))) { + dprintf(DEBUG_NORMAL, "Error while setting framebuffer mode\n"); + exit(-1); + } + //make 1..8 transparent for dummy painting + //for(int count =0;count<256;count++) + for(int count =0;count<8;count++) + frameBuffer->paletteSetColor(count, 0x000000, 0xffff); + frameBuffer->paletteSet(); + frameBuffer->ClearFrameBuffer(); +} + +/************************************************************************************** +* CNeutrinoApp - setup fonts * +**************************************************************************************/ +#if 0 +const neutrino_font_descr_struct predefined_font[2] = +{ + {"Micron" , {FONTDIR "/micron.ttf" , FONTDIR "/micron_bold.ttf", FONTDIR "/micron_italic.ttf"}, 0}, + {"MD King KhammuRabi", {FONTDIR "/md_khmurabi_10.ttf", NULL , NULL }, 0} +}; +const char* predefined_lcd_font[2][6] = +{ + {FONTDIR "/12.pcf.gz", "Fix12", FONTDIR "/14B.pcf.gz", "Fix14", FONTDIR "/15B.pcf.gz", "Fix15"}, + {FONTDIR "/md_khmurabi_10.ttf", "MD King KhammuRabi", NULL, NULL, NULL, NULL} +}; +#endif + +void CNeutrinoApp::SetupFonts() +{ + const char * style[3]; + + if (g_fontRenderer != NULL) + delete g_fontRenderer; + + g_fontRenderer = new FBFontRenderClass(xres, yres); + + if(font.filename != NULL) + free((void *)font.filename); + + printf("[neutrino] settings font file %s\n", g_settings.font_file); + + if(access(g_settings.font_file, F_OK)) { + font.filename = strdup(FONTDIR"/neutrino.ttf"); + strcpy(g_settings.font_file, font.filename); + } + else + font.filename = strdup(g_settings.font_file); + + style[0] = g_fontRenderer->AddFont(font.filename); + + if(font.name != NULL) + free((void *)font.name); + + font.name = strdup(g_fontRenderer->getFamily(font.filename).c_str()); + + printf("[neutrino] font family %s\n", font.name); + + style[1] = "Bold Regular"; + + g_fontRenderer->AddFont(font.filename, true); // make italics + style[2] = "Italic"; + + for (int i = 0; i < FONT_TYPE_COUNT; i++) + { + if(g_Font[i]) delete g_Font[i]; + g_Font[i] = g_fontRenderer->getFont(font.name, style[neutrino_font[i].style], configfile.getInt32(locale_real_names[neutrino_font[i].name], neutrino_font[i].defaultsize) + neutrino_font[i].size_offset * font.size_offset); + } + g_SignalFont = g_fontRenderer->getFont(font.name, style[signal_font.style], signal_font.defaultsize + signal_font.size_offset * font.size_offset); +} + +/************************************************************************************** +* CNeutrinoApp - setup the menu timouts * +**************************************************************************************/ +void CNeutrinoApp::SetupTiming() +{ + for (int i = 0; i < TIMING_SETTING_COUNT; i++) + sprintf(g_settings.timing_string[i], "%d", g_settings.timing[i]); +} + +CAudioPlayerGui * audioPlayer; + +bool sectionsd_getActualEPGServiceKey(const t_channel_id uniqueServiceKey, CEPGData * epgdata); +bool sectionsd_getEPGid(const event_id_t epgID, const time_t startzeit, CEPGData * epgdata); + +int startAutoRecord(bool addTimer) +{ + CTimerd::RecordingInfo eventinfo; + if(CNeutrinoApp::getInstance()->recordingstatus || !CVCRControl::getInstance()->isDeviceRegistered() || (g_settings.recording_type != RECORDING_FILE)) + return 0; + + CZapitClient::CCurrentServiceInfo si = g_Zapit->getCurrentServiceInfo(); + + //eventinfo.channel_id = g_Zapit->getCurrentServiceID(); + eventinfo.channel_id = live_channel_id; + CEPGData epgData; + //if (g_Sectionsd->getActualEPGServiceKey(g_RemoteControl->current_channel_id&0xFFFFFFFFFFFFULL, &epgData )) + if (sectionsd_getActualEPGServiceKey(live_channel_id&0xFFFFFFFFFFFFULL, &epgData )) + { + eventinfo.epgID = epgData.eventID; + eventinfo.epg_starttime = epgData.epg_times.startzeit; + strncpy(eventinfo.epgTitle, epgData.title.c_str(), EPG_TITLE_MAXLEN-1); + eventinfo.epgTitle[EPG_TITLE_MAXLEN-1]=0; + } + else { + eventinfo.epgID = 0; + eventinfo.epg_starttime = 0; + strcpy(eventinfo.epgTitle, ""); + } + eventinfo.apids = TIMERD_APIDS_CONF; +printf("*********************************** startAutoRecord: dir %s\n", timeshiftDir); + (static_cast(recordingdevice))->Directory = timeshiftDir; + + autoshift = 1; + CNeutrinoApp::getInstance()->recordingstatus = 1; + if(CVCRControl::getInstance()->Record(&eventinfo)==false) { + CNeutrinoApp::getInstance()->recordingstatus = 0; + autoshift = 0; + } + else if (addTimer) { + time_t now = time(NULL); + CNeutrinoApp::getInstance()->recording_id = g_Timerd->addImmediateRecordTimerEvent(eventinfo.channel_id, now, now+g_settings.record_hours*60*60, eventinfo.epgID, eventinfo.epg_starttime, eventinfo.apids); + } +//printf("startAutoRecord: recording_id = %d\n", CNeutrinoApp::getInstance()->recording_id); + return 0; +} +void stopAutoRecord() +{ + if(autoshift && CNeutrinoApp::getInstance()->recordingstatus) { +printf("stopAutoRecord: autoshift, recordingstatus %d, stopping ...\n", CNeutrinoApp::getInstance()->recordingstatus); + CVCRControl::getInstance()->Stop(); + autoshift = false; + if(CNeutrinoApp::getInstance()->recording_id) { +//printf("stopAutoRecord: recording_id = %d\n", CNeutrinoApp::getInstance()->recording_id); + g_Timerd->stopTimerEvent(CNeutrinoApp::getInstance()->recording_id); + CNeutrinoApp::getInstance()->recording_id = 0; + } + } else if(shift_timer) { + g_RCInput->killTimer (shift_timer); + shift_timer = 0; + } +} + +bool CNeutrinoApp::doGuiRecord(char * preselectedDir, bool addTimer) +{ + CTimerd::RecordingInfo eventinfo; + bool refreshGui = false; + if(CVCRControl::getInstance()->isDeviceRegistered()) { + if(autoshift) { + stopAutoRecord(); + } + if(recordingstatus == 1) { + puts("[neutrino.cpp] executing " NEUTRINO_RECORDING_START_SCRIPT "."); + if (system(NEUTRINO_RECORDING_START_SCRIPT) != 0) + perror(NEUTRINO_RECORDING_START_SCRIPT " failed"); + + CZapitClient::CCurrentServiceInfo si = g_Zapit->getCurrentServiceInfo(); + + //eventinfo.channel_id = g_Zapit->getCurrentServiceID(); + eventinfo.channel_id = live_channel_id; + CEPGData epgData; + //if (g_Sectionsd->getActualEPGServiceKey(g_RemoteControl->current_channel_id&0xFFFFFFFFFFFFULL, &epgData )) + if (sectionsd_getActualEPGServiceKey(live_channel_id&0xFFFFFFFFFFFFULL, &epgData )) + { + eventinfo.epgID = epgData.eventID; + eventinfo.epg_starttime = epgData.epg_times.startzeit; + strncpy(eventinfo.epgTitle, epgData.title.c_str(), EPG_TITLE_MAXLEN-1); + eventinfo.epgTitle[EPG_TITLE_MAXLEN-1]=0; + } + else { + eventinfo.epgID = 0; + eventinfo.epg_starttime = 0; + strcpy(eventinfo.epgTitle, ""); + } + eventinfo.apids = TIMERD_APIDS_CONF; + bool doRecord = true; + if (g_settings.recording_type == RECORDING_FILE) { + strcpy(recDir, (preselectedDir != NULL) ? preselectedDir : g_settings.network_nfs_recordingdir); + // data == NULL -> called after stream problem so do not show a dialog again + // but which dir has been chosen? + if(preselectedDir == NULL && (g_settings.recording_choose_direct_rec_dir == 2)) { + CFileBrowser b; + b.Dir_Mode=true; + refreshGui = true; + if (b.exec(g_settings.network_nfs_recordingdir)) { + strcpy(recDir, b.getSelectedFile()->Name.c_str()); + } + else doRecord = false; + } + else if(preselectedDir == NULL && (g_settings.recording_choose_direct_rec_dir == 1)) { + int userDecision = -1; + + CMountChooser recDirs(LOCALE_TIMERLIST_RECORDING_DIR,NEUTRINO_ICON_SETTINGS,&userDecision,NULL,g_settings.network_nfs_recordingdir); + if (recDirs.hasItem()) { + recDirs.exec(NULL,""); + refreshGui = true; + if (userDecision != -1) { + //recDir = g_settings.network_nfs_local_dir[userDecision]; + strcpy(recDir, g_settings.network_nfs_local_dir[userDecision]); + if (!CFSMounter::isMounted(g_settings.network_nfs_local_dir[userDecision])) + { + CFSMounter::MountRes mres = + CFSMounter::mount(g_settings.network_nfs_ip[userDecision].c_str(), + g_settings.network_nfs_dir[userDecision], + g_settings.network_nfs_local_dir[userDecision], + (CFSMounter::FSType) g_settings.network_nfs_type[userDecision], + g_settings.network_nfs_username[userDecision], + g_settings.network_nfs_password[userDecision], + g_settings.network_nfs_mount_options1[userDecision], + g_settings.network_nfs_mount_options2[userDecision]); + if (mres != CFSMounter::MRES_OK) { + //recDir = g_settings.network_nfs_local_dir[userDecision]; + //strcpy(recDir, g_settings.network_nfs_local_dir[userDecision]); + doRecord = false; + const char * merr = mntRes2Str(mres); + int msglen = strlen(merr) + strlen(g_settings.network_nfs_local_dir[userDecision]) + 7; + char msg[msglen]; + strcpy(msg,merr); + strcat(msg,"\nDir: "); + strcat(msg,g_settings.network_nfs_local_dir[userDecision]); + + ShowMsgUTF(LOCALE_MESSAGEBOX_ERROR, msg, + CMessageBox::mbrBack, CMessageBox::mbBack,NEUTRINO_ICON_ERROR, 450, 10); // UTF-8 + } + } + } else { + doRecord = false; + } + } else { + printf("[neutrino.cpp] no network devices available\n"); + doRecord = false; + } + } + (static_cast(recordingdevice))->Directory = recDir; +printf("CNeutrinoApp::doGuiRecord: start to dir %s\n", recDir); + } + if(!doRecord || (CVCRControl::getInstance()->Record(&eventinfo)==false)) { + recordingstatus=0; + if(doRecord) + return true;// try to refresh gui if record was not ok ? + return refreshGui; + } + else if (addTimer) { + time_t now = time(NULL); + recording_id = g_Timerd->addImmediateRecordTimerEvent(eventinfo.channel_id, now, now+g_settings.record_hours*60*60, eventinfo.epgID, eventinfo.epg_starttime, eventinfo.apids); + } + } else { + g_Timerd->stopTimerEvent(recording_id); + startNextRecording(); + } + return refreshGui; + } + else + puts("[neutrino.cpp] no recording devices"); + return false; +} + +#define LCD_UPDATE_TIME_RADIO_MODE (6 * 1000 * 1000) +#define LCD_UPDATE_TIME_TV_MODE (60 * 1000 * 1000) + +void CNeutrinoApp::SendSectionsdConfig(void) +{ + CSectionsdClient::epg_config config; + config.scanMode = scanSettings.scanSectionsd; + config.epg_cache = atoi(g_settings.epg_cache.c_str()); + config.epg_old_events = atoi(g_settings.epg_old_events.c_str()); + config.epg_max_events = atoi(g_settings.epg_max_events.c_str()); + config.epg_extendedcache = atoi(g_settings.epg_extendedcache.c_str()); + config.epg_dir = g_settings.epg_dir; + config.network_ntpserver = g_settings.network_ntpserver; + config.network_ntprefresh = atoi(g_settings.network_ntprefresh.c_str()); + config.network_ntpenable = g_settings.network_ntpenable; + g_Sectionsd->setConfig(config); +} + +void CNeutrinoApp::InitZapper() +{ + struct stat my_stat; + + g_InfoViewer->start(); + SendSectionsdConfig(); + if (g_settings.epg_save){ + if(stat(g_settings.epg_dir.c_str(), &my_stat) == 0) + g_Sectionsd->readSIfromXML(g_settings.epg_dir.c_str()); + } + firstChannel(); + channelsInit(); + + if(firstchannel.mode == 't') { + tvMode(false); + } else { + g_RCInput->killTimer(g_InfoViewer->lcdUpdateTimer); + g_InfoViewer->lcdUpdateTimer = g_RCInput->addTimer( LCD_UPDATE_TIME_RADIO_MODE, false ); + radioMode(false); + } + if(g_settings.cacheTXT) + tuxtxt_init(); + if(channelList->getSize() && live_channel_id) { + channelList->adjustToChannelID(live_channel_id); + CVFD::getInstance ()->showServicename(channelList->getActiveChannelName()); + g_Sectionsd->setPauseScanning(false); + g_Sectionsd->setServiceChanged(live_channel_id&0xFFFFFFFFFFFFULL, true ); + g_Zapit->getPIDS(g_RemoteControl->current_PIDs); + if(g_settings.cacheTXT) + if(g_RemoteControl->current_PIDs.PIDs.vtxtpid != 0) + tuxtxt_start(g_RemoteControl->current_PIDs.PIDs.vtxtpid); + g_RCInput->postMsg(NeutrinoMessages::SHOW_INFOBAR, 0); + } +} + +void CNeutrinoApp::setupRecordingDevice(void) +{ + if (g_settings.recording_type == RECORDING_SERVER) + { + unsigned int port; + sscanf(g_settings.recording_server_port, "%u", &port); + + recordingdevice = new CVCRControl::CServerDevice(g_settings.recording_stopplayback, g_settings.recording_stopsectionsd, g_settings.recording_server_ip.c_str(), port); + CVCRControl::getInstance()->registerDevice(recordingdevice); + } + else if (g_settings.recording_type == RECORDING_FILE) + { + unsigned int splitsize, ringbuffers; + sscanf(g_settings.recording_splitsize, "%u", &splitsize); + sscanf(g_settings.recording_ringbuffers, "%u", &ringbuffers); + + recordingdevice = new CVCRControl::CFileDevice(g_settings.recording_stopplayback, g_settings.recording_stopsectionsd, g_settings.network_nfs_recordingdir, splitsize, g_settings.recording_use_o_sync, g_settings.recording_use_fdatasync, g_settings.recording_stream_vtxt_pid, g_settings.recording_stream_pmt_pid, ringbuffers); + + CVCRControl::getInstance()->registerDevice(recordingdevice); + } + else if(g_settings.recording_type == RECORDING_VCR) + { + recordingdevice = new CVCRControl::CVCRDevice((g_settings.recording_vcr_no_scart == 0)); + + CVCRControl::getInstance()->registerDevice(recordingdevice); + } + else + { + if (CVCRControl::getInstance()->isDeviceRegistered()) + CVCRControl::getInstance()->unregisterDevice(); + } +} + +//CMenuWidget moviePlayer (LOCALE_MOVIEPLAYER_HEAD , "streaming.raw" ); +CMenuWidget * gmoviePlayer; +#if 0 +CPipSetup * g_Pip0; +#endif +#include "videosettings.h" +extern CVideoSettings * videoSettings; +extern CMenuOptionStringChooser* tzSelect; + +void CISendMessage(uint32_t msg, uint32_t data) +{ + g_RCInput->postMsg(msg, data); +} + +int CNeutrinoApp::run(int argc, char **argv) +{ + CmdParser(argc, argv); + + CHintBox * hintBox; + + int loadSettingsErg = loadSetup(NEUTRINO_SETTINGS_FILE); + + bool display_language_selection; + CLocaleManager::loadLocale_ret_t loadLocale_ret = g_Locale->loadLocale(g_settings.language); + if (loadLocale_ret == CLocaleManager::NO_SUCH_LOCALE) + { + strcpy(g_settings.language, "english"); + loadLocale_ret = g_Locale->loadLocale(g_settings.language); + display_language_selection = true; + } + else + display_language_selection = false; + + SetupFonts(); + SetupTiming(); + colorSetupNotifier = new CColorSetupNotifier; + colorSetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_NEUTRINO_STARTING)); + hintBox->paint(); + CVFD::getInstance()->init(font.filename, font.name); + + CVFD::getInstance()->Clear(); + CVFD::getInstance()->ShowText((char *) g_Locale->getText(LOCALE_NEUTRINO_STARTING)); + + init_cs_api(); + + pthread_create (&zapit_thread, NULL, zapit_main_thread, (void *) g_settings.video_Mode); + audioSetupNotifier = new CAudioSetupNotifier; + + while(!zapit_ready) + usleep(0); + printf("zapit ready\n\n"); + + audioDecoder->SetSRS(g_settings.srs_enable, g_settings.srs_nmgr_enable, g_settings.srs_algo, g_settings.srs_ref_volume); + audioDecoder->setVolume(g_settings.current_volume, g_settings.current_volume); + audioDecoder->SetHdmiDD(g_settings.hdmi_dd ? true : false); + audioDecoder->SetSpdifDD(g_settings.spdif_dd ? true : false); + videoDecoder->SetDBDR(g_settings.video_dbdr); + audioSetupNotifier->changeNotify(LOCALE_AUDIOMENU_AVSYNC, NULL); + + if(display_language_selection) + videoDecoder->ShowPicture(DATADIR "/neutrino/icons/start.jpg"); + + powerManager = new cPowerManager; + + if (powerManager) { + if (!powerManager->Open()) + printf("opening powermanager failed\n"); + } + + cpuFreq = new cCpuFreqManager(); + cpuFreq->SetCpuFreq(g_settings.cpufreq * 1000 * 1000); + + + dvbsub_init(); + + pthread_create (&timer_thread, NULL, timerd_main_thread, (void *) NULL); + pthread_create (&nhttpd_thread, NULL, nhttpd_main_thread, (void *) NULL); + + pthread_create (&stream_thread, NULL, streamts_main_thread, (void *) NULL); + + hintBox->hide(); //FIXME + hintBox->paint(); + +#ifndef DISABLE_SECTIONSD + pthread_create (§ions_thread, NULL, sectionsd_main_thread, (void *) NULL); +#endif + g_Zapit = new CZapitClient; + + if (!scanSettings.loadSettings(NEUTRINO_SCAN_SETTINGS_FILE, (g_info.delivery_system = g_Zapit->getDeliverySystem()))) { + dprintf(DEBUG_NORMAL, "Loading of scan settings failed. Using defaults.\n"); + } + + + CVFD::getInstance()->showVolume(g_settings.current_volume); + CVFD::getInstance()->setMuted(current_muted); + + InfoClock = new CInfoClock(); + if(g_settings.mode_clock) + InfoClock->StartClock(); + + g_RCInput = new CRCInput; + + g_Sectionsd = new CSectionsdClient; + //g_Sectionsd->setServiceChanged(live_channel_id &0xFFFFFFFFFFFFULL, false); + g_Timerd = new CTimerdClient; + + g_RemoteControl = new CRemoteControl; + g_EpgData = new CEpgData; + g_InfoViewer = new CInfoViewer; + g_EventList = new EventList; + g_volscale = new CScale(200, 15, 50, 100, 80, true); + g_CamHandler = new CCAMMenuHandler(); + g_CamHandler->init(); + + audio_menu = new CAudioSelectMenuHandler; + + g_PluginList = new CPlugins; + g_PluginList->setPluginDir(PLUGINDIR); + g_PicViewer = new CPictureViewer(); + // mount shares before scanning for plugins + CFSMounter::automount(); + //load Pluginlist before main menu (only show script menu if at least one script is available + g_PluginList->loadPlugins(); + + APIDChanger = new CAPIDChangeExec; + NVODChanger = new CNVODChangeExec; + StreamFeaturesChanger = new CStreamFeaturesChangeExec; + MoviePluginChanger = new CMoviePluginChangeExec; + OnekeyPluginChanger = new COnekeyPluginChangeExec; + MyIPChanger = new CIPChangeNotifier; + ConsoleDestinationChanger = new CConsoleDestChangeNotifier; + rcLock = new CRCLock(); + //USERMENU + Timerlist = new CTimerList; + + // setup recording device + if (g_settings.recording_type != RECORDING_OFF) + setupRecordingDevice(); + + dprintf( DEBUG_NORMAL, "menue setup\n"); + + c_SMSKeyInput = new SMSKeyInput(); + //Main settings + CMenuWidget mainMenu (LOCALE_MAINMENU_HEAD , "mainmenue.raw" ); + CMenuWidget mainSettings (LOCALE_MAINSETTINGS_HEAD , NEUTRINO_ICON_SETTINGS); + CMenuWidget languageSettings (LOCALE_LANGUAGESETUP_HEAD , "language.raw" ); + CMenuWidget audioSettings (LOCALE_AUDIOMENU_HEAD , "audio.raw" ); + CMenuWidget parentallockSettings(LOCALE_PARENTALLOCK_PARENTALLOCK , "lock.raw" , 500); + CMenuWidget networkSettings (LOCALE_NETWORKMENU_HEAD , "network.raw" ); + CMenuWidget recordingSettings (LOCALE_RECORDINGMENU_HEAD , "recording.raw" ); + CMenuWidget streamingSettings (LOCALE_STREAMINGMENU_HEAD , "streaming.raw" ); + //CMenuWidget colorSettings (LOCALE_COLORMENU_HEAD , "colors.raw" ); + CMenuWidget colorSettings (LOCALE_MAINSETTINGS_OSD , "colors.raw" ); + CMenuWidget fontSettings (LOCALE_FONTMENU_HEAD , "colors.raw" ); + CMenuWidget lcdSettings (LOCALE_LCDMENU_HEAD , "lcd.raw" ); + //CMenuWidget keySettings (LOCALE_KEYBINDINGMENU_HEAD , "keybinding.raw" , 400); + CMenuWidget keySettings (LOCALE_MAINSETTINGS_KEYBINDING , "keybinding.raw" , 400); + CMenuWidget miscSettings (LOCALE_MISCSETTINGS_HEAD , NEUTRINO_ICON_SETTINGS); + CMenuWidget audioplPicSettings (LOCALE_AUDIOPLAYERPICSETTINGS_GENERAL, NEUTRINO_ICON_SETTINGS); + CMenuWidget scanSettings (LOCALE_SERVICEMENU_SCANTS , NEUTRINO_ICON_SETTINGS); + CMenuWidget service (LOCALE_SERVICEMENU_HEAD , NEUTRINO_ICON_SETTINGS); + CMenuWidget moviePlayer (LOCALE_MOVIEPLAYER_HEAD , "streaming.raw" ); + gmoviePlayer = &moviePlayer; + + InitMainMenu(mainMenu, mainSettings, audioSettings, parentallockSettings, networkSettings, recordingSettings, + colorSettings, lcdSettings, keySettings, languageSettings, miscSettings, + service, fontSettings, audioplPicSettings, streamingSettings, moviePlayer); + + InitServiceSettings(service, scanSettings); + InitLanguageSettings(languageSettings); + InitAudioplPicSettings(audioplPicSettings); + InitMiscSettings(miscSettings); + InitAudioSettings(audioSettings, audioSetupNotifier); + InitParentalLockSettings(parentallockSettings); + InitScanSettings(scanSettings); + + dprintf( DEBUG_NORMAL, "registering as event client\n"); +#if 0 + g_Controld->registerEvent(CControldClient::EVT_MUTECHANGED, 222, NEUTRINO_UDS_NAME); + g_Controld->registerEvent(CControldClient::EVT_VOLUMECHANGED, 222, NEUTRINO_UDS_NAME); + g_Controld->registerEvent(CControldClient::EVT_MODECHANGED, 222, NEUTRINO_UDS_NAME); + g_Controld->registerEvent(CControldClient::EVT_VCRCHANGED, 222, NEUTRINO_UDS_NAME); +#endif + + g_Sectionsd->registerEvent(CSectionsdClient::EVT_TIMESET, 222, NEUTRINO_UDS_NAME); + g_Sectionsd->registerEvent(CSectionsdClient::EVT_GOT_CN_EPG, 222, NEUTRINO_UDS_NAME); + g_Sectionsd->registerEvent(CSectionsdClient::EVT_SERVICES_UPDATE, 222, NEUTRINO_UDS_NAME); + g_Sectionsd->registerEvent(CSectionsdClient::EVT_BOUQUETS_UPDATE, 222, NEUTRINO_UDS_NAME); + g_Sectionsd->registerEvent(CSectionsdClient::EVT_WRITE_SI_FINISHED, 222, NEUTRINO_UDS_NAME); + +#define ZAPIT_EVENT_COUNT 29 + const CZapitClient::events zapit_event[ZAPIT_EVENT_COUNT] = + { + CZapitClient::EVT_ZAP_COMPLETE, + CZapitClient::EVT_ZAP_COMPLETE_IS_NVOD, + CZapitClient::EVT_ZAP_FAILED, + CZapitClient::EVT_ZAP_SUB_COMPLETE, + CZapitClient::EVT_ZAP_SUB_FAILED, + CZapitClient::EVT_ZAP_MOTOR, + CZapitClient::EVT_ZAP_CA_CLEAR, + CZapitClient::EVT_ZAP_CA_LOCK, + CZapitClient::EVT_ZAP_CA_FTA, + CZapitClient::EVT_ZAP_CA_ID, + CZapitClient::EVT_RECORDMODE_ACTIVATED, + CZapitClient::EVT_RECORDMODE_DEACTIVATED, + CZapitClient::EVT_SCAN_COMPLETE, + CZapitClient::EVT_SCAN_FAILED, + CZapitClient::EVT_SCAN_NUM_TRANSPONDERS, + CZapitClient::EVT_SCAN_REPORT_NUM_SCANNED_TRANSPONDERS, + CZapitClient::EVT_SCAN_REPORT_FREQUENCY, + CZapitClient::EVT_SCAN_REPORT_FREQUENCYP, + CZapitClient::EVT_SCAN_SATELLITE, + CZapitClient::EVT_SCAN_NUM_CHANNELS, + CZapitClient::EVT_SCAN_PROVIDER, + CZapitClient::EVT_BOUQUETS_CHANGED, + CZapitClient::EVT_SERVICES_CHANGED, + CZapitClient::EVT_SCAN_SERVICENAME, + CZapitClient::EVT_SCAN_FOUND_A_CHAN, + CZapitClient::EVT_SCAN_FOUND_TV_CHAN, + CZapitClient::EVT_SCAN_FOUND_RADIO_CHAN, + CZapitClient::EVT_SCAN_FOUND_DATA_CHAN, + CZapitClient::EVT_SDT_CHANGED + }; + + for (int i = 0; i < ZAPIT_EVENT_COUNT; i++) + g_Zapit->registerEvent(zapit_event[i], 222, NEUTRINO_UDS_NAME); + + g_Timerd->registerEvent(CTimerdClient::EVT_ANNOUNCE_SHUTDOWN, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_SHUTDOWN, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_ANNOUNCE_NEXTPROGRAM, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_NEXTPROGRAM, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_STANDBY_ON, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_STANDBY_OFF, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_ANNOUNCE_RECORD, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_RECORD_START, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_RECORD_STOP, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_ANNOUNCE_ZAPTO, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_ZAPTO, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_SLEEPTIMER, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_ANNOUNCE_SLEEPTIMER, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_REMIND, 222, NEUTRINO_UDS_NAME); + g_Timerd->registerEvent(CTimerdClient::EVT_EXEC_PLUGIN, 222, NEUTRINO_UDS_NAME); + + InitNetworkSettings(networkSettings); + InitKeySettings(keySettings); + InitFontSettings(fontSettings); + InitColorSettings(colorSettings, fontSettings); + + if (display_language_selection) { + hintBox->hide(); + int ret = languageSettings.exec(NULL, ""); + + if(ret != menu_return::RETURN_EXIT_ALL) + videoSettings->exec(NULL, ""); + if(ret != menu_return::RETURN_EXIT_ALL) + colorSettings.exec(NULL, ""); + if(ret != menu_return::RETURN_EXIT_ALL) + if(tzSelect) + tzSelect->exec(NULL); + if(ret != menu_return::RETURN_EXIT_ALL) + networkSettings.exec(NULL, ""); + if(ret != menu_return::RETURN_EXIT_ALL) + scanSettings.exec(NULL, ""); + + videoDecoder->StopPicture(); + } + + if(loadSettingsErg) { + hintBox->hide(); + dprintf(DEBUG_INFO, "config file or options missing\n"); + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, loadSettingsErg == 1 ? g_Locale->getText(LOCALE_SETTINGS_NOCONFFILE) + : g_Locale->getText(LOCALE_SETTINGS_MISSINGOPTIONSCONFFILE)); + configfile.setModifiedFlag(true); + saveSetup(NEUTRINO_SETTINGS_FILE); + } +#if 1 // FIXME + system("mkdir /media/sda1 2> /dev/null"); + system("mount /media/sda1 2> /dev/null"); + system("mkdir /media/sdb1 2> /dev/null"); + system("mount /media/sdb1 2> /dev/null"); + CHDDDestExec * hdd = new CHDDDestExec(); + hdd->exec(NULL, ""); +#endif + + InitZapper(); + InitRecordingSettings(recordingSettings); + InitStreamingSettings(streamingSettings); + InitLcdSettings(lcdSettings); + + AudioMute( current_muted, true); + + SHTDCNT::getInstance()->init(); + + hintBox->hide(); + delete hintBox; + + cDvbCi::getInstance()->SetHook(CISendMessage); + RealRun(mainMenu); + + ExitRun(true); + + return 0; +} + +int tuxtx_main(int _rc, void * _fb, int pid, int x, int y, int w, int h); + +void CNeutrinoApp::quickZap(int msg) +{ + if((bouquetList != NULL) && !(bouquetList->Bouquets.empty())) + bouquetList->Bouquets[bouquetList->getActiveBouquetNumber()]->channelList->quickZap(msg, g_settings.zap_cycle); + else + channelList->quickZap(msg); +} + +void CNeutrinoApp::RealRun(CMenuWidget &mainMenu) +{ + neutrino_msg_t msg; + neutrino_msg_data_t data; + + dprintf(DEBUG_NORMAL, "initialized everything\n"); + + g_PluginList->startPlugin("startup.cfg"); + if (!g_PluginList->getScriptOutput().empty()) { + ShowMsgUTF(LOCALE_PLUGINS_RESULT, g_PluginList->getScriptOutput(), CMessageBox::mbrBack,CMessageBox::mbBack,NEUTRINO_ICON_SHELL); + } + g_RCInput->clearRCMsg(); + if(g_settings.power_standby) + standbyMode(true); + + while( true ) { + g_RCInput->getMsg(&msg, &data, 100); // 10 secs.. + + if( ( mode == mode_tv ) || ( ( mode == mode_radio ) ) ) { + if( (msg == NeutrinoMessages::SHOW_EPG) /* || (msg == CRCInput::RC_info) */ ) { + //g_EpgData->show( g_Zapit->getCurrentServiceID() ); + g_EpgData->show(live_channel_id); + } + else if( msg == CRCInput::RC_epg ) { + g_EventList->exec(live_channel_id, channelList->getActiveChannelName()); + } + else if( msg == CRCInput::RC_text) { + g_RCInput->clearRCMsg(); + if(g_settings.mode_clock) + InfoClock->StopClock(); + + tuxtx_main(g_RCInput->getFileHandle(), frameBuffer->getFrameBufferPointer(), g_RemoteControl->current_PIDs.PIDs.vtxtpid, + frameBuffer->getScreenX(), frameBuffer->getScreenY(), frameBuffer->getScreenWidth(), frameBuffer->getScreenHeight()); + + frameBuffer->paintBackground(); + //if(!g_settings.cacheTXT) + // tuxtxt_stop(); + g_RCInput->clearRCMsg(); + AudioMute(current_muted, true); + if(g_settings.mode_clock) + InfoClock->StartClock(); + } + else if( msg == CRCInput::RC_setup ) { + if(!g_settings.minimode) { + dvbsub_pause(); + if(g_settings.mode_clock) + InfoClock->StopClock(); + mainMenu.exec(NULL, ""); + // restore mute symbol + AudioMute(current_muted, true); + if(g_settings.mode_clock) + InfoClock->StartClock(); + dvbsub_start(0); + saveSetup(NEUTRINO_SETTINGS_FILE); + } + } + else if( msg == (neutrino_msg_t) g_settings.key_tvradio_mode ) { + if( mode == mode_tv ) + radioMode(); + else if( mode == mode_radio ) + tvMode(); + } + else if( ((msg == CRCInput::RC_tv) || (msg == CRCInput::RC_radio)) && ((neutrino_msg_t)g_settings.key_tvradio_mode == CRCInput::RC_nokey)) { + if(mode == mode_radio ) + tvMode(); + else if(mode == mode_tv) + radioMode(); + } + else if( ( msg == (neutrino_msg_t) g_settings.key_quickzap_up ) || ( msg == (neutrino_msg_t) g_settings.key_quickzap_down ) ) + { + //quickzap + quickZap(msg); + } + else if( msg == (neutrino_msg_t) g_settings.key_subchannel_up ) { + if(g_RemoteControl->subChannels.size() > 0) { + g_RemoteControl->subChannelUp(); + g_InfoViewer->showSubchan(); + } else + quickZap( msg ); + } + else if( msg == (neutrino_msg_t) g_settings.key_subchannel_down ) { + if(g_RemoteControl->subChannels.size()> 0) { + g_RemoteControl->subChannelDown(); + g_InfoViewer->showSubchan(); + } else + quickZap( msg ); + } + else if( msg == (neutrino_msg_t) g_settings.key_zaphistory ) { + // Zap-History "Bouquet" + if(g_settings.mode_clock && g_settings.key_zaphistory == CRCInput::RC_home) { + InfoClock->StopClock(); + g_settings.mode_clock=false; + } else { + dvbsub_pause(); + int res = channelList->numericZap( msg ); + if(res < 0) + dvbsub_start(0); + } + } + else if( msg == (neutrino_msg_t) g_settings.key_lastchannel ) { + // Quick Zap + channelList->numericZap( msg ); + } + else if( msg == (neutrino_msg_t) g_settings.key_plugin ) { + g_PluginList->start_plugin_by_name(g_settings.onekey_plugin.c_str(), 0); + } + else if( (msg == (neutrino_msg_t) g_settings.key_timeshift) || msg == CRCInput::RC_rewind) { + if((g_settings.recording_type == RECORDING_FILE) && !g_settings.minimode) { +printf("[neutrino] timeshift try, recordingstatus %d, rec dir %s, timeshift dir %s temp timeshift %d ...\n", recordingstatus, g_settings.network_nfs_recordingdir, timeshiftDir, g_settings.temp_timeshift); + std::string tmode; + if(msg == CRCInput::RC_rewind) + tmode = "rtimeshift"; // rewind + else if(recordingstatus && msg == (neutrino_msg_t) g_settings.key_timeshift) + tmode = "ptimeshift"; // already recording, pause + else + tmode = "timeshift"; // record just started + + if(g_RemoteControl->is_video_started) { + if(recordingstatus) { + //dvbsub_pause(); + moviePlayerGui->exec(NULL, tmode); + //dvbsub_start(0); + } else if(msg != CRCInput::RC_rewind) { + //dvbsub_pause(); + if(g_settings.temp_timeshift) { + startAutoRecord(true); + } else { + recordingstatus = 1; + doGuiRecord(g_settings.network_nfs_recordingdir, true); + } + if(recordingstatus) { + //dvbsub_pause(); + moviePlayerGui->exec(NULL, tmode); + //dvbsub_start(0); + } + } + } + } + } + else if( msg == CRCInput::RC_record || msg == CRCInput::RC_stop ) { +printf("[neutrino] direct record\n"); + if(recordingstatus) { + if(ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_SHUTDOWN_RECODING_QUERY, + CMessageBox::mbrYes, CMessageBox::mbYes | CMessageBox::mbNo, NULL, 450, 30, true) == CMessageBox::mbrYes) + g_Timerd->stopTimerEvent(recording_id); + } else if(msg != CRCInput::RC_stop ) { + recordingstatus = 1; + doGuiRecord(g_settings.network_nfs_recordingdir, true); + } + } + else if( msg == CRCInput::RC_red ) { + showUserMenu(SNeutrinoSettings::BUTTON_RED); + } + else if( (msg == CRCInput::RC_green) || ((msg == CRCInput::RC_audio) && !g_settings.audio_run_player) ) + { + showUserMenu(SNeutrinoSettings::BUTTON_GREEN); + } + else if( msg == CRCInput::RC_yellow ) { // NVODs + showUserMenu(SNeutrinoSettings::BUTTON_YELLOW); + } + else if( msg == CRCInput::RC_blue ) { + showUserMenu(SNeutrinoSettings::BUTTON_BLUE); + } + else if( (msg == CRCInput::RC_audio) && g_settings.audio_run_player) { + dvbsub_pause(); + audioPlayer->exec(NULL, ""); + dvbsub_start(0); + } + else if( msg == CRCInput::RC_video || msg == CRCInput::RC_play ) { + bool show = true; + if ((g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_ONSIGNAL) || (g_settings.parentallock_prompt == PARENTALLOCK_PROMPT_CHANGETOLOCKED)) { + CZapProtection* zapProtection = new CZapProtection( g_settings.parentallock_pincode, 0x100 ); + show = zapProtection->check(); + delete zapProtection; + } + if(show) { + //dvbsub_pause(); + if( mode == mode_radio ) + videoDecoder->StopPicture(); + moviePlayerGui->exec(NULL, "tsmoviebrowser"); + if( mode == mode_radio ) + videoDecoder->ShowPicture(DATADIR "/neutrino/icons/radiomode.jpg"); + //dvbsub_start(0); + } + } + else if (CRCInput::isNumeric(msg) && g_RemoteControl->director_mode ) { + g_RemoteControl->setSubChannel(CRCInput::getNumericValue(msg)); + g_InfoViewer->showSubchan(); + } + else if (CRCInput::isNumeric(msg)) { + channelList->numericZap( msg ); + } + else if( ( msg == CRCInput::RC_help ) || ( msg == CRCInput::RC_info) || + ( msg == NeutrinoMessages::SHOW_INFOBAR ) ) + { + bool show_info = ((msg != NeutrinoMessages::SHOW_INFOBAR) || (g_InfoViewer->is_visible || g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR] != 0)); + // turn on LCD display + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + + // show Infoviewer + if(show_info && channelList->getSize()) { + dvbsub_pause(); + g_InfoViewer->showTitle(channelList->getActiveChannelNumber(), channelList->getActiveChannelName(), channelList->getActiveSatellitePosition(), channelList->getActiveChannel_ChannelID()); // UTF-8 + dvbsub_start(0); + } + } +#if 0 + else if( msg == CRCInput::RC_shift_blue ) { + if(CVFD::getInstance()->has_lcd) { + standbyMode( true ); + //this->rcLock->exec(NULL,CRCLock::NO_USER_INPUT); + this->rcLock->lockBox(); + standbyMode( false ); + } + } + else if( msg == CRCInput::RC_shift_tv ) { + if(CVFD::getInstance()->has_lcd) { // FIXME hack for 5xxx dreams + scartMode( true ); + //this->rcLock->exec(NULL,CRCLock::NO_USER_INPUT); + this->rcLock->lockBox(); + scartMode( false ); + } + } + else if( msg == CRCInput::RC_shift_red) { + if(CVFD::getInstance()->has_lcd) { // FIXME hack for 5xxx dreams + g_settings.minimode = !g_settings.minimode; + saveSetup(NEUTRINO_SETTINGS_FILE); + } + } else if( msg == CRCInput::RC_shift_radio) { + CVCRControl::getInstance()->Screenshot(g_RemoteControl->current_channel_id); + } +#endif + else { + if (msg == CRCInput::RC_home) { + if(g_settings.mode_clock && g_settings.key_zaphistory == CRCInput::RC_home) { + InfoClock->StopClock(); + g_settings.mode_clock=false; + } + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + } + handleMsg(msg, data); + } + } + else { + // mode == mode_scart + if( msg == CRCInput::RC_home ) { + if( mode == mode_scart ) { + //wenn VCR Aufnahme dann stoppen + if(CVCRControl::getInstance()->isDeviceRegistered()) { + if ((CVCRControl::getInstance()->Device->getDeviceType() == CVCRControl::DEVICE_VCR) && + (CVCRControl::getInstance()->getDeviceState() == CVCRControl::CMD_VCR_RECORD || + CVCRControl::getInstance()->getDeviceState() == CVCRControl::CMD_VCR_PAUSE)) + { + CVCRControl::getInstance()->Stop(); + recordingstatus=0; + startNextRecording(); + } + } + // Scart-Mode verlassen + scartMode( false ); + } + } + else { + handleMsg(msg, data); + } + } + } +} + +int CNeutrinoApp::handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t data) +{ + int res = 0; +//printf("[neutrino] handleMsg %X data %X\n", msg, data); fflush(stdout); + + if(msg == NeutrinoMessages::EVT_ZAP_COMPLETE) { + g_Zapit->getAudioMode(&g_settings.audio_AnalogMode); + if(g_settings.audio_AnalogMode < 0 || g_settings.audio_AnalogMode > 2) + g_settings.audio_AnalogMode = 0; +#if 0 // per-channel auto volume save/restore + unsigned int volume; + g_Zapit->getVolume(&volume, &volume); + current_volume = 100 - volume*100/63; + printf("zapit volume %d new current %d mode %d\n", volume, current_volume, g_settings.audio_AnalogMode); + setvol(current_volume,(g_settings.audio_avs_Control)); +#endif + if(shift_timer) { + g_RCInput->killTimer (shift_timer); + shift_timer = 0; + } + if (!recordingstatus && g_settings.auto_timeshift) { + int delay = g_settings.auto_timeshift; + shift_timer = g_RCInput->addTimer( delay*1000*1000, true ); + g_InfoViewer->handleMsg(NeutrinoMessages::EVT_RECORDMODE, 1); + } + + if(scrambled_timer) { + g_RCInput->killTimer(scrambled_timer); + scrambled_timer = 0; + } + scrambled_timer = g_RCInput->addTimer(10*1000*1000, true); + } + if ((msg == NeutrinoMessages::EVT_TIMER)) { + if(data == shift_timer) { + shift_timer = 0; + startAutoRecord(true); + return messages_return::handled; + } else if(data == scrambled_timer) { + scrambled_timer = 0; + if(videoDecoder->getBlank() && videoDecoder->getPlayState()) { + const char * text = g_Locale->getText(LOCALE_SCRAMBLED_CHANNEL); + ShowHintUTF (LOCALE_MESSAGEBOX_INFO, text, g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth (text, true) + 10, 5); + } + return messages_return::handled; + + } + } + + res = res | g_RemoteControl->handleMsg(msg, data); + res = res | g_InfoViewer->handleMsg(msg, data); + res = res | channelList->handleMsg(msg, data); + + //printf("[neutrino] handleMsg %X unhandled by others\n", msg); fflush(stdout); + if( res != messages_return::unhandled ) { + if( ( msg>= CRCInput::RC_WithData ) && ( msg< CRCInput::RC_WithData+ 0x10000000 ) ) + delete (unsigned char*) data; + return( res & ( 0xFFFFFFFF - messages_return::unhandled ) ); + } + + /* we assume g_CamHandler free/delete data if needed */ + res = g_CamHandler->handleMsg(msg, data); + if( res != messages_return::unhandled ) { + return(res & (0xFFFFFFFF - messages_return::unhandled)); + } + + /* ================================== KEYS ================================================ */ + if( msg == CRCInput::RC_ok || msg == CRCInput::RC_sat || msg == CRCInput::RC_favorites) { + if( (mode == mode_tv) || (mode == mode_radio) || (mode == mode_ts)) { + if(g_settings.mode_clock) + InfoClock->StopClock(); + + dvbsub_pause(); + + int nNewChannel = -1; + int old_num = 0; + int old_b = bouquetList->getActiveBouquetNumber(); + int old_mode = g_settings.channel_mode; + printf("************************* ZAP START: bouquetList %x size %d old_b %d\n", (int) bouquetList, bouquetList->Bouquets.size(), old_b);fflush(stdout); + + if(bouquetList->Bouquets.size()) { + old_num = bouquetList->Bouquets[old_b]->channelList->getActiveChannelNumber(); + } + + //if(msg == CRCInput::RC_ok && bouquetList->Bouquets.size()) + if(msg == CRCInput::RC_ok) + { + if(bouquetList->Bouquets.size() && bouquetList->Bouquets[old_b]->channelList->getSize() > 0) + nNewChannel = bouquetList->Bouquets[old_b]->channelList->exec();//with ZAP! + else + nNewChannel = bouquetList->exec(true); + } else if(msg == CRCInput::RC_sat) { + SetChannelMode(LIST_MODE_SAT); + nNewChannel = bouquetList->exec(true); + } else if(msg == CRCInput::RC_favorites) { + SetChannelMode(LIST_MODE_FAV); + nNewChannel = bouquetList->exec(true); + } +_repeat: + printf("************************* ZAP RES: nNewChannel %d\n", nNewChannel);fflush(stdout); + if(nNewChannel == -1) { // restore orig. bouquet and selected channel on cancel + SetChannelMode(old_mode); + bouquetList->activateBouquet(old_b, false); + if(bouquetList->Bouquets.size()) + bouquetList->Bouquets[old_b]->channelList->setSelected(old_num-1); + } + else if(nNewChannel == -3) { // list mode changed + printf("************************* ZAP NEW MODE: bouquetList %x size %d\n", (int) bouquetList, bouquetList->Bouquets.size());fflush(stdout); + nNewChannel = bouquetList->exec(true); + goto _repeat; + } + else if(nNewChannel == -4) { + if(old_b_id < 0) old_b_id = old_b; + g_Zapit->saveBouquets(); + } + + if(g_settings.mode_clock) + InfoClock->StartClock(); + if(mode == mode_tv) + dvbsub_start(0); + return messages_return::handled; + } + } + else if (msg == CRCInput::RC_standby) { + if (data == 0) { + neutrino_msg_t new_msg; + + /* Note: pressing the power button on the dbox (not the remote control) over 1 second */ + /* shuts down the system even if !g_settings.shutdown_real_rcdelay (see below) */ + gettimeofday(&standby_pressed_at, NULL); + + if ((mode != mode_standby) && (g_settings.shutdown_real)) { + new_msg = NeutrinoMessages::SHUTDOWN; + } + else { + new_msg = (mode == mode_standby) ? NeutrinoMessages::STANDBY_OFF : NeutrinoMessages::STANDBY_ON; + //printf("standby: new msg %X\n", new_msg); + if ((g_settings.shutdown_real_rcdelay)) { + neutrino_msg_t msg; + neutrino_msg_data_t data; + struct timeval endtime; + time_t seconds; + + int timeout = 0; + int timeout1 = 0; + + sscanf(g_settings.repeat_blocker, "%d", &timeout); + sscanf(g_settings.repeat_genericblocker, "%d", &timeout1); + + if (timeout1 > timeout) + timeout = timeout1; + + timeout += 500; + //printf("standby: timeout %d\n", timeout); + + while(true) { + g_RCInput->getMsg_ms(&msg, &data, timeout); + + //printf("standby: input msg %X\n", msg); + if (msg == CRCInput::RC_timeout) + break; + + gettimeofday(&endtime, NULL); + seconds = endtime.tv_sec - standby_pressed_at.tv_sec; + if (endtime.tv_usec < standby_pressed_at.tv_usec) + seconds--; + //printf("standby: input seconds %d\n", seconds); + if (seconds >= 1) { + if (msg == CRCInput::RC_standby) + new_msg = NeutrinoMessages::SHUTDOWN; + break; + } + } + } + } + g_RCInput->postMsg(new_msg, 0); + return messages_return::cancel_all | messages_return::handled; + } + else /* data == 1: KEY_POWER released */ + if (standby_pressed_at.tv_sec != 0) /* check if we received a KEY_POWER pressed event before */ + { /* required for correct handling of KEY_POWER events of */ + /* the power button on the dbox (not the remote control) */ + struct timeval endtime; + gettimeofday(&endtime, NULL); + time_t seconds = endtime.tv_sec - standby_pressed_at.tv_sec; + if (endtime.tv_usec < standby_pressed_at.tv_usec) + seconds--; + if (seconds >= 1) { + g_RCInput->postMsg(NeutrinoMessages::SHUTDOWN, 0); + return messages_return::cancel_all | messages_return::handled; + } + } + } + else if ((msg == CRCInput::RC_plus) || (msg == CRCInput::RC_minus)) + { + setVolume(msg, (mode != mode_scart)); + return messages_return::handled; + } +#if 0 + else if ((msg == CRCInput::RC_left) || (msg == CRCInput::RC_right)) // FIXME temp, until new remote + { + setVolume(msg, (mode != mode_scart)); + return messages_return::handled; + } +#endif + else if( msg == CRCInput::RC_spkr ) { + if( mode == mode_standby ) { + //switch lcd off/on + CVFD::getInstance()->togglePower(); + } + else { + //mute + AudioMute( !current_muted, true); + } + return messages_return::handled; + } + else if( msg == CRCInput::RC_mode ) { + videoSettings->nextMode(); + return messages_return::handled; + } + else if( msg == CRCInput::RC_next ) { + videoSettings->next43Mode(); + return messages_return::handled; + } + else if( msg == CRCInput::RC_prev ) { + videoSettings->SwitchFormat(); + return messages_return::handled; + } + /* ================================== MESSAGES ================================================ */ + else if (msg == NeutrinoMessages::EVT_VOLCHANGED) { + //setVolume(msg, false, true); + return messages_return::handled; + } + else if( msg == NeutrinoMessages::EVT_VCRCHANGED ) { + if (g_settings.vcr_AutoSwitch) { + if( data != VCR_STATUS_OFF ) + g_RCInput->postMsg( NeutrinoMessages::VCR_ON, 0 ); + else + g_RCInput->postMsg( NeutrinoMessages::VCR_OFF, 0 ); + } + return messages_return::handled | messages_return::cancel_info; + } + else if( msg == NeutrinoMessages::EVT_MUTECHANGED ) { + CControldMsg::commandMute* cmd = (CControldMsg::commandMute*) data; + if(cmd->type == (CControld::volume_type)g_settings.audio_avs_Control) + AudioMute( cmd->mute, true ); + delete[] (unsigned char*) data; + return messages_return::handled; + } + else if( msg == NeutrinoMessages::EVT_SERVICESCHANGED ) { + channelsInit(); + channelList->adjustToChannelID(live_channel_id);//FIXME what if deleted ? + if(old_b_id >= 0) { + bouquetList->activateBouquet(old_b_id, false); + old_b_id = -1; + g_RCInput->postMsg(CRCInput::RC_ok, 0); + } + } + else if( msg == NeutrinoMessages::EVT_BOUQUETSCHANGED ) { + channelsInit(); + channelList->adjustToChannelID(live_channel_id);//FIXME what if deleted ? + return messages_return::handled; + } + else if( msg == NeutrinoMessages::EVT_RECORDMODE ) { + /* sent by rcinput, then got msg from zapit about record activated/deactivated */ + dprintf(DEBUG_DEBUG, "neutino - recordmode %s\n", ( data ) ? "on":"off" ); + if(!recordingstatus && was_record && (!data)) { + g_Zapit->setStandby(true); + was_record = 0; + if( mode == mode_standby ) + cpuFreq->SetCpuFreq(g_settings.standby_cpufreq * 1000 * 1000); + } + if( mode == mode_standby && data ) + was_record = 1; + recordingstatus = data; + if( ( !g_InfoViewer->is_visible ) && data && !autoshift) + g_RCInput->postMsg( NeutrinoMessages::SHOW_INFOBAR, 0 ); + + return messages_return::handled; + } + else if (msg == NeutrinoMessages::RECORD_START) { + if( mode == mode_standby ) + cpuFreq->SetCpuFreq(g_settings.cpufreq * 1000 * 1000); + + if(autoshift) { + stopAutoRecord(); + recordingstatus = 0; + } + puts("[neutrino.cpp] executing " NEUTRINO_RECORDING_START_SCRIPT "."); + if (system(NEUTRINO_RECORDING_START_SCRIPT) != 0) + perror(NEUTRINO_RECORDING_START_SCRIPT " failed"); + /* set nextRecordingInfo to current event (replace other scheduled recording if available) */ + /* Note: CTimerd::RecordingInfo is a class! + * => typecast to avoid destructor call */ + + if (nextRecordingInfo != NULL) + delete[] (unsigned char *) nextRecordingInfo; + + nextRecordingInfo = (CTimerd::RecordingInfo *) data; + startNextRecording(); + + return messages_return::handled | messages_return::cancel_all; + } + else if( msg == NeutrinoMessages::RECORD_STOP) { + if(((CTimerd::RecordingStopInfo*)data)->eventID == recording_id) + { // passendes stop zur Aufnahme + //CVCRControl * vcr_control = CVCRControl::getInstance(); + if (CVCRControl::getInstance()->isDeviceRegistered()) { + if ((CVCRControl::getInstance()->getDeviceState() == CVCRControl::CMD_VCR_RECORD) || + (CVCRControl::getInstance()->getDeviceState() == CVCRControl::CMD_VCR_PAUSE )) + { + CVCRControl::getInstance()->Stop(); + recordingstatus = 0; + autoshift = 0; + } + else + printf("falscher state\n"); + } + else + puts("[neutrino.cpp] no recording devices"); + + startNextRecording(); + + if (recordingstatus == 0) { + puts("[neutrino.cpp] executing " NEUTRINO_RECORDING_ENDED_SCRIPT "."); + if (system(NEUTRINO_RECORDING_ENDED_SCRIPT) != 0) + perror(NEUTRINO_RECORDING_ENDED_SCRIPT " failed"); + if( mode == mode_standby ) + cpuFreq->SetCpuFreq(g_settings.standby_cpufreq * 1000 * 1000); + } + } + else if(nextRecordingInfo!=NULL) { + if(((CTimerd::RecordingStopInfo*)data)->eventID == nextRecordingInfo->eventID) { + /* Note: CTimerd::RecordingInfo is a class! + * => typecast to avoid destructor call */ + delete[] (unsigned char *) nextRecordingInfo; + nextRecordingInfo=NULL; + } + } + delete[] (unsigned char*) data; + return messages_return::handled; + } + else if( msg == NeutrinoMessages::ZAPTO) { + CTimerd::EventInfo * eventinfo; + eventinfo = (CTimerd::EventInfo *) data; + if(recordingstatus==0) { + bool isTVMode = g_Zapit->isChannelTVChannel(eventinfo->channel_id); + + dvbsub_stop(); + + if ((!isTVMode) && (mode != mode_radio)) { + radioMode(false); + } + else if (isTVMode && (mode != mode_tv)) { + tvMode(false); + } + channelList->zapTo_ChannelID(eventinfo->channel_id); + } + delete[] (unsigned char*) data; + return messages_return::handled; + } + else if( msg == NeutrinoMessages::ANNOUNCE_ZAPTO) { + if( mode == mode_standby ) { + standbyMode( false ); + } + if( mode != mode_scart ) { + std::string name = g_Locale->getText(LOCALE_ZAPTOTIMER_ANNOUNCE); + + CTimerd::TimerList tmpTimerList; + CTimerdClient tmpTimerdClient; + + tmpTimerList.clear(); + tmpTimerdClient.getTimerList( tmpTimerList ); + + if(tmpTimerList.size() > 0) { + sort( tmpTimerList.begin(), tmpTimerList.end() ); + + CTimerd::responseGetTimer &timer = tmpTimerList[0]; + + CZapitClient Zapit; + name += "\n"; + + std::string zAddData = Zapit.getChannelName( timer.channel_id ); // UTF-8 + if( zAddData.empty()) { + zAddData = g_Locale->getText(LOCALE_TIMERLIST_PROGRAM_UNKNOWN); + } + + if(timer.epgID!=0) { + CEPGData epgdata; + zAddData += " :\n"; + //if (g_Sectionsd->getEPGid(timer.epgID, timer.epg_starttime, &epgdata)) + if (sectionsd_getEPGid(timer.epgID, timer.epg_starttime, &epgdata)) { + zAddData += epgdata.title; + } + else if(strlen(timer.epgTitle)!=0) { + zAddData += timer.epgTitle; + } + } + else if(strlen(timer.epgTitle)!=0) { + zAddData += timer.epgTitle; + } + + name += zAddData; + } + ShowHintUTF( LOCALE_MESSAGEBOX_INFO, name.c_str() ); + } + + return messages_return::handled; + } + else if( msg == NeutrinoMessages::ANNOUNCE_RECORD) { + system(NEUTRINO_RECORDING_TIMER_SCRIPT); + if( g_settings.recording_server_wakeup ) { + std::string command = "etherwake "; + command += g_settings.recording_server_mac; + if(system(command.c_str()) != 0) + perror("etherwake failed"); + } + if (g_settings.recording_type == RECORDING_FILE) { + char * recDir = ((CTimerd::RecordingInfo*)data)->recordingDir; + for(int i=0 ; i < NETWORK_NFS_NR_OF_ENTRIES ; i++) { + if (strcmp(g_settings.network_nfs_local_dir[i],recDir) == 0) { + printf("[neutrino] waking up %s (%s)\n",g_settings.network_nfs_ip[i].c_str(),recDir); + std::string command = "etherwake "; + command += g_settings.network_nfs_mac[i]; + if(system(command.c_str()) != 0) + perror("etherwake failed"); + break; + } + } + if(autoshift) { + stopAutoRecord(); + recordingstatus = 0; + } + if(has_hdd) { + system("(rm /media/sda1/.wakeup; touch /media/sda1/.wakeup; sync) > /dev/null 2> /dev/null &"); // wakeup hdd + } + } + if( g_settings.recording_zap_on_announce ) { + if(recordingstatus==0) { + dvbsub_stop(); //FIXME if same channel ? + t_channel_id channel_id=((CTimerd::RecordingInfo*)data)->channel_id; + g_Zapit->zapTo_serviceID_NOWAIT(channel_id); + } + } + delete[] (unsigned char*) data; + if( mode != mode_scart ) + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_RECORDTIMER_ANNOUNCE)); + return messages_return::handled; + } + else if( msg == NeutrinoMessages::ANNOUNCE_SLEEPTIMER) { + if( mode != mode_scart ) + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_SLEEPTIMERBOX_ANNOUNCE)); + return messages_return::handled; + } + else if( msg == NeutrinoMessages::SLEEPTIMER) { + if(g_settings.shutdown_real) + ExitRun(true); + else + standbyMode( true ); + return messages_return::handled; + } + else if( msg == NeutrinoMessages::STANDBY_TOGGLE ) { + standbyMode( !(mode & mode_standby) ); + g_RCInput->clearRCMsg(); + return messages_return::handled; + } + else if( msg == NeutrinoMessages::STANDBY_ON ) { + if( mode != mode_standby ) { + standbyMode( true ); + } + g_RCInput->clearRCMsg(); + return messages_return::handled; + } + else if( msg == NeutrinoMessages::STANDBY_OFF ) { + if( mode == mode_standby ) { + standbyMode( false ); + } + g_RCInput->clearRCMsg(); + return messages_return::handled; + } + else if( msg == NeutrinoMessages::ANNOUNCE_SHUTDOWN) { + if( mode != mode_scart ) + skipShutdownTimer = (ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_SHUTDOWNTIMER_ANNOUNCE, CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo, NULL, 450, 5) == CMessageBox::mbrYes); + } + else if( msg == NeutrinoMessages::SHUTDOWN ) { + if(!skipShutdownTimer) { + ExitRun(true); + } + else { + skipShutdownTimer=false; + } + return messages_return::handled; + } + else if (msg == NeutrinoMessages::EVT_POPUP) { + if (mode != mode_scart) + ShowHintUTF(LOCALE_MESSAGEBOX_INFO, (const char *) data); // UTF-8 + delete (unsigned char*) data; + return messages_return::handled; + } + else if (msg == NeutrinoMessages::EVT_EXTMSG) { + if (mode != mode_scart) + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, (const char *) data, CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); // UTF-8 + delete[] (unsigned char*) data; + return messages_return::handled; + } + else if (msg == NeutrinoMessages::EVT_RECORDING_ENDED) { + if (mode != mode_scart) { + neutrino_locale_t msgbody; + if ((* (stream2file_status2_t *) data).status == STREAM2FILE_STATUS_BUFFER_OVERFLOW) + msgbody = LOCALE_STREAMING_BUFFER_OVERFLOW; + else if ((* (stream2file_status2_t *) data).status == STREAM2FILE_STATUS_WRITE_OPEN_FAILURE) + msgbody = LOCALE_STREAMING_WRITE_ERROR_OPEN; + else if ((* (stream2file_status2_t *) data).status == STREAM2FILE_STATUS_WRITE_FAILURE) + msgbody = LOCALE_STREAMING_WRITE_ERROR; + else + goto skip_message; + + /* use a short timeout of only 5 seconds in case it was only a temporary network problem + * in case of STREAM2FILE_STATUS_IDLE we might even have to immediately start the next recording */ + ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, msgbody, CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO, 450, 5); + +skip_message: + ; + } + if ((* (stream2file_status2_t *) data).status != STREAM2FILE_STATUS_IDLE) { + /* + * note that changeNotify does not distinguish between LOCALE_MAINMENU_RECORDING_START and LOCALE_MAINMENU_RECORDING_STOP + * instead it checks the state of the variable recordingstatus + */ + /* restart recording */ + //FIXME doGuiRecord((*(stream2file_status2_t *) data).dir); + //changeNotify(LOCALE_MAINMENU_RECORDING_START, data); + } + + delete[] (unsigned char*) data; + return messages_return::handled; + } + else if( msg == NeutrinoMessages::REMIND) { + std::string text = (char*)data; + std::string::size_type pos; + while((pos=text.find('/'))!= std::string::npos) + { + text[pos] = '\n'; + } + if( mode != mode_scart ) + ShowMsgUTF(LOCALE_TIMERLIST_TYPE_REMIND, text, CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); // UTF-8 + delete[] (unsigned char*) data; + return messages_return::handled; + } + else if (msg == NeutrinoMessages::LOCK_RC) { + this->rcLock->exec(NULL,CRCLock::NO_USER_INPUT); + return messages_return::handled; + } + else if( msg == NeutrinoMessages::CHANGEMODE ) { + int newmode = data & mode_mask; + + if((data & mode_mask)== mode_radio) { + if( mode != mode_radio ) { + if((data & norezap)==norezap) + radioMode(false); + else + radioMode(true); + } + } + if((data & mode_mask)== mode_tv) { + if( mode != mode_tv ) { + if((data & norezap)==norezap) + tvMode(false); + else + tvMode(true); + } + } + if((data &mode_mask)== mode_standby) { + if(mode != mode_standby) + standbyMode( true ); + } + if((data &mode_mask)== mode_audio) { + lastMode=mode; + mode=mode_audio; + } + if((data &mode_mask)== mode_pic) { + lastMode=mode; + mode=mode_pic; + } + if((data &mode_mask)== mode_ts) { + if(mode == mode_radio) + videoDecoder->StopPicture(); + lastMode=mode; + mode=mode_ts; + } + } + else if( msg == NeutrinoMessages::VCR_ON ) { + if( mode != mode_scart ) { + scartMode( true ); + } + else + CVFD::getInstance()->setMode(CVFD::MODE_SCART); + } + + else if( msg == NeutrinoMessages::VCR_OFF ) { + if( mode == mode_scart ) { + scartMode( false ); + } + } + else if (msg == NeutrinoMessages::EVT_START_PLUGIN) { + g_PluginList->startPlugin((const char *)data); + if (!g_PluginList->getScriptOutput().empty()) { + ShowMsgUTF(LOCALE_PLUGINS_RESULT, g_PluginList->getScriptOutput(), CMessageBox::mbrBack,CMessageBox::mbBack,NEUTRINO_ICON_SHELL); + } + + delete[] (unsigned char*) data; + return messages_return::handled; + } + else if (msg == NeutrinoMessages::EVT_SERVICES_UPD) { + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_ZAPIT_SDTCHANGED), + CMessageBox::mbrBack,CMessageBox::mbBack, NEUTRINO_ICON_INFO); + } + if ((msg >= CRCInput::RC_WithData) && (msg < CRCInput::RC_WithData + 0x10000000)) + delete [] (unsigned char*) data; + + return messages_return::unhandled; +} + +void CNeutrinoApp::ExitRun(const bool write_si, int retcode) +{ + if (!recordingstatus || + ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_SHUTDOWN_RECODING_QUERY, CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo, NULL, 450, 30, true) == CMessageBox::mbrYes) + { + if(recordingstatus) { + CVCRControl::getInstance()->Stop(); + g_Timerd->stopTimerEvent(recording_id); + } + CVFD::getInstance()->setMode(CVFD::MODE_SHUTDOWN); + + dprintf(DEBUG_INFO, "exit\n"); + g_Zapit->stopPlayBack(); + + frameBuffer->paintBackground(); + videoDecoder->ShowPicture(DATADIR "/neutrino/icons/shutdown.jpg"); + + networkConfig.automatic_start = (network_automatic_start == 1); + networkConfig.commitConfig(); + saveSetup(NEUTRINO_SETTINGS_FILE); + + if(g_settings.epg_save /* && timeset && g_Sectionsd->getIsTimeSet ()*/) { + saveEpg(); + } + + if(retcode) { + neutrino_msg_t msg; + neutrino_msg_data_t data; + + printf("entering off state\n"); + mode = mode_off; + + stop_daemons(false); + + system("/bin/sync"); + system("/bin/umount -a"); + cpuFreq->SetCpuFreq(g_settings.standby_cpufreq * 1000 * 1000); + powerManager->SetStandby(true, true); + int fspeed = 0; + funNotifier->changeNotify(NONEXISTANT_LOCALE, (void *) &fspeed); + + if (powerManager) { + powerManager->Close(); + delete powerManager; + } + + delete moviePlayerGui; + shutdown_cs_api(); + + system("/etc/init.d/rcK"); + CVFD::getInstance()->ShowIcon(VFD_ICON_CAM1, true); + InfoClock->StopClock(); + + g_RCInput->clearRCMsg(); + while( true ) { + g_RCInput->getMsg(&msg, &data, 10000); + if( msg == CRCInput::RC_standby ) { + printf("Power key, going to reboot...\n"); + sleep(2); + reboot(LINUX_REBOOT_CMD_RESTART); + } else if( ( msg == NeutrinoMessages::ANNOUNCE_RECORD) || ( msg == NeutrinoMessages::ANNOUNCE_ZAPTO) ) { + printf("Zap/record timer, going to reboot...\n"); + sleep(2); + reboot(LINUX_REBOOT_CMD_RESTART); + } + } + } else { + if (g_RCInput != NULL) + delete g_RCInput; + + stop_daemons(); + + int fspeed = 0; + funNotifier->changeNotify(NONEXISTANT_LOCALE, (void *) &fspeed); + exit(retcode); + } + } +} +void CNeutrinoApp::saveEpg() +{ + struct stat my_stat; + if(stat(g_settings.epg_dir.c_str(), &my_stat) == 0){ + printf("Saving EPG to %s....\n", g_settings.epg_dir.c_str()); + neutrino_msg_t msg; + neutrino_msg_data_t data; + g_Sectionsd->writeSI2XML(g_settings.epg_dir.c_str()); + while( true ) { + g_RCInput->getMsg(&msg, &data, 300); // 30 secs.. + if (( msg == CRCInput::RC_timeout ) || (msg == NeutrinoMessages::EVT_SI_FINISHED)) { + //printf("Msg %x timeout %d EVT_SI_FINISHED %x\n", msg, CRCInput::RC_timeout, NeutrinoMessages::EVT_SI_FINISHED); + break; + } + } + } +} +void CNeutrinoApp::AudioMute( int newValue, bool isEvent ) +{ + //printf("MUTE: val %d current %d event %d\n", newValue, current_muted, isEvent); + int dx = 40; + int dy = 40; + int x = g_settings.screen_EndX-dx; + int y = g_settings.screen_StartY; + + CVFD::getInstance()->setMuted(newValue); + current_muted = newValue; + +printf("AudioMute: current %d new %d isEvent: %d\n", current_muted, newValue, isEvent); + //if( !isEvent ) + g_Zapit->muteAudio(current_muted); + + if( isEvent && ( mode != mode_scart ) && ( mode != mode_audio) && ( mode != mode_pic)) + { + if( current_muted ) { + frameBuffer->paintBoxRel(x, y, dx, dy, COL_INFOBAR_PLUS_0); + frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MUTE, x+5, y+5); + } + else + frameBuffer->paintBackgroundBoxRel(x, y, dx, dy); + } +} + +void CNeutrinoApp::setvol(int vol, int avs) +{ + audioDecoder->setVolume(vol, vol); +} + +void CNeutrinoApp::setVolume(const neutrino_msg_t key, const bool bDoPaint, bool nowait) +{ + neutrino_msg_t msg = key; + + int dx = 256; + int dy = 40; +#if 0 // orig + int x = (((g_settings.screen_EndX- g_settings.screen_StartX)- dx) / 2) + g_settings.screen_StartX; + int y = g_settings.screen_EndY - 100; +#else + + int x = frameBuffer->getScreenX() + 10; + int y = frameBuffer->getScreenY() + 0; +#endif + int vol = g_settings.current_volume; + + fb_pixel_t * pixbuf = NULL; + + if(bDoPaint) { + pixbuf = new fb_pixel_t[dx * dy]; + if(pixbuf!= NULL) + frameBuffer->SaveScreen(x, y, dx, dy, pixbuf); + + frameBuffer->paintIcon("volume.raw",x,y, COL_INFOBAR); + frameBuffer->paintBoxRel (x + 40, y+12, 200, 15, COL_INFOBAR_PLUS_0); + g_volscale->reset(); + g_volscale->paint(x + 41, y + 12, g_settings.current_volume); + } + + neutrino_msg_data_t data; + + unsigned long long timeoutEnd; + + do { + if (msg <= CRCInput::RC_MaxRC) { + if (msg == CRCInput::RC_plus || msg == CRCInput::RC_right) { //FIXME + if (g_settings.current_volume < 100 - 2) + g_settings.current_volume += 2; + else + g_settings.current_volume = 100; + } + else if (msg == CRCInput::RC_minus || msg == CRCInput::RC_left) { //FIXME + if (g_settings.current_volume > 2) + g_settings.current_volume -= 2; + else + g_settings.current_volume = 0; + } + else { + g_RCInput->postMsg(msg, data); + break; + } + + setvol(g_settings.current_volume,(g_settings.audio_avs_Control)); + //timeoutEnd = CRCInput::calcTimeoutEnd(nowait ? 1 : g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR] / 2); + timeoutEnd = CRCInput::calcTimeoutEnd(nowait ? 1 : 3); + } + else if (msg == NeutrinoMessages::EVT_VOLCHANGED) { + //current_volume = g_Controld->getVolume((CControld::volume_type)g_settings.audio_avs_Control);//FIXME +//printf("setVolume EVT_VOLCHANGED %d\n", current_volume); + //timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_INFOBAR] / 2); + timeoutEnd = CRCInput::calcTimeoutEnd(3); + } + else if (handleMsg(msg, data) & messages_return::unhandled) { + g_RCInput->postMsg(msg, data); + break; + } + + if (bDoPaint) { + if(vol != g_settings.current_volume) { + vol = g_settings.current_volume; + g_volscale->paint(x + 41, y + 12, g_settings.current_volume); + } + } + + CVFD::getInstance()->showVolume(g_settings.current_volume); + if (msg != CRCInput::RC_timeout) { + g_RCInput->getMsgAbsoluteTimeout(&msg, &data, &timeoutEnd ); + } + } while (msg != CRCInput::RC_timeout); + + //frameBuffer->paintBackgroundBoxRel(x, y, dx, dy); //FIXME osd bug + + if( (bDoPaint) && (pixbuf!= NULL) ) { + frameBuffer->RestoreScreen(x, y, dx, dy, pixbuf); + delete [] pixbuf; + } +} + +void CNeutrinoApp::tvMode( bool rezap ) +{ + if(mode==mode_radio ) { + videoDecoder->StopPicture(); + g_RCInput->killTimer(g_InfoViewer->lcdUpdateTimer); + g_InfoViewer->lcdUpdateTimer = g_RCInput->addTimer( LCD_UPDATE_TIME_TV_MODE, false ); + CVFD::getInstance()->ShowIcon(VFD_ICON_RADIO, false); + if(!rezap) + dvbsub_start(0); + } + + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + CVFD::getInstance()->ShowIcon(VFD_ICON_TV, true); + + if( mode == mode_tv ) { + if(g_settings.mode_clock) { + InfoClock->StopClock(); + g_settings.mode_clock=false; + } else { + InfoClock->StartClock(); + g_settings.mode_clock=true; + } + return; + } else if( mode == mode_scart ) { + //g_Controld->setScartMode( 0 ); + } else if( mode == mode_standby ) { + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + videoDecoder->Standby(false); + } + + bool stopauto = (mode != mode_ts); + mode = mode_tv; + if(stopauto && autoshift) { +//printf("standby on: autoshift ! stopping ...\n"); + stopAutoRecord(); + recordingstatus = 0; + } + + frameBuffer->useBackground(false); + frameBuffer->paintBackground(); + + g_RemoteControl->tvMode(); + SetChannelMode(g_settings.channel_mode);//FIXME needed ? + if( rezap ) { + firstChannel(); + channelList->tuned = 0xfffffff;; + channelList->zapTo( firstchannel.channelNumber -1 ); + } +#ifdef USEACTIONLOG + g_ActionLog->println("mode: tv"); +#endif +} + +void CNeutrinoApp::scartMode( bool bOnOff ) +{ + //printf( ( bOnOff ) ? "mode: scart on\n" : "mode: scart off\n" ); + + if( bOnOff ) { + // SCART AN + frameBuffer->useBackground(false); + frameBuffer->paintBackground(); + + //g_Controld->setScartMode( 1 ); + CVFD::getInstance()->setMode(CVFD::MODE_SCART); + lastMode = mode; + mode = mode_scart; + } else { + // SCART AUS + //g_Controld->setScartMode( 0 ); + + mode = mode_unknown; + //re-set mode + if( lastMode == mode_radio ) { + radioMode( false ); + } + else if( lastMode == mode_tv ) { + tvMode( false ); + } + else if( lastMode == mode_standby ) { + standbyMode( true ); + } + } +} + +void CNeutrinoApp::standbyMode( bool bOnOff ) +{ + static bool wasshift = false; +//printf("********* CNeutrinoApp::standbyMode, was_record %d bOnOff %d\n", was_record, bOnOff); + //printf( ( bOnOff ) ? "mode: standby on\n" : "mode: standby off\n" ); + if( bOnOff ) { + puts("[neutrino.cpp] executing " NEUTRINO_ENTER_STANDBY_SCRIPT "."); + if (system(NEUTRINO_ENTER_STANDBY_SCRIPT) != 0) + perror(NEUTRINO_ENTER_STANDBY_SCRIPT " failed"); + + if(autoshift) { + stopAutoRecord(); + wasshift = true; + recordingstatus = 0; + } + if( mode == mode_scart ) { + //g_Controld->setScartMode( 0 ); + } + dvbsub_pause(); + + frameBuffer->useBackground(false); + frameBuffer->paintBackground(); + + CVFD::getInstance()->Clear(); + CVFD::getInstance()->setMode(CVFD::MODE_STANDBY); + + videoDecoder->Standby(true); + if(recordingstatus) was_record = 1; + if(!was_record) { + g_Zapit->setStandby(true); + system("hdparm -y /dev/ide/host0/bus0/target0/lun0/disc >/dev/null 2>/dev/null"); + } else + g_Zapit->stopPlayBack(); + + g_Sectionsd->setPauseScanning(true); + if(g_settings.epg_save) { + saveEpg(); + } + if(g_settings.mode_clock) + InfoClock->StopClock(); + + + lastMode = mode; + mode = mode_standby; + int fspeed = 1; + funNotifier->changeNotify(NONEXISTANT_LOCALE, (void *) &fspeed); + + frameBuffer->setActive(false); + // Active standby on + powerManager->SetStandby(true, false); + if(!was_record) + cpuFreq->SetCpuFreq(g_settings.standby_cpufreq * 1000 * 1000); + } else { + // Active standby off + cpuFreq->SetCpuFreq(g_settings.cpufreq * 1000 * 1000); + + powerManager->SetStandby(false, false); + frameBuffer->setActive(true); + + funNotifier->changeNotify(NONEXISTANT_LOCALE, (void*) &g_settings.fan_speed); + puts("[neutrino.cpp] executing " NEUTRINO_LEAVE_STANDBY_SCRIPT "."); + if (system(NEUTRINO_LEAVE_STANDBY_SCRIPT) != 0) + perror(NEUTRINO_LEAVE_STANDBY_SCRIPT " failed"); + + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + g_Zapit->setStandby(false); + if(was_record) + g_Zapit->startPlayBack(); + if(recordingstatus) was_record = 0; + + videoDecoder->Standby(false); + g_Sectionsd->setPauseScanning(false); + + if(g_settings.mode_clock) + InfoClock->StartClock(); + + mode = mode_unknown; + if( lastMode == mode_radio ) { + radioMode( false ); + } else { + tvMode( false ); + } + AudioMute(current_muted, false ); + if((mode == mode_tv) && wasshift) { + startAutoRecord(true); + } + wasshift = false; + dvbsub_start(0); + } +} + +void CNeutrinoApp::radioMode( bool rezap) +{ +printf("radioMode: rezap %s\n", rezap ? "yes" : "no"); + if(mode==mode_tv ) { + g_RCInput->killTimer(g_InfoViewer->lcdUpdateTimer); + g_InfoViewer->lcdUpdateTimer = g_RCInput->addTimer( LCD_UPDATE_TIME_RADIO_MODE, false ); + CVFD::getInstance()->ShowIcon(VFD_ICON_TV, false); + dvbsub_pause(); + } + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + CVFD::getInstance()->ShowIcon(VFD_ICON_RADIO, true); + + if( mode==mode_radio ) { + if(g_settings.mode_clock) { + InfoClock->StopClock(); + g_settings.mode_clock=false; + } else { + InfoClock->StartClock(); + g_settings.mode_clock=true; + } + return; + } + else if( mode == mode_scart ) { + //g_Controld->setScartMode( 0 ); + } + else if( mode == mode_standby ) { + CVFD::getInstance()->setMode(CVFD::MODE_TVRADIO); + videoDecoder->Standby(false); + } + mode = mode_radio; + if(autoshift) { +//printf("standby on: autoshift ! stopping ...\n"); + stopAutoRecord(); + recordingstatus = 0; + } + + g_RemoteControl->radioMode(); + SetChannelMode(g_settings.channel_mode);//FIXME needed? + if( rezap ) { + firstChannel(); + channelList->tuned = 0xfffffff;; + channelList->zapTo( firstchannel.channelNumber -1 ); + } + videoDecoder->ShowPicture(DATADIR "/neutrino/icons/radiomode.jpg"); +} + +void CNeutrinoApp::startNextRecording() +{ + if ((recordingstatus == 0) && (nextRecordingInfo != NULL)) { + bool doRecord = true; + if (CVCRControl::getInstance()->isDeviceRegistered()) { + recording_id = nextRecordingInfo->eventID; + if (g_settings.recording_type == RECORDING_FILE) { + char *recDir = strlen(nextRecordingInfo->recordingDir) > 0 ? + nextRecordingInfo->recordingDir : g_settings.network_nfs_recordingdir; + if (!CFSMounter::isMounted(recDir)) { + doRecord = false; + for(int i=0 ; i < NETWORK_NFS_NR_OF_ENTRIES ; i++) { + if (strcmp(g_settings.network_nfs_local_dir[i],recDir) == 0) { + CFSMounter::MountRes mres = + CFSMounter::mount(g_settings.network_nfs_ip[i].c_str(), g_settings.network_nfs_dir[i], + g_settings.network_nfs_local_dir[i], (CFSMounter::FSType) g_settings.network_nfs_type[i], + g_settings.network_nfs_username[i], g_settings.network_nfs_password[i], + g_settings.network_nfs_mount_options1[i], g_settings.network_nfs_mount_options2[i]); + if (mres == CFSMounter::MRES_OK) { + doRecord = true; + } else { + const char * merr = mntRes2Str(mres); + int msglen = strlen(merr) + strlen(nextRecordingInfo->recordingDir) + 7; + char msg[msglen]; + strcpy(msg,merr); + strcat(msg,"\nDir: "); + strcat(msg,nextRecordingInfo->recordingDir); + + ShowHintUTF(LOCALE_MESSAGEBOX_ERROR, msg); // UTF-8 + doRecord = false; + } + break; + } + } + if (!doRecord) { + // recording dir does not seem to exist in config anymore + // or an error occured while mounting + // -> try default dir + recDir = g_settings.network_nfs_recordingdir; + doRecord = true; + } + } + (static_cast(recordingdevice))->Directory = std::string(recDir); +printf("CNeutrinoApp::startNextRecording: start to dir %s\n", recDir); + } + if(doRecord && CVCRControl::getInstance()->Record(nextRecordingInfo)) + recordingstatus = 1; + else + recordingstatus = 0; + } + else + puts("[neutrino.cpp] no recording devices"); + + /* Note: CTimerd::RecordingInfo is a class! + * What a brilliant idea to send classes via the eventserver! + * => typecast to avoid destructor call + */ + delete [](unsigned char *)nextRecordingInfo; + + nextRecordingInfo = NULL; + } +} +/************************************************************************************** +* CNeutrinoApp - exec, menuitem callback (shutdown) * +**************************************************************************************/ +void SaveMotorPositions(); +int CNeutrinoApp::exec(CMenuTarget* parent, const std::string & actionKey) +{ + // printf("ac: %s\n", actionKey.c_str()); + int returnval = menu_return::RETURN_REPAINT; + + if(actionKey == "help_recording") { + ShowLocalizedMessage(LOCALE_SETTINGS_HELP, LOCALE_RECORDINGMENU_HELP, CMessageBox::mbrBack, CMessageBox::mbBack); + } + else if(actionKey=="shutdown") { + ExitRun(true, 1); + } + else if(actionKey=="reboot") + { + FILE *f = fopen("/tmp/.reboot", "w"); + fclose(f); + ExitRun(true); + unlink("/tmp/.reboot"); + returnval = menu_return::RETURN_NONE; + } + else if(actionKey=="tv") { + tvMode(); + returnval = menu_return::RETURN_EXIT_ALL; + } + else if(actionKey=="radio") { + radioMode(); + returnval = menu_return::RETURN_EXIT_ALL; + } + else if(actionKey=="scart") { + g_RCInput->postMsg( NeutrinoMessages::VCR_ON, 0 ); + returnval = menu_return::RETURN_EXIT_ALL; + } + else if(actionKey=="network") { + networkConfig.automatic_start = (network_automatic_start == 1); + networkConfig.stopNetwork(); + networkConfig.commitConfig(); + networkConfig.startNetwork(); + } + else if(actionKey=="networktest") { + dprintf(DEBUG_INFO, "doing network test...\n"); + testNetworkSettings(networkConfig.address.c_str(), networkConfig.netmask.c_str(), networkConfig.broadcast.c_str(), networkConfig.gateway.c_str(), networkConfig.nameserver.c_str(), networkConfig.inet_static); + } + else if(actionKey=="networkshow") { + dprintf(DEBUG_INFO, "showing current network settings...\n"); + showCurrentNetworkSettings(); + } + else if (actionKey=="theme_neutrino") { + setupColors_neutrino(); + colorSetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + } + else if (actionKey=="theme_classic") { + setupColors_classic(); + colorSetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + } + else if (actionKey=="theme_dblue") { + setupColors_dblue(); + colorSetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + } + else if (actionKey=="theme_dvb2k") { + setupColors_dvb2k(); + colorSetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + } + else if(actionKey=="theme_ru") { + setupColors_ru(); + colorSetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + } + else if(actionKey=="theme_red") { + setupColors_red(); + colorSetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + } + else if(actionKey=="savescansettings") { + SaveMotorPositions(); + } + else if(actionKey=="savesettings") { + CHintBox * hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_MAINSETTINGS_SAVESETTINGSNOW_HINT)); // UTF-8 + hintBox->paint(); + + networkConfig.automatic_start = (network_automatic_start == 1); + networkConfig.commitConfig(); + saveSetup(NEUTRINO_SETTINGS_FILE); + SaveMotorPositions(); + + zapitCfg.gotoXXLatitude = strtod(zapit_lat, NULL); + zapitCfg.gotoXXLongitude = strtod(zapit_long, NULL); + + setZapitConfig(&zapitCfg); + if(g_settings.cacheTXT) { + tuxtxt_init(); + } else + tuxtxt_close(); + + //g_Sectionsd->setEventsAreOldInMinutes((unsigned short) (g_settings.epg_old_hours*60)); + //g_Sectionsd->setHoursToCache((unsigned short) (g_settings.epg_cache_days*24)); + + hintBox->hide(); + delete hintBox; + } + else if(actionKey=="recording") { + setupRecordingDevice(); + } + else if(actionKey=="reloadchannels") { + //reloadhintBox->paint(); + g_Zapit->reinitChannels(); +#if 0 + system(mode == mode_radio + ? "wget -q -O /dev/null http://127.0.0.1/control/setmode?radio > /dev/null 2>&1" + : "wget -q -O /dev/null http://127.0.0.1/control/setmode?tv > /dev/null 2>&1"); +#endif + //reloadhintBox->hide(); + + } + else if(actionKey=="reloadplugins") { + CHintBox * hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_SERVICEMENU_GETPLUGINS_HINT)); + hintBox->paint(); + + g_PluginList->loadPlugins(); + + hintBox->hide(); + delete hintBox; + } + else if(actionKey=="restart") { + if (recordingstatus) + DisplayErrorMessage(g_Locale->getText(LOCALE_SERVICEMENU_RESTART_REFUSED_RECORDING)); + else { + CHintBox * hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_SERVICEMENU_RESTART_HINT)); + hintBox->paint(); + + stop_daemons(); + + delete g_RCInput; + delete g_Sectionsd; + delete g_Timerd; + delete g_RemoteControl; + delete g_fontRenderer; + delete g_Zapit; + delete CVFD::getInstance(); + + networkConfig.automatic_start = (network_automatic_start == 1); + networkConfig.commitConfig(); + saveSetup(NEUTRINO_SETTINGS_FILE); + delete frameBuffer; + execvp(global_argv[0], global_argv); // no return if successful + exit(1); + } + } + else if(strncmp(actionKey.c_str(), "fontsize.d", 10) == 0) { + for (int i = 0; i < 6; i++) { + if (actionKey == font_sizes_groups[i].actionkey) + for (unsigned int j = 0; j < font_sizes_groups[i].count; j++) { + SNeutrinoSettings::FONT_TYPES k = font_sizes_groups[i].content[j]; + configfile.setInt32(locale_real_names[neutrino_font[k].name], neutrino_font[k].defaultsize); + } + } + fontsizenotifier.changeNotify(NONEXISTANT_LOCALE, NULL); + } + else if(actionKey=="osd.def") { + for (int i = 0; i < TIMING_SETTING_COUNT; i++) + g_settings.timing[i] = default_timing[i]; + + SetupTiming(); + } + else if(actionKey == "audioplayerdir") { + parent->hide(); + CFileBrowser b; + b.Dir_Mode=true; + if (b.exec(g_settings.network_nfs_audioplayerdir)) + strncpy(g_settings.network_nfs_audioplayerdir, b.getSelectedFile()->Name.c_str(), sizeof(g_settings.network_nfs_audioplayerdir)-1); + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "picturedir") { + parent->hide(); + CFileBrowser b; + b.Dir_Mode=true; + if (b.exec(g_settings.network_nfs_picturedir)) + strncpy(g_settings.network_nfs_picturedir, b.getSelectedFile()->Name.c_str(), sizeof(g_settings.network_nfs_picturedir)-1); + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "moviedir") { + parent->hide(); + CFileBrowser b; + b.Dir_Mode=true; + if (b.exec(g_settings.network_nfs_moviedir)) + strncpy(g_settings.network_nfs_moviedir, b.getSelectedFile()->Name.c_str(), sizeof(g_settings.network_nfs_moviedir)-1); + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "recordingdir") { + parent->hide(); + CFileBrowser b; + b.Dir_Mode=true; + if (b.exec(g_settings.network_nfs_recordingdir)) { + const char * newdir = b.getSelectedFile()->Name.c_str(); +printf("New recordingdir: selected %s\n", newdir); + if(check_dir(newdir)) + printf("Wrong/unsupported recording dir %s\n", newdir); + else { + strncpy(g_settings.network_nfs_recordingdir, b.getSelectedFile()->Name.c_str(), sizeof(g_settings.network_nfs_recordingdir)-1); +printf("New recordingdir: %s (timeshift %s)\n", g_settings.network_nfs_recordingdir, g_settings.timeshiftdir); + if(strlen(g_settings.timeshiftdir) == 0) { + sprintf(timeshiftDir, "%s/.timeshift", g_settings.network_nfs_recordingdir); + safe_mkdir(timeshiftDir); +printf("New timeshift dir: %s\n", timeshiftDir); + } + } + } + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "timeshiftdir") { + parent->hide(); + CFileBrowser b; + b.Dir_Mode=true; + if (b.exec(g_settings.timeshiftdir)) { + const char * newdir = b.getSelectedFile()->Name.c_str(); +printf("New timeshift: selected %s\n", newdir); + if(check_dir(newdir)) + printf("Wrong/unsupported recording dir %s\n", newdir); + else { +printf("New timeshift dir: old %s (record %s)\n", g_settings.timeshiftdir, g_settings.network_nfs_recordingdir); + if(strcmp(newdir, g_settings.network_nfs_recordingdir)) { +printf("New timeshift != rec dir\n"); + strncpy(g_settings.timeshiftdir, b.getSelectedFile()->Name.c_str(), sizeof(g_settings.timeshiftdir)-1); + strcpy(timeshiftDir, g_settings.timeshiftdir); + } else { + sprintf(timeshiftDir, "%s/.timeshift", g_settings.network_nfs_recordingdir); + strcpy(g_settings.timeshiftdir, newdir); + safe_mkdir(timeshiftDir); +printf("New timeshift == rec dir\n"); + } +printf("New timeshift dir: %s\n", timeshiftDir); + } + } + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "update_dir") { + parent->hide(); + CFileBrowser fileBrowser; + fileBrowser.Dir_Mode = true; + if (fileBrowser.exec(g_settings.update_dir) == true) { + const char * newdir = fileBrowser.getSelectedFile()->Name.c_str(); + if(check_dir(newdir)) + printf("Wrong/unsupported recording dir %s\n", newdir); + else { + strcpy(g_settings.update_dir, fileBrowser.getSelectedFile()->Name.c_str()); + printf("[neutrino] new update dir %s\n", fileBrowser.getSelectedFile()->Name.c_str()); + } + } + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "epgdir") { + parent->hide(); + CFileBrowser b; + b.Dir_Mode=true; + if (b.exec(g_settings.epg_dir.c_str())) { + const char * newdir = b.getSelectedFile()->Name.c_str(); + if(check_dir(newdir)) + printf("Wrong/unsupported epg dir %s\n", newdir); + else { + g_settings.epg_dir = b.getSelectedFile()->Name; + SendSectionsdConfig(); + } + } + + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "select_font") { + parent->hide(); + CFileBrowser fileBrowser; + CFileFilter fileFilter; + fileFilter.addFilter("ttf"); + fileBrowser.Filter = &fileFilter; + if (fileBrowser.exec(FONTDIR) == true) { + strcpy(g_settings.font_file, fileBrowser.getSelectedFile()->Name.c_str()); + printf("[neutrino] new font file %s\n", fileBrowser.getSelectedFile()->Name.c_str()); + SetupFonts(); + } + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "movieplugin") { + parent->hide(); + CMenuWidget MoviePluginSelector(LOCALE_MOVIEPLAYER_DEFPLUGIN, "features.raw", 350); + MoviePluginSelector.addItem(GenericMenuSeparator); + + char id[5]; + int cnt = 0; + int enabled_count = 0; + for(unsigned int count=0;count < (unsigned int) g_PluginList->getNumberOfPlugins();count++) { + if (g_PluginList->getType(count)== CPlugins::P_TYPE_TOOL && !g_PluginList->isHidden(count)) { + // zB vtxt-plugins + sprintf(id, "%d", count); + enabled_count++; + MoviePluginSelector.addItem(new CMenuForwarderNonLocalized(g_PluginList->getName(count), true, NULL, MoviePluginChanger, id, CRCInput::convertDigitToKey(count)), (cnt == 0)); + cnt++; + } + } + + MoviePluginSelector.exec(NULL, ""); + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "onekeyplugin") { + parent->hide(); + CMenuWidget MoviePluginSelector(LOCALE_EXTRA_KEY_PLUGIN, "features.raw", 350); + MoviePluginSelector.addItem(GenericMenuSeparator); + + char id[5]; + int cnt = 0; + int enabled_count = 0; + for(unsigned int count=0;count < (unsigned int) g_PluginList->getNumberOfPlugins();count++) { + if (g_PluginList->getType(count)== CPlugins::P_TYPE_TOOL && !g_PluginList->isHidden(count)) { + // zB vtxt-plugins + sprintf(id, "%d", count); + enabled_count++; + MoviePluginSelector.addItem(new CMenuForwarderNonLocalized(g_PluginList->getName(count), true, NULL, OnekeyPluginChanger, id, CRCInput::convertDigitToKey(count)), (cnt == 0)); + cnt++; + } + } + + MoviePluginSelector.exec(NULL, ""); + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "loadconfig") { + parent->hide(); + CFileBrowser fileBrowser; + CFileFilter fileFilter; + fileFilter.addFilter("conf"); + fileBrowser.Filter = &fileFilter; + if (fileBrowser.exec("/var/tuxbox/config") == true) { + loadSetup(fileBrowser.getSelectedFile()->Name.c_str()); + colorSetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + CVFD::getInstance()->setlcdparameter(); + printf("[neutrino] new settings: %s\n", fileBrowser.getSelectedFile()->Name.c_str()); + } + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "saveconfig") { + parent->hide(); + CFileBrowser fileBrowser; + fileBrowser.Dir_Mode = true; + if (fileBrowser.exec("/var/tuxbox") == true) { + char fname[256] = "neutrino.conf", sname[256]; + CStringInputSMS * sms = new CStringInputSMS(LOCALE_EXTRA_SAVECONFIG, fname, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789. "); + sms->exec(NULL, ""); + sprintf(sname, "%s/%s", fileBrowser.getSelectedFile()->Name.c_str(), fname); + printf("[neutrino] save settings: %s\n", sname); + saveSetup(sname); + delete sms; + } + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "loadcolors") { + parent->hide(); + CFileBrowser fileBrowser; + CFileFilter fileFilter; + fileFilter.addFilter("conf"); + fileBrowser.Filter = &fileFilter; + if (fileBrowser.exec("/var/tuxbox/config") == true) { + loadColors(fileBrowser.getSelectedFile()->Name.c_str()); + //printf("[neutrino] new colors: %s\n", fileBrowser.getSelectedFile()->Name.c_str()); + } + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "savecolors") { + parent->hide(); + CFileBrowser fileBrowser; + fileBrowser.Dir_Mode = true; + if (fileBrowser.exec("/var/tuxbox") == true) { + char fname[256] = "colors.conf", sname[256]; + CStringInputSMS * sms = new CStringInputSMS(LOCALE_EXTRA_SAVECOLORS, fname, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789. "); + sms->exec(NULL, ""); + sprintf(sname, "%s/%s", fileBrowser.getSelectedFile()->Name.c_str(), fname); + printf("[neutrino] save colors: %s\n", sname); + saveColors(sname); + delete sms; + } + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "loadkeys") { + parent->hide(); + CFileBrowser fileBrowser; + CFileFilter fileFilter; + fileFilter.addFilter("conf"); + fileBrowser.Filter = &fileFilter; + if (fileBrowser.exec("/var/tuxbox/config") == true) { + loadKeys(fileBrowser.getSelectedFile()->Name.c_str()); + printf("[neutrino] new keys: %s\n", fileBrowser.getSelectedFile()->Name.c_str()); + } + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "savekeys") { + parent->hide(); + CFileBrowser fileBrowser; + fileBrowser.Dir_Mode = true; + if (fileBrowser.exec("/var/tuxbox") == true) { + char fname[256] = "keys.conf", sname[256]; + CStringInputSMS * sms = new CStringInputSMS(LOCALE_EXTRA_SAVEKEYS, fname, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789. "); + sms->exec(NULL, ""); + sprintf(sname, "%s/%s", fileBrowser.getSelectedFile()->Name.c_str(), fname); + printf("[neutrino] save keys: %s\n", sname); + saveKeys(sname); + delete sms; + } + return menu_return::RETURN_REPAINT; + } + else if(actionKey == "autolink") { + if(autoshift) { + char buf[512]; + autoshift = false; + sprintf(buf, "ln %s/* %s", timeshiftDir, g_settings.network_nfs_recordingdir); + system(buf); + autoshift_delete = true; + //sprintf(buf, "rm -f %s/* &", timeshiftDir); + //system(buf); + } + returnval = menu_return::RETURN_EXIT_ALL; + } + else if(actionKey == "clearSectionsd") + { + g_Sectionsd->freeMemory(); + } + + return returnval; +} + +/************************************************************************************** +* changeNotify - features menu recording start / stop * +**************************************************************************************/ +bool CNeutrinoApp::changeNotify(const neutrino_locale_t OptionName, void *data) +{ + if ((ARE_LOCALES_EQUAL(OptionName, LOCALE_MAINMENU_RECORDING_START)) || (ARE_LOCALES_EQUAL(OptionName, LOCALE_MAINMENU_RECORDING))) + { + if(g_RemoteControl->is_video_started) { + bool res = doGuiRecord(NULL,ARE_LOCALES_EQUAL(OptionName, LOCALE_MAINMENU_RECORDING)); + return res; + } + else { + recordingstatus = 0; + return false; + } + } + else if (ARE_LOCALES_EQUAL(OptionName, LOCALE_LANGUAGESETUP_SELECT)) { + g_Locale->loadLocale(g_settings.language); + return true; + } + return false; +} + +/************************************************************************************** +* Main programm - no function here * +**************************************************************************************/ +void stop_daemons(bool stopall) +{ + dvbsub_close(); + tuxtxt_stop(); + tuxtxt_close(); + + printf("httpd shutdown\n"); + pthread_cancel(nhttpd_thread); + pthread_join(nhttpd_thread, NULL); + printf("httpd shutdown done\n"); + streamts_stop = 1; + pthread_join(stream_thread, NULL); + sectionsd_stop = 1; + if(stopall) { + printf("timerd shutdown\n"); + g_Timerd->shutdown(); + pthread_join(timer_thread, NULL); + printf("timerd shutdown done\n"); + } +#ifndef DISABLE_SECTIONSD + printf("sectionsd shutdown\n"); + pthread_join(sections_thread, NULL); + printf("sectionsd shutdown done\n"); +#endif + printf("zapit shutdown\n"); + g_Zapit->shutdown(); + pthread_join(zapit_thread, NULL); + printf("zapit shutdown done\n"); + CVFD::getInstance()->Clear(); + if(stopall) { + delete moviePlayerGui; + if (powerManager) { + powerManager->Close(); + delete powerManager; + } + shutdown_cs_api(); + } +} + +void sighandler (int signum) +{ + signal (signum, SIG_IGN); + switch (signum) { + case SIGTERM: + case SIGINT: + stop_daemons(); + _exit(0); + default: + break; + } +} + +int main(int argc, char **argv) +{ + setDebugLevel(DEBUG_NORMAL); + signal(SIGTERM, sighandler); + signal(SIGINT, sighandler); + signal(SIGHUP, SIG_IGN); + + for(int i = 3; i < 256; i++) + close(i); + + tzset(); + initGlobals(); + + return CNeutrinoApp::getInstance()->run(argc, argv); +} + +void CNeutrinoApp::loadColors(const char * fname) +{ + bool res; + CConfigFile tconfig(',', true); + + printf("CNeutrinoApp::loadColors: %s\n", fname); + + res = tconfig.loadConfig(fname); + if(!res) return; + //colors (neutrino defaultcolors) + g_settings.menu_Head_alpha = tconfig.getInt32( "menu_Head_alpha", 0x00 ); + g_settings.menu_Head_red = tconfig.getInt32( "menu_Head_red", 0x00 ); + g_settings.menu_Head_green = tconfig.getInt32( "menu_Head_green", 0x0A ); + g_settings.menu_Head_blue = tconfig.getInt32( "menu_Head_blue", 0x19 ); + + g_settings.menu_Head_Text_alpha = tconfig.getInt32( "menu_Head_Text_alpha", 0x00 ); + g_settings.menu_Head_Text_red = tconfig.getInt32( "menu_Head_Text_red", 0x5f ); + g_settings.menu_Head_Text_green = tconfig.getInt32( "menu_Head_Text_green", 0x46 ); + g_settings.menu_Head_Text_blue = tconfig.getInt32( "menu_Head_Text_blue", 0x00 ); + + g_settings.menu_Content_alpha = tconfig.getInt32( "menu_Content_alpha", 0x14 ); + g_settings.menu_Content_red = tconfig.getInt32( "menu_Content_red", 0x00 ); + g_settings.menu_Content_green = tconfig.getInt32( "menu_Content_green", 0x0f ); + g_settings.menu_Content_blue = tconfig.getInt32( "menu_Content_blue", 0x23 ); + + g_settings.menu_Content_Text_alpha = tconfig.getInt32( "menu_Content_Text_alpha", 0x00 ); + g_settings.menu_Content_Text_red = tconfig.getInt32( "menu_Content_Text_red", 0x64 ); + g_settings.menu_Content_Text_green = tconfig.getInt32( "menu_Content_Text_green", 0x64 ); + g_settings.menu_Content_Text_blue = tconfig.getInt32( "menu_Content_Text_blue", 0x64 ); + + g_settings.menu_Content_Selected_alpha = tconfig.getInt32( "menu_Content_Selected_alpha", 0x14 ); + g_settings.menu_Content_Selected_red = tconfig.getInt32( "menu_Content_Selected_red", 0x19 ); + g_settings.menu_Content_Selected_green = tconfig.getInt32( "menu_Content_Selected_green", 0x37 ); + g_settings.menu_Content_Selected_blue = tconfig.getInt32( "menu_Content_Selected_blue", 0x64 ); + + g_settings.menu_Content_Selected_Text_alpha = tconfig.getInt32( "menu_Content_Selected_Text_alpha", 0x00 ); + g_settings.menu_Content_Selected_Text_red = tconfig.getInt32( "menu_Content_Selected_Text_red", 0x00 ); + g_settings.menu_Content_Selected_Text_green = tconfig.getInt32( "menu_Content_Selected_Text_green", 0x00 ); + g_settings.menu_Content_Selected_Text_blue = tconfig.getInt32( "menu_Content_Selected_Text_blue", 0x00 ); + + g_settings.menu_Content_inactive_alpha = tconfig.getInt32( "menu_Content_inactive_alpha", 0x14 ); + g_settings.menu_Content_inactive_red = tconfig.getInt32( "menu_Content_inactive_red", 0x00 ); + g_settings.menu_Content_inactive_green = tconfig.getInt32( "menu_Content_inactive_green", 0x0f ); + g_settings.menu_Content_inactive_blue = tconfig.getInt32( "menu_Content_inactive_blue", 0x23 ); + + g_settings.menu_Content_inactive_Text_alpha = tconfig.getInt32( "menu_Content_inactive_Text_alpha", 0x00 ); + g_settings.menu_Content_inactive_Text_red = tconfig.getInt32( "menu_Content_inactive_Text_red", 55 ); + g_settings.menu_Content_inactive_Text_green = tconfig.getInt32( "menu_Content_inactive_Text_green", 70 ); + g_settings.menu_Content_inactive_Text_blue = tconfig.getInt32( "menu_Content_inactive_Text_blue", 85 ); + + g_settings.infobar_alpha = tconfig.getInt32( "infobar_alpha", 0x14 ); + g_settings.infobar_red = tconfig.getInt32( "infobar_red", 0x00 ); + g_settings.infobar_green = tconfig.getInt32( "infobar_green", 0x0e ); + g_settings.infobar_blue = tconfig.getInt32( "infobar_blue", 0x23 ); + + g_settings.infobar_Text_alpha = tconfig.getInt32( "infobar_Text_alpha", 0x00 ); + g_settings.infobar_Text_red = tconfig.getInt32( "infobar_Text_red", 0x64 ); + g_settings.infobar_Text_green = tconfig.getInt32( "infobar_Text_green", 0x64 ); + g_settings.infobar_Text_blue = tconfig.getInt32( "infobar_Text_blue", 0x64 ); + for (int i = 0; i < LCD_SETTING_COUNT; i++) + g_settings.lcd_setting[i] = tconfig.getInt32(lcd_setting[i].name, lcd_setting[i].default_value); + strcpy(g_settings.lcd_setting_dim_time, tconfig.getString("lcd_dim_time","0").c_str()); + strcpy(g_settings.lcd_setting_dim_brightness, tconfig.getString("lcd_dim_brightness","0").c_str()); + + strcpy( g_settings.font_file, configfile.getString( "font_file", "/share/fonts/neutrino.ttf" ).c_str() ); + colorSetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + SetupFonts(); + CVFD::getInstance()->setlcdparameter(); +} + +void CNeutrinoApp::saveColors(const char * fname) +{ + //bool res; + CConfigFile tconfig(',', true); + + //colors + tconfig.setInt32( "menu_Head_alpha", g_settings.menu_Head_alpha ); + tconfig.setInt32( "menu_Head_red", g_settings.menu_Head_red ); + tconfig.setInt32( "menu_Head_green", g_settings.menu_Head_green ); + tconfig.setInt32( "menu_Head_blue", g_settings.menu_Head_blue ); + + tconfig.setInt32( "menu_Head_Text_alpha", g_settings.menu_Head_Text_alpha ); + tconfig.setInt32( "menu_Head_Text_red", g_settings.menu_Head_Text_red ); + tconfig.setInt32( "menu_Head_Text_green", g_settings.menu_Head_Text_green ); + tconfig.setInt32( "menu_Head_Text_blue", g_settings.menu_Head_Text_blue ); + + tconfig.setInt32( "menu_Content_alpha", g_settings.menu_Content_alpha ); + tconfig.setInt32( "menu_Content_red", g_settings.menu_Content_red ); + tconfig.setInt32( "menu_Content_green", g_settings.menu_Content_green ); + tconfig.setInt32( "menu_Content_blue", g_settings.menu_Content_blue ); + + tconfig.setInt32( "menu_Content_Text_alpha", g_settings.menu_Content_Text_alpha ); + tconfig.setInt32( "menu_Content_Text_red", g_settings.menu_Content_Text_red ); + tconfig.setInt32( "menu_Content_Text_green", g_settings.menu_Content_Text_green ); + tconfig.setInt32( "menu_Content_Text_blue", g_settings.menu_Content_Text_blue ); + + tconfig.setInt32( "menu_Content_Selected_alpha", g_settings.menu_Content_Selected_alpha ); + tconfig.setInt32( "menu_Content_Selected_red", g_settings.menu_Content_Selected_red ); + tconfig.setInt32( "menu_Content_Selected_green", g_settings.menu_Content_Selected_green ); + tconfig.setInt32( "menu_Content_Selected_blue", g_settings.menu_Content_Selected_blue ); + + tconfig.setInt32( "menu_Content_Selected_Text_alpha", g_settings.menu_Content_Selected_Text_alpha ); + tconfig.setInt32( "menu_Content_Selected_Text_red", g_settings.menu_Content_Selected_Text_red ); + tconfig.setInt32( "menu_Content_Selected_Text_green", g_settings.menu_Content_Selected_Text_green ); + tconfig.setInt32( "menu_Content_Selected_Text_blue", g_settings.menu_Content_Selected_Text_blue ); + + tconfig.setInt32( "menu_Content_inactive_alpha", g_settings.menu_Content_inactive_alpha ); + tconfig.setInt32( "menu_Content_inactive_red", g_settings.menu_Content_inactive_red ); + tconfig.setInt32( "menu_Content_inactive_green", g_settings.menu_Content_inactive_green ); + tconfig.setInt32( "menu_Content_inactive_blue", g_settings.menu_Content_inactive_blue ); + + tconfig.setInt32( "menu_Content_inactive_Text_alpha", g_settings.menu_Content_inactive_Text_alpha ); + tconfig.setInt32( "menu_Content_inactive_Text_red", g_settings.menu_Content_inactive_Text_red ); + tconfig.setInt32( "menu_Content_inactive_Text_green", g_settings.menu_Content_inactive_Text_green ); + tconfig.setInt32( "menu_Content_inactive_Text_blue", g_settings.menu_Content_inactive_Text_blue ); + + tconfig.setInt32( "infobar_alpha", g_settings.infobar_alpha ); + tconfig.setInt32( "infobar_red", g_settings.infobar_red ); + tconfig.setInt32( "infobar_green", g_settings.infobar_green ); + tconfig.setInt32( "infobar_blue", g_settings.infobar_blue ); + + tconfig.setInt32( "infobar_Text_alpha", g_settings.infobar_Text_alpha ); + tconfig.setInt32( "infobar_Text_red", g_settings.infobar_Text_red ); + tconfig.setInt32( "infobar_Text_green", g_settings.infobar_Text_green ); + tconfig.setInt32( "infobar_Text_blue", g_settings.infobar_Text_blue ); + for (int i = 0; i < LCD_SETTING_COUNT; i++) + tconfig.setInt32(lcd_setting[i].name, g_settings.lcd_setting[i]); + tconfig.setString("lcd_dim_time", g_settings.lcd_setting_dim_time); + tconfig.setString("lcd_dim_brightness", g_settings.lcd_setting_dim_brightness); + + tconfig.setString("font_file", g_settings.font_file); + tconfig.saveConfig(fname); +} + +void CNeutrinoApp::loadKeys(const char * fname) +{ + bool res; + CConfigFile tconfig(',', true); + + res = tconfig.loadConfig(fname); + if(!res) return; + //rc-key configuration + g_settings.key_tvradio_mode = tconfig.getInt32( "key_tvradio_mode", CRCInput::RC_nokey ); + + g_settings.key_channelList_pageup = tconfig.getInt32( "key_channelList_pageup", CRCInput::RC_minus ); + g_settings.key_channelList_pagedown = tconfig.getInt32( "key_channelList_pagedown", CRCInput::RC_plus ); + g_settings.key_channelList_cancel = tconfig.getInt32( "key_channelList_cancel", CRCInput::RC_home ); + g_settings.key_channelList_sort = tconfig.getInt32( "key_channelList_sort", CRCInput::RC_blue ); + g_settings.key_channelList_addrecord = tconfig.getInt32( "key_channelList_addrecord", CRCInput::RC_nokey ); + g_settings.key_channelList_addremind = tconfig.getInt32( "key_channelList_addremind", CRCInput::RC_nokey ); + + g_settings.key_list_start = tconfig.getInt32( "key_list_start", CRCInput::RC_nokey ); + g_settings.key_list_end = tconfig.getInt32( "key_list_end", CRCInput::RC_nokey ); + g_settings.menu_left_exit = tconfig.getInt32( "menu_left_exit", 0 ); + + g_settings.audio_run_player = tconfig.getInt32( "audio_run_player", 1 ); + g_settings.key_click = tconfig.getInt32( "key_click", 0 ); + g_settings.mpkey_rewind = tconfig.getInt32( "mpkey.rewind", CRCInput::RC_left ); + g_settings.mpkey_forward = tconfig.getInt32( "mpkey.forward", CRCInput::RC_right ); + g_settings.mpkey_pause = tconfig.getInt32( "mpkey.pause", CRCInput::RC_yellow ); + g_settings.mpkey_stop = tconfig.getInt32( "mpkey.stop", CRCInput::RC_home ); + g_settings.mpkey_play = tconfig.getInt32( "mpkey.play", CRCInput::RC_ok ); + g_settings.mpkey_audio = tconfig.getInt32( "mpkey.audio", CRCInput::RC_green ); + g_settings.mpkey_time = tconfig.getInt32( "mpkey.time", CRCInput::RC_setup ); + g_settings.mpkey_bookmark = tconfig.getInt32( "mpkey.bookmark", CRCInput::RC_blue ); + g_settings.mpkey_plugin = tconfig.getInt32( "mpkey.plugin", CRCInput::RC_red ); + g_settings.key_timeshift = configfile.getInt32( "key_timeshift", CRCInput::RC_nokey ); + g_settings.key_plugin = configfile.getInt32( "key_plugin", CRCInput::RC_nokey ); + + g_settings.key_quickzap_up = tconfig.getInt32( "key_quickzap_up", CRCInput::RC_up ); + g_settings.key_quickzap_down = tconfig.getInt32( "key_quickzap_down", CRCInput::RC_down ); + g_settings.key_subchannel_up = tconfig.getInt32( "key_subchannel_up", CRCInput::RC_right ); + g_settings.key_subchannel_down = tconfig.getInt32( "key_subchannel_down", CRCInput::RC_left ); + g_settings.key_zaphistory = tconfig.getInt32( "key_zaphistory", CRCInput::RC_home ); + g_settings.key_lastchannel = tconfig.getInt32( "key_lastchannel", CRCInput::RC_0 ); + + g_settings.key_bouquet_up = tconfig.getInt32( "key_bouquet_up", CRCInput::RC_right); + g_settings.key_bouquet_down = tconfig.getInt32( "key_bouquet_down", CRCInput::RC_left); + strcpy(g_settings.repeat_blocker, tconfig.getString("repeat_blocker", "300").c_str()); + strcpy(g_settings.repeat_genericblocker, tconfig.getString("repeat_genericblocker", "100").c_str()); +} + +void CNeutrinoApp::saveKeys(const char * fname) +{ + CConfigFile tconfig(',', true); + //rc-key configuration + tconfig.setInt32( "key_tvradio_mode", g_settings.key_tvradio_mode ); + + tconfig.setInt32( "key_channelList_pageup", g_settings.key_channelList_pageup ); + tconfig.setInt32( "key_channelList_pagedown", g_settings.key_channelList_pagedown ); + tconfig.setInt32( "key_channelList_cancel", g_settings.key_channelList_cancel ); + tconfig.setInt32( "key_channelList_sort", g_settings.key_channelList_sort ); + tconfig.setInt32( "key_channelList_addrecord", g_settings.key_channelList_addrecord ); + tconfig.setInt32( "key_channelList_addremind", g_settings.key_channelList_addremind ); + + tconfig.setInt32( "key_quickzap_up", g_settings.key_quickzap_up ); + tconfig.setInt32( "key_quickzap_down", g_settings.key_quickzap_down ); + tconfig.setInt32( "key_bouquet_up", g_settings.key_bouquet_up ); + tconfig.setInt32( "key_bouquet_down", g_settings.key_bouquet_down ); + tconfig.setInt32( "key_subchannel_up", g_settings.key_subchannel_up ); + tconfig.setInt32( "key_subchannel_down", g_settings.key_subchannel_down ); + tconfig.setInt32( "key_zaphistory", g_settings.key_zaphistory ); + tconfig.setInt32( "key_lastchannel", g_settings.key_lastchannel ); + + tconfig.setInt32( "key_list_start", g_settings.key_list_start ); + tconfig.setInt32( "key_list_end", g_settings.key_list_end ); + tconfig.setInt32( "menu_left_exit", g_settings.menu_left_exit ); + tconfig.setInt32( "audio_run_player", g_settings.audio_run_player ); + tconfig.setInt32( "key_click", g_settings.key_click ); + tconfig.setInt32( "mpkey.rewind", g_settings.mpkey_rewind ); + tconfig.setInt32( "mpkey.forward", g_settings.mpkey_forward ); + tconfig.setInt32( "mpkey.pause", g_settings.mpkey_pause ); + tconfig.setInt32( "mpkey.stop", g_settings.mpkey_stop ); + tconfig.setInt32( "mpkey.play", g_settings.mpkey_play ); + tconfig.setInt32( "mpkey.audio", g_settings.mpkey_audio ); + tconfig.setInt32( "mpkey.time", g_settings.mpkey_time ); + tconfig.setInt32( "mpkey.bookmark", g_settings.mpkey_bookmark ); + tconfig.setInt32( "mpkey.plugin", g_settings.mpkey_plugin ); + tconfig.setInt32( "key_timeshift", g_settings.key_timeshift ); + tconfig.setInt32( "key_plugin", g_settings.key_plugin ); + tconfig.setInt32( "key_unlock", g_settings.key_unlock ); + + tconfig.setString( "repeat_blocker", g_settings.repeat_blocker ); + tconfig.setString( "repeat_genericblocker", g_settings.repeat_genericblocker ); + tconfig.saveConfig(fname); +} diff --git a/src/neutrino.h b/src/neutrino.h new file mode 100644 index 000000000..31336e47a --- /dev/null +++ b/src/neutrino.h @@ -0,0 +1,255 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __neutrino__ +#define __neutrino__ + +#include + +#include +#include +#include +#include +#include +#include +#include /* CChannelList */ +#include +#include /* st_rmsg */ + +#include + +#include + +#define widest_number "2" + +#define ANNOUNCETIME (1 * 60) + +/************************************************************************************** +* * +* CNeutrinoApp - main run-class * +* * +**************************************************************************************/ + +typedef struct neutrino_font_descr +{ + const char * name; + const char * filename; + int size_offset; +} neutrino_font_descr_struct; + +typedef struct font_sizes +{ + const neutrino_locale_t name; + const unsigned int defaultsize; + const unsigned int style; + const unsigned int size_offset; +} font_sizes_struct; + +typedef struct font_sizes_groups +{ + const neutrino_locale_t groupname; + const unsigned int count; + const SNeutrinoSettings::FONT_TYPES * const content; + const char * const actionkey; +} font_sizes_groups_struct; + + +class CNeutrinoApp : public CMenuTarget, CChangeObserver +{ + public: + enum + { + RECORDING_OFF = 0, + RECORDING_SERVER = 1, + RECORDING_VCR = 2, + RECORDING_FILE = 3 + }; + + private: + CFrameBuffer * frameBuffer; + + enum + { + mode_unknown = -1, + mode_tv = 1, + mode_radio = 2, + mode_scart = 3, + mode_standby = 4, + mode_audio = 5, + mode_pic = 6, + mode_ts = 7, + mode_off = 8, + mode_mask = 0xFF, + norezap = 0x100 + }; + + CConfigFile configfile; + CScanSettings scanSettings; + int network_dhcp; + int network_automatic_start; + + neutrino_font_descr_struct font; + + int mode; + int lastMode; + bool softupdate; + bool fromflash; + CTimerd::RecordingInfo* nextRecordingInfo; + //bool record_mode; + + struct timeval standby_pressed_at; + + CZapitClient::responseGetLastChannel firstchannel; + st_rmsg sendmessage; + + int current_muted; + + bool skipShutdownTimer; + + CColorSetupNotifier *colorSetupNotifier; + CKeySetupNotifier *keySetupNotifier; + CNVODChangeExec *NVODChanger; + CStreamFeaturesChangeExec *StreamFeaturesChanger; + CMoviePluginChangeExec *MoviePluginChanger; + COnekeyPluginChangeExec *OnekeyPluginChanger; + CIPChangeNotifier *MyIPChanger; +// CVCRControl *vcrControl; + CConsoleDestChangeNotifier *ConsoleDestinationChanger; + CRCLock *rcLock; + // USERMENU + CTimerList *Timerlist; + + bool showUserMenu(int button); + bool getNVODMenu(CMenuWidget* menu); + + void firstChannel(); + void setupColors_red(); + void setupColors_ru(); + void setupColors_dvb2000(); + void setupColors_classic(); + void setupColors_neutrino(); + void setupColors_dblue(); + void setupColors_dvb2k(); + void setupNetwork( bool force= false ); + void setupNFS(); + void setupRecordingDevice(void); + + void startNextRecording(); + + void tvMode( bool rezap = true ); + void radioMode( bool rezap = true ); + void scartMode( bool bOnOff ); + void standbyMode( bool bOnOff ); + void AudioMute( int newValue, bool isEvent= false ); + void setvol(int vol, int avs); + void saveEpg(); + + void ExitRun(const bool write_si = true, int retcode = 0); + void RealRun(CMenuWidget &mainSettings); + void InitZapper(); + void InitKeySettings(CMenuWidget &); + void InitServiceSettings(CMenuWidget &, CMenuWidget &); + void InitColorSettingsMenuColors(CMenuWidget &); + void InitAudioSettings(CMenuWidget &audioSettings, CAudioSetupNotifier* audioSetupNotifier); + void InitColorSettings(CMenuWidget &, CMenuWidget &); + void InitLanguageSettings(CMenuWidget &); + void InitColorThemesSettings(CMenuWidget &); + void InitColorSettingsStatusBarColors(CMenuWidget &colorSettings_menuColors); + void InitColorSettingsTiming(CMenuWidget &colorSettings_timing); + void InitLcdSettings(CMenuWidget &lcdSettings); + void InitNetworkSettings(CMenuWidget &networkSettings); + void AddFontSettingItem(CMenuWidget &fontSettings, const SNeutrinoSettings::FONT_TYPES number_of_fontsize_entry); + void InitFontSettings(CMenuWidget &fontSettings); + void InitRecordingSettings(CMenuWidget &recordingSettings); + void InitStreamingSettings(CMenuWidget &streamingSettings); + void InitScreenSettings(CMenuWidget &); + void InitAudioplPicSettings(CMenuWidget &); + void InitMiscSettings(CMenuWidget &); + void InitScanSettings(CMenuWidget &); + void InitParentalLockSettings(CMenuWidget &); + void InitMainMenu(CMenuWidget &mainMenu, CMenuWidget &mainSettings, CMenuWidget &audioSettings, + CMenuWidget &parentallockSettings, CMenuWidget &networkSettings1, CMenuWidget &networkSettings2, + CMenuWidget &colorSettings, CMenuWidget &lcdSettings, CMenuWidget &keySettings, + CMenuWidget &languageSettings, CMenuWidget &miscSettings, CMenuWidget &service, CMenuWidget &fontSettings, + CMenuWidget &audioplPicSettings, CMenuWidget &streamingSettings, CMenuWidget &moviePlayer); + void SetupFrameBuffer(); + void SelectAPID(); + void SelectNVOD(); + void CmdParser(int argc, char **argv); + void ShowStreamFeatures(); + void InitSCSettings(CMenuWidget &); + bool doGuiRecord(char * preselectedDir, bool addTimer = false); + void saveColors(const char * fname); + void loadKeys(const char * fname); + void saveKeys(const char * fname); + CNeutrinoApp(); + + public: + void saveSetup(const char * fname); + int loadSetup(const char * fname); + void loadColors(const char * fname); + void SetupTiming(); + void SetupFonts(); + + void setVolume(const neutrino_msg_t key, const bool bDoPaint = true, bool nowait = false); + ~CNeutrinoApp(); + CScanSettings& getScanSettings(){ return scanSettings;}; + + CChannelList *TVchannelList; + CChannelList *RADIOchannelList; + CChannelList *channelList; + CNetworkConfig networkConfig; + + static CNeutrinoApp* getInstance(); + + void channelsInit(bool bOnly = false); + int run(int argc, char **argv); + + //callback stuff only.... + int exec(CMenuTarget* parent, const std::string & actionKey); + + //onchange + bool changeNotify(const neutrino_locale_t OptionName, void *); + + int handleMsg(const neutrino_msg_t msg, neutrino_msg_data_t data); + + int getMode() { return mode; } + int getLastMode() { return lastMode; } + bool isMuted() { return current_muted; } + int recordingstatus; + int recording_id; + void SendSectionsdConfig(void); + int GetChannelMode(void) { return g_settings.channel_mode; }; + void SetChannelMode(int mode); + void quickZap(int msg); +}; +#endif diff --git a/src/neutrinoMessages.h b/src/neutrinoMessages.h new file mode 100644 index 000000000..2b636028e --- /dev/null +++ b/src/neutrinoMessages.h @@ -0,0 +1,168 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef __neutrinoMessages__ +#define __neutrinoMessages__ + +#include "driver/rcinput.h" + + +struct messages_return +{ + enum + { + none = 0x00, + handled = 0x01, + unhandled = 0x02, + cancel_all = 0x04, + cancel_info = 0x08 + }; +}; + +struct NeutrinoMessages { + enum + { + SHOW_EPG = CRCInput::RC_Messages + 1, + SHOW_INFOBAR = CRCInput::RC_Messages + 2, + VCR_ON = CRCInput::RC_Messages + 3, + VCR_OFF = CRCInput::RC_Messages + 4, + STANDBY_ON = CRCInput::RC_Messages + 5, + STANDBY_OFF = CRCInput::RC_Messages + 6, + STANDBY_TOGGLE = CRCInput::RC_Messages + 7, + SHUTDOWN = CRCInput::RC_Messages + 8, + ANNOUNCE_SHUTDOWN = CRCInput::RC_Messages + 9, + ANNOUNCE_ZAPTO = CRCInput::RC_Messages + 10, + ZAPTO = CRCInput::RC_Messages + 11, + ANNOUNCE_RECORD = CRCInput::RC_Messages + 12, + RECORD_START = CRCInput::RC_Messages + 13, + RECORD_STOP = CRCInput::RC_Messages + 14, + ANNOUNCE_SLEEPTIMER = CRCInput::RC_Messages + 15, + SLEEPTIMER = CRCInput::RC_Messages + 16, + CHANGEMODE = CRCInput::RC_Messages + 17, + REMIND = CRCInput::RC_Messages + 18, + LOCK_RC = CRCInput::RC_Messages + 19, + UNLOCK_RC = CRCInput::RC_Messages + 20, + + EVT_VOLCHANGED = CRCInput::RC_Events + 1, + EVT_MUTECHANGED = CRCInput::RC_Events + 2, + EVT_VCRCHANGED = CRCInput::RC_Events + 3, + EVT_MODECHANGED = CRCInput::RC_Events + 4, + EVT_BOUQUETSCHANGED = CRCInput::RC_Events + 6, + EVT_SERVICESCHANGED = CRCInput::RC_Events + 7, + EVT_SCAN_COMPLETE = CRCInput::RC_Events + 16, + EVT_SCAN_NUM_TRANSPONDERS = CRCInput::RC_Events + 17, + EVT_SCAN_NUM_CHANNELS = CRCInput::RC_Events + 18, + EVT_SHUTDOWN = CRCInput::RC_Events + 19, + EVT_TIMER = CRCInput::RC_Events + 20, + EVT_PROGRAMLOCKSTATUS = CRCInput::RC_Events + 22, + EVT_RECORDMODE = CRCInput::RC_Events + 24, +#ifndef SKIP_CA_STATUS + EVT_ZAP_CA_ID = CRCInput::RC_Events + 50, + EVT_ZAP_CA_CLEAR = CRCInput::RC_Events + 26, + EVT_ZAP_CA_LOCK = CRCInput::RC_Events + 27, + EVT_ZAP_CA_FTA = CRCInput::RC_Events + 28, +#endif + EVT_SCAN_FAILED = CRCInput::RC_Events + 29, + EVT_SCAN_REPORT_NUM_SCANNED_TRANSPONDERS = CRCInput::RC_Events + 30, + EVT_SCAN_REPORT_FREQUENCY = CRCInput::RC_Events + 31, + EVT_SCAN_FOUND_RADIO_CHAN = CRCInput::RC_Events + 32, + EVT_SCAN_FOUND_DATA_CHAN = CRCInput::RC_Events + 33, + EVT_SCAN_FOUND_TV_CHAN = CRCInput::RC_Events + 34, + EVT_SCAN_REPORT_FREQUENCYP = CRCInput::RC_Events + 36, + EVT_ZAP_MOTOR = CRCInput::RC_Events + 37, + /* sectionsd */ + EVT_SERVICES_UPD = CRCInput::RC_Events + 38, + EVT_SI_FINISHED = CRCInput::RC_Events + 39, + + /* NEVER CHANGE THIS */ + EVT_CI_INSERTED = CRCInput::RC_Events + 60, /* data = slot num */ + EVT_CI_REMOVED = CRCInput::RC_Events + 61, /* data = slot num */ + EVT_CI_INIT_OK = CRCInput::RC_Events + 62, /* data = slot num */ + EVT_CI_MMI_MENU = CRCInput::RC_Events + 63, + EVT_CI_MMI_LIST = CRCInput::RC_Events + 64, + EVT_CI_MMI_TEXT = CRCInput::RC_Events + 65, + EVT_CI_MMI_REQUEST_INPUT = CRCInput::RC_Events + 66, + EVT_CI_MMI_CLOSE = CRCInput::RC_Events + 67, + /* END */ + + EVT_CURRENTEPG = CRCInput::RC_WithData + 1, + EVT_NEXTEPG = CRCInput::RC_WithData + 2, + EVT_POPUP = CRCInput::RC_WithData + 3, + EVT_EXTMSG = CRCInput::RC_WithData + 4, + EVT_START_PLUGIN = CRCInput::RC_WithData + 5, + + /* sectionsd */ + EVT_CURRENTNEXT_EPG = CRCInput::RC_WithData + 6, /* data: (t_channel_id *) */ + EVT_TIMESET = CRCInput::RC_WithData + 7, /* data: (long long *) */ + + /* "sectionsd" events triggered by neutrino */ + EVT_NOEPG_YET = CRCInput::RC_WithData + 8, /* data: (t_channel_id *) */ + + /* "timerd" events triggered by neutrino */ + EVT_NEXTPROGRAM = CRCInput::RC_WithData + 9, /* data: (t_channel_id *) */ + + /* zapit */ + EVT_SCAN_FOUND_A_CHAN = CRCInput::RC_WithData + 10, + EVT_SCAN_PROVIDER = CRCInput::RC_WithData + 11, + EVT_SCAN_SATELLITE = CRCInput::RC_WithData + 12, + EVT_SCAN_SERVICENAME = CRCInput::RC_WithData + 13, + EVT_ZAP_COMPLETE = CRCInput::RC_WithData + 14, /* data: (t_channel_id *) */ + EVT_ZAP_FAILED = CRCInput::RC_WithData + 15, /* data: (t_channel_id *) */ + EVT_ZAP_ISNVOD = CRCInput::RC_WithData + 16, /* data: (t_channel_id *) */ + EVT_ZAP_SUB_COMPLETE = CRCInput::RC_WithData + 17, /* data: (t_channel_id *) */ + EVT_ZAP_SUB_FAILED = CRCInput::RC_WithData + 18, /* data: (t_channel_id *) */ + + /* "zapit" events triggered by neutrino */ + EVT_ZAP_GOT_SUBSERVICES = CRCInput::RC_WithData + 19, /* data: (t_channel_id *) */ + EVT_ZAP_GOTAPIDS = CRCInput::RC_WithData + 20, /* data: (t_channel_id *) */ + EVT_ZAP_GOTPIDS = CRCInput::RC_WithData + 21, /* data: (t_channel_id *) */ + + /* neutrino */ + EVT_RECORDING_ENDED = CRCInput::RC_WithData + 22 + }; + enum + { + mode_unknown = -1, + mode_tv = 1, + mode_radio = 2, + mode_scart = 3, + mode_standby = 4, + mode_audio = 5, + mode_pic = 6, + mode_ts = 7, + mode_mask = 0xFF, + norezap = 0x100 + }; +}; + + +#endif diff --git a/src/neutrino_menue.cpp b/src/neutrino_menue.cpp new file mode 100644 index 000000000..a89e04c1a --- /dev/null +++ b/src/neutrino_menue.cpp @@ -0,0 +1,3019 @@ +/* + Neutrino-GUI - DBoxII-Project + + Copyright (C) 2001 Steffen Hehn 'McClean' + and some other guys + Homepage: http://dbox.cyberphoria.org/ + + Kommentar: + + Diese GUI wurde von Grund auf neu programmiert und sollte nun vom + Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert + auf der Client-Server Idee, diese GUI ist also von der direkten DBox- + Steuerung getrennt. Diese wird dann von Daemons uebernommen. + + + License: GPL + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +#include "global.h" +#include "neutrino.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "gui/widget/colorchooser.h" +#include "gui/widget/menue.h" +#include "gui/widget/messagebox.h" +#include "gui/widget/hintbox.h" +#include "gui/widget/icons.h" +#include "gui/widget/lcdcontroler.h" +#include "gui/widget/vfdcontroler.h" +#include "gui/widget/rgbcsynccontroler.h" +#include "gui/widget/keychooser.h" +#include "gui/widget/stringinput.h" +#include "gui/widget/stringinput_ext.h" +#include "gui/widget/mountchooser.h" + +#include "gui/color.h" +#include "gui/customcolor.h" + +#include "gui/bedit/bouqueteditor_bouquets.h" +#include "gui/bouquetlist.h" +#include "gui/eventlist.h" +#include "gui/channellist.h" +#include "gui/screensetup.h" +#include "gui/pluginlist.h" +#include "gui/plugins.h" +#include "gui/infoviewer.h" +#include "gui/epgview.h" +#include "gui/epg_menu.h" +#include "gui/update.h" +#include "gui/scan.h" +#include "gui/favorites.h" +#include "gui/sleeptimer.h" +#include "gui/rc_lock.h" +#include "gui/timerlist.h" +#include "gui/alphasetup.h" +#include "gui/audioplayer.h" +#include "gui/imageinfo.h" +#include "gui/movieplayer.h" +#include "gui/nfs.h" +#include "gui/pictureviewer.h" +#include "gui/motorcontrol.h" +#include "gui/filebrowser.h" +#include "gui/scale.h" +#include "gui/upnpbrowser.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "gui/infoclock.h" +#include "mymenu.h" +#include "gui/dboxinfo.h" +#include "gui/hdd_menu.h" +#include "gui/audio_select.h" +#include "gui/cam_menu.h" + +#include +#include + +//#define TEST_MENU + +extern CFrontend * frontend; +extern CAudioPlayerGui * audioPlayer; +extern CMoviePlayerGui* moviePlayerGui; +extern CPlugins * g_PluginList; +extern bool has_hdd; +extern CZapitClient::SatelliteList satList; +extern Zapit_config zapitCfg; +extern char zapit_lat[20]; +extern char zapit_long[20]; +extern char current_timezone[50]; +extern cVideo *videoDecoder; +extern cAudio *audioDecoder; +extern int prev_video_mode; +extern bool parentallocked; +extern const char * locale_real_names[]; +extern CFontSizeNotifier fontsizenotifier; +extern CFanControlNotifier * funNotifier; +extern CRemoteControl * g_RemoteControl; +extern CCAMMenuHandler * g_CamHandler; +extern bool autoshift; +extern unsigned int system_rev; + +//extern int sectionsd_scanning; + +static CTimingSettingsNotifier timingsettingsnotifier; + +#define get_set CNeutrinoApp::getInstance()->getScanSettings() + +int safe_mkdir(char * path); + +#define OPTIONS_OFF0_ON1_OPTION_COUNT 2 +const CMenuOptionChooser::keyval OPTIONS_OFF0_ON1_OPTIONS[OPTIONS_OFF0_ON1_OPTION_COUNT] = +{ + { 0, LOCALE_OPTIONS_OFF }, + { 1, LOCALE_OPTIONS_ON } +}; + +#define OPTIONS_OFF1_ON0_OPTION_COUNT 2 +const CMenuOptionChooser::keyval OPTIONS_OFF1_ON0_OPTIONS[OPTIONS_OFF1_ON0_OPTION_COUNT] = +{ + { 1, LOCALE_OPTIONS_OFF }, + { 0, LOCALE_OPTIONS_ON } +}; + +#define VIDEOMENU_VIDEOSIGNAL_HD1_OPTION_COUNT 8 +const CMenuOptionChooser::keyval VIDEOMENU_VIDEOSIGNAL_HD1_OPTIONS[VIDEOMENU_VIDEOSIGNAL_HD1_OPTION_COUNT] = +{ + { ANALOG_SD_RGB_SCART, LOCALE_VIDEOMENU_ANALOG_MODE_SD_RGB_SCART }, /* composite + RGB (for both SCART and Cinch) */ + { ANALOG_SD_RGB_CINCH, LOCALE_VIDEOMENU_ANALOG_MODE_SD_RGB_CINCH }, /* composite + RGB (for both SCART and Cinch) */ + { ANALOG_SD_YPRPB_SCART, LOCALE_VIDEOMENU_ANALOG_MODE_SD_YPRPB_SCART }, /* YPbPr SCART (with wrongly connected Cinch) */ + { ANALOG_SD_YPRPB_CINCH, LOCALE_VIDEOMENU_ANALOG_MODE_SD_YPRPB_CINCH }, /* YPbPr Cinch (with wrongly connected SCART) */ + { ANALOG_HD_RGB_SCART, LOCALE_VIDEOMENU_ANALOG_MODE_HD_RGB_SCART }, + { ANALOG_HD_RGB_CINCH, LOCALE_VIDEOMENU_ANALOG_MODE_HD_RGB_CINCH }, + { ANALOG_HD_YPRPB_SCART, LOCALE_VIDEOMENU_ANALOG_MODE_HD_YPRPB_SCART }, + { ANALOG_HD_YPRPB_CINCH, LOCALE_VIDEOMENU_ANALOG_MODE_HD_YPRPB_CINCH } +}; + +#define VIDEOMENU_VIDEOSIGNAL_HD1PLUS_SCART_OPTION_COUNT 4 +const CMenuOptionChooser::keyval VIDEOMENU_VIDEOSIGNAL_HD1PLUS_SCART_OPTIONS[VIDEOMENU_VIDEOSIGNAL_HD1PLUS_SCART_OPTION_COUNT] = +{ + { ANALOG_SD_RGB_SCART, LOCALE_VIDEOMENU_ANALOG_MODE_SD_RGB_SCART }, /* composite + RGB */ + { ANALOG_SD_YPRPB_SCART, LOCALE_VIDEOMENU_ANALOG_MODE_SD_YPRPB_SCART }, /* YPbPr SCART */ + { ANALOG_HD_RGB_SCART, LOCALE_VIDEOMENU_ANALOG_MODE_HD_RGB_SCART }, + { ANALOG_HD_YPRPB_SCART, LOCALE_VIDEOMENU_ANALOG_MODE_HD_YPRPB_SCART }, +}; + +#define VIDEOMENU_VIDEOSIGNAL_HD1PLUS_CINCH_OPTION_COUNT 4 +const CMenuOptionChooser::keyval VIDEOMENU_VIDEOSIGNAL_HD1PLUS_CINCH_OPTIONS[VIDEOMENU_VIDEOSIGNAL_HD1PLUS_CINCH_OPTION_COUNT] = +{ + { ANALOG_SD_RGB_CINCH, LOCALE_VIDEOMENU_ANALOG_MODE_SD_RGB_CINCH }, /* composite + RGB (for both SCART and Cinch) */ + { ANALOG_SD_YPRPB_CINCH, LOCALE_VIDEOMENU_ANALOG_MODE_SD_YPRPB_CINCH }, /* YPbPr Cinch (with wrongly connected SCART) */ + { ANALOG_HD_RGB_CINCH, LOCALE_VIDEOMENU_ANALOG_MODE_HD_RGB_CINCH }, + { ANALOG_HD_YPRPB_CINCH, LOCALE_VIDEOMENU_ANALOG_MODE_HD_YPRPB_CINCH } +}; + +#define VIDEOMENU_VCRSIGNAL_OPTION_COUNT 2 +const CMenuOptionChooser::keyval VIDEOMENU_VCRSIGNAL_OPTIONS[VIDEOMENU_VCRSIGNAL_OPTION_COUNT] = +{ + { 2, LOCALE_VIDEOMENU_VCRSIGNAL_SVIDEO }, + { 0, LOCALE_VIDEOMENU_VCRSIGNAL_COMPOSITE } +}; + +#define VIDEOMENU_VIDEOFORMAT_OPTION_COUNT 3//2 +const CMenuOptionChooser::keyval VIDEOMENU_VIDEOFORMAT_OPTIONS[VIDEOMENU_VIDEOFORMAT_OPTION_COUNT] = +{ + { 1, LOCALE_VIDEOMENU_VIDEOFORMAT_43 }, + { 3, LOCALE_VIDEOMENU_VIDEOFORMAT_169 }, + { 2, LOCALE_VIDEOMENU_VIDEOFORMAT_149 } +}; + +#define VIDEOMENU_43MODE_OPTION_COUNT 4 +const CMenuOptionChooser::keyval VIDEOMENU_43MODE_OPTIONS[VIDEOMENU_43MODE_OPTION_COUNT] = +{ + { DISPLAY_AR_MODE_PANSCAN, LOCALE_VIDEOMENU_PANSCAN }, + { DISPLAY_AR_MODE_PANSCAN2, LOCALE_VIDEOMENU_PANSCAN2 }, + { DISPLAY_AR_MODE_LETTERBOX, LOCALE_VIDEOMENU_LETTERBOX }, + { DISPLAY_AR_MODE_NONE, LOCALE_VIDEOMENU_FULLSCREEN } + //{ 2, LOCALE_VIDEOMENU_AUTO } // whatever is this auto mode, it seems its totally broken +}; + +/* numbers corresponding to video.cpp from zapit */ +//#define VIDEOMENU_VIDEOMODE_OPTION_COUNT 11 +const CMenuOptionChooser::keyval VIDEOMENU_VIDEOMODE_OPTIONS[VIDEOMENU_VIDEOMODE_OPTION_COUNT] = +{ + { 1, NONEXISTANT_LOCALE, "SECAM" }, + { 2, NONEXISTANT_LOCALE, "PAL" }, + { 4, NONEXISTANT_LOCALE, "576p" }, + { 7, NONEXISTANT_LOCALE, "720p 50Hz" }, + { 8, NONEXISTANT_LOCALE, "1080i 50Hz" }, + { 10, NONEXISTANT_LOCALE, "1080p 24Hz" }, + { 11, NONEXISTANT_LOCALE, "1080p 25Hz" }, + + { 0, NONEXISTANT_LOCALE, "NTSC" }, + { 3, NONEXISTANT_LOCALE, "480p" }, + { 5, NONEXISTANT_LOCALE, "720p 60Hz" }, + { 6, NONEXISTANT_LOCALE, "1080i 60Hz" }, + { VIDEO_STD_AUTO, NONEXISTANT_LOCALE, "Auto" } +}; + +#define VIDEOMENU_DBDR_OPTION_COUNT 3 +const CMenuOptionChooser::keyval VIDEOMENU_DBDR_OPTIONS[VIDEOMENU_DBDR_OPTION_COUNT] = +{ + { 0, LOCALE_VIDEOMENU_DBDR_NONE }, + { 1, LOCALE_VIDEOMENU_DBDR_DEBLOCK }, + { 2, LOCALE_VIDEOMENU_DBDR_BOTH } +}; + +#include "videosettings.h" +CVideoSettings::CVideoSettings() : CMenuWidget(LOCALE_VIDEOMENU_HEAD, "video.raw"), RGBCSyncControler(LOCALE_VIDEOMENU_RGB_CENTERING, &g_settings.video_csync) +{ + addItem(GenericMenuSeparator); + addItem(GenericMenuBack); + + addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_VIDEOMENU_TV_SCART)); + + if (system_rev == 0x06) { + addItem(new CMenuOptionChooser(LOCALE_VIDEOMENU_ANALOG_MODE, &g_settings.analog_mode1, VIDEOMENU_VIDEOSIGNAL_HD1_OPTIONS, VIDEOMENU_VIDEOSIGNAL_HD1_OPTION_COUNT, true, this)); + } else if (system_rev > 0x06) { + addItem(new CMenuOptionChooser(LOCALE_VIDEOMENU_SCART, &g_settings.analog_mode1, VIDEOMENU_VIDEOSIGNAL_HD1PLUS_SCART_OPTIONS, VIDEOMENU_VIDEOSIGNAL_HD1PLUS_SCART_OPTION_COUNT, true, this)); + addItem(new CMenuOptionChooser(LOCALE_VIDEOMENU_CINCH, &g_settings.analog_mode2, VIDEOMENU_VIDEOSIGNAL_HD1PLUS_CINCH_OPTIONS, VIDEOMENU_VIDEOSIGNAL_HD1PLUS_CINCH_OPTION_COUNT, true, this)); + } + + addItem(new CMenuOptionChooser(LOCALE_VIDEOMENU_VIDEOFORMAT, &g_settings.video_Format, VIDEOMENU_VIDEOFORMAT_OPTIONS, VIDEOMENU_VIDEOFORMAT_OPTION_COUNT, true, this)); + addItem(new CMenuOptionChooser(LOCALE_VIDEOMENU_43MODE, &g_settings.video_43mode, VIDEOMENU_43MODE_OPTIONS, VIDEOMENU_43MODE_OPTION_COUNT, true, this)); + addItem(new CMenuOptionChooser(LOCALE_VIDEOMENU_VIDEOMODE, &g_settings.video_Mode, VIDEOMENU_VIDEOMODE_OPTIONS, VIDEOMENU_VIDEOMODE_OPTION_COUNT, true, this, CRCInput::RC_nokey, "", true)); + addItem(new CMenuOptionChooser(LOCALE_VIDEOMENU_DBDR, &g_settings.video_dbdr, VIDEOMENU_DBDR_OPTIONS, VIDEOMENU_DBDR_OPTION_COUNT, true, this)); + + CMenuWidget* menu = new CMenuWidget(LOCALE_VIDEOMENU_ENABLED_MODES, NEUTRINO_ICON_SETTINGS); + for(int i = 0; i < VIDEOMENU_VIDEOMODE_OPTION_COUNT; i++) + menu->addItem(new CMenuOptionChooser(VIDEOMENU_VIDEOMODE_OPTIONS[i].valname, &g_settings.enabled_video_modes[i], OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + + addItem(new CMenuForwarder(LOCALE_VIDEOMENU_ENABLED_MODES, true, NULL, menu)); +#if 0 + addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_VIDEOMENU_VCR_SCART)); + addItem(new CMenuOptionChooser(LOCALE_VIDEOMENU_VCRSWITCH, &g_settings.vcr_AutoSwitch, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_VIDEOMENU_OSD)); + addItem(new CMenuForwarder(LOCALE_VIDEOMENU_SCREENSETUP, true, NULL, &ScreenSetup, NULL, CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); +#endif + changeNotify(LOCALE_VIDEOMENU_VIDEOFORMAT, NULL); + if (system_rev == 0x06) { + changeNotify(LOCALE_VIDEOMENU_ANALOG_MODE, NULL); + } else { + changeNotify(LOCALE_VIDEOMENU_SCART, NULL); + changeNotify(LOCALE_VIDEOMENU_CINCH, NULL); + } +}; + +void CVideoSettings::nextMode(void) +{ + const char * text; + int curmode = 0; + int i; + + for(i = 0; i < VIDEOMENU_VIDEOMODE_OPTION_COUNT; i++) { + if(VIDEOMENU_VIDEOMODE_OPTIONS[i].key == g_settings.video_Mode) { + curmode = i; + break; + } + } + + i = 0; + while(true) { + curmode++; + if(curmode >= VIDEOMENU_VIDEOMODE_OPTION_COUNT) + curmode = 0; + if(g_settings.enabled_video_modes[curmode]) + break; + i++; + if(i >= VIDEOMENU_VIDEOMODE_OPTION_COUNT) + return; + } + + text = VIDEOMENU_VIDEOMODE_OPTIONS[curmode].valname; + + g_settings.video_Mode = VIDEOMENU_VIDEOMODE_OPTIONS[curmode].key; + videoDecoder->SetVideoSystem(g_settings.video_Mode); + //videoDecoder->SetVideoMode((analog_mode_t) g_settings.analog_mode);//FIXME + ShowHintUTF(LOCALE_VIDEOMENU_VIDEOMODE, text, 450, 2); +} + +void CVideoSettings::next43Mode(void) +{ + neutrino_locale_t text; + int curmode = 0; + + for(int i = 0; i < VIDEOMENU_43MODE_OPTION_COUNT; i++) { + if(VIDEOMENU_43MODE_OPTIONS[i].key == g_settings.video_43mode) { + curmode = i; + break; + } + } + curmode++; + if(curmode >= VIDEOMENU_43MODE_OPTION_COUNT) + curmode = 0; + + text = VIDEOMENU_43MODE_OPTIONS[curmode].value; + g_settings.video_43mode = VIDEOMENU_43MODE_OPTIONS[curmode].key; + videoDecoder->setAspectRatio(-1, g_settings.video_43mode); + ShowHintUTF(LOCALE_VIDEOMENU_43MODE, g_Locale->getText(text), 450, 2); +} + +void CVideoSettings::SwitchFormat(void) +{ + neutrino_locale_t text; + int curmode = 0; + + for(int i = 0; i < VIDEOMENU_VIDEOFORMAT_OPTION_COUNT; i++) { + if(VIDEOMENU_VIDEOFORMAT_OPTIONS[i].key == g_settings.video_Format) { + curmode = i; + break; + } + } + curmode++; + if(curmode >= VIDEOMENU_VIDEOFORMAT_OPTION_COUNT) + curmode = 0; + + text = VIDEOMENU_VIDEOFORMAT_OPTIONS[curmode].value; + g_settings.video_Format = VIDEOMENU_VIDEOFORMAT_OPTIONS[curmode].key; + + videoDecoder->setAspectRatio(g_settings.video_Format, -1); + ShowHintUTF(LOCALE_VIDEOMENU_VIDEOFORMAT, g_Locale->getText(text), 450, 2); +} + +bool CVideoSettings::changeNotify(const neutrino_locale_t OptionName, void *) +{ + if (ARE_LOCALES_EQUAL(OptionName, LOCALE_VIDEOMENU_ANALOG_MODE)) + { + videoDecoder->SetVideoMode((analog_mode_t) g_settings.analog_mode1); + } + else if (ARE_LOCALES_EQUAL(OptionName, LOCALE_VIDEOMENU_SCART)) + { + videoDecoder->SetVideoMode((analog_mode_t) g_settings.analog_mode1); + } + else if (ARE_LOCALES_EQUAL(OptionName, LOCALE_VIDEOMENU_CINCH)) + { + videoDecoder->SetVideoMode((analog_mode_t) g_settings.analog_mode2); + } + else if (ARE_LOCALES_EQUAL(OptionName, LOCALE_VIDEOMENU_DBDR)) + { + videoDecoder->SetDBDR(g_settings.video_dbdr); + } + else if (ARE_LOCALES_EQUAL(OptionName, LOCALE_VIDEOMENU_VCRSIGNAL)) + { + } + else if (ARE_LOCALES_EQUAL(OptionName, LOCALE_VIDEOMENU_VIDEOFORMAT) || + ARE_LOCALES_EQUAL(OptionName, LOCALE_VIDEOMENU_43MODE)) + { + //if(g_settings.video_Format != 1 && g_settings.video_Format != 3) + if(g_settings.video_Format != 1 && g_settings.video_Format != 3 && g_settings.video_Format != 2) + g_settings.video_Format = 3; + videoDecoder->setAspectRatio(g_settings.video_Format, g_settings.video_43mode); + } + else if (ARE_LOCALES_EQUAL(OptionName, LOCALE_VIDEOMENU_VIDEOMODE)) + { + videoDecoder->SetVideoSystem(g_settings.video_Mode); + //videoDecoder->SetVideoMode((analog_mode_t) g_settings.analog_mode);//FIXME + if(prev_video_mode != g_settings.video_Mode) { + frameBuffer->paintBackground(); + if(ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_VIDEOMODE_OK), CMessageBox::mbrNo, CMessageBox::mbYes | CMessageBox::mbNo, "info.raw") != CMessageBox::mbrYes) { + g_settings.video_Mode = prev_video_mode; + videoDecoder->SetVideoSystem(g_settings.video_Mode); + //videoDecoder->SetVideoMode((analog_mode_t) g_settings.analog_mode);//FIXME + } else + prev_video_mode = g_settings.video_Mode; + } + } + + return true; +}; + +void CVideoSettings::paint() +{ + CMenuWidget::paint(); +}; + +#ifdef TEST_MENU +class CTestMenu : public CMenuTarget +{ + public: + int exec(CMenuTarget* parent, const std::string &actionkey); +}; + +#include +#include +#include + +int CTestMenu::exec(CMenuTarget* parent, const std::string &actionKey) +{ + if(parent) + parent->hide(); + + printf("CTestMenu::exec: %s\n", actionKey.c_str()); + if(actionKey == "vfd") { + CVFD::getInstance()->Clear(); + int icon = 0x00040000; + while(icon > 0x2) { + CVFD::getInstance()->ShowIcon((vfd_icon) icon, true); + icon /= 2; + } + for(int i = 0x01000001; i <= 0x0C000001; i+= 0x01000000) { + CVFD::getInstance()->ShowIcon((vfd_icon) i, true); + } + CVFD::getInstance()->ShowIcon((vfd_icon) 0x09000002, true); + CVFD::getInstance()->ShowIcon((vfd_icon) 0x0B000002, true); + char text[255]; + char buf[XML_UTF8_ENCODE_MAX]; + int ch = 0x2588; + int len = XmlUtf8Encode(ch, buf); + + for(int i = 0; i < 12; i++) { + memcpy(&text[i*len], buf, len); + } + text[12*len] = 0; + + CVFD::getInstance()->ShowText(text); + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, "VFD test, Press OK to return", CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + CVFD::getInstance()->Clear(); + } + else if(actionKey == "network") { + int fd, ret; + struct ifreq ifr; + char * ip = NULL, str[255]; + struct sockaddr_in *addrp=NULL; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1); + + ret = ioctl(fd, SIOCGIFHWADDR, &ifr); + if(ret < 0) + perror("SIOCGIFHWADDR"); + + ret = ioctl(fd, SIOCGIFADDR, &ifr ); + if(ret < 0) + perror("SIOCGIFADDR"); + else { + addrp = (struct sockaddr_in *)&(ifr.ifr_addr); + ip = inet_ntoa(addrp->sin_addr); + } + + sprintf(str, "MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\nIP: %s", + (unsigned char)ifr.ifr_hwaddr.sa_data[0], + (unsigned char)ifr.ifr_hwaddr.sa_data[1], + (unsigned char)ifr.ifr_hwaddr.sa_data[2], + (unsigned char)ifr.ifr_hwaddr.sa_data[3], + (unsigned char)ifr.ifr_hwaddr.sa_data[4], + (unsigned char)ifr.ifr_hwaddr.sa_data[5], ip == NULL ? "Unknown" : ip); + + close(fd); + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, str, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + } + else if(actionKey == "card") { + } + else if(actionKey == "hdd") { + char buffer[255]; + FILE *f = fopen("/proc/mounts", "r"); + bool mounted = false; + if(f != NULL) { + while (fgets (buffer, 255, f) != NULL) { + if(strstr(buffer, "/dev/sda1")) { + mounted = true; + break; + } + } + fclose(f); + } + sprintf(buffer, "HDD: /dev/sda1 is %s", mounted ? "mounted" : "NOT mounted"); + printf("%s\n", buffer); + ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, buffer, CMessageBox::mbrBack, CMessageBox::mbBack, "info.raw"); + } + else if(actionKey == "buttons") { + neutrino_msg_t msg; + neutrino_msg_data_t data; + CHintBox * khintBox = NULL; + CHintBox * hintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, "Press button, or press EXIT to return"); + hintBox->paint(); + while(1) { + g_RCInput->getMsg(&msg, &data, 100); + if(msg == CRCInput::RC_home) + break; + + if (msg != CRCInput::RC_timeout && msg <= CRCInput::RC_MaxRC) { + char keyname[50]; + sprintf(keyname, "Button [%s] pressed (EXIT to return)", g_RCInput->getKeyName(msg).c_str()); + if(khintBox) { + delete khintBox; + } + khintBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, keyname); + hintBox->hide(); + khintBox->paint(); + } + } + if(khintBox) + delete khintBox; + delete hintBox; + } + else if(actionKey == "22kon" || actionKey == "22koff") { + CScanTs * scanTs = new CScanTs(); + + int freq = (actionKey == "22kon") ? 12000*1000: 11000*1000; + + sprintf(get_set.TP_freq, "%d", freq); +#if 0 // not needed ? + switch(frontend->getInfo()->type) { + case FE_QPSK: + sprintf(get_set.TP_rate, "%d", tmpI->second.feparams.u.qpsk.symbol_rate); + get_set.TP_fec = tmpI->second.feparams.u.qpsk.fec_inner; + get_set.TP_pol = tmpI->second.polarization; + break; + case FE_QAM: + sprintf(get_set.TP_rate, "%d", tmpI->second.feparams.u.qam.symbol_rate); + get_set.TP_fec = tmpI->second.feparams.u.qam.fec_inner; + get_set.TP_mod = tmpI->second.feparams.u.qam.modulation; + break; + } +#endif + scanTs->exec(NULL, "test"); + delete scanTs; + } + else if(actionKey == "scan") { + CScanTs * scanTs = new CScanTs(); + + int freq = 12538000; + sprintf(get_set.TP_freq, "%d", freq); + switch(frontend->getInfo()->type) { + case FE_QPSK: + sprintf(get_set.TP_rate, "%d", 41250*1000); + get_set.TP_fec = 1; + get_set.TP_pol = 1; + break; + case FE_QAM: +#if 0 + sprintf(get_set.TP_rate, "%d", tmpI->second.feparams.u.qam.symbol_rate); + get_set.TP_fec = tmpI->second.feparams.u.qam.fec_inner; + get_set.TP_mod = tmpI->second.feparams.u.qam.modulation; +#endif + break; + case FE_OFDM: + case FE_ATSC: + break; + } + scanTs->exec(NULL, "manual"); + delete scanTs; + } + + return menu_return::RETURN_REPAINT; +} + +CMenuWidget * TestMenu; +#endif + +CVideoSettings * videoSettings; +CMenuOptionStringChooser* tzSelect; +/************************************************************************************** +* CNeutrinoApp - init main menu * +**************************************************************************************/ +void CNeutrinoApp::InitMainMenu(CMenuWidget &mainMenu, CMenuWidget &mainSettings, CMenuWidget &audioSettings, CMenuWidget &parentallockSettings, + CMenuWidget &networkSettings, CMenuWidget &recordingSettings, CMenuWidget &colorSettings, CMenuWidget &lcdSettings, + CMenuWidget &keySettings, CMenuWidget &languageSettings, CMenuWidget &miscSettings, + CMenuWidget &service, CMenuWidget &fontSettings, CMenuWidget &audiopl_picSettings, CMenuWidget &streamingSettings, CMenuWidget &moviePlayer) +{ + +#ifdef TEST_MENU + TestMenu = new CMenuWidget("Test menu"); + CTestMenu * testHandler = new CTestMenu(); + TestMenu->addItem(new CMenuForwarderNonLocalized("VFD", true, NULL, testHandler, "vfd")); + TestMenu->addItem(new CMenuForwarderNonLocalized("Network", true, NULL, testHandler, "network")); + TestMenu->addItem(new CMenuForwarderNonLocalized("Smartcard", true, NULL, testHandler, "card")); + TestMenu->addItem(new CMenuForwarderNonLocalized("HDD", true, NULL, testHandler, "hdd")); + TestMenu->addItem(new CMenuForwarderNonLocalized("Buttons", true, NULL, testHandler, "buttons")); + TestMenu->addItem(new CMenuForwarderNonLocalized("Scan 12538000", true, NULL, testHandler, "scan")); + //TestMenu->addItem(new CMenuForwarderNonLocalized("22 Khz ON", true, NULL, testHandler, "22kon")); + //TestMenu->addItem(new CMenuForwarderNonLocalized("22 Khz OFF", true, NULL, testHandler, "22koff")); +#endif + videoSettings = new CVideoSettings(); + + dprintf(DEBUG_DEBUG, "init mainmenue\n"); + mainMenu.addItem(GenericMenuSeparator); + + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_TVMODE, true, NULL, this, "tv", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED), true); + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_RADIOMODE, true, NULL, this, "radio", CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN)); + //mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_SCARTMODE, true, NULL, this, "scart", CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW)); + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_GAMES, true, NULL, new CPluginList(LOCALE_MAINMENU_GAMES,CPlugins::P_TYPE_GAME), "", CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE)); + mainMenu.addItem(GenericMenuSeparatorLine); + + mainMenu.addItem(new CMenuForwarder(LOCALE_UPNPBROWSER_HEAD, true, NULL, new CUpnpBrowserGui(), NULL, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW)); + audioPlayer = new CAudioPlayerGui(); + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_AUDIOPLAYER, true, NULL, audioPlayer, NULL, CRCInput::RC_1)); + + moviePlayerGui = new CMoviePlayerGui(); + //mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_MOVIEPLAYER, true, NULL, &moviePlayer, NULL, CRCInput::RC_2)); + +#if 0 + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_MOVIEPLAYER, true, NULL, moviePlayerGui, "tsmoviebrowser", CRCInput::RC_2)); +#else + moviePlayer.addItem(GenericMenuSeparator); + moviePlayer.addItem(GenericMenuBack); + moviePlayer.addItem(GenericMenuSeparatorLine); + moviePlayer.addItem(new CMenuForwarder(LOCALE_MOVIEBROWSER_HEAD, true, NULL, moviePlayerGui, "tsmoviebrowser", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + moviePlayer.addItem(new CMenuForwarder(LOCALE_MOVIEPLAYER_FILEPLAYBACK, true, NULL, moviePlayerGui, "fileplayback", CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN)); + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_MOVIEPLAYER, true, NULL, &moviePlayer, NULL, CRCInput::RC_2)); +#endif +#if 0 + moviePlayer.addItem(GenericMenuSeparator); + moviePlayer.addItem(GenericMenuBack); + moviePlayer.addItem(GenericMenuSeparatorLine); + + + //moviePlayer.addItem(new CMenuForwarder(LOCALE_MOVIEPLAYER_PESPLAYBACK, true, NULL, moviePlayerGui, "pesplayback")); + //moviePlayer.addItem(new CMenuForwarder(LOCALE_MOVIEPLAYER_TSPLAYBACK_PC, true, NULL, moviePlayerGui, "tsplayback_pc")); + moviePlayer.addItem(new CLockedMenuForwarder(LOCALE_MOVIEBROWSER_HEAD, g_settings.parentallock_pincode, false, true, NULL, moviePlayerGui, "tsmoviebrowser")); + moviePlayer.addItem(new CLockedMenuForwarder(LOCALE_MOVIEPLAYER_TSPLAYBACK, g_settings.parentallock_pincode, false, true, NULL, moviePlayerGui, "tsplayback", CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN)); + + moviePlayer.addItem(new CLockedMenuForwarder(LOCALE_MOVIEPLAYER_BOOKMARK, g_settings.parentallock_pincode, false, true, NULL, moviePlayerGui, "bookmarkplayback")); + moviePlayer.addItem(GenericMenuSeparator); + moviePlayer.addItem(new CMenuForwarder(LOCALE_MOVIEPLAYER_FILEPLAYBACK, true, NULL, moviePlayerGui, "fileplayback", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + moviePlayer.addItem(new CMenuForwarder(LOCALE_MOVIEPLAYER_DVDPLAYBACK, true, NULL, moviePlayerGui, "dvdplayback", CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW)); + moviePlayer.addItem(new CMenuForwarder(LOCALE_MOVIEPLAYER_VCDPLAYBACK, true, NULL, moviePlayerGui, "vcdplayback", CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE)); + moviePlayer.addItem(GenericMenuSeparatorLine); + moviePlayer.addItem(new CMenuForwarder(LOCALE_MAINMENU_SETTINGS, true, NULL, &streamingSettings, NULL, CRCInput::RC_help, NEUTRINO_ICON_BUTTON_HELP_SMALL)); + moviePlayer.addItem(new CMenuForwarder(LOCALE_NFSMENU_HEAD, true, NULL, new CNFSSmallMenu(), NULL, CRCInput::RC_setup, NEUTRINO_ICON_BUTTON_DBOX_SMALL)); +#endif + + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_PICTUREVIEWER, true, NULL, new CPictureViewerGui(), NULL, CRCInput::RC_3)); + int shortcut = 4; + if (g_PluginList->hasPlugin(CPlugins::P_TYPE_SCRIPT)) + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_SCRIPTS, true, NULL, new CPluginList(LOCALE_MAINMENU_SCRIPTS,CPlugins::P_TYPE_SCRIPT), "", + CRCInput::convertDigitToKey(shortcut++))); + mainMenu.addItem(GenericMenuSeparatorLine); + + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_SETTINGS, true, NULL, &mainSettings, NULL, + CRCInput::convertDigitToKey(shortcut++))); + mainMenu.addItem(new CLockedMenuForwarder(LOCALE_MAINMENU_SERVICE, g_settings.parentallock_pincode, false, true, NULL, &service, NULL, + CRCInput::convertDigitToKey(shortcut++))); + mainMenu.addItem(GenericMenuSeparatorLine); + + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_SLEEPTIMER, true, NULL, new CSleepTimerWidget, NULL, + CRCInput::convertDigitToKey(shortcut++))); + mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_REBOOT, true, NULL, this, "reboot", + CRCInput::convertDigitToKey(shortcut++))); + + //mainMenu.addItem(new CMenuForwarder(LOCALE_MAINMENU_SHUTDOWN, true, NULL, this, "shutdown", CRCInput::RC_standby, "power.raw"));//FIXME + + mainMenu.addItem( new CMenuSeparator(CMenuSeparator::LINE) ); + mainMenu.addItem( new CMenuForwarder(LOCALE_DBOXINFO, true, NULL, new CDBoxInfoWidget, NULL, CRCInput::convertDigitToKey(shortcut++))); + + mainSettings.addItem(GenericMenuSeparator); + mainSettings.addItem(GenericMenuBack); + mainSettings.addItem(GenericMenuSeparatorLine); + mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_SAVESETTINGSNOW, true, NULL, this, "savesettings", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + mainSettings.addItem(new CMenuForwarder(LOCALE_EXTRA_LOADCONFIG, true, NULL, this, "loadconfig")); + mainSettings.addItem(new CMenuForwarder(LOCALE_EXTRA_SAVECONFIG, true, NULL, this, "saveconfig")); + + CDataResetNotifier * resetNotifier = new CDataResetNotifier(); + mainSettings.addItem(new CMenuForwarder(LOCALE_RESET_SETTINGS , true, NULL, resetNotifier, "settings")); + + mainSettings.addItem(GenericMenuSeparatorLine); + mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_VIDEO , true, NULL, videoSettings , NULL, CRCInput::RC_1)); + mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_AUDIO , true, NULL, &audioSettings , NULL, CRCInput::RC_2)); + mainSettings.addItem(new CLockedMenuForwarder(LOCALE_PARENTALLOCK_PARENTALLOCK, g_settings.parentallock_pincode, true, true, NULL, &parentallockSettings, NULL, CRCInput::RC_3)); +#if 0 + if(g_settings.parentallock_prompt) + mainSettings.addItem(new CLockedMenuForwarder(LOCALE_PARENTALLOCK_PARENTALLOCK, g_settings.parentallock_pincode, true, true, NULL, &parentallockSettings, NULL, CRCInput::RC_3)); + else + mainSettings.addItem(new CMenuForwarder(LOCALE_PARENTALLOCK_PARENTALLOCK, true, NULL, &parentallockSettings, NULL, CRCInput::RC_3)); +#endif + mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_NETWORK , true, NULL, &networkSettings , NULL, CRCInput::RC_4)); + mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_RECORDING , true, NULL, &recordingSettings, NULL, CRCInput::RC_5)); + //mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_STREAMING , true, NULL, &streamingSettings, NULL, CRCInput::RC_6)); + mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_LANGUAGE , true, NULL, &languageSettings , NULL, CRCInput::RC_6)); + + xmlDocPtr parser; + + parser = parseXmlFile("/etc/timezone.xml"); + if (parser != NULL) { + tzSelect = new CMenuOptionStringChooser(LOCALE_MAINSETTINGS_TIMEZONE, g_settings.timezone, true, new CTZChangeNotifier(), CRCInput::RC_7, "", true); + xmlNodePtr search = xmlDocGetRootElement(parser)->xmlChildrenNode; + bool found = false; + while (search) { + if (!strcmp(xmlGetName(search), "zone")) { + std::string name = xmlGetAttribute(search, (char *) "name"); + std::string zone = xmlGetAttribute(search, (char *) "zone"); + //printf("Timezone: %s -> %s\n", name.c_str(), zone.c_str()); + tzSelect->addOption(name.c_str()); + found = true; + } + search = search->xmlNextNode; + } + if(found) + mainSettings.addItem(tzSelect); + else { + delete tzSelect; + tzSelect = NULL; + } + xmlFreeDoc(parser); + } + mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_OSD , true, NULL, &colorSettings , NULL, CRCInput::RC_8)); + + if(CVFD::getInstance()->has_lcd) + mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_LCD , true, NULL, &lcdSettings , NULL, CRCInput::RC_9)); + + mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_KEYBINDING, true, NULL, &keySettings , NULL, CRCInput::RC_blue , NEUTRINO_ICON_BUTTON_BLUE )); + mainSettings.addItem(new CMenuForwarder(LOCALE_AUDIOPLAYERPICSETTINGS_GENERAL , true, NULL, &audiopl_picSettings , NULL, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW)); + mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_MISC , true, NULL, &miscSettings , NULL, CRCInput::RC_green , NEUTRINO_ICON_BUTTON_GREEN )); + + mainSettings.addItem(new CMenuForwarder(LOCALE_HDD_SETTINGS, true, NULL, new CHDDMenuHandler())); + mainSettings.addItem(new CMenuForwarder(LOCALE_CAM_SETTINGS, true, NULL, g_CamHandler)); + +#ifdef TEST_MENU + mainMenu.addItem(new CMenuForwarderNonLocalized("Test menu", true, NULL, TestMenu)); +#endif +#if 0 + g_RFmod = new RFmod(); + if(g_RFmod->rfmodfd >=0) { + g_RFmod->init(); + CMenuWidget * rfmenu = new CMenuWidget(LOCALE_RFMOD, "settings.raw"); + CRfNotifier * rfnot = new CRfNotifier(); + CRfExec * rfexec = new CRfExec(); + + rfmenu->addItem( GenericMenuBack ); + rfmenu->addItem( new CMenuForwarder(LOCALE_RECORDINGMENU_SETUPNOW, true, NULL, rfexec, "savesettings", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + rfmenu->addItem( GenericMenuSeparatorLine ); + + rfmenu->addItem( new CMenuOptionChooser(LOCALE_RF_CARRIER, &g_settings.rf_subcarrier, RF_CARRIER_OPTIONS, RF_CARRIER_OPTION_COUNT, true, rfnot)); + rfmenu->addItem( new CMenuOptionChooser(LOCALE_RF_ENABLE, &g_settings.rf_soundenable, OPTIONS_OFF1_ON0_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, rfnot)); + rfmenu->addItem( new CMenuOptionNumberChooser(LOCALE_RF_CHANNEL, &g_settings.rf_channel, true, 21, 69) ); + rfmenu->addItem( new CMenuOptionNumberChooser(LOCALE_RF_FINETUNE, &g_settings.rf_finetune, true, 0, 64) ); + + rfmenu->addItem( new CMenuOptionChooser(LOCALE_RF_STANDBY, &g_settings.rf_standby, OPTIONS_OFF1_ON0_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, rfnot)); + rf_dummy = 0; + rfmenu->addItem( new CMenuOptionChooser(LOCALE_RF_TEST, &rf_dummy, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, rfnot)); + mainSettings.addItem(new CMenuForwarder(LOCALE_RFMOD, true, NULL, rfmenu)); + } +#endif +} + +#define SCANTS_BOUQUET_OPTION_COUNT 3 +const CMenuOptionChooser::keyval SCANTS_BOUQUET_OPTIONS[SCANTS_BOUQUET_OPTION_COUNT] = +{ + { CZapitClient::BM_DELETEBOUQUETS , LOCALE_SCANTS_BOUQUET_ERASE }, + /*{ CZapitClient::BM_CREATEBOUQUETS , LOCALE_SCANTS_BOUQUET_CREATE },*/ + { CZapitClient::BM_DONTTOUCHBOUQUETS , LOCALE_SCANTS_BOUQUET_LEAVE }, + { CZapitClient::BM_UPDATEBOUQUETS , LOCALE_SCANTS_BOUQUET_UPDATE } + /*{ CZapitClient::BM_CREATESATELLITEBOUQUET, LOCALE_SCANTS_BOUQUET_SATELLITE }*/ +}; + +#define SCANTS_ZAPIT_SCANTYPE_COUNT 4 +const CMenuOptionChooser::keyval SCANTS_ZAPIT_SCANTYPE[SCANTS_ZAPIT_SCANTYPE_COUNT] = +{ + { CZapitClient::ST_TVRADIO , LOCALE_ZAPIT_SCANTYPE_TVRADIO }, + { CZapitClient::ST_TV , LOCALE_ZAPIT_SCANTYPE_TV }, + { CZapitClient::ST_RADIO , LOCALE_ZAPIT_SCANTYPE_RADIO }, + { CZapitClient::ST_ALL , LOCALE_ZAPIT_SCANTYPE_ALL } +}; + +#define SATSETUP_DISEQC_OPTION_COUNT 6 +const CMenuOptionChooser::keyval SATSETUP_DISEQC_OPTIONS[SATSETUP_DISEQC_OPTION_COUNT] = +{ + { NO_DISEQC , LOCALE_SATSETUP_NODISEQC, NULL }, + { MINI_DISEQC , LOCALE_SATSETUP_MINIDISEQC, NULL }, + { DISEQC_1_0 , LOCALE_SATSETUP_DISEQC10, NULL }, + { DISEQC_1_1 , LOCALE_SATSETUP_DISEQC11, NULL }, + /*{ DISEQC_1_2 , LOCALE_SATSETUP_DISEQC12, NULL },*/ + { DISEQC_ADVANCED , LOCALE_SATSETUP_DISEQ_ADVANCED, NULL }, + { SMATV_REMOTE_TUNING, LOCALE_SATSETUP_SMATVREMOTE, NULL } +}; + +#define SATSETUP_SCANTP_FEC_COUNT 23 +#define CABLESETUP_SCANTP_FEC_COUNT 5 +const CMenuOptionChooser::keyval SATSETUP_SCANTP_FEC[SATSETUP_SCANTP_FEC_COUNT] = +{ + { FEC_1_2, LOCALE_SCANTP_FEC_1_2 }, + { FEC_2_3, LOCALE_SCANTP_FEC_2_3 }, + { FEC_3_4, LOCALE_SCANTP_FEC_3_4 }, + { FEC_5_6, LOCALE_SCANTP_FEC_5_6 }, + { FEC_7_8, LOCALE_SCANTP_FEC_7_8 }, + { FEC_S2_QPSK_1_2, LOCALE_FEC_S2_QPSK_1_2 }, + { FEC_S2_QPSK_2_3, LOCALE_FEC_S2_QPSK_2_3 }, + { FEC_S2_QPSK_3_4, LOCALE_FEC_S2_QPSK_3_4 }, + { FEC_S2_QPSK_5_6, LOCALE_FEC_S2_QPSK_5_6 }, + { FEC_S2_QPSK_7_8, LOCALE_FEC_S2_QPSK_7_8 }, + { FEC_S2_QPSK_8_9, LOCALE_FEC_S2_QPSK_8_9 }, + { FEC_S2_QPSK_3_5, LOCALE_FEC_S2_QPSK_3_5 }, + { FEC_S2_QPSK_4_5, LOCALE_FEC_S2_QPSK_4_5 }, + { FEC_S2_QPSK_9_10, LOCALE_FEC_S2_QPSK_9_10 }, + { FEC_S2_8PSK_1_2, LOCALE_FEC_S2_8PSK_1_2 }, + { FEC_S2_8PSK_2_3, LOCALE_FEC_S2_8PSK_2_3 }, + { FEC_S2_8PSK_3_4, LOCALE_FEC_S2_8PSK_3_4 }, + { FEC_S2_8PSK_5_6, LOCALE_FEC_S2_8PSK_5_6 }, + { FEC_S2_8PSK_7_8, LOCALE_FEC_S2_8PSK_7_8 }, + { FEC_S2_8PSK_8_9, LOCALE_FEC_S2_8PSK_8_9 }, + { FEC_S2_8PSK_3_5, LOCALE_FEC_S2_8PSK_3_5 }, + { FEC_S2_8PSK_4_5, LOCALE_FEC_S2_8PSK_4_5 }, + { FEC_S2_8PSK_9_10, LOCALE_FEC_S2_8PSK_9_10 } +}; + +#define SATSETUP_SCANTP_MOD_COUNT 5 +const CMenuOptionChooser::keyval SATSETUP_SCANTP_MOD[SATSETUP_SCANTP_MOD_COUNT] = +{ + { 1, LOCALE_SCANTP_MOD_16 }, + { 2, LOCALE_SCANTP_MOD_32 }, + { 3, LOCALE_SCANTP_MOD_64 }, + { 4, LOCALE_SCANTP_MOD_128}, + { 5, LOCALE_SCANTP_MOD_256} +}; +#define SATSETUP_SCANTP_POL_COUNT 2 +const CMenuOptionChooser::keyval SATSETUP_SCANTP_POL[SATSETUP_SCANTP_POL_COUNT] = +{ + { 0, LOCALE_EXTRA_POL_H }, + { 1, LOCALE_EXTRA_POL_V } +}; + +#if 0 +/*Cable*/ +#define CABLESETUP_SCANTP_MOD_COUNT 7 +const CMenuOptionChooser::keyval CABLESETUP_SCANTP_MOD[CABLESETUP_SCANTP_MOD_COUNT] = +{ + {0, LOCALE_SCANTP_MOD_QPSK } , + {1, LOCALE_SCANTP_MOD_QAM_16 } , + {2, LOCALE_SCANTP_MOD_QAM_32 } , + {3, LOCALE_SCANTP_MOD_QAM_64 } , + {4, LOCALE_SCANTP_MOD_QAM_128 } , + {5, LOCALE_SCANTP_MOD_QAM_256 } , + {6, LOCALE_SCANTP_MOD_QAM_AUTO } +}; +#endif + +#define SECTIONSD_SCAN_OPTIONS_COUNT 3 +const CMenuOptionChooser::keyval SECTIONSD_SCAN_OPTIONS[SECTIONSD_SCAN_OPTIONS_COUNT] = +{ + { 0, LOCALE_OPTIONS_OFF }, + { 1, LOCALE_OPTIONS_ON }, + { 2, LOCALE_OPTIONS_ON_WITHOUT_MESSAGES } +}; +#define DISEQC_ORDER_OPTION_COUNT 2 +const CMenuOptionChooser::keyval DISEQC_ORDER_OPTIONS[DISEQC_ORDER_OPTION_COUNT] = +{ + { COMMITED_FIRST, LOCALE_SATSETUP_DISEQC_COM_UNCOM }, + { UNCOMMITED_FIRST, LOCALE_SATSETUP_DISEQC_UNCOM_COM } +}; + +class CTPSelectHandler : public CMenuTarget +{ + public: + int exec(CMenuTarget* parent, const std::string &actionkey); +}; + +extern std::map select_transponders; +int CTPSelectHandler::exec(CMenuTarget* parent, const std::string &actionkey) +{ + transponder_list_t::iterator tI; + sat_iterator_t sit; + t_satellite_position position = 0; + std::map tmplist; + std::map::iterator tmpI; + int i; + char cnt[5]; + int select = -1; + static int old_selected = 0; + static t_satellite_position old_position = 0; + + if (parent) + parent->hide(); + + for(sit = satellitePositions.begin(); sit != satellitePositions.end(); sit++) { + if(!strcmp(sit->second.name.c_str(), CNeutrinoApp::getInstance()->getScanSettings().satNameNoDiseqc)) { + position = sit->first; + break; + } + } + if(old_position != position) { + old_selected = 0; + old_position = position; + } + + CMenuWidget* menu = new CMenuWidget(LOCALE_SCANTS_SELECT_TP, NEUTRINO_ICON_SETTINGS); + CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select); + i = 0; + for(tI = select_transponders.begin(); tI != select_transponders.end(); tI++) { + t_satellite_position satpos = GET_SATELLITEPOSITION_FROM_TRANSPONDER_ID(tI->first) & 0xFFF; + if(GET_SATELLITEPOSITION_FROM_TRANSPONDER_ID(tI->first) & 0xF000) + satpos = -satpos; + if(satpos != position) + continue; + + char buf[128]; + sprintf(cnt, "%d", i); + char * f, *s, *m; + switch(frontend->getInfo()->type) { + case FE_QPSK: + frontend->getDelSys(tI->second.feparams.u.qpsk.fec_inner, dvbs_get_modulation(tI->second.feparams.u.qpsk.fec_inner), f, s, m); + snprintf(buf, sizeof(buf), "%d %c %d %s %s %s ", tI->second.feparams.frequency/1000, tI->second.polarization ? 'V' : 'H', tI->second.feparams.u.qpsk.symbol_rate/1000, f, s, m); + break; + case FE_QAM: + frontend->getDelSys(tI->second.feparams.u.qam.fec_inner, tI->second.feparams.u.qam.modulation, f, s, m); + snprintf(buf, sizeof(buf), "%d %d %s %s %s ", tI->second.feparams.frequency/1000, tI->second.feparams.u.qam.symbol_rate/1000, f, s, m); + break; + case FE_OFDM: + case FE_ATSC: + break; + } + menu->addItem(new CMenuForwarderNonLocalized(buf, true, NULL, selector, cnt), old_selected == i); + tmplist.insert(std::pair (i, tI->second)); + i++; + } + int retval = menu->exec(NULL, ""); + delete menu; + delete selector; + if(select >= 0) { + old_selected = select; + + tmpI = tmplist.find(select); + printf("CTPSelectHandler::exec: selected TP: freq %d pol %d SR %d\n", tmpI->second.feparams.frequency, + tmpI->second.polarization, tmpI->second.feparams.u.qpsk.symbol_rate); + sprintf(get_set.TP_freq, "%d", tmpI->second.feparams.frequency); + switch(frontend->getInfo()->type) { + case FE_QPSK: + sprintf(get_set.TP_rate, "%d", tmpI->second.feparams.u.qpsk.symbol_rate); + get_set.TP_fec = tmpI->second.feparams.u.qpsk.fec_inner; + get_set.TP_pol = tmpI->second.polarization; + break; + case FE_QAM: + sprintf(get_set.TP_rate, "%d", tmpI->second.feparams.u.qam.symbol_rate); + get_set.TP_fec = tmpI->second.feparams.u.qam.fec_inner; + get_set.TP_mod = tmpI->second.feparams.u.qam.modulation; + break; + case FE_OFDM: + case FE_ATSC: + break; + } + + } + if(retval == menu_return::RETURN_EXIT_ALL) + return menu_return::RETURN_EXIT_ALL; + + return menu_return::RETURN_REPAINT; +} + +extern int scan_pids; +void CNeutrinoApp::InitScanSettings(CMenuWidget &settings) +{ + dprintf(DEBUG_DEBUG, "init scansettings\n"); + int sfound = 0; + int dmode = scanSettings.diseqcMode; + int shortcut = 1; + CTPSelectHandler * tpSelect = new CTPSelectHandler(); + + CSatelliteSetupNotifier * satNotify = new CSatelliteSetupNotifier(); + + CMenuOptionChooser* ojScantype = new CMenuOptionChooser(LOCALE_ZAPIT_SCANTYPE, (int *)&scanSettings.scanType, SCANTS_ZAPIT_SCANTYPE, SCANTS_ZAPIT_SCANTYPE_COUNT, true, NULL, CRCInput::convertDigitToKey(shortcut++), "", true); + CMenuOptionChooser* ojBouquets = new CMenuOptionChooser(LOCALE_SCANTS_BOUQUET, (int *)&scanSettings.bouquetMode, SCANTS_BOUQUET_OPTIONS, SCANTS_BOUQUET_OPTION_COUNT, true, NULL, CRCInput::convertDigitToKey(shortcut++), "", true); + + CMenuOptionChooser* useNit = new CMenuOptionChooser(LOCALE_SATSETUP_USE_NIT, (int *)&scanSettings.scan_mode, OPTIONS_OFF1_ON0_OPTIONS, OPTIONS_OFF1_ON0_OPTION_COUNT, true, NULL, CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN); + CMenuOptionChooser* scanPids = new CMenuOptionChooser(LOCALE_EXTRA_ZAPIT_SCANPIDS, &scan_pids, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, NULL, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW); + + CMenuWidget* satSetup = new CMenuWidget(LOCALE_SATSETUP_SAT_SETUP, NEUTRINO_ICON_SETTINGS); + satSetup->addItem(GenericMenuSeparator); + satSetup->addItem(GenericMenuBack); + + satSetup->addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_SAVESETTINGSNOW, true, NULL, this, "savescansettings", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + satSetup->addItem(GenericMenuSeparatorLine); + + CMenuWidget* satfindMenu = new CMenuWidget(LOCALE_MOTORCONTROL_HEAD, NEUTRINO_ICON_SETTINGS); + + satfindMenu->addItem(GenericMenuSeparator); + satfindMenu->addItem(GenericMenuBack); + satfindMenu->addItem(GenericMenuSeparatorLine); + CMenuOptionStringChooser *satSelect = NULL; + CMenuWidget* satOnOff = NULL; + sat_iterator_t sit; + + if(g_info.delivery_system == DVB_S) { + satSelect = new CMenuOptionStringChooser(LOCALE_SATSETUP_SATELLITE, scanSettings.satNameNoDiseqc, true, NULL, CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED, true); + satOnOff = new CMenuWidget(LOCALE_SATSETUP_SATELLITE, NEUTRINO_ICON_SETTINGS); + satOnOff->addItem(GenericMenuSeparator); + satOnOff->addItem(GenericMenuBack); + satOnOff->addItem(GenericMenuSeparatorLine); + + t_satellite_position currentSatellitePosition = frontend->getCurrentSatellitePosition(); + + for(sit = satellitePositions.begin(); sit != satellitePositions.end(); sit++) { + printf("Adding sat menu for %s position %d\n", sit->second.name.c_str(), sit->first); + + satSelect->addOption(sit->second.name.c_str()); + if(currentSatellitePosition == sit->first) { + strcpy(scanSettings.satNameNoDiseqc, sit->second.name.c_str()); + sfound = 1; + } + + CMenuWidget* tempsat = new CMenuWidget(sit->second.name.c_str(), NEUTRINO_ICON_SETTINGS); + tempsat->addItem(GenericMenuSeparator); + tempsat->addItem(GenericMenuBack); + tempsat->addItem(GenericMenuSeparatorLine); + + CMenuOptionChooser * inuse = new CMenuOptionChooser(sit->second.name.c_str(), &sit->second.use_in_scan, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + CMenuOptionNumberChooser * diseqc = new CMenuOptionNumberChooser(LOCALE_SATSETUP_DISEQC_INPUT, &sit->second.diseqc, ((dmode != NO_DISEQC) && (dmode != DISEQC_ADVANCED)), -1, 15, NULL, 1, -1, LOCALE_OPTIONS_OFF); + CMenuOptionNumberChooser * comm = new CMenuOptionNumberChooser(LOCALE_SATSETUP_COMM_INPUT, &sit->second.commited, dmode == DISEQC_ADVANCED, -1, 15, NULL, 1, -1, LOCALE_OPTIONS_OFF); + CMenuOptionNumberChooser * uncomm = new CMenuOptionNumberChooser(LOCALE_SATSETUP_UNCOMM_INPUT, &sit->second.uncommited, dmode == DISEQC_ADVANCED, -1, 15, NULL, 1, -1, LOCALE_OPTIONS_OFF); + //CMenuOptionNumberChooser * motor = new CMenuOptionNumberChooser(LOCALE_SATSETUP_MOTOR_POS, &sit->second.motor_position, dmode == DISEQC_ADVANCED, 0, 64, NULL, 0, 0, LOCALE_OPTIONS_OFF); + CMenuOptionNumberChooser * motor = new CMenuOptionNumberChooser(LOCALE_SATSETUP_MOTOR_POS, &sit->second.motor_position, true, 0, 64, NULL, 0, 0, LOCALE_OPTIONS_OFF); + //CMenuOptionChooser * usals = new CMenuOptionChooser(LOCALE_EXTRA_USE_GOTOXX, &sit->second.use_usals, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, dmode == DISEQC_ADVANCED); + CMenuOptionChooser * usals = new CMenuOptionChooser(LOCALE_EXTRA_USE_GOTOXX, &sit->second.use_usals, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + + satNotify->addItem(1, diseqc); + satNotify->addItem(0, comm); + satNotify->addItem(0, uncomm); + //satNotify->addItem(0, motor); //FIXME testing motor with not DISEQC_ADVANCED + //satNotify->addItem(0, usals); + + CIntInput* lofL = new CIntInput(LOCALE_SATSETUP_LOFL, (int&) sit->second.lnbOffsetLow, 5, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE); + CIntInput* lofH = new CIntInput(LOCALE_SATSETUP_LOFH, (int&) sit->second.lnbOffsetHigh, 5, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE); + CIntInput* lofS = new CIntInput(LOCALE_SATSETUP_LOFS, (int&) sit->second.lnbSwitch, 5, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE); + + satOnOff->addItem(inuse); + tempsat->addItem(diseqc); + tempsat->addItem(comm); + tempsat->addItem(uncomm); + tempsat->addItem(motor); + tempsat->addItem(usals); + tempsat->addItem(new CMenuForwarder(LOCALE_SATSETUP_LOFL, true, lofL->getValue(), lofL)); + tempsat->addItem(new CMenuForwarder(LOCALE_SATSETUP_LOFH, true, lofH->getValue(), lofH)); + tempsat->addItem(new CMenuForwarder(LOCALE_SATSETUP_LOFS, true, lofS->getValue(), lofS)); + satSetup->addItem(new CMenuForwarderNonLocalized(sit->second.name.c_str(), true, NULL, tempsat)); + } + } else if (g_info.delivery_system == DVB_C) { + satSelect = new CMenuOptionStringChooser(LOCALE_CABLESETUP_PROVIDER, (char*)scanSettings.satNameNoDiseqc, true); + for(sit = satellitePositions.begin(); sit != satellitePositions.end(); sit++) { + satSelect->addOption(sit->second.name.c_str()); +printf("Adding cable menu for %s position %d\n", sit->second.name.c_str(), sit->first); + dprintf(DEBUG_DEBUG, "got scanprovider (cable): %s\n", sit->second.name.c_str()); + } + } + satfindMenu->addItem(satSelect); + + int freq_length = (g_info.delivery_system == DVB_S) ? 8 : 6; + + CStringInput* freq = new CStringInput(LOCALE_EXTRA_FREQ, (char *) scanSettings.TP_freq, freq_length, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "0123456789"); + CStringInput* rate = new CStringInput(LOCALE_EXTRA_RATE, (char *) scanSettings.TP_rate, 8, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "0123456789"); + CMenuForwarder * Freq = new CMenuForwarder(LOCALE_EXTRA_FREQ, true, scanSettings.TP_freq, freq, "", CRCInput::convertDigitToKey(1)); + CMenuForwarder * Rate = new CMenuForwarder(LOCALE_EXTRA_RATE, true, scanSettings.TP_rate, rate, "", CRCInput::convertDigitToKey(2)); + + int fec_count = (g_info.delivery_system == DVB_S) ? SATSETUP_SCANTP_FEC_COUNT : CABLESETUP_SCANTP_FEC_COUNT; + + CMenuOptionChooser* fec = new CMenuOptionChooser(LOCALE_EXTRA_FEC, (int *)&scanSettings.TP_fec, SATSETUP_SCANTP_FEC, fec_count, true, NULL, CRCInput::convertDigitToKey(3), "", true); + CMenuOptionChooser* mod_pol = NULL; + + if (g_info.delivery_system == DVB_S) + mod_pol = new CMenuOptionChooser(LOCALE_EXTRA_POL, (int *)&scanSettings.TP_pol, SATSETUP_SCANTP_POL, SATSETUP_SCANTP_POL_COUNT, true, NULL, CRCInput::convertDigitToKey(4)); + else if(g_info.delivery_system == DVB_C) + mod_pol = new CMenuOptionChooser(LOCALE_EXTRA_MOD, (int *)&scanSettings.TP_mod, SATSETUP_SCANTP_MOD, SATSETUP_SCANTP_MOD_COUNT, true, NULL, CRCInput::convertDigitToKey(4)); + + satfindMenu->addItem(Freq); + satfindMenu->addItem(Rate); + satfindMenu->addItem(fec); + satfindMenu->addItem(mod_pol); + + CMenuWidget* motorMenu = NULL; + if (g_info.delivery_system == DVB_S) { + satfindMenu->addItem(new CMenuForwarder(LOCALE_MOTORCONTROL_HEAD, true, NULL, new CMotorControl(), "", CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE)); + + motorMenu = new CMenuWidget(LOCALE_SATSETUP_EXTENDED_MOTOR, NEUTRINO_ICON_SETTINGS); + motorMenu->addItem(GenericMenuSeparator); + motorMenu->addItem(GenericMenuBack); + motorMenu->addItem(new CMenuForwarder(LOCALE_SATSETUP_SAVESETTINGSNOW, true, NULL, this, "savesettings", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + //motorMenu->addItem(new CMenuForwarder(LOCALE_SATSETUP_MOTORCONTROL , true, NULL, new CMotorControl())); + motorMenu->addItem(new CMenuForwarder(LOCALE_MOTORCONTROL_HEAD, true, NULL, satfindMenu, "", CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN)); + motorMenu->addItem(GenericMenuSeparatorLine); + + motorMenu->addItem(new CMenuOptionNumberChooser(LOCALE_EXTRA_ZAPIT_ROTATION_SPEED, (int *)&zapitCfg.motorRotationSpeed, true, 0, 64, NULL) ); + //motorMenu->addItem(new CMenuOptionChooser(LOCALE_EXTRA_USE_GOTOXX, (int *)&zapitCfg.useGotoXX, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + + CStringInput * toff; + sprintf(zapit_lat, "%3.6f", zapitCfg.gotoXXLatitude); + sprintf(zapit_long, "%3.6f", zapitCfg.gotoXXLongitude); + + motorMenu->addItem(new CMenuOptionChooser(LOCALE_EXTRA_LADIR, (int *)&zapitCfg.gotoXXLaDirection, OPTIONS_SOUTH0_NORTH1_OPTIONS, OPTIONS_SOUTH0_NORTH1_OPTION_COUNT, true)); + toff = new CStringInput(LOCALE_EXTRA_LAT, (char *) zapit_lat, 10, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "0123456789."); + motorMenu->addItem(new CMenuForwarder(LOCALE_EXTRA_LAT, true, zapit_lat, toff)); + + motorMenu->addItem(new CMenuOptionChooser(LOCALE_EXTRA_LODIR, (int *)&zapitCfg.gotoXXLoDirection, OPTIONS_EAST0_WEST1_OPTIONS, OPTIONS_EAST0_WEST1_OPTION_COUNT, true)); + toff = new CStringInput(LOCALE_EXTRA_LONG, (char *) zapit_long, 10, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "0123456789."); + motorMenu->addItem(new CMenuForwarder(LOCALE_EXTRA_LONG, true, zapit_long, toff)); + motorMenu->addItem(new CMenuOptionNumberChooser(LOCALE_SATSETUP_USALS_REPEAT, (int *)&zapitCfg.repeatUsals, true, 0, 10, NULL, 0, 0, LOCALE_OPTIONS_OFF) ); + } + + if(!sfound && satellitePositions.size()) { + sit = satellitePositions.begin(); + strcpy(scanSettings.satNameNoDiseqc, sit->second.name.c_str()); + } + + CMenuWidget* manualScan = new CMenuWidget(LOCALE_SATSETUP_MANUAL_SCAN, NEUTRINO_ICON_SETTINGS); + + CScanTs * scanTs = new CScanTs(); + + manualScan->addItem(GenericMenuSeparator); + manualScan->addItem(GenericMenuBack); + manualScan->addItem(GenericMenuSeparatorLine); + + manualScan->addItem(satSelect); + manualScan->addItem(new CMenuForwarder(LOCALE_SCANTS_SELECT_TP, true, NULL, tpSelect, "test")); + manualScan->addItem(Freq); + manualScan->addItem(Rate); + manualScan->addItem(fec); + manualScan->addItem(mod_pol); + manualScan->addItem(useNit); + manualScan->addItem(GenericMenuSeparatorLine); + manualScan->addItem(new CMenuForwarder(LOCALE_SCANTS_TEST, true, NULL, scanTs, "test", CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW)); + manualScan->addItem(new CMenuForwarder(LOCALE_SCANTS_STARTNOW, true, NULL, scanTs, "manual", CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE)); + + CMenuWidget* autoScan = new CMenuWidget(LOCALE_SATSETUP_AUTO_SCAN, NEUTRINO_ICON_SETTINGS); + autoScan->addItem(GenericMenuSeparator); + autoScan->addItem(GenericMenuBack); + autoScan->addItem(GenericMenuSeparatorLine); + autoScan->addItem(satSelect); + autoScan->addItem(useNit); + autoScan->addItem(scanPids); + autoScan->addItem(new CMenuForwarder(LOCALE_SCANTS_STARTNOW, true, NULL, scanTs, "auto", CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE)); + + CMenuOptionChooser* ojDiseqc = NULL; + CMenuOptionNumberChooser * ojDiseqcRepeats = NULL; + CMenuForwarder *fsatSetup = NULL; + CMenuForwarder *fmotorMenu = NULL; + CMenuForwarder *fautoScanAll = NULL; + + if (g_info.delivery_system == DVB_S) { + ojDiseqc = new CMenuOptionChooser(LOCALE_SATSETUP_DISEQC, (int *)&scanSettings.diseqcMode, SATSETUP_DISEQC_OPTIONS, SATSETUP_DISEQC_OPTION_COUNT, true, satNotify, CRCInput::convertDigitToKey(shortcut++), "", true); + ojDiseqcRepeats = new CMenuOptionNumberChooser(LOCALE_SATSETUP_DISEQCREPEAT, (int *)&scanSettings.diseqcRepeat, (dmode != NO_DISEQC) && (dmode != DISEQC_ADVANCED), 0, 2, NULL); + + satNotify->addItem(1, ojDiseqcRepeats); + + fsatSetup = new CMenuForwarder(LOCALE_SATSETUP_SAT_SETUP, true, NULL, satSetup, "", CRCInput::convertDigitToKey(shortcut++)); + //fmotorMenu = new CMenuForwarder(LOCALE_SATSETUP_EXTENDED_MOTOR, (dmode == DISEQC_ADVANCED), NULL, motorMenu, "", CRCInput::convertDigitToKey(shortcut++)); + //satNotify->addItem(0, fmotorMenu); //FIXME testing motor with not DISEQC_ADVANCED + fmotorMenu = new CMenuForwarder(LOCALE_SATSETUP_EXTENDED_MOTOR, true, NULL, motorMenu, "", CRCInput::convertDigitToKey(shortcut++)); + + CMenuWidget* autoScanAll = new CMenuWidget(LOCALE_SATSETUP_AUTO_SCAN_ALL, NEUTRINO_ICON_SETTINGS); + fautoScanAll = new CMenuForwarder(LOCALE_SATSETUP_AUTO_SCAN_ALL, (dmode != NO_DISEQC), NULL, autoScanAll, "", CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE); + satNotify->addItem(2, fautoScanAll); + + + autoScanAll->addItem(GenericMenuSeparator); + autoScanAll->addItem(GenericMenuBack); + autoScanAll->addItem(GenericMenuSeparatorLine); + autoScanAll->addItem(new CMenuForwarder(LOCALE_SATSETUP_SATELLITE, true, NULL, satOnOff, "", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + autoScanAll->addItem(useNit); + autoScanAll->addItem(scanPids); + autoScanAll->addItem(new CMenuForwarder(LOCALE_SCANTS_STARTNOW, true, NULL, scanTs, "all", CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE)); + } + + settings.addItem(GenericMenuSeparator); + settings.addItem(GenericMenuBack); + settings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_SAVESETTINGSNOW, true, NULL, this, "savesettings", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + settings.addItem(GenericMenuSeparatorLine); + + settings.addItem(ojScantype); + settings.addItem(ojBouquets); + + if(g_info.delivery_system == DVB_S) { + settings.addItem(ojDiseqc); + settings.addItem(ojDiseqcRepeats); + settings.addItem(fsatSetup); + settings.addItem(fmotorMenu); + } + + settings.addItem(new CMenuForwarder(LOCALE_SATSETUP_MANUAL_SCAN, true, NULL, manualScan, "", CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN)); + settings.addItem(new CMenuForwarder(LOCALE_SATSETUP_AUTO_SCAN, true, NULL, autoScan, "", CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW)); + + if(g_info.delivery_system == DVB_S) { + settings.addItem(fautoScanAll); + } +} + +#define FLASHUPDATE_UPDATEMODE_OPTION_COUNT 2 +const CMenuOptionChooser::keyval FLASHUPDATE_UPDATEMODE_OPTIONS[FLASHUPDATE_UPDATEMODE_OPTION_COUNT] = +{ + { 0, LOCALE_FLASHUPDATE_UPDATEMODE_MANUAL }, + { 1, LOCALE_FLASHUPDATE_UPDATEMODE_INTERNET } +}; + +void getZapitConfig(Zapit_config *Cfg); +void CNeutrinoApp::InitServiceSettings(CMenuWidget &service, CMenuWidget &scanSettings) +{ + dprintf(DEBUG_DEBUG, "init serviceSettings\n"); + getZapitConfig(&zapitCfg); + +#if 0 + CZapitDestExec * zexec = new CZapitDestExec(); + + CMenuWidget* zapit_menu = new CMenuWidget(LOCALE_EXTRA_ZAPIT_MENU, "settings.raw"); + zapit_menu->addItem( GenericMenuBack ); + //zapit_menu->addItem(new CMenuForwarder(LOCALE_EXTRA_SAVESETTINGS, true, "", new CZapitDestExec, "savesettings", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + zapit_menu->addItem(new CMenuForwarder(LOCALE_EXTRA_SAVESETTINGS, true, "", this, "savesettings", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + zapit_menu->addItem( GenericMenuSeparatorLine ); + + zapit_menu->addItem(new CMenuOptionChooser(LOCALE_EXTRA_ZAPIT_MAKE_BOUQUET, (int *)&zapitCfg.makeRemainingChannelsBouquet, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + zapit_menu->addItem(new CMenuOptionChooser(LOCALE_EXTRA_ZAPIT_SAVE_LAST, (int *)&zapitCfg.saveLastChannel, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + zapit_menu->addItem(new CMenuOptionChooser(LOCALE_EXTRA_ZAPIT_WRITE_NAMES, (int *)&zapitCfg.writeChannelsNames, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + zapit_menu->addItem(new CMenuOptionChooser(LOCALE_EXTRA_ZAPIT_SORTNAMES, (int *)&zapitCfg.sortNames, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + +#if 0 + zapit_menu->addItem(new CMenuOptionNumberChooser(LOCALE_EXTRA_ZAPIT_TIMEOUT, (int *)&zapitCfg.feTimeout, true, 0, 100) ); +#else + zapit_menu->addItem(new CMenuOptionChooser(LOCALE_EXTRA_ZAPIT_FASTZAP, (int *)&zapitCfg.fastZap, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); +#endif + zapit_menu->addItem( new CMenuOptionChooser(LOCALE_ZAPIT_SCANSDT, (int *)&zapitCfg.scanSDT, SECTIONSD_SCAN_OPTIONS, SECTIONSD_SCAN_OPTIONS_COUNT, true)); + + zapit_menu->addItem(new CMenuOptionChooser(LOCALE_EXTRA_ZAPIT_SCANPIDS, (int *)&zapitCfg.scanPids, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + zapit_menu->addItem(new CMenuOptionChooser(LOCALE_EXTRA_ZAPIT_HVOLTAGE, (int *)&zapitCfg.highVoltage, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + + zapit_menu->addItem( GenericMenuSeparatorLine ); + zapit_menu->addItem(new CMenuForwarder(LOCALE_EXTRA_ZAPIT_DELETE, true, "", zexec /*new CZapitDestExec*/, "delete")); + zapit_menu->addItem(new CMenuForwarder(LOCALE_EXTRA_ZAPIT_BACKUP, true, "", zexec /*new CZapitDestExec*/, "backup")); + zapit_menu->addItem(new CMenuForwarder(LOCALE_EXTRA_ZAPIT_RESTORE, true, "", zexec /*new CZapitDestExec*/, "restore")); +#endif + + service.addItem(GenericMenuSeparator); + service.addItem(GenericMenuBack); + service.addItem(GenericMenuSeparatorLine); + service.addItem(new CMenuForwarder(LOCALE_SERVICEMENU_SCANTS , true, NULL, &scanSettings, "savesettings", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED) ); + // service.addItem(new CMenuForwarder(LOCALE_EXTRA_ZAPIT_MENU , true, NULL, zapit_menu, NULL, CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN)); + service.addItem(new CMenuForwarder(LOCALE_SERVICEMENU_RELOAD , true, NULL, this, "reloadchannels", CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW)); + service.addItem(new CMenuForwarder(LOCALE_BOUQUETEDITOR_NAME , true, NULL, new CBEBouquetWidget(), NULL, CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE )); + + CDataResetNotifier * resetNotifier = new CDataResetNotifier(); + service.addItem(new CMenuForwarder(LOCALE_RESET_CHANNELS , true, NULL, resetNotifier, "channels", CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN )); + //service.addItem(new CMenuForwarder(LOCALE_SERVICEMENU_GETPLUGINS, true, NULL, this, "reloadplugins")); + + service.addItem(GenericMenuSeparatorLine); + service.addItem(new CMenuForwarder(LOCALE_SERVICEMENU_IMAGEINFO, true, NULL, new CImageInfo(), NULL, CRCInput::RC_help, NEUTRINO_ICON_BUTTON_HELP_SMALL ), false); + service.addItem(new CMenuForwarder(LOCALE_SERVICEMENU_RESTART , true, NULL, this, "restart", CRCInput::RC_standby, "power.raw")); + //softupdate + //if(softupdate) + { + dprintf(DEBUG_DEBUG, "init soft-update-stuff\n"); + CMenuWidget* updateSettings = new CMenuWidget(LOCALE_SERVICEMENU_UPDATE, "softupdate.raw", 550); + updateSettings->addItem(GenericMenuSeparator); + updateSettings->addItem(GenericMenuBack); + updateSettings->addItem(GenericMenuSeparatorLine); + + //experten-funktionen für mtd lesen/schreiben + CMenuWidget* mtdexpert = new CMenuWidget(LOCALE_FLASHUPDATE_EXPERTFUNCTIONS, "softupdate.raw"); + mtdexpert->addItem(GenericMenuSeparator); + mtdexpert->addItem(GenericMenuBack); + mtdexpert->addItem(GenericMenuSeparatorLine); + CFlashExpert* fe = new CFlashExpert(); + + //mtdexpert->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_READFLASH , true, NULL, fe, "readflash" )); + //if(softupdate) + // mtdexpert->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_WRITEFLASH , true, NULL, fe, "writeflash" )); + mtdexpert->addItem(GenericMenuSeparatorLine); + mtdexpert->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_READFLASHMTD , true, NULL, fe, "readflashmtd" )); + if(softupdate) + mtdexpert->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_WRITEFLASHMTD, true, NULL, fe, "writeflashmtd")); + mtdexpert->addItem(GenericMenuSeparatorLine); + + CStringInputSMS * updateSettings_url_file = new CStringInputSMS(LOCALE_FLASHUPDATE_URL_FILE, g_settings.softupdate_url_file, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789!""§$%&/()=?-. "); + mtdexpert->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_URL_FILE, true, g_settings.softupdate_url_file, updateSettings_url_file)); + + updateSettings->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_EXPERTFUNCTIONS, true, NULL, mtdexpert, "", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + + updateSettings->addItem(GenericMenuSeparatorLine); + CMenuOptionChooser *oj = new CMenuOptionChooser(LOCALE_FLASHUPDATE_UPDATEMODE, &g_settings.softupdate_mode, FLASHUPDATE_UPDATEMODE_OPTIONS, FLASHUPDATE_UPDATEMODE_OPTION_COUNT, true, NULL, CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN); + updateSettings->addItem( oj ); + updateSettings->addItem( new CMenuForwarder(LOCALE_EXTRA_UPDATE_DIR, true, g_settings.update_dir , this, "update_dir", CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW) ); + + /* show current version */ + updateSettings->addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_FLASHUPDATE_CURRENTVERSION_SEP)); + + /* get current version SBBBYYYYMMTTHHMM -- formatsting */ + CConfigFile configfile('\t'); + + const char * versionString = (configfile.loadConfig("/.version")) ? (configfile.getString( "version", "????????????????").c_str()) : "????????????????"; + + dprintf(DEBUG_INFO, "current flash-version: %s\n", versionString); + + static CFlashVersionInfo versionInfo(versionString); + + updateSettings->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_CURRENTVERSIONDATE , false, versionInfo.getDate())); + updateSettings->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_CURRENTVERSIONTIME , false, versionInfo.getTime())); + updateSettings->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_CURRENTRELEASECYCLE , false, versionInfo.getReleaseCycle())); + /* versionInfo.getType() returns const char * which is never deallocated */ + updateSettings->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_CURRENTVERSIONSNAPSHOT, false, versionInfo.getType())); + + updateSettings->addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_FLASHUPDATE_PROXYSERVER_SEP)); + + CStringInputSMS * updateSettings_proxy = new CStringInputSMS(LOCALE_FLASHUPDATE_PROXYSERVER, g_settings.softupdate_proxyserver, 23, LOCALE_FLASHUPDATE_PROXYSERVER_HINT1, LOCALE_FLASHUPDATE_PROXYSERVER_HINT2, "abcdefghijklmnopqrstuvwxyz0123456789-.: "); + updateSettings->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_PROXYSERVER, true, g_settings.softupdate_proxyserver, updateSettings_proxy)); + + CStringInputSMS * updateSettings_proxyuser = new CStringInputSMS(LOCALE_FLASHUPDATE_PROXYUSERNAME, g_settings.softupdate_proxyusername, 23, LOCALE_FLASHUPDATE_PROXYUSERNAME_HINT1, LOCALE_FLASHUPDATE_PROXYUSERNAME_HINT2, "abcdefghijklmnopqrstuvwxyz0123456789!""§$%&/()=?-. "); + updateSettings->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_PROXYUSERNAME, true, g_settings.softupdate_proxyusername, updateSettings_proxyuser)); + + CStringInputSMS * updateSettings_proxypass = new CStringInputSMS(LOCALE_FLASHUPDATE_PROXYPASSWORD, g_settings.softupdate_proxypassword, 20, LOCALE_FLASHUPDATE_PROXYPASSWORD_HINT1, LOCALE_FLASHUPDATE_PROXYPASSWORD_HINT2, "abcdefghijklmnopqrstuvwxyz0123456789!""§$%&/()=?-. "); + updateSettings->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_PROXYPASSWORD, true, g_settings.softupdate_proxypassword, updateSettings_proxypass)); + + updateSettings->addItem(GenericMenuSeparatorLine); + updateSettings->addItem(new CMenuForwarder(LOCALE_FLASHUPDATE_CHECKUPDATE, true, NULL, new CFlashUpdate(), "", CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE)); + + service.addItem(new CMenuForwarder(LOCALE_SERVICEMENU_UPDATE, true, NULL, updateSettings)); + } +} + +#define MESSAGEBOX_NO_YES_OPTION_COUNT 2 +const CMenuOptionChooser::keyval MESSAGEBOX_NO_YES_OPTIONS[MESSAGEBOX_NO_YES_OPTION_COUNT] = +{ + { 0, LOCALE_MESSAGEBOX_NO }, + { 1, LOCALE_MESSAGEBOX_YES } +}; + +#define PICTUREVIEWER_SCALING_OPTION_COUNT 3 +const CMenuOptionChooser::keyval PICTUREVIEWER_SCALING_OPTIONS[PICTUREVIEWER_SCALING_OPTION_COUNT] = +{ + { CPictureViewer::SIMPLE, LOCALE_PICTUREVIEWER_RESIZE_SIMPLE }, + { CPictureViewer::COLOR , LOCALE_PICTUREVIEWER_RESIZE_COLOR_AVERAGE }, + { CPictureViewer::NONE , LOCALE_PICTUREVIEWER_RESIZE_NONE } +}; + +#define AUDIOPLAYER_DISPLAY_ORDER_OPTION_COUNT 2 +const CMenuOptionChooser::keyval AUDIOPLAYER_DISPLAY_ORDER_OPTIONS[AUDIOPLAYER_DISPLAY_ORDER_OPTION_COUNT] = +{ + { CAudioPlayerGui::ARTIST_TITLE, LOCALE_AUDIOPLAYER_ARTIST_TITLE }, + { CAudioPlayerGui::TITLE_ARTIST, LOCALE_AUDIOPLAYER_TITLE_ARTIST } +}; + +void CNeutrinoApp::InitAudioplPicSettings(CMenuWidget &audioplPicSettings) +{ + audioplPicSettings.addItem(GenericMenuSeparator); + audioplPicSettings.addItem(GenericMenuBack); + + audioplPicSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_PICTUREVIEWER_HEAD)); + audioplPicSettings.addItem(new CMenuOptionChooser(LOCALE_PICTUREVIEWER_SCALING , &g_settings.picviewer_scaling , PICTUREVIEWER_SCALING_OPTIONS , PICTUREVIEWER_SCALING_OPTION_COUNT , true )); + CStringInput * pic_timeout= new CStringInput(LOCALE_PICTUREVIEWER_SLIDE_TIME, g_settings.picviewer_slide_time, 2, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "0123456789 "); + audioplPicSettings.addItem(new CMenuForwarder(LOCALE_PICTUREVIEWER_SLIDE_TIME, true, g_settings.picviewer_slide_time, pic_timeout)); + audioplPicSettings.addItem(new CMenuForwarder(LOCALE_PICTUREVIEWER_DEFDIR, true, g_settings.network_nfs_picturedir, this, "picturedir")); + + audioplPicSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_AUDIOPLAYER_NAME)); + audioplPicSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOPLAYER_DISPLAY_ORDER, &g_settings.audioplayer_display , AUDIOPLAYER_DISPLAY_ORDER_OPTIONS, AUDIOPLAYER_DISPLAY_ORDER_OPTION_COUNT, true )); + audioplPicSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOPLAYER_FOLLOW , &g_settings.audioplayer_follow , MESSAGEBOX_NO_YES_OPTIONS , MESSAGEBOX_NO_YES_OPTION_COUNT , true )); + audioplPicSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOPLAYER_SELECT_TITLE_BY_NAME , &g_settings.audioplayer_select_title_by_name , MESSAGEBOX_NO_YES_OPTIONS , MESSAGEBOX_NO_YES_OPTION_COUNT , true )); + audioplPicSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOPLAYER_REPEAT_ON , &g_settings.audioplayer_repeat_on , MESSAGEBOX_NO_YES_OPTIONS , MESSAGEBOX_NO_YES_OPTION_COUNT , true )); + audioplPicSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOPLAYER_SHOW_PLAYLIST, &g_settings.audioplayer_show_playlist, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true )); + + CStringInput * audio_screensaver= new CStringInput(LOCALE_AUDIOPLAYER_SCREENSAVER_TIMEOUT, g_settings.audioplayer_screensaver, 2, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "0123456789 "); + audioplPicSettings.addItem(new CMenuForwarder(LOCALE_AUDIOPLAYER_SCREENSAVER_TIMEOUT, true, g_settings.audioplayer_screensaver, audio_screensaver)); + + audioplPicSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOPLAYER_HIGHPRIO , &g_settings.audioplayer_highprio , MESSAGEBOX_NO_YES_OPTIONS , MESSAGEBOX_NO_YES_OPTION_COUNT , true )); + + if(CVFD::getInstance()->has_lcd) //FIXME + audioplPicSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOPLAYER_SPECTRUM , &g_settings.spectrum , MESSAGEBOX_NO_YES_OPTIONS , MESSAGEBOX_NO_YES_OPTION_COUNT , true )); + audioplPicSettings.addItem(new CMenuForwarder(LOCALE_AUDIOPLAYER_DEFDIR, true, g_settings.network_nfs_audioplayerdir, this, "audioplayerdir")); + audioplPicSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOPLAYER_ENABLE_SC_METADATA, &g_settings.audioplayer_enable_sc_metadata, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true )); + +} + +#define MISCSETTINGS_FB_DESTINATION_OPTION_COUNT 3 +const CMenuOptionChooser::keyval MISCSETTINGS_FB_DESTINATION_OPTIONS[MISCSETTINGS_FB_DESTINATION_OPTION_COUNT] = +{ + { 0, LOCALE_OPTIONS_NULL }, + { 1, LOCALE_OPTIONS_SERIAL }, + { 2, LOCALE_OPTIONS_FB } +}; + +#define MISCSETTINGS_FILESYSTEM_IS_UTF8_OPTION_COUNT 2 +const CMenuOptionChooser::keyval MISCSETTINGS_FILESYSTEM_IS_UTF8_OPTIONS[MISCSETTINGS_FILESYSTEM_IS_UTF8_OPTION_COUNT] = +{ + { 0, LOCALE_FILESYSTEM_IS_UTF8_OPTION_ISO8859_1 }, + { 1, LOCALE_FILESYSTEM_IS_UTF8_OPTION_UTF8 } +}; + +#define INFOBAR_SUBCHAN_DISP_POS_OPTIONS_COUNT 4 +const CMenuOptionChooser::keyval INFOBAR_SUBCHAN_DISP_POS_OPTIONS[INFOBAR_SUBCHAN_DISP_POS_OPTIONS_COUNT]= +{ + { 0 , LOCALE_SETTINGS_POS_TOP_RIGHT }, + { 1 , LOCALE_SETTINGS_POS_TOP_LEFT }, + { 2 , LOCALE_SETTINGS_POS_BOTTOM_LEFT }, + { 3 , LOCALE_SETTINGS_POS_BOTTOM_RIGHT } +}; + +#define CHANNELLIST_EPGTEXT_ALIGN_RIGHT_OPTIONS_COUNT 2 +const CMenuOptionChooser::keyval CHANNELLIST_EPGTEXT_ALIGN_RIGHT_OPTIONS[CHANNELLIST_EPGTEXT_ALIGN_RIGHT_OPTIONS_COUNT]= +{ + { 0 , LOCALE_CHANNELLIST_EPGTEXT_ALIGN_LEFT }, + { 1 , LOCALE_CHANNELLIST_EPGTEXT_ALIGN_RIGHT } +}; + +#define CPU_FREQ_OPTION_COUNT 13 +const CMenuOptionChooser::keyval CPU_FREQ_OPTIONS[CPU_FREQ_OPTION_COUNT] = +{ + { 0, LOCALE_CPU_FREQ_DEFAULT }, + { 50, NONEXISTANT_LOCALE, "50 Mhz"}, + { 100, NONEXISTANT_LOCALE, "100 Mhz"}, + { 150, NONEXISTANT_LOCALE, "150 Mhz"}, + { 200, NONEXISTANT_LOCALE, "200 Mhz"}, + { 250, NONEXISTANT_LOCALE, "250 Mhz"}, + { 300, NONEXISTANT_LOCALE, "300 Mhz"}, + { 350, NONEXISTANT_LOCALE, "350 Mhz"}, + { 400, NONEXISTANT_LOCALE, "400 Mhz"}, + { 450, NONEXISTANT_LOCALE, "450 Mhz"}, + { 500, NONEXISTANT_LOCALE, "500 Mhz"}, + { 550, NONEXISTANT_LOCALE, "550 Mhz"}, + { 600, NONEXISTANT_LOCALE, "600 Mhz"}, +}; + +void CNeutrinoApp::InitMiscSettings(CMenuWidget &miscSettings) +{ + dprintf(DEBUG_DEBUG, "init miscsettings\n"); + miscSettings.addItem(GenericMenuSeparator); + miscSettings.addItem(GenericMenuBack); + miscSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_SAVESETTINGSNOW, true, NULL, this, "savesettings", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + miscSettings.addItem( new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_MISCSETTINGS_GENERAL)); + +#if 0 + CMenuOptionChooser *m1 = new CMenuOptionChooser(LOCALE_MISCSETTINGS_SHUTDOWN_REAL_RCDELAY, &g_settings.shutdown_real_rcdelay, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, !g_settings.shutdown_real); + + CMiscNotifier* miscNotifier = new CMiscNotifier( m1 ); + + miscSettings.addItem(new CMenuOptionChooser(LOCALE_MISCSETTINGS_SHUTDOWN_REAL, &g_settings.shutdown_real, OPTIONS_OFF1_ON0_OPTIONS, OPTIONS_OFF1_ON0_OPTION_COUNT, true, miscNotifier)); +#endif + CStringInput * miscSettings_shutdown_count = new CStringInput(LOCALE_MISCSETTINGS_SHUTDOWN_COUNT, g_settings.shutdown_count, 3, LOCALE_MISCSETTINGS_SHUTDOWN_COUNT_HINT1, LOCALE_MISCSETTINGS_SHUTDOWN_COUNT_HINT2, "0123456789 "); + + miscSettings.addItem(new CMenuForwarder(LOCALE_MISCSETTINGS_SHUTDOWN_COUNT, true, g_settings.shutdown_count, miscSettings_shutdown_count)); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_EXTRA_STARTSTANDBY, &g_settings.power_standby, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + + //miscSettings.addItem(new CMenuOptionChooser(LOCALE_MISCSETTINGS_INFOBAR_SAT_DISPLAY, &g_settings.infobar_sat_display, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_EXTRA_ROTORSWAP, &g_settings.rotor_swap, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + + miscSettings.addItem(new CMenuOptionChooser(LOCALE_INFOVIEWER_SUBCHAN_DISP_POS, &g_settings.infobar_subchan_disp_pos, INFOBAR_SUBCHAN_DISP_POS_OPTIONS, INFOBAR_SUBCHAN_DISP_POS_OPTIONS_COUNT, true)); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_EXTRA_CACHE_TXT, (int *)&g_settings.cacheTXT, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_MISCSETTINGS_VIRTUAL_ZAP_MODE, &g_settings.virtual_zap_mode, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + + //channellist + miscSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_MISCSETTINGS_CHANNELLIST)); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_MISCSETTINGS_CHANNELLIST_EPGTEXT_ALIGN, &g_settings.channellist_epgtext_align_right, CHANNELLIST_EPGTEXT_ALIGN_RIGHT_OPTIONS, CHANNELLIST_EPGTEXT_ALIGN_RIGHT_OPTIONS_COUNT, true)); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_CHANNELLIST_EXTENDED, &g_settings.channellist_extended, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_CHANNELLIST_MAKE_HDLIST, &g_settings.make_hd_list, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_EXTRA_ZAP_CYCLE, &g_settings.zap_cycle, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + + miscSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_MISCSETTINGS_EPG_HEAD)); + + CSectionsdConfigNotifier* sectionsdConfigNotifier = new CSectionsdConfigNotifier; + miscSettings.addItem(new CMenuOptionChooser(LOCALE_MISCSETTINGS_EPG_SAVE, &g_settings.epg_save, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + CStringInput * miscSettings_epg_cache = new CStringInput(LOCALE_MISCSETTINGS_EPG_CACHE, &g_settings.epg_cache, 2,LOCALE_MISCSETTINGS_EPG_CACHE_HINT1, LOCALE_MISCSETTINGS_EPG_CACHE_HINT2 , "0123456789 ", sectionsdConfigNotifier); + miscSettings.addItem(new CMenuForwarder(LOCALE_MISCSETTINGS_EPG_CACHE, true, g_settings.epg_cache, miscSettings_epg_cache)); + CStringInput * miscSettings_epg_cache_e = new CStringInput(LOCALE_MISCSETTINGS_EPG_EXTENDEDCACHE, &g_settings.epg_extendedcache, 3,LOCALE_MISCSETTINGS_EPG_EXTENDEDCACHE_HINT1, LOCALE_MISCSETTINGS_EPG_EXTENDEDCACHE_HINT2 , "0123456789 ", sectionsdConfigNotifier); + + miscSettings.addItem(new CMenuForwarder(LOCALE_MISCSETTINGS_EPG_EXTENDEDCACHE, true, g_settings.epg_extendedcache, miscSettings_epg_cache_e)); + + CStringInput * miscSettings_epg_old_events = new CStringInput(LOCALE_MISCSETTINGS_EPG_OLD_EVENTS, &g_settings.epg_old_events, 2,LOCALE_MISCSETTINGS_EPG_OLD_EVENTS_HINT1, LOCALE_MISCSETTINGS_EPG_OLD_EVENTS_HINT2 , "0123456789 ", sectionsdConfigNotifier); + miscSettings.addItem(new CMenuForwarder(LOCALE_MISCSETTINGS_EPG_OLD_EVENTS, true, g_settings.epg_old_events, miscSettings_epg_old_events)); + CStringInput * miscSettings_epg_max_events = new CStringInput(LOCALE_MISCSETTINGS_EPG_MAX_EVENTS, &g_settings.epg_max_events, 5,LOCALE_MISCSETTINGS_EPG_MAX_EVENTS_HINT1, LOCALE_MISCSETTINGS_EPG_MAX_EVENTS_HINT2 , "0123456789 ", sectionsdConfigNotifier); + miscSettings.addItem(new CMenuForwarder(LOCALE_MISCSETTINGS_EPG_MAX_EVENTS, true, g_settings.epg_max_events, miscSettings_epg_max_events)); + miscSettings.addItem(new CMenuForwarder(LOCALE_MISCSETTINGS_EPG_DIR, true, g_settings.epg_dir, this, "epgdir")); + +#if 0 + miscSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_MISCSETTINGS_DRIVER_BOOT)); + if(access("/var/tuxbox/emlog", F_OK) == 0) + g_settings.emlog = 1; + miscSettings.addItem(new CMenuOptionChooser(LOCALE_EXTRA_USELOG, &g_settings.emlog, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, new CLogChangeNotifier)); +#endif + +#if 0 + keySetupNotifier = new CKeySetupNotifier; + CStringInput * keySettings_repeat_genericblocker = new CStringInput(LOCALE_KEYBINDINGMENU_REPEATBLOCKGENERIC, g_settings.repeat_genericblocker, 3, LOCALE_REPEATBLOCKER_HINT_1, LOCALE_REPEATBLOCKER_HINT_2, "0123456789 ", keySetupNotifier); + CStringInput * keySettings_repeatBlocker = new CStringInput(LOCALE_KEYBINDINGMENU_REPEATBLOCK, g_settings.repeat_blocker, 3, LOCALE_REPEATBLOCKER_HINT_1, LOCALE_REPEATBLOCKER_HINT_2, "0123456789 ", keySetupNotifier); + keySetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + + miscSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_KEYBINDINGMENU_RC)); + miscSettings.addItem(new CMenuForwarder(LOCALE_KEYBINDINGMENU_REPEATBLOCK, true, g_settings.repeat_blocker, keySettings_repeatBlocker)); + miscSettings.addItem(new CMenuForwarder(LOCALE_KEYBINDINGMENU_REPEATBLOCKGENERIC, true, g_settings.repeat_genericblocker, keySettings_repeat_genericblocker)); + miscSettings.addItem(m1); +#endif + + miscSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_FILEBROWSER_HEAD)); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_FILESYSTEM_IS_UTF8 , &g_settings.filesystem_is_utf8 , MISCSETTINGS_FILESYSTEM_IS_UTF8_OPTIONS, MISCSETTINGS_FILESYSTEM_IS_UTF8_OPTION_COUNT, true )); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_FILEBROWSER_SHOWRIGHTS , &g_settings.filebrowser_showrights , MESSAGEBOX_NO_YES_OPTIONS , MESSAGEBOX_NO_YES_OPTION_COUNT , true )); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_FILEBROWSER_DENYDIRECTORYLEAVE, &g_settings.filebrowser_denydirectoryleave, MESSAGEBOX_NO_YES_OPTIONS , MESSAGEBOX_NO_YES_OPTION_COUNT , true )); + // miscSettings.addItem(new CMenuForwarder(LOCALE_EXTRA_KEY_PLUGIN, true, g_settings.onekey_plugin,this,"onekeyplugin")); + funNotifier = new CFanControlNotifier(); + //miscSettings.addItem(new CMenuOptionNumberChooser(LOCALE_FAN_SPEED, &g_settings.fan_speed, true, 0, 14, funNotifier, 0, 0, LOCALE_OPTIONS_OFF) ); + miscSettings.addItem(GenericMenuSeparatorLine); + miscSettings.addItem(new CMenuOptionNumberChooser(LOCALE_FAN_SPEED, &g_settings.fan_speed, true, 1, 14, funNotifier, 0, 0, LOCALE_OPTIONS_OFF) ); + funNotifier->changeNotify(NONEXISTANT_LOCALE, (void*) &g_settings.fan_speed); + + CCpuFreqNotifier * cpuNotifier = new CCpuFreqNotifier(); +#if 0 + miscSettings.addItem(new CMenuOptionChooser(LOCALE_CPU_FREQ_NORMAL, &g_settings.cpufreq, CPU_FREQ_OPTIONS, CPU_FREQ_OPTION_COUNT, true, cpuNotifier)); + miscSettings.addItem(new CMenuOptionChooser(LOCALE_CPU_FREQ_STANDBY, &g_settings.standby_cpufreq, CPU_FREQ_OPTIONS, CPU_FREQ_OPTION_COUNT, true)); +#endif +} + +void CNeutrinoApp::InitLanguageSettings(CMenuWidget &languageSettings) +{ + languageSettings.addItem(GenericMenuSeparator); + languageSettings.addItem(GenericMenuBack); + languageSettings.addItem(GenericMenuSeparatorLine); + + struct dirent **namelist; + int n; + // printf("scanning locale dir now....(perhaps)\n"); + + char *pfad[] = {(char *) DATADIR "/neutrino/locale",(char *) "/var/tuxbox/config/locale"}; + + for(int p = 0;p < 2;p++) { + n = scandir(pfad[p], &namelist, 0, alphasort); + if(n < 0) { + perror("loading locales: scandir"); + } else { + for(int count=0;countd_name); + char * pos = strstr(locale, ".locale"); + if(pos != NULL) { + char iname[50]; + *pos = '\0'; + sprintf(iname, "%s.raw", locale); + CMenuOptionLanguageChooser* oj = new CMenuOptionLanguageChooser((char*)locale, this, iname); + oj->addOption(locale); + languageSettings.addItem( oj ); + } else + free(locale); + free(namelist[count]); + } + free(namelist); + } + } +} + +#define AUDIOMENU_ANALOGOUT_OPTION_COUNT 3 +const CMenuOptionChooser::keyval AUDIOMENU_ANALOGOUT_OPTIONS[AUDIOMENU_ANALOGOUT_OPTION_COUNT] = +{ + { 0, LOCALE_AUDIOMENU_STEREO }, + { 1, LOCALE_AUDIOMENU_MONOLEFT }, + { 2, LOCALE_AUDIOMENU_MONORIGHT } +}; + +#define AUDIOMENU_AVS_CONTROL_OPTION_COUNT 3 +const CMenuOptionChooser::keyval AUDIOMENU_AVS_CONTROL_OPTIONS[AUDIOMENU_AVS_CONTROL_OPTION_COUNT] = +{ + { CControld::TYPE_OST , LOCALE_AUDIOMENU_OST }, + { CControld::TYPE_AVS , LOCALE_AUDIOMENU_AVS }, + { CControld::TYPE_LIRC, LOCALE_AUDIOMENU_LIRC } +}; + +#define AUDIOMENU_SRS_OPTION_COUNT 2 +const CMenuOptionChooser::keyval AUDIOMENU_SRS_OPTIONS[AUDIOMENU_SRS_OPTION_COUNT] = +{ + { 0 , LOCALE_SRS_ALGO_LIGHT }, + { 1 , LOCALE_SRS_ALGO_NORMAL } +}; + +#define AUDIOMENU_AVSYNC_OPTION_COUNT 3 +const CMenuOptionChooser::keyval AUDIOMENU_AVSYNC_OPTIONS[AUDIOMENU_AVSYNC_OPTION_COUNT] = +{ + { 0, LOCALE_OPTIONS_OFF }, + { 1, LOCALE_OPTIONS_ON }, + { 2, LOCALE_AUDIOMENU_AVSYNC_AM } +}; + +#define AUDIOMENU_CLOCKREC_OPTION_COUNT 3 +const CMenuOptionChooser::keyval AUDIOMENU_CLOCKREC_OPTIONS[AUDIOMENU_CLOCKREC_OPTION_COUNT] = +{ + { 0, LOCALE_OPTIONS_OFF }, + { 1, LOCALE_OPTIONS_ON }, +}; + +void CNeutrinoApp::InitAudioSettings(CMenuWidget &audioSettings, CAudioSetupNotifier* audioSetupNotifier) +{ + audioSettings.addItem(GenericMenuSeparator); + audioSettings.addItem(GenericMenuBack); + audioSettings.addItem(GenericMenuSeparatorLine); + + audioSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOMENU_ANALOGOUT, &g_settings.audio_AnalogMode, AUDIOMENU_ANALOGOUT_OPTIONS, AUDIOMENU_ANALOGOUT_OPTION_COUNT, true, audioSetupNotifier)); + audioSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOMENU_DOLBYDIGITAL, &g_settings.audio_DolbyDigital, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, audioSetupNotifier)); + audioSettings.addItem(new CMenuOptionChooser(LOCALE_EXTRA_ENGLISH, &g_settings.audio_english, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, audioSetupNotifier)); + audioSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOMENU_HDMI_DD, &g_settings.hdmi_dd, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, audioSetupNotifier)); + audioSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOMENU_SPDIF_DD, &g_settings.spdif_dd, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, audioSetupNotifier)); + audioSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOMENU_AVSYNC, &g_settings.avsync, AUDIOMENU_AVSYNC_OPTIONS, AUDIOMENU_AVSYNC_OPTION_COUNT, true, audioSetupNotifier)); + audioSettings.addItem(new CMenuOptionChooser(LOCALE_AUDIOMENU_CLOCKREC, &g_settings.clockrec, AUDIOMENU_CLOCKREC_OPTIONS, AUDIOMENU_CLOCKREC_OPTION_COUNT, true, audioSetupNotifier)); + audioSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_SRS_IQ)); + audioSettings.addItem(new CMenuOptionChooser(LOCALE_SRS_IQ, &g_settings.srs_enable, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, audioSetupNotifier)); + audioSettings.addItem(new CMenuOptionChooser(LOCALE_SRS_ALGO, &g_settings.srs_algo, AUDIOMENU_SRS_OPTIONS, AUDIOMENU_SRS_OPTION_COUNT, true, audioSetupNotifier)); + audioSettings.addItem(new CMenuOptionChooser(LOCALE_SRS_NMGR, &g_settings.srs_nmgr_enable, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, audioSetupNotifier)); + audioSettings.addItem(new CMenuOptionNumberChooser(LOCALE_SRS_VOLUME, &g_settings.srs_ref_volume, true, 1, 100, audioSetupNotifier)); + +#if 0 + CStringInput * audio_PCMOffset = new CStringInput(LOCALE_AUDIOMENU_PCMOFFSET, g_settings.audio_PCMOffset, 2, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "0123456789 ", audioSetupNotifier); + CMenuForwarder *mf = new CMenuForwarder(LOCALE_AUDIOMENU_PCMOFFSET, (g_settings.audio_avs_Control == CControld::TYPE_LIRC), g_settings.audio_PCMOffset, audio_PCMOffset ); + audioSettings.addItem(mf); +#endif +} + + + +#if 1 +#define PARENTALLOCK_PROMPT_OPTION_COUNT 3 +#else +#define PARENTALLOCK_PROMPT_OPTION_COUNT 4 +#endif +const CMenuOptionChooser::keyval PARENTALLOCK_PROMPT_OPTIONS[PARENTALLOCK_PROMPT_OPTION_COUNT] = +{ + { PARENTALLOCK_PROMPT_NEVER , LOCALE_PARENTALLOCK_NEVER }, +#if 0 + { PARENTALLOCK_PROMPT_ONSTART , LOCALE_PARENTALLOCK_ONSTART }, +#endif + { PARENTALLOCK_PROMPT_CHANGETOLOCKED, LOCALE_PARENTALLOCK_CHANGETOLOCKED }, + { PARENTALLOCK_PROMPT_ONSIGNAL , LOCALE_PARENTALLOCK_ONSIGNAL } +}; + +#define PARENTALLOCK_LOCKAGE_OPTION_COUNT 3 +const CMenuOptionChooser::keyval PARENTALLOCK_LOCKAGE_OPTIONS[PARENTALLOCK_LOCKAGE_OPTION_COUNT] = +{ + { 12, LOCALE_PARENTALLOCK_LOCKAGE12 }, + { 16, LOCALE_PARENTALLOCK_LOCKAGE16 }, + { 18, LOCALE_PARENTALLOCK_LOCKAGE18 } +}; + +void CNeutrinoApp::InitParentalLockSettings(CMenuWidget &parentallockSettings) +{ + parentallockSettings.addItem(GenericMenuSeparator); + parentallockSettings.addItem(GenericMenuBack); + parentallockSettings.addItem(GenericMenuSeparatorLine); + + parentallockSettings.addItem(new CMenuOptionChooser(LOCALE_PARENTALLOCK_PROMPT , &g_settings.parentallock_prompt , PARENTALLOCK_PROMPT_OPTIONS , PARENTALLOCK_PROMPT_OPTION_COUNT , !parentallocked)); + + parentallockSettings.addItem(new CMenuOptionChooser(LOCALE_PARENTALLOCK_LOCKAGE, &g_settings.parentallock_lockage, PARENTALLOCK_LOCKAGE_OPTIONS, PARENTALLOCK_LOCKAGE_OPTION_COUNT, !parentallocked)); + + CPINChangeWidget * pinChangeWidget = new CPINChangeWidget(LOCALE_PARENTALLOCK_CHANGEPIN, g_settings.parentallock_pincode, 4, LOCALE_PARENTALLOCK_CHANGEPIN_HINT1); + parentallockSettings.addItem( new CMenuForwarder(LOCALE_PARENTALLOCK_CHANGEPIN, true, g_settings.parentallock_pincode, pinChangeWidget)); +} + +void CNeutrinoApp::InitNetworkSettings(CMenuWidget &networkSettings) +{ + CIPInput * networkSettings_NetworkIP = new CIPInput(LOCALE_NETWORKMENU_IPADDRESS , networkConfig.address , LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2, MyIPChanger); + CIPInput * networkSettings_NetMask = new CIPInput(LOCALE_NETWORKMENU_NETMASK , networkConfig.netmask , LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CIPInput * networkSettings_Broadcast = new CIPInput(LOCALE_NETWORKMENU_BROADCAST , networkConfig.broadcast , LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CIPInput * networkSettings_Gateway = new CIPInput(LOCALE_NETWORKMENU_GATEWAY , networkConfig.gateway , LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CIPInput * networkSettings_NameServer = new CIPInput(LOCALE_NETWORKMENU_NAMESERVER, networkConfig.nameserver, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + + CSectionsdConfigNotifier* sectionsdConfigNotifier = new CSectionsdConfigNotifier; + CStringInputSMS * networkSettings_NtpServer = new CStringInputSMS(LOCALE_NETWORKMENU_NTPSERVER, &g_settings.network_ntpserver, 30, LOCALE_NETWORKMENU_NTPSERVER_HINT1, LOCALE_NETWORKMENU_NTPSERVER_HINT2, "abcdefghijklmnopqrstuvwxyz0123456789-. ", sectionsdConfigNotifier); + CStringInput * networkSettings_NtpRefresh = new CStringInput(LOCALE_NETWORKMENU_NTPREFRESH, &g_settings.network_ntprefresh, 3,LOCALE_NETWORKMENU_NTPREFRESH_HINT1, LOCALE_NETWORKMENU_NTPREFRESH_HINT2 , "0123456789 ", sectionsdConfigNotifier); + + CMenuForwarder *m0 = new CMenuForwarder(LOCALE_NETWORKMENU_SETUPNOW, true, NULL, this, "network", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED); + CMenuForwarder *m1 = new CMenuForwarder(LOCALE_NETWORKMENU_IPADDRESS , networkConfig.inet_static, networkConfig.address , networkSettings_NetworkIP ); + CMenuForwarder *m2 = new CMenuForwarder(LOCALE_NETWORKMENU_NETMASK , networkConfig.inet_static, networkConfig.netmask , networkSettings_NetMask ); + CMenuForwarder *m3 = new CMenuForwarder(LOCALE_NETWORKMENU_BROADCAST , networkConfig.inet_static, networkConfig.broadcast , networkSettings_Broadcast ); + CMenuForwarder *m4 = new CMenuForwarder(LOCALE_NETWORKMENU_GATEWAY , networkConfig.inet_static, networkConfig.gateway , networkSettings_Gateway ); + CMenuForwarder *m5 = new CMenuForwarder(LOCALE_NETWORKMENU_NAMESERVER, networkConfig.inet_static, networkConfig.nameserver, networkSettings_NameServer); + CMenuForwarder *m6 = new CMenuForwarder( LOCALE_NETWORKMENU_NTPSERVER, true , g_settings.network_ntpserver, networkSettings_NtpServer ); + CMenuForwarder *m7 = new CMenuForwarder( LOCALE_NETWORKMENU_NTPREFRESH, true , g_settings.network_ntprefresh, networkSettings_NtpRefresh ); + + CDHCPNotifier* dhcpNotifier = new CDHCPNotifier(m1,m2,m3,m4,m5); + + network_automatic_start = networkConfig.automatic_start ? 1 : 0; + CMenuOptionChooser* oj = new CMenuOptionChooser(LOCALE_NETWORKMENU_SETUPONSTARTUP, &network_automatic_start, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + + networkSettings.addItem(GenericMenuSeparator); + networkSettings.addItem(GenericMenuBack); + networkSettings.addItem(GenericMenuSeparatorLine); + + networkSettings.addItem( oj ); + networkSettings.addItem(new CMenuForwarder(LOCALE_NETWORKMENU_TEST, true, NULL, this, "networktest")); + networkSettings.addItem(new CMenuForwarder(LOCALE_NETWORKMENU_SHOW, true, NULL, this, "networkshow", CRCInput::RC_help, NEUTRINO_ICON_BUTTON_HELP_SMALL)); + networkSettings.addItem( m0 ); + + networkSettings.addItem(GenericMenuSeparatorLine); + + + network_dhcp = networkConfig.inet_static ? 0 : 1; + oj = new CMenuOptionChooser(LOCALE_NETWORKMENU_DHCP, &network_dhcp, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, dhcpNotifier); + networkSettings.addItem(oj); + networkSettings.addItem(GenericMenuSeparatorLine); + + networkSettings.addItem( m1); + networkSettings.addItem( m2); + networkSettings.addItem( m3); + + networkSettings.addItem(GenericMenuSeparatorLine); + networkSettings.addItem( m4); + networkSettings.addItem( m5); + networkSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_NETWORKMENU_NTPTITLE)); + networkSettings.addItem(new CMenuOptionChooser(LOCALE_NETWORKMENU_NTPENABLE, &g_settings.network_ntpenable, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, sectionsdConfigNotifier)); + networkSettings.addItem( m6); + networkSettings.addItem( m7); + + networkSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_NETWORKMENU_MOUNT)); + networkSettings.addItem(new CMenuForwarder(LOCALE_NFS_MOUNT , true, NULL, new CNFSMountGui(), NULL, CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN)); + networkSettings.addItem(new CMenuForwarder(LOCALE_NFS_UMOUNT, true, NULL, new CNFSUmountGui(), NULL, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW)); +} + +#define RECORDINGMENU_RECORDING_TYPE_OPTION_COUNT 4 +const CMenuOptionChooser::keyval RECORDINGMENU_RECORDING_TYPE_OPTIONS[RECORDINGMENU_RECORDING_TYPE_OPTION_COUNT] = +{ + { CNeutrinoApp::RECORDING_OFF , LOCALE_RECORDINGMENU_OFF }, + { CNeutrinoApp::RECORDING_SERVER, LOCALE_RECORDINGMENU_SERVER }, + { CNeutrinoApp::RECORDING_VCR , LOCALE_RECORDINGMENU_VCR }, + { CNeutrinoApp::RECORDING_FILE , LOCALE_RECORDINGMENU_FILE } +}; + +#define CHOOSE_DIRECT_REC_DIR_COUNT 3 +const CMenuOptionChooser::keyval CHOOSE_DIRECT_REC_DIR[RECORDINGMENU_RECORDING_TYPE_OPTION_COUNT] = +{ + {0, LOCALE_OPTIONS_OFF}, + {1, LOCALE_NFS_TYPE_NFS}, + {2, LOCALE_NFS_LOCALDIR} +}; +void CNeutrinoApp::InitRecordingSettings(CMenuWidget &recordingSettings) +{ +#if 0 + CIPInput * recordingSettings_server_ip = new CIPInput(LOCALE_RECORDINGMENU_SERVER_IP, g_settings.recording_server_ip, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CStringInput * recordingSettings_server_port = new CStringInput(LOCALE_RECORDINGMENU_SERVER_PORT, g_settings.recording_server_port, 6, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2, "0123456789 "); + + CMenuForwarder * mf1 = new CMenuForwarder(LOCALE_RECORDINGMENU_SERVER_IP, (g_settings.recording_type == RECORDING_SERVER), g_settings.recording_server_ip, recordingSettings_server_ip); + CMenuForwarder * mf2 = new CMenuForwarder(LOCALE_RECORDINGMENU_SERVER_PORT, (g_settings.recording_type == RECORDING_SERVER), g_settings.recording_server_port, recordingSettings_server_port); + + CMACInput * recordingSettings_server_mac = new CMACInput(LOCALE_RECORDINGMENU_SERVER_MAC, g_settings.recording_server_mac, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CMenuForwarder * mf3 = new CMenuForwarder(LOCALE_RECORDINGMENU_SERVER_MAC, ((g_settings.recording_type == RECORDING_SERVER) && g_settings.recording_server_wakeup==1), g_settings.recording_server_mac, recordingSettings_server_mac); + + CRecordingNotifier2 * RecordingNotifier2 = new CRecordingNotifier2(mf3); + + CMenuOptionChooser * oj2 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_SERVER_WAKEUP, &g_settings.recording_server_wakeup, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, (g_settings.recording_type == RECORDING_SERVER), RecordingNotifier2); + + CMenuOptionChooser* oj3 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_STOPPLAYBACK, &g_settings.recording_stopplayback, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, (g_settings.recording_type == RECORDING_SERVER || g_settings.recording_type == RECORDING_FILE)); + + CMenuOptionChooser* oj4 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_STOPSECTIONSD, &g_settings.recording_stopsectionsd, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, (g_settings.recording_type == RECORDING_SERVER || g_settings.recording_type == RECORDING_FILE)); + CMenuOptionChooser* oj4b = new CMenuOptionChooser(LOCALE_RECORDINGMENU_ZAP_ON_ANNOUNCE, &g_settings.recording_zap_on_announce, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + + CMenuOptionChooser* oj5 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_NO_SCART, &g_settings.recording_vcr_no_scart, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, (g_settings.recording_type == RECORDING_VCR)); + + CMenuOptionChooser* oj12 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_RECORD_IN_SPTS_MODE, &g_settings.recording_in_spts_mode, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT,(g_settings.recording_type == RECORDING_SERVER || g_settings.recording_type == RECORDING_FILE) ); +#endif + int pre,post; + g_Timerd->getRecordingSafety(pre,post); + sprintf(g_settings.record_safety_time_before, "%02d", pre/60); + sprintf(g_settings.record_safety_time_after, "%02d", post/60); + + CRecordingSafetyNotifier *RecordingSafetyNotifier = new CRecordingSafetyNotifier; + CStringInput * timerBefore = new CStringInput(LOCALE_TIMERSETTINGS_RECORD_SAFETY_TIME_BEFORE, g_settings.record_safety_time_before, 2, LOCALE_TIMERSETTINGS_RECORD_SAFETY_TIME_BEFORE_HINT_1, LOCALE_TIMERSETTINGS_RECORD_SAFETY_TIME_BEFORE_HINT_2,"0123456789 ", RecordingSafetyNotifier); + CMenuForwarder *fTimerBefore = new CMenuForwarder(LOCALE_TIMERSETTINGS_RECORD_SAFETY_TIME_BEFORE, true, g_settings.record_safety_time_before, timerBefore); + + CStringInput * timerAfter = new CStringInput(LOCALE_TIMERSETTINGS_RECORD_SAFETY_TIME_AFTER, g_settings.record_safety_time_after, 2, LOCALE_TIMERSETTINGS_RECORD_SAFETY_TIME_AFTER_HINT_1, LOCALE_TIMERSETTINGS_RECORD_SAFETY_TIME_AFTER_HINT_2,"0123456789 ", RecordingSafetyNotifier); + CMenuForwarder *fTimerAfter = new CMenuForwarder(LOCALE_TIMERSETTINGS_RECORD_SAFETY_TIME_AFTER, true, g_settings.record_safety_time_after, timerAfter); + + // default recording audio pids + //CMenuWidget * apidMenu = new CMenuWidget(LOCALE_RECORDINGMENU_APIDS, "audio.raw"); + //CMenuForwarder* fApidMenu = new CMenuForwarder(LOCALE_RECORDINGMENU_APIDS ,true, NULL, apidMenu); + g_settings.recording_audio_pids_std = ( g_settings.recording_audio_pids_default & TIMERD_APIDS_STD ) ? 1 : 0 ; + g_settings.recording_audio_pids_alt = ( g_settings.recording_audio_pids_default & TIMERD_APIDS_ALT ) ? 1 : 0 ; + g_settings.recording_audio_pids_ac3 = ( g_settings.recording_audio_pids_default & TIMERD_APIDS_AC3 ) ? 1 : 0 ; + + CRecAPIDSettingsNotifier * an = new CRecAPIDSettingsNotifier; + CMenuOptionChooser* aoj1 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_APIDS_STD, &g_settings.recording_audio_pids_std, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true, an); + CMenuOptionChooser* aoj2 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_APIDS_ALT, &g_settings.recording_audio_pids_alt, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true, an); + CMenuOptionChooser* aoj3 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_APIDS_AC3, &g_settings.recording_audio_pids_ac3, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true, an); +#if 0 + apidRecordingSettings->addItem(GenericMenuSeparator); + apidRecordingSettings->addItem(GenericMenuBack); + apidRecordingSettings->addItem(GenericMenuSeparatorLine); + apidRecordingSettings->addItem(aoj1); + apidRecordingSettings->addItem(aoj2); + apidRecordingSettings->addItem(aoj3); +#endif + CMenuForwarder* fRecDir = new CMenuForwarder(LOCALE_RECORDINGMENU_DEFDIR, true, g_settings.network_nfs_recordingdir, this, "recordingdir"); + CMenuForwarder* fTsDir = new CMenuForwarder(LOCALE_RECORDINGMENU_TSDIR, true, g_settings.timeshiftdir, this, "timeshiftdir"); + CMenuOptionChooser* zapAnnounce = new CMenuOptionChooser(LOCALE_RECORDINGMENU_ZAP_ON_ANNOUNCE, &g_settings.recording_zap_on_announce, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + + recordingSettings.addItem(GenericMenuSeparator); + recordingSettings.addItem(GenericMenuBack); + recordingSettings.addItem(new CMenuForwarder(LOCALE_RECORDINGMENU_SETUPNOW, true, NULL, this, "recording", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + recordingSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_TIMERSETTINGS_SEPARATOR)); + recordingSettings.addItem(fTimerBefore); + recordingSettings.addItem(fTimerAfter); + recordingSettings.addItem(zapAnnounce); + recordingSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_RECORDINGMENU_APIDS)); + recordingSettings.addItem(aoj1); + recordingSettings.addItem(aoj2); + recordingSettings.addItem(aoj3); + recordingSettings.addItem(GenericMenuSeparatorLine); + recordingSettings.addItem(fRecDir); + recordingSettings.addItem(fTsDir); + recordingSettings.addItem(new CMenuOptionNumberChooser(LOCALE_EXTRA_RECORD_TIME, &g_settings.record_hours, true, 1, 24, NULL) ); + if(1) { //has_hdd) { + recordingSettings.addItem(new CMenuOptionChooser(LOCALE_EXTRA_TIMESHIFT_PAUSE, &g_settings.timeshift_pause, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + recordingSettings.addItem(new CMenuOptionNumberChooser(LOCALE_EXTRA_AUTO_TIMESHIFT, &g_settings.auto_timeshift, true, 0, 300, NULL)); + recordingSettings.addItem(new CMenuOptionChooser(LOCALE_EXTRA_AUTO_DELETE, &g_settings.auto_delete, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + recordingSettings.addItem(new CMenuOptionChooser(LOCALE_EXTRA_TEMP_TIMESHIFT, &g_settings.temp_timeshift, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + } +#if 0 + // for direct recording + CMenuWidget *directRecordingSettings = new CMenuWidget(LOCALE_RECORDINGMENU_FILESETTINGS, NEUTRINO_ICON_RECORDING); + + CMenuForwarder* mf7 = new CMenuForwarder(LOCALE_RECORDINGMENU_FILESETTINGS,(g_settings.recording_type == RECORDING_FILE),NULL,directRecordingSettings, NULL, CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN); + + + CStringInput * recordingSettings_splitsize = new CStringInput(LOCALE_RECORDINGMENU_SPLITSIZE, g_settings.recording_splitsize, 6, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2, "0123456789 "); + CMenuForwarder* mf9 = new CMenuForwarder(LOCALE_RECORDINGMENU_SPLITSIZE, true, g_settings.recording_splitsize,recordingSettings_splitsize); + + CMenuOptionChooser* oj6 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_USE_O_SYNC, &g_settings.recording_use_o_sync, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + + CMenuOptionChooser* oj7 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_USE_FDATASYNC, &g_settings.recording_use_fdatasync, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + + CMenuOptionChooser* oj8 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_STREAM_VTXT_PID, &g_settings.recording_stream_vtxt_pid, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + CMenuOptionChooser* oj9 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_STREAM_PMT_PID, &g_settings.recording_stream_pmt_pid, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + + CStringInput * recordingSettings_ringbuffers = new CStringInput(LOCALE_RECORDINGMENU_RINGBUFFERS, g_settings.recording_ringbuffers, 2, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2, "0123456789 "); + CMenuForwarder* mf10 = new CMenuForwarder(LOCALE_RECORDINGMENU_RINGBUFFERS, true, g_settings.recording_ringbuffers,recordingSettings_ringbuffers); + //CMenuOptionChooser* oj10 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_CHOOSE_DIRECT_REC_DIR, &g_settings.recording_choose_direct_rec_dir, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + CMenuOptionChooser* oj10 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_CHOOSE_DIRECT_REC_DIR, &g_settings.recording_choose_direct_rec_dir, CHOOSE_DIRECT_REC_DIR, CHOOSE_DIRECT_REC_DIR_COUNT, true); + + CMenuOptionChooser* oj11 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_EPG_FOR_FILENAME, &g_settings.recording_epg_for_filename, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + CMenuOptionChooser* oj13 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_SAVE_IN_CHANNELDIR, &g_settings.recording_save_in_channeldir, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true); + + CRecordingNotifier *RecordingNotifier = new CRecordingNotifier(mf1,mf2,oj2,mf3,oj3,oj4,oj5,mf7,oj12); + + CMenuOptionChooser* oj1 = new CMenuOptionChooser(LOCALE_RECORDINGMENU_RECORDING_TYPE, &g_settings.recording_type, RECORDINGMENU_RECORDING_TYPE_OPTIONS, RECORDINGMENU_RECORDING_TYPE_OPTION_COUNT, true, RecordingNotifier); + + recordingSettings.addItem(GenericMenuSeparator); + recordingSettings.addItem(GenericMenuBack); + //recordingSettings.addItem(new CMenuForwarder(LOCALE_SETTINGS_HELP, true, NULL, this, "help_recording", CRCInput::RC_help, NEUTRINO_ICON_BUTTON_HELP_SMALL)); + recordingSettings.addItem(new CMenuForwarder(LOCALE_RECORDINGMENU_SETUPNOW, true, NULL, this, "recording", CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); + recordingSettings.addItem(GenericMenuSeparatorLine); + recordingSettings.addItem( oj1); + recordingSettings.addItem(GenericMenuSeparatorLine); + recordingSettings.addItem( mf1); + recordingSettings.addItem( mf2); + recordingSettings.addItem( oj2); + recordingSettings.addItem( mf3); + recordingSettings.addItem( oj3); + recordingSettings.addItem( oj4); + recordingSettings.addItem(GenericMenuSeparatorLine); + recordingSettings.addItem( oj5); + recordingSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_TIMERSETTINGS_SEPARATOR)); + recordingSettings.addItem( mf5); + recordingSettings.addItem( mf6); + recordingSettings.addItem( oj4b); + recordingSettings.addItem(new CMenuOptionNumberChooser(LOCALE_EXTRA_RECORD_TIME, &g_settings.record_hours, true, 1, 24) ); + recordingSettings.addItem(GenericMenuSeparatorLine); +#if 0 + recordingSettings.addItem(oj12); +#endif + recordingSettings.addItem( mf13); + recordingSettings.addItem( mf7); + + directRecordingSettings->addItem(GenericMenuSeparator); + directRecordingSettings->addItem(GenericMenuBack); + directRecordingSettings->addItem(GenericMenuSeparatorLine); + directRecordingSettings->addItem(mf8); + directRecordingSettings->addItem(mf9); + directRecordingSettings->addItem(mf10); + directRecordingSettings->addItem(oj6); + directRecordingSettings->addItem(oj7); + directRecordingSettings->addItem(oj8); + directRecordingSettings->addItem(oj9); + directRecordingSettings->addItem(oj10); + directRecordingSettings->addItem(oj11); + directRecordingSettings->addItem(oj13); + recordingstatus = 0; + if(has_hdd) { + directRecordingSettings->addItem(new CMenuOptionChooser(LOCALE_EXTRA_TIMESHIFT_PAUSE, &g_settings.timeshift_pause, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + directRecordingSettings->addItem(new CMenuOptionNumberChooser(LOCALE_EXTRA_AUTO_TIMESHIFT, &g_settings.auto_timeshift, true, 0, 300)); + directRecordingSettings->addItem(new CMenuOptionChooser(LOCALE_EXTRA_AUTO_DELETE, &g_settings.auto_delete, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + directRecordingSettings->addItem(new CMenuOptionChooser(LOCALE_EXTRA_TEMP_TIMESHIFT, &g_settings.temp_timeshift, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + } +#endif +} + +#define STREAMINGMENU_STREAMING_TRANSCODE_VIDEO_CODEC_OPTION_COUNT 2 +const CMenuOptionChooser::keyval STREAMINGMENU_STREAMING_TRANSCODE_VIDEO_CODEC_OPTIONS[STREAMINGMENU_STREAMING_TRANSCODE_VIDEO_CODEC_OPTION_COUNT] = +{ + { 0, LOCALE_STREAMINGMENU_MPEG1 }, + { 1, LOCALE_STREAMINGMENU_MPEG2 } +}; + +#define STREAMINGMENU_STREAMING_RESOLUTION_OPTION_COUNT 4 +const CMenuOptionChooser::keyval STREAMINGMENU_STREAMING_RESOLUTION_OPTIONS[STREAMINGMENU_STREAMING_RESOLUTION_OPTION_COUNT] = +{ + { 0, LOCALE_STREAMINGMENU_352X288 }, + { 1, LOCALE_STREAMINGMENU_352X576 }, + { 2, LOCALE_STREAMINGMENU_480X576 }, + { 3, LOCALE_STREAMINGMENU_704X576 } +}; + +#define STREAMINGMENU_STREAMING_TYPE_OPTION_COUNT 2 +const CMenuOptionChooser::keyval STREAMINGMENU_STREAMING_TYPE_OPTIONS[STREAMINGMENU_STREAMING_TYPE_OPTION_COUNT] = +{ + { 0, LOCALE_STREAMINGMENU_OFF }, + { 1, LOCALE_STREAMINGMENU_ON } +}; + +void CNeutrinoApp::InitStreamingSettings(CMenuWidget &streamingSettings) +{ + streamingSettings.addItem(GenericMenuSeparator); + streamingSettings.addItem(GenericMenuBack); + streamingSettings.addItem(GenericMenuSeparatorLine); + + CIPInput * streamingSettings_server_ip = new CIPInput(LOCALE_STREAMINGMENU_SERVER_IP, g_settings.streaming_server_ip, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2); + CStringInput * streamingSettings_server_port = new CStringInput(LOCALE_STREAMINGMENU_SERVER_PORT, g_settings.streaming_server_port, 6, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2,"0123456789 "); + CStringInputSMS * cddriveInput = new CStringInputSMS(LOCALE_STREAMINGMENU_STREAMING_SERVER_CDDRIVE, g_settings.streaming_server_cddrive, 20, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE, "abcdefghijklmnopqrstuvwxyz0123456789!""§$%&/()=?-:\\ "); + CStringInput * streamingSettings_videorate = new CStringInput(LOCALE_STREAMINGMENU_STREAMING_VIDEORATE, g_settings.streaming_videorate, 5, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2,"0123456789 "); + CStringInput * streamingSettings_audiorate = new CStringInput(LOCALE_STREAMINGMENU_STREAMING_AUDIORATE, g_settings.streaming_audiorate, 5, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2,"0123456789 "); + CStringInputSMS * startdirInput = new CStringInputSMS(LOCALE_STREAMINGMENU_STREAMING_SERVER_STARTDIR, g_settings.streaming_server_startdir, 30, NONEXISTANT_LOCALE, NONEXISTANT_LOCALE,"abcdefghijklmnopqrstuvwxyz0123456789!""§$%&/()=?-:\\ "); + + CMenuForwarder* mf1 = new CMenuForwarder(LOCALE_STREAMINGMENU_SERVER_IP , (g_settings.streaming_type==1), g_settings.streaming_server_ip , streamingSettings_server_ip); + CMenuForwarder* mf2 = new CMenuForwarder(LOCALE_STREAMINGMENU_SERVER_PORT , (g_settings.streaming_type==1), g_settings.streaming_server_port , streamingSettings_server_port); + CMenuForwarder* mf3 = new CMenuForwarder(LOCALE_STREAMINGMENU_STREAMING_SERVER_CDDRIVE , (g_settings.streaming_type==1), g_settings.streaming_server_cddrive , cddriveInput); + CMenuForwarder* mf4 = new CMenuForwarder(LOCALE_STREAMINGMENU_STREAMING_VIDEORATE , (g_settings.streaming_type==1), g_settings.streaming_videorate , streamingSettings_videorate); + CMenuForwarder* mf5 = new CMenuForwarder(LOCALE_STREAMINGMENU_STREAMING_AUDIORATE , (g_settings.streaming_type==1), g_settings.streaming_audiorate , streamingSettings_audiorate); + CMenuForwarder* mf6 = new CMenuForwarder(LOCALE_STREAMINGMENU_STREAMING_SERVER_STARTDIR, (g_settings.streaming_type==1), g_settings.streaming_server_startdir, startdirInput); + CMenuForwarder* mf7 = new CMenuForwarder(LOCALE_MOVIEPLAYER_DEFDIR, true, g_settings.network_nfs_moviedir,this,"moviedir"); + CMenuForwarder* mf8 = new CMenuForwarder(LOCALE_MOVIEPLAYER_DEFPLUGIN, true, g_settings.movieplayer_plugin,this,"movieplugin"); + CMenuOptionChooser* oj1 = new CMenuOptionChooser(LOCALE_STREAMINGMENU_STREAMING_TRANSCODE_AUDIO , &g_settings.streaming_transcode_audio , MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); + + CMenuOptionChooser* oj2 = new CMenuOptionChooser(LOCALE_STREAMINGMENU_STREAMING_FORCE_AVI_RAWAUDIO , &g_settings.streaming_force_avi_rawaudio , MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); + + CMenuOptionChooser* oj3 = new CMenuOptionChooser(LOCALE_STREAMINGMENU_STREAMING_FORCE_TRANSCODE_VIDEO, &g_settings.streaming_force_transcode_video, MESSAGEBOX_NO_YES_OPTIONS, MESSAGEBOX_NO_YES_OPTION_COUNT, true); + +// not yet supported by VLC + CMenuOptionChooser* oj4 = new CMenuOptionChooser(LOCALE_STREAMINGMENU_STREAMING_TRANSCODE_VIDEO_CODEC, &g_settings.streaming_transcode_video_codec, STREAMINGMENU_STREAMING_TRANSCODE_VIDEO_CODEC_OPTIONS, STREAMINGMENU_STREAMING_TRANSCODE_VIDEO_CODEC_OPTION_COUNT, true); + + CMenuOptionChooser* oj5 = new CMenuOptionChooser(LOCALE_STREAMINGMENU_STREAMING_RESOLUTION , &g_settings.streaming_resolution , STREAMINGMENU_STREAMING_RESOLUTION_OPTIONS, STREAMINGMENU_STREAMING_RESOLUTION_OPTION_COUNT, true); + + CStreamingNotifier *StreamingNotifier = new CStreamingNotifier(mf1,mf2,mf3,mf4,mf5,mf6,oj1,oj2,oj3,oj4,oj5); + + streamingSettings.addItem(new CMenuOptionChooser(LOCALE_STREAMINGMENU_STREAMING_TYPE , &g_settings.streaming_type , STREAMINGMENU_STREAMING_TYPE_OPTIONS, STREAMINGMENU_STREAMING_TYPE_OPTION_COUNT, true, StreamingNotifier)); + streamingSettings.addItem(GenericMenuSeparatorLine); + streamingSettings.addItem( mf1); //Server IP + streamingSettings.addItem( mf2); //Server Port + streamingSettings.addItem( mf3); //CD-Drive + streamingSettings.addItem( mf6); //Startdir + streamingSettings.addItem(GenericMenuSeparatorLine); + streamingSettings.addItem( mf4); //Video-Rate + streamingSettings.addItem( oj3); + streamingSettings.addItem( oj4); + streamingSettings.addItem( oj5); + streamingSettings.addItem(GenericMenuSeparatorLine); + streamingSettings.addItem( mf5); //Audiorate + streamingSettings.addItem( oj1); + streamingSettings.addItem( oj2); + streamingSettings.addItem(GenericMenuSeparatorLine); + streamingSettings.addItem( mf7); //default dir + streamingSettings.addItem( mf8); //default movieplugin +} + + +class CMenuNumberInput : public CMenuForwarder, CMenuTarget, CChangeObserver +{ +private: + CChangeObserver * observer; + CConfigFile * configfile; + int32_t defaultvalue; + char value[11]; + +protected: + + virtual const char * getOption(void) + { + sprintf(value, "%u", configfile->getInt32(locale_real_names[text], defaultvalue)); + return value; + } + + virtual bool changeNotify(const neutrino_locale_t OptionName, void * Data) + { + configfile->setInt32(locale_real_names[text], atoi(value)); + return observer->changeNotify(OptionName, Data); + } + + +public: + CMenuNumberInput(const neutrino_locale_t Text, const int32_t DefaultValue, CChangeObserver * const _observer, CConfigFile * const _configfile) : CMenuForwarder(Text, true, NULL, this) + { + observer = _observer; + configfile = _configfile; + defaultvalue = DefaultValue; + } + + int exec(CMenuTarget * parent, const std::string & actionKey) + { + CStringInput input(text, (char *)getOption(), 3, LOCALE_IPSETUP_HINT_1, LOCALE_IPSETUP_HINT_2, "0123456789 ", this); + return input.exec(parent, actionKey); + } +}; + +const SNeutrinoSettings::FONT_TYPES channellist_font_sizes[4] = +{ + SNeutrinoSettings::FONT_TYPE_CHANNELLIST, + SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR, + SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER, + SNeutrinoSettings::FONT_TYPE_CHANNEL_NUM_ZAP +}; + +const SNeutrinoSettings::FONT_TYPES eventlist_font_sizes[4] = +{ + SNeutrinoSettings::FONT_TYPE_EVENTLIST_TITLE, + SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMLARGE, + SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMSMALL, + SNeutrinoSettings::FONT_TYPE_EVENTLIST_DATETIME, +}; + +const SNeutrinoSettings::FONT_TYPES infobar_font_sizes[4] = +{ + SNeutrinoSettings::FONT_TYPE_INFOBAR_NUMBER, + SNeutrinoSettings::FONT_TYPE_INFOBAR_CHANNAME, + SNeutrinoSettings::FONT_TYPE_INFOBAR_INFO, + SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL +}; + +const SNeutrinoSettings::FONT_TYPES epg_font_sizes[4] = +{ + SNeutrinoSettings::FONT_TYPE_EPG_TITLE, + SNeutrinoSettings::FONT_TYPE_EPG_INFO1, + SNeutrinoSettings::FONT_TYPE_EPG_INFO2, + SNeutrinoSettings::FONT_TYPE_EPG_DATE +}; + +const SNeutrinoSettings::FONT_TYPES gamelist_font_sizes[2] = +{ + SNeutrinoSettings::FONT_TYPE_GAMELIST_ITEMLARGE, + SNeutrinoSettings::FONT_TYPE_GAMELIST_ITEMSMALL +}; + +const SNeutrinoSettings::FONT_TYPES other_font_sizes[4] = +{ + SNeutrinoSettings::FONT_TYPE_MENU, + SNeutrinoSettings::FONT_TYPE_MENU_TITLE, + SNeutrinoSettings::FONT_TYPE_MENU_INFO, + SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM +}; + +font_sizes_groups font_sizes_groups[6] = +{ + {LOCALE_FONTMENU_CHANNELLIST, 4, channellist_font_sizes, "fontsize.dcha"}, + {LOCALE_FONTMENU_EVENTLIST , 4, eventlist_font_sizes , "fontsize.deve"}, + {LOCALE_FONTMENU_EPG , 4, epg_font_sizes , "fontsize.depg"}, + {LOCALE_FONTMENU_INFOBAR , 4, infobar_font_sizes , "fontsize.dinf"}, + {LOCALE_FONTMENU_GAMELIST , 2, gamelist_font_sizes , "fontsize.dgam"}, + {NONEXISTANT_LOCALE , 4, other_font_sizes , "fontsize.doth"} +}; + +#define FONT_STYLE_REGULAR 0 +#define FONT_STYLE_BOLD 1 +#define FONT_STYLE_ITALIC 2 + +font_sizes_struct neutrino_font[FONT_TYPE_COUNT] = +{ + {LOCALE_FONTSIZE_MENU , 20, FONT_STYLE_BOLD , 0}, + {LOCALE_FONTSIZE_MENU_TITLE , 30, FONT_STYLE_BOLD , 0}, + {LOCALE_FONTSIZE_MENU_INFO , 16, FONT_STYLE_REGULAR, 0}, + {LOCALE_FONTSIZE_EPG_TITLE , 25, FONT_STYLE_REGULAR, 1}, + {LOCALE_FONTSIZE_EPG_INFO1 , 17, FONT_STYLE_ITALIC , 2}, + {LOCALE_FONTSIZE_EPG_INFO2 , 17, FONT_STYLE_REGULAR, 2}, + {LOCALE_FONTSIZE_EPG_DATE , 15, FONT_STYLE_REGULAR, 2}, + {LOCALE_FONTSIZE_EVENTLIST_TITLE , 30, FONT_STYLE_REGULAR, 0}, + {LOCALE_FONTSIZE_EVENTLIST_ITEMLARGE, 20, FONT_STYLE_BOLD , 1}, + {LOCALE_FONTSIZE_EVENTLIST_ITEMSMALL, 14, FONT_STYLE_REGULAR, 1}, + {LOCALE_FONTSIZE_EVENTLIST_DATETIME , 16, FONT_STYLE_REGULAR, 1}, + {LOCALE_FONTSIZE_GAMELIST_ITEMLARGE , 20, FONT_STYLE_BOLD , 1}, + {LOCALE_FONTSIZE_GAMELIST_ITEMSMALL , 16, FONT_STYLE_REGULAR, 1}, + {LOCALE_FONTSIZE_CHANNELLIST , 20, FONT_STYLE_BOLD , 1}, + {LOCALE_FONTSIZE_CHANNELLIST_DESCR , 20, FONT_STYLE_REGULAR, 1}, + {LOCALE_FONTSIZE_CHANNELLIST_NUMBER , 14, FONT_STYLE_BOLD , 2}, + {LOCALE_FONTSIZE_CHANNEL_NUM_ZAP , 40, FONT_STYLE_BOLD , 0}, + {LOCALE_FONTSIZE_INFOBAR_NUMBER , 30 /* orig 50*/, FONT_STYLE_BOLD , 0}, + {LOCALE_FONTSIZE_INFOBAR_CHANNAME , 30, FONT_STYLE_BOLD , 0}, + {LOCALE_FONTSIZE_INFOBAR_INFO , 20, FONT_STYLE_REGULAR, 1}, + {LOCALE_FONTSIZE_INFOBAR_SMALL , 14, FONT_STYLE_REGULAR, 1}, + {LOCALE_FONTSIZE_FILEBROWSER_ITEM , 16, FONT_STYLE_BOLD , 1} +}; + +void CNeutrinoApp::AddFontSettingItem(CMenuWidget &fontSettings, const SNeutrinoSettings::FONT_TYPES number_of_fontsize_entry) +{ + fontSettings.addItem(new CMenuNumberInput(neutrino_font[number_of_fontsize_entry].name, neutrino_font[number_of_fontsize_entry].defaultsize, &fontsizenotifier, &configfile)); +} + +void CNeutrinoApp::InitFontSettings(CMenuWidget &fontSettings) +{ + fontSettings.addItem(GenericMenuSeparator); + fontSettings.addItem(GenericMenuBack); + fontSettings.addItem(GenericMenuSeparatorLine); + //fontSettings.addItem( new CMenuForwarder(LOCALE_EPGPLUS_SELECT_FONT_NAME, true, NULL, this, "select_font")); + AddFontSettingItem(fontSettings, SNeutrinoSettings::FONT_TYPE_MENU); + AddFontSettingItem(fontSettings, SNeutrinoSettings::FONT_TYPE_MENU_TITLE); + AddFontSettingItem(fontSettings, SNeutrinoSettings::FONT_TYPE_MENU_INFO); + fontSettings.addItem(GenericMenuSeparatorLine); + + for (int i = 0; i < 5; i++) + { + CMenuWidget * fontSettingsSubMenu = new CMenuWidget(font_sizes_groups[i].groupname, "colors.raw"); + fontSettingsSubMenu->addItem(GenericMenuSeparator); + fontSettingsSubMenu->addItem(GenericMenuBack); + fontSettingsSubMenu->addItem(GenericMenuSeparatorLine); + for (unsigned int j = 0; j < font_sizes_groups[i].count; j++) + { + AddFontSettingItem(*fontSettingsSubMenu, font_sizes_groups[i].content[j]); + } + fontSettingsSubMenu->addItem(GenericMenuSeparatorLine); + fontSettingsSubMenu->addItem(new CMenuForwarder(LOCALE_OPTIONS_DEFAULT, true, NULL, this, font_sizes_groups[i].actionkey)); + + fontSettings.addItem(new CMenuForwarder(font_sizes_groups[i].groupname, true, NULL, fontSettingsSubMenu)); + } + + AddFontSettingItem(fontSettings, SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM); + fontSettings.addItem(GenericMenuSeparatorLine); + fontSettings.addItem(new CMenuForwarder(LOCALE_OPTIONS_DEFAULT, true, NULL, this, font_sizes_groups[5].actionkey)); +} + +void CNeutrinoApp::InitColorSettings(CMenuWidget &colorSettings, CMenuWidget &fontSettings ) +{ + CScreenSetup * ScreenSetup = new CScreenSetup(); + colorSettings.addItem(GenericMenuSeparator); + colorSettings.addItem(GenericMenuBack); + colorSettings.addItem(GenericMenuSeparatorLine); + + CMenuWidget *colorSettings_Themes = new CMenuWidget(LOCALE_COLORTHEMEMENU_HEAD, NEUTRINO_ICON_SETTINGS); + InitColorThemesSettings(*colorSettings_Themes); + + colorSettings.addItem( new CMenuForwarder(LOCALE_COLORMENU_THEMESELECT, true, NULL, colorSettings_Themes, NULL, CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED) ); + CMenuWidget *colorSettings_menuColors = new CMenuWidget(LOCALE_COLORMENUSETUP_HEAD, NEUTRINO_ICON_SETTINGS, 400, 400); + InitColorSettingsMenuColors(*colorSettings_menuColors); + colorSettings.addItem( new CMenuForwarder(LOCALE_COLORMENU_MENUCOLORS, true, NULL, colorSettings_menuColors, NULL, CRCInput::RC_green, NEUTRINO_ICON_BUTTON_GREEN) ); + + CMenuWidget *colorSettings_statusbarColors = new CMenuWidget(LOCALE_COLORMENU_STATUSBAR, NEUTRINO_ICON_SETTINGS); + InitColorSettingsStatusBarColors(*colorSettings_statusbarColors); + colorSettings.addItem( new CMenuForwarder(LOCALE_COLORSTATUSBAR_HEAD, true, NULL, colorSettings_statusbarColors, NULL, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW) ); + + colorSettings.addItem(GenericMenuSeparatorLine); + colorSettings.addItem( new CMenuForwarder(LOCALE_COLORMENU_FONT, true, NULL, &fontSettings, NULL, CRCInput::RC_blue, NEUTRINO_ICON_BUTTON_BLUE) ); + colorSettings.addItem( new CMenuForwarder(LOCALE_EPGPLUS_SELECT_FONT_NAME, true, NULL, this, "select_font")); + + CMenuWidget *colorSettings_timing = new CMenuWidget(LOCALE_COLORMENU_TIMING, NEUTRINO_ICON_SETTINGS); + InitColorSettingsTiming(*colorSettings_timing); + + colorSettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_VIDEOMENU_OSD)); + colorSettings.addItem(new CMenuForwarder(LOCALE_TIMING_HEAD, true, NULL, colorSettings_timing)); + colorSettings.addItem(new CMenuForwarder(LOCALE_VIDEOMENU_SCREENSETUP, true, NULL, ScreenSetup));//, NULL, CRCInput::RC_red, NEUTRINO_ICON_BUTTON_RED)); +#if 0 + colorSettings.addItem(GenericMenuSeparatorLine); + //menuefaden nur bei enx-chips! + CMenuOptionChooser* oj = new CMenuOptionChooser(LOCALE_COLORMENU_FADE, &g_settings.widget_fade, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true ); + colorSettings.addItem( oj ); + + CAlphaSetup* chAlphaSetup = new CAlphaSetup(LOCALE_COLORMENU_GTX_ALPHA, &g_settings.gtx_alpha1, &g_settings.gtx_alpha2); + colorSettings.addItem( new CMenuForwarder(LOCALE_COLORMENU_GTX_ALPHA, true, NULL, chAlphaSetup)); +#endif +} + +void CNeutrinoApp::InitColorThemesSettings(CMenuWidget &colorSettings_Themes) +{ + colorSettings_Themes.addItem(GenericMenuSeparator); + colorSettings_Themes.addItem(GenericMenuBack); + colorSettings_Themes.addItem(GenericMenuSeparatorLine); + colorSettings_Themes.addItem(new CMenuForwarder(LOCALE_EXTRA_LOADCOLORS, true, NULL, this, "loadcolors")); + colorSettings_Themes.addItem(new CMenuForwarder(LOCALE_EXTRA_SAVECOLORS, true, NULL, this, "savecolors")); + colorSettings_Themes.addItem(GenericMenuSeparatorLine); + colorSettings_Themes.addItem(new CMenuForwarder(LOCALE_COLORTHEMEMENU_NEUTRINO_THEME, true, NULL, this, "theme_neutrino")); + colorSettings_Themes.addItem(new CMenuForwarder(LOCALE_COLORTHEMEMENU_CLASSIC_THEME, true, NULL, this, "theme_classic")); + colorSettings_Themes.addItem( new CMenuForwarder(LOCALE_COLORTHEMEMENU_GRAY, true, NULL, this, "theme_ru") ); + colorSettings_Themes.addItem(new CMenuForwarder(LOCALE_COLORTHEMEMENU_DBLUE_THEME, true, NULL, this, "theme_dblue")); + colorSettings_Themes.addItem(new CMenuForwarder(LOCALE_COLORTHEMEMENU_DVB2K_THEME, true, NULL, this, "theme_dvb2k")); + colorSettings_Themes.addItem(new CMenuForwarder(LOCALE_COLORTHEMEMENU_RED_THEME, true, NULL, this, "theme_red")); +} + +void CNeutrinoApp::InitColorSettingsMenuColors(CMenuWidget &colorSettings_menuColors) +{ + colorSettings_menuColors.addItem(GenericMenuSeparator); + colorSettings_menuColors.addItem(GenericMenuBack); + + CColorChooser* chHeadcolor = new CColorChooser(LOCALE_COLORMENU_BACKGROUND, &g_settings.menu_Head_red, &g_settings.menu_Head_green, &g_settings.menu_Head_blue, + &g_settings.menu_Head_alpha, colorSetupNotifier); + CColorChooser* chHeadTextcolor = new CColorChooser(LOCALE_COLORMENU_TEXTCOLOR, &g_settings.menu_Head_Text_red, &g_settings.menu_Head_Text_green, &g_settings.menu_Head_Text_blue, + NULL, colorSetupNotifier); + CColorChooser* chContentcolor = new CColorChooser(LOCALE_COLORMENU_BACKGROUND, &g_settings.menu_Content_red, &g_settings.menu_Content_green, &g_settings.menu_Content_blue, + &g_settings.menu_Content_alpha, colorSetupNotifier); + CColorChooser* chContentTextcolor = new CColorChooser(LOCALE_COLORMENU_TEXTCOLOR, &g_settings.menu_Content_Text_red, &g_settings.menu_Content_Text_green, &g_settings.menu_Content_Text_blue, + NULL, colorSetupNotifier); + CColorChooser* chContentSelectedcolor = new CColorChooser(LOCALE_COLORMENU_BACKGROUND, &g_settings.menu_Content_Selected_red, &g_settings.menu_Content_Selected_green, &g_settings.menu_Content_Selected_blue, + &g_settings.menu_Content_Selected_alpha, colorSetupNotifier); + CColorChooser* chContentSelectedTextcolor = new CColorChooser(LOCALE_COLORMENU_TEXTCOLOR, &g_settings.menu_Content_Selected_Text_red, &g_settings.menu_Content_Selected_Text_green, &g_settings.menu_Content_Selected_Text_blue, + NULL, colorSetupNotifier); + CColorChooser* chContentInactivecolor = new CColorChooser(LOCALE_COLORMENU_BACKGROUND, &g_settings.menu_Content_inactive_red, &g_settings.menu_Content_inactive_green, &g_settings.menu_Content_inactive_blue, + &g_settings.menu_Content_inactive_alpha, colorSetupNotifier); + CColorChooser* chContentInactiveTextcolor = new CColorChooser(LOCALE_COLORMENU_TEXTCOLOR, &g_settings.menu_Content_inactive_Text_red, &g_settings.menu_Content_inactive_Text_green, &g_settings.menu_Content_inactive_Text_blue, + NULL, colorSetupNotifier); + colorSettings_menuColors.addItem( new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_COLORMENUSETUP_MENUHEAD)); + colorSettings_menuColors.addItem( new CMenuForwarder(LOCALE_COLORMENU_BACKGROUND, true, NULL, chHeadcolor )); + colorSettings_menuColors.addItem( new CMenuForwarder(LOCALE_COLORMENU_TEXTCOLOR, true, NULL, chHeadTextcolor )); + colorSettings_menuColors.addItem( new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_COLORMENUSETUP_MENUCONTENT)); + colorSettings_menuColors.addItem( new CMenuForwarder(LOCALE_COLORMENU_BACKGROUND, true, NULL, chContentcolor )); + colorSettings_menuColors.addItem( new CMenuForwarder(LOCALE_COLORMENU_TEXTCOLOR, true, NULL, chContentTextcolor )); + colorSettings_menuColors.addItem( new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_COLORMENUSETUP_MENUCONTENT_INACTIVE)); + colorSettings_menuColors.addItem( new CMenuForwarder(LOCALE_COLORMENU_BACKGROUND, true, NULL, chContentInactivecolor )); + colorSettings_menuColors.addItem( new CMenuForwarder(LOCALE_COLORMENU_TEXTCOLOR, true, NULL, chContentInactiveTextcolor)); + colorSettings_menuColors.addItem( new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_COLORMENUSETUP_MENUCONTENT_SELECTED)); + colorSettings_menuColors.addItem( new CMenuForwarder(LOCALE_COLORMENU_BACKGROUND, true, NULL, chContentSelectedcolor )); + colorSettings_menuColors.addItem( new CMenuForwarder(LOCALE_COLORMENU_TEXTCOLOR, true, NULL, chContentSelectedTextcolor )); +} + +void CNeutrinoApp::InitColorSettingsStatusBarColors(CMenuWidget &colorSettings_statusbarColors) +{ + colorSettings_statusbarColors.addItem(GenericMenuSeparator); + + colorSettings_statusbarColors.addItem(GenericMenuBack); + + CColorChooser* chInfobarcolor = new CColorChooser(LOCALE_COLORMENU_BACKGROUND, &g_settings.infobar_red, &g_settings.infobar_green, &g_settings.infobar_blue, + &g_settings.infobar_alpha, colorSetupNotifier); + CColorChooser* chInfobarTextcolor = new CColorChooser(LOCALE_COLORMENU_TEXTCOLOR, &g_settings.infobar_Text_red, &g_settings.infobar_Text_green, &g_settings.infobar_Text_blue, + NULL, colorSetupNotifier); + + colorSettings_statusbarColors.addItem( new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_COLORSTATUSBAR_TEXT)); + colorSettings_statusbarColors.addItem( new CMenuForwarder(LOCALE_COLORMENU_BACKGROUND, true, NULL, chInfobarcolor )); + colorSettings_statusbarColors.addItem( new CMenuForwarder(LOCALE_COLORMENU_TEXTCOLOR, true, NULL, chInfobarTextcolor )); +} + +void CNeutrinoApp::InitColorSettingsTiming(CMenuWidget &colorSettings_timing) +{ + colorSettings_timing.addItem(GenericMenuSeparator); + colorSettings_timing.addItem(GenericMenuBack); + colorSettings_timing.addItem(GenericMenuSeparatorLine); + + for (int i = 0; i < TIMING_SETTING_COUNT; i++) + { + CStringInput * colorSettings_timing_item = new CStringInput(timing_setting_name[i], g_settings.timing_string[i], 3, LOCALE_TIMING_HINT_1, LOCALE_TIMING_HINT_2, "0123456789 ", &timingsettingsnotifier); + colorSettings_timing.addItem(new CMenuForwarder(timing_setting_name[i], true, g_settings.timing_string[i], colorSettings_timing_item)); + } + + colorSettings_timing.addItem(GenericMenuSeparatorLine); + colorSettings_timing.addItem(new CMenuForwarder(LOCALE_OPTIONS_DEFAULT, true, NULL, this, "osd.def")); +} + +#define LCDMENU_STATUSLINE_OPTION_COUNT 2 +const CMenuOptionChooser::keyval LCDMENU_STATUSLINE_OPTIONS[LCDMENU_STATUSLINE_OPTION_COUNT] = +{ + { 0, LOCALE_LCDMENU_STATUSLINE_PLAYTIME }, + { 1, LOCALE_LCDMENU_STATUSLINE_VOLUME } + //,{ 2, LOCALE_LCDMENU_STATUSLINE_BOTH } +}; + +void CNeutrinoApp::InitLcdSettings(CMenuWidget &lcdSettings) +{ + lcdSettings.addItem(GenericMenuSeparator); + + lcdSettings.addItem(GenericMenuBack); + lcdSettings.addItem(GenericMenuSeparatorLine); + + CVfdControler* lcdsliders = new CVfdControler(LOCALE_LCDMENU_HEAD, NULL); + +#if 0 + CLcdNotifier* lcdnotifier = new CLcdNotifier(); + + CMenuOptionChooser* oj = new CMenuOptionChooser(LOCALE_LCDMENU_INVERSE, &g_settings.lcd_setting[SNeutrinoSettings::LCD_INVERSE], OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, lcdnotifier); + lcdSettings.addItem(oj); + + oj = new CMenuOptionChooser(LOCALE_LCDMENU_POWER, &g_settings.lcd_setting[SNeutrinoSettings::LCD_POWER], OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, lcdnotifier); + lcdSettings.addItem(oj); +#endif + CStringInput * dim_time = new CStringInput(LOCALE_LCDMENU_DIM_TIME, g_settings.lcd_setting_dim_time, 3, + NONEXISTANT_LOCALE, NONEXISTANT_LOCALE,"0123456789 "); + lcdSettings.addItem(new CMenuForwarder(LOCALE_LCDMENU_DIM_TIME,true, g_settings.lcd_setting_dim_time,dim_time)); + + CStringInput * dim_brightness = new CStringInput(LOCALE_LCDMENU_DIM_BRIGHTNESS, g_settings.lcd_setting_dim_brightness, 3, + NONEXISTANT_LOCALE, NONEXISTANT_LOCALE,"0123456789 "); + lcdSettings.addItem(new CMenuForwarder(LOCALE_LCDMENU_DIM_BRIGHTNESS,true, g_settings.lcd_setting_dim_brightness,dim_brightness)); + + lcdSettings.addItem(GenericMenuSeparatorLine); + lcdSettings.addItem(new CMenuForwarder(LOCALE_LCDMENU_LCDCONTROLER, true, NULL, lcdsliders)); + + lcdSettings.addItem(GenericMenuSeparatorLine); + CMenuOptionChooser* oj = new CMenuOptionChooser(LOCALE_LCDMENU_STATUSLINE, &g_settings.lcd_setting[SNeutrinoSettings::LCD_SHOW_VOLUME], LCDMENU_STATUSLINE_OPTIONS, LCDMENU_STATUSLINE_OPTION_COUNT, true); + lcdSettings.addItem(oj); +} + +#define KEYBINDINGMENU_BOUQUETHANDLING_OPTION_COUNT 3 +const CMenuOptionChooser::keyval KEYBINDINGMENU_BOUQUETHANDLING_OPTIONS[KEYBINDINGMENU_BOUQUETHANDLING_OPTION_COUNT] = +{ + { 0, LOCALE_KEYBINDINGMENU_BOUQUETCHANNELS_ON_OK }, + { 1, LOCALE_KEYBINDINGMENU_BOUQUETLIST_ON_OK }, + { 2, LOCALE_KEYBINDINGMENU_ALLCHANNELS_ON_OK } +}; + +enum keynames { + KEY_TV_RADIO_MODE, + KEY_PAGE_UP, + KEY_PAGE_DOWN, + KEY_LIST_START, + KEY_LIST_END, + KEY_CANCEL_ACTION, + KEY_SORT, + KEY_ADD_RECORD, + KEY_ADD_REMIND, + KEY_BOUQUET_UP, + KEY_BOUQUET_DOWN, + KEY_CHANNEL_UP, + KEY_CHANNEL_DOWN, + KEY_SUBCHANNEL_UP, + KEY_SUBCHANNEL_DOWN, + KEY_ZAP_HISTORY, + KEY_LASTCHANNEL, + MPKEY_REWIND, + MPKEY_FORWARD, + MPKEY_PAUSE, + MPKEY_STOP, + MPKEY_PLAY, + MPKEY_AUDIO, + MPKEY_TIME, + MPKEY_BOOKMARK, + KEY_TIMESHIFT, + MPKEY_PLUGIN, + KEY_PLUGIN, + KEY_UNLOCK +}; + +#define KEYBINDS_COUNT 29 +const neutrino_locale_t keydescription_head[KEYBINDS_COUNT] = +{ + LOCALE_KEYBINDINGMENU_TVRADIOMODE, + LOCALE_KEYBINDINGMENU_PAGEUP, + LOCALE_KEYBINDINGMENU_PAGEDOWN, + LOCALE_EXTRA_KEY_LIST_START, + LOCALE_EXTRA_KEY_LIST_END, + LOCALE_KEYBINDINGMENU_CANCEL, + LOCALE_KEYBINDINGMENU_SORT, + LOCALE_KEYBINDINGMENU_ADDRECORD, + LOCALE_KEYBINDINGMENU_ADDREMIND, + LOCALE_KEYBINDINGMENU_BOUQUETUP, + LOCALE_KEYBINDINGMENU_BOUQUETDOWN, + LOCALE_KEYBINDINGMENU_CHANNELUP, + LOCALE_KEYBINDINGMENU_CHANNELDOWN, + LOCALE_KEYBINDINGMENU_SUBCHANNELUP, + LOCALE_KEYBINDINGMENU_SUBCHANNELDOWN, + LOCALE_KEYBINDINGMENU_ZAPHISTORY, + LOCALE_KEYBINDINGMENU_LASTCHANNEL, + LOCALE_MPKEY_REWIND, + LOCALE_MPKEY_FORWARD, + LOCALE_MPKEY_PAUSE, + LOCALE_MPKEY_STOP, + LOCALE_MPKEY_PLAY, + LOCALE_MPKEY_AUDIO, + LOCALE_MPKEY_TIME, + LOCALE_MPKEY_BOOKMARK, + LOCALE_EXTRA_KEY_TIMESHIFT, + LOCALE_MPKEY_PLUGIN, + LOCALE_EXTRA_KEY_PLUGIN, + LOCALE_EXTRA_KEY_UNLOCK +}; + +const neutrino_locale_t keydescription[KEYBINDS_COUNT] = +{ + LOCALE_KEYBINDINGMENU_TVRADIOMODE, + LOCALE_KEYBINDINGMENU_PAGEUP, + LOCALE_KEYBINDINGMENU_PAGEDOWN, + LOCALE_EXTRA_KEY_LIST_START, + LOCALE_EXTRA_KEY_LIST_END, + LOCALE_KEYBINDINGMENU_CANCEL, + LOCALE_KEYBINDINGMENU_SORT, + LOCALE_KEYBINDINGMENU_ADDRECORD, + LOCALE_KEYBINDINGMENU_ADDREMIND, + LOCALE_KEYBINDINGMENU_BOUQUETUP, + LOCALE_KEYBINDINGMENU_BOUQUETDOWN, + LOCALE_KEYBINDINGMENU_CHANNELUP, + LOCALE_KEYBINDINGMENU_CHANNELDOWN, + LOCALE_KEYBINDINGMENU_SUBCHANNELUP, + LOCALE_KEYBINDINGMENU_SUBCHANNELDOWN, + LOCALE_KEYBINDINGMENU_ZAPHISTORY, + LOCALE_KEYBINDINGMENU_LASTCHANNEL, + LOCALE_MPKEY_REWIND, + LOCALE_MPKEY_FORWARD, + LOCALE_MPKEY_PAUSE, + LOCALE_MPKEY_STOP, + LOCALE_MPKEY_PLAY, + LOCALE_MPKEY_AUDIO, + LOCALE_MPKEY_TIME, + LOCALE_MPKEY_BOOKMARK, + LOCALE_EXTRA_KEY_TIMESHIFT, + LOCALE_MPKEY_PLUGIN, + LOCALE_EXTRA_KEY_PLUGIN, + LOCALE_EXTRA_KEY_UNLOCK +}; + +void CNeutrinoApp::InitKeySettings(CMenuWidget &keySettings) +{ + CMenuWidget* bindSettings = new CMenuWidget(LOCALE_KEYBINDINGMENU_HEAD, "keybinding.raw", 400); + + keySettings.addItem(GenericMenuSeparator); + keySettings.addItem(GenericMenuBack); + keySettings.addItem(GenericMenuSeparatorLine); + + keySettings.addItem(new CMenuForwarder(LOCALE_EXTRA_LOADKEYS, true, NULL, this, "loadkeys")); + keySettings.addItem(new CMenuForwarder(LOCALE_EXTRA_SAVEKEYS, true, NULL, this, "savekeys")); + //keySettings.addItem(GenericMenuSeparatorLine); + + keySetupNotifier = new CKeySetupNotifier; + CStringInput * keySettings_repeat_genericblocker = new CStringInput(LOCALE_KEYBINDINGMENU_REPEATBLOCKGENERIC, g_settings.repeat_genericblocker, 3, LOCALE_REPEATBLOCKER_HINT_1, LOCALE_REPEATBLOCKER_HINT_2, "0123456789 ", keySetupNotifier); + CStringInput * keySettings_repeatBlocker = new CStringInput(LOCALE_KEYBINDINGMENU_REPEATBLOCK, g_settings.repeat_blocker, 3, LOCALE_REPEATBLOCKER_HINT_1, LOCALE_REPEATBLOCKER_HINT_2, "0123456789 ", keySetupNotifier); + keySetupNotifier->changeNotify(NONEXISTANT_LOCALE, NULL); + + keySettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_KEYBINDINGMENU_RC)); + keySettings.addItem(new CMenuForwarder(LOCALE_KEYBINDINGMENU_REPEATBLOCK, true, g_settings.repeat_blocker, keySettings_repeatBlocker)); + keySettings.addItem(new CMenuForwarder(LOCALE_KEYBINDINGMENU_REPEATBLOCKGENERIC, true, g_settings.repeat_genericblocker, keySettings_repeat_genericblocker)); + + keySettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_MAINMENU_SHUTDOWN)); + CMenuOptionChooser *m1 = new CMenuOptionChooser(LOCALE_MISCSETTINGS_SHUTDOWN_REAL_RCDELAY, &g_settings.shutdown_real_rcdelay, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, !g_settings.shutdown_real); + + CMiscNotifier* miscNotifier = new CMiscNotifier( m1 ); + + keySettings.addItem(new CMenuOptionChooser(LOCALE_MISCSETTINGS_SHUTDOWN_REAL, &g_settings.shutdown_real, OPTIONS_OFF1_ON0_OPTIONS, OPTIONS_OFF1_ON0_OPTION_COUNT, true, miscNotifier)); + keySettings.addItem(m1); + + int * keyvalue_p[KEYBINDS_COUNT] = + { + &g_settings.key_tvradio_mode, + &g_settings.key_channelList_pageup, + &g_settings.key_channelList_pagedown, + &g_settings.key_list_start, + &g_settings.key_list_end, + + &g_settings.key_channelList_cancel, + &g_settings.key_channelList_sort, + &g_settings.key_channelList_addrecord, + &g_settings.key_channelList_addremind, + &g_settings.key_bouquet_up, + + &g_settings.key_bouquet_down, + &g_settings.key_quickzap_up, + &g_settings.key_quickzap_down, + &g_settings.key_subchannel_up, + &g_settings.key_subchannel_down, + + &g_settings.key_zaphistory, + &g_settings.key_lastchannel, + + &g_settings.mpkey_rewind, + &g_settings.mpkey_forward, + &g_settings.mpkey_pause, + &g_settings.mpkey_stop, + &g_settings.mpkey_play, + &g_settings.mpkey_audio, + &g_settings.mpkey_time, + &g_settings.mpkey_bookmark, + + &g_settings.key_timeshift, + &g_settings.mpkey_plugin, + &g_settings.key_plugin, + &g_settings.key_unlock + }; + + CKeyChooser * keychooser[KEYBINDS_COUNT]; + + for (int i = 0; i < KEYBINDS_COUNT; i++) + keychooser[i] = new CKeyChooser(keyvalue_p[i], keydescription_head[i], NEUTRINO_ICON_SETTINGS); + + keySettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_KEYBINDINGMENU_HEAD)); + + bindSettings->addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_KEYBINDINGMENU_MODECHANGE)); + bindSettings->addItem(new CMenuForwarder(keydescription[KEY_TV_RADIO_MODE], true, NULL, keychooser[KEY_TV_RADIO_MODE])); + + bindSettings->addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_KEYBINDINGMENU_CHANNELLIST)); + + CMenuOptionChooser *oj = new CMenuOptionChooser(LOCALE_KEYBINDINGMENU_BOUQUETHANDLING, &g_settings.bouquetlist_mode, KEYBINDINGMENU_BOUQUETHANDLING_OPTIONS, KEYBINDINGMENU_BOUQUETHANDLING_OPTION_COUNT, true ); + bindSettings->addItem(oj); + + for (int i = KEY_PAGE_UP; i <= KEY_BOUQUET_DOWN; i++) + bindSettings->addItem(new CMenuForwarder(keydescription[i], true, NULL, keychooser[i])); + + bindSettings->addItem(new CMenuOptionChooser(LOCALE_EXTRA_SMS_CHANNEL, &g_settings.sms_channel, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); +// Zapping keys + bindSettings->addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_KEYBINDINGMENU_QUICKZAP)); + + for (int i = KEY_CHANNEL_UP; i <= KEY_LASTCHANNEL; i++) + bindSettings->addItem(new CMenuForwarder(keydescription[i], true, NULL, keychooser[i])); + + bindSettings->addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_MAINMENU_MOVIEPLAYER)); + for (int i = MPKEY_REWIND; i <= MPKEY_PLUGIN; i++) + bindSettings->addItem(new CMenuForwarder(keydescription[i], true, NULL, keychooser[i])); + + bindSettings->addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_MAINSETTINGS_MISC)); + //bindSettings->addItem(new CMenuForwarder(keydescription[KEY_PLUGIN], true, NULL, keychooser[KEY_PLUGIN])); + bindSettings->addItem(new CMenuForwarder(keydescription[KEY_UNLOCK], true, NULL, keychooser[KEY_UNLOCK])); + //bindSettings->addItem(new CMenuOptionChooser(LOCALE_EXTRA_ZAP_CYCLE, &g_settings.zap_cycle, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + bindSettings->addItem(new CMenuOptionChooser(LOCALE_EXTRA_MENU_LEFT_EXIT, &g_settings.menu_left_exit, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + + bindSettings->addItem(new CMenuOptionChooser(LOCALE_EXTRA_AUDIO_RUN_PLAYER, &g_settings.audio_run_player, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + //bindSettings->addItem(new CMenuOptionChooser(LOCALE_EXTRA_KEY_CLICK, &g_settings.key_click, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true)); + + keySettings.addItem(new CMenuForwarder(LOCALE_KEYBINDINGMENU_HEAD, true, NULL, bindSettings)); + //mainSettings.addItem(new CMenuForwarder(LOCALE_MAINSETTINGS_KEYBINDING, true, NULL, &keySettings , NULL, CRCInput::RC_blue , NEUTRINO_ICON_BUTTON_BLUE )); + + // USERMENU + keySettings.addItem(new CMenuSeparator(CMenuSeparator::LINE | CMenuSeparator::STRING, LOCALE_USERMENU_HEAD)); + keySettings.addItem(new CMenuForwarder(LOCALE_USERMENU_BUTTON_RED, true, NULL, new CUserMenuMenu(LOCALE_USERMENU_BUTTON_RED,0))); + keySettings.addItem(new CMenuForwarder(LOCALE_USERMENU_BUTTON_GREEN, true, NULL, new CUserMenuMenu(LOCALE_USERMENU_BUTTON_GREEN,1))); + keySettings.addItem(new CMenuForwarder(LOCALE_USERMENU_BUTTON_YELLOW, true, NULL, new CUserMenuMenu(LOCALE_USERMENU_BUTTON_YELLOW,2))); + keySettings.addItem(new CMenuForwarder(LOCALE_USERMENU_BUTTON_BLUE, true, NULL, new CUserMenuMenu(LOCALE_USERMENU_BUTTON_BLUE,3))); + + +} +// USERMENU +// leave this functions, somebody might want to use it in the future again +void CNeutrinoApp::SelectNVOD() +{ + if (!(g_RemoteControl->subChannels.empty())) + { + // NVOD/SubService- Kanal! + CMenuWidget NVODSelector(g_RemoteControl->are_subchannels ? LOCALE_NVODSELECTOR_SUBSERVICE : LOCALE_NVODSELECTOR_HEAD, "video.raw", 350); + if(getNVODMenu(&NVODSelector)) + NVODSelector.exec(NULL, ""); + } +} + +bool CNeutrinoApp::getNVODMenu(CMenuWidget* menu) +{ + if(menu == NULL) + return false; + if (g_RemoteControl->subChannels.empty()) + return false; + + menu->addItem(GenericMenuSeparator); + + int count = 0; + char nvod_id[5]; + + for( CSubServiceListSorted::iterator e=g_RemoteControl->subChannels.begin(); e!=g_RemoteControl->subChannels.end(); ++e) + { + sprintf(nvod_id, "%d", count); + + if( !g_RemoteControl->are_subchannels ) { + char nvod_time_a[50], nvod_time_e[50], nvod_time_x[50]; + char nvod_s[100]; + struct tm *tmZeit; + + tmZeit= localtime(&e->startzeit); + sprintf(nvod_time_a, "%02d:%02d", tmZeit->tm_hour, tmZeit->tm_min); + + time_t endtime = e->startzeit+ e->dauer; + tmZeit= localtime(&endtime); + sprintf(nvod_time_e, "%02d:%02d", tmZeit->tm_hour, tmZeit->tm_min); + + time_t jetzt=time(NULL); + if(e->startzeit > jetzt) { + int mins=(e->startzeit- jetzt)/ 60; + sprintf(nvod_time_x, g_Locale->getText(LOCALE_NVOD_STARTING), mins); + } + else if( (e->startzeit<= jetzt) && (jetzt < endtime) ) { + int proz=(jetzt- e->startzeit)*100/ e->dauer; + sprintf(nvod_time_x, g_Locale->getText(LOCALE_NVOD_PERCENTAGE), proz); + } + else + nvod_time_x[0]= 0; + + sprintf(nvod_s, "%s - %s %s", nvod_time_a, nvod_time_e, nvod_time_x); + menu->addItem(new CMenuForwarderNonLocalized(nvod_s, true, NULL, NVODChanger, nvod_id), (count == g_RemoteControl->selected_subchannel)); + } else { + menu->addItem(new CMenuForwarderNonLocalized(e->subservice_name.c_str(), true, NULL, NVODChanger, nvod_id, CRCInput::convertDigitToKey(count)), (count == g_RemoteControl->selected_subchannel)); + } + + count++; + } + + if( g_RemoteControl->are_subchannels ) { + menu->addItem(GenericMenuSeparatorLine); + CMenuOptionChooser* oj = new CMenuOptionChooser(LOCALE_NVODSELECTOR_DIRECTORMODE, &g_RemoteControl->director_mode, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, NULL, CRCInput::RC_yellow, NEUTRINO_ICON_BUTTON_YELLOW); + menu->addItem(oj); + } + return true; +} + +void CNeutrinoApp::SelectAPID() +{ +#if 0 + if( g_RemoteControl->current_PIDs.APIDs.size()> 1 ) + { + // wir haben APIDs für diesen Kanal! + + CMenuWidget APIDSelector(LOCALE_APIDSELECTOR_HEAD, "audio.raw", 300); + APIDSelector.addItem(GenericMenuSeparator); + + for( unsigned int count=0; countcurrent_PIDs.APIDs.size(); count++ ) + { + char apid[5]; + sprintf(apid, "%d", count); + APIDSelector.addItem(new CMenuForwarderNonLocalized(g_RemoteControl->current_PIDs.APIDs[count].desc, true, NULL, APIDChanger, apid, CRCInput::convertDigitToKey(count + 1)), (count == g_RemoteControl->current_PIDs.PIDs.selected_apid)); + } + APIDSelector.exec(NULL, ""); + } +#endif +} + +#define MAINMENU_RECORDING_OPTION_COUNT 2 +const CMenuOptionChooser::keyval MAINMENU_RECORDING_OPTIONS[MAINMENU_RECORDING_OPTION_COUNT] = +{ + { 0, LOCALE_MAINMENU_RECORDING_START }, + { 1, LOCALE_MAINMENU_RECORDING_STOP } +}; + +// USERMENU +// This is just a quick helper for the usermenu only. I already made it a class for future use. +#define BUTTONMAX 4 +const neutrino_msg_t key_helper_msg_def[BUTTONMAX]={CRCInput::RC_red,CRCInput::RC_green,CRCInput::RC_yellow,CRCInput::RC_blue}; +const char * key_helper_icon_def[BUTTONMAX]={NEUTRINO_ICON_BUTTON_RED,NEUTRINO_ICON_BUTTON_GREEN,NEUTRINO_ICON_BUTTON_YELLOW,NEUTRINO_ICON_BUTTON_BLUE}; +class CKeyHelper +{ + private: + int number_key; + bool color_key_used[BUTTONMAX]; + public: + CKeyHelper(){reset();}; + void reset(void) + { + number_key = 1; + for(int i= 0; i < BUTTONMAX; i++ ) + color_key_used[i] = false; + }; + + /* Returns the next available button, to be used in menu as 'direct' keys. Appropriate + * definitions are returnd in msp and icon + * A color button could be requested as prefered button (other buttons are not supported yet). + * If the appropriate button is already in used, the next number_key button is returned instead + * (first 1-9 and than 0). */ + bool get(neutrino_msg_t* msg, const char** icon, neutrino_msg_t prefered_key = CRCInput::RC_nokey) + { + bool result = false; + int button = -1; + if(prefered_key == CRCInput::RC_red) + button = 0; + if(prefered_key == CRCInput::RC_green) + button = 1; + if(prefered_key == CRCInput::RC_yellow) + button = 2; + if(prefered_key == CRCInput::RC_blue) + button = 3; + + *msg = CRCInput::RC_nokey; + *icon = ""; + if(button >= 0 && button < BUTTONMAX) + { // try to get color button + if( color_key_used[button] == false) + { + color_key_used[button] = true; + *msg = key_helper_msg_def[button]; + *icon = key_helper_icon_def[button]; + result = true; + } + } + + if( result == false && number_key < 10) // no key defined yet, at least try to get a numbered key + { + // there is still a available number_key + *msg = CRCInput::convertDigitToKey(number_key); + *icon = ""; + if(number_key == 9) + number_key = 0; + else if(number_key == 0) + number_key = 10; + else + number_key++; + result = true; + } + return (result); + }; +}; + +// USERMENU +bool CNeutrinoApp::showUserMenu(int button) +{ + if(button < 0 || button >= SNeutrinoSettings::BUTTON_MAX) + return false; + + CMenuItem* menu_item = NULL; + CKeyHelper keyhelper; + neutrino_msg_t key = CRCInput::RC_nokey; + const char * icon = NULL; + int dummy; + + int menu_items = 0; + int menu_prev = -1; + static int selected[SNeutrinoSettings::BUTTON_MAX] = {-1, -1, -1, -1}; + + // define classes + CFavorites* tmpFavorites = NULL; + CPauseSectionsdNotifier* tmpPauseSectionsdNotifier = NULL; + CAudioSelectMenuHandler* tmpAudioSelectMenuHandler = NULL; + CMenuWidget* tmpNVODSelector = NULL; + CStreamInfo2Handler* tmpStreamInfo2Handler = NULL; + CEventListHandler* tmpEventListHandler = NULL; + CEPGplusHandler* tmpEPGplusHandler = NULL; + CEPGDataHandler* tmpEPGDataHandler = NULL; + + std::string txt = g_settings.usermenu_text[button]; + if (button == SNeutrinoSettings::BUTTON_RED) { + if( txt.empty() ) + txt = g_Locale->getText(LOCALE_INFOVIEWER_EVENTLIST); + } + else if( button == SNeutrinoSettings::BUTTON_GREEN) { + if( txt.empty() ) + txt = g_Locale->getText(LOCALE_INFOVIEWER_LANGUAGES); + } + else if( button == SNeutrinoSettings::BUTTON_YELLOW) { + if( txt.empty() ) + txt = g_Locale->getText((g_RemoteControl->are_subchannels) ? LOCALE_INFOVIEWER_SUBSERVICE : LOCALE_INFOVIEWER_SELECTTIME); + //txt = g_Locale->getText(LOCALE_NVODSELECTOR_DIRECTORMODE); + } + else if( button == SNeutrinoSettings::BUTTON_BLUE) { + if( txt.empty() ) + txt = g_Locale->getText(LOCALE_INFOVIEWER_STREAMINFO); + } + CMenuWidget *menu = new CMenuWidget(txt.c_str() , "features.raw", 350); + if (menu == NULL) + return 0; + menu->addItem(GenericMenuSeparator); + + // go through any postition number + for(int pos = 0; pos < SNeutrinoSettings::ITEM_MAX ; pos++) { + // now compare pos with the position of any item. Add this item if position is the same + switch(g_settings.usermenu[button][pos]) { + case SNeutrinoSettings::ITEM_NONE: + // do nothing + break; + + case SNeutrinoSettings::ITEM_BAR: + if(menu_prev == -1 || menu_prev == SNeutrinoSettings::ITEM_BAR ) + break; + + menu->addItem(GenericMenuSeparatorLine); + menu_prev = SNeutrinoSettings::ITEM_BAR; + break; + + case SNeutrinoSettings::ITEM_FAVORITS: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_FAVORITS; + tmpFavorites = new CFavorites; + keyhelper.get(&key,&icon,CRCInput::RC_green); + menu_item = new CMenuForwarder(LOCALE_FAVORITES_MENUEADD, true, NULL, tmpFavorites, "-1", key, icon); + menu->addItem(menu_item, false); + break; + + case SNeutrinoSettings::ITEM_RECORD: + if(g_settings.recording_type == RECORDING_OFF) + break; + + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_RECORD; + keyhelper.get(&key,&icon,CRCInput::RC_red); + menu_item = new CMenuOptionChooser(LOCALE_MAINMENU_RECORDING, &recordingstatus, MAINMENU_RECORDING_OPTIONS, MAINMENU_RECORDING_OPTION_COUNT, true, this, key, icon); + menu->addItem(menu_item, false); + //if(has_hdd) + // menu->addItem(new CMenuForwarder(LOCALE_EXTRA_AUTO_TO_RECORD, autoshift, NULL, this, "autolink"), false); + break; + + case SNeutrinoSettings::ITEM_MOVIEPLAYER_MB: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_MOVIEPLAYER_MB; + keyhelper.get(&key,&icon,CRCInput::RC_green); + menu_item = new CMenuForwarder(LOCALE_MOVIEBROWSER_HEAD, true, NULL, moviePlayerGui, "tsmoviebrowser", key, icon); + menu->addItem(menu_item, false); + break; + + case SNeutrinoSettings::ITEM_TIMERLIST: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_TIMERLIST; + keyhelper.get(&key,&icon,CRCInput::RC_yellow); + menu_item = new CMenuForwarder(LOCALE_TIMERLIST_NAME, true, NULL, Timerlist, "-1", key, icon); + menu->addItem(menu_item, false); + break; + + case SNeutrinoSettings::ITEM_REMOTE: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_REMOTE; + keyhelper.get(&key,&icon); + menu_item = new CMenuForwarder(LOCALE_RCLOCK_MENUEADD, true, NULL, this->rcLock, "-1" , key, icon ); + menu->addItem(menu_item, false); + break; + + case SNeutrinoSettings::ITEM_EPG_SUPER: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_EPG_SUPER; + tmpEPGplusHandler = new CEPGplusHandler(); + keyhelper.get(&key,&icon,CRCInput::RC_green); + menu_item = new CMenuForwarder(LOCALE_EPGMENU_EPGPLUS , true, NULL, tmpEPGplusHandler , "-1", key, icon); + menu->addItem(menu_item, false); + break; + + case SNeutrinoSettings::ITEM_EPG_LIST: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_EPG_LIST; + tmpEventListHandler = new CEventListHandler(); + keyhelper.get(&key,&icon,CRCInput::RC_red); + menu_item = new CMenuForwarder(LOCALE_EPGMENU_EVENTLIST , true, NULL, tmpEventListHandler, "-1", key, icon); + menu->addItem(menu_item, false); + break; + + case SNeutrinoSettings::ITEM_EPG_INFO: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_EPG_INFO; + tmpEPGDataHandler = new CEPGDataHandler(); + keyhelper.get(&key,&icon,CRCInput::RC_yellow); + menu_item = new CMenuForwarder(LOCALE_EPGMENU_EVENTINFO , true, NULL, tmpEPGDataHandler , "-1", key, icon); + menu->addItem(menu_item, false); + break; + + case SNeutrinoSettings::ITEM_EPG_MISC: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_EPG_MISC; + dummy = g_Sectionsd->getIsScanningActive(); + //dummy = sectionsd_scanning; + tmpPauseSectionsdNotifier = new CPauseSectionsdNotifier; + keyhelper.get(&key,&icon); + menu_item = new CMenuOptionChooser(LOCALE_MAINMENU_PAUSESECTIONSD, &dummy, OPTIONS_OFF0_ON1_OPTIONS, OPTIONS_OFF0_ON1_OPTION_COUNT, true, tmpPauseSectionsdNotifier , key, icon ); + menu->addItem(menu_item, false); + menu_items++; + keyhelper.get(&key,&icon); + menu_item = new CMenuForwarder(LOCALE_MAINMENU_CLEARSECTIONSD, true, NULL, this, "clearSectionsd", key,icon); + menu->addItem(menu_item, false); + break; + + case SNeutrinoSettings::ITEM_AUDIO_SELECT: + //g_settings.audio_left_right_selectable || g_RemoteControl->current_PIDs.APIDs.size() > 1) + if (1) { + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_AUDIO_SELECT; + tmpAudioSelectMenuHandler = new CAudioSelectMenuHandler; + keyhelper.get(&key,&icon); + menu_item = new CMenuForwarder(LOCALE_AUDIOSELECTMENUE_HEAD, true, NULL, tmpAudioSelectMenuHandler, "-1", key,icon); + menu->addItem(menu_item, false); + } + break; + + case SNeutrinoSettings::ITEM_SUBCHANNEL: + if (!(g_RemoteControl->subChannels.empty())) { + // NVOD/SubService- Kanal! + tmpNVODSelector = new CMenuWidget(g_RemoteControl->are_subchannels ? LOCALE_NVODSELECTOR_SUBSERVICE : LOCALE_NVODSELECTOR_HEAD, "video.raw", 350); + if(getNVODMenu(tmpNVODSelector)) { + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_SUBCHANNEL; + keyhelper.get(&key,&icon); + menu_item = new CMenuForwarder(g_RemoteControl->are_subchannels ? LOCALE_NVODSELECTOR_SUBSERVICE : LOCALE_NVODSELECTOR_HEAD, true, NULL, tmpNVODSelector, "-1", key,icon); + menu->addItem(menu_item, false); + } + } + break; + + case SNeutrinoSettings::ITEM_TECHINFO: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_TECHINFO; + tmpStreamInfo2Handler = new CStreamInfo2Handler(); + keyhelper.get(&key,&icon,CRCInput::RC_blue); + menu_item = new CMenuForwarder(LOCALE_EPGMENU_STREAMINFO, true, NULL, tmpStreamInfo2Handler , "-1", key, icon ); + menu->addItem(menu_item, false); + break; + case SNeutrinoSettings::ITEM_PLUGIN: + { + char id[5]; + int cnt = 0; + for(unsigned int count = 0; count < (unsigned int) g_PluginList->getNumberOfPlugins(); count++) + { + std::string tmp = g_PluginList->getName(count); + if (g_PluginList->getType(count)== CPlugins::P_TYPE_TOOL && !g_PluginList->isHidden(count) && tmp.find("Teletext") == std::string::npos) + { + sprintf(id, "%d", count); + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_PLUGIN; + + //keyhelper.get(&key,&icon,CRCInput::RC_blue); + keyhelper.get(&key,&icon); + menu_item = new CMenuForwarderNonLocalized(g_PluginList->getName(count), true, NULL, StreamFeaturesChanger, id, key, icon); + //menu->addItem(menu_item, (cnt == 0)); + menu->addItem(menu_item, 0); + cnt++; + } + } + } + break; + case SNeutrinoSettings::ITEM_VTXT: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_VTXT; + keyhelper.get(&key,&icon); + menu_item = new CMenuForwarder(LOCALE_USERMENU_ITEM_VTXT, true, NULL, StreamFeaturesChanger, "teletext", key, icon); + menu->addItem(menu_item, 0); + + break; +#if 0 // FIXME not supported yet + case SNeutrinoSettings::ITEM_MOVIEPLAYER_TS: + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_MOVIEPLAYER_TS; + keyhelper.get(&key,&icon,CRCInput::RC_green); + menu_item = new CMenuForwarder(LOCALE_MOVIEPLAYER_TSPLAYBACK, true, NULL, moviePlayerGui, "tsplayback", key, icon); + menu->addItem(menu_item, false); + break; + + case SNeutrinoSettings::ITEM_VTXT: + for(unsigned int count = 0; count < (unsigned int) g_PluginList->getNumberOfPlugins(); count++) + { + std::string tmp = g_PluginList->getName(count); + if (g_PluginList->getType(count)== CPlugins::P_TYPE_TOOL && !g_PluginList->isHidden(count) && tmp.find("Teletext") != std::string::npos) + { + sprintf(id, "%d", count); + menu_items++; + menu_prev = SNeutrinoSettings::ITEM_VTXT; + + //keyhelper.get(&key,&icon,CRCInput::RC_blue); + keyhelper.get(&key,&icon); + menu_item = new CMenuForwarderNonLocalized(g_PluginList->getName(count), true, NULL, StreamFeaturesChanger, id, key, icon); + menu->addItem(menu_item, 0); + } + } + break; +#endif + default: + printf("[neutrino] WARNING! menu wrong item!!\n"); + break; + } + } + + // Allow some tailoring for privat image bakers ;) + if (button == SNeutrinoSettings::BUTTON_RED) { + } + else if( button == SNeutrinoSettings::BUTTON_GREEN) { + } + else if( button == SNeutrinoSettings::BUTTON_YELLOW) { + } + else if( button == SNeutrinoSettings::BUTTON_BLUE) { +#ifdef _EXPERIMENTAL_SETTINGS_ + //Experimental Settings + if(menu_prev != -1) + menu->addItem(GenericMenuSeparatorLine); + menu_items ++; + menu_key++; + // FYI: there is a memory leak with 'new CExperimentalSettingsMenuHandler() + menu_item = new CMenuForwarder(LOCALE_EXPERIMENTALSETTINGS, true, NULL, new CExperimentalSettingsMenuHandler(), "-1", CRCInput::convertDigitToKey(menu_key), ""); + menu->addItem(menu_item, false); +#endif + } + + // show menu if there are more than 2 items only + // otherwise, we start the item directly (must be the last one) + if(menu_items > 1 ) { + menu->setSelected(selected[button]); + menu->exec(NULL,""); + selected[button] = menu->getSelected(); + } + else if (menu_item != NULL) + menu_item->exec( NULL ); + + // restore mute symbol + //AudioMute(current_muted, true); + + // clear the heap + if(tmpFavorites) delete tmpFavorites; + if(tmpPauseSectionsdNotifier) delete tmpPauseSectionsdNotifier; + if(tmpAudioSelectMenuHandler) delete tmpAudioSelectMenuHandler; + if(tmpNVODSelector) delete tmpNVODSelector; + if(tmpStreamInfo2Handler) delete tmpStreamInfo2Handler; + if(tmpEventListHandler) delete tmpEventListHandler; + if(tmpEPGplusHandler) delete tmpEPGplusHandler; + if(tmpEPGDataHandler) delete tmpEPGDataHandler; + if(menu) delete menu; + return 0; +} + +void CNeutrinoApp::ShowStreamFeatures() +{ +} diff --git a/src/nhttpd/AUTHORS b/src/nhttpd/AUTHORS new file mode 100644 index 000000000..5ee23b668 --- /dev/null +++ b/src/nhttpd/AUTHORS @@ -0,0 +1,21 @@ +AUTHORS +of Neutrino Webserver +in order of appearance (bottom up) + + +Johannes Golombek [yjogol@cvs.tuxbox.org] +Bengt Martensson [barf@cvs.tuxbox.org] +Jacek Jendrzej [metallica@cvs.tuxbox.org] +Henning Behrend [sat_man@cvs.tuxbox.org] +Axel Buehning [diemade@cvs.tuxbox.org] +Michael Schuele [chakazulu@cvs.tuxbox.org] +Peter Reich [digi_casi@cvs.tuxbox.org] +H.Heinold [heinold@physik.tu-cottbus.de] +Sven Traenkle [zwen@cvs.tuxbox.org] +gagga +wjoost +Ralf Gandy +Michael Lantzen +Andreas Oberritter +Dirk Szymanski [dirch@cvs.tuxbox.org] +Steffen Hehn diff --git a/src/nhttpd/COPYING b/src/nhttpd/COPYING new file mode 100644 index 000000000..623b6258a --- /dev/null +++ b/src/nhttpd/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/nhttpd/Makefile.am b/src/nhttpd/Makefile.am new file mode 100644 index 000000000..19586226b --- /dev/null +++ b/src/nhttpd/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = yhttpd_core yhttpd_mods tuxboxapi web + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/src/nhttpd/yhttpd_core \ + -I$(top_srcdir)/src/nhttpd/yhttpd_mods \ + -I$(top_srcdir)/src/nhttpd/tuxboxapi \ + -I$(top_srcdir)/lib/libeventserver \ + -I$(top_srcdir)/lib/libconfigfile \ + -I$(top_srcdir)/lib/connection \ + @FREETYPE_CFLAGS@ + +noinst_LIBRARIES = libnhttpd.a +libnhttpd_a_SOURCES = yhttpd.cpp diff --git a/src/nhttpd/README b/src/nhttpd/README new file mode 100644 index 000000000..052946f82 --- /dev/null +++ b/src/nhttpd/README @@ -0,0 +1,18 @@ +------------------------------------------------------------------------------ +nhttpd Version 3.x = (yhttpd 3.x + tuxboxapi) +------------------------------------------------------------------------------ + +13.09.2006 (yjogol) +------------------- +Starting with Version 3.0 the nhttpd source code was splitted into +a core Webserver (yhttpd_core), extension modules (yhttpd_mods) and the +tuxbox specific code (tuxboxapi). + +The yhttpd_core and yhttp_mods are completly rewritten. +All Neutrino specific code was reorganized into yParser- and ControlAPI-code. + +The Hook-System (extension modules) encapsulate all requests and responses +for the tuxboxapi. So both tuxboxapi and yhttpd can be developed seperatlly and +independ from each other. + +Look at yhttpd_core/README diff --git a/src/nhttpd/doc/Changelog.txt b/src/nhttpd/doc/Changelog.txt new file mode 100644 index 000000000..f06bd2b72 --- /dev/null +++ b/src/nhttpd/doc/Changelog.txt @@ -0,0 +1,320 @@ +Severity id Headline Build + +5-Enhancement JG200000540 nhttpd: new: /y/cache-info view and clear cache nhttpd 3.0.5 +5-Enhancement JG200000553 Live: Support for Non-compatible HTTP1.1-Clients like JtG-Servernhttpd 3.0.5 +5-Enhancement JG200000548 nhttpd: new hooks for Upload handling n httpd 3.0.5 +5-Enhancement JG200000549 nhttpd: mod_auth new Base64 algorism nhttpd 3.0.5 +5-Enhancement JG200000545 nhttpd: upload POST works with SSL now nhttpd 3.0.5 +5-Enhancement JG200000528 nhttpd: Autentication: new implemented nhttpd 3.0.5 +5-Enhancement JG200000538 nhttpd: yParser Cache nhttpd 3.0.5 +5-Enhancement JG200000544 nhttpd: new format of nhttpd.conf nhttpd 3.0.5 +5-Enhancement JG200000541 nhttpd: new /y/server-config nhttpd 3.0.5 +5-Enhancement JG200000550 nhttpd: add SSL support nhttpd 3.0.5 +5-Enhancement JG200000542 nhttpd: new module mod_cache for caching dynamic content nhttpd 3.0.5 +5-Enhancement JG200000543 nhttpd: new module mod_weblog CLF and ELF logging nhttpd 3.0.5 +5-Enhancement JG200000547 nhttpd: more Features for HTTP1.1 support nhttpd 3.0.5 +5-Enhancement JG200000546 nhttpd: new Socket multiplexing for multi-threading nhttpd 3.0.5 +5-Enhancement JG200000536 nhttpd: Upload Progress .. nhttpd 3.0.5 + +5-Enhancement JG200000552 Settings: Support for new nhttpd.conf Format R2.2.0 +5-Enhancement JG200000530 nhttpd: Webserver (yhhtpd) rewritten nhttpd 3.0.0 +5-Enhancement JG200000529 nhttpd: split nhttpd in yhttpd_core, yhttpd_mods, neutrinoAPI nhttpd 3.0.0 +5-Enhancement JG200000527 Bouquet: Bouquet-Editor moved to tools R2.1.0 +5-Enhancement JG200000523 Bouquet-Editor: new implemented R2.1.0 +5-Enhancement JG200000526 Bouquet: EPG-List: new implemented R2.1.0 +5-Enhancement JG200000534 Boxcontrol: Use /control/standby to determine standby status R2.1.0 +5-Enhancement JG200000440 Timer: ANNOUNCE_TIME_1=-120 at Rec from EPG .. R2.1.0 +5-Enhancement JG200000524 Timer: TimerList new implemented R2.1.0 +5-Enhancement JG200000531 Timer: use RecordingSafty in Timer-Prog R2.1.0 +5-Enhancement JG200000525 Timer: add/modify Timer: new implemented R2.1.0 +4-Minor JG200000522 Tools: Flash fix reboot button R2.1.0 + +5-Enhancement JG200000511 GUI: disable AutoMount if ManagementIP does not match R2.0.2 +4-Minor JG200000519 Live: VLC Snapshot with IE works again R2.0.2 +5-Enhancement JG200000512 Live: fix: Fullscreen-Button (IE) does not work R2.0.2 +5-Enhancement JG200000518 Live: add EPG-Button for Popup R2.0.2 +3-Average JG200000517 Record: fixed: Record without transcoding works again R2.0.2 +5-Enhancement JG200000514 Settings: Diverse: add EPG-Settings R2.0.2 +5-Enhancement JG200000513 Settings: Diverse: add Virtual zap R2.0.2 + +3-Average JG200000504 fix: call dboxshot correctly if installed in /var/bin (in Remote OSD) R2.0.1 +3-Average JG200000506 Live: fixed Problems switching channels in LiveTV/Radio R2.0.1 +5-Enhancement JG200000507 Live: MiniEPG only on demand R2.0.1 + +5-Enhancement JG200000478 Boxcontrol: OSD Screenshot: Support for dboxshot R2.0.0 +5-Enhancement JG200000480 Boxcontrol: Control: Live lock / unlock R2.0.0 +5-Enhancement JG200000482 Boxcontrol: Control: new: Standby Status R2.0.0 +5-Enhancement JG200000483 EPG: Link to IMDB R2.0.0 +5-Enhancement JG200000498 Boxcontrol: add SPTS Status R2.0.0 +5-Enhancement JG200000497 Boxcontrol: New RC-Imake: Nokia-Remote R2.0.0 +5-Enhancement JG200000494 Boxcontrol: Control: Add optical Output on/off/status R2.0.0 +4-Minor JG200000392 GUI: initialize Volumen correctly .. R2.0.0 +5-Enhancement JG200000331 GUI: all Pages W3C XHTML 1.0 conform .. R2.0.0 +5-Enhancement JG200000465 GUI: new volumen control R2.0.0 +5-Enhancement JG200000459 GUI: new yWeb 2.0 Layout R2.0.0 +5-Enhancement JG200000254 GUI: Show channel-logos (if mounted) R2.0.0 +5-Enhancement JG200000455 GUI: Help: New Item to Wiki R2.0.0 +5-Enhancement JG200000449 GUI: show actual time in main menu R2.0.0 +5-Enhancement JG200000439 GUI: show custom text in Menue to identify box (if you have several boxes) R2.0.0 +5-Enhancement JG200000468 Info: add external Links for getting help R2.0.0 +5-Enhancement JG200000473 Live: Radio-Streaming with VLC (0.8.5) New! R2.0.0 +5-Enhancement JG200000500 Live: Transcode: own dialogue and more settings R2.0.0 +5-Enhancement JG200000464 Live: Mini EPG for actual channel R2.0.0 +5-Enhancement JG200000484 Live: dont show bouquet if set to hidden R2.0.0 +5-Enhancement JG200000408 Live: deinterlace & http-caching R2.0.0 +5-Enhancement JG200000492 Live: Set Timer from Mini EPG R2.0.0 +5-Enhancement JG200000457 Record: Transcode while recording R2.0.0 +5-Enhancement JG200000443 Record: new option: display off R2.0.0 +5-Enhancement JG200000458 Record: add Profiles for transcoding (iPodVideo, custom...) R2.0.0 +5-Enhancement JG200000474 Record: Radio-Recording & Transcoding (VLC) to mp3, iPod, custom R2.0.0 +5-Enhancement JG200000477 Record: Radio-Recording & Transcoding (mp3, iPod, custom) R2.0.0 +5-Enhancement JG200000456 Settings: Backup & Restore settings R2.0.0 +5-Enhancement JG200000475 Settings: new direct recording Filename template R2.0.0 +5-Enhancement JG200000496 settings: remove support antiservices.xml R2.0.0 +5-Enhancement JG200000479 Settings: New Menu for Live-Settings R2.0.0 +5-Enhancement JG200000487 Settings: WebServer: new ExtrasDocRoot/URL R2.0.0 +5-Enhancement JG200000134 Timer: new: EPG+ R2.0.0 +5-Enhancement JG200000452 Timer: SyncTimer: Switch to TV only from radio-mode R2.0.0 +5-Enhancement JG200000490 Timer: EPG+ add set timer and zapto R2.0.0 +4-Minor JG200000137 Tools: Message to box displays special charachers correct R2.0.0 +5-Enhancement JG200000448 Tools: Wake on Lan fix Javascript Error R2.0.0 +5-Enhancement JG200000470 Tools: Flash image: add Demo mode R2.0.0 +5-Enhancement JG200000469 Tools: Flash image: new dialogs R2.0.0 +5-Enhancement JG200000476 Tools: AutoMount (Warmduscher Interface) R2.0.0 + +3-Average JG200000485 nhttpd: fixed: yvars now in WebserverRequest (multi-threading) nhttpd 2.2.4 +5-Enhancement JG200000463 nhttpd: add EPG data in XML format nhttpd 2.2.4 +5-Enhancement JG200000486 nhttpd: add caching for blocks nhttpd 2.2.4 +5-Enhancement JG200000488 nhttpd: Set Timer, zapto,epg: Channel_name with multiple values .. nhttpd 2.2.4 +5-Enhancement JG200000491 nhttpd: new: XML-Format for bouquets nhttpd 2.2.4 +5-Enhancement JG200000495 nhttpd: new: zapto?getallsubchannels nhttpd 2.2.4 + +5-Enhancement JG200000399 Boxcontrol: view box record-status .. R1.5.0 +3-Average JG200000424 Bouquetedit: fixed probs with Firefox 1.5 editing problems R1.5.0 +5-Enhancement JG200000414 GUI: Links to Wiki R1.5.0 +3-Average JG200000420 Live: fixed Stream-URL problems with yadd & Firefox R1.5.0 +5-Enhancement JG200000432 Live: Radio works with yadds R1.5.0 +5-Enhancement JG200000351 LiveView: Build Stream-URL with ClientAddr (for NAT, Remapping) R1.5.0 +4-Minor JG200000433 Settings: WOL fixed Javascript Errors R1.5.0 +5-Enhancement JG200000394 Settings: add: Neutrino direct recording settings ... R1.5.0 +5-Enhancement JG200000417 Settings: WebServer: add HostedDocumentRoot R1.5.0 +5-Enhancement JG200000418 Settings: WebServer: add NoAuthClient R1.5.0 +5-Enhancement JG200000373 Settings: yWeb speed up using caching R1.5.0 +5-Enhancement JG200000434 Settings: WOL Link to yWeb-Settings R1.5.0 +5-Enhancement JG200000435 Settings: About: Links to Wiki R1.5.0 +5-Enhancement JG200000425 Timer: SyncTimer: added start and stop deplay from recording settings R1.5.0 +5-Enhancement JG200000405 Timer: Sync Timer: add rec_dir R1.5.0 +5-Enhancement JG200000231 Timer: tvinfo.de download & TimerSync R1.5.0 +5-Enhancement JG200000398 Timer: new timer default now: record R1.5.0 +4-Minor JG200000410 Tools: Sagem RC is displayed in primary menu R1.5.0 +5-Enhancement JG200000415 Tools: new: Check Installation R1.5.0 +5-Enhancement JG200000348 Tools: Info: use echo -e to advoid escaped newline output R1.5.0 + +5-Enhancement JG200000438 nhttpd: add Timer: rec_dir from neutrino.conf as default nhttpd 2.2.3 +5-Enhancement JG200000423 nhttpd: fixed lost Data in POST-Method (Mozilla/Firefox) nhttpd 2.2.2 +5-Enhancement JG200000422 nhttpd: No Authentication with new NoAuthClient fixed nhttpd 2.2.2 +5-Enhancement JG200000428 nhttpd: ini-set caching: clear config on open nhttpd 2.2.2 + +5-Enhancement JG200000294 nhttpd: Host other Webs (Root defined at HostedDocumentRoot in nhttpd.conf) nhttpd 2.2.1 +5-Enhancement JG200000388 nhttpd: set IP with no authentication (e.g. for JtG etc) nhttpd 2.2.1 +5-Enhancement JG200000416 nhttdp: zapto mit channel_name nhttpd 2.2.1 + +3-Average JG200000369 Live: fixed problems switching Radio-Channels R1.4.3 +4-Minor JG200000355 nhttpd: change port now used in Scripts R1.4.3 +4-Minor JG200000365 Settings: fixed: upload cam-alpha.bin now named correctly R1.4.3 +5-Enhancement JG200000366 settings: add port to WebServer settings R1.4.3 +5-Enhancement JG200000367 gui: add remote control for Sagem R1.4.3 +5-Enhancement JG200000389 tools: restart sectionsd R1.4.3 +5-Enhancement JG200000391 flash: fixed reboot after flashing R1.4.3 + +4-Minor JG200000359 tools: fix reboot after flash R1.4.2 +5-Enhancement JG200000332 Live: record: filepath settings at settings->yWeb R1.4.2 +5-Enhancement JG200000337 bouquets: start bouquetlist at actual bouquet R1.4.2 +5-Enhancement JG200000360 bouquet: text in black again R1.4.2 + +5-Enhancement JG200000127 flash download: button for delete download-image in /tmp R1.4.1 +5-Enhancement JG200000339 nhttpd: new: file-action:;; R1.4.1 +5-Enhancement JG200000340 new: Neutrino-Settings: pictureviewer R1.4.1 +5-Enhancement JG200000341 new: Neutrino-Settings: Audioplayer R1.4.1 +5-Enhancement JG200000342 new: Neutrino-Settings: Movieplayer R1.4.1 +5-Enhancement JG200000343 new: Neutrino-Settings: Diverse R1.4.1 +5-Enhancement JG200000344 new: Neutrino-Settings: Boot Options R1.4.1 +5-Enhancement JG200000345 new: Neutrino-Settings: Parental R1.4.1 +5-Enhancement JG200000346 new: Neutrino-Settings: Recording R1.4.1 +5-Enhancement JG200000347 Timer: add recordingDir R1.4.1 + +3-Average JG200000156 Flash: Error in mtd list if length!=5 R1.4.0 +5-Enhancement JG200000326 Flash: New Dialogs R1.4.0 +5-Enhancement JG200000233 Tools: new: Wake on LAN for 3 MACs R1.4.0 +5-Enhancement JG200000246 mount: do mount at mount list R1.4.0 +5-Enhancement JG200000247 mount: new: unmount list R1.4.0 +5-Enhancement JG200000305 infos: /proc/cpuinfo, meminfo, version... R1.4.0 +5-Enhancement JG200000271 nhttpd: ycgi: new: include-block:;; R1.4.0 +5-Enhancement JG200000314 nhttpd: ycgi: new: ini-set:;; R1.4.0 +5-Enhancement JG200000234 nhttpd: ycgi: new: if-file-exists:~~ R1.4.0 +5-Enhancement JG200000315 nhttpd: ycgi: new: if-not-equal R1.4.0 +5-Enhancement JG200000317 nhttpd: ycgi: new: add var-set, var-get for local ycgi varables R1.4.0 +5-Enhancement JG200000318 Live: Experimental: Change VLC audio channel R1.4.0 +5-Enhancement JG200000311 Live: record (Expert Mode ActiveX).. R1.4.0 +5-Enhancement JG200000312 Live: record: mux type = ts, ps R1.4.0 +5-Enhancement JG200000319 Live: Expert Mode: Take VLC Snapshot R1.4.0 +5-Enhancement JG200000320 after change Web Password: reload nhttpd.conf R1.4.0 +5-Enhancement JG200000325 General from-dialog updates R1.4.0 +5-Enhancement JG200000327 New: OSD Snapshot with fbshot R1.4.0 +5-Enhancement JG200000316 Management IP for some dialogs required R1.4.0 + +3-Average JG200000308 nhttpd: re-write file upload handling (solved: problems with pre-send data - mozilla engines) R1.3.6 +5-Enhancement JG200000144 Live: add Streaminfo button R1.3.6 +5-Enhancement JG200000145 yInstaller: upload a tar-file and execude included install.sh R1.3.6 +5-Enhancement JG200000287 WebIF: telnet like commandline R1.3.6 +5-Enhancement JG200000292 Live: channel-EPG-Panel autorefresh all 5min R1.3.6 +5-Enhancement JG200000297 Live: epg preview for selected channel R1.3.6 +5-Enhancement JG200000304 nhttpd: new func get_request_data R1.3.6 +5-Enhancement JG200000307 nhttpd: re-write file upload handling (saving memory) R1.3.6 + +4-Minor JG200000266 Settings: WebServer JavaScript-Error for field port R1.3.5 +4-Minor JG200000269 _Y_Library.sh:config_set_value() interpret backslash R1.3.5 +4-Minor JG200000232 Live:Sprache: DropDown ins TV Fenster R1.3.5 +5-Enhancement JG200000141 Live: enable select audio-pid R1.3.5 +5-Enhancement JG200000237 robots.txt in html-root R1.3.5 +5-Enhancement JG200000255 keine hard-links nach httpd-y (z.B. _Y_Globals.sh) R1.3.5 +5-Enhancement JG200000272 Dialog Boot-Logo und LCD-Logo zusammenfassen R1.3.5 +5-Enhancement JG200000277 Tooltips in english R1.3.5 +5-Enhancement JG200000278 Tools->msg beide Dialoge zusammenfassen R1.3.5 +5-Enhancement JG200000280 tools: move Message to Boxcontrol R1.3.5 +5-Enhancement JG200000284 use image am maps for web-based remote control R1.3.5 + +4-Minor JG200000216 nhttp: Upload temporary file moved from /var/tmp to /tmp/upload.tmp R1.3.4 +5-Enhancement JG200000139 Live: EPG-Title in Channel-Dropdown R1.3.4 +5-Enhancement JG200000212 nhttpd: use relative path for includes R1.3.4 +5-Enhancement JG200000217 nhttpd: ycgi: set Working-Dir to template path R1.3.4 +5-Enhancement JG200000227 ycgi: new:func:get_audio_pids_as_dropdown R1.3.4 +5-Enhancement JG200000229 remote RC via Web R1.3.4 + +5-Enhancement JG200000218 ycgi: new cmd: if-empty R1.3.3 +5-Enhancement JG200000219 ycgi: new cmd: if-equal R1.3.3 +5-Enhancement JG200000220 ycgi: new:func:get_bouquts_as_dropdown R1.3.3 +5-Enhancement JG200000221 ycgi: new:func:get_actual_bouquet_numer R1.3.3 +5-Enhancement JG200000222 ycgi: new:func:get_canel_as_dropdown R1.3.3 +5-Enhancement JG200000223 ycgi: new:func:get_actual_channel_id R1.3.3 +5-Enhancement JG200000224 ycgi: new:func:get_mode R1.3.3 +5-Enhancement JG200000225 ycgi: new:func:get_video_pids R1.3.3 +5-Enhancement JG200000226 ycgi: new:func:get_radio_pid R1.3.3 +5-Enhancement JG200000235 ycgi: Neu *.yhtm-Dateien & Reorg der Dateien R1.3.3 + +5-Enhancement JG200000035 Live: Window size configurable R1.3.2 +5-Enhancement JG200000107 Live: new: Double-View R1.3.2 +5-Enhancement JG200000206 nhttpd: Set Working dir for Skripts R1.3.2 +5-Enhancement JG200000207 scripts: relative local include path R1.3.2 +5-Enhancement JG200000209 correct Frame-Destinations VNC, Skins, WebServer R1.3.2 +5-Enhancement JG200000210 Settings: yWeb Configurator (slave box, live resolution) R1.3.2 +5-Enhancement JG200000211 add ucode.bin for up/download R1.3.2 + +5-Enhancement JG200000200 Live: Radio: Player via Dateierweiterung m3u, m4u starten R1.3.1 +3-Average JG200000147 LiveView nur 9 Bouquets im Dropdown. fixed. R1.3.1 +4-Minor JG200000179 dietmarW-Images habe kein /var/tmp also /tmp nutzen R1.3.1 +5-Enhancement JG200000084 Plugins: Settings: Mount-Einstellungen R1.3.1 +5-Enhancement JG200000182 Live: Bouquets & Channel: Dropdown Breite begrenzen R1.3.1 +5-Enhancement JG200000183 Bouquets: epg und settings im yWeb_Layout R1.3.1 +5-Enhancement JG200000184 ycgi: execute= + + + + +{=var-set:wait_text=Save.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:BoxControl#Bouquet-Editor=}{=var-set:menu=Bouquet "{=name=}" workon=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+

+ + + + + + +
+ + +

+

+

+

+
+ +
+ +

+

+ All changes must be still stored! +
+
+
+ + diff --git a/src/nhttpd/web/Y_Boxcontrol_Bouquet_Editor_Main.yhtm b/src/nhttpd/web/Y_Boxcontrol_Bouquet_Editor_Main.yhtm new file mode 100644 index 000000000..6b9255c55 --- /dev/null +++ b/src/nhttpd/web/Y_Boxcontrol_Bouquet_Editor_Main.yhtm @@ -0,0 +1,186 @@ +{=include-block:Y_Blocks.txt;head_no_charset=} + + + + + + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:BoxControl#Bouquet-Editor=}{=var-set:menu=Bouquet-Editor=}{=include-block:Y_Blocks.txt;work_menu=}
+
+

+ [add Bouquet] + [save] +

+
+
+

Bouquet add
+ New Bouquets' name: + +
+ + +

+
+
+
+
+

+

Bouquet rename
+ New Bouquets' name: + + +
+ + +

+
+
+ + +{=var-set:row= + + + + + + +=} +{=func:bouquet_editor_main {=var-get:row=}=} +
+ %s + + %s + + + %s + +%s + + umbenennen  + + löschen  + + nach unten  + + nach oben  +
+
+
+ + + diff --git a/src/nhttpd/web/Y_Boxcontrol_Bouquetlist.yhtm b/src/nhttpd/web/Y_Boxcontrol_Bouquetlist.yhtm new file mode 100644 index 000000000..a55389a43 --- /dev/null +++ b/src/nhttpd/web/Y_Boxcontrol_Bouquetlist.yhtm @@ -0,0 +1,11 @@ +{=include-block:Y_Blocks.txt;head_no_charset=} + + + + + + +{=func:get_bouquets_as_templatelist =} +
Channels

%s
+ + diff --git a/src/nhttpd/web/Y_Boxcontrol_Bouquets.yhtm b/src/nhttpd/web/Y_Boxcontrol_Bouquets.yhtm new file mode 100644 index 000000000..ff46521b2 --- /dev/null +++ b/src/nhttpd/web/Y_Boxcontrol_Bouquets.yhtm @@ -0,0 +1,15 @@ +{=include-block:Y_Blocks.txt;head=} + + +
+
+ {=var-set:help_url=Neutrino:yWeb:BoxControl#Bouquet=}{=var-set:menu=Bouquet=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ + +
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Boxcontrol_Channellist.yhtm b/src/nhttpd/web/Y_Boxcontrol_Channellist.yhtm new file mode 100644 index 000000000..7baed8edc --- /dev/null +++ b/src/nhttpd/web/Y_Boxcontrol_Channellist.yhtm @@ -0,0 +1,28 @@ +{=include-block:Y_Blocks.txt;head_no_charset=} + + + + + + +{=func:get_bouquets_with_epg {=bouquet=}=} +
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Boxcontrol_Menue.yhtm b/src/nhttpd/web/Y_Boxcontrol_Menue.yhtm new file mode 100644 index 000000000..60f196876 --- /dev/null +++ b/src/nhttpd/web/Y_Boxcontrol_Menue.yhtm @@ -0,0 +1,115 @@ +{=var-set:cancache=yPInstall=} +{=include-block:Y_Blocks.txt;head=} + + + +{=var-set:fbshot={=if-file-exists:/bin/fbshot~true~{=if-file-exists:/var/bin/fbshot~true~{=if-file-exists:/bin/dboxshot~true~{=if-file-exists:/var/bin/dboxshot~true~false=}=}=}=}=} +{=var-set:dboxshot={=if-file-exists:/bin/dboxshot~true~{=if-file-exists:/var/bin/dboxshot~true~false=}=}=} + +
+

Boxcontrol

+
+
+ +
+
+
+
+

Control

+
+
+ + + + + +
..
+
+ +  -  + +  +  + + Mute +

+ TV + Radio +
+
+
+ + + diff --git a/src/nhttpd/web/Y_Boxcontrol_Messages.yhtm b/src/nhttpd/web/Y_Boxcontrol_Messages.yhtm new file mode 100644 index 000000000..efe1273bb --- /dev/null +++ b/src/nhttpd/web/Y_Boxcontrol_Messages.yhtm @@ -0,0 +1,40 @@ +{=var-set:cancache=yPyes=} +{=include-block:Y_Blocks.txt;head=} + + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:BoxControl#Message=}{=var-set:menu=Message=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + +
Message to Coolstram-TV Screen
+ + +
Popup message to Coolstream-TV Screen
+ + +
+
+
+
+
+ + diff --git a/src/nhttpd/web/Y_Dyn_Pages.yhtm b/src/nhttpd/web/Y_Dyn_Pages.yhtm new file mode 100644 index 000000000..607f97fd4 --- /dev/null +++ b/src/nhttpd/web/Y_Dyn_Pages.yhtm @@ -0,0 +1 @@ +{=include-block:Y_Blocks.txt;{=page=}=} \ No newline at end of file diff --git a/src/nhttpd/web/Y_EPG_Plus.yhtm b/src/nhttpd/web/Y_EPG_Plus.yhtm new file mode 100644 index 000000000..1d673fb55 --- /dev/null +++ b/src/nhttpd/web/Y_EPG_Plus.yhtm @@ -0,0 +1,211 @@ +{=include-block:Y_Blocks.txt;head_no_charset=} + + + + + +{=var-set:wait_text=get EPG.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Live_Timer#EPG_Plus=}{=var-set:menu=EPG Plus=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + +
+ +
 
+
+ Details + + +
 
+
 
+
 
+ + + +
+ + + + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Ext_Menue.yhtm b/src/nhttpd/web/Y_Ext_Menue.yhtm new file mode 100644 index 000000000..aa0c080c4 --- /dev/null +++ b/src/nhttpd/web/Y_Ext_Menue.yhtm @@ -0,0 +1,72 @@ +{=var-set:extention={=if-file-exists:/var/tuxbox/config/extentions.txt~/var/tuxbox/config/extentions.txt~{=if-file-exists:/var/httpd/extentions.txt~/var/httpd/extentions.txt~/share/tuxbox/neutrino/httpd-y/extentions.txt=}=}=} +{=var-set:management={=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip;{=func:get_request_data client_addr=}=}~1~=}{=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip2=}~1~=}=} +{=include-block:Y_Blocks.txt;head=} + + + + +
+

Extentions

+
+
Normal
+
+
    +
      +
+
Management
+
+
    +
+
+
Admin
+
+ +
+
+
+ + + diff --git a/src/nhttpd/web/Y_Ext_Settings.yhtm b/src/nhttpd/web/Y_Ext_Settings.yhtm new file mode 100644 index 000000000..ca6f62ca7 --- /dev/null +++ b/src/nhttpd/web/Y_Ext_Settings.yhtm @@ -0,0 +1,37 @@ +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Save.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Extentions#Settings=}{=var-set:menu=Extentions Settings=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + +
 
+
+ + + +
+
+
+ + +{=include-block:Y_Blocks.txt;management_check_bottom=} + diff --git a/src/nhttpd/web/Y_Ext_Update.yhtm b/src/nhttpd/web/Y_Ext_Update.yhtm new file mode 100644 index 000000000..1832d3a21 --- /dev/null +++ b/src/nhttpd/web/Y_Ext_Update.yhtm @@ -0,0 +1,236 @@ +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Values are updated.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Extentions#Update=}{=var-set:menu=Extentions Updater/Installer=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ +
+ update Preview List + + + + + + + + + + + +
 SiteExtentionTagyour VersionUpdate Version
+   +
+
New extention settings (preview)
+
+ + + + +
+
+ + +
+
+
+ Log
+ + + + + + + + + +
 AktionStatus
+
+
+
+
+ + +{=include-block:Y_Blocks.txt;management_check_bottom=} + diff --git a/src/nhttpd/web/Y_Ext_Update_refresh.yhtm b/src/nhttpd/web/Y_Ext_Update_refresh.yhtm new file mode 100644 index 000000000..bd71d09f1 --- /dev/null +++ b/src/nhttpd/web/Y_Ext_Update_refresh.yhtm @@ -0,0 +1,23 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Values are updated.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Extentions#Update=}{=var-set:menu=Extentions Settings saved=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ Settings stored. Menu is updated. +
+
+ + + diff --git a/src/nhttpd/web/Y_Info_Help.yhtm b/src/nhttpd/web/Y_Info_Help.yhtm new file mode 100644 index 000000000..fc3462ca6 --- /dev/null +++ b/src/nhttpd/web/Y_Info_Help.yhtm @@ -0,0 +1,18 @@ +{=var-set:cancache=yPyes=} +{=include-block:Y_Blocks.txt;headCache=} + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Info#Hilfe=}{=var-set:menu=Help=}{=include-block:Y_Blocks.txt;work_menu=}
+ +
+ + diff --git a/src/nhttpd/web/Y_Info_Menue.yhtm b/src/nhttpd/web/Y_Info_Menue.yhtm new file mode 100644 index 000000000..f16744315 --- /dev/null +++ b/src/nhttpd/web/Y_Info_Menue.yhtm @@ -0,0 +1,25 @@ +{=var-set:cancache=yPConf=} +{=include-block:Y_Blocks.txt;head=} + +{=var-set:management={=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip;{=func:get_request_data client_addr=}=}~1~=}{=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip2=}~1~=}=} + +
+

Info

+
+
+ +
+ +
+
+ + + diff --git a/src/nhttpd/web/Y_Info_Updates.yhtm b/src/nhttpd/web/Y_Info_Updates.yhtm new file mode 100644 index 000000000..be149bfc4 --- /dev/null +++ b/src/nhttpd/web/Y_Info_Updates.yhtm @@ -0,0 +1,47 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Info#Auf_Updates_pr.C3.BCfen=}{=var-set:menu=Auf Updates prüfen=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ + + + + + +
+ Deine Version +

+ {=ini-get:Y_Version.txt;version=}
+ {=ini-get:Y_Version.txt;date=}
+ {=ini-get:Y_Version.txt;type=}

+ {=ini-get:Y_Version.txt;info=}
+

+
+ Neue Version +

+ {=ini-get:/tmp/version.txt;version=}
+ {=ini-get:/tmp/version.txt;date=}
+ {=ini-get:/tmp/version.txt;type=}

+ {=ini-get:/tmp/version.txt;info=}
+ {=if-empty:{=ini-get:/tmp/version.txt;url=}~~ + Download
+ =} +

+
+
+
+ + diff --git a/src/nhttpd/web/Y_Live.yhtm b/src/nhttpd/web/Y_Live.yhtm new file mode 100644 index 000000000..c3a5bfffb --- /dev/null +++ b/src/nhttpd/web/Y_Live.yhtm @@ -0,0 +1,471 @@ +{=var-set:must_management={=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip=}~1~=}{=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip2=}~1~=}=} +{=include-block:Y_Blocks.txt;head_no_charset=} + + + + + + +{=var-set:wait_text=Streaming-Informationen
werden ermittelt.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ + + +
+
+ getting bouquets ...
+
+
+ {=if-equal:{=typ=}~popup~ + {=if-equal:{=mode=}~tv~ + + ~ =}=} +
+
+ getting channels ...
+
+
+ + +
+
+
+ +
+
+
+
+ + + + + + {=if-equal:{=mode=}~tv~ + + =} + + + {=if-equal:{=mode=}~tv~ + + + + =} + {=if-equal:{=typ=}~popup~~ + {=if-equal:{=typ=}~transcode~~ + + =} + + =} + + + +
+
+ + + + diff --git a/src/nhttpd/web/Y_LiveViewFull.yhtm b/src/nhttpd/web/Y_LiveViewFull.yhtm new file mode 100644 index 000000000..d678ef65e --- /dev/null +++ b/src/nhttpd/web/Y_LiveViewFull.yhtm @@ -0,0 +1,45 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Live_Timer#LiveView=}{=var-set:menu={=typ=}=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ + + + +
+ + + +
+
+
+ + + + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Live_DoubleView.yhtm b/src/nhttpd/web/Y_Live_DoubleView.yhtm new file mode 100644 index 000000000..4fa1e2d68 --- /dev/null +++ b/src/nhttpd/web/Y_Live_DoubleView.yhtm @@ -0,0 +1,19 @@ +{=include-block:Y_Blocks.txt;head=} + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Live_Timer#Double_View=}{=var-set:menu=Live - DoubleView=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ + {=if-empty:{=ini-get:/var/tuxbox/config/Y-Web.conf;slavebox=}~
No IP for the Slave Box supplied!
Einstellen unter Settings->yWeb.
~ + + =} +
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Live_EPG.yhtm b/src/nhttpd/web/Y_Live_EPG.yhtm new file mode 100644 index 000000000..4163b183d --- /dev/null +++ b/src/nhttpd/web/Y_Live_EPG.yhtm @@ -0,0 +1,122 @@ +{=include-block:Y_Blocks.txt;head=} + + + +{=var-set:wait_text=EPG is loaded.=}{=include-block:Y_Blocks.txt;snip_show_wait=} + + + + + + + + + + + +
 FromtoBroadcasting
+
+ + + + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Live_EPG_Info.yhtm b/src/nhttpd/web/Y_Live_EPG_Info.yhtm new file mode 100644 index 000000000..2b96573d2 --- /dev/null +++ b/src/nhttpd/web/Y_Live_EPG_Info.yhtm @@ -0,0 +1,22 @@ +{=include-block:Y_Blocks.txt;head=} + + + +Back + +
+
 
+
 
+
For details: move the mouse on the corresponding program.
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Live_Menue.yhtm b/src/nhttpd/web/Y_Live_Menue.yhtm new file mode 100644 index 000000000..1988372ff --- /dev/null +++ b/src/nhttpd/web/Y_Live_Menue.yhtm @@ -0,0 +1,85 @@ +{=include-block:Y_Blocks.txt;head=} + + + +{=var-set:management={=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip;{=func:get_request_data client_addr=}=}~1~=}{=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip2=}~1~=}=} + +
+

Live/Timer

+
+
Live
+
+ +
+
Timer
+
+ +
+
+
+ + + diff --git a/src/nhttpd/web/Y_Live_Msg.yhtm b/src/nhttpd/web/Y_Live_Msg.yhtm new file mode 100644 index 000000000..74a2f6d5b --- /dev/null +++ b/src/nhttpd/web/Y_Live_Msg.yhtm @@ -0,0 +1,14 @@ +{=include-block:Y_Blocks.txt;head=} + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Live_Timer#LiveView=}{=var-set:menu=LiveView PopUp=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ Under Live-View do not zap channels direct by the web or by the dbox' RC.
+ unlock +
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Live_Record.yhtm b/src/nhttpd/web/Y_Live_Record.yhtm new file mode 100644 index 000000000..8a59bb5ef --- /dev/null +++ b/src/nhttpd/web/Y_Live_Record.yhtm @@ -0,0 +1,325 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + {=if-equal:{=mode=}~tv~ + + + + + + + + + + + + + + + + + + + + + + + =} + + + + + + + + + + + + + + + + + + + + + + + +
Record Mode
 Filename:
  + Display on  + Transcoding on +
  +
+ +

Record Transcode
 Profile: + +   

Video
 
 Breite:Höhe:
 Codec: + + Bitrate: + +
 Scale: + +   
Audio 
 Codec: + + Bitrate: + +
 Channels: + +   
Mux 
 Mux: + +   
+
+ + + diff --git a/src/nhttpd/web/Y_Live_Transcode.yhtm b/src/nhttpd/web/Y_Live_Transcode.yhtm new file mode 100644 index 000000000..bb2ecdf4c --- /dev/null +++ b/src/nhttpd/web/Y_Live_Transcode.yhtm @@ -0,0 +1,174 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Transcode-Broadcast

Video
 
 Width:Height:
 Codec: + + Bitrate: + +
 Scale: + +   

Audio
 
 Codec: + + Bitrate: + +
 Channels: + +   

Access
 
 Type: + + Mux: + +
 IP:Port: + +
  +
+ Display on +   +
+
+ + diff --git a/src/nhttpd/web/Y_Main.css b/src/nhttpd/web/Y_Main.css new file mode 100644 index 000000000..43054a4b4 --- /dev/null +++ b/src/nhttpd/web/Y_Main.css @@ -0,0 +1,678 @@ +body +{ + font-family: Arial, Tahoma, Verdana, Geneva, Helvetica, sans-serif; + background-color: White; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; + margin-bottom: 0px; + padding:0; + font-size:10pt; + color: #555555; +} + +img {border:0;} +button {font-family:Arial,Sans-Serif; color:#555555;} +input {font-family:Arial,Sans-Serif; color:#555555;} +select {font-family:Arial,Sans-Serif; color:#555555;} +form {margin: 0; padding: 0;} + +* html .boxhead h2 {height: 1%;} /* For IE 5 PC */ + +a { + color: #555555; + font-size:10pt; + text-decoration:none; +} + +td { + color: #555555; + font-size:10pt; +} + +tr { + color: #555555; + font-size:10pt; +} + +/* primary Navigation */ +.y_menu_prim_box { + margin: 0; + width: 100%; + background: url(/images/body-trans-r.gif) no-repeat bottom right; + font-size: 100%; +} +.y_menu_prim_box_head { + background: url(/images/head-trans-r.gif) no-repeat top right; + margin: 0; + padding: 0; + text-align: center; +} +.y_menu_prim_box_head h2 { + background: url(/images/head-trans-l.gif) no-repeat top left; + margin: 0; + padding: 5px 0px 5px; + color: white; + font-size: 0; + line-height: 0.5em; +} +.y_menu_prim_box_body { + background: url(/images/body-trans-l.gif) no-repeat bottom left; + margin: 0; + padding-bottom: 8px; + padding-left: 20px; + padding-right: 20px; +} +.y_menu_item +{ + margin: 0; + display: block; + background-repeat: no-repeat; +} +.y_menu_prim +{ + background-color: transparent; + padding: 0em 0em 0em 0em; + white-space: nowrap; + list-style: none; + margin: 0; + height: auto; + line-height: normal; +} +.y_menu_prim li +{ + display: inline; +} +.y_menu_prim_item +{ + margin: 0; + background-repeat: no-repeat; + background-position: 0 1px; + text-align:center; + font-weight: bold; + font-size: 12pt; + text-decoration: none; + height: auto; + padding: 0em 0.5em; +} +.y_menu_prim li a { +} +.y_menu_prim li.selected a +{ + background-color: #dee7ec; + border: 1px solid #6D96A9; + color: #555555; +} +.y_menu_prim li a:hover +{ + color: #FF6600; +} + +/* secondary Navigation */ +.y_menu_sec_box { + margin: 0; + width: 100%; + background: url(/images/body-trans-r.gif) no-repeat bottom right; + font-size: 100%; +} +.y_menu_sec_box_head { + background: url(/images/head-orange-r.gif) no-repeat top right; + margin: 0; + padding: 0; +} +.y_menu_sec_box_head h2 { + background: url(/images/head-orange-l.gif) no-repeat top left; + + margin: 0; + padding: 12px 30px 3px 30px; + color: white; + font-weight: bold; + font-size: 1.2em; + line-height: 1.5em; + text-align: left; +} +.y_menu_sec_box_body { + background: url(/images/body-trans-l.gif) no-repeat bottom left; + margin: 0; + padding-top: 5px; + padding-left: 6px; + padding-bottom: 20px; + padding-right: 6px; + +} +.y_menu_sec { + display: block; + background-repeat: no-repeat; + margin: 0px; + +} +.y_menu_sec ul { + padding: 0em 0em 0em 0em; + list-style: none; + margin: 0px; +} + +.y_menu_sec li { + text-align: left; + margin-bottom: 1px; + padding-left: 20px; + color: #555555 +} +.y_menu_sec li.disabled +{ + height: auto; + margin-bottom: 0.1em; + color: #808080; + text-decoration:line-through; +} +.y_menu_sec li a +{ + text-decoration: none; + font-size: 12px; +} +.y_menu_sec li.plain a +{ + color: #555555 +} +.y_menu_sec li.disabled a +{ +} +.y_menu_sec li a:hover +{ + color: #FF6600; +} +.y_menu_sec_section { + margin: 10px 0px 0px 0px; + padding: 5px 2px 5px 10px; + background-color: #FFCC99; + font-size: 10pt; + font-weight: bold; +} + +/*work*/ +.work_box { + margin: 0; + background: url(/images/body-trans-r.gif) no-repeat bottom right; + font-size: 100.01%; +} +.work_box_head { + background: url(/images/head-blue-r.gif) no-repeat top right; + margin: 0; + padding: 0; + text-align: center; +} +.work_box_head h2 { + background: url(/images/head-blue-l.gif) no-repeat top left; + margin: 0; + padding: 12px 30px 3px 30px; + color: white; + font-weight: bold; + font-size: 1.2em; + line-height: 1.5em; + text-align: left; +} +.work_box_head_h2 { + background: url(/images/head-blue-l.gif) no-repeat top left; + margin: 0; + padding: 12px 30px 3px 30px; + color: white; + font-weight: bold; + font-size: 1.2em; + line-height: 1.5em; + text-align: left; +} +.work_box_body { + background: url(/images/body-trans-l.gif) no-repeat bottom left; + margin: 0; + padding: 5px 30px 10px 30px; +} +.work_box_help { + float:right; + width:3em; + text-align:right; + font-size: 100.01%; +} +.work_box_help a { + float:right; + width:3em; + color: white; + font-weight: bold; + font-size: 1.2em; + text-align:right; +} +.y_menu +{ + font-size: 10pt; + text-align: center; + border: 1px solid #6D96A9; + border-collapse: collapse; + background: #F0FAFF; + border-spacing: 1px; + height: auto; +} +.y_menu a:hover +{ + text-decoration:underline; + font-weight:bold; +} +.y_menu_logo +{ + background-image: url(images/tuxbox3.gif); + background-position: center; + background-repeat: no-repeat; +} +.y_audio_bar +{ + background: #6D96A9; +} +.y_head +{ + font-weight: bold; + color: #555555; + font-size: 14pt; + clear:both; +} +.y_work_box +{ + border-spacing: 1px; + padding-left: 20px; + padding-right: 20px; + padding-top: 10px; + padding-bottom: 10px; + float:left; + width: auto; + color: #555555; + display:block; +} +.y_work_table +{ + border: 1px dashed #2188e0; + border-collapse: collapse; + background: white; + color: #555555; + margin:0; + padding:0; +} +.y_live_box +{ + border-top: 1px solid #6D96A9; + font-size: 8pt; + +} +/*wait box*/ +.y_wait_box { + margin: 0; + background: url(/images/body-trans-r.gif) no-repeat bottom right; + font-size: 100%; + position : absolute; + left : 100px; + top : 100px; + visibility : hidden; + z-index : 500; +} +.y_wait_box_visible { + margin: 0; + background: url(/images/body-trans-r.gif) no-repeat bottom right; + font-size: 100%; + position : absolute; + left : 100px; + top : 100px; + visibility : visible; + z-index : 500; +} +.y_wait_box_head { + background: url(/images/head-orange-r.gif) no-repeat top right; + margin: 0; + padding: 0; +} +.y_wait_box_head h2 { + background: url(/images/head-orange-l.gif) no-repeat top left; + + margin: 0; + padding: 12px 30px 3px 30px; + color: white; + font-weight: bold; + font-size: 1.2em; + line-height: 1.5em; + text-align: center; +} +.y_wait_box_body { + background: url(/images/body-trans-l.gif) no-repeat bottom left; + margin: 0; + padding-top: 5px; + padding-left: 16px; + padding-bottom: 20px; + padding-right: 16px; + +} +.y_wait_box_main { + color: #666666; + font-weight: bold; + text-align: center; +} +/**/ +.y_live_table +{ + color: #555555; + padding: 0; + margin: 0; + border: 0; +} +.y_live_button +{ +/* font-size: 8pt; + height: 22px;*/ + padding: 0; + color: #555555; + margin:0; + +} +.y_live_bouquets +{ + font-size: 8pt; + height: 20px; + width: 300px; + color: #555555; +} +.y_live_channels +{ + font-size: 8pt; + height: 20px; + width: 300px; + color: #555555; +} +.y_live_audio_pids +{ + font-size: 8pt; + height: 20px; + width: 70px; + color: #555555; +} + +.y_form_table +{ + font-size: 10pt; + border: 0px; + border-spacing: 0px; + padding: 0; + margin:0; +} + +.y_invisible_table +{ + border: 0px; + border-spacing: 0px; + padding: 0; +} +.y_topline +{ + border-top: 1px solid #2188e0; +} +.y_form_header +{ + font-size : 12pt; + font-weight:bold; + border-bottom : 1px solid #6cadfd; + color : #0066cc; + margin:0; +} +.y_form_section +{ + font-size : 10pt; + font-weight:bold; + border-bottom : 1px solid #aaaaaa; + color : #555555; +} +.y_text_boxcontrol_button +{ + padding : 1px; + border : #FF8e42 solid 1px; +} +.y_text_boxcontrol_button a:hover +{ + background:#FF8e42; +} +.y_text_boxcontrol_table { + width:114px; + height: 22px; + background : url('/images/audiobar.gif') no-repeat 1px 0px; + padding : 1px; + border : #FF8e42 solid 1px; +} +.y_epg_info { + border: 1px solid #CCCCCC; + display:block; +} +.y_epg_info #description { + font-weight:bold; +} +.y_epg_info #info2 { + font-size:8pt; +} +.channel_logos +{ + width: 40px; + height: 21px; +} +.ep_bouquet { + margin-bottom: 2px; + position:relative; +} +.ep_bouquet_name { + border : #BBBBBB solid 1px; + width : 100px; + height: 1.3em; + overflow:hidden; + padding-left: 1px; + padding-right: 1px; +} +.ep_bouquet_item { + border : #BBBBBB solid 1px; + overflow:hidden; + height: 1.3em; + padding-left: 1px; + padding-right: 1px; +} +.ep_time_bar { + width:100%; + margin-bottom: 2px; + position:relative; +} +.ep_time_bar_item { + border : #999999 solid 1px; + height: 1.3em; + padding-left: 1px; + padding-right: 1px; + overflow:hidden; +} +.ep_info_desc { + font-weight:bold; + font-size:10pt; +} +.ep_info_info1 { + font-size:8pt; +} +.ep_info_info2 { + font-size:10pt; +} +#epg_info { + border : #999999 solid 1px; + visibility:hidden; +} +#epg_plus { + width:auto; + overflow:auto; +} +#epg_time { + font-size: 8pt; + height: 20px; +} +/* bouquet*/ +.bouquetlist +{ + border-collapse: collapse; + color: #436976; + padding: 3px; +} +tr.bouquetlist +{ +} +/*channels*/ +.bouquetitemlist +{ + border-collapse: collapse; + padding: 0px; + margin: 0px; + width: 100%; +} +.a +{ + background-color: #F0FAFF; + font-family:Arial,Sans-Serif; + font-size:11pt; + border-spacing: 0px; + padding: 0px; + padding-left: 10px; + padding-right: 20px; + margin:0px; +} +.aepg +{ + background-color: #F0FAFF; + font-weight:normal; + font-size:10pt; + padding-left: 10px; +} +.b +{ + background-color: white; + font-size:11pt; + border-spacing: 0px; + padding: 0px; + padding-left: 10px; + padding-right: 20px; + margin:0px; +} +.bepg +{ + background-color: white; + font-weight:normal; + font-size:10pt; + padding-left: 10px; +} +a:hover.clist +{ + font-size:10pt; + text-decoration:underline; +} +a:hover.clistsmall +{ + font-size:10pt; + text-decoration:underline; +} +.c +{ + background-color:#dee7ec; + font-weight:bold; + font-size:11pt; + padding-left: 10px; + padding-right: 20px; + margin:0px; +} +.cepg +{ + background-color:#dee7ec; + font-weight:normal; + font-size:10pt; + padding-left: 10px; +} +.cslider_table +{ + height: 10px; + border: 1px solid #436976; + width: 30px; + border-spacing: 0px; + padding: 0px; + border-collapse: collapse; +} +.cslider_used +{ + background-color: #6D96A9; + height: 10px; +} +.cslider_free +{ + background-color: #EAEBFF; + height: 10px; +} +/*EPG*/ +.epg +{ + font-weight: bold; + color: #555555; + font-size: 12pt; + clear:both; + +} +.epglist +{ + border-collapse: collapse; + border-spacing: 0px; + padding: 0px; +} +a:hover.elist +{ + font-size:10pt; + text-decoration:underline; + font-weight:bold; +} + +/*Timer*/ +.timer +{ + border-collapse: collapse; + padding: 0px; + margin: 0px; +} +a.timer +{ + text-decoration:underline; +} +.atimer +{ + background-color: #F0FAFF; + font-weight:normal; + padding-left: 5px; + padding-right: 5px; +} +.atimer td +{ + text-align: center; +} +.btimer +{ + background-color:White; + font-weight:normal; + padding-left: 5px; + padding-right: 5px; +} +.btimer td +{ + text-align: center; +} +.ctimer +{ + background-color:#dee7ec; + font-weight:normal; + padding-left: 5px; + padding-right: 5px; +} +.ctimer td +{ + text-align: center; +} +.blist +{ + white-space: nowrap; + height: 20px; +} diff --git a/src/nhttpd/web/Y_Menue.yhtm b/src/nhttpd/web/Y_Menue.yhtm new file mode 100644 index 000000000..2db143c43 --- /dev/null +++ b/src/nhttpd/web/Y_Menue.yhtm @@ -0,0 +1,110 @@ +{=var-set:cancache=true=} +{=include-block:Y_Blocks.txt;head=} + + + + +
+

 

+
+ + + + + + + + +
Tuxbox Wiki + yWeb +
+ Version {=ini-get:Y_Version.txt;version=} +
+ + +   +   + + +   + + {=ini-get:/var/tuxbox/config/Y-Web.conf;yweb_box_name=} + 00:00 +
+
+
+ + + + diff --git a/src/nhttpd/web/Y_Settings.yhtm b/src/nhttpd/web/Y_Settings.yhtm new file mode 100644 index 000000000..3f4ec1dbd --- /dev/null +++ b/src/nhttpd/web/Y_Settings.yhtm @@ -0,0 +1,17 @@ +{=var-set:cancache=yPyes=} + + + + + + + + + + <body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0" marginwidth="0" marginheight="0"> + <p>Diese Seite verwendet Frames. Frames werden von Ihrem Browser aber nicht unterst&uuml;zt.</p> + </body> + + + + diff --git a/src/nhttpd/web/Y_Settings_Backup.yhtm b/src/nhttpd/web/Y_Settings_Backup.yhtm new file mode 100644 index 000000000..9f2b61f44 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_Backup.yhtm @@ -0,0 +1,67 @@ +{=var-set:cancache=yPConf=} +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Settings=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Backup_.26_Restore=}{=var-set:menu=Backup & Restore=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ + + + + + + + + +
Backup
+ +
Restore (Warning: box will REBOOT after restore!)
+
+ tar-File:  
+ +

+
+
+ +
+
+ + + +{=include-block:Y_Blocks.txt;management_check_bottom=} diff --git a/src/nhttpd/web/Y_Settings_Live.yhtm b/src/nhttpd/web/Y_Settings_Live.yhtm new file mode 100644 index 000000000..df51355f3 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_Live.yhtm @@ -0,0 +1,69 @@ +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Save.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+ + + + + + + + + + + + + +

VLC Settings (IE & Mozilla >= 0.8.6.1)
Deinterlace + Off  + On +
http caching
UDP as default + Off  + On +
+
+ + + + +
+ + + + +{=include-block:Y_Blocks.txt;management_check_bottom=} + diff --git a/src/nhttpd/web/Y_Settings_Menue.yhtm b/src/nhttpd/web/Y_Settings_Menue.yhtm new file mode 100644 index 000000000..68f99c2d6 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_Menue.yhtm @@ -0,0 +1,71 @@ +{=var-set:cancache=yPConf=} +{=include-block:Y_Blocks.txt;head=} + + +{=var-set:management={=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip;{=func:get_request_data client_addr=}=}~1~=}{=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip2=}~1~=}=} +
+

Settings

+
+
General
+
+ +
+
Neutrino
+
+ +
+
Plugins
+
+
    + {=if-empty:{=var-get:management=}~ +
  • VNC
  • + ~ +
  • VNC
  • + =} +
+
+
+
+ + + diff --git a/src/nhttpd/web/Y_Settings_Skin.yhtm b/src/nhttpd/web/Y_Settings_Skin.yhtm new file mode 100644 index 000000000..deeed572b --- /dev/null +++ b/src/nhttpd/web/Y_Settings_Skin.yhtm @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Skin {=var-set:help_url=Neutrino:yWeb:Settings#Skins=}{=include-block:Y_Blocks.txt;wiki_help=}
+
+
+ + + + + + + +
Skin 
+
+ +
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Settings_Timer.yhtm b/src/nhttpd/web/Y_Settings_Timer.yhtm new file mode 100644 index 000000000..d0394d476 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_Timer.yhtm @@ -0,0 +1,60 @@ +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Save.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Timer_Settings=}{=var-set:menu=Timer Settings=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
tvinfo.de
Username
Passwort

klack.de
(& will be converted to ";" on save)
personal RSS TV-Planer URL

Sender name
 
+
+ + + +
+
+
+ + +{=include-block:Y_Blocks.txt;management_check_bottom=} + diff --git a/src/nhttpd/web/Y_Settings_VNC.yhtm b/src/nhttpd/web/Y_Settings_VNC.yhtm new file mode 100644 index 000000000..ba0cf69ff --- /dev/null +++ b/src/nhttpd/web/Y_Settings_VNC.yhtm @@ -0,0 +1,58 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Save.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#VNC=}{=var-set:menu=VNC=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + +
Server
Port
Passwort
Scaling + +
+
+ + + +
+
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Settings_automount.yhtm b/src/nhttpd/web/Y_Settings_automount.yhtm new file mode 100644 index 000000000..f19396b13 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_automount.yhtm @@ -0,0 +1,182 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Save.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+
{=var-set:help_url=Neutrino:yWeb:Tools#AutoMount=}{=var-set:menu=AutoMount=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mountname
Typ + NFS  + CIFS  + +
IP
Directory
Option
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Settings_automount_liste.yhtm b/src/nhttpd/web/Y_Settings_automount_liste.yhtm new file mode 100644 index 000000000..92c860bf0 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_automount_liste.yhtm @@ -0,0 +1,55 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +{=include-block:Y_Blocks.txt;snip_wait=} +
+
+
{=var-set:help_url=Neutrino:yWeb:Tools#AutoMount=}{=var-set:menu=AutoMount=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+
+ {=script:Y_Tools automount_list {=if-file-exists:/var/etc/auto.net~/var/etc/auto.net~/etc/auto.net=}=} + + + + + + +
+
+
+{=include-block:Y_neutrino_Blocks.txt;neutrino_form_helpbox=} + + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Settings_mount.yhtm b/src/nhttpd/web/Y_Settings_mount.yhtm new file mode 100644 index 000000000..4504d9b73 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_mount.yhtm @@ -0,0 +1,87 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Save.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+
{=var-set:help_url=Neutrino:yWeb:Tools#Mounts=}{=var-set:menu=Mount {=R1=}=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Typ + NFS  + CIFS  + FTPFS +
IP
Directory
Local Directory
MAC
Option 1
Option 2
Automount + Off  + On +
Username
Passwort
+
+ + + + +
+
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Settings_mount_liste.yhtm b/src/nhttpd/web/Y_Settings_mount_liste.yhtm new file mode 100644 index 000000000..907fe9664 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_mount_liste.yhtm @@ -0,0 +1,45 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +{=include-block:Y_Blocks.txt;snip_wait=} +
+
+
{=var-set:help_url=Neutrino:yWeb:Tools#Mounts=}{=var-set:menu=Mount=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+
+ {=func:mount-get-list=} + + + + + +
+
+
+{=include-block:Y_neutrino_Blocks.txt;neutrino_form_helpbox=} + + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Settings_neutrino_forms.yhtm b/src/nhttpd/web/Y_Settings_neutrino_forms.yhtm new file mode 100644 index 000000000..2987db99d --- /dev/null +++ b/src/nhttpd/web/Y_Settings_neutrino_forms.yhtm @@ -0,0 +1,2 @@ +{=var-set:neutrino={=form=}=} +{=include-block:Y_neutrino_Blocks.txt;neutrino_form=} diff --git a/src/nhttpd/web/Y_Settings_nhttpd.yhtm b/src/nhttpd/web/Y_Settings_nhttpd.yhtm new file mode 100644 index 000000000..b8b60d0e8 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_nhttpd.yhtm @@ -0,0 +1,116 @@ +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Save.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#WebServer=}{=var-set:menu=WebServer (nhttpd)=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Authentification
User
Passwort
Client ohne Authentification
Authentification + OFF  + ON +
General
Port +
Changed port will only be valid after a restart. +
Hosted Web (Mount)
Logos & Extras
Directory ("web"=nur URL)
URL
Server
IPs Not keep-alive
(like JtG, comma seperated)
+
CacheCache info 
Server ConfigurationServer Config
+
+ + + +
+
+
+ + +{=include-block:Y_Blocks.txt;management_check_bottom=} diff --git a/src/nhttpd/web/Y_Settings_ucodes.yhtm b/src/nhttpd/web/Y_Settings_ucodes.yhtm new file mode 100644 index 000000000..aa7ec6ba9 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_ucodes.yhtm @@ -0,0 +1,61 @@ +{=include-block:Y_Blocks.txt;head=} + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#ucodes=}{=var-set:menu=Ucodes=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ + + + + + + + + +
Upload
+
+

+ camalpha.bin
+ avia500.ux
+ avia600.ux
+ ucode.bin
+ +   + +

+
+
Download
+ +
+
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Settings_umount_liste.yhtm b/src/nhttpd/web/Y_Settings_umount_liste.yhtm new file mode 100644 index 000000000..993fb1970 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_umount_liste.yhtm @@ -0,0 +1,38 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +{=include-block:Y_Blocks.txt;snip_wait=} +
+
+
{=var-set:help_url=Neutrino:yWeb:Tools#Mounts=}{=var-set:menu=UnMount=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ {=func:umount_get_list=} + + + + +
+
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Settings_wol.yhtm b/src/nhttpd/web/Y_Settings_wol.yhtm new file mode 100644 index 000000000..783b152d7 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_wol.yhtm @@ -0,0 +1,53 @@ +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +
+
+
{=var-set:help_url=Neutrino:yWeb:Tools#Wake_on_LAN=}{=var-set:menu=Wake on LAN=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + +
Wake on Lan MAC 1 ({=ini-get:/var/tuxbox/config/Y-Web.conf;wol_mac_1=})
Wake on Lan MAC 2 ({=ini-get:/var/tuxbox/config/Y-Web.conf;wol_mac_2=})
Wake on Lan MAC 3 ({=ini-get:/var/tuxbox/config/Y-Web.conf;wol_mac_3=})
+
+ +
+
+ + + +{=include-block:Y_Blocks.txt;management_check_bottom=} diff --git a/src/nhttpd/web/Y_Settings_yWeb.yhtm b/src/nhttpd/web/Y_Settings_yWeb.yhtm new file mode 100644 index 000000000..cd1412b32 --- /dev/null +++ b/src/nhttpd/web/Y_Settings_yWeb.yhtm @@ -0,0 +1,78 @@ +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Values are saved (Save).=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#yWeb=}{=var-set:menu=yWeb=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Slave Box IP (2. dbox)
Management IP 1
Management IP 2
Wake on Lan MAC 1
Wake on Lan MAC 2
Wake on Lan MAC 3
VLC Recording path
Box-name
Box-name/colour
+
+ + + +
+
+
+ + + +{=include-block:Y_Blocks.txt;management_check_bottom=} + diff --git a/src/nhttpd/web/Y_Settings_zapit.yhtm b/src/nhttpd/web/Y_Settings_zapit.yhtm new file mode 100644 index 000000000..050776c2e --- /dev/null +++ b/src/nhttpd/web/Y_Settings_zapit.yhtm @@ -0,0 +1,56 @@ +{=include-block:Y_Blocks.txt;head=} + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#zapit=}{=var-set:menu=zapit=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ + + + + + + + + +
Upload
+
+

+ bouquets.xml
+ services.xml
+ ubouquets.xml
+ +   + +

+
+
Download
+ +
+
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_StreamInfo.yhtm b/src/nhttpd/web/Y_StreamInfo.yhtm new file mode 100644 index 000000000..eebca22e1 --- /dev/null +++ b/src/nhttpd/web/Y_StreamInfo.yhtm @@ -0,0 +1,73 @@ +{=include-block:Y_Blocks.txt;head_no_charset=} + + +
+{=func:get_current_stream_info=} +
Streaminfo ({=ServiceName=})
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Resolution: {=VideoFormat=}
Relation: 
{=AspectRatio=}
Bitrate: 
{=BitRate=} bit/sec
Framerate: 
{=FPS=} fps
Audiotype: 
{=AudioType=}
onid: 
{=onid=}
sid: 
{=sid=}
tsid: 
{=tsid=}
frequency: 
{=tsfrequency=} ({=polarisation=})
vpid: 
{=vpid=}
apid: 
{=apid=}
vtxtpid: 
{=vtxtpid=}
+ +
+ + diff --git a/src/nhttpd/web/Y_Timer_Edit.yhtm b/src/nhttpd/web/Y_Timer_Edit.yhtm new file mode 100644 index 000000000..dc309370e --- /dev/null +++ b/src/nhttpd/web/Y_Timer_Edit.yhtm @@ -0,0 +1,166 @@ +{=func:set_timer_form {=typ=} {=tid=}=} +{=include-block:Y_Blocks.txt;head_no_charset=} + + + + + +{=var-set:wait_text=Save.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Live#Timer=}{=var-set:menu=Timer=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{=if-empty:{=timer_recordingDir=}~~ + + + + +=} +
Timer
Type +
Times
Alarm-Date + .  + .  +  Time  +  :  +
Stop-Datum + .  + .  +  Time  +  :  +
Repeat +
Values
List: +
+
+ + + +
+
+
+ + diff --git a/src/nhttpd/web/Y_Timer_List.yhtm b/src/nhttpd/web/Y_Timer_List.yhtm new file mode 100644 index 000000000..cb0f14e75 --- /dev/null +++ b/src/nhttpd/web/Y_Timer_List.yhtm @@ -0,0 +1,55 @@ +{=include-block:Y_Blocks.txt;head_no_charset=} + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Live_Timer#Timer=}{=var-set:menu=Timer=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ + + + + + + + + + + +{=var-set:row= + + + + + + + + + +=} +{=func:get_timer_list {=var-get:row=}=} + + + + + + + +
Alarm timeStop timeRepeatRepeatsTypeDescription  
%s%s%s%s%s%s
+
+ + del Timer + + + edit Timer +
+ + Update + + + new Timer +
+
+
+ diff --git a/src/nhttpd/web/Y_Timer_Menue.yhtm b/src/nhttpd/web/Y_Timer_Menue.yhtm new file mode 100644 index 000000000..9b82c5b23 --- /dev/null +++ b/src/nhttpd/web/Y_Timer_Menue.yhtm @@ -0,0 +1,24 @@ +{=include-block:Y_Blocks.txt;head=} + +{=var-set:management={=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip;{=func:get_request_data client_addr=}=}~1~=}{=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip2=}~1~=}=} + +
+

Timer

+
+
+ +
+
+
+ + + diff --git a/src/nhttpd/web/Y_Tools_Bootlogo.yhtm b/src/nhttpd/web/Y_Tools_Bootlogo.yhtm new file mode 100644 index 000000000..9a740cdcb --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Bootlogo.yhtm @@ -0,0 +1,36 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Logo wird hochgeladen (Upload).=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Boot_Logo=}{=var-set:menu=Bootlogo / LCD=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+

+ Achtung
Das Boot-Logo muss schon im Zielformat vorliegen!

+ Boot Logo
+ Boot LCD Logo
+
+ +

+
+
+
+ + diff --git a/src/nhttpd/web/Y_Tools_Boxcontrol.yhtm b/src/nhttpd/web/Y_Tools_Boxcontrol.yhtm new file mode 100644 index 000000000..32a027d8d --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Boxcontrol.yhtm @@ -0,0 +1,77 @@ +{=var-set:cancache=yPyes=} +{=include-block:Y_Blocks.txt;head=} + + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:BoxControl#Control=}{=var-set:menu=Control=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + +
Coolstream HD1Standby Mode
+ + + + + + +
PlaybackRecording
+ + + + + + + +
Remote ControlLive Lock
+ + + + + + +
+
+
+
+
+ + + + diff --git a/src/nhttpd/web/Y_Tools_Check_Install.yhtm b/src/nhttpd/web/Y_Tools_Check_Install.yhtm new file mode 100644 index 000000000..1aba765e8 --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Check_Install.yhtm @@ -0,0 +1,148 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +
+
+
+ {=var-set:help_url=Neutrino:yWeb:Tools#Check_Install=}{=var-set:menu=Check Install=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+
+   +
+ +
+ Check Results
+ + + + + + + + + +
 AktionStatus
+
+
+
+
+ + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Tools_Cmd.yhtm b/src/nhttpd/web/Y_Tools_Cmd.yhtm new file mode 100644 index 000000000..d3cff727f --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Cmd.yhtm @@ -0,0 +1,91 @@ +{=var-set:cancache=yPConf=} +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Tools#Command_Shell=}{=var-set:menu=Command Shell=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ +
+ +
+ + + + + + + + + + + +
append output (only IE scrollen) + +
Path: 
Command: +
+
+
+
+ + + + + + + +{=include-block:Y_Blocks.txt;management_check_bottom=} diff --git a/src/nhttpd/web/Y_Tools_Flash_Menue.yhtm b/src/nhttpd/web/Y_Tools_Flash_Menue.yhtm new file mode 100644 index 000000000..dbc0ce317 --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Flash_Menue.yhtm @@ -0,0 +1,101 @@ +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Image will be generated (create image).=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+
{=var-set:help_url=Neutrino:yWeb:Tools#Image=}{=var-set:menu=Image=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ Partition
+
+ {=func:get_partition_list=} + + + + + + +
+
+
+
 
+
+

Instruction

+
+ + It is usefull to reboot the Box before flashing.
+ +
+
+
 
+ + + +{=include-block:Y_Blocks.txt;management_check_bottom=} diff --git a/src/nhttpd/web/Y_Tools_Flash_Upload.yhtm b/src/nhttpd/web/Y_Tools_Flash_Upload.yhtm new file mode 100644 index 000000000..da5b5ecbb --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Flash_Upload.yhtm @@ -0,0 +1,162 @@ +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:fcp={=if-file-exists:/sbin/fcp~true~{=if-file-exists:/var/bin/fcp~true~{=if-file-exists:/bin/fcp~true~false=}=}=}=} +{=var-set:wait_text=Image wird hochgeladen (upload image).=}{=include-block:Y_Blocks.txt;snip_wait=} + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Tools#Image=}{=var-set:menu=Image flashen=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ Partition mtd {=mtd=}
{=mtd_text=}
+ {=if-equal:{=var-get:fcp=}~true~ +
+

+
+ Demomodus  +
+ +

+
+ ~ +




fcp ist nicht installiert!

+ =} +
+
+ + + +{=include-block:Y_Blocks.txt;management_check_bottom=} diff --git a/src/nhttpd/web/Y_Tools_Info_Menue.yhtm b/src/nhttpd/web/Y_Tools_Info_Menue.yhtm new file mode 100644 index 000000000..815356ce2 --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Info_Menue.yhtm @@ -0,0 +1,47 @@ +{=var-set:cancache=yPyes=} +{=include-block:Y_Blocks.txt;head=} + + + +
+
+
{=var-set:help_url=Neutrino:yWeb#Info=}{=var-set:menu=Info=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + +
Linux
+ + + +
Coolstream HD1
+ + + + +
proc
+ + + + + + +
+
+
+
+ + + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Tools_Installer.yhtm b/src/nhttpd/web/Y_Tools_Installer.yhtm new file mode 100644 index 000000000..1069c1a1a --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Installer.yhtm @@ -0,0 +1,42 @@ +{=var-set:cancache=yPConf=} +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Tools#yInstaller=}{=var-set:menu=yInstaller=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ tar-File:  
+ +

+
+
+ +
+
+
+ + + +{=include-block:Y_Blocks.txt;management_check_bottom=} diff --git a/src/nhttpd/web/Y_Tools_Menue.yhtm b/src/nhttpd/web/Y_Tools_Menue.yhtm new file mode 100644 index 000000000..c7f15ce2d --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Menue.yhtm @@ -0,0 +1,48 @@ +{=include-block:Y_Blocks.txt;head=} + + +{=var-set:automount={=if-file-exists:/sbin/automount~true~{=if-file-exists:/var/bin/automount~true~false=}=}=} +{=var-set:management={=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip;{=func:get_request_data client_addr=}=}~1~=}{=if-equal:{=func:get_request_data client_addr=}~{=ini-get:/var/tuxbox/config/Y-Web.conf;management_ip2=}~1~=}=} + +
+

Tools

+
+
Tools
+
+
    + {=if-empty:{=var-get:management=}~ + +
  • Mounts
  • +
  • Wake on LAN
  • + ~ + {=if-empty:{=var-get:automount=}~ + + ~ + + =} +
  • Mounts
  • +
  • Wake on LAN
  • + =} +
  • Check Install
  • +
+
+
Expert
+
+ +
+
+
+ + + diff --git a/src/nhttpd/web/Y_Tools_NetStream.yhtm b/src/nhttpd/web/Y_Tools_NetStream.yhtm new file mode 100644 index 000000000..23e6ec8e2 --- /dev/null +++ b/src/nhttpd/web/Y_Tools_NetStream.yhtm @@ -0,0 +1,125 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +
+
+ {=var-set:help_url=Neutrino:yWeb:Live_Timer#NetStream=}{=var-set:menu=Net Stream=}{=include-block:Y_Blocks.txt;work_menu=}
+
+     VLC Plugin Test +
+ + + + + + + + + + + + + +
+ MRL: + + +
+ {=if-equal:{=browser=}~ie~ + + + + + + The VideoLan Client ActiveX is not installed.
+ You need VideoLan Client V0.8.2 or higher.
+ Install with Option "ActiveX". +
+
+ + + + + + + + ~ + + +
+ + + + + + + =} +
+
+
+
+ + + + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Tools_Rcsim.yhtm b/src/nhttpd/web/Y_Tools_Rcsim.yhtm new file mode 100644 index 000000000..74631b585 --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Rcsim.yhtm @@ -0,0 +1,19 @@ +{=var-set:cancache=yPyes=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=include-block:Y_Blocks.txt;remote=} + + diff --git a/src/nhttpd/web/Y_Tools_Timer_Sync.yhtm b/src/nhttpd/web/Y_Tools_Timer_Sync.yhtm new file mode 100644 index 000000000..5e7020146 --- /dev/null +++ b/src/nhttpd/web/Y_Tools_Timer_Sync.yhtm @@ -0,0 +1,385 @@ +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=get timer.=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:Live_Timer#Timer_Sync=}{=var-set:menu=Timer Sync=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ Sync Timer + + + + + + + +
+ TVInfo
+ Klack + +
+ Debugging + +
+ Recording Directory: +
Settings within Settings-Timer
+   + +
+
+
+ Timer Preview List + + + + + + + + + + +
StartTimeEndeTimeSenderProgramQuelle
+   + +
+
+
+ Log
+ + + + + + + + + +
 ActionStatus
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/nhttpd/web/Y_Tools_fbshot.yhtm b/src/nhttpd/web/Y_Tools_fbshot.yhtm new file mode 100644 index 000000000..0d7df60cc --- /dev/null +++ b/src/nhttpd/web/Y_Tools_fbshot.yhtm @@ -0,0 +1,67 @@ +{=var-set:cancache=yPInstall=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Snapshot taken=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:BoxControl#OSD_Screenshot=}{=var-set:menu=OSD Screenshot=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ + {=var-set:dboxshot={=if-file-exists:/bin/dboxshot~true~{=if-file-exists:/var/bin/dboxshot~true~false=}=}=} + {=if-equal:{=var-get:dboxshot=}~true~ + + =} + +  Filename: +
+ +
+
+ + diff --git a/src/nhttpd/web/Y_Tools_remote_osd.yhtm b/src/nhttpd/web/Y_Tools_remote_osd.yhtm new file mode 100644 index 000000000..0ace138e7 --- /dev/null +++ b/src/nhttpd/web/Y_Tools_remote_osd.yhtm @@ -0,0 +1,60 @@ +{=var-set:cancache=yPInstall=} +{=var-set:dboxshot={=if-file-exists:/bin/dboxshot~/bin/dboxshot~{=if-file-exists:/var/bin/dboxshot~/var/bin/dboxshot~/var/bin/dboxshot=}=}=} +{=include-block:Y_Blocks.txt;head=} + + + + +{=var-set:wait_text=Snapshot taken=}{=include-block:Y_Blocks.txt;snip_wait=} +
+
+ {=var-set:help_url=Neutrino:yWeb:BoxControl#Remote_OSD=}{=var-set:menu=Remote & OSD=}{=include-block:Y_Blocks.txt;work_menu=}
+
+ {=if-empty:{=var-get:dboxshot=}~~ + + =} + + + + + + +
{=include-block:Y_Blocks.txt;remote=}
+ +
+
+ + + diff --git a/src/nhttpd/web/Y_VLC.js b/src/nhttpd/web/Y_VLC.js new file mode 100644 index 000000000..4b590dba1 --- /dev/null +++ b/src/nhttpd/web/Y_VLC.js @@ -0,0 +1,246 @@ +/* VLC abstraction by yjogol@online.de + $Date: 2007/02/21 17:38:48 $ + $Revision: 1.1 $ +*/ +/*ie1=ActiveC, moz1=Mozilla<0.8.5.1, moz2>= 0.8.5.1*/ +var CyVLC = function(_id, masterid, width, height) { + this.initialize(_id, masterid, width, height); +}; +CyVLC.prototype = { + id : "vlc", + vlc : "", + plugin : "ie1", + version_string : "", + version_level1 : 0, + version_level2 : 0, + version_level3 : 0, + version_level4 : 0, + options : [], + + c_masterid : "vlc_view", + c_width : 384, + c_height: 288, + c_loop : false, + c_show_display : true, + c_auto_play : false, + + initialize : function(_id, masterid, width, height) { + this.id = _id; + this.c_masterid = masterid; + this.c_width = width; + this.c_height = height; + if(!is_ie) { + this.version_string = this._get_version(); + this._generate_sub_versions(); + this._determine_plugin_generation(); + } + this.insert_control(); + this.vlc = id(_id); + this.set_resolution(this.c_width, this.c_height); + if(is_ie) { + this.version_string = this._get_version(); + this._generate_sub_versions(); + this._determine_plugin_generation(); + } + }, + _get_version : function() { + if(is_ie) + { + var vstr = this.vlc.VersionInfo; + var words = vstr.split(" "); + return words[0]; + } + else + if(navigator.plugins) { + var plug = navigator.plugins['VLC multimedia plugin']; + if(typeof plug == 'undefined') + var plug = navigator.plugins['VLC Multimedia Plugin']; + var ex = /^.*[vV]ersion [\"]*([^ \"]*)[\"]*.*$/; + var ve = ex.exec(plug.description); + if(ve[1]) + return ve[1]; + else + return "0.0.0"; + } + else + return "0.0.0"; + }, + _generate_sub_versions : function() { + if(this.version_string == "") + return + var ex = /([^\.]*)[\.]*([^\.]*)[\.]*([^\.-]*)[\.-]*([^\.]*).*$/; + var ve = ex.exec(this.version_string); + if(ve.length >1) this.version_level1 = ve[1]; + if(ve.length >2) this.version_level2 = ve[2]; + if(ve.length >3 && ve[3] != "") this.version_level3 = ve[3]; + if(ve.length >4 && ve[4] != "") this.version_level4 = ve[4]; + }, + _determine_plugin_generation : function() { + if(is_ie) + this.plugin = "ie1"; + else + if(this.version_level1 <= "0" && this.version_level2 <= "8" && this.version_level3 <= "5") + this.plugin = "moz1"; + else + this.plugin = "moz2"; + }, + set_actual_mrl : function(mrl) { + switch(this.plugin) { + case "ie1": + this.vlc.playlistClear(); + this.vlc.addTarget(mrl, this.options, 4+8, -666); + break; + case "moz2": + this.vlc.playlist.clear(); + this.vlc.playlist.add(mrl, null, this.options); + break; + default: + this.vlc.clear_playlist(); + this.vlc.add_item(mrl); + break; + } + }, + play : function() { + switch(this.plugin) { + case "moz2": this.vlc.playlist.play();break; + default: this.vlc.play();break; + } + }, + stop : function() { + switch(this.plugin) { + case "moz2": this.vlc.playlist.stop();break; + default: this.vlc.stop();break; + } + }, + pause : function() { + switch(this.plugin) { + case "moz2": + if(this.vlc.playlist.isPlaying) + this.vlc.playlist.togglePause(); + break; + default: this.vlc.pause(); break; + } + }, + next : function() { + switch(this.plugin) { + case "moz1": this.vlc.next();break; + case "moz2": this.vlc.playlist.next();break; + default: this.vlc.playlistNext();break; + } + }, + prev : function() { + switch(this.plugin) { + case "moz1": this.vlc.playlist.previous();break; + case "moz2": this.vlc.playlist.prev();break; + default: this.vlc.playlistPrev();break; + } + }, + is_playing : function() { + switch(this.plugin) { + case "ie1": return this.vlc.Playing;break; + case "moz2": return this.vlc.playlist.isPlaying;break; + default: return this.vlc.isplaying();break; + } + }, + toggle_fullscreen : function() { + switch(this.plugin) { + case "moz2": this.vlc.video.toggleFullscreen();break; + default: this.vlc.fullscreen();break; + } + }, + set_volume : function(vol) { + switch(this.plugin) { + case "ie1": this.vlc.volume = vol;break; + case "moz2": this.vlc.audio.volume = vol;break; + default: this.vlc.set_volume(vol);break; + } + }, + get_volume : function() { + switch(this.plugin) { + case "ie1": return this.vlc.volume;break; + case "moz2": return this.vlc.audio.volume;break; + default: return this.vlc.get_volume();break; + } + }, + set_volume_delta : function(delta) { + var new_vol = this.get_volume() + delta; + new_vol = (new_vol >= 0) ? new_vol : 0; + new_vol = (new_vol <= 200) ? new_vol : 200; + this.set_volume(new_vol); + }, + toggle_mute : function() { + switch(this.plugin) { + case "ie1": this.vlc.toggleMute();reak; + case "moz2": this.vlc.audio.toggleMute();break; + default: this.vlc.mute();break; + } + }, + press_key : function(key) { + switch(this.plugin) { + case "ie1": + var keyvalue = this.vlc.getVariable(key); + this.vlc.setVariable("key-pressed", keyvalue); + break; + case "moz2": + var keyvalue = this.vlc.get_int_variable(key); + this.vlc.set_int_variable("key-pressed", keyvalue); +// alert("not implemented for this version of vlc"); + break; + default: + var keyvalue = this.vlc.get_int_variable(key); + this.vlc.set_int_variable("key-pressed", keyvalue); + break; + } + }, + snapshot : function() { + this.press_key("key-snapshot"); + }, + change_audio_channel : function() { + this.press_key("key-audio-track"); + }, + direct_record : function() { + this.press_key("key-record"); + }, + set_resolution : function (w,h) { + this.vlc.width = w; + this.vlc.height = h; + this.vlc.style.width = w; + this.vlc.style.height = h; + }, + have_options : function() { + switch(this.plugin) { + case "ie1": + case "moz2": return true;break; + default: return false;break; + } + }, + insert_control : function() + { + var vlc_control_html = ""; + if(is_ie) { + vlc_control_html = + "" + + "" + + "" + + "" + + "" + + "The VideoLan Client ActiveX is not installed.
"+ + "You need VideoLan Client V0.8.5 or higher.
" + + "Install with Option ActiveX." + + "
"; + } + else { + vlc_control_html = "" + + ""; + } + obj_update(this.c_masterid,vlc_control_html); + this.vlc = id(this.id); + } +}; diff --git a/src/nhttpd/web/Y_Version.txt b/src/nhttpd/web/Y_Version.txt new file mode 100644 index 000000000..d039aa59a --- /dev/null +++ b/src/nhttpd/web/Y_Version.txt @@ -0,0 +1,6 @@ +version=2.5.0 +date=21.02.2007 +type=Release +info=mod neutrino.dream plus + + diff --git a/src/nhttpd/web/Y_blank.htm b/src/nhttpd/web/Y_blank.htm new file mode 100644 index 000000000..c99ab7e31 --- /dev/null +++ b/src/nhttpd/web/Y_blank.htm @@ -0,0 +1,10 @@ + + + + +yWeb + + + + + diff --git a/src/nhttpd/web/Y_neutrino_Blocks.txt b/src/nhttpd/web/Y_neutrino_Blocks.txt new file mode 100644 index 000000000..083e5ca6a --- /dev/null +++ b/src/nhttpd/web/Y_neutrino_Blocks.txt @@ -0,0 +1,1230 @@ +# ------- Neutrino form +# form-data in block (var-get:neutrino) +start-block~neutrino_form + +{=include-block:Y_Blocks.txt;management_check_top=} +{=include-block:Y_Blocks.txt;head=} + + + +{=var-set:wait_text=Save.=}{=include-block:Y_Blocks.txt;snip_wait=} +{=include-block:Y_neutrino_Blocks.txt;{=var-get:neutrino=}=} +{=include-block:Y_neutrino_Blocks.txt;neutrino_form_helpbox=} + + +{=include-block:Y_Blocks.txt;management_check_bottom=} +end-block~neutrino_form + +# ------- Neutrino form help box +start-block~neutrino_form_helpbox +
+
To Synchronize with Neutrino
+
+ After changing settings via yWeb:
+ Choose on TV "Main Menu->Service->Soft restart", to accept the changes within neutrino. +

+ After changing settings within Neutrino:
+ Choose on TV "Main Menu->Settings->Save settings now", to accept these changes and reload this page. +
+
+end-block~neutrino_form_helpbox + +# ------- Neutrino form-data: record ------------------------------- +start-block~neutrino_form-data_record +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Aufnahme=}{=var-set:menu=Recording=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Recording device + +
IP
Port
Wake up + Off  + On +
MAC
Stop Playback + Off + On +
Sectionsd + Off + On +
Scart + Off + On +
Recording start time correction (sec) Reboot urgently
Recording stop time correction (sec) Reboot urgently
Standard audio stream + Off + On +
Alternative audio streams + Off + On +
AC3 audio stream + Off + On +
+
+ + + + +
+
+
+ +end-block~neutrino_form-data_record + +# ------- yWeb save Settings +start-block~neutrino_record_save_settings +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_server_ip;{=ip=}~open=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_server_port;{=port=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_server_mac;{=mac=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_server_wakeup;{=wol=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_type;{=rec_type=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_stopplayback;{=stopplayback=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_stopsectionsd;{=stopsectionsd=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_vcr_no_scart;{=vcr_no_scart=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_in_spts_mode;{=in_spts_mode=}~save=} +{=ini-set:/var/tuxbox/config/timerd.conf;EXTRA_TIME_START;{=EXTRA_TIME_START=}=} +{=ini-set:/var/tuxbox/config/timerd.conf;EXTRA_TIME_END;{=EXTRA_TIME_END=}=} +end-block~neutrino_record_save_settings + + +# ------- Neutrino form-data: movieplayer ------------------------------- +start-block~neutrino_form-data_movieplayer +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Movieplayer=}{=var-set:menu=Movieplayer=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Streaming server + Off  + On +
Streamingserver IP
Streamingserver Port
DVD Drive
Directory (VLC)
Data Rate Video
Transcode + Off  + On +
MPEG Video Codec + +
Resulotion + +
Data Rate Audio
Transcode Audio (dvd/vcd/mpg) + Off  + On +
Force AC3 with avi + Off  + On +
Start Directory
+
+ + + + +
+
+
+ +end-block~neutrino_form-data_movieplayer + +# ------- yWeb save Settings +start-block~neutrino_movieplayer_save_settings +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_type;{=streaming_type=}~open=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_server_ip;{=streaming_server_ip=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_server_port;{=streaming_server_port=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_server_cddrive;{=streaming_server_cddrive=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_server_startdir;{=streaming_server_startdir=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_videorate;{=streaming_videorate=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_force_transcode_video;{=streaming_force_transcode_video=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_transcode_video_codec;{=streaming_transcode_video_codec=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_resolution;{=streaming_resolution=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_audiorate;{=streaming_audiorate=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_transcode_audio;{=streaming_transcode_audio=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;streaming_force_avi_rawaudio;{=streaming_force_avi_rawaudio=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;network_nfs_moviedir;{=network_nfs_moviedir=}~save=} +end-block~neutrino_movieplayer_save_settings + + +# ------- Neutrino form-data: parental ------------------------------- +start-block~neutrino_form-data_parental +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Jugendschutz=}{=var-set:menu=Parental=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + +
Activate + +
Minimum Age + +
PIN
+
+ + + + +
+
+
+ +end-block~neutrino_form-data_parental + +# ------- yWeb save Settings +start-block~neutrino_parental_save_settings +{=ini-set:/var/tuxbox/config/neutrino.conf;parentallock_prompt;{=parentallock_prompt=}~open=} +{=ini-set:/var/tuxbox/config/neutrino.conf;parentallock_lockage;{=parentallock_lockage=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;parentallock_pincode;{=parentallock_pincode=}~save=} +end-block~neutrino_parental_save_settings + +# ------- Neutrino form-data: diverse ------------------------------- +start-block~neutrino_form-data_diverse +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Diverse=}{=var-set:menu=Misc=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Standard 
Standby mode + Off  + On +
Turn off completely
Infobar Satellite type + Off  + On +
Show Subchannel + +
Save Teletext + Off  + On +
Virtual zap Infobar + Off  + On +
EPG-Settings 
EPG-Cache (Days)
EPG remove after (Std.)
Max. Events
Remote Control 
Repeat delay
Start delay
Delay Shutdown + Off  + On +
Filebrowser 
Filesystem + ISO-8859-1  + UTF-8 +
Show file rights + Off  + On +
Absolute start directory + Off  + On +
+
+ + + + +
+
+
+ +end-block~neutrino_form-data_diverse + +# ------- yWeb save Settings +start-block~neutrino_diverse_save_settings +{=ini-set:/var/tuxbox/config/neutrino.conf;shutdown_real;{=shutdown_real=}~open=} +{=ini-set:/var/tuxbox/config/neutrino.conf;shutdown_count;{=shutdown_count=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;infobar_sat_display;{=infobar_sat_display=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;infobar_subchan_disp_pos;{=infobar_subchan_disp_pos=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;tuxtxt_cache;{=tuxtxt_cache=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;virtual_zap_mode;{=virtual_zap_mode=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;epg_cache_time;{=epg_cache_time=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;epg_old_events;{=epg_old_events=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;epg_max_events;{=epg_max_events=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;repeat_blocker;{=repeat_blocker=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;repeat_genericblocker;{=repeat_genericblocker=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;shutdown_real_rcdelay;{=shutdown_real_rcdelay=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;filesystem_is_utf8;{=filesystem_is_utf8=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;filebrowser_showrights;{=filebrowser_showrights=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;filebrowser_denydirectoryleave;{=filebrowser_denydirectoryleave=}~save=} +end-block~neutrino_diverse_save_settings + + +# ------- Neutrino form-data: bootoptions ------------------------------- +start-block~neutrino_form-data_bootoptions +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Bootoptionen=}{=var-set:menu=Driver- and Bootoptions=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Load SPTS-Mode Drivers + Off  + On +
Show Bootmenu + Off  + On +
Show Infos whilst booting + Off  + On +
Use HW-Sections + Off  + On +
Activate AVIA-Watchdog + Off  + On +
Activate eNX-Watchdog + Off  + On +
Use PMT Update + Off  + On +
+
+ + + + +
+
+
+ +end-block~neutrino_form-data_bootoptions + +# ------- yWeb save Settings +start-block~neutrino_bootoptions_save_settings +{=ini-set:/var/tuxbox/config/neutrino.conf;misc_spts;{=misc_spts=}=} +{=file-action:/var/etc/.neutrino;{=if-equal:{=bootmenu=}~0~add~delete=}=} +{=file-action:/var/etc/.boot_info;{=if-equal:{=bootinfo=}~1~add~delete=}=} +{=file-action:/var/etc/.hw_sections;{=if-equal:{=hwsections=}~0~add~delete=}=} +{=file-action:/var/etc/.no_watchdog;{=if-equal:{=no_watchdog=}~0~add~delete=}=} +{=file-action:/var/etc/.no_enxwatchdog;{=if-equal:{=no_enxwatchdog=}~0~add~delete=}=} +{=file-action:/var/etc/.pmt_update;{=if-equal:{=pmt_update=}~1~add~delete=}=} + +{=file-action:/var/etc/.test;add;moin\nduu=} +end-block~neutrino_bootoptions_save_settings + +# ------- Neutrino form-data: pictureviewer ------------------------------- +start-block~neutrino_form-data_pictureviewer +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Bildbetrachter=}{=var-set:menu=Pictureviewer=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Scaling + +
Slideshow display time
Start Directory
Decoding-Server IP
Decoding-Server Port
+
+ + + + +
+
+
+ + +end-block~neutrino_form-data_pictureviewer + +# ------- yWeb save Settings +start-block~neutrino_pictureviewer_save_settings +{=ini-set:/var/tuxbox/config/neutrino.conf;picviewer_scaling;{=picviewer_scaling=}~open=} +{=ini-set:/var/tuxbox/config/neutrino.conf;picviewer_slide_time;{=picviewer_slide_time=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;network_nfs_picturedir;{=network_nfs_picturedir=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;picviewer_decode_server_ip;{=picviewer_decode_server_ip=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;picviewer_decode_server_port;{=picviewer_decode_server_port=}~save=} +end-block~neutrino_pictureviewer_save_settings + +# ------- Neutrino form-data: audioplayer ------------------------------- +start-block~neutrino_form-data_audioplayer +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Audioplayer=}{=var-set:menu=Audioplayer=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Display order + +
Select actual track + Off  + On +
Titele search by Name + Off  + On +
Activate repeat-mode + Off  + On +
Show Playlist + Off  + On +
Screensaver (min, 0=off)
High Decoding-Priority + Off  + On +
Start Directory
Shoutcast Meta-Daten + Off  + On +
+
+ + + + +
+
+
+ +end-block~neutrino_form-data_audioplayer + +# ------- save Settings +start-block~neutrino_audioplayer_save_settings +{=ini-set:/var/tuxbox/config/neutrino.conf;audioplayer_display;{=audioplayer_display=}~open=} +{=ini-set:/var/tuxbox/config/neutrino.conf;audioplayer_follow;{=audioplayer_follow=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;audioplayer_select_title_by_name;{=audioplayer_select_title_by_name=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;audioplayer_repeat_on;{=audioplayer_repeat_on=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;audioplayer_show_playlist;{=audioplayer_show_playlist=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;audioplayer_screensaver;{=audioplayer_screensaver=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;audioplayer_highprio;{=audioplayer_highprio=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;network_nfs_audioplayerdir;{=network_nfs_audioplayerdir=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;audioplayer_enable_sc_metadata;{=audioplayer_enable_sc_metadata=}~save=} +end-block~neutrino_audioplayer_save_settings + +# ------- Neutrino form-data: direct_recording ------------------------------- +start-block~neutrino_form-data_direct_recording +
+
+ {=var-set:help_url=Neutrino:yWeb:Settings#Direktaufnahme=}{=var-set:menu=Direkt Recording=}{=include-block:Y_Blocks.txt;work_menu=}
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Recording Directory
Max. File size (MB)
Max. Ringbuffer
Sync write (O_SYNC) + Off  + On +
Sync write (fdatasync) + Off  + On +
Record Teletext + Off  + On +
Record PMT + Off  + On +
Directory selection on direct recording + Off  + On +
Long Filenames (with EPG-Data) + Off  + On +
Recording Filename Template
Directory permission
+
+ + + + +
+
+
+ +end-block~neutrino_form-data_direct_recording + +# ------- direct recording save Settings +start-block~neutrino_direct_recording_save_settings +{=ini-set:/var/tuxbox/config/neutrino.conf;network_nfs_recordingdir;{=network_nfs_recordingdir=}~open=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_splitsize;{=recording_splitsize=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recordingmenu.ringbuffers;{=recordingmenu_ringbuffers=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recordingmenu.use_o_sync;{=recordingmenu_use_o_sync=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recordingmenu.use_fdatasync;{=recordingmenu_use_fdatasync=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recordingmenu.stream_vtxt_pid;{=recordingmenu_stream_vtxt_pid=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recordingmenu.stream_pmt_pid;{=recordingmenu_stream_pmt_pid=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_choose_direct_rec_dir;{=recording_choose_direct_rec_dir=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_epg_for_filename;{=recording_epg_for_filename=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_filename_template_0;{=recording_filename_template_0=}~cache=} +{=ini-set:/var/tuxbox/config/neutrino.conf;recording_dir_permissions_0;{=recording_dir_permissions_0=}~save=} +end-block~neutrino_direct_recording_save_settings + diff --git a/src/nhttpd/web/channels.js b/src/nhttpd/web/channels.js new file mode 100644 index 000000000..30cfb8fde --- /dev/null +++ b/src/nhttpd/web/channels.js @@ -0,0 +1,46 @@ +function fertig() +{ + for (i=document.getElementById('channels').bchannels.length-1; i >= 0 ; i--) { + document.getElementById('channels').bchannels.options[i].selected=true; + } + document.getElementById('channels').submit(); +} + +function movechannels(source, destination) +{ + for (i=0; i < source.length; i++) { + if (source.options[i].selected==true) { + destination.options[destination.length] = new Option(source.options[i].text, source.options[i].value); + } + } + for (i=source.length-1; i >= 0 ; i--) { + if (source.options[i].selected==true) { + source.options[i] = null; + } + } +} + +function poschannel(box, direction) +{ + if (direction==0) { + for (i=1; i < box.length ; i++) { + if (box.options[i].selected==true) { + buffer = new Option(box.options[i].text, box.options[i].value); + box.options[i].selected=false; + box.options[i]= new Option(box.options[i-1].text, box.options[i-1].value); + box.options[i-1]=buffer; + box.options[i-1].selected=true; + } + } + } else { + for (i=box.length-2; i >= 0 ; i--) { + if (box.options[i].selected==true) { + buffer = new Option(box.options[i].text, box.options[i].value); + box.options[i].selected=false; + box.options[i]=new Option(box.options[i+1].text, box.options[i+1].value); + box.options[i+1]=buffer; + box.options[i+1].selected=true; + } + } + } +} diff --git a/src/nhttpd/web/channels.txt b/src/nhttpd/web/channels.txt new file mode 100644 index 000000000..f99830109 --- /dev/null +++ b/src/nhttpd/web/channels.txt @@ -0,0 +1,25 @@ +dbox;tvinfo;klack +#ARDx +Das Erste;ARD;ARD +Bayerisches FS;Bayern;Bayern +WDR Köln;WDR;WDR +hr-fernsehen;HR;HR +BR-alpha;Alpha;BR Alpha +SÜWEST Ferns. BW;SWR;SWR BW + +#Free +Pro Sieben;Pro7;Pro7 +terranova;Terra Nova;Terra Nova +Kabel 1;Kabel1;Kabel1 +RTL II;RTL2;RTL2 +RTL Television;RTL;RTL +Sat. 1;SAT1;Sat1 +9Live;9 Live;9Live + +#Kabel Deutschland +History Channel;;The History Channel +SciFi (KD);Sci Fi;SciFi +13th Street (KD);13th Street;13th Street +Wetter Fernsehen;;Wetterfernsehen +Disney Toon;;Toon Disney +Disney Toon + 1;;Toon Disney Plus diff --git a/src/nhttpd/web/extentions.txt b/src/nhttpd/web/extentions.txt new file mode 100644 index 000000000..13437862f --- /dev/null +++ b/src/nhttpd/web/extentions.txt @@ -0,0 +1 @@ +u,yjogol,yjogol update site,http://www.yjogol.de/download/Y_extentions.txt diff --git a/src/nhttpd/web/favicon.ico b/src/nhttpd/web/favicon.ico new file mode 100644 index 000000000..5e17fbdcf Binary files /dev/null and b/src/nhttpd/web/favicon.ico differ diff --git a/src/nhttpd/web/images/Makefile.am b/src/nhttpd/web/images/Makefile.am new file mode 100644 index 000000000..cea5fda76 --- /dev/null +++ b/src/nhttpd/web/images/Makefile.am @@ -0,0 +1,8 @@ +install-data-local: + install -d $(DATADIR)/neutrino/httpd-y/images + install -m 0644 *.gif $(DATADIR)/neutrino/httpd-y/images + install -m 0644 *.png $(DATADIR)/neutrino/httpd-y/images + install -m 0644 *.jpg $(DATADIR)/neutrino/httpd-y/images + +uninstall-local: + -rm -rf $(DATADIR)/neutrino/httpd-y/images diff --git a/src/nhttpd/web/images/addfolder.gif b/src/nhttpd/web/images/addfolder.gif new file mode 100755 index 000000000..b191cc40e Binary files /dev/null and b/src/nhttpd/web/images/addfolder.gif differ diff --git a/src/nhttpd/web/images/arrowdown.gif b/src/nhttpd/web/images/arrowdown.gif new file mode 100644 index 000000000..76941dab9 Binary files /dev/null and b/src/nhttpd/web/images/arrowdown.gif differ diff --git a/src/nhttpd/web/images/arrowup.gif b/src/nhttpd/web/images/arrowup.gif new file mode 100644 index 000000000..505dab69a Binary files /dev/null and b/src/nhttpd/web/images/arrowup.gif differ diff --git a/src/nhttpd/web/images/audiobar.gif b/src/nhttpd/web/images/audiobar.gif new file mode 100644 index 000000000..45974b211 Binary files /dev/null and b/src/nhttpd/web/images/audiobar.gif differ diff --git a/src/nhttpd/web/images/blank.gif b/src/nhttpd/web/images/blank.gif new file mode 100644 index 000000000..5bfd67a2d Binary files /dev/null and b/src/nhttpd/web/images/blank.gif differ diff --git a/src/nhttpd/web/images/body-trans-l.gif b/src/nhttpd/web/images/body-trans-l.gif new file mode 100644 index 000000000..5eb6479cc Binary files /dev/null and b/src/nhttpd/web/images/body-trans-l.gif differ diff --git a/src/nhttpd/web/images/body-trans-r.gif b/src/nhttpd/web/images/body-trans-r.gif new file mode 100644 index 000000000..3de6b14d4 Binary files /dev/null and b/src/nhttpd/web/images/body-trans-r.gif differ diff --git a/src/nhttpd/web/images/check_green.gif b/src/nhttpd/web/images/check_green.gif new file mode 100644 index 000000000..243b99b51 Binary files /dev/null and b/src/nhttpd/web/images/check_green.gif differ diff --git a/src/nhttpd/web/images/chmod.gif b/src/nhttpd/web/images/chmod.gif new file mode 100755 index 000000000..5710725f6 Binary files /dev/null and b/src/nhttpd/web/images/chmod.gif differ diff --git a/src/nhttpd/web/images/delete.gif b/src/nhttpd/web/images/delete.gif new file mode 100755 index 000000000..5a74564d0 Binary files /dev/null and b/src/nhttpd/web/images/delete.gif differ diff --git a/src/nhttpd/web/images/download.gif b/src/nhttpd/web/images/download.gif new file mode 100755 index 000000000..f43af17b6 Binary files /dev/null and b/src/nhttpd/web/images/download.gif differ diff --git a/src/nhttpd/web/images/elist.gif b/src/nhttpd/web/images/elist.gif new file mode 100644 index 000000000..d5281c0ee Binary files /dev/null and b/src/nhttpd/web/images/elist.gif differ diff --git a/src/nhttpd/web/images/epg.png b/src/nhttpd/web/images/epg.png new file mode 100755 index 000000000..2fbdd6920 Binary files /dev/null and b/src/nhttpd/web/images/epg.png differ diff --git a/src/nhttpd/web/images/excl_yellow.gif b/src/nhttpd/web/images/excl_yellow.gif new file mode 100644 index 000000000..e604db74e Binary files /dev/null and b/src/nhttpd/web/images/excl_yellow.gif differ diff --git a/src/nhttpd/web/images/ftype_file.gif b/src/nhttpd/web/images/ftype_file.gif new file mode 100755 index 000000000..070d57944 Binary files /dev/null and b/src/nhttpd/web/images/ftype_file.gif differ diff --git a/src/nhttpd/web/images/ftype_folder.gif b/src/nhttpd/web/images/ftype_folder.gif new file mode 100755 index 000000000..1e3e3d82d Binary files /dev/null and b/src/nhttpd/web/images/ftype_folder.gif differ diff --git a/src/nhttpd/web/images/ftype_link.gif b/src/nhttpd/web/images/ftype_link.gif new file mode 100755 index 000000000..66881b86a Binary files /dev/null and b/src/nhttpd/web/images/ftype_link.gif differ diff --git a/src/nhttpd/web/images/fullscreen.png b/src/nhttpd/web/images/fullscreen.png new file mode 100755 index 000000000..fc3c393ca Binary files /dev/null and b/src/nhttpd/web/images/fullscreen.png differ diff --git a/src/nhttpd/web/images/head-blue-l.gif b/src/nhttpd/web/images/head-blue-l.gif new file mode 100644 index 000000000..08203a4b1 Binary files /dev/null and b/src/nhttpd/web/images/head-blue-l.gif differ diff --git a/src/nhttpd/web/images/head-blue-r.gif b/src/nhttpd/web/images/head-blue-r.gif new file mode 100644 index 000000000..ab01edef7 Binary files /dev/null and b/src/nhttpd/web/images/head-blue-r.gif differ diff --git a/src/nhttpd/web/images/head-orange-l.gif b/src/nhttpd/web/images/head-orange-l.gif new file mode 100644 index 000000000..d3c19631e Binary files /dev/null and b/src/nhttpd/web/images/head-orange-l.gif differ diff --git a/src/nhttpd/web/images/head-orange-r.gif b/src/nhttpd/web/images/head-orange-r.gif new file mode 100644 index 000000000..a6b0b09e7 Binary files /dev/null and b/src/nhttpd/web/images/head-orange-r.gif differ diff --git a/src/nhttpd/web/images/head-trans-l.gif b/src/nhttpd/web/images/head-trans-l.gif new file mode 100644 index 000000000..f92828d89 Binary files /dev/null and b/src/nhttpd/web/images/head-trans-l.gif differ diff --git a/src/nhttpd/web/images/head-trans-r.gif b/src/nhttpd/web/images/head-trans-r.gif new file mode 100644 index 000000000..91da79fcd Binary files /dev/null and b/src/nhttpd/web/images/head-trans-r.gif differ diff --git a/src/nhttpd/web/images/help.gif b/src/nhttpd/web/images/help.gif new file mode 100644 index 000000000..4d1c304ba Binary files /dev/null and b/src/nhttpd/web/images/help.gif differ diff --git a/src/nhttpd/web/images/help_white.gif b/src/nhttpd/web/images/help_white.gif new file mode 100644 index 000000000..c8aa83cf1 Binary files /dev/null and b/src/nhttpd/web/images/help_white.gif differ diff --git a/src/nhttpd/web/images/hidden.gif b/src/nhttpd/web/images/hidden.gif new file mode 100644 index 000000000..0dde1842b Binary files /dev/null and b/src/nhttpd/web/images/hidden.gif differ diff --git a/src/nhttpd/web/images/home-dir.gif b/src/nhttpd/web/images/home-dir.gif new file mode 100755 index 000000000..949be9d22 Binary files /dev/null and b/src/nhttpd/web/images/home-dir.gif differ diff --git a/src/nhttpd/web/images/hourglas.gif b/src/nhttpd/web/images/hourglas.gif new file mode 100644 index 000000000..1345110a8 Binary files /dev/null and b/src/nhttpd/web/images/hourglas.gif differ diff --git a/src/nhttpd/web/images/live.gif b/src/nhttpd/web/images/live.gif new file mode 100755 index 000000000..3f0c7c72a Binary files /dev/null and b/src/nhttpd/web/images/live.gif differ diff --git a/src/nhttpd/web/images/live.png b/src/nhttpd/web/images/live.png new file mode 100755 index 000000000..1738a4f10 Binary files /dev/null and b/src/nhttpd/web/images/live.png differ diff --git a/src/nhttpd/web/images/live_popup.gif b/src/nhttpd/web/images/live_popup.gif new file mode 100755 index 000000000..c1022b2b6 Binary files /dev/null and b/src/nhttpd/web/images/live_popup.gif differ diff --git a/src/nhttpd/web/images/live_popup.png b/src/nhttpd/web/images/live_popup.png new file mode 100755 index 000000000..2baaad99e Binary files /dev/null and b/src/nhttpd/web/images/live_popup.png differ diff --git a/src/nhttpd/web/images/livelock.png b/src/nhttpd/web/images/livelock.png new file mode 100755 index 000000000..a7b566b1f Binary files /dev/null and b/src/nhttpd/web/images/livelock.png differ diff --git a/src/nhttpd/web/images/liveunlock.png b/src/nhttpd/web/images/liveunlock.png new file mode 100755 index 000000000..ecb50a93f Binary files /dev/null and b/src/nhttpd/web/images/liveunlock.png differ diff --git a/src/nhttpd/web/images/lock.gif b/src/nhttpd/web/images/lock.gif new file mode 100644 index 000000000..720e21028 Binary files /dev/null and b/src/nhttpd/web/images/lock.gif differ diff --git a/src/nhttpd/web/images/modify.png b/src/nhttpd/web/images/modify.png new file mode 100644 index 000000000..c407bb828 Binary files /dev/null and b/src/nhttpd/web/images/modify.png differ diff --git a/src/nhttpd/web/images/new.gif b/src/nhttpd/web/images/new.gif new file mode 100644 index 000000000..1d739f13e Binary files /dev/null and b/src/nhttpd/web/images/new.gif differ diff --git a/src/nhttpd/web/images/ok.gif b/src/nhttpd/web/images/ok.gif new file mode 100644 index 000000000..73a4f1ce7 Binary files /dev/null and b/src/nhttpd/web/images/ok.gif differ diff --git a/src/nhttpd/web/images/pause.png b/src/nhttpd/web/images/pause.png new file mode 100755 index 000000000..ec61099b0 Binary files /dev/null and b/src/nhttpd/web/images/pause.png differ diff --git a/src/nhttpd/web/images/play.png b/src/nhttpd/web/images/play.png new file mode 100755 index 000000000..f8c8ec683 Binary files /dev/null and b/src/nhttpd/web/images/play.png differ diff --git a/src/nhttpd/web/images/properties.gif b/src/nhttpd/web/images/properties.gif new file mode 100755 index 000000000..963ead1c9 Binary files /dev/null and b/src/nhttpd/web/images/properties.gif differ diff --git a/src/nhttpd/web/images/rc.gif b/src/nhttpd/web/images/rc.gif new file mode 100644 index 000000000..dfa2a1520 Binary files /dev/null and b/src/nhttpd/web/images/rc.gif differ diff --git a/src/nhttpd/web/images/rc_sagem.jpg b/src/nhttpd/web/images/rc_sagem.jpg new file mode 100644 index 000000000..99e40dc9c Binary files /dev/null and b/src/nhttpd/web/images/rc_sagem.jpg differ diff --git a/src/nhttpd/web/images/rcd.jpg b/src/nhttpd/web/images/rcd.jpg new file mode 100644 index 000000000..129742060 Binary files /dev/null and b/src/nhttpd/web/images/rcd.jpg differ diff --git a/src/nhttpd/web/images/record.gif b/src/nhttpd/web/images/record.gif new file mode 100644 index 000000000..8390bfd82 Binary files /dev/null and b/src/nhttpd/web/images/record.gif differ diff --git a/src/nhttpd/web/images/reload.gif b/src/nhttpd/web/images/reload.gif new file mode 100644 index 000000000..c2c00610e Binary files /dev/null and b/src/nhttpd/web/images/reload.gif differ diff --git a/src/nhttpd/web/images/remove.png b/src/nhttpd/web/images/remove.png new file mode 100644 index 000000000..2aedce084 Binary files /dev/null and b/src/nhttpd/web/images/remove.png differ diff --git a/src/nhttpd/web/images/rename.gif b/src/nhttpd/web/images/rename.gif new file mode 100755 index 000000000..0b2bcc665 Binary files /dev/null and b/src/nhttpd/web/images/rename.gif differ diff --git a/src/nhttpd/web/images/smallwait.gif b/src/nhttpd/web/images/smallwait.gif new file mode 100755 index 000000000..dba81f511 Binary files /dev/null and b/src/nhttpd/web/images/smallwait.gif differ diff --git a/src/nhttpd/web/images/snapshot.png b/src/nhttpd/web/images/snapshot.png new file mode 100755 index 000000000..f501a593a Binary files /dev/null and b/src/nhttpd/web/images/snapshot.png differ diff --git a/src/nhttpd/web/images/stop.png b/src/nhttpd/web/images/stop.png new file mode 100755 index 000000000..e6f75d232 Binary files /dev/null and b/src/nhttpd/web/images/stop.png differ diff --git a/src/nhttpd/web/images/streaminfo.png b/src/nhttpd/web/images/streaminfo.png new file mode 100644 index 000000000..7df94f66f Binary files /dev/null and b/src/nhttpd/web/images/streaminfo.png differ diff --git a/src/nhttpd/web/images/timer.gif b/src/nhttpd/web/images/timer.gif new file mode 100644 index 000000000..e632d2739 Binary files /dev/null and b/src/nhttpd/web/images/timer.gif differ diff --git a/src/nhttpd/web/images/transcode.png b/src/nhttpd/web/images/transcode.png new file mode 100755 index 000000000..dd0168ea9 Binary files /dev/null and b/src/nhttpd/web/images/transcode.png differ diff --git a/src/nhttpd/web/images/tux.gif b/src/nhttpd/web/images/tux.gif new file mode 100644 index 000000000..720c053b7 Binary files /dev/null and b/src/nhttpd/web/images/tux.gif differ diff --git a/src/nhttpd/web/images/unlock.gif b/src/nhttpd/web/images/unlock.gif new file mode 100644 index 000000000..10eb77697 Binary files /dev/null and b/src/nhttpd/web/images/unlock.gif differ diff --git a/src/nhttpd/web/images/upload.gif b/src/nhttpd/web/images/upload.gif new file mode 100755 index 000000000..f76ba7c7a Binary files /dev/null and b/src/nhttpd/web/images/upload.gif differ diff --git a/src/nhttpd/web/images/visible.gif b/src/nhttpd/web/images/visible.gif new file mode 100644 index 000000000..70c1c4b55 Binary files /dev/null and b/src/nhttpd/web/images/visible.gif differ diff --git a/src/nhttpd/web/images/vlc.gif b/src/nhttpd/web/images/vlc.gif new file mode 100755 index 000000000..2b18cb0e3 Binary files /dev/null and b/src/nhttpd/web/images/vlc.gif differ diff --git a/src/nhttpd/web/images/volumedown.png b/src/nhttpd/web/images/volumedown.png new file mode 100755 index 000000000..ab9577aa1 Binary files /dev/null and b/src/nhttpd/web/images/volumedown.png differ diff --git a/src/nhttpd/web/images/volumemute.png b/src/nhttpd/web/images/volumemute.png new file mode 100755 index 000000000..b652d2a71 Binary files /dev/null and b/src/nhttpd/web/images/volumemute.png differ diff --git a/src/nhttpd/web/images/volumeunmute.png b/src/nhttpd/web/images/volumeunmute.png new file mode 100755 index 000000000..b497ebd54 Binary files /dev/null and b/src/nhttpd/web/images/volumeunmute.png differ diff --git a/src/nhttpd/web/images/volumeup.png b/src/nhttpd/web/images/volumeup.png new file mode 100755 index 000000000..965c503c6 Binary files /dev/null and b/src/nhttpd/web/images/volumeup.png differ diff --git a/src/nhttpd/web/images/wait.gif b/src/nhttpd/web/images/wait.gif new file mode 100644 index 000000000..6bdefde94 Binary files /dev/null and b/src/nhttpd/web/images/wait.gif differ diff --git a/src/nhttpd/web/images/x_red.gif b/src/nhttpd/web/images/x_red.gif new file mode 100644 index 000000000..e5db0cf6f Binary files /dev/null and b/src/nhttpd/web/images/x_red.gif differ diff --git a/src/nhttpd/web/images/y.png b/src/nhttpd/web/images/y.png new file mode 100644 index 000000000..64d55055a Binary files /dev/null and b/src/nhttpd/web/images/y.png differ diff --git a/src/nhttpd/web/index.html b/src/nhttpd/web/index.html new file mode 100644 index 000000000..d819152c5 --- /dev/null +++ b/src/nhttpd/web/index.html @@ -0,0 +1,12 @@ + + + + +Coolstream HD1 yWeb + + + + + + + diff --git a/src/nhttpd/web/robots.txt b/src/nhttpd/web/robots.txt new file mode 100644 index 000000000..53bedca66 --- /dev/null +++ b/src/nhttpd/web/robots.txt @@ -0,0 +1,4 @@ +# robots.txt +User-agent: * +Disallow: / + diff --git a/src/nhttpd/web/scripts/Makefile.am b/src/nhttpd/web/scripts/Makefile.am new file mode 100644 index 000000000..3cfeaf2a5 --- /dev/null +++ b/src/nhttpd/web/scripts/Makefile.am @@ -0,0 +1,8 @@ +install-data-local: + install -d $(DATADIR)/neutrino/httpd-y/scripts + install -m 0755 Y_*.sh $(DATADIR)/neutrino/httpd-y/scripts + install -m 0644 _Y_*.sh $(DATADIR)/neutrino/httpd-y/scripts + install -m 0755 api.sh $(DATADIR)/neutrino/httpd-y/scripts + +uninstall-local: + -rm -rf $(DATADIR)/neutrino/httpd-y/scripts \ No newline at end of file diff --git a/src/nhttpd/web/scripts/Y_Live.sh b/src/nhttpd/web/scripts/Y_Live.sh new file mode 100755 index 000000000..1ba1dff5f --- /dev/null +++ b/src/nhttpd/web/scripts/Y_Live.sh @@ -0,0 +1,118 @@ +#!/bin/sh +# ----------------------------------------------------------- +# Live (yjogol) +# $Date: 2007/02/21 17:41:04 $ +# $Revision: 1.2 $ +# ----------------------------------------------------------- + +. ./_Y_Globals.sh +. ./_Y_Library.sh + +# ----------------------------------------------------------- +live_lock() +{ + call_webserver "control/lcd?lock=1&clear=1&rect=10,10,110,50,1,0&xpos=20&ypos=27&size=22&font=2&text=%20%20%20%20yWeb%0A%20%20LiveView&update=1" >/dev/null + call_webserver "control/rc?lock" >/dev/null + call_webserver "control/zapto?stopplayback" >/dev/null +} +# ----------------------------------------------------------- +live_unlock() +{ + call_webserver "control/lcd?lock=0" >/dev/null + call_webserver "control/rc?unlock" >/dev/null + call_webserver "control/zapto?startplayback" >/dev/null +} +# ----------------------------------------------------------- +prepare_tv() +{ + # SPTS on + call_webserver "control/system?setAViAExtPlayBack=spts" >/dev/null +} +# ----------------------------------------------------------- +prepare_radio() +{ + # SPTS off + call_webserver "control/system?setAViAExtPlayBack=pes" >/dev/null +} + +# ----------------------------------- +# Main +# ----------------------------------- +echo "$1" >/tmp/debug.txt +echo "$*" +case "$1" in + zapto) + if [ "$2" != "" ] + then + call_webserver "control/zapto?$2" >/dev/null + fi + ;; + + switchto) + if [ "$2" = "Radio" ] + then + call_webserver "control/setmode?radio" >/dev/null + else + call_webserver "control/setmode?tv" >/dev/null + fi + ;; + + url) + url=`buildStreamingRawURL` + echo "$url" ;; + + audio-url) + url=`buildStreamingAudioRawURL` + echo "$url" ;; + + live_lock) + live_lock ;; + + live_unlock) + live_unlock ;; + + dboxIP) + buildLocalIP ;; + + prepare_radio) + prepare_radio + Y_APid=`call_webserver "control/yweb?radio_stream_pid"` + url="http://$2:31338/$Y_APid" + echo "$url" > $y_tmp_m3u + echo "$url" > $y_tmp_pls + ;; + + prepare_tv) + prepare_tv + ;; + + udp_stream) +echo "udp stream" + if [ "$2" = "start" ] + then + shift 2 +echo "kill all streams" + killall streamts + killall streampes + killall udpstreamts +echo "start udpstream" + if [ -e /var/bin/udpstreamts ] + then + /var/bin/udpstreamts $* & + else + udpstreamts $* & + fi + pidof udpstreamts >/tmp/udpstreamts.pid + fi + if [ "$2" = "stop" ] + then + killall udpstreamts + fi + ;; + + *) + echo "Parameter falsch: $*" ;; +esac + + + diff --git a/src/nhttpd/web/scripts/Y_Plugins.sh b/src/nhttpd/web/scripts/Y_Plugins.sh new file mode 100755 index 000000000..be1ae5584 --- /dev/null +++ b/src/nhttpd/web/scripts/Y_Plugins.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# ----------------------------------------------------------- +# Plugins (yjogol) +# $Date: 2006/09/16 14:52:23 $ +# $Revision: 1.1 $ +# ----------------------------------------------------------- + +. ./_Y_Globals.sh +. ./_Y_Library.sh + +# =========================================================== +# Settings : Skins +# =========================================================== +# ----------------------------------------------------------- +# Skin Liste +# ----------------------------------------------------------- +skin_get() +{ + check_Y_Web_conf + active_skin=`config_get_value_direct $y_config_Y_Web 'skin'` + html_option_list="" + skin_list=`find $y_path_httpd -name 'Y_Main-*'` + for f in $skin_list + do + skin=`echo "$f"|sed -e s/^.*Y_Main-//g|sed -e s/.css//g` + if [ "$skin" = "$active_skin" ] + then + selec="selected" + else + selec="" + fi + opt="" + html_option_list="$html_option_list $opt" + done + echo "$html_option_list" +} + +# ----------------------------------------------------------- +# Skin setzen : css ueberschreiben $1=Skin-Name +# ----------------------------------------------------------- +skin_set() +{ + cd $y_path_httpd + cp Y_Main-$1.css Y_Main.css + if [ -e global-$1.css ] + then + cp global-$1.css global.css + else + cp global-Standard.css global.css + fi + config_set_value_direct $y_config_Y_Web 'skin' $1 + + msg="Skin changed - Now browsers Refresh/actualization explain" + y_format_message_html +} + +# ----------------------------------------------------------- +# Main +# ----------------------------------------------------------- + +case "$1" in + skin_set) + skin_set $2 ;; + + skin_get) + skin_get ;; + *) + echo "Parameter falsch: $*" ;; +esac + diff --git a/src/nhttpd/web/scripts/Y_Tools.sh b/src/nhttpd/web/scripts/Y_Tools.sh new file mode 100755 index 000000000..c43f76e79 --- /dev/null +++ b/src/nhttpd/web/scripts/Y_Tools.sh @@ -0,0 +1,579 @@ +#!/bin/sh +# ----------------------------------------------------------- +# Tools (yjogol) +# $Date: 2007/02/21 17:41:04 $ +# $Revision: 1.2 $ +# ----------------------------------------------------------- +. ./_Y_Globals.sh +. ./_Y_Library.sh +# =========================================================== +# Settings : Skins +# =========================================================== +# ----------------------------------------------------------- +# Skin Liste +# ----------------------------------------------------------- +skin_get() +{ + check_Y_Web_conf + active_skin=`config_get_value_direct $y_config_Y_Web 'skin'` + html_option_list="" + skin_list=`find $y_path_httpd -name 'Y_Main-*'` + for f in $skin_list + do + skin=`echo "$f"|sed -e s/^.*Y_Main-//g|sed -e s/.css//g` + if [ "$skin" = "$active_skin" ] + then + selec="selected" + else + selec="" + fi + opt="" + html_option_list="$html_option_list $opt" + done + echo "$html_option_list" +} +# ----------------------------------------------------------- +# Skin setzen : css ueberschreiben $1=Skin-Name +# ----------------------------------------------------------- +skin_set() +{ + cd $y_path_httpd + cp Y_Main-$1.css Y_Main.css + if [ -e global-$1.css ] + then + cp global-$1.css global.css + else + cp global-Standard.css global.css + fi + config_set_value_direct $y_config_Y_Web 'skin' $1 + + msg="Skin changed - Now browsers Refresh/actualization explain" + y_format_message_html +} +# ----------------------------------------------------------- +# Image Backup - build form +# ----------------------------------------------------------- +image_upload() +{ + if [ -s "$y_upload_file" ] + then + msg="Image upload ok
" + msg="$msg " + else + msg="Upload-Problem.
Please, try again." + msg="$msg " + fi + y_format_message_html +} +# =========================================================== +# Flashimage +# =========================================================== +# ----------------------------------- +# Flash-Backup ($1=mtd Nummer) +# ----------------------------------- +image_backup_mtd() +{ + rm /tmp/*.img + cat /dev/mtd/$1 > /tmp/flash_mtd$1.img +} +# ----------------------------------- +# Sende Download-Page ($1=mtd Nummer) +# ----------------------------------- +# ----------------------------------- +image_delete_download_page() +{ + rm -r /tmp/*.img +# msg="
The image file in tmp was extinguished.
" +# y_format_message_html +} +# ----------------------------------------------------------- +# Flash ($1=mtd Nummer) Upload-File $2=true/false =simulate +# ----------------------------------------------------------- +flash_mtd() +{ + simulate="true" + if [ "$2" = "false" ] + then + simulate="false" + fi + rm /tmp/*.img + if [ -s "$y_upload_file" ] + then + echo "" >/tmp/e.txt + msg_nmsg "Image%20%20flashing!" + if [ "$simulate" = "false" ] + then + fcp -v "$y_upload_file" /dev/mtd/$1 >/tmp/e.txt + else #simulation/DEMO + i="0" + while test $i -le 10 + do + p=`expr $i \* 10` + b=`expr $i \* 63` + b=`expr $b / 10` + echo -e "\rDEMO: Erasing blocks: $b/63 ($p%)" >>/tmp/e.txt + i=`expr $i + 1` + sleep 1 + done + i="0" + while test $i -le 20 + do + p=`expr $i \* 5` + b=`expr $i \* 8064` + b=`expr $b / 20` + echo -e "\rDEMO: Writing data: $b k/8064k ($p%)" >>/tmp/e.txt + i=`expr $i + 1` + sleep 2 + done + i="0" + while test $i -le 5 + do + p=`expr $i \* 20` + b=`expr $i \* 8064` + b=`expr $b / 5` + echo -e "\rDEMO: Verifying data: $b k/8064k ($p%)" >>/tmp/e.txt + i=`expr $i + 1` + sleep 1 + done + fi + msg_nmsg "flashing%20ready.%20Reboot..." + msg="flashing done ... please reboot box now ..." + msg="$msg " + y_format_message_html + + if [ "$simulate" = "false" ] + then + busybox reboot -d10 + fi + else + msg="Upload-Problem.
Try again, please." + msg="$msg " + y_format_message_html + fi +} +# ----------------------------------------------------------- +# copies Uploadfile to $1 +# ----------------------------------------------------------- +upload_copy() +{ + if [ -s "$y_upload_file" ] + then + cp "$y_upload_file" "$1" + else + msg="Upload-Problem.
Try again, please." + fi +} +# ----------------------------------------------------------- +bootlogo_upload() +{ + msg="Boot-Logo neu gesetzt" + upload_copy "$y_boot_logo" + y_format_message_html +} +# ----------------------------------------------------------- +bootlogo_lcd_upload() +{ + msg="Boot-Logo-LCD neu gesetzt" + upload_copy "$y_boot_logo_lcd" + y_format_message_html +} +# ----------------------------------------------------------- +ucodes_upload() +{ + msg="$1 hochgeladen
next file" + upload_copy "$y_path_ucodes/$1" + y_format_message_html +} +# ----------------------------------------------------------- +zapit_upload() +{ + msg="$1 hochgeladen
next file" + upload_copy "$y_path_zapit/$1" + y_format_message_html +} +# ----------------------------------------------------------- +# Mount from Neutrino-Settings $1=nr +# ----------------------------------------------------------- +do_mount() +{ + config_open $y_config_neutrino + fstype=`config_get_value "network_nfs_type_$1"` + ip=`config_get_value "network_nfs_ip_$1"` + local_dir=`config_get_value "network_nfs_local_dir_$1"` + dir=`config_get_value "network_nfs_dir_$1"` + options1=`config_get_value "network_nfs_mount_options1_$1"` + options2=`config_get_value "network_nfs_mount_options2_$1"` + username=`config_get_value "network_nfs_username_$1"` + password=`config_get_value "network_nfs_password_$1"` + + # check options + if [ "$options1" = "" ] + then + options1=options2 + options2="" + fi + + # default options + if [ "$options1" = "" ] + then + if [ "$options2" = "" ] + then + if [ "$fstype" = "0" ] + then + options1="ro,soft,udp" + options2="nolock,rsize=8192,wsize=8192" + fi + if [ "$fstype" = "1" ] + then + options1="ro" + fi + fi + fi + # build mount command + case "$fstype" in + 0) #nfs + cmd="mount -t nfs $ip:$dir $local_dir -o $options1" + ;; + 1) + cmd="mount -t cifs //$ip/$dir $local_dir -o username=$username,password=$password,unc=//$ip/$dir,$options1"; + ;; + 2) + cmd="lufsd none $local_dir -o fs=ftpfs,username=$username,password=$password,host=$ip,root=/$dir,$options1"; + ;; + default) + echo "mount type not supported" + esac + + if [ "$options2" != "" ] + then + cmd="$cmd,$options2" + fi + + res=`$cmd` + echo "$res" + echo "view mounts" + m=`mount` + msg="mount cmd:$cmd

res=$res
view Mounts;
$m" + y_format_message_html +} +# ----------------------------------------------------------- +# unmount $1=local_dir +# ----------------------------------------------------------- +do_unmount() +{ + umount $1 +} +# ----------------------------------------------------------- +# AutoMount +# deaktive mount "#" replaces "---" and "=" replaced ",," +# ----------------------------------------------------------- +do_automount_list() +{ + i="1" + sel="checked='checked'" + cat $1|sed -n /-fstype/p|\ + while read mountname options share + do + mountvalue=`echo "$mountname"|sed -e "s/#/---/g"` + echo "$i: $mountname ($share)
" + sel="" + i=`expr $i + 1` + done +} +do_automount_getline() +{ + mountname=`echo "$2"|sed -e "s/---/#/g"` + cat $1|sed -n "/^[#]*$mountname[^a-zA-Z0-9]/p" +} +# $1:filename, $2:mountname, $3-*:mountstring +do_automount_setline() +{ + if ! [ -e $1 ]; then + cp /etc/auto.net $1 + fi + filename=$1 + mountname=`echo "$2"|sed -e "s;---;;g"` + shift 2 + mountset=`echo "$*"|sed -e "s;---;#;g" -e "s;,,;=;g"` + cp $filename "$filename.old" + chmod ou+rwss $filename + ex=`cat $filename|sed -n "/^$mountname[^a-zA-Z0-9].*$/p"` + if [ "$ex" = "" ]; then + echo "$mountset" >>$filename + else + tmp=`cat "$filename"|sed -e "s;^$mountname[^a-zA-Z0-9].*$;$mountset;g"` + echo "$tmp" >$filename + fi + + kill -HUP `cat /var/run/automount.pid` +} +# ----------------------------------------------------------- +# Execute shell command +# 1: directory 2: append [true|false] 3+: cmd +# ----------------------------------------------------------- +do_cmd() +{ + cd $1 + pw1="$1" + app="$2" + shift 2 + + if [ "$1" = "cd" ] + then + cd $2 + else + tmp=`$*` #Execute command + fi + pw=`pwd` + echo '
' + echo '' +} +# ----------------------------------------------------------- +# yInstaller +# un-tar uploaded file to /tmp. Execute included install.sh +# ----------------------------------------------------------- +do_installer() +{ + # clean up + if [ -s "$y_out_html" ] + then + rm $y_out_html + fi + + if [ -s "$y_upload_file" ] + then + # unpack /tmp/upload.tmp + cd $y_path_tmp + tar -xf "$y_upload_file" + rm $y_upload_file + if [ -s "$y_install" ] #look for install.sh + then + chmod 755 $y_install + o=`$y_install` # execute + rm -f $y_install # clean up + if [ -s "$y_out_html" ] #html - output? + then + echo '' + echo "" + echo "If automatic forwarding does not go." + echo '' +# cat $y_out_html + else + echo '' + echo '' + echo "$o" + echo '' + fi + else + msg="$y_install not found" + y_format_message_html + fi + else + msg="Upload-Problem.
Try again, please." + y_format_message_html + fi +} +# ----------------------------------------------------------- +# extention Installer $1=URL +# ----------------------------------------------------------- +do_ext_installer() +{ + rm $y_upload_file + wgetlog=`wget -O $y_upload_file $1 2>/tmp/err.log` + if [ -s "$y_upload_file" ];then + cd $y_path_tmp + tar -xf "$y_upload_file" + rm $y_upload_file + if [ -s "$y_install" ] #look for install.sh + then + chmod 755 $y_install + o=`$y_install` # execute + rm -f $y_install # clean up + echo "ok: wget=$wgetlog" + fi + else + e=`cat /tmp/err.log` + echo "error: $y_install not found. wget=$wgetlog $e" + fi +} +# ----------------------------------------------------------- +# view /proc/$1 Informations +# ----------------------------------------------------------- +proc() +{ + msg=`cat /proc/$1` + msg="proc: $1

$msg" + y_format_message_html +} +# ----------------------------------------------------------- +# wake up $1=MAC +# ----------------------------------------------------------- +wol() +{ + msg=`etherwake $1` + msg="Wake on LAN $1

$msg" + y_format_message_html +} +# ----------------------------------------------------------- +# ----------------------------------------------------------- +dofbshot() +{ + rm -r /tmp/a.png + fbshot -q /tmp/a.png >/dev/null + msg="" + msg="$msg " + y_format_message_html_plain +} + +# ----------------------------------------------------------- +# Settings Backup/Restore +# ----------------------------------------------------------- +do_settings_backup_restore() +{ + workdir="$y_path_tmp/y_save_settings" + yI_Version="0.1" + case "$1" in + backup) + mkdir $workdir >/dev/null + cp -r $y_path_config $workdir >/dev/null + t=`date +%y%m%d_%H%M%S` + filename="$y_path_tmp/y_Save_Settings_$t.tar" + cd $workdir + tar -cvf $filename ./* >/dev/null + rm -r $workdir >/dev/null + echo "$filename" + ;; + + restore) + msg="restore settings" + if [ -s "$y_upload_file" ] + then + # unpack /tmp/upload.tmp + cd $y_path_tmp + tar -xf "$y_upload_file" + rm $y_upload_file + cp -rf ./config /var/tuxbox/ + rm -r ./config + msg="$msg ok" + y_format_message_html + sync + sync + umount -a + reboot -f + else + msg="$msg error: no upload file" + fi + y_format_message_html + ;; + esac +} +# ----------------------------------------------------------- +# Main +# ----------------------------------------------------------- +#debug +echo "call:$*" >> "/tmp/debug.txt" +case "$1" in + skin_set) skin_set $2 ;; + skin_get) skin_get ;; + image_upload) image_upload ;; + image_backup) image_backup_mtd $2; echo "/tmp/flash_mtd$2.img" ;; + image_flash) shift 1; flash_mtd $* ;; + image_flash_free_tmp) rm -r /tmp/*.img ;; + image_delete) image_delete_download_page ;; + bootlogo_upload) bootlogo_upload ;; + bootlogo_lcd_upload) bootlogo_lcd_upload ;; + ucodes_upload) ucodes_upload $2 ;; + zapit_upload) zapit_upload $2 ;; + kernel-stack) msg=`dmesg`; y_format_message_html ;; + ps) msg=`ps -c`; y_format_message_html ;; + free) f=`free`; p=`df -h`; msg="RAM Memory use\n-------------------\n$f\n\nPartitions\n-------------------\n$p" + y_format_message_html ;; + yreboot) yreboot; echo "Reboot..." ;; + check_yWeb_conf) check_Y_Web_conf ;; + rcsim) rcsim $2 >/dev/null ;; + domount) shift 1; do_mount $* ;; + dounmount) shift 1; do_unmount $* ;; + cmd) shift 1; do_cmd $* ;; + installer) shift 1; do_installer $* ;; + ext_installer) shift 1; do_ext_installer $* ;; + proc) shift 1; proc $* ;; + wol) shift 1; wol $* ;; + dofbshot) dofbshot ;; + get_update_version) wget -O /tmp/version.txt "http://www.yjogol.de/download/Y_Version.txt" ;; + settings_backup_restore) shift 1; do_settings_backup_restore $* ;; + exec_cmd) shift 1; $* ;; + automount_list) shift 1; do_automount_list $* ;; + automount_getline) shift 1; do_automount_getline $* ;; + automount_setline) shift 1; do_automount_setline $* ;; + + timer_get_tvinfo) + shift 1 + res=`wget -O /tmp/tvinfo.xml "http://www.tvinfo.de/share/vidac/rec_info.php?username=$1&password=$2"` + if ! [ -s /tmp/tvinfo.xml ] + then + res="$res File empty!" + fi + echo "$res" + ;; + + timer_get_klack) + config_open $y_config_Y_Web + url=`config_get_value "klack_url"` + klack_url=`echo "$url"|sed -e 's/;/\&/g'` + wget -O /tmp/klack.xml "$klack_url" ;; + + get_synctimer_channels) + if [ -e "$y_path_config/channels.txt" ] + then + cat $y_path_config/channels.txt + else + cat $y_path_httpd/channels.txt + fi + ;; + + get_extention_list) + if [ -e "$y_path_config/extentions.txt" ] + then + cat $y_path_config/extentions.txt + else + cat $y_path_httpd/extentions.txt + fi + ;; + + write_extention_list) + shift 1 + echo "$*" >$y_path_config/extentions.txt + ;; + + url_get) + shift 1 + res=`wget -O /tmp/$2 "$1" >/tmp/url.log` + cat /tmp/$2 + ;; + + standby_status) + status=`switch -s|grep "FNC: 0"` + if [ "$status" = "" ] + then + echo "off" + else + echo "on" + fi + ;; + + *) + echo "[Y_Tools.sh] Parameter falsch: $*" ;; +esac diff --git a/src/nhttpd/web/scripts/_Y_Globals.sh b/src/nhttpd/web/scripts/_Y_Globals.sh new file mode 100755 index 000000000..ac814a69c --- /dev/null +++ b/src/nhttpd/web/scripts/_Y_Globals.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# ----------------------------------------------------------- +# Y Globals (yjogol) +# $Date: 2006/09/16 14:52:23 $ +# $Revision: 1.1 $ +# ----------------------------------------------------------- + +# ----------------------------------------------------------- +# Pathes +# ----------------------------------------------------------- +#y_path_httpd="/share/tuxbox/neutrino/httpd-y" +y_path_httpd=".." +y_path_scripts="$y_path_httpd/scripts" +y_path_usrbin="/var/bin" +y_path_config="/var/tuxbox/config" +y_path_tmp="/tmp" +y_path_ucodes="/var/tuxbox/ucodes" +y_path_zapit="/var/tuxbox/config/zapit" + +y_path_plugin_tuxnew="/var/tuxbox/config/tuxnews" + +y_url_control="http://localhost/control" + +# ----------------------------------------------------------- +# Files +# ----------------------------------------------------------- +y_config_Y_Web="$y_path_config/Y-Web.conf" +y_config_vnc="$y_path_config/vnc.conf" +y_config_nhttpd="$y_path_config/nhttpd.conf" +y_config_neutrino="$y_path_config/neutrino.conf" +y_upload_file="$y_path_tmp/upload.tmp" +y_boot_logo="/var/tuxbox/boot/logo-fb" +y_boot_logo_lcd="/var/tuxbox/boot/logo-lcd" +y_tmp="$y_path_tmp/y.tmp" +y_wait_live="$y_path_httpd/Y_Live_Wait.yhtm" +y_tmp_m3u="$y_path_tmp/y.m3u" +y_tmp_pls="$y_path_tmp/y.pls" + +y_out_html="$y_path_tmp/y_out.yhtm" +y_install="$y_path_tmp/install.sh" + + diff --git a/src/nhttpd/web/scripts/_Y_Library.sh b/src/nhttpd/web/scripts/_Y_Library.sh new file mode 100755 index 000000000..cb5fd8575 --- /dev/null +++ b/src/nhttpd/web/scripts/_Y_Library.sh @@ -0,0 +1,207 @@ +#!/bin/sh +# ----------------------------------------------------------- +# Y Library (yjogol) +# $Date: 2006/09/16 14:52:23 $ +# $Revision: 1.1 $ +# ----------------------------------------------------------- + +# ----------------------------------------------------------- +# local call to WebServer $1=url (after http://locahost:port/<$1>) +# ----------------------------------------------------------- +call_webserver() +{ + port=`sed -n /^Port=/p $y_config_nhttpd | sed -e s/^Port=//1` + tmp=`wget -O - -q "http://localhost:$port/$1"` + echo "$tmp" +} +# =========================================================== +# Streaming URL +# =========================================================== + +buildLocalIP() +{ + localIP=`ifconfig eth0|sed -n '/inet addr/p'|sed -e 's/^.*inet addr://g' -e 's/ .*//g'` + echo "$localIP" +} + +# ----------------------------------------------------------- +# Streaming URL für sed +# ----------------------------------------------------------- +buildStreamingURL() +{ + localIP=`buildLocalIP` + + pids=`call_webserver "control/yweb?video_stream_pids=0"` + echo "http:\/\/$localIP:31339\/0,$pids" +} + +# ----------------------------------------------------------- +# Streaming URL +# ----------------------------------------------------------- +buildStreamingRawURL() +{ + localIP=`buildLocalIP` + pids=`call_webserver "control/yweb?video_stream_pids=0"` + echo "http://$localIP:31339/0,$pids" +} + +# ----------------------------------------------------------- +# Audio: Streaming URL für sed +# ----------------------------------------------------------- +buildStreamingAudioURL() +{ + localIP=`buildLocalIP` + Y_APid=`call_webserver "control/yweb?radio_stream_pid"` + echo "http:\/\/$localIP:31338\/$Y_APid" +} + +# ----------------------------------------------------------- +# Streaming URL +# ----------------------------------------------------------- +buildStreamingAudioRawURL() +{ + localIP=`buildLocalIP` + Y_APid=`call_webserver "control/yweb?radio_stream_pid"` + echo "http://$localIP:31338/$Y_APid" +} + +# ----------------------------------- +# UNIX ($msg) Text als HTML ausgeben +# noch sehr unschoen +# ----------------------------------- + +y_format_message_html() +{ + tmp="" + tmp="$tmp " + tmp="$tmp
Results
" + tmp="$tmp
\n$msg\n
" + +# tmp="$tmp
\n$msg\n
" + echo -e "$tmp" +} +y_format_message_html2() +{ + tmp="" + tmp="$tmp " + tmp="$tmp
Results
" + tmp="$tmp $msg
" + echo "$tmp" +} +y_format_message_html_plain() +{ + tmp="" + tmp="$tmp " + tmp="$tmp $msg" + echo "$tmp" +} +# =========================================================== +# config-Dateien - lesen / schreiben +# (Zeilenformat: VarName=VarValue) +# =========================================================== +cfg="" +# ----------------------------------------------------------- +# config-Datei lesen/cachen (Inhalt in $cfg) +# $1=config-Filename +# ----------------------------------------------------------- +config_open() +{ + cfg="" + cfg=`cat $1` +} +# ----------------------------------------------------------- +# config-Datei schreiben (Inhalt in $cfg) +# $1=config-Filename +# ----------------------------------------------------------- +config_write() +{ + echo "$cfg" >$1 +} +# ----------------------------------------------------------- +# Variablenwert zurueckgeben (vorher open) +# $1=VarName +# ----------------------------------------------------------- +config_get_value() +{ + cmd="sed -n /^$1=/p" + tmp=`echo "$cfg" | $cmd` + cmd="sed -e s/^$1=//1" + tmp=`echo "$tmp" | $cmd` + echo $tmp +} +# ----------------------------------------------------------- +# Variablenwert zurueckgeben (ohne open) +# $1=config-Filename +# $2=VarName +# ----------------------------------------------------------- +config_get_value_direct() +{ + config_open $1 + config_get_value $2 +} +# ----------------------------------------------------------- +# Variablenwert setzen (vorher open) +# $1=VarName) +# $2=VarValue +# ----------------------------------------------------------- +config_set_value() +{ + tmp=`echo "$cfg" | sed -n "/^$1=.*/p"` + if [ "$tmp" = "" ] + then + cfg=`echo -e "$cfg\n$1=$2"` + else + cmd="sed -e s/^$1=.*/$1=$2/g" + cfg=`echo "$cfg" | $cmd` + fi +} +# ----------------------------------------------------------- +# Variablenwert zurueckgeben (ohne open) +# $1=config-Filename +# $2=VarName) +# $3=VarValue +# ----------------------------------------------------------- +config_set_value_direct() +{ + config_open $1 + config_set_value $2 $3 + config_write $1 +} +# ----------------------------------------------------------- +# Reboot +# ----------------------------------------------------------- +yreboot() +{ +# reboot + call_webserver "control/reboot" +} + +# ----------------------------------------------------------- +# Message - nmsg (waiting - press ok on rc) +# ----------------------------------------------------------- +msg_nmsg() +{ + call_webserver "control/message?nmsg=$1" +} + +# ----------------------------------------------------------- +# Message - popup (closes autom.) +# ----------------------------------------------------------- +msg_popup() +{ + call_webserver "control/message?popup=$1" +} + +# ----------------------------------------------------------- +# create Y_Web.conf if does not exists +# ----------------------------------------------------------- +check_Y_Web_conf() +{ + if ! [ -e $y_config_Y_Web ] + then + echo "skin=Tuxbox" >$y_config_Y_Web + echo "slavebox=" >>$y_config_Y_Web + echo "live_resolution_w=384" >>$y_config_Y_Web + echo "live_resolution_wh=288" >>$y_config_Y_Web + fi +} diff --git a/src/nhttpd/web/scripts/api.sh b/src/nhttpd/web/scripts/api.sh new file mode 100755 index 000000000..f6f7aacc9 --- /dev/null +++ b/src/nhttpd/web/scripts/api.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# ----------------------------------------------------------- +# API Script (yjogol) +# $Date: 2007/02/21 17:41:04 $ +# $Revision: 1.1 $ +# ----------------------------------------------------------- +path_httpd=".." +path_scripts="$path_httpd/scripts" +path_usrbin="/var/bin" +path_config="/var/tuxbox/config" +path_tmp="/tmp" + +# ----------------------------------------------------------- +do_udp_stream() +{ +echo "para: $*" + up="no" + if [ -e /var/bin/udpstreamts ]; then + up="/var/bin/udpstreamts" + else + up="udpstreamts" + fi + case "$1" in + installed) + echo "$up" ;; + start) + shift 1 + killall streamts + killall streampes + killall udpstreamts + trap "" 1;$up $* & + ;; + stop) + killall udpstreamts ;; + esac +} +# ----------------------------------------------------------- +# Main +# ----------------------------------------------------------- +case "$1" in + version) + echo '$Revision: 1.1 $' ;; + + udp_stream) + shift 1 + do_udp_stream $* + ;; + *) + echo "[api.sh] Parameter wrong: $*" ;; +esac + + + diff --git a/src/nhttpd/yconfig.h b/src/nhttpd/yconfig.h new file mode 100644 index 000000000..b6e4d74e9 --- /dev/null +++ b/src/nhttpd/yconfig.h @@ -0,0 +1,236 @@ +//============================================================================= +// YHTTPD +// Global System Configuration +//============================================================================= + +//----------------------------------------------------------------------------- +#ifndef __yconfig_h__ +#define __yconfig_h__ + +// c++ +#include +#include +#include + +//----------------------------------------------------------------------------- +// TODO: comment it, if CVS checkin +//#define Y_UPDATE_BETA y +#ifdef Y_UPDATE_BETA +#warning "!!!! THIS IS BETA COMPILING. SWITCH OF (Y_UPDATE_BETA) FOR CVS" +#define Y_CONFIG_USE_WEBLOG y +#endif +//----------------------------------------------------------------------------- +// System Choice ONE choice +//----------------------------------------------------------------------------- +#ifndef CONFIG_SYSTEM_BY_COMPILER // use Compiler directive to set CONFIG_SYSTEM +#define CONFIG_SYSTEM_TUXBOX y // Tuxbox dbox project +//#define CONFIG_SYSTEM_AVM y // AVM FritzBox +//#define CONFIG_SYSTEM_MSS y // Maxtor Shared Storage +//#define CONFIG_SYSTEM_LINUX y // Normal Linux PC +//#define CONFIG_SYSTEM_CYGWIN y // Windows (Cygwin) +#endif +//----------------------------------------------------------------------------- +// General central Definitions +//----------------------------------------------------------------------------- +#define HTTPD_VERSION "3.1.2" // Webserver version (can be overloaded) +#define YHTTPD_VERSION "1.2.0" // Webserver version (Version of yhttpd-core!) +#define IADDR_LOCAL "127.0.0.1" // local IP +#define HTTPD_NAME "yhttpd" // Webserver name (can be overloaded) +#define YHTTPD_NAME "yhttpd_core" // Webserver name (Name of yhttpd-core!) +#define AUTH_NAME_MSG "yhhtpd" // Name in Authentication Dialogue + +#define HTTPD_KEEPALIVE_TIMEOUT 500000 // Timeout for Keep-Alive in mircoseconds +//============================================================================= +// Features wanted +//============================================================================= +//----------------------------------------------------------------------------- +// modules +//----------------------------------------------------------------------------- +//#define Y_CONFIG_USE_TESTHOOK y // Add mod: "Test-Hook" (hook example) +#define Y_CONFIG_USE_YPARSER y // Add mod: "y-Parsing" +#define Y_CONFIG_USE_AUTHHOOK y // Add mod: "Authentication" +#define Y_CONFIG_USE_WEBLOG y // Add mod: "WebLogging" +#define Y_CONFIG_USE_CACHE y // Add mod: Can cache production pages +#define Y_CONFIG_USE_SENDFILE y // Add mod: can send static files (mandantory) +//----------------------------------------------------------------------------- +// modules +//----------------------------------------------------------------------------- +#define Y_CONFIG_FEATURE_CHECK_PORT_AUTORITY y // System: Port < 1024 need Admin-Privileges-Check +#define Y_CONFIG_HAVE_SENDFILE y // System: Have *IX SendFile +#define Y_CONFIG_FEATURE_UPLOAD y // Add Feature: File Upload POST Command +#define Y_CONFIG_USE_HOSTEDWEB y // Add Feature: Use HOSTED Web +#define Y_CONFIG_FEATURE_SHOW_SERVER_CONFIG y // Add Feature (in yParser): add /y/server-config +//#define Y_CONFIG_USE_OPEN_SSL y // Add Feature: use openSSL +//#define Y_CONFIG_FEATURE_KEEP_ALIVE y // Add Feature: Keep-alive //FIXME: does not work correctly now +#define Y_CONFIG_FEATUE_SENDFILE_CAN_ACCESS_ALL y // Add Feature: every file can be accessed (use carefully: security!!) +//#define Y_CONFIG_FEATURE_CHROOT y // Add Feature: Use Change Root for Security +//#define Y_CONFIG_FEATURE_HTTPD_USER y // Add Feature: Set User for yhttpd-Process + +// TODO build error page function +//#define Y_CONFIG_HAVE_HTTPD_ERRORPAGE y // Have an HTTPD Error Page + +//----------------------------------------------------------------------------- +// Define/Undefine Features forced by CONFIG_SYSTEM_xxx +// Dependencies +//----------------------------------------------------------------------------- +#ifdef Y_CONFIG_USE_OPEN_SSL +#undef Y_CONFIG_HAVE_SENDFILE // Sendfile does not work for SSL +#endif + +#ifdef CONFIG_SYSTEM_CYGWIN +#undef Y_CONFIG_FEATURE_CHECK_PORT_AUTORITY +#undef Y_CONFIG_HAVE_SENDFILE // No Sendfile under cygwin +#endif +#ifdef CONFIG_SYSTEM_TUXBOX +#define Y_CONFIG_FEATURE_UPLOAD y +#define Y_CONFIG_USE_YPARSER y +#define Y_CONFIG_USE_AUTHHOOK y +#endif +#ifdef Y_CONFIG_FEATURE_KEEP_ALIVE +#define HTTP_PROTOCOL "HTTP/1.1" +#else +#define HTTP_PROTOCOL "HTTP/1.0" +#endif +//============================================================================= +// Configurations for systems/OSs +//============================================================================= +//----------------------------------------------------------------------------- +// Configurations for LINUX +//----------------------------------------------------------------------------- +#ifdef CONFIG_SYSTEM_LINUX +#define HTTPD_STANDARD_PORT 8080 +#define HTTPD_MAX_CONNECTIONS 3 +#define HTTPD_CONFIGDIR "/home/y" +#define HTTPD_CONFIGFILE HTTPD_CONFIGDIR "/yhttpd.conf" +#define HTTPD_REQUEST_LOG "/tmp/httpd_log" //TODO: delete every occurence +#define HTTPD_ERRORPAGE "/Y_ErrorPage.yhtm" +#define HTTPD_SENDFILE_EXT "htm:text/html,html:text/html,xml:text/xml,txt:text/plain,jpg:image/jpeg,jpeg:image/jpeg,gif:image/gif,png:image/png,bmp:image/bmp,css:text/css,js:text/plain,img:application/octet-stream,ico:image/x-icon,m3u:application/octet-stream,tar:application/octet-stream" +#define AUTHUSER "test" +#define AUTHPASSWORD "test1" +#define PRIVATEDOCUMENTROOT "/home/y/nhttpd-y" +#define PUBLICDOCUMENTROOT "/var/httpd" +#define HOSTEDDOCUMENTROOT "/mnt/hosted" + +#define SSL_PEMFILE HTTPD_CONFIGDIR "/server.pem" +#define SSL_CA_FILE HTTPD_CONFIGDIR "/cacert.pem" + +#define UPLOAD_TMP_FILE "/tmp/upload.tmp" +#define CACHE_DIR "/tmp/.cache" +#endif +//----------------------------------------------------------------------------- +// Configurations for WINDOWS (Cygwin) +//----------------------------------------------------------------------------- +#ifdef CONFIG_SYSTEM_CYGWIN +#define HTTPD_STANDARD_PORT 80 +#define HTTPD_MAX_CONNECTIONS 32 +#define HTTPD_CONFIGDIR "/usr/local/yweb" +#define HTTPD_CONFIGFILE HTTPD_CONFIGDIR "/yhttpd.conf" +#define HTTPD_REQUEST_LOG "/tmp/httpd_log" +#define HTTPD_ERRORPAGE "/Y_ErrorPage.yhtm" +#define HTTPD_SENDFILE_EXT "htm:text/html,html:text/html,xml:text/xml,txt:text/plain,jpg:image/jpeg,jpeg:image/jpeg,gif:image/gif,png:image/png,bmp:image/bmp,css:text/css,js:text/plain" + +#define AUTHUSER "test" +#define AUTHPASSWORD "test1" +#define PRIVATEDOCUMENTROOT "/cygdrive/d/Work/y/ws/nhttpd30/web" +#define PUBLICDOCUMENTROOT "/var/httpd" +#define HOSTEDDOCUMENTROOT "/mnt/hosted" + +#define SSL_PEMFILE HTTPD_CONFIGDIR "/server.pem" +#define SSL_CA_FILE HTTPD_CONFIGDIR "/cacert.pem" + +#define LOG_FILE "./yhhtpd.log" +#define LOG_FORMAT "CLF" + +#define UPLOAD_TMP_FILE "/tmp/upload.tmp" +#define CACHE_DIR "/tmp/.cache" +#endif +//----------------------------------------------------------------------------- +// Configurations for LINUX (Tuxbox dbox2) +//----------------------------------------------------------------------------- +#ifdef CONFIG_SYSTEM_TUXBOX +#undef HTTPD_NAME +#define HTTPD_NAME "nhttpd" +#define HTTPD_STANDARD_PORT 80 +#define HTTPD_MAX_CONNECTIONS 10 +#define HTTPD_CONFIGDIR "/var/tuxbox/config" +#define HTTPD_CONFIGFILE HTTPD_CONFIGDIR "/nhttpd.conf" +#define HTTPD_REQUEST_LOG "/tmp/httpd_log" +#define HTTPD_ERRORPAGE "/Y_ErrorPage.yhtm" +#define HTTPD_SENDFILE_EXT "htm:text/html,html:text/html,xml:text/xml,txt:text/plain,jpg:image/jpeg,jpeg:image/jpeg,gif:image/gif,png:image/png,bmp:image/bmp,css:text/css,js:text/plain,img:application/octet-stream,ico:image/x-icon,m3u:application/octet-stream" + +#define AUTHUSER "root" +#define AUTHPASSWORD "dbox2" +#define PRIVATEDOCUMENTROOT "/share/tuxbox/neutrino/httpd-y" +#define PUBLICDOCUMENTROOT "/var/httpd" +#define NEUTRINO_CONFIGFILE "/var/tuxbox/config/neutrino.conf" +#define HOSTEDDOCUMENTROOT "/mnt/hosted" +#define EXTRASDOCUMENTROOT "/mnt/hosted/extras" +#define EXTRASDOCUMENTURL "/hosted/extras" +#define ZAPITXMLPATH "/var/tuxbox/config/zapit" + +#define SSL_PEMFILE HTTPD_CONFIGDIR "/server.pem" +#define SSL_CA_FILE HTTPD_CONFIGDIR "/cacert.pem" + +#define LOG_FILE "/tmp/yhhtpd.log" +#define LOG_FORMAT "" + +#define UPLOAD_TMP_FILE "/tmp/upload.tmp" +#define CACHE_DIR "/tmp/.cache" +#endif +//----------------------------------------------------------------------------- +// Configurations for AVM FritzBox +//----------------------------------------------------------------------------- +#ifdef CONFIG_SYSTEM_AVM +#define HTTPD_STANDARD_PORT 81 +#define HTTPD_MAX_CONNECTIONS 3 +#define HTTPD_CONFIGDIR "/tmp" +#define HTTPD_CONFIGFILE HTTPD_CONFIGDIR "/yhttpd.conf" +#define HTTPD_REQUEST_LOG "/tmp/httpd_log" +#define HTTPD_ERRORPAGE "/Y_ErrorPage.yhtm" +#define HTTPD_SENDFILE_EXT "htm:text/html,html:text/html,xml:text/xml,txt:text/plain,jpg:image/jpeg,jpeg:image/jpeg,gif:image/gif,png:image/png,bmp:image/bmp,css:text/css,js:text/plain" + +#define AUTHUSER "root" +#define AUTHPASSWORD "oxmox" +#define PRIVATEDOCUMENTROOT "/tmp/web" //FIXME: Test +#define PUBLICDOCUMENTROOT "/var/httpd" +#define HOSTEDDOCUMENTROOT "/mnt/hosted" + +#define SSL_PEMFILE HTTPD_CONFIGDIR "/server.pem" +#define SSL_CA_FILE HTTPD_CONFIGDIR "/cacert.pem" + +#define UPLOAD_TMP_FILE "/tmp/upload.tmp" +#define CACHE_DIR "/tmp/.cache" +#endif + +//----------------------------------------------------------------------------- +// Configurations for Maxtor Shared Storage +//----------------------------------------------------------------------------- +#ifdef CONFIG_SYSTEM_MSS +#define HTTPD_STANDARD_PORT 81 +#define HTTPD_MAX_CONNECTIONS 3 +#define HTTPD_CONFIGDIR "/tmp" +#define HTTPD_CONFIGFILE HTTPD_CONFIGDIR "/yhttpd.conf" +#define HTTPD_REQUEST_LOG "/tmp/httpd_log" +#define HTTPD_ERRORPAGE "/Y_ErrorPage.yhtm" +#define HTTPD_SENDFILE_EXT "htm:text/html,html:text/html,xml:text/xml,txt:text/plain,jpg:image/jpeg,jpeg:image/jpeg,gif:image/gif,png:image/png,bmp:image/bmp,css:text/css,js:text/plain" + +#define AUTHUSER "root" +#define AUTHPASSWORD "oxmox" +#define PRIVATEDOCUMENTROOT "/shares/mss-hdd/Install/web" +#define PUBLICDOCUMENTROOT "/var/httpd" +#define HOSTEDDOCUMENTROOT "/mnt/hosted" + +#define SSL_PEMFILE HTTPD_CONFIGDIR "/server.pem" +#define SSL_CA_FILE HTTPD_CONFIGDIR "/cacert.pem" + +#define UPLOAD_TMP_FILE "/tmp/upload.tmp" +#define CACHE_DIR "/tmp/.cache" +#endif + + +//----------------------------------------------------------------------------- +// Aggregated definitions +//----------------------------------------------------------------------------- +#define WEBSERVERNAME HTTPD_NAME "/" HTTPD_VERSION " (" YHTTPD_NAME "/" YHTTPD_VERSION ")" + +#endif // __yconfig_h__ diff --git a/src/nhttpd/yhttpd.cpp b/src/nhttpd/yhttpd.cpp new file mode 100644 index 000000000..f0e813de2 --- /dev/null +++ b/src/nhttpd/yhttpd.cpp @@ -0,0 +1,494 @@ +//============================================================================= +// YHTTPD +// Main Program +//============================================================================= + +// system +#include +#include +#include +#include +#include +#include + +// yhttpd +#include "yconfig.h" +#include "ylogging.h" +#include "yhook.h" + +#ifdef Y_CONFIG_USE_YPARSER +#include "mod_yparser.h" +static CyParser yParser; +#endif + +//----------------------------------------------------------------------------- +// Setting yhttpd Instance +//----------------------------------------------------------------------------- +#include "yhttpd.h" +static Cyhttpd *yhttpd = NULL; +CStringList Cyhttpd::ConfigList; +//============================================================================= +// HOOKS: Definition & Instance for Hooks, attach/detach Hooks +//============================================================================= + +#ifdef Y_CONFIG_USE_AUTHHOOK +#include "mod_auth.h" +static CmAuth *auth = NULL; +#endif + +#ifdef Y_CONFIG_USE_TESTHOOK +#include "mod_testhook.h" +static CTesthook *testhook = NULL; +#endif + +#ifdef Y_CONFIG_USE_WEBLOG +#include "mod_weblog.h" +static CmWebLog *weblog = NULL; +#endif + +#ifdef Y_CONFIG_USE_SENDFILE +#include "mod_sendfile.h" +static CmodSendfile *mod_sendfile = NULL; +#endif + +#ifdef Y_CONFIG_USE_CACHE +#include "mod_cache.h" +static CmodCache mod_cache; // static instance +#endif + +//----------------------------------------------------------------------------- +#ifdef CONFIG_SYSTEM_TUXBOX +#include "neutrinoapi.h" +static CNeutrinoAPI *NeutrinoAPI; +#endif + +//============================================================================= +// Main: Main Entry, Command line passing, Webserver Instance creation & Loop +//============================================================================= +volatile sig_atomic_t Cyhttpd::sig_do_shutdown = 0; +#if 0 +//----------------------------------------------------------------------------- +// Signal Handling +//----------------------------------------------------------------------------- +static void sig_catch(int msignal) +{ + aprintf("!!! SIGNAL !!! :%d!\n",msignal); + switch (msignal) { +// case SIGTERM: +// case SIGINT: + + case SIGPIPE: + aprintf("got signal PIPE, nice!\n"); + break; + case SIGHUP: + case SIGUSR1: + aprintf("got signal HUP/USR1, reading config\n"); + if (yhttpd) + yhttpd->ReadConfig(); + break; + default: + aprintf("No special SIGNAL-Handler:%d!\n",msignal); +// log_level_printf(1, "Got SIGTERM\n"); + Cyhttpd::sig_do_shutdown = 1; + yhttpd->stop_webserver(); + delete yhttpd; + exit(EXIT_SUCCESS); //FIXME: return to main() some way... + break; + + } +} +#endif + +void yhttpd_reload_config() +{ + if (yhttpd) + yhttpd->ReadConfig(); +} +//----------------------------------------------------------------------------- +// Main Entry +//----------------------------------------------------------------------------- +//int main(int argc, char **argv) +void * nhttpd_main_thread(void *data) +{ + //int argc = 1; + //char **argv; + //bool do_fork = false; + + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); + + aprintf("Webserver %s tid %ld\n", WEBSERVERNAME, syscall(__NR_gettid)); + yhttpd = new Cyhttpd(); + +//CLogging::getInstance()->setDebug(true); +//CLogging::getInstance()->LogLevel = 9; + if(!yhttpd) + { + aprintf("Error initializing WebServer\n"); + return (void *) EXIT_FAILURE; + } + yhttpd->flag_threading_off = true; +#if 0 + for (int i = 1; i < argc; i++) + { + if ((!strncmp(argv[i], "-d", 2)) || (!strncmp(argv[i], "--debug", 7))) + { + CLogging::getInstance()->setDebug(true); + do_fork = false; + } + else if ((!strncmp(argv[i], "-f", 2)) || (!strncmp(argv[i], "--fork", 6)) || (!strncmp(argv[i], "-nf", 3))) + { + do_fork = false; + } + else if ((!strncmp(argv[i], "-h", 2)) || (!strncmp(argv[i], "--help", 6))) + { + yhttpd->usage(stdout); + return (void *) EXIT_SUCCESS; + } + else if ((!strncmp(argv[i], "-v", 2)) || (!strncmp(argv[i],"--version", 9))) + { + yhttpd->version(stdout); + return (void *) EXIT_SUCCESS; + } + else if ((!strncmp(argv[i], "-t", 2)) || (!strncmp(argv[i],"--thread-off", 12))) + { + yhttpd->flag_threading_off = true; + } + else if ((!strncmp(argv[i], "-l", 2)) ) + { + if(argv[i][2] >= '0' && argv[i][2] <= '9') + CLogging::getInstance()->LogLevel = (argv[i][2]-'0'); + } + else + { + yhttpd->usage(stderr); + return (void *) EXIT_FAILURE; + } + } + // setup signal catching (subscribing) + //signal(SIGPIPE, sig_catch); + //signal(SIGINT, sig_catch); + //signal(SIGHUP, sig_catch); + //signal(SIGUSR1, sig_catch); + //signal(SIGTERM, sig_catch); + //signal(SIGCLD, SIG_IGN); +// signal(SIGALRM, sig_catch); +#endif + + yhttpd->hooks_attach(); + yhttpd->ReadConfig(); + if(yhttpd->Configure()) + { + // Start Webserver: fork ist if not in debug mode + aprintf("Webserver starting...\n"); + dprintf("Start in Debug-Mode\n"); // non forked debugging loop + + yhttpd->run(); + } + delete yhttpd; + + aprintf("Main end\n"); + return (void *) EXIT_SUCCESS; +} + +//============================================================================= +// Class yhttpd +//============================================================================= +Cyhttpd::Cyhttpd() +{ + webserver = new CWebserver(); + flag_threading_off = false; +} +//----------------------------------------------------------------------------- +Cyhttpd::~Cyhttpd() +{ + if(webserver) + delete webserver; + webserver = NULL; +} + +//----------------------------------------------------------------------------- +// Change to Root +//----------------------------------------------------------------------------- +bool Cyhttpd::Configure() +{ + + if(!getuid()) // you must be root to do that! + { + // Get user and group data +#ifdef Y_CONFIG_FEATURE_HTTPD_USER + struct passwd *pwd = NULL; + struct group *grp = NULL; + std::string username = ConfigList["server.user_name"]; + std::string groupname= ConfigList["server.group_name"]; + + // get user data + if(username != "") + { + if((pwd = getpwnam(username.c_str())) == NULL) + { + dperror("Dont know user to set uid\n"); + return false; + } + } + // get group data + if(groupname != "") + { + if((grp = getgrnam(groupname.c_str())) == NULL) + { + aprintf("Can not get Group-Information. Group: %s\n", groupname.c_str()); + return false; + } + } +#endif +// change root directory +#ifdef Y_CONFIG_FEATURE_CHROOT + if(!ConfigList["server.chroot"].empty()) + { + log_level_printf(2, "do chroot to dir:%s\n", ConfigList["server.chroot"].c_str() ); + // do change Root + if(chroot(ConfigList["server.chroot"].c_str()) == -1) + { + dperror("Change Root failed\n"); + return false; + } + // Set Working Dir + if(chdir("/") == -1) + { + dperror("Change Directory to Root failed\n"); + return false; + } + } +#endif +#ifdef Y_CONFIG_FEATURE_HTTPD_USER + if(username != "" && pwd != NULL && grp != NULL) + { + log_level_printf(2, "set user and groups\n"); + + // drop root privileges + setgid(grp->gr_gid); + setgroups(0, NULL); + // set user group + if(groupname != "") + initgroups(username.c_str(), grp->gr_gid); + // set user + if(setuid(pwd->pw_uid) == -1) + { + dperror("Change User Context failed\n"); + return false; + } + } +#endif + } + return true; +} +//----------------------------------------------------------------------------- +// Main Webserver call +//----------------------------------------------------------------------------- +void Cyhttpd::run() +{ + if(webserver) + { + if(flag_threading_off) + webserver->is_threading = false; + webserver->run(); + stop_webserver(); + } + else + aprintf("Error initializing WebServer\n"); +} + +//----------------------------------------------------------------------------- +// Show Version Text and Number +//----------------------------------------------------------------------------- +void Cyhttpd::version(FILE *dest) +{ + fprintf(dest, "%s - Webserver v%s\n", HTTPD_NAME, HTTPD_VERSION); +} + +//----------------------------------------------------------------------------- +// Show Usage +//----------------------------------------------------------------------------- +void Cyhttpd::usage(FILE *dest) +{ + version(dest); + fprintf(dest, "command line parameters:\n"); + fprintf(dest, "-d, --debug enable debugging code (implies -f)\n"); + fprintf(dest, "-f, --fork do not fork\n"); + fprintf(dest, "-h, --help display this text and exit\n\n"); + fprintf(dest, "-v, --version display version and exit\n"); + fprintf(dest, "-l, set loglevel (0 .. 9)\n"); + fprintf(dest, "-t, --thread-off set threading off\n"); +} + +//----------------------------------------------------------------------------- +// Stop WebServer +//----------------------------------------------------------------------------- +void Cyhttpd::stop_webserver() +{ + aprintf("stop requested......\n"); + if (webserver) { + webserver->stop(); + hooks_detach(); + } +} +//----------------------------------------------------------------------------- +// Attach hooks (use hook order carefully) +//----------------------------------------------------------------------------- +void Cyhttpd::hooks_attach() +{ +#ifdef Y_CONFIG_USE_AUTHHOOK + // First Check Authentication + auth = new CmAuth(); + CyhookHandler::attach(auth); +#endif + +#ifdef Y_CONFIG_USE_TESTHOOK + testhook = new CTesthook(); + CyhookHandler::attach(testhook); +#endif + +#ifdef CONFIG_SYSTEM_TUXBOX + NeutrinoAPI = new CNeutrinoAPI(); + CyhookHandler::attach(NeutrinoAPI->NeutrinoYParser); + CyhookHandler::attach(NeutrinoAPI->ControlAPI); +#else +#ifdef Y_CONFIG_USE_YPARSER + CyhookHandler::attach(&yParser); +#endif +#endif + +#ifdef Y_CONFIG_USE_CACHE + CyhookHandler::attach(&mod_cache); +#endif + +#ifdef Y_CONFIG_USE_SENDFILE + mod_sendfile = new CmodSendfile(); + CyhookHandler::attach(mod_sendfile); +#endif +#ifdef Y_CONFIG_USE_WEBLOG + weblog = new CmWebLog(); + CyhookHandler::attach(weblog); +#endif +} + +//----------------------------------------------------------------------------- +// Detach hooks & Destroy +//----------------------------------------------------------------------------- +void Cyhttpd::hooks_detach() +{ +#ifdef Y_CONFIG_USE_AUTHHOOK + CyhookHandler::detach(auth); + delete auth; +#endif + +#ifdef Y_CONFIG_USE_TESTHOOK + CyhookHandler::detach(testhook); + delete testhook; +#endif + +#ifdef CONFIG_SYSTEM_TUXBOX + CyhookHandler::detach(NeutrinoAPI->NeutrinoYParser); +#else +#ifdef Y_CONFIG_USE_YPARSER + CyhookHandler::detach(&yParser); +#endif +#endif + +#ifdef Y_CONFIG_USE_CACHE + CyhookHandler::detach(&mod_cache); +#endif + +#ifdef Y_CONFIG_USE_SENDFILE + CyhookHandler::detach(mod_sendfile); +#endif + +#ifdef Y_CONFIG_USE_WEBLOG + CyhookHandler::detach(weblog); + delete weblog; +#endif +} + +//----------------------------------------------------------------------------- +// Read Webserver Configurationfile +// Call "Hooks_ReadConfig" so Hooks can read/write own Configuration Values +//----------------------------------------------------------------------------- +void Cyhttpd::ReadConfig(void) +{ + log_level_printf(3,"ReadConfig Start\n"); + CConfigFile *Config = new CConfigFile(','); + bool have_config = false; + if(access(HTTPD_CONFIGFILE,4) == 0) + have_config = true; + Config->loadConfig(HTTPD_CONFIGFILE); + // convert old config files + if(have_config) + if(Config->getInt32("Port", 0) != 0) + { + CConfigFile OrgConfig = *Config; + Config->clear(); + + Config->setInt32("server.log.loglevel", OrgConfig.getInt32("LogLevel", 0)); + Config->setString("configfile.version", "1"); + Config->setString("webserver.websites", "WebsiteMain"); + Config->setBool("webserver.threading", OrgConfig.getBool("THREADS", true)); + Config->setInt32("WebsiteMain.port",OrgConfig.getInt32("Port", HTTPD_STANDARD_PORT)); + Config->setString("WebsiteMain.directory", OrgConfig.getString("PrivatDocRoot", PRIVATEDOCUMENTROOT)); + if(OrgConfig.getString("PublicDocRoot", "") != "") + Config->setString("WebsiteMain.override_directory", OrgConfig.getString("PublicDocRoot", PRIVATEDOCUMENTROOT)); + if(OrgConfig.getString("HostedDocRoot", "") != "") + Config->setString("WebsiteMain.special_locations", "/hosted/="+OrgConfig.getString("HostedDocRoot", PRIVATEDOCUMENTROOT)); + if(OrgConfig.getString("HostedDocRoot", "") != "") + Config->setString("Tuxbox.HostedDocumentRoot", OrgConfig.getString("HostedDocRoot", PRIVATEDOCUMENTROOT)); + // mod_auth + Config->setString("mod_auth.username", OrgConfig.getString("AuthUser", AUTHUSER)); + Config->setString("mod_auth.password", OrgConfig.getString("AuthPassword", AUTHPASSWORD)); + Config->setString("mod_auth.no_auth_client", OrgConfig.getString("NoAuthClient", "")); + Config->setString("mod_auth.authenticate", OrgConfig.getString("Authenticate", "false")); + + Config->setString("mod_sendfile.mime_types", HTTPD_SENDFILE_EXT); + + Config->saveConfig(HTTPD_CONFIGFILE); + + } + // configure debugging & logging + if(CLogging::getInstance()->LogLevel == 0) + CLogging::getInstance()->LogLevel = Config->getInt32("server.log.loglevel", 0); + + // get variables + webserver->init(Config->getInt32("WebsiteMain.port", HTTPD_STANDARD_PORT), Config->getBool("webserver.threading", true)); + // informational use + ConfigList["WebsiteMain.port"]= itoa(Config->getInt32("WebsiteMain.port", HTTPD_STANDARD_PORT)); + ConfigList["webserver.threading"]= Config->getString("webserver.threading", "true"); + ConfigList["configfile.version"]= Config->getString("configfile.version", "1"); + ConfigList["server.log.loglevel"]= itoa(Config->getInt32("server.log.loglevel", 0)); + ConfigList["server.no_keep-alive_ips"]= Config->getString("server.no_keep-alive_ips", ""); + webserver->conf_no_keep_alive_ips = Config->getStringVector("server.no_keep-alive_ips"); + + // MainSite + ConfigList["PrivatDocumentRoot"]= Config->getString("WebsiteMain.directory", PRIVATEDOCUMENTROOT); + ConfigList["PublicDocumentRoot"]= Config->getString("WebsiteMain.override_directory", PUBLICDOCUMENTROOT); + ConfigList["HostedDocumentRoot"]= Config->getString("Tuxbox.HostedDocumentRoot", HOSTEDDOCUMENTROOT); +#ifdef Y_CONFIG_USE_OPEN_SSL + ConfigList["SSL"] = Config->getString("WebsiteMain.ssl", "false"); + ConfigList["SSL_pemfile"] = Config->getString("WebsiteMain.ssl_pemfile", SSL_PEMFILE); + ConfigList["SSL_CA_file"] = Config->getString("WebsiteMain.ssl_ca_file", SSL_CA_FILE); + + CySocket::SSL_pemfile = ConfigList["SSL_pemfile"]; + CySocket::SSL_CA_file = ConfigList["SSL_CA_file"]; + if(ConfigList["SSL"] == "true") + CySocket::initSSL(); +#endif + ConfigList["server.user_name"]= Config->getString("server.user_name", ""); + ConfigList["server.group_name"]= Config->getString("server.group_name", ""); + ConfigList["server.chroot"]= Config->getString("server.chroot", ""); + + + // Read App specifig settings by Hook + CyhookHandler::Hooks_ReadConfig(Config, ConfigList); + + // Save if new defaults are set + if (!have_config) + Config->saveConfig(HTTPD_CONFIGFILE); + log_level_printf(3,"ReadConfig End\n"); + delete Config; +} diff --git a/src/nhttpd/yhttpd.h b/src/nhttpd/yhttpd.h new file mode 100644 index 000000000..507ad259c --- /dev/null +++ b/src/nhttpd/yhttpd.h @@ -0,0 +1,50 @@ +//============================================================================= +// YHTTPD +// Main Class +//----------------------------------------------------------------------------- +// Cyhttpd +// Main Function and Class for Handlicg the Webserver-Application +// - Handles Command Line Input +// - Reads and Handles "ReadConfig" (inclusive Hooking) +// - Creates Webserver and start them listening +//============================================================================= +#ifndef __yhttpd_h__ +#define __yhttpd_h__ +// system +#include +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "ywebserver.h" + + +//----------------------------------------------------------------------------- +class Cyhttpd +{ +private: + CWebserver *webserver; // Aggregation of Webserver (now: only one) + +public: + bool flag_threading_off; // switch of Connection Threading + static CStringList ConfigList; // Vars & Values from ReadConfig + + // signal handler + static volatile sig_atomic_t sig_do_shutdown; + + // constructor & destructor + Cyhttpd(); + ~Cyhttpd(); + + // Main Programm calls + void run(); // Init Hooks, ReadConfig, Start Webserver + bool Configure(); + void stop_webserver(); // Remove Hooks, Stop Webserver + static void version(FILE *dest); // Show Webserver Version + static void usage(FILE *dest); // Show command line usage + // Hooks + void hooks_attach(); // Add a Hook-Class to HookList + void hooks_detach(); // Remove a Hook-Class from HookList + void ReadConfig(void); // Read the config file for the webserver +}; + +#endif // __yhttpd_h__ diff --git a/src/nhttpd/yhttpd_core/AUTHORS b/src/nhttpd/yhttpd_core/AUTHORS new file mode 100644 index 000000000..ca6361b99 --- /dev/null +++ b/src/nhttpd/yhttpd_core/AUTHORS @@ -0,0 +1,4 @@ +The code-base of yhttpd is Tuxbox-nhttpd 2.x (cvs.tuxbox.org) + +Authors since re-writting of yhttpd: +Johannes Golombek [yjogol@cvs.tuxbox.org] diff --git a/src/nhttpd/yhttpd_core/Makefile.am b/src/nhttpd/yhttpd_core/Makefile.am new file mode 100644 index 000000000..1cd16c57f --- /dev/null +++ b/src/nhttpd/yhttpd_core/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/nhttpd \ + -I$(top_srcdir)/lib/connection \ + -I$(top_srcdir)/lib/libeventserver \ + -I$(top_srcdir)/lib/libconfigfile \ + @FREETYPE_CFLAGS@ + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +noinst_LIBRARIES = libyhttpd.a + +libyhttpd_a_SOURCES = \ + ylogging.cpp helper.cpp \ + ywebserver.cpp yconnection.cpp yrequest.cpp yresponse.cpp yhook.cpp ysocket.cpp + diff --git a/src/nhttpd/yhttpd_core/README b/src/nhttpd/yhttpd_core/README new file mode 100644 index 000000000..f4bb97634 --- /dev/null +++ b/src/nhttpd/yhttpd_core/README @@ -0,0 +1,22 @@ +------------------------------------------------------------------------------ +yhttpd-GOALS +(yjogol@online.de, August 2006) +------------------------------------------------------------------------------ +The yhttpd-Webserver is a small C++ based Webserver for embedded Systems. +It has a simple Software-Architecture and uses for string-operations +mostly buffer-save functions to prevent security exploits like buffer overruns. +It is designed for threading and multiuser access for static files. +It can be compiled on Windows Systems using Cygwin, on Linux-Systems +and had been succesfully compiled for AVM Fritzbox or for +Maxtor Shared Storage. + +The code-base of yhttpd is Tuxbox-nhttpd 2.x (cvs.tuxbox.org) + +Starting with Version 3.0 the nhttpd source code was splitted into +a core Webserver (yhttpd_core) and extension modules (yhttpd_mods). + +The yhttpd_core and yhttp_mods ware completly rewritten. + +The Hook-System (extension modules) encapsulate all requests and responses +for the tuxboxapi. So both tuxapi and yhttpd can be developed seperatlly and +independ from each other. \ No newline at end of file diff --git a/src/nhttpd/yhttpd_core/helper.cpp b/src/nhttpd/yhttpd_core/helper.cpp new file mode 100644 index 000000000..7490e090b --- /dev/null +++ b/src/nhttpd/yhttpd_core/helper.cpp @@ -0,0 +1,280 @@ +//============================================================================= +// YHTTPD +// Helper +//============================================================================= + +// c +#include // printf prototype. +#include // calloc and free prototypes. +#include // str* and memset prototypes. +#include + +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "helper.h" +#include "ylogging.h" + +//============================================================================= +// Integers +//============================================================================= +//------------------------------------------------------------------------- +// Check and set integer inside boundaries (min, max) +//------------------------------------------------------------------------- +int minmax(int value,int min, int max) +{ + if(value < min) return min; + if(value > max) return max; + return value; +} +//============================================================================= +// Date & Time +//============================================================================= +//------------------------------------------------------------------------- +// Check and set Date/Time (tm*) inside boundaries +//------------------------------------------------------------------------- +void correctTime(struct tm *zt) +{ + + zt->tm_year = minmax(zt->tm_year,0,129); + zt->tm_mon = minmax(zt->tm_mon,0,11); + zt->tm_mday = minmax(zt->tm_mday,1,31); //-> eine etwas laxe pruefung, aber mktime biegt das wieder grade + zt->tm_hour = minmax(zt->tm_hour,0,23); + zt->tm_min = minmax(zt->tm_min,0,59); + zt->tm_sec = minmax(zt->tm_sec,0,59); +} +//============================================================================= +// Strings +//============================================================================= +//------------------------------------------------------------------------- +// Integer to Hexadecimal-String +//------------------------------------------------------------------------- +std::string itoh(unsigned int conv) +{ + return string_printf("0x%06x",conv); +} +//------------------------------------------------------------------------- +// Integer to String +//------------------------------------------------------------------------- +std::string itoa(unsigned int conv) +{ + return string_printf("%u",conv); +} +//------------------------------------------------------------------------- +// convert timer_t to ":" String +//------------------------------------------------------------------------- +std::string timeString(time_t time) +{ + char tmp[7]={'\0'}; + struct tm *tm = localtime(&time); + if (strftime(tmp, 6, "%H:%M", tm)) + return std::string(tmp); + else + return std::string("??:??"); +} +//------------------------------------------------------------------------- +// Printf and return formatet String. Buffer-save! +// max length up to bufferlen -> then snip +//------------------------------------------------------------------------- +#define bufferlen 4*1024 +std::string string_printf(const char *fmt, ...) +{ + char buffer[bufferlen]; + va_list arglist; + va_start( arglist, fmt ); + if(arglist) + vsnprintf( buffer, bufferlen, fmt, arglist ); + va_end(arglist); + return std::string(buffer); +} +//------------------------------------------------------------------------- +// ySplitString: spit string "str" in two strings "left" and "right" at +// one of the chars in "delimiter" returns true if delimiter found +//------------------------------------------------------------------------- +bool ySplitString(std::string str, std::string delimiter, std::string& left, std::string& right) +{ + unsigned int pos; + if ((pos = str.find_first_of(delimiter)) != std::string::npos) + { + left = str.substr(0, pos); + right = str.substr(pos + 1, str.length() - (pos + 1 )); + } + else + { + left = str; //default if not found + right = ""; + } + return (pos != std::string::npos); +} +//------------------------------------------------------------------------- +// ySplitString: spit string "str" in two strings "left" and "right" at +// one of the chars in "delimiter" returns true if delimiter found +//------------------------------------------------------------------------- +bool ySplitStringExact(std::string str, std::string delimiter, std::string& left, std::string& right) +{ + unsigned int pos; + if ((pos = str.find(delimiter)) != std::string::npos) + { + left = str.substr(0, pos); + right = str.substr(pos + delimiter.length(), str.length() - (pos + delimiter.length() )); + } + else + { + left = str; //default if not found + right = ""; + } + return (pos != std::string::npos); +} +//------------------------------------------------------------------------- +// ySplitStringRight: spit string "str" in two strings "left" and "right" at +// one of the chars in "delimiter" returns true if delimiter found +//------------------------------------------------------------------------- +bool ySplitStringLast(std::string str, std::string delimiter, std::string& left, std::string& right) +{ + unsigned int pos; + if ((pos = str.find_last_of(delimiter)) != std::string::npos) + { + left = str.substr(0, pos); + right = str.substr(pos + 1, str.length() - (pos + 1 )); + } + else + { + left = str; //default if not found + right = ""; + } + return (pos != std::string::npos); +} +//------------------------------------------------------------------------- +// ySplitStringVector: spit string "str" and build vector of strings +//------------------------------------------------------------------------- +CStringArray ySplitStringVector(std::string str, std::string delimiter) +{ + std::string left, right, rest; + bool found; + CStringArray split; + rest = str; + do + { + found = ySplitString(rest, delimiter, left, right); + split.push_back(left); + rest = right; + } + while(found); + return split; +} +//------------------------------------------------------------------------- +// trim whitespaces +//------------------------------------------------------------------------- +std::string trim(std::string const& source, char const* delims) +{ + std::string result(source); + std::string::size_type index = result.find_last_not_of(delims); + if(index != std::string::npos) + result.erase(++index); + + index = result.find_first_not_of(delims); + if(index != std::string::npos) + result.erase(0, index); + else + result.erase(); + return result; +} +//------------------------------------------------------------------------- +// equal-function for case insensitive compare +//------------------------------------------------------------------------- +bool nocase_compare (char c1, char c2) +{ + return toupper(c1) == toupper(c2); +} +//----------------------------------------------------------------------------- +// Decode URLEncoded std::string +//----------------------------------------------------------------------------- +std::string decodeString(std::string encodedString) +{ + const char *string = encodedString.c_str(); + unsigned int count=0; + char hex[3]={'\0'}; + unsigned long iStr; + std::string result = ""; + count = 0; + + while(count +#include +// c++ +#include +#include +#include "ytypes_globals.h" + +//----------------------------------------------------------------------------- +int minmax(int value,int min, int max); +void correctTime(struct tm *zt); + +//----------------------------------------------------------------------------- +// String Converter +//----------------------------------------------------------------------------- +std::string itoa(unsigned int conv); +std::string itoh(unsigned int conv); +std::string decodeString(std::string encodedString); +std::string encodeString(std::string decodedString); +std::string string_tolower(std::string str); + +//----------------------------------------------------------------------------- +// String Helpers +//----------------------------------------------------------------------------- +std::string trim(std::string const& source, char const* delims = " \t\r\n"); +std::string string_printf(const char *fmt, ...); +bool ySplitString(std::string str, std::string delimiter, std::string& left, std::string& right); +bool ySplitStringExact(std::string str, std::string delimiter, std::string& left, std::string& right); +bool ySplitStringLast(std::string str, std::string delimiter, std::string& left, std::string& right); +CStringArray ySplitStringVector(std::string str, std::string delimiter); +bool nocase_compare (char c1, char c2); +std::string timeString(time_t time); +bool write_to_file(std::string filename, std::string content); + +#endif /* __yhttpd_helper_h__ */ diff --git a/src/nhttpd/yhttpd_core/yconnection.cpp b/src/nhttpd/yhttpd_core/yconnection.cpp new file mode 100644 index 000000000..d047563ad --- /dev/null +++ b/src/nhttpd/yhttpd_core/yconnection.cpp @@ -0,0 +1,147 @@ +//============================================================================= +// YHTTPD +// Connection +//============================================================================= + +// system +#include +#include +#include +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "ywebserver.h" +#include "yconnection.h" +#include "helper.h" +//============================================================================= +// Initialization of static variables +//============================================================================= +long CWebserverConnection::GConnectionNumber = 0; + +//============================================================================= +// Constructor & Destructor & Initialization +//============================================================================= +CWebserverConnection::CWebserverConnection(CWebserver *pWebserver) +{ + Webserver = pWebserver; + Request.Webserver = pWebserver; + Request.Connection = this; + Response.Webserver = pWebserver; + Response.Connection = this; + Method = M_UNKNOWN; + HttpStatus = 0; + RequestCanceled = false; +#ifdef Y_CONFIG_FEATURE_KEEP_ALIVE + keep_alive = true; +#else + keep_alive = false; +#endif +} +//------------------------------------------------------------------------- +CWebserverConnection::CWebserverConnection() +{ +// aprintf("test CWebserverConnection::CWebserverConnection()\n"); + ConnectionNumber = ++GConnectionNumber; +} +//------------------------------------------------------------------------- +CWebserverConnection::~CWebserverConnection(void) +{ +} +//------------------------------------------------------------------------- +// End The Connection. Request and Response allready handled. +// do "after done" work, like create a www-Log entry. +// Use "Hooks_EndConnection()" Handler to write own Hooks. +//------------------------------------------------------------------------- +void CWebserverConnection::EndConnection() +{ + HookHandler.HookVarList["enlapsed_request"] = itoa(enlapsed_request/1000); + HookHandler.HookVarList["enlapsed_response"] = itoa(enlapsed_response/1000); + HookHandler.Hooks_EndConnection(); // Handle Hooks + if(RequestCanceled) // Canceled + keep_alive = false; + RequestCanceled = true; +// sock->Flush(); +#ifndef Y_CONFIG_FEATURE_KEEP_ALIVE + sock->close(); +#endif +} +//------------------------------------------------------------------------- +// Main +// Handle the Request, Handle (Send) Response), End the Connection +//------------------------------------------------------------------------- +void CWebserverConnection::HandleConnection() +{ + gettimeofday(&tv_connection_start, &tz_connection_start); + + // get the request + if (Request.HandleRequest()) + { + // determine time from Connection creation until now + gettimeofday(&tv_connection_Response_start, &tz_connection_Response_start); + enlapsed_request = ((tv_connection_Response_start.tv_sec - tv_connection_start.tv_sec) * 1000000 + + (tv_connection_Response_start.tv_usec - tv_connection_start.tv_usec)); + + // Keep-Alive checking +#ifdef Y_CONFIG_FEATURE_KEEP_ALIVE + if(string_tolower(Request.HeaderList["Connection"]) == "close" + || (httprotocol != "HTTP/1.1" && string_tolower(Request.HeaderList["Connection"]) != "keep-alive") + || !Webserver->CheckKeepAliveAllowedByIP(sock->get_client_ip())) + keep_alive = false; +#else + keep_alive = false; +#endif + // Send a response + Response.SendResponse(); + + // determine time for SendResponse + gettimeofday(&tv_connection_Response_end, &tz_connection_Response_end); + enlapsed_response = ((tv_connection_Response_end.tv_sec - tv_connection_Response_start.tv_sec) * 1000000 + + (tv_connection_Response_end.tv_usec - tv_connection_Response_start.tv_usec)); + + // print production times + log_level_printf(1,"enlapsed time request:%ld response:%ld url:%s\n", + enlapsed_request, enlapsed_response, (Request.UrlData["fullurl"]).c_str()); + + } + else + { + RequestCanceled = true; + keep_alive = false; // close this connection socket +// dperror("Error while parsing request\n"); + log_level_printf(1,"request canceled: %s\n", strerror(errno)); + } + EndConnection(); +} + +//------------------------------------------------------------------------- +void CWebserverConnection::ShowEnlapsedRequest(char *text) +{ + + long enlapsed = GetEnlapsedRequestTime() / 1000; + log_level_printf(1,"enlapsed-f-start (%s) t:%ld url:%s\n", + text, enlapsed, (Request.UrlData["fullurl"]).c_str()); +} +//------------------------------------------------------------------------- +// Time from creation of socket until now in microseconds! +//------------------------------------------------------------------------- +long CWebserverConnection::GetEnlapsedRequestTime() +{ + struct timeval tv_now; + struct timezone tz_now; + gettimeofday(&tv_now, &tz_now); + return ((tv_now.tv_sec - tv_connection_start.tv_sec) * 1000000 + + (tv_now.tv_usec - tv_connection_start.tv_usec)); +} + +//------------------------------------------------------------------------- +// Time from beginning of response until now in microseconds! +//------------------------------------------------------------------------- +long CWebserverConnection::GetEnlapsedResponseTime() +{ + struct timeval tv_now; + struct timezone tz_now; + gettimeofday(&tv_now, &tz_now); + return ((tv_now.tv_sec - tv_connection_Response_start.tv_sec) * 1000000 + + (tv_now.tv_usec - tv_connection_Response_start.tv_usec)); +} + diff --git a/src/nhttpd/yhttpd_core/yconnection.h b/src/nhttpd/yhttpd_core/yconnection.h new file mode 100644 index 000000000..50dca5580 --- /dev/null +++ b/src/nhttpd/yhttpd_core/yconnection.h @@ -0,0 +1,73 @@ +//============================================================================= +// YHTTPD +// Connection +//----------------------------------------------------------------------------- +// The Connection Class handles a given Socket-Connection for an arriving +// Request. Normally many Connections exists and they are Threaded! +// "HandleConnection()" calls "HandleRequest()" and "SendResponse()" +//============================================================================= +#ifndef __yhttpd_connection_h__ +#define __yhttpd_connection_h__ + +// system +#include +// c++ +#include +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "ywebserver.h" +#include "yrequest.h" +#include "yresponse.h" + +// Forward definition +class CWebserver; + +//----------------------------------------------------------------------------- +class CWebserverConnection +{ +public: + class CWebserver *Webserver; // Backreference + CWebserverRequest Request; // http Request + CWebserverResponse Response; // http Response + CyhookHandler HookHandler; // One Instance per Connection + + CySocket *sock; // Connection Socket + bool RequestCanceled; // Canceled flag + static long GConnectionNumber; // Number of Connection. Global counter + long ConnectionNumber; // Number of Connection since Webserver start. Local number + bool keep_alive; // should the response keep-alive socket? + + THttp_Method Method; // http Method (GET, POST,...) + int HttpStatus; // http response code + std::string httprotocol; // HTTP 1.x + + long enlapsed_request, // time for request in usec + enlapsed_response; // time for response in usec + + CWebserverConnection(CWebserver *pWebserver); // Constructor with given Backreferece + CWebserverConnection(); + ~CWebserverConnection(void); + + void HandleConnection(); // Main: Handle the Connecten Live time + + // performance/time measurement + void ShowEnlapsedRequest(char *text); // Print text and time difference to Connection creation + long GetEnlapsedRequestTime(); // Get time in micro-seconds from Connection creation + long GetEnlapsedResponseTime(); // Get time in micro-seconds after Request handles. Start Respnse. + +private: + void EndConnection(); // End Connection Handling + + // performance/time measurement + struct timeval tv_connection_start, + tv_connection_Response_start, + tv_connection_Response_end; + struct timezone tz_connection_start, + tz_connection_Response_start, + tz_connection_Response_end; + + +}; + +#endif /* __yhttpd_connection_h__ */ diff --git a/src/nhttpd/yhttpd_core/yhook.cpp b/src/nhttpd/yhttpd_core/yhook.cpp new file mode 100644 index 000000000..a49ba0222 --- /dev/null +++ b/src/nhttpd/yhttpd_core/yhook.cpp @@ -0,0 +1,357 @@ +//============================================================================= +// YHTTPD +// Hook and HookHandler +//============================================================================= +// C +#include +#include +#include + +// yhttpd +#include "yhook.h" +#include "ylogging.h" +#include "helper.h" + +//============================================================================= +// Initialization of static variables +//============================================================================= +THookList CyhookHandler::HookList; + +//============================================================================= +// Hook Handling +//============================================================================= +//----------------------------------------------------------------------------- +// Hook Dispatcher for Session Hooks +// Execute every Hook in HookList until State change != HANDLED_NONE +//----------------------------------------------------------------------------- +THandleStatus CyhookHandler::Hooks_SendResponse() +{ + log_level_printf(4,"Response Hook-List Start\n"); + THandleStatus _status = HANDLED_NONE; + THookList::iterator i = HookList.begin(); + for ( ; i!= HookList.end(); i++ ) + { + log_level_printf(4,"Response Hook-List (%s) Start\n", ((*i)->getHookName()).c_str()); + // response Hook + _status = (*i)->Hook_SendResponse(this); + log_level_printf(4,"Response Hook-List (%s) End. Status (%d)\n", ((*i)->getHookName()).c_str(), status); + if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE)) + break; + } + log_level_printf(4,"Response Hook-List End\n"); + log_level_printf(8,"Response Hook-List Result:\n%s\n", yresult.c_str()); + status = _status; + return _status; +} +//----------------------------------------------------------------------------- +// Hook Dispatcher for Session Hooks +// Execute every Hook in HookList until State change != HANDLED_NONE +//----------------------------------------------------------------------------- +THandleStatus CyhookHandler::Hooks_PrepareResponse() +{ + log_level_printf(4,"PrepareResponse Hook-List Start\n"); + THandleStatus _status = HANDLED_NONE; + THookList::iterator i = HookList.begin(); + for ( ; i!= HookList.end(); i++ ) + { + log_level_printf(4,"PrepareResponse Hook-List (%s) Start\n", ((*i)->getHookName()).c_str()); + // response Hook + _status = (*i)->Hook_PrepareResponse(this); + log_level_printf(4,"PrepareResponse Hook-List (%s) End. Status (%d) HTTP Status (%d)\n", ((*i)->getHookName()).c_str(), status, httpStatus); + if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE)) + break; + } + log_level_printf(4,"PrepareResponse Hook-List End\n"); + log_level_printf(8,"PrepareResponse Hook-List Result:\n%s\n", yresult.c_str()); + status = _status; + return _status; +} + +//----------------------------------------------------------------------------- +// Hook Dispatcher for Server based Hooks +// Execute every Hook in HookList until State change != HANDLED_NONE and +// != HANDLED_CONTINUE +//----------------------------------------------------------------------------- +THandleStatus CyhookHandler::Hooks_ReadConfig(CConfigFile *Config, CStringList &ConfigList) +{ + log_level_printf(4,"ReadConfig Hook-List Start\n"); + THandleStatus _status = HANDLED_NONE; + THookList::iterator i = HookList.begin(); + for ( ; i!= HookList.end(); i++ ) + { +// log_level_printf(4,"ReadConfig Hook-List (%s) Start\n", ((*i)->getHookName()).c_str()); + // response Hook + _status = (*i)->Hook_ReadConfig(Config, ConfigList); + log_level_printf(4,"ReadConfig Hook-List (%s) Status (%d)\n", ((*i)->getHookName()).c_str(), _status); + if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE)) + break; + } + log_level_printf(4,"ReadConfig Hook-List End\n"); + return _status; +} +//----------------------------------------------------------------------------- +// Hook Dispatcher for EndConnection +//----------------------------------------------------------------------------- +THandleStatus CyhookHandler::Hooks_EndConnection() +{ + log_level_printf(4,"EndConnection Hook-List Start\n"); + THandleStatus _status = HANDLED_NONE; + THookList::iterator i = HookList.begin(); + for ( ; i!= HookList.end(); i++ ) + { + log_level_printf(4,"EndConnection Hook-List (%s) Start\n", ((*i)->getHookName()).c_str()); + // response Hook + _status = (*i)->Hook_EndConnection(this); + log_level_printf(4,"EndConnection Hook-List (%s) End. Status (%d)\n", ((*i)->getHookName()).c_str(), _status); + if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE)) + break; + } + log_level_printf(4,"EndConnection Hook-List End\n"); + status = _status; + return _status; +} +//----------------------------------------------------------------------------- +// Hook Dispatcher for UploadSetFilename +//----------------------------------------------------------------------------- +THandleStatus CyhookHandler::Hooks_UploadSetFilename(std::string &Filename) +{ + log_level_printf(4,"UploadSetFilename Hook-List Start. Filename:(%s)\n", Filename.c_str()); + THandleStatus _status = HANDLED_NONE; + THookList::iterator i = HookList.begin(); + for ( ; i!= HookList.end(); i++ ) + { + log_level_printf(4,"UploadSetFilename Hook-List (%s) Start\n", ((*i)->getHookName()).c_str()); + // response Hook + _status = (*i)->Hook_UploadSetFilename(this, Filename); + log_level_printf(4,"UploadSetFilename Hook-List (%s) End. Status (%d)\n", ((*i)->getHookName()).c_str(), _status); + if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE)) + break; + } + log_level_printf(4,"UploadSetFilename Hook-List End\n"); + status = _status; + return _status; +} +//----------------------------------------------------------------------------- +// Hook Dispatcher for UploadSetFilename +//----------------------------------------------------------------------------- +THandleStatus CyhookHandler::Hooks_UploadReady(const std::string& Filename) +{ + log_level_printf(4,"UploadReady Hook-List Start. Filename:(%s)\n", Filename.c_str()); + THandleStatus _status = HANDLED_NONE; + THookList::iterator i = HookList.begin(); + for ( ; i!= HookList.end(); i++ ) + { + log_level_printf(4,"UploadReady Hook-List (%s) Start\n", ((*i)->getHookName()).c_str()); + // response Hook + _status = (*i)->Hook_UploadReady(this, Filename); + log_level_printf(4,"UploadReady Hook-List (%s) End. Status (%d)\n", ((*i)->getHookName()).c_str(), _status); + if((_status != HANDLED_NONE) && (_status != HANDLED_CONTINUE)) + break; + } + log_level_printf(4,"UploadReady Hook-List End\n"); + status = _status; + return _status; +} + +//============================================================================= +// Output helpers +//============================================================================= +void CyhookHandler::session_init(CStringList _ParamList, CStringList _UrlData, CStringList _HeaderList, + CStringList& _ConfigList, THttp_Method _Method, bool _keep_alive) +{ + ParamList = _ParamList; + UrlData = _UrlData; + HeaderList = _HeaderList; + WebserverConfigList = _ConfigList; + Method = _Method; + status = HANDLED_NONE; + httpStatus = HTTP_OK; + ContentLength = 0; + LastModified = (time_t)-1; + keep_alive = _keep_alive; + HookVarList.clear(); +} + +//============================================================================= +// Build Header +//----------------------------------------------------------------------------- +// RFC 2616 / 6 Response (Header) +// +// The first line of a Response message is the Status-Line, consisting +// of the protocol version followed by a numeric status code and its +// associated textual phrase, with each element separated by SP +// characters. No CR or LF is allowed except in the final CRLF sequence. +// +// Response =Status-Line ; generated by SendHeader +// *(( general-header +// | response-header +// | entity-header ) CRLF) +// CRLF ; generated by SendHeader +// [ message-body ] ; by HOOK Handling Loop or Sendfile +// +// Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF ; generated by SendHeader +// +// general-header = Cache-Control ; not implemented +// | Connection ; implemented +// | Date ; implemented +// | Pragma ; not implemented +// | Trailer ; not implemented +// | Transfer-Encoding ; not implemented +// | Upgrade ; not implemented +// | Via ; not implemented +// | Warning ; not implemented +// +// response-header = Accept-Ranges ; not implemented +// | Age ; not implemented +// | ETag ; not implemented +// | Location ; implemented (redirection / Object moved) +// | Proxy-Authenticate ; not implemented +// | Retry-After ; not implemented +// | Server ; implemented +// | Vary ; not implemented +// | WWW-Authenticate ; implemented (by mod_auth and SendHeader) +// +// entity-header = Allow ; not implemented +// | Content-Encoding ; not implemented +// | Content-Language ; not implemented +// | Content-Length ; implemented +// | Content-Location ; not implemented +// | Content-MD5 ; not implemented +// | Content-Range ; not implemented +// | Content-Type ; implemented +// | Expires ; not implemented +// | Last-Modified ; implemented for static files +// | extension-header +// +// extension-header = message-header +//============================================================================= +std::string CyhookHandler::BuildHeader(bool cache) +{ + std::string result=""; + + const char *responseString = ""; + const char *infoString = 0; + + // get Info Index + for (unsigned int i = 0;i < (sizeof(httpResponseNames)/sizeof(httpResponseNames[0])); i++) + if (httpResponseNames[i].type == httpStatus) + { + responseString = httpResponseNames[i].name; + infoString = httpResponseNames[i].info; + break; + } + // print Status-line + result = string_printf(HTTP_PROTOCOL " %d %s\r\nContent-Type: %s\r\n",httpStatus, responseString, ResponseMimeType.c_str()); + log_level_printf(2,"Respose: HTTP/1.1 %d %s\r\nContent-Type: %s\r\n",httpStatus, responseString, ResponseMimeType.c_str()); + + switch (httpStatus) + { + case HTTP_UNAUTHORIZED: + result += "WWW-Authenticate: Basic realm=\""; + result += AUTH_NAME_MSG "\r\n"; + break; + + case HTTP_MOVED_TEMPORARILY: + case HTTP_MOVED_PERMANENTLY: + // Status HTTP_*_TEMPORARILY (redirection) + result += string_printf("Location: %s\r\n",NewURL.c_str()); + // NO break HERE !!! + + default: + time_t timer = time(0); + char timeStr[80]; + // cache + if(!cache && (HookVarList["CacheCategory"]).empty() ) + result += "Cache-Control: no-cache\r\n"; + else + { + time_t x_time = time(NULL); + struct tm *ptm = gmtime(&x_time); + ptm->tm_mday+=1; + x_time = mktime(ptm); + strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&x_time)); + result += string_printf("Expires: %s\r\n", timeStr); + } + result += "Server: " WEBSERVERNAME "\r\n"; + // actual date + strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&timer)); + result += string_printf("Date: %s\r\n", timeStr); + // connection type +#ifdef Y_CONFIG_FEATURE_KEEP_ALIVE + if(keep_alive) + result += "Connection: keep-alive\r\n"; + else + result += "Connection: close\r\n"; +#else + result += "Connection: close\r\n"; +#endif + // content-len, last-modified + if(httpStatus == HTTP_NOT_MODIFIED ||httpStatus == HTTP_NOT_FOUND) + result += "Content-Length: 0\r\n"; + else if(GetContentLength() >0) + { + time_t mod_time = time(NULL); + if(LastModified != (time_t)-1) + mod_time = LastModified; + + strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&mod_time)); + result += string_printf("Last-Modified: %s\r\nContent-Length: %ld\r\n", timeStr, GetContentLength()); + } + result += "\r\n"; // End of Header + break; + } + + // Body + if (Method != M_HEAD) + switch (httpStatus) + { + case HTTP_OK: + case HTTP_NOT_MODIFIED: + case HTTP_CONTINUE: + case HTTP_ACCEPTED: + case HTTP_NO_CONTENT: + case HTTP_NOT_FOUND: + case HTTP_INTERNAL_SERVER_ERROR: + break; + + case HTTP_MOVED_TEMPORARILY: + case HTTP_MOVED_PERMANENTLY: + result += "Object moved"; + result += string_printf("302 : Object moved.
If you dont get redirected click here\n",NewURL.c_str()); + break; + + default: + // Error pages + break; + } + return result; +} + +//============================================================================= +// Output helpers +//============================================================================= +//----------------------------------------------------------------------------- +void CyhookHandler::SendHTMLHeader(const std::string& Titel) +{ + WriteLn("\n" + Titel + "\n"); + WriteLn(""); + WriteLn("\n\n\n"); +} +//----------------------------------------------------------------------------- +void CyhookHandler::SendHTMLFooter(void) +{ + WriteLn("\n\n\n"); +} + +//----------------------------------------------------------------------------- +#define OUTBUFSIZE 4096 +void CyhookHandler::printf ( const char *fmt, ... ) +{ + char outbuf[OUTBUFSIZE]; + bzero(outbuf,OUTBUFSIZE); + va_list arglist; + va_start( arglist, fmt ); + vsnprintf( outbuf,OUTBUFSIZE, fmt, arglist ); + va_end(arglist); + Write(outbuf); +} diff --git a/src/nhttpd/yhttpd_core/yhook.h b/src/nhttpd/yhttpd_core/yhook.h new file mode 100644 index 000000000..796031af0 --- /dev/null +++ b/src/nhttpd/yhttpd_core/yhook.h @@ -0,0 +1,187 @@ +//============================================================================= +// YHTTPD +// Hook and HookHandler +//----------------------------------------------------------------------------- +// Extentions for the Webserver can be implemented with Hooks. +// A "Hook"-Class must be inherited from Cyhook and can override the virtual +// functions from Cyhook. +// There are three types of Hooks. +// 1) Server based Hooks (exactly one Instance of Cyhttpd) +// 2) Webserver based Hooks (for each Instance of CWebserver, actually one; not now) +// 3) Connection based Hooks (for each Instance of CWebserverConnection) +//----------------------------------------------------------------------------- +// The CyhookHandler-Class itselfs calls the "attached" hooks. +// Hook-Classes must be attached/de-attached in Cyhttpd-Class attach()/detach(). +// Hook-Class instances should be initialized in yhttpd.cpp. +//----------------------------------------------------------------------------- +// "Hook_SendResponse" +//----------------------------------------------------------------------------- +// "Hook_SendResponse": this is the most important Hook. +// The CyhookHandler implements an abstraction for Request and Response data. +// Every Hook which has implemented Hook_SendResponse could be called in order +// of the "attach" to HookHandler. The control flow, which Hook will be called +// depends on the return value "THandleStatus" from the hook called before. +// For example HANDLED_NONE indicates that the Hook has not handled by the call. +// For example HANDLED_READY indicates that the call is handled and HookHandler +// should finish the Hook-Loop. HANDLED_NOT_IMPLEMENTED indicated that the Hook +// should handle the call, but has not any function to do that. +// Several Hooks can work together (HANDLED_CONTINUE or HANDLED_REWRITE); so the +// next called Hook can work with the output (in yresult) from the before called +// Hook or controls the workflow of following Hooks. +// For example the CmAuth-Hook validates HTTP-Authentication and returns +// HANDLED_CONTINUE if the authentication fits. +// Each Hook_SendResponse is encapsulated from the webserver and should not work +// on Socket-Connections. The Response is written to yresult. There are many +// helper-function for Output and Status-Handling. +// The Input is encapsulated too: ParamList, HeaderList, UrlData, ... +// Look at Response.SendResponse() +//----------------------------------------------------------------------------- +// Other Hooks +//----------------------------------------------------------------------------- +// - Hook_ReadConfig: Every Hook can read OWN Variables from the yhttpd-Configfile +// - Hook_EndConnection: After Response is sent and before Connection Instance +// is deleted +// - Hook_UploadSetFilename: this hook can set the filename for a file to upload +// via POST (before upload) +// - Hook_UploadReady: this Hook is called after uploading a file +//============================================================================= +#ifndef __yhttpd_yhook_h__ +#define __yhttpd_yhook_h__ +// C++ +#include +#include +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "ylogging.h" +// tuxbox +#include + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class CyhookHandler; +class Cyhook; + +//----------------------------------------------------------------------------- +// Type definitions for Hooks +//----------------------------------------------------------------------------- +typedef enum +{ + HANDLED_NONE = 0, // Init + HANDLED_READY, // Handled + HANDLED_ABORT, // Abort Connection Fatal + HANDLED_ERROR, // Have Error like missing Parameter + HANDLED_NOT_IMPLEMENTED,// URL should be handled but not implemented + HANDLED_REDIRECTION, // Set new URL and send HTTPD Object Moved + HANDLED_SENDFILE, // Set new URL and Send File + HANDLED_REWRITE, // Set new URL and call Hooks again + HANDLED_CONTINUE, // handled but go on + +} THandleStatus; +typedef std::list THookList; + +//----------------------------------------------------------------------------- +// An abstract Hook-Class. Custom Hook must be inherited. +//----------------------------------------------------------------------------- +class Cyhook +{ +protected: +public: + Cyhook(){}; + virtual ~Cyhook(){}; + // Informations & Control + virtual std::string getHookVersion(void) {return std::string("0.0.0");} + virtual std::string getHookName(void) {return std::string("Abstract Hook Class");} + // CWebserverConnection based hooks + virtual THandleStatus Hook_PrepareResponse(CyhookHandler *hh){return HANDLED_NONE;}; + virtual THandleStatus Hook_SendResponse(CyhookHandler *hh){return HANDLED_NONE;}; + virtual THandleStatus Hook_EndConnection(CyhookHandler *hh){return HANDLED_NONE;} + virtual THandleStatus Hook_UploadSetFilename(CyhookHandler *hh, std::string &Filename){return HANDLED_NONE;} + virtual THandleStatus Hook_UploadReady(CyhookHandler *hh, std::string Filename){return HANDLED_NONE;} + // Cyhttpd based hooks + virtual THandleStatus Hook_ReadConfig(CConfigFile *Config, CStringList &ConfigList){return HANDLED_NONE;}; +}; + +//----------------------------------------------------------------------------- +// Hook Handling and Input & Output abstraction +//----------------------------------------------------------------------------- +class CyhookHandler +{ +protected: + static THookList HookList; +public: + // Output + std::string yresult; // content for response output + THandleStatus status; // status of Hook handling + HttpResponseType httpStatus; // http-status code for response + std::string ResponseMimeType; // mime-type for response + std::string NewURL; // new URL for Redirection + long ContentLength; // Length of Response Body + time_t LastModified; // Last Modified Time of Item to send / -1 dynamic content + std::string Sendfile; // Path & Name (local os style) of file to send + bool keep_alive; + + // Input + CStringList ParamList; // local copy of ParamList (Request) + CStringList UrlData; // local copy of UrlData (Request) + CStringList HeaderList; // local copy of HeaderList (Request) + CStringList WebserverConfigList; // Reference (writable) to ConfigList + CStringList HookVarList; // Variables in Hook-Handling passing to other Hooks + THttp_Method Method; // HTTP Method (requested) + // constructor & deconstructor + CyhookHandler(){}; + virtual ~CyhookHandler(){}; + + // hook slot handler + static void attach(Cyhook *yh) // attach a Hook-Class to HookHandler + {HookList.push_back(yh);}; + static void detach(Cyhook *yh) // detach a Hook-Class to HookHandler + {HookList.remove(yh);}; + + // session handling + void session_init(CStringList _ParamList, CStringList _UrlData, CStringList _HeaderList, + CStringList& _ConfigList, THttp_Method _Method, bool _keep_alive); + + // Cyhttpd based hooks + static THandleStatus Hooks_ReadConfig(CConfigFile *Config, CStringList &ConfigList); + // CWebserverConnection based hooks + THandleStatus Hooks_PrepareResponse(); // Hook for Response.SendResonse Dispatching + THandleStatus Hooks_SendResponse(); // Hook for Response.SendResonse Dispatching + THandleStatus Hooks_EndConnection(); + THandleStatus Hooks_UploadSetFilename(std::string &Filename); + THandleStatus Hooks_UploadReady(const std::string& Filename); + + // status handling + void SetHeader(HttpResponseType _httpStatus, std::string _ResponseMimeType) + {httpStatus = _httpStatus; ResponseMimeType = _ResponseMimeType;} + void SetHeader(HttpResponseType _httpStatus, std::string _ResponseMimeType, THandleStatus _status) + {httpStatus = _httpStatus; ResponseMimeType = _ResponseMimeType; status = _status;} + void SetError(HttpResponseType responseType) + {SetHeader(responseType, "text/html");} + void SetError(HttpResponseType responseType, THandleStatus _status) + {SetError(responseType); status = _status;} + // others + long GetContentLength() + {return (status==HANDLED_SENDFILE)?ContentLength : (long)yresult.length();} + // output methods + std::string BuildHeader(bool cache = false); + void addResult(const std::string& result) {yresult += result;} + void addResult(const std::string& result, THandleStatus _status) + {yresult += result; status = _status;} + void printf(const char *fmt, ...); + void Write(const std::string& text) { addResult(text); } + void WriteLn(const std::string& text) { addResult(text+"\r\n"); } + void Write(char const *text) {Write(std::string(text));} + void WriteLn(char const *text) {WriteLn(std::string(text));} + void SendHTMLHeader(const std::string& Titel); + void SendHTMLFooter(void); + void SendOk(void) {Write("ok");} + void SendError(void) {Write("error");} + void SendFile(const std::string& url) {NewURL = url; status = HANDLED_SENDFILE;} + void SendRedirect(const std::string& url) {httpStatus=HTTP_MOVED_TEMPORARILY; NewURL = url; status = HANDLED_REDIRECTION;} + void SendRewrite(const std::string& url){NewURL = url; status = HANDLED_REWRITE;} + friend class CyParser; +}; + +#endif /*__yhttpd_yhook_h__*/ diff --git a/src/nhttpd/yhttpd_core/ylogging.cpp b/src/nhttpd/yhttpd_core/ylogging.cpp new file mode 100644 index 000000000..1a40c87cb --- /dev/null +++ b/src/nhttpd/yhttpd_core/ylogging.cpp @@ -0,0 +1,94 @@ +//============================================================================= +// YHTTPD +// Logging & Debugging +//============================================================================= + +// c +#include +#include +#include + +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "ylogging.h" +#include "yconnection.h" +//============================================================================= +// Instance Handling - like Singelton Pattern +//============================================================================= +//----------------------------------------------------------------------------- +// Init as Singelton +//----------------------------------------------------------------------------- +CLogging *CLogging::instance = NULL; + +//----------------------------------------------------------------------------- +// There is only one Instance +//----------------------------------------------------------------------------- +CLogging *CLogging::getInstance(void) +{ + if (!instance) + instance = new CLogging(); + return instance; +} + +//----------------------------------------------------------------------------- +void CLogging::deleteInstance(void) +{ + if (instance) + delete instance; + instance = NULL; +} + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CLogging::CLogging(void) +{ + Debug = false; + LogToFile = false; //not implemented + LogLevel = 0; + Logfile = NULL; + pthread_mutex_init(&Log_mutex, NULL); +} + +//----------------------------------------------------------------------------- +CLogging::~CLogging(void) +{ +} +//============================================================================= + +//----------------------------------------------------------------------------- +void CLogging::setDebug(bool _debug) +{ + Debug = _debug; +} +//----------------------------------------------------------------------------- +bool CLogging::getDebug(void) +{ + return Debug; +} +//============================================================================= +// Logging Calls +// use mutex controlled calls to output resources +// Normal Logging to Stdout, if "Log" is true then Log to file +//============================================================================= +#define bufferlen 1024*8 +//----------------------------------------------------------------------------- +void CLogging::printf ( const char *fmt, ... ) +{ + char buffer[bufferlen]; + + + va_list arglist; + va_start( arglist, fmt ); + if(arglist) + vsnprintf( buffer, bufferlen, fmt, arglist ); + va_end(arglist); + + pthread_mutex_lock( &Log_mutex ); + ::printf(buffer); + if(LogToFile) + ; //FIXME Logging to File + pthread_mutex_unlock( &Log_mutex ); +} + diff --git a/src/nhttpd/yhttpd_core/ylogging.h b/src/nhttpd/yhttpd_core/ylogging.h new file mode 100644 index 000000000..d5a461bfd --- /dev/null +++ b/src/nhttpd/yhttpd_core/ylogging.h @@ -0,0 +1,86 @@ +//============================================================================= +// YHTTPD +// Logging & Debugging +//============================================================================= +#ifndef __yhttpd_logging_h__ +#define __yhttpd_logging_h__ + +// system +#include +// yhttpd +#include "yconfig.h" + +// forward declaration +class CWebserverConnection; + +//----------------------------------------------------------------------------- +// Log Level +//----------------------------------------------------------------------------- +// 1 : Connection Information (called URL) +// 2 : Parameters?? +// 3 : yParser Main Infos +// 5 : ycmd: Every yParser Loop Command expansion +// 6 : yresult: Every yParser Loop Command expansion +// 8 : Central Functions Detailed +// 9 : Socket Operations +//----------------------------------------------------------------------------- +class CLogging +{ + protected: + pthread_mutex_t Log_mutex; + FILE *Logfile; + bool Debug; + bool LogToFile; + + static CLogging *instance; + + CLogging(void); + ~CLogging(void); + + public: + int LogLevel; + + // Instance Handling + static CLogging *getInstance(void); + static void deleteInstance(void); + + void setDebug(bool _debug); + bool getDebug(void); + + // Logging + void printf(const char *fmt, ...); +}; + +//----------------------------------------------------------------------------- +// definitions for easy use +//----------------------------------------------------------------------------- + +// print always +#define aprintf(fmt, args...) \ + do { CLogging::getInstance()->printf("[yhttpd] " fmt, ## args); } while (0) + +// print show file and linenumber +#define log_printfX(fmt, args...) \ + do { CLogging::getInstance()->printf("[yhttpd(%s:%d)] " fmt, __FILE__, __LINE__, ## args); } while (0) + +//Set Watch Point (show file and linenumber and function) +#define WP() \ + do { CLogging::getInstance()->printf("[yhttpd(%s:%d)%s]\n", __FILE__, __LINE__, __FUNCTION__); } while (0) + +// print if level matches +#define log_level_printf(level, fmt, args...) \ + do { if(CLogging::getInstance()->LogLevel>=level) CLogging::getInstance()->printf("[yhttpd#%d] " fmt, level, ## args); } while (0) + +// print if level matches / show file and linenumber +#define log_level_printfX(level, fmt, args...) \ + do { if(CLogging::getInstance()->LogLevel>=level) CLogging::getInstance()->printf("[yhttpd#%d(%s:%d)] " fmt, level, __FILE__, __LINE__, ## args); } while (0) + +// print only if debug is on +#define dprintf(fmt, args...) \ + do { if(CLogging::getInstance()->getDebug())CLogging::getInstance()->printf("[yhttpd] " fmt, ## args); } while (0) + +// print string to stdandard error +#define dperror(str) \ + do { perror("[yhttpd] " str); } while (0) + +#endif /* __yttpd_logging_h__ */ diff --git a/src/nhttpd/yhttpd_core/yrequest.cpp b/src/nhttpd/yhttpd_core/yrequest.cpp new file mode 100644 index 000000000..71a067cd9 --- /dev/null +++ b/src/nhttpd/yhttpd_core/yrequest.cpp @@ -0,0 +1,601 @@ +//============================================================================= +// YHTTPD +// Request +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// Request-Data +// UrlData (CStringList) +// startline First line of http-request (GET HTTP/1.x) +// fullurl ::= ? +// paramstring Is provided by String-Array ParameterList +// url ::= / "/" is last "/" in string +// path begin with /... +// filename ::= . +// filenamepure +// fileext Extension like html, jpg, ... +//============================================================================= + +// c++ +#include +#include +#include +#include +#include +// system +#include +#include + +// yhttpd +#include "yrequest.h" +#include "yconnection.h" +#include "helper.h" + +//============================================================================= +// Constructor & Destructor +//============================================================================= +CWebserverRequest::CWebserverRequest(CWebserver *pWebserver) +{ + Webserver = pWebserver; + CWebserverRequest(); +} + +//============================================================================= +// Parsing Request +//============================================================================= +//----------------------------------------------------------------------------- +// Main Request Parsing +// RFC2616 +// generic-message = start-line +// *(message-header CRLF) +// CRLF +// [ message-body ] +// start-line = Request-Line | Status-Line +//----------------------------------------------------------------------------- +bool CWebserverRequest::HandleRequest(void) +{ + std::string start_line = ""; + // read first line + do + { + start_line = Connection->sock->ReceiveLine(); + if(!Connection->sock->isValid) + return false; + if(start_line == "") // Socket empty + { + log_level_printf(1,"HandleRequest: End of line not found\n"); + Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR); + Connection->RequestCanceled = true; + return false; + } + } + while(start_line == "\r\n"); // ignore empty lines at begin on start-line + + start_line = trim(start_line); + log_level_printf(1,"Request: %s\n", start_line.c_str() ); + UrlData["startline"] = start_line; + if(!ParseStartLine(start_line)) + return false; + + + if(Connection->Method == M_GET || Connection->Method == M_HEAD) + { + std::string tmp_line; + //read header (speed up: read rest of request in blockmode) + tmp_line = Connection->sock->ReceiveBlock(); + if(!Connection->sock->isValid) + { + Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR); + return false; + } + + if(tmp_line == "") + { + Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR); + return false; + } + ParseHeader(tmp_line); + } + // Other Methods + if(Connection->Method == M_DELETE || Connection->Method == M_PUT || Connection->Method == M_TRACE) + { + //todo: implement + aprintf("HTTP Method not implemented :%d\n",Connection->Method); + Connection->Response.SendError(HTTP_NOT_IMPLEMENTED); + return false; + } + // handle POST (read header & body) + if(Connection->Method == M_POST) + { + Connection->Response.Write("HTTP/1.1 100 Continue\r\n\r\n"); // POST Requests requires CONTINUE in HTTP/1.1 + return HandlePost(); + } + // if you are here, something went wrong + + return true; +} + +//----------------------------------------------------------------------------- +// Parse the start-line +// from RFC2616 / 5.1 Request-Line (start-line): +// Request-Line = Method SP Request-URI SP HTTP-Version CRLF (SP=Space) +// +// Determine Reqest-Method, URL, HTTP-Version and Split Parameters +// Split URL into path, filename, fileext .. UrlData[] +//----------------------------------------------------------------------------- +bool CWebserverRequest::ParseStartLine(std::string start_line) +{ + std::string method,url,http,tmp; + + log_level_printf(8,": line: %s\n", start_line.c_str() ); + if(ySplitString(start_line," ",method,tmp)) + { + if(ySplitStringLast(tmp," ",url,Connection->httprotocol)) + { + analyzeURL(url); + UrlData["httprotocol"] = Connection->httprotocol; + // determine http Method + if(method.compare("POST") == 0) Connection->Method = M_POST; + else if(method.compare("GET") == 0) Connection->Method = M_GET; + else if(method.compare("PUT") == 0) Connection->Method = M_PUT; + else if(method.compare("HEAD") == 0) Connection->Method = M_HEAD; + else if(method.compare("PUT") == 0) Connection->Method = M_PUT; + else if(method.compare("DELETE") == 0) Connection->Method = M_DELETE; + else if(method.compare("TRACE") == 0) Connection->Method = M_TRACE; + else + { + log_level_printf(1,"Unknown Method or invalid request\n"); + Connection->Response.SendError(HTTP_NOT_IMPLEMENTED); + log_level_printf(3,"Request: '%s'\n",rawbuffer.c_str()); + return false; + } + log_level_printf(3,"Request: FullURL: %s\n",UrlData["fullurl"].c_str()); + return true; + } + } + return false; +} + +//----------------------------------------------------------------------------- +// parse parameter string +// parameter = attribute "=" value +// attribute = token +// value = token | quoted-string +// +// If parameter attribute is multiple times given, the values are stored like this: +// =,,.., +//----------------------------------------------------------------------------- +bool CWebserverRequest::ParseParams(std::string param_string) +{ + bool ende = false; + std::string param, name="", value, number; + + while(!ende) + { + if(!ySplitStringExact(param_string,"&",param,param_string)) + ende = true; + if(ySplitStringExact(param,"=",name,value)) + { + value = trim(value); + if(ParameterList[name].empty()) + ParameterList[name] = value; + else + { + ParameterList[name] += ","; + ParameterList[name] += value; + } + } + number = string_printf("%d", ParameterList.size()+1); + log_level_printf(7,"ParseParams: name: %s value: %s\n",name.c_str(), value.c_str()); + ParameterList[number] = name; + } + return true; +} + +//----------------------------------------------------------------------------- +// parse the header of the request +// from RFC 2616 / 4.2 Message Header: +// message-header = field-name ":" [ field-value ] +// field-name = token +// field-value = *( field-content | LWS ) +// field-content = +//----------------------------------------------------------------------------- +bool CWebserverRequest::ParseHeader(std::string header) +{ + bool ende = false; + std::string sheader, name, value; + HeaderList.clear(); + + while(!ende) + { + if(!ySplitStringExact(header,"\r\n",sheader,header)) + ende = true; + if(ySplitStringExact(sheader,":",name,value)) + HeaderList[name] = trim(value); + log_level_printf(8,"ParseHeader: name: %s value: %s\n",name.c_str(), value.c_str()); + } + return true; +} + +//----------------------------------------------------------------------------- +// Analyze URL +// Extract Filename, Path, FileExt +// form RFC2616 / 3.2.2: +// http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]] +// query data is splitted and stored in ParameterList +//----------------------------------------------------------------------------- +void CWebserverRequest::analyzeURL(std::string url) +{ + ParameterList.clear(); + // URI decode + url = decodeString(url); + url = trim(url, "\r\n"); // non-HTTP-Standard: allow \r or \n in URL. Delete it. + UrlData["fullurl"] = url; + // split Params + if(ySplitString(url,"?",UrlData["url"],UrlData["paramstring"])) // split pure URL and all Params + ParseParams(UrlData["paramstring"]); // split params to ParameterList + else // No Params + UrlData["url"] = url; + + if(!ySplitStringLast(UrlData["url"],"/",UrlData["path"],UrlData["filename"])) + { + UrlData["path"] = "/"; // Set "/" if not contained + } + else + UrlData["path"] += "/"; + if(( UrlData["url"].length() == 1) || (UrlData["url"][UrlData["url"].length()-1] == '/' )) + { // if "/" at end use index.html + UrlData["path"] = UrlData["url"]; + UrlData["filename"] = "index.html"; + } + ySplitStringLast(UrlData["filename"],".",UrlData["filenamepure"],UrlData["fileext"]); +} + +//----------------------------------------------------------------------------- +// Handle Post (Form and ONE file upload) +//----------------------------------------------------------------------------- +bool CWebserverRequest::HandlePost() +{ + //read header: line by line + std::string raw_header, tmp_line; + do + { + tmp_line = Connection->sock->ReceiveLine(); + if(tmp_line == "") // Socket empty + { + log_level_printf(1,"HandleRequest: (Header) End of line not found: %s\n", strerror(errno)); + Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR); + return false; + } + raw_header.append(tmp_line); + } + while(tmp_line != "\r\n"); // header ends with first empty line + ParseHeader(raw_header); + + // read meesage body + unsigned int content_len = 0; + if(HeaderList["Content-Length"] != "") + content_len = atoi( HeaderList["Content-Length"].c_str() ); + + // Get Rest of Request from Socket + log_level_printf(2,"Connection->Method Post !\n"); + log_level_printf(9,"Conntent Type:%s\n",(HeaderList["Content-Type"]).c_str()); + log_level_printf(8,"Post Content-Length:%d as string:(%s)\n", content_len, HeaderList["Content-Length"].c_str()); + + static const std::string t = "multipart/form-data; boundary="; + if(HeaderList["Content-Type"].compare(0,t.length(),t) == 0) // this a a multpart POST, normallly: file upload + { +#ifdef Y_CONFIG_FEATURE_UPLOAD + std::string boundary = "--" + HeaderList["Content-Type"].substr(t.length(),HeaderList["Content-Type"].length() - t.length()); + std::string post_header; + do + { + content_len = HandlePostBoundary(boundary, content_len); + } + while(content_len > 0); +#else + Connection->Response.SendError(HTTP_NOT_IMPLEMENTED); + return false; +#endif + } + else if(HeaderList["Content-Type"].compare("application/x-www-form-urlencoded") == 0) //this is a normal POST with form-data (no upload) + { + // handle normal form POST + log_level_printf(6,"Handle POST application/x-www-form-urlencoded\n"); + std::string post_header; + // get message-body + post_header = Connection->sock->ReceiveBlock(); + if(post_header.length() < content_len) + { + aprintf("POST form less data then expected\n"); + Connection->Response.SendError(HTTP_INTERNAL_SERVER_ERROR); + return false; + } + // parse the params in post_header (message-body) an add them to ParameterList + ParseParams(post_header); + } + return true; +} +//----------------------------------------------------------------------------- +// POST multipart ! FILE UPLOAD! +// +// No 'Content-type: multipart/mixed' now supported +// designed for recursion for different boundaries. +// +// from RFC 1867: +// 2. HTML forms with file submission +// +// The current HTML specification defines eight possible values for the +// attribute TYPE of an INPUT element: CHECKBOX, HIDDEN, IMAGE, +// PASSWORD, RADIO, RESET, SUBMIT, TEXT. +// +// In addition, it defines the default ENCTYPE attribute of the FORM +// element using the POST METHOD to have the default value +// "application/x-www-form-urlencoded" +// +// 6. Examples +// +// Suppose the server supplies the following HTML: +// +//
+// What is your name? +// What files are you sending? +//
+// +// and the user types "Joe Blow" in the name field, and selects a text +// file "file1.txt" for the answer to 'What files are you sending?' +// +// The client might send back the following data: +// +// Content-type: multipart/form-data, boundary=AaB03x +// +// --AaB03x +// content-disposition: form-data; name="field1" +// +// Joe Blow +// --AaB03x +// content-disposition: form-data; name="pics"; filename="file1.txt" +// Content-Type: text/plain +// +// ... contents of file1.txt ... +// --AaB03x-- +// +// 7. Registration of multipart/form-data +// +// The media-type multipart/form-data follows the rules of all multipart +// MIME data streams as outlined in RFC 1521. It is intended for use in +// returning the data that comes about from filling out a form. In a +// form (in HTML, although other applications may also use forms), there +// are a series of fields to be supplied by the user who fills out the +// form. Each field has a name. Within a given form, the names are +// unique. +// +// multipart/form-data contains a series of parts. Each part is expected +// to contain a content-disposition header where the value is "form- +// data" and a name attribute specifies the field name within the form, +// e.g., 'content-disposition: form-data; name="xxxxx"', where xxxxx is +// the field name corresponding to that field. Field names originally in +// non-ASCII character sets may be encoded using the method outlined in +// RFC 1522. +// +// As with all multipart MIME types, each part has an optional Content- +// Type which defaults to text/plain. If the contents of a file are +// returned via filling out a form, then the file input is identified as +// application/octet-stream or the appropriate media type, if known. If +// multiple files are to be returned as the result of a single form +// entry, they can be returned as multipart/mixed embedded within the +// multipart/form-data. +// +// Each part may be encoded and the "content-transfer-encoding" header +// supplied if the value of that part does not conform to the default +// encoding. +// +// File inputs may also identify the file name. The file name may be +// described using the 'filename' parameter of the "content-disposition" +// header. This is not required, but is strongly recommended in any case +// where the original filename is known. This is useful or necessary in +// many applications. +//----------------------------------------------------------------------------- +unsigned int CWebserverRequest::HandlePostBoundary(std::string boundary, unsigned int content_len) +{ + std::string tmp_line; + + // read boundary + tmp_line = Connection->sock->ReceiveLine(); + content_len -= tmp_line.length(); + + log_level_printf(2," Start\n"); + if(tmp_line.find(boundary) != std::string::npos) + { + // is it the boudary end? + if(tmp_line.find(boundary+"--") != std::string::npos) + { + log_level_printf(7," Boundary END found\n"); + return 0; + } + log_level_printf(7," Boundary START found\n"); + + // read content-disposition: ... + tmp_line = Connection->sock->ReceiveLine(); + content_len -= tmp_line.length(); + if(tmp_line.find("Content-Disposition:") == std::string::npos) + { + log_level_printf(7," no content-disposition found. line:(%s)\n", tmp_line.c_str()); + return 0; + } + if(tmp_line.find("filename") != std::string::npos) + { +#ifdef Y_CONFIG_FEATURE_UPLOAD + // this part is a file + log_level_printf(2," disposition !!this is a file!! found. line:(%s)\n", tmp_line.c_str()); + // get para from 'content-disposition: form-data; name="pics"; filename="file1.txt"' + // set to ParameterList[""]="" + std::string left, right, var_name, var_value; + if(!ySplitStringExact(tmp_line, "name=\"", left, right)) + { + log_level_printf(7," no var_name START found. line:(%s)\n", tmp_line.c_str()); + return 0; + } + if(!ySplitStringExact(right, "\"", var_name, right)) + { + log_level_printf(7," no var_name END found. line:(%s)\n", tmp_line.c_str()); + return 0; + } + if(!ySplitStringExact(right, "filename=\"", left, right)) + { + log_level_printf(7," no filename START found. line:(%s)\n", tmp_line.c_str()); + return 0; + } + if(!ySplitStringExact(right, "\"", var_value, right)) + { + log_level_printf(7," no filename END found. line:(%s)\n", tmp_line.c_str()); + return 0; + } + var_value = trim(var_value); + ParameterList[var_name] = var_value; + log_level_printf(7," filename found. name:(%s) value:(%s)\n", var_name.c_str(), var_value.c_str()); + + //read 'Content-Type: ' + tmp_line = Connection->sock->ReceiveLine(); + content_len -= tmp_line.length(); + // Get Content-Type: put it to ParameterList["_mime"]="" + if(!ySplitStringExact(tmp_line, "Content-Type:", left, right)) + { + log_level_printf(7," no Content-Type found. line:(%s)\n", tmp_line.c_str()); + return 0; + } + var_value = trim(right); + ParameterList[var_name+"_mime"] = var_value; + log_level_printf(7," Content-Type found. name:(%s_mime) value:(%s)\n", var_name.c_str(), var_value.c_str()); + + + //read empty line as separator + tmp_line = Connection->sock->ReceiveLine(); + content_len -= tmp_line.length(); + if(tmp_line != "\r\n") + { + log_level_printf(7," no empty line found. line:(%s)\n", tmp_line.c_str()); + return 0; + + } + log_level_printf(7," read file Start\n"); + + std::string upload_filename; + upload_filename = UPLOAD_TMP_FILE; + // Hook for Filename naming + Connection->HookHandler.Hooks_UploadSetFilename(upload_filename); + // Set upload filename to ParameterList["_upload_filename"]="" + ParameterList[var_name+"_upload_filename"] = upload_filename; + + // open file for write + int fd = open(upload_filename.c_str(), O_WRONLY|O_CREAT|O_TRUNC); + if (fd<=0) + { + aprintf("cannot open file %s: ", upload_filename.c_str()); + dperror(""); + return 0; + } + + // ASSUMPTION: the complete multipart has no more then SEARCH_BOUNDARY_LEN bytes after the file. + // It only works, if no multipart/mixed is used (e.g. in file attachments). Not nessesary in embedded systems. + // To speed up uploading, read content_len - SEARCH_BOUNDARY_LEN bytes in blockmode. + // To save memory, write them direct into the file. + #define SEARCH_BOUNDARY_LEN 2*RECEIVE_BLOCK_LEN // >= RECEIVE_BLOCK_LEN in ySocket + unsigned int _readbytes = 0; + if((int)content_len - SEARCH_BOUNDARY_LEN >0) + { + _readbytes = Connection->sock->ReceiveFileGivenLength(fd, content_len - SEARCH_BOUNDARY_LEN); + content_len -= _readbytes; + log_level_printf(8," read block (already:%d all:%d)\n", _readbytes, content_len); + } + + // read rest of file and check for boundary end + _readbytes = 0; + bool is_CRLF = false; + + bool found_end_boundary = false; + do + { + // read line by line + tmp_line = Connection->sock->ReceiveLine(); + _readbytes += tmp_line.length(); + + // is this line a boundary? + if(tmp_line.find(boundary) != std::string::npos) + { + if(tmp_line.find(boundary+"--") != std::string::npos) + found_end_boundary = true; // it is the end! of POST request! + break; // boundary found. end of file. + } + else // no Boundary: write CRFL if found in last line + { + if(is_CRLF) + if ((unsigned int)write(fd, "\r\n", 2) != 2) + { + perror("write file failed\n"); + return 0; + } + } + // normal line: write it to file + // CRLF at end? Maybe CRLF before boundary. Can not decide yet + is_CRLF = (tmp_line.length()>=2 && tmp_line[tmp_line.length()-2]=='\r' && tmp_line[tmp_line.length()-1]=='\n'); + int write_len = is_CRLF ? tmp_line.length()-2 : tmp_line.length(); + if (write(fd, tmp_line.c_str(), write_len) != write_len) + { + perror("write file failed\n"); + return 0; + } + log_level_printf(2," read file (already:%d all:%d)\n", _readbytes, content_len); + } + while((_readbytes < content_len) && (tmp_line.length() != 0)); + content_len -= _readbytes; + close(fd); + log_level_printf(2," read file End\n"); + if(found_end_boundary) // upload ok? + { + + Connection->HookHandler.Hooks_UploadReady(upload_filename); + return 0; + } +#endif // Y_CONFIG_FEATURE_UPLOAD + } + else + // this part is a POST variable/parameter + { + // get var_name from 'content-disposition: form-data; name="var_name"' + std::string left, right, var_name, var_value; + if(!ySplitStringExact(tmp_line, "name=\"", left, right)) + { + log_level_printf(7," no var_name START found. line:(%s)\n", tmp_line.c_str()); + return 0; + } + if(!ySplitStringExact(right, "\"", var_name, right)) + { + log_level_printf(7," no var_name END found. line:(%s)\n", tmp_line.c_str()); + return 0; + } + + //read empty line as separator + tmp_line = Connection->sock->ReceiveLine(); + content_len -= tmp_line.length(); + if(tmp_line != "\r\n") + { + log_level_printf(7," no empty line found. line:(%s)\n", tmp_line.c_str()); + return 0; + + } + //read var_value line + // ASSUMPTION!!!! Only one Line for value, new line is a boundary again + // ATTENTION!! var_name must not be unique. So Parameters are store by number too. + var_value = Connection->sock->ReceiveLine(); + content_len -= tmp_line.length(); + var_value = trim(var_value); + ParameterList[var_name] = var_value; + log_level_printf(7," Parameter found. name:(%s) value:(%s)\n", var_name.c_str(), var_value.c_str()); + } + } + return content_len; +} diff --git a/src/nhttpd/yhttpd_core/yrequest.h b/src/nhttpd/yhttpd_core/yrequest.h new file mode 100644 index 000000000..65b670ab3 --- /dev/null +++ b/src/nhttpd/yhttpd_core/yrequest.h @@ -0,0 +1,52 @@ +//============================================================================= +// YHTTPD +// Request +//============================================================================= + +#ifndef __yhttpd_request_h__ +#define __yhttpd_request_h__ + +// C++ +#include +#include + +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" + +// forward declaration +class CWebserver; +class CWebserverConnection; + +//----------------------------------------------------------------------------- +class CWebserverRequest +{ +private: + bool HandlePost(); + unsigned int HandlePostBoundary(std::string boundary, unsigned int content_len); + bool ParseStartLine(std::string start_line); + bool ParseParams(std::string param_string); + bool ParseHeader(std::string header); + +protected: + std::string rawbuffer; + + // request control +public: + class CWebserver *Webserver; + class CWebserverConnection *Connection; + + // Request Data + CStringList ParameterList; + CStringList HeaderList; + CStringList UrlData; // url, fullurl, path, filename, fileext, paramstring + void analyzeURL(std::string); + + // constructor & destructor + CWebserverRequest() {}; + CWebserverRequest(CWebserver *pWebserver); + // Handler + bool HandleRequest(void); +}; + +#endif /* __yhttpd_request_h__ */ diff --git a/src/nhttpd/yhttpd_core/yresponse.cpp b/src/nhttpd/yhttpd_core/yresponse.cpp new file mode 100644 index 000000000..1a3f8c9cf --- /dev/null +++ b/src/nhttpd/yhttpd_core/yresponse.cpp @@ -0,0 +1,251 @@ +//============================================================================= +// YHTTPD +// Response +//============================================================================= + +// c +#include +#include +#include +// c++ +#include +// system +#include +#include +// yhttpd +#include "yconfig.h" +#include "yhttpd.h" +#include "ytypes_globals.h" +#include "ylogging.h" +#include "ywebserver.h" +#include "yconnection.h" +#include "helper.h" +#include "yhook.h" + +#ifdef Y_CONFIG_HAVE_SENDFILE +#include +#endif + +//============================================================================= +// Constructor & Destructor +//============================================================================= +CWebserverResponse::CWebserverResponse(CWebserver *pWebserver) +{ + Webserver = pWebserver; + CWebserverResponse(); +} +//----------------------------------------------------------------------------- +CWebserverResponse::CWebserverResponse() +{ +} + +//============================================================================= +// Main Dispacher for Response +// To understand HOOKS reade yhook.cpp Comments!!! +//----------------------------------------------------------------------------- +// RFC 2616 / 6 Response +// +// After receiving and interpreting a request message, a server responds +// with an HTTP response message. +// Response =Status-Line ; generated by SendHeader +// *(( general-header ; generated by SendHeader +// | response-header ; generated by SendHeader +// | entity-header ) CRLF); generated by SendHeader +// CRLF ; generated by SendHeader +// [ message-body ] ; by HOOK Handling Loop or Sendfile +//============================================================================= +bool CWebserverResponse::SendResponse() +{ + // Init Hookhandler + Connection->HookHandler.session_init(Connection->Request.ParameterList, Connection->Request.UrlData, + (Connection->Request.HeaderList), (Cyhttpd::ConfigList), Connection->Method, Connection->keep_alive); + //-------------------------------------------------------------- + // HOOK Handling Loop [ PREPARE response hook ] + // Checking and Preperation: Auth, static, cache, ... + //-------------------------------------------------------------- + +// move to mod_sendfile ??? +#ifdef Y_CONFIG_USE_HOSTEDWEB + // for hosted webs: rewrite URL + std::string _hosted="/hosted/"; + if((Connection->Request.UrlData["path"]).compare(0,_hosted.length(),"/hosted/") == 0) // hosted Web ? + Connection->Request.UrlData["path"]=Cyhttpd::ConfigList["HostedDocumentRoot"] + +(Connection->Request.UrlData["path"]).substr(_hosted.length()-1); +#endif //Y_CONFIG_USE_HOSTEDWEB + + do + { + if(Connection->RequestCanceled) + return false; + + Connection->HookHandler.Hooks_PrepareResponse(); + if(Connection->HookHandler.status == HANDLED_ERROR || Connection->HookHandler.status == HANDLED_ABORT) + { + log_level_printf(2,"Response Prepare Hook found but Error\n"); + Write(Connection->HookHandler.BuildHeader()); + Write(Connection->HookHandler.yresult); + return false; + } + // URL has new value. Analyze new URL for SendFile + else if(Connection->HookHandler.status == HANDLED_SENDFILE || + Connection->HookHandler.status == HANDLED_REWRITE) + { + Connection->Request.analyzeURL(Connection->HookHandler.NewURL); + Connection->HookHandler.UrlData = Connection->Request.UrlData; + } + if(Connection->HookHandler.status == HANDLED_REDIRECTION) + { + Write(Connection->HookHandler.BuildHeader()); + return false; + } + } + while(Connection->HookHandler.status == HANDLED_REWRITE); + + // Prepare = NOT_MODIFIED ? + if(Connection->HookHandler.httpStatus == HTTP_NOT_MODIFIED) + { + Write(Connection->HookHandler.BuildHeader()); + return true; + } + + //-------------------------------------------------------------- + // HOOK Handling Loop [ response hook ] + // Production + //-------------------------------------------------------------- + if(Connection->HookHandler.status != HANDLED_SENDFILE) + do + { + if(Connection->RequestCanceled) + return false; + + Connection->HookHandler.Hooks_SendResponse(); + if((Connection->HookHandler.status == HANDLED_READY)||(Connection->HookHandler.status == HANDLED_CONTINUE)) + { + log_level_printf(2,"Response Hook Output. Status:%d\n", Connection->HookHandler.status); + Write(Connection->HookHandler.BuildHeader()); + if(Connection->Method != M_HEAD) + Write(Connection->HookHandler.yresult); + if(Connection->HookHandler.status != HANDLED_CONTINUE) + return true; + } + else if(Connection->HookHandler.status == HANDLED_ERROR) + { + log_level_printf(2,"Response Hook found but Error\n"); + Write(Connection->HookHandler.BuildHeader()); + if(Connection->Method != M_HEAD) + Write(Connection->HookHandler.yresult); + return false; + } + else if(Connection->HookHandler.status == HANDLED_ABORT) + return false; + // URL has new value. Analyze new URL for SendFile + else if(Connection->HookHandler.status == HANDLED_SENDFILE || + Connection->HookHandler.status == HANDLED_REWRITE) + { + Connection->Request.analyzeURL(Connection->HookHandler.NewURL); + Connection->HookHandler.UrlData = Connection->Request.UrlData; + } + if(Connection->HookHandler.status == HANDLED_REDIRECTION) + { + Write(Connection->HookHandler.BuildHeader()); + return false; + } + } + while(Connection->HookHandler.status == HANDLED_REWRITE); + + // Send static file + if(Connection->HookHandler.status == HANDLED_SENDFILE && !Connection->RequestCanceled) + { + bool cache = true; +// if(Connection->HookHandler.UrlData["path"] == "/tmp/")//TODO: un-cachable dirs +// cache = false; + Write(Connection->HookHandler.BuildHeader(cache)); + if(Connection->Method != M_HEAD) + Sendfile(Connection->Request.UrlData["url"]); + return true; + } + + // arrived here? = error! + SendError(HTTP_NOT_FOUND); + return false; +} + +//============================================================================= +// Output +//============================================================================= +void CWebserverResponse::SendHeader(HttpResponseType responseType, bool cache, std::string ContentType) +{ + Connection->HookHandler.SetHeader(responseType, ContentType); + Write(Connection->HookHandler.BuildHeader(cache)); +} + +//----------------------------------------------------------------------------- +// BASIC Send over Socket for Strings (char*) +//----------------------------------------------------------------------------- +bool CWebserverResponse::WriteData(char const * data, long length) +{ + if(Connection->RequestCanceled) + return false; + if(Connection->sock->Send(data, length) == -1) + { + log_level_printf(1,"response canceled: %s\n", strerror(errno)); + Connection->RequestCanceled = true; + return false; + } + else + return true; +} +//----------------------------------------------------------------------------- +#define bufferlen 4*1024 +void CWebserverResponse::printf ( const char *fmt, ... ) +{ + char buffer[bufferlen]; + va_list arglist; + va_start( arglist, fmt ); + vsnprintf( buffer, bufferlen, fmt, arglist ); + va_end(arglist); + Write(buffer); +} +//----------------------------------------------------------------------------- +bool CWebserverResponse::Write(char const *text) +{ + return WriteData(text, strlen(text)); +} +//----------------------------------------------------------------------------- +bool CWebserverResponse::WriteLn(char const *text) +{ + if(!WriteData(text, strlen(text))) + return false; + return WriteData("\r\n",2); +} + +//----------------------------------------------------------------------------- +bool CWebserverResponse::Sendfile(std::string filename) +{ + if(Connection->RequestCanceled) + return false; + int filed = open( filename.c_str(), O_RDONLY ); + if(filed != -1 ) //can access file? + { + if(!Connection->sock->SendFile(filed)) + Connection->RequestCanceled = true; + close(filed); + } + return (filed != -1 ); +} + +//----------------------------------------------------------------------------- +// Send File: Determine MIME-Type fro File-Extention +//----------------------------------------------------------------------------- +std::string CWebserverResponse::GetContentType(std::string ext) +{ + std::string ctype = "text/plain"; + ext = string_tolower(ext); + for (unsigned int i = 0;i < (sizeof(MimeFileExtensions)/sizeof(MimeFileExtensions[0])); i++) + if (MimeFileExtensions[i].fileext == ext) + { + ctype = MimeFileExtensions[i].mime; + break; + } + return ctype; +} diff --git a/src/nhttpd/yhttpd_core/yresponse.h b/src/nhttpd/yhttpd_core/yresponse.h new file mode 100644 index 000000000..6bdaeab1b --- /dev/null +++ b/src/nhttpd/yhttpd_core/yresponse.h @@ -0,0 +1,56 @@ +//============================================================================= +// YHTTPD +// Response +//============================================================================= + +#ifndef __yhttpd_response_h__ +#define __yhttpd_response_h__ + +// c++ +#include +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "yhook.h" + +// forward declaration +class CWebserver; +class CWebserverConnection; + +//----------------------------------------------------------------------------- +class CWebserverResponse +{ +private: + +protected: + bool WriteData(char const *data, long length); + bool Sendfile(std::string filename); + std::string redirectURI; // URI for redirection else: empty + +public: + class CWebserver *Webserver; + class CWebserverConnection *Connection; + + // con/destructors + CWebserverResponse(); + CWebserverResponse(CWebserver *pWebserver); + + // response control + bool SendResponse(void); + + // output methods + void printf(const char *fmt, ...); + bool Write(char const *text); + bool WriteLn(char const *text); + bool Write(const std::string text) { return Write(text.c_str()); } + bool WriteLn(const std::string text) { return WriteLn(text.c_str()); } + + // Headers + void SendError(HttpResponseType responseType) {SendHeader(responseType, false, "text/html");} + void SendHeader(HttpResponseType responseType, bool cache=false, std::string ContentType="text/html"); + + // Helpers + std::string GetContentType(std::string ext); +}; + +#endif /* __yhttpd_response_h__ */ diff --git a/src/nhttpd/yhttpd_core/ysocket.cpp b/src/nhttpd/yhttpd_core/ysocket.cpp new file mode 100644 index 000000000..3ff1aa675 --- /dev/null +++ b/src/nhttpd/yhttpd_core/ysocket.cpp @@ -0,0 +1,504 @@ +//============================================================================= +// YHTTPD +// Socket Class : Basic Socket Operations +//============================================================================= + +#include + +// system +#include +#include +#include +#include +#include +#include +#include +// yhttpd +#include "yhttpd.h" +#include "ysocket.h" +#include "ylogging.h" +// system +#ifdef Y_CONFIG_HAVE_SENDFILE +#include +#endif +#ifdef Y_CONFIG_USE_OPEN_SSL +#include +#include +#include +#endif + +//============================================================================= +// Initialization of static variables +//============================================================================= +#ifdef Y_CONFIG_USE_OPEN_SSL +SSL_CTX *CySocket::SSL_ctx; +std::string CySocket::SSL_pemfile; +std::string CySocket::SSL_CA_file; +#endif + +//============================================================================= +// Constructor & Destructor & Initialization +//============================================================================= +CySocket::CySocket() + : sock(0) +{ +#ifdef Y_CONFIG_USE_OPEN_SSL + ssl = NULL; +#endif + tv_start_waiting.tv_sec = 0; + tv_start_waiting.tv_usec = 0; + BytesSend =0; + sock = socket(AF_INET,SOCK_STREAM,0); + init(); +} +//----------------------------------------------------------------------------- +CySocket::~CySocket() +{ +#ifdef Y_CONFIG_USE_OPEN_SSL + if(isSSLSocket && ssl != NULL) + SSL_free(ssl); +#endif +} +//----------------------------------------------------------------------------- +// initialize +//----------------------------------------------------------------------------- +void CySocket::init(void) +{ + handling = false; + isOpened = false; + isValid = true; + addr_len = sizeof(addr); + memset(&addr, 0, addr_len); +#ifdef Y_CONFIG_USE_OPEN_SSL + isSSLSocket = false; +#endif +} +//----------------------------------------------------------------------------- +// Initialize this socket as a SSL-socket +//----------------------------------------------------------------------------- +#ifdef Y_CONFIG_USE_OPEN_SSL + +bool CySocket::initAsSSL(void) +{ + isSSLSocket = true; + if (NULL == (ssl = SSL_new(CySocket::SSL_ctx))) // create SSL-socket + { + aprintf("ySocket:SSL Error: Create SSL_new : %s\n", ERR_error_string(ERR_get_error(), NULL) ); + return false; + } + SSL_set_accept_state(ssl); // accept connection + if(1 != (SSL_set_fd(ssl, sock))) // associate socket descriptor + if (NULL == (ssl = SSL_new(CySocket::SSL_ctx))) + { + aprintf("ySocket:SSL Error: Create SSL_new : %s\n", ERR_error_string(ERR_get_error(), NULL) ); + return false; + } + return true; +} +//----------------------------------------------------------------------------- +// static: initialize the SSL-Library and the SSL ctx object. +// Read and assoziate the keyfile. +//----------------------------------------------------------------------------- +bool CySocket::initSSL(void) +{ + SSL_load_error_strings(); // Load SSL Error Strings + SSL_library_init(); // Load SSL Library + if (0 == RAND_status()) // set Random + { + aprintf("ySocket:SSL got no rand\n"); + return false; + } + if((SSL_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) // create master ctx + { + aprintf("ySocket:SSL Error: Create SSL_CTX_new : %s\n", ERR_error_string(ERR_get_error(), NULL) ); + return false; + } + if(SSL_pemfile == "") + { + aprintf("ySocket:SSL Error: no pemfile given\n"); + return false; + } + if(SSL_CA_file != "") // have a CA? + if(1 != SSL_CTX_load_verify_locations(SSL_ctx, SSL_CA_file.c_str(), NULL)) + { + aprintf("ySocket:SSL Error: %s CA-File:%s\n",ERR_error_string(ERR_get_error(), NULL), SSL_CA_file.c_str()); + return false; + } + if(SSL_CTX_use_certificate_file(SSL_ctx, SSL_pemfile.c_str(), SSL_FILETYPE_PEM) < 0) + { + aprintf("ySocket:SSL Error: %s PEM-File:%s\n",ERR_error_string(ERR_get_error(), NULL), SSL_pemfile.c_str()); + return false; + } + + if(SSL_CTX_use_PrivateKey_file(SSL_ctx, SSL_pemfile.c_str(), SSL_FILETYPE_PEM) < 0) + { + aprintf("ySocket:SSL Error: Private Keys: %s PEM-File:%s\n",ERR_error_string(ERR_get_error(), NULL), SSL_pemfile.c_str()); + return false; + } + if(SSL_CTX_check_private_key(SSL_ctx) != 1) + { + aprintf("ySocket:SSL Error: Private Keys not compatile to public keys: %s PEM-File:%s\n",ERR_error_string(ERR_get_error(), NULL), SSL_pemfile.c_str()); + return false; + } + return true; +} +#endif +//============================================================================= +// Socket handling +//============================================================================= +void CySocket::close(void) +{ + if(sock != 0 && sock != INVALID_SOCKET) + ::close(sock); +#ifndef Y_CONFIG_FEATURE_KEEP_ALIVE + sock = 0; +#endif + isOpened = false; +} +//----------------------------------------------------------------------------- +void CySocket::shutdown(void) +{ + if(sock != 0 && sock != INVALID_SOCKET) + ::shutdown(sock,SHUT_RDWR); +} +//----------------------------------------------------------------------------- +bool CySocket::listen(int port, int max_connections) +{ + if(sock == INVALID_SOCKET) + return false; + + // set sockaddr for listening + sockaddr_in sai; + memset(&sai, 0, sizeof(sai)); + sai.sin_family = AF_INET; // Protocol + sai.sin_addr.s_addr = htonl(INADDR_ANY); // No Filter + sai.sin_port = htons(port); // Listening Port + + set_reuse_port(); // Re-Use Port + set_reuse_addr(); // Re-Use IP + if(bind(sock, (sockaddr *)&sai, sizeof(sockaddr_in)) != SOCKET_ERROR) + if(::listen(sock, max_connections) == 0) + return true; + return false; +} +//----------------------------------------------------------------------------- +CySocket* CySocket::accept() +{ + init(); + SOCKET newSock = ::accept(sock, (sockaddr *) &addr, &addr_len); + if(newSock == INVALID_SOCKET) + { + dperror("accept: invalid socket\n"); + return NULL; + } + CySocket *new_ySocket = new CySocket(newSock); + if(new_ySocket != NULL) + { + new_ySocket->setAddr(addr); +#ifdef TCP_CORK + new_ySocket->set_option(IPPROTO_TCP, TCP_CORK); +#else + set_tcp_nodelay(); +#endif + } + new_ySocket->isOpened = true; +// handling = true; + return new_ySocket; +} +//----------------------------------------------------------------------------- +std::string CySocket::get_client_ip(void) +{ + return inet_ntoa(addr.sin_addr); +} +//----------------------------------------------------------------------------- +int CySocket::get_accept_port(void) +{ + return (int)ntohs(addr.sin_port); +} +//----------------------------------------------------------------------------- +void CySocket::setAddr(sockaddr_in _addr) +{ + addr = _addr; +} + +//----------------------------------------------------------------------------- +// Set Socket Option (return = false = error) +//----------------------------------------------------------------------------- +bool CySocket::set_option(int typ, int option) +{ + int on = 1; + return (setsockopt(sock, typ, option, (char *)&on, sizeof(on)) >= 0); +} + +//----------------------------------------------------------------------------- +// Set Re-Use Option for Port. +//----------------------------------------------------------------------------- +void CySocket::set_reuse_port() +{ +#ifdef SO_REUSEPORT + if(!set_option(SOL_SOCKET, SO_REUSEPORT)) + dperror("setsockopt(SO_REUSEPORT)\n"); +#endif +} + +//----------------------------------------------------------------------------- +// Set Re-Use Option for Address. +//----------------------------------------------------------------------------- +void CySocket::set_reuse_addr() +{ +#ifdef SO_REUSEADDR + if(!set_option(SOL_SOCKET, SO_REUSEADDR)) + dperror("setsockopt(SO_REUSEADDR)\n"); +#endif +} + +//----------------------------------------------------------------------------- +// Set Keep-Alive Option for Socket. +//----------------------------------------------------------------------------- +void CySocket::set_keep_alive() +{ +#ifdef SO_KEEPALIVE + if(!set_option(SOL_SOCKET, SO_KEEPALIVE)) + dperror("setsockopt(SO_KEEPALIVE)\n"); +#endif +} + +//----------------------------------------------------------------------------- +// Set Keep-Alive Option for Socket. +//----------------------------------------------------------------------------- +void CySocket::set_tcp_nodelay() +{ +#ifdef TCP_NODELAY + if(!set_option(IPPROTO_TCP, TCP_NODELAY)) + dperror("setsockopt(SO_KEEPALIVE)\n"); +#endif +} +//============================================================================= +// Send and receive +//============================================================================= +//----------------------------------------------------------------------------- +// Read a buffer (normal or SSL) +//----------------------------------------------------------------------------- +int CySocket::Read(char *buffer, unsigned int length) +{ +#ifdef Y_CONFIG_USE_OPEN_SSL + if(isSSLSocket) + return SSL_read(ssl, buffer, length); + else +#endif + return ::read(sock, buffer, length); +} +//----------------------------------------------------------------------------- +// Send a buffer (normal or SSL) +//----------------------------------------------------------------------------- +int CySocket::Send(char const *buffer, unsigned int length) +{ + unsigned int len = 0; +#ifdef Y_CONFIG_USE_OPEN_SSL + if(isSSLSocket) + len = SSL_write(ssl, buffer, length); + else +#endif + len = ::send(sock, buffer, length, MSG_NOSIGNAL); + if(len >= 0) + BytesSend += len; + return len; +} +//----------------------------------------------------------------------------- +// Check if Socket was closed by client +//----------------------------------------------------------------------------- +bool CySocket::CheckSocketOpen() +{ + char buffer[32]; + +#ifdef CONFIG_SYSTEM_CYGWIN + return !(recv(sock, buffer, sizeof(buffer), MSG_PEEK | MSG_NOSIGNAL) == 0); +#else + return !(recv(sock, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0); +#endif +} + +//============================================================================= +// Aggregated Send- and Receive- Operations +//============================================================================= + +//----------------------------------------------------------------------------- +// BASIC Send File over Socket for FILE* +// fd is an opened FILE-Descriptor +//----------------------------------------------------------------------------- +int CySocket::SendFile(int filed) +{ + if(!isValid) + return false; +#ifdef Y_CONFIG_HAVE_SENDFILE + // does not work with SSL !!! + off_t start = 0; + off_t end = lseek(filed,0,SEEK_END); + int written = 0; + if((written = ::sendfile(sock,filed,&start,end)) == -1) + { + perror("sendfile failed\n"); + return false; + } + else + BytesSend += written; +#else + char sbuf[1024]; + unsigned int r=0; + while ((r=read(filed, sbuf, 1024)) > 0) + { + if (Send(sbuf, r) < 0) + { + perror("sendfile failed\n"); + return false; + } + } +#endif // Y_CONFIG_HAVE_SENDFILE + log_level_printf(9,": Bytes:%ld\n", BytesSend); + return true; +} +//----------------------------------------------------------------------------- +// Receive File over Socket for FILE* filed +// read/write in small blocks (to save memory). +// usind sleep for sync input +// fd is an opened FILE-Descriptor +//----------------------------------------------------------------------------- +//TODO: Write upload Progress Informations into a file +unsigned int CySocket::ReceiveFileGivenLength(int filed, unsigned int _length) +{ + unsigned int _readbytes = 0; + char buffer[RECEIVE_BLOCK_LEN]; + int retries=0; + + do + { + // check bytes in Socket buffer + u_long readarg = 0; +#ifdef Y_CONFIG_USE_OPEN_SSL + if(isSSLSocket) + readarg = RECEIVE_BLOCK_LEN; + else +#endif + { + if(ioctl(sock, FIONREAD, &readarg) != 0)// How many bytes avaiable on socket? + break; + if(readarg > RECEIVE_BLOCK_LEN) // enough bytes to read + readarg = RECEIVE_BLOCK_LEN; // read only given length + } + if(readarg == 0) // nothing to read: sleep + { + retries++; + if(retries >NON_BLOCKING_MAX_RETRIES) + break; + sleep(1); + } + else + { + int bytes_gotten = Read(buffer, readarg); + + if(bytes_gotten == -1 && errno == EINTR)// non-blocking + continue; + if(bytes_gotten <= 0) // ERROR Code gotten or Conection closed by peer + { + isValid = false; + break; + } + _readbytes += bytes_gotten; + if (write(filed, buffer, bytes_gotten) != bytes_gotten) + { + perror("write file failed\n"); + return 0; + } + retries = 0; + if(bytes_gotten < NON_BLOCKING_TRY_BYTES) // to few bytes gotten: sleep + sleep(1); + } + log_level_printf(8,"Receive Block length:%d all:%d\n",_readbytes, _length); + } + while(_readbytes + RECEIVE_BLOCK_LEN < _length); + return _readbytes; +} +//----------------------------------------------------------------------------- +// read all data avaiable on Socket +//----------------------------------------------------------------------------- +std::string CySocket::ReceiveBlock() +{ + std::string result = ""; + char buffer[RECEIVE_BLOCK_LEN]; + + if(!isValid || !isOpened) + return ""; +// signal(SIGALRM, ytimeout); + alarm(1); + + while(true) + { + // check bytes in Socket buffer + u_long readarg = 0; +#ifdef Y_CONFIG_USE_OPEN_SSL + if(isSSLSocket) + readarg = RECEIVE_BLOCK_LEN; + else +#endif + // determine bytes that can be read + { + if(ioctl(sock, FIONREAD, &readarg) != 0) + break; + if(readarg == 0) // nothing to read + break; + if(readarg > RECEIVE_BLOCK_LEN) // need more loops + readarg = RECEIVE_BLOCK_LEN; + } + // Read data + int bytes_gotten = Read(buffer, readarg); + + if(bytes_gotten == -1 && errno == EINTR)// non-blocking + continue; + if(bytes_gotten <= 0) // ERROR Code gotten or Conection closed by peer + { + isValid = false; + break; + } + result.append(buffer, bytes_gotten); + if((u_long)bytes_gotten < readarg) // no more bytes + break; + } + alarm(0); + signal(SIGALRM,SIG_IGN); + return result; +} + +//----------------------------------------------------------------------------- +// Read on line (Ends with LF) or maximum MAX_LINE_BUFFER chars +// Result Contains [CR]LF! +//----------------------------------------------------------------------------- +std::string CySocket::ReceiveLine() +{ + char buffer[MAX_LINE_BUFFER]; + int bytes_gotten = 0; + std::string result=""; + + while(true) + { + // read one char + if(Read(buffer+bytes_gotten, 1) == 1) + { + if(buffer[bytes_gotten] == '\n') + break; + } + else + { + isValid = false; + break; + } + + if(bytes_gotten < MAX_LINE_BUFFER-1) + bytes_gotten ++; + else + break; + } + buffer[++bytes_gotten] = '\0'; + result.assign(buffer, bytes_gotten); + + return result; +} diff --git a/src/nhttpd/yhttpd_core/ysocket.h b/src/nhttpd/yhttpd_core/ysocket.h new file mode 100644 index 000000000..3db236a51 --- /dev/null +++ b/src/nhttpd/yhttpd_core/ysocket.h @@ -0,0 +1,98 @@ +//============================================================================= +// YHTTPD +// Socket Class : Basic Socket Operations +//----------------------------------------------------------------------------- +// Socket-Handler +//============================================================================= +#ifndef __yhttpd_ysocket_h__ +#define __yhttpd_ysocket_h__ + +// system +#include +#include +#include +#include + +#include "yconfig.h" +#include "ytypes_globals.h" + +#ifdef Y_CONFIG_USE_OPEN_SSL +#include +#endif +//----------------------------------------------------------------------------- +// Some common socket definitions +#ifndef SOCKET +#define SOCKET int +#endif +#ifndef INVALID_SOCKET +#define INVALID_SOCKET (SOCKET)(~0) +#define SOCKET_ERROR (-1) +#endif + +//----------------------------------------------------------------------------- +#define NON_BLOCKING_MAX_RETRIES 10 // Retries, if receive buffer is empty +#define NON_BLOCKING_TRY_BYTES 512 // try to catch min bytes .. else sleep +#define RECEIVE_BLOCK_LEN 1024 // receiving block length +#define MAX_LINE_BUFFER 1024*2 // Max length of one line + +//----------------------------------------------------------------------------- +class CySocket +{ +public: + // constructor & destructor + CySocket(); + CySocket(SOCKET s):sock(s){init();}; + virtual ~CySocket(void); + void init(void); // some extra initialization +#ifdef Y_CONFIG_USE_OPEN_SSL + bool initAsSSL(void); // initialize this socket as a SSL-socket + static bool initSSL(void); // global initialize of SSL-Library, CTX and cerificate/key-file + static std::string SSL_pemfile; // "server.pem" file with SSL-Certificate (now: only one certificate at all) + static std::string SSL_CA_file; // CA Certificate (optional) +#endif + // Socket handling + bool handling; // true: Socket yet is handled by a Connection Thread + bool isOpened; // is this socket open? + bool isValid; // false on Socket Errors. Must close. + struct timeval tv_start_waiting; // Put keep-alive Socket to Wait-Queue + + void close(void); // Close Socket + void shutdown(void); // Shutdown Socket + bool listen(int port, int max_connections); // Listen on Port for max Slave Connections + CySocket* accept(); // Wait for Connection. Returns "slave" Socket + void setAddr(sockaddr_in _clientaddr); + std::string get_client_ip(void); // Get IP from Client + SOCKET get_socket(){return sock;} // Return "C" Socket-ID + int get_accept_port(void); // Get Port for accepted connection + + // send & receive (basic) + int Read(char *buffer, unsigned int length); // Read a buffer (normal or SSL) + int Send(char const *buffer, unsigned int length); // Send a buffer (normal or SSL) + bool CheckSocketOpen(); // check if socket was closed by client + + // send & receive + int SendFile(int filed); // Send a File + std::string ReceiveBlock(); // receive a Block. Look at length + unsigned int ReceiveFileGivenLength(int filed, unsigned int _length); // Receive File of given length + std::string ReceiveLine(); // receive until "\n" + +protected: + long BytesSend; // Bytes send over Socket + bool set_option(int typ, int option); // Set Socket Options + void set_reuse_port(); // Set Reuse Port Option for Socket + void set_reuse_addr(); // Set Reuse Address Option for Socket + void set_keep_alive(); // Set Keep-Alive Option for Socket + void set_tcp_nodelay(); + +#ifdef Y_CONFIG_USE_OPEN_SSL + bool isSSLSocket; // This is a SSL based Socket + static SSL_CTX *SSL_ctx; // Global SSL ctx object + SSL *ssl; // ssl habdler for this socket +#endif +private: + std::string receive_buffer; // buffer for receive from socket + sockaddr_in addr; // "slave" Client Socket Data + socklen_t addr_len; // Length of addr struct + SOCKET sock; // "C" Socket-ID +}; +#endif // __yhttpd_ysocket_h__ diff --git a/src/nhttpd/yhttpd_core/ytypes_globals.h b/src/nhttpd/yhttpd_core/ytypes_globals.h new file mode 100644 index 000000000..43bdb43e3 --- /dev/null +++ b/src/nhttpd/yhttpd_core/ytypes_globals.h @@ -0,0 +1,157 @@ +//============================================================================= +// YHTTPD +// Type Definitions and Global Variables +//============================================================================= + +//----------------------------------------------------------------------------- +#ifndef __yhttpd_types_globals_h__ +#define __yhttpd_types_globals_h__ + +// c++ +#include +#include +#include + +//============================================================================= +// Global Types +//============================================================================= +typedef std::map CStringList; +typedef std::vector CStringArray; +typedef std::vector CStringVector; + +//============================================================================= +// HTTP Protocol Definitions +//============================================================================= +// HTTP-Status codes +typedef enum +{ + HTTP_NIL = -1, + HTTP_CONTINUE = 100, + HTTP_SWITCHING_PROTOCOLS = 101, // not used + HTTP_OK = 200, // use: everything is right. request (and response) handled + HTTP_CREATED = 201, // not used + HTTP_ACCEPTED = 202, // use: idicate accept of request. request take more time. + HTTP_NON_AUTHORITATIVE_INFO = 203, + HTTP_NO_CONTENT = 204, + HTTP_RESET_CONTENT = 205, // not used + HTTP_PARTIAL_CONTENT = 206, // not used + HTTP_MULTIBLE_CHOICES = 300, // not used + HTTP_MOVED_PERMANENTLY = 301, + HTTP_MOVED_TEMPORARILY = 302, + HTTP_SEE_OTHER = 303, // not used + HTTP_NOT_MODIFIED = 304, + HTTP_USE_PROXY = 305, // not used + HTTP_TEMPORARY_REDIRECT = 307, // not used + HTTP_BAD_REQUEST = 400, + HTTP_UNAUTHORIZED = 401, + HTTP_PAYMENT_REQUIRED = 402, // not used + HTTP_FORBIDDEN = 403, + HTTP_NOT_FOUND = 404, + HTTP_METHOD_NOT_ALLOWED = 405, // not used + HTTP_NOT_ACCEPTABLE = 406, // not used + HTTP_PROXY_AUTHENTICATION_REQUIRED= 407, // not used + HTTP_REQUEST_TIMEOUT = 408, // not used + HTTP_CONFLICT = 409, // not used + HTTP_GONE = 410, // not used + HTTP_LENGTH_REQUIRED = 411, // not used + HTTP_PRECONDITION_FAILED = 412, // not used + HTTP_REQUEST_ENTITY_TOO_LARGE = 413, // not used + HTTP_REQUEST_URI_TOO_LARGE = 414, // not used + HTTP_UNSUPPORTED_MEDIA_TYPE = 415, // not used + HTTP_REQUEST_RANGE_NOT_SATISFIABLE= 416, // not used + HTTP_EXPECTAION_FAILED = 417, // not used + HTTP_INTERNAL_SERVER_ERROR = 500, + HTTP_NOT_IMPLEMENTED = 501, + HTTP_BAD_GATEWAY = 502, // not used + HTTP_SERVICE_UNAVAILABLE = 503, // not used + HTTP_GATEWAY_TIMEOUT = 504, // not used + HTTP_HTTP_VERSION_NOT_SUPPORTED = 505, // not used +} HttpResponseType; + +typedef struct +{ + HttpResponseType type; + const char *name; + const char *info; +} HttpEnumString; + +static const HttpEnumString httpResponseNames[] = { + { HTTP_CONTINUE, "Continue" }, + { HTTP_SWITCHING_PROTOCOLS, "Switching Protocols" }, + { HTTP_OK, "OK" }, + { HTTP_CREATED, "Created" }, + { HTTP_ACCEPTED, "Accepted" }, + { HTTP_NON_AUTHORITATIVE_INFO, "No Authorative Info" }, + { HTTP_NO_CONTENT, "No Content" }, + { HTTP_RESET_CONTENT, "Reset Content" }, + { HTTP_PARTIAL_CONTENT, "Partial Content" }, + { HTTP_MULTIBLE_CHOICES, "Multiple Choices" }, + { HTTP_MOVED_PERMANENTLY, "Moved Permanently" }, + { HTTP_MOVED_TEMPORARILY, "Moved Temporarily" }, + { HTTP_SEE_OTHER, "See Other" }, + { HTTP_NOT_MODIFIED, "Not Modified" }, + { HTTP_USE_PROXY, "Use Proxy" }, + { HTTP_TEMPORARY_REDIRECT, "Temporary Redirect" }, + { HTTP_BAD_REQUEST, "Bad Request", "Unsupported method." }, + { HTTP_UNAUTHORIZED, "Unauthorized", "Access denied." }, + { HTTP_PAYMENT_REQUIRED, "Payment Required" }, + { HTTP_FORBIDDEN, "Forbidden", "" }, + { HTTP_NOT_FOUND, "Not Found", "The requested URL was not found on this server." }, + { HTTP_METHOD_NOT_ALLOWED, "Method Not Allowed" }, + { HTTP_NOT_ACCEPTABLE, "Not Acceptable" }, + { HTTP_PROXY_AUTHENTICATION_REQUIRED,"Proxy Authentication Required" }, + { HTTP_REQUEST_TIMEOUT, "Request Time-out" }, + { HTTP_CONFLICT, "Conflict" }, + { HTTP_GONE, "Gone" }, + { HTTP_LENGTH_REQUIRED, "Length Required" }, + { HTTP_PRECONDITION_FAILED, "Precondition Failed" }, + { HTTP_REQUEST_ENTITY_TOO_LARGE,"Request Entity Too Large" }, + { HTTP_REQUEST_URI_TOO_LARGE, "Request-URI Too Large" }, + { HTTP_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type" }, + { HTTP_REQUEST_RANGE_NOT_SATISFIABLE,"Requested range not satisfiable" }, + { HTTP_EXPECTAION_FAILED, "Expectation Failed" }, + { HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error", "Internal Server Error" }, + { HTTP_NOT_IMPLEMENTED, "Not Implemented", "The requested method is not recognized by this server." }, + { HTTP_BAD_GATEWAY, "Bad Gateway" }, + { HTTP_SERVICE_UNAVAILABLE, "Service Unavailable" }, + { HTTP_GATEWAY_TIMEOUT, "Gateway Time-out" }, + { HTTP_HTTP_VERSION_NOT_SUPPORTED,"HTTP Version not supported" }, +}; + +// HTTP-methods +typedef enum +{ + M_UNKNOWN = 0, + M_POST = 1, + M_GET, + M_HEAD, + M_PUT, + M_DELETE, + M_TRACE +} THttp_Method; + +// Date Format RFC 1123 +static const char RFC1123FMT[] = "%a, %d %b %Y %H:%M:%S GMT"; + +// mime-table +typedef struct +{ + const char *fileext; + const char *mime; +} TMimePair; +static const TMimePair MimeFileExtensions[] = { + {"xml", "text/xml"}, + {"htm", "text/html"}, + {"html", "text/html"}, + {"yhtm", "text/html"}, + {"yhtml", "text/html"}, + {"jpg", "image/jpeg"}, + {"jpeg", "image/jpeg"}, + {"gif", "image/gif"}, + {"png", "image/png"}, + {"txt", "image/plain"}, + {"css", "text/css"}, + +}; + +#endif // __yhttpd_types_globals_h__ diff --git a/src/nhttpd/yhttpd_core/ywebserver.cpp b/src/nhttpd/yhttpd_core/ywebserver.cpp new file mode 100644 index 000000000..27e32259a --- /dev/null +++ b/src/nhttpd/yhttpd_core/ywebserver.cpp @@ -0,0 +1,507 @@ +//============================================================================= +// YHTTPD +// Webserver Class : Until now: exact one instance +//============================================================================= +// c++ +#include +#include + +// system +#include +#include +#include +#include +#include +#include +#include +// tuxbox +#include + +// yhttpd +#include "yhttpd.h" +#include "ytypes_globals.h" +#include "ywebserver.h" +#include "ylogging.h" +#include "helper.h" +#include "ysocket.h" +#include "yconnection.h" +#include "yrequest.h" + +//============================================================================= +// Initialization of static variables +//============================================================================= + bool CWebserver::is_threading = true; + pthread_mutex_t CWebserver::mutex = PTHREAD_MUTEX_INITIALIZER;; + +//============================================================================= +// Constructor & Destructor & Initialization +//============================================================================= +CWebserver::CWebserver() +{ + terminate = false; + for(int i=0;i= HTTPD_MAX_CONNECTIONS-1) + sleep(1); + + // Socket Error? + if(fd == -1 && errno != EINTR) + { + perror("select"); + return false; + } + + // Socket Timeout? + if(fd == 0) + { + // Testoutput for long living threads + if(++test_counter >= MAX_TIMEOUTS_TO_TEST) + { + for(int j=0;j < HTTPD_MAX_CONNECTIONS;j++) + if(SocketList[j] != NULL) // here is a socket + log_level_printf(2,"FD-TEST sock:%d handle:%d open:%d\n",SocketList[j]->get_socket(), + SocketList[j]->handling,SocketList[j]->isOpened); + test_counter=0; + } + // some connection closing previous missed? + if(++timeout_counter >= MAX_TIMEOUTS_TO_CLOSE) + { + CloseConnectionSocketsByTimeout(); + timeout_counter=0; + } + continue; // main loop again + } + //---------------------------------------------------------------------------------------- + // Check all observed descriptors & check new or re-use Connections + //---------------------------------------------------------------------------------------- + for(int i = listener; i <= fdmax; i++) + { + int slot = -1; + if(FD_ISSET(i, &read_fds)) // Socket observed? + { // we got one!! + if (i == listener) // handle new connections + slot = AcceptNewConnectionSocket(); + else // Connection on an existing open Socket = reuse (keep-alive) + { + slot = SL_GetExistingSocket(i); + if(slot>=0) + log_level_printf(2,"FD: reuse con fd:%d\n",SocketList[slot]->get_socket()); + } + // prepare Connection handling + if(slot>=0) + if(SocketList[slot] != NULL && !SocketList[slot]->handling && SocketList[slot]->isValid) + { + log_level_printf(2,"FD: START CON HANDLING con fd:%d\n",SocketList[slot]->get_socket()); + FD_CLR(SocketList[slot]->get_socket(), &master); // remove from master set + SocketList[slot]->handling = true; // prepares for thread-handling + if(!handle_connection(SocketList[slot]))// handle this activity + { // Can not handle more threads + char httpstr[]=HTTP_PROTOCOL " 503 Service Unavailable\r\n\r\n"; + SocketList[slot]->Send(httpstr, strlen(httpstr)); + SL_CloseSocketBySlot(slot); + } + } + } + }// for + CloseConnectionSocketsByTimeout(); // Check connections to close + + }//while +#else + while(!terminate) + { + CySocket *newConnectionSock; + if(!(newConnectionSock = listenSocket.accept() )) //Now: Blocking wait + { + dperror("Socket accept error. Continue.\n"); + continue; + } + log_level_printf(3,"Socket connect from %s\n", (listenSocket.get_client_ip()).c_str() ); +#ifdef Y_CONFIG_USE_OPEN_SSL + if(Cyhttpd::ConfigList["SSL"]=="true") + newConnectionSock->initAsSSL(); // make it a SSL-socket +#endif + handle_connection(newConnectionSock); + } +#endif + return true; +} +//============================================================================= +// SocketList Handler +//============================================================================= +//----------------------------------------------------------------------------- +// Accept new Connection +//----------------------------------------------------------------------------- +int CWebserver::AcceptNewConnectionSocket() +{ + int slot = -1; + CySocket *connectionSock = NULL; + int newfd; + + if(!(connectionSock = listenSocket.accept() )) // Blocking wait + { + dperror("Socket accept error. Continue.\n"); + delete connectionSock; + return -1; + } +#ifdef Y_CONFIG_USE_OPEN_SSL + if(Cyhttpd::ConfigList["SSL"]=="true") + connectionSock->initAsSSL(); // make it a SSL-socket +#endif + log_level_printf(2,"FD: new con fd:%d on port:%d\n",connectionSock->get_socket(), connectionSock->get_accept_port()); + + // Add Socket to List + slot = SL_GetFreeSlot(); + if(slot < 0) + { + connectionSock->close(); + aprintf("No free Slot in SocketList found. Open:%d\n",open_connections); + } + else + { + SocketList[slot] = connectionSock; // put it to list + fcntl(connectionSock->get_socket() , F_SETFD , O_NONBLOCK); // set non-blocking + open_connections++; // count open connectins + newfd = connectionSock->get_socket(); + if (newfd > fdmax) // keep track of the maximum fd + fdmax = newfd; + } + return slot; +} + +//----------------------------------------------------------------------------- +// Get Index for Socket from SocketList +//----------------------------------------------------------------------------- +int CWebserver::SL_GetExistingSocket(SOCKET sock) +{ + int slot = -1; + for(int j=0;j < HTTPD_MAX_CONNECTIONS;j++) + if(SocketList[j] != NULL // here is a socket + && SocketList[j]->get_socket() == sock) // we know that socket + { + slot = j; + break; + } + return slot; +} +//----------------------------------------------------------------------------- +// Get Index for free Slot in SocketList +//----------------------------------------------------------------------------- +int CWebserver::SL_GetFreeSlot() +{ + int slot = -1; + for(int j=0;j < HTTPD_MAX_CONNECTIONS;j++) + if(SocketList[j] == NULL) // here is a free slot + { + slot = j; + break; + } + return slot; +} + +//----------------------------------------------------------------------------- +// Look for Sockets to close +//----------------------------------------------------------------------------- +void CWebserver::CloseConnectionSocketsByTimeout() +{ + CySocket *connectionSock = NULL; + for(int j=0;j < HTTPD_MAX_CONNECTIONS;j++) + if(SocketList[j] != NULL // here is a socket + && !SocketList[j]->handling) // it is not handled + { + connectionSock = SocketList[j]; + SOCKET thisSocket = connectionSock->get_socket(); + bool shouldClose = true; + + if(!connectionSock->isValid) // If not valid -> close + ; // close + else if(connectionSock->tv_start_waiting.tv_sec != 0 || SocketList[j]->tv_start_waiting.tv_usec != 0) + { // calculate keep-alive timeout + struct timeval tv_now; + struct timezone tz_now; + gettimeofday(&tv_now, &tz_now); + long long tdiff = ((tv_now.tv_sec - connectionSock->tv_start_waiting.tv_sec) * 1000000 + + (tv_now.tv_usec - connectionSock->tv_start_waiting.tv_usec)); + if(tdiff < HTTPD_KEEPALIVE_TIMEOUT || tdiff <0) + shouldClose = false; + } + if(shouldClose) + { + log_level_printf(2,"FD: close con Timeout fd:%d\n",thisSocket); + SL_CloseSocketBySlot(j); + } + } +} +//----------------------------------------------------------------------------- +// Add Socket fd to FD_SET again (for select-handling) +// Add start-time for waiting for connection re-use / keep-alive +//----------------------------------------------------------------------------- +void CWebserver::addSocketToMasterSet(SOCKET fd) +{ + int slot = SL_GetExistingSocket(fd); // get slot/index for fd + if(slot<0) + return; + log_level_printf(2,"FD: add to master fd:%d\n",fd); + struct timeval tv_now; + struct timezone tz_now; + gettimeofday(&tv_now, &tz_now); + SocketList[slot]->tv_start_waiting = tv_now; // add keep-alive wait time + FD_SET(fd, &master); // add fd to select-master-set +} + +//----------------------------------------------------------------------------- +// Close (FD_SET handled) Socket +// Clear it from SocketList +//----------------------------------------------------------------------------- +void CWebserver::SL_CloseSocketBySlot(int slot) +{ + open_connections--; // count open connections + if(SocketList[slot] == NULL) + return; + SocketList[slot]->handling = false; // no handling anymore + FD_CLR(SocketList[slot]->get_socket(), &master);// remove from master set + SocketList[slot]->close(); // close the socket + delete SocketList[slot]; // destroy ySocket + SocketList[slot] = NULL; // free in list +} + +//============================================================================= +// Thread Handling +//============================================================================= +//----------------------------------------------------------------------------- +// Check if IP is allowed for keep-alive +//----------------------------------------------------------------------------- +bool CWebserver::CheckKeepAliveAllowedByIP(std::string client_ip) +{ + pthread_mutex_lock( &mutex ); + bool do_keep_alive = true; + CStringVector::const_iterator it = conf_no_keep_alive_ips.begin(); + while(it != conf_no_keep_alive_ips.end()) + { + if(trim(*it) == client_ip) + do_keep_alive = false; + it++; + } + pthread_mutex_unlock( &mutex ); + return do_keep_alive; +} +//----------------------------------------------------------------------------- +// Set Entry(number)to NULL in Threadlist +//----------------------------------------------------------------------------- +void CWebserver::clear_Thread_List_Number(int number) +{ + pthread_mutex_lock( &mutex ); + if(number ySock = newSock; + newConn->ySock->handling = true; + newConn->WebserverBackref = this; + //newConn->is_treaded = is_threading; + newConn->is_treaded = false; + + int index = -1; + if(0) /*if(is_threading) FIXME not work */ + { + pthread_mutex_lock( &mutex ); + // look for free Thread slot + for(int i=0;ithread_number = index; //remember Index of Thread slot (for clean up) + + // Create an orphan Thread. It is not joinable anymore + pthread_mutex_unlock( &mutex ); + + // start connection Thread + if(pthread_create(&Connection_Thread_List[index], &attr, WebThread, (void *)newConn) != 0) + dperror("Could not create Connection-Thread\n"); + } + else // non threaded + WebThread((void *)newConn); + return ((index != -1) || !is_threading); +} +//------------------------------------------------------------------------- +// Webserver-Thread for each connection +//------------------------------------------------------------------------- +void *WebThread(void *args) +{ + CWebserverConnection *con; + CWebserver *ws; + TWebserverConnectionArgs *newConn = (TWebserverConnectionArgs *) args; + ws = newConn->WebserverBackref; + + bool is_threaded = newConn->is_treaded; + if(is_threaded) + log_level_printf(1,"++ Thread 0x06%X gestartet\n", (int) pthread_self()); + + if (!newConn) { + dperror("WebThread called without arguments!\n"); + if(newConn->is_treaded) + pthread_exit(NULL); + } + + // (1) create & init Connection + con = new CWebserverConnection(ws); + con->Request.UrlData["clientaddr"] = newConn->ySock->get_client_ip(); // TODO:here? + con->sock = newConn->ySock; // give socket reference + newConn->ySock->handling = true; // dont handle this socket now be webserver main loop + + // (2) handle the connection + con->HandleConnection(); + + // (3) end connection handling +#ifdef Y_CONFIG_FEATURE_KEEP_ALIVE + if(!con->keep_alive) + log_level_printf(2,"FD SHOULD CLOSE sock:%d!!!\n",con->sock->get_socket()); + else + ws->addSocketToMasterSet(con->sock->get_socket()); // add to master set +#else + delete newConn->ySock; +#endif + if(!con->keep_alive) + con->sock->isValid = false; + con->sock->handling = false; // socket can be handled by webserver main loop (select) again + + // (4) end thread + delete con; + int thread_number = newConn->thread_number; + delete newConn; + if(is_threaded) + { + log_level_printf(1,"-- Thread 0x06%X beendet\n",(int)pthread_self()); + ws->clear_Thread_List_Number(thread_number); + pthread_exit(NULL); + } + return NULL; +} diff --git a/src/nhttpd/yhttpd_core/ywebserver.h b/src/nhttpd/yhttpd_core/ywebserver.h new file mode 100644 index 000000000..73c5c8b9f --- /dev/null +++ b/src/nhttpd/yhttpd_core/ywebserver.h @@ -0,0 +1,91 @@ +//============================================================================= +// YHTTPD +// Webserver Class : Until now: exact one instance +//----------------------------------------------------------------------------- +// The Webserver Class creates one "master" Listener Socket on given Port. +// If a Connection is accepted, a new Socket ist used. The Webserver creates +// a new Connection-Class witch is (normaly) Threaded. The Connection-Class +// handles Request and Response. +// For HTTP/1.1 permanent Connections (keep-alive) socket-multiplexing using +// FD_SET and select() is implemented. Sockets are stored in SocketList and +// can be reused for the connected client (to reduce socket handling overhead). +// Reuse of connections is often done by pipelinig (read->send->read->send ...) +//============================================================================= +#ifndef __yhttpd_ywebserver_h__ +#define __yhttpd_ywebserver_h__ + +// system +#include +#include +#include + +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "ysocket.h" + +//----------------------------------------------------------------------------- +class CWebserver; //forward declaration + +//----------------------------------------------------------------------------- +// Arguments for Connection-Thread +//----------------------------------------------------------------------------- +typedef struct +{ + CySocket *ySock; // Connection "Slave" Socket + CWebserver *WebserverBackref; // Backreference to Webserver + bool is_treaded; // Use threading? + int thread_number; // Number of Thread (informational use) +} TWebserverConnectionArgs; + +//----------------------------------------------------------------------------- +// until now: One Instance for one hosted Web +//----------------------------------------------------------------------------- +class CWebserver +{ +private: + static pthread_mutex_t mutex; + pthread_t Connection_Thread_List[HTTPD_MAX_CONNECTIONS]; //Thread-List per webserver + fd_set master; // master file descriptor list for select() + fd_set read_fds; // read file descriptor list for select() + int fdmax; // maximum file descriptor number + CySocket *SocketList[HTTPD_MAX_CONNECTIONS]; // List of concurrent hadled connections + int open_connections; // Number of opened connections + pthread_attr_t attr; // pthread Attributes for deattach +protected: + bool terminate; // flag: indicate to terminate the Webserver + CySocket listenSocket; // Master Socket for listening + unsigned int port; // Port to listen on + bool handle_connection(CySocket *newSock); // Create a new Connection Instance and handle Connection + + // Connection Socket handling + int AcceptNewConnectionSocket(); // Start new Socket connection + void CloseConnectionSocketsByTimeout(); // Check Sockets to close + void SL_CloseSocketBySlot(int slot); // Close socket by slot index + int SL_GetExistingSocket(SOCKET sock); // look for socket reuse + int SL_GetFreeSlot(); // get free slot + + +public: + static bool is_threading; // Use Threading for new Connections + CStringVector conf_no_keep_alive_ips; // List of IP for NO keep-alive + + // constructor & destructor + CWebserver(); + ~CWebserver(void); + + void init(unsigned int _port, bool _is_threading) // Initialize Webserver Settings + {port=_port; is_threading=_is_threading;} + void set_conf_no_keep_alive_ips(CStringVector _conf_no_keep_alive_ips) + {conf_no_keep_alive_ips=_conf_no_keep_alive_ips;} + bool run(void); // Start the Webserver + void stop(void) // Stop the Webserver + {terminate=true;}; + + // public for WebTread + void clear_Thread_List_Number(int number); // Set Entry(number)to NULL in Threadlist + void addSocketToMasterSet(SOCKET fd); // add Socket to select master set + bool CheckKeepAliveAllowedByIP(std::string client_ip); // Check if IP is allowed for keep-alive +}; + +#endif // __yhttpd_ywebserver_h__ diff --git a/src/nhttpd/yhttpd_mods/AUTHORS b/src/nhttpd/yhttpd_mods/AUTHORS new file mode 100644 index 000000000..aec719772 --- /dev/null +++ b/src/nhttpd/yhttpd_mods/AUTHORS @@ -0,0 +1,3 @@ + + +Johannes Golombek [yjogol@cvs.tuxbox.org] diff --git a/src/nhttpd/yhttpd_mods/Makefile.am b/src/nhttpd/yhttpd_mods/Makefile.am new file mode 100644 index 000000000..74d213c4f --- /dev/null +++ b/src/nhttpd/yhttpd_mods/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src/zapit/include \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/nhttpd \ + -I$(top_srcdir)/src/nhttpd/yhttpd_core \ + -I$(top_srcdir)/lib/connection \ + -I$(top_srcdir)/lib/libeventserver \ + -I$(top_srcdir)/lib/libconfigfile \ + @FREETYPE_CFLAGS@ + +AM_CPPFLAGS = -fno-rtti -fno-exceptions + +noinst_LIBRARIES = libyhttpdmods.a + +libyhttpdmods_a_SOURCES = \ + mod_yparser.cpp mod_testhook.cpp mod_auth.cpp mod_cache.cpp mod_sendfile.cpp mod_weblog.cpp + diff --git a/src/nhttpd/yhttpd_mods/mod_auth.cpp b/src/nhttpd/yhttpd_mods/mod_auth.cpp new file mode 100644 index 000000000..5a7af3c5f --- /dev/null +++ b/src/nhttpd/yhttpd_mods/mod_auth.cpp @@ -0,0 +1,108 @@ +//============================================================================= +// YHTTPD +// TestHook +//============================================================================= + +#include +#include +#include "mod_auth.h" +#include "helper.h" + +//----------------------------------------------------------------------------- +// HOOK: response_hook +//----------------------------------------------------------------------------- +THandleStatus CmAuth::Hook_PrepareResponse(CyhookHandler *hh) +{ + THandleStatus status = HANDLED_CONTINUE; + + if(authenticate) + { + if( (hh->UrlData["clientaddr"]).find(IADDR_LOCAL)>0 && + (no_auth_client == "" || + (hh->UrlData["clientaddr"]).find(no_auth_client)>0)) // dont check local calls or calls from NoAuthClient + { + if (!CheckAuth(hh)) + { + hh->SetError(HTTP_UNAUTHORIZED); + status = HANDLED_ERROR; + } + } + } + return status; +} + +//----------------------------------------------------------------------------- +// HOOK: webserver_readconfig_hook Handler +// This hook ist called from ReadConfig +//----------------------------------------------------------------------------- +THandleStatus CmAuth::Hook_ReadConfig(CConfigFile *Config, CStringList &ConfigList) +{ + username = Config->getString("mod_auth.username", AUTHUSER); + password = Config->getString("mod_auth.password", AUTHPASSWORD); + no_auth_client = Config->getString("mod_auth.no_auth_client", ""); + authenticate = Config->getBool("mod_auth.authenticate", false); + ConfigList["mod_auth.username"] = username; + ConfigList["mod_auth.password"] = password; + ConfigList["mod_auth.no_auth_client"] = no_auth_client; + ConfigList["mod_auth.authenticate"] = Config->getString("mod_auth.authenticate", "false"); + return HANDLED_CONTINUE; +} + +//----------------------------------------------------------------------------- +// check if given username an pssword are valid +//----------------------------------------------------------------------------- +bool CmAuth::CheckAuth(CyhookHandler *hh) +{ + if (hh->HeaderList["Authorization"] == "") + return false; + std::string encodet = hh->HeaderList["Authorization"].substr(6,hh->HeaderList["Authorization"].length() - 6); + std::string decodet = decodeBase64(encodet.c_str()); + int pos = decodet.find_first_of(':'); + std::string user = decodet.substr(0,pos); + std::string passwd = decodet.substr(pos + 1, decodet.length() - pos - 1); + return (user.compare(username) == 0 && + passwd.compare(password) == 0); +} + +//----------------------------------------------------------------------------- +// decode Base64 buffer to String +//----------------------------------------------------------------------------- +std::string CmAuth::decodeBase64(const char *b64buffer) +{ + char *newString, *org_newString; //shorter then b64buffer + std::string result; + if((newString = (char *)malloc(sizeof(char) * strlen(b64buffer) + 1) ) != NULL) + { + org_newString = newString; + int i = 0; + unsigned long c = 0; + + while (*b64buffer) + { + int oneChar = *b64buffer++; + if(oneChar >= '0' && oneChar <= '9') oneChar = oneChar - '0' + 52; + else if(oneChar >= 'A' && oneChar <= 'Z') oneChar = oneChar - 'A'; + else if(oneChar >= 'a' && oneChar <= 'z') oneChar = oneChar - 'a' + 26; + else if(oneChar == '+') oneChar = 62; + else if(oneChar == '/') oneChar = 63; + else if(oneChar == '=') oneChar = 0; + else continue; + + c = (c << 6) | oneChar; + if (++i == 4) + { + *newString++ = (char) (c >> 16); + *newString++ = (char) (c >> 8); + *newString++ = (char) c; + i = 0; + } + } + *newString++ = '\0'; + result = std::string(org_newString); + free(org_newString); + return result; + } + else + return ""; +} + diff --git a/src/nhttpd/yhttpd_mods/mod_auth.h b/src/nhttpd/yhttpd_mods/mod_auth.h new file mode 100644 index 000000000..a010dba63 --- /dev/null +++ b/src/nhttpd/yhttpd_mods/mod_auth.h @@ -0,0 +1,30 @@ +//============================================================================= +// YHTTPD +// mod_auth : Authentication +//============================================================================= +#ifndef __yhttpd_mod_auth_h__ +#define __yhttpd_mod_auth_h__ + + +#include "yhook.h" +class CmAuth : public Cyhook +{ +public: + bool authenticate; + CmAuth(){}; + ~CmAuth(){}; + + // Hooks + virtual THandleStatus Hook_PrepareResponse(CyhookHandler *hh); + virtual std::string getHookName(void) {return std::string("mod_auth");} + virtual std::string getHookVersion(void) {return std::string("$Revision: 1.2 $");} + virtual THandleStatus Hook_ReadConfig(CConfigFile *Config, CStringList &ConfigList); +protected: + bool CheckAuth(CyhookHandler *hh); + std::string decodeBase64(const char *b64buffer); + std::string username; + std::string password; + std::string no_auth_client; +}; +#endif // __yhttpd_mod_auth_h__ + diff --git a/src/nhttpd/yhttpd_mods/mod_cache.cpp b/src/nhttpd/yhttpd_mods/mod_cache.cpp new file mode 100644 index 000000000..fb685e1c2 --- /dev/null +++ b/src/nhttpd/yhttpd_mods/mod_cache.cpp @@ -0,0 +1,257 @@ +//============================================================================= +// YHTTPD +// Module: CacheManager (mod_cache) +//============================================================================= + +// system +#include +#include +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "helper.h" +#include "mod_cache.h" + +//============================================================================= +// Initialization of static variables +//============================================================================= +pthread_mutex_t CmodCache::mutex = PTHREAD_MUTEX_INITIALIZER; +TCacheList CmodCache::CacheList; + +//============================================================================= +// Constructor & Destructor & Initialization +//============================================================================= + +//----------------------------------------------------------------------------- +// HOOK: Response Prepare Handler +// Response Prepare Check. +// Is it in cache? +//----------------------------------------------------------------------------- +THandleStatus CmodCache::Hook_PrepareResponse(CyhookHandler *hh) +{ + hh->status = HANDLED_NONE; + + log_level_printf(4,"mod_cache prepare hook start url:%s\n",hh->UrlData["fullurl"].c_str()); + std::string url = hh->UrlData["fullurl"]; + if(CacheList.find(url) != CacheList.end()) // is in Cache. Rewrite URL or not modified + { + pthread_mutex_lock(&mutex); // yeah, its mine + + // Check if modified + time_t if_modified_since = (time_t)-1; + if(hh->HeaderList["If-Modified-Since"] != "") // Have If-Modified-Since Requested by Browser? + { + struct tm mod; + if(strptime(hh->HeaderList["If-Modified-Since"].c_str(), RFC1123FMT, &mod) != NULL) + { + mod.tm_isdst = 0; // daylight saving flag! + if_modified_since = mktime(&mod); // Date given + } + } + + // normalize obj_last_modified to GMT + struct tm *tmp = gmtime(&(CacheList[url].created)); + time_t obj_last_modified_gmt = mktime(tmp); + bool modified = (if_modified_since == (time_t)-1) || (if_modified_since < obj_last_modified_gmt); + + // Send file or not-modified header + if(modified) + { + hh->SendFile(CacheList[url].filename); + hh->ResponseMimeType = CacheList[url].mime_type; + } + else + hh->SetHeader(HTTP_NOT_MODIFIED, CacheList[url].mime_type, HANDLED_READY); + pthread_mutex_unlock(&mutex); + } + log_level_printf(4,"mod_cache hook prepare end status:%d\n",(int)hh->status); + + return hh->status; +} +//----------------------------------------------------------------------------- +// HOOK: Response Send Handler +// If an other Hook has set HookVarList["CacheCategory"] then the Conntent +// in hh->yresult should be cached into a file. +// Remeber: url, filename, mimetype, category, createdate +//----------------------------------------------------------------------------- +THandleStatus CmodCache::Hook_SendResponse(CyhookHandler *hh) +{ + hh->status = HANDLED_NONE; + std::string url = hh->UrlData["fullurl"]; + log_level_printf(4,"mod_cache hook start url:%s\n",url.c_str()); + + std::string category = hh->HookVarList["CacheCategory"]; + if(!(hh->HookVarList["CacheCategory"]).empty()) // Category set = cache it + { + AddToCache(hh, url, hh->yresult, hh->HookVarList["CacheMimeType"], category); // create cache file and add to cache list + hh->ContentLength = (hh->yresult).length(); + hh->SendFile(CacheList[url].filename); // Send as file + hh->ResponseMimeType = CacheList[url].mime_type; // remember mime + } + else if(hh->UrlData["path"] == "/y/") // /y/ commands + { + hh->status = HANDLED_READY; + if(hh->UrlData["filename"] == "cache-info") + yshowCacheInfo(hh); + else if(hh->UrlData["filename"] == "cache-clear") + yCacheClear(hh); + else + hh->status = HANDLED_CONTINUE; // y-calls can be implemented anywhere + } + log_level_printf(4,"mod_cache hook end status:%d\n",(int)hh->status); + + return hh->status; +} + +//----------------------------------------------------------------------------- +// HOOK: Hook_ReadConfig +// This hook ist called from ReadConfig +//----------------------------------------------------------------------------- +THandleStatus CmodCache::Hook_ReadConfig(CConfigFile *Config, CStringList &ConfigList) +{ + cache_directory= Config->getString("mod_cache.cache_directory", CACHE_DIR); + ConfigList["mod_cache.cache_directory"] = cache_directory; + return HANDLED_CONTINUE; +} + +//------------------------------------------------------------------------- +// Build and Add a cache item +//------------------------------------------------------------------------- +void CmodCache::AddToCache(CyhookHandler *hh, std::string url, std::string content, std::string mime_type, std::string category) +{ + FILE *fd = NULL; + pthread_mutex_lock(&mutex); + std::string filename = cache_directory + "/" + itoa(CacheList.size()); // build cache filename + mkdir(cache_directory.c_str(), 0777); // Create Cache directory + if((fd = fopen(filename.c_str(),"w")) != NULL) // open file + { + if(fwrite(content.c_str(), content.length(), 1, fd) == 1) // write cache file + { + CacheList[url].filename = filename; // add cache data item + CacheList[url].mime_type = mime_type; + CacheList[url].category = category; + CacheList[url].created = time(NULL); + std::string test = CacheList[url].filename; + } + fflush(fd); // flush and close file + fclose(fd); + } + pthread_mutex_unlock(&mutex); // Free +} +//------------------------------------------------------------------------- +// Delete URL from cachelist +//------------------------------------------------------------------------- +void CmodCache::RemoveURLFromCache(std::string url) +{ + pthread_mutex_lock(&mutex); // yeah, its mine + if(CacheList.find(url) != CacheList.end()) + { + remove((CacheList[url].filename).c_str()); // delete file + CacheList.erase(url); // remove from list + } + pthread_mutex_unlock(&mutex); // Free +} +//------------------------------------------------------------------------- +//------------------------------------------------------------------------- +void CmodCache::RemoveCategoryFromCache(std::string category) +{ + pthread_mutex_lock(&mutex); + bool restart = false; + do + { + restart = false; + TCacheList::iterator i = CacheList.begin(); + for ( ; i!= CacheList.end(); i++ ) + { + TCache *item = &((*i).second); + if(item->category == category) + { + CacheList.erase( ((*i).first) ); + restart = true; + break; + } + } + } + while(restart); + pthread_mutex_unlock(&mutex); +} + +//------------------------------------------------------------------------- +// +//------------------------------------------------------------------------- +void CmodCache::DeleteCache(void) +{ + pthread_mutex_lock(&mutex); // yeah, its mine + CacheList.clear(); // Clear entire list + pthread_mutex_unlock(&mutex); // Free +} + +//------------------------------------------------------------------------- +// y-Call : show cache Information +//------------------------------------------------------------------------- +void CmodCache::yshowCacheInfo(CyhookHandler *hh) +{ + std::string yresult; + + hh->SendHTMLHeader("Cache Information"); + yresult += string_printf("Cache Information
\n\n"); + yresult += string_printf("Cache Module...: %s
\n",(getHookName()).c_str() ); + yresult += string_printf("Cache Version..: %s
\n",(getHookVersion()).c_str() ); + yresult += string_printf("Cache Directory: %s
\n",cache_directory.c_str() ); + yresult += string_printf("
\n
CACHE
\n"); + + // cache list + yresult += string_printf("\n"); + yresult += string_printf("\n"); + pthread_mutex_lock(&mutex); + TCacheList::iterator i = CacheList.begin(); + for ( ; i!= CacheList.end(); i++ ) + { + TCache *item = &((*i).second); + char timeStr[80]; + strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&(item->created)) ); + yresult += string_printf("" \ + "\n", + ((*i).first).c_str(), + item->mime_type.c_str(), + item->filename.c_str(), + item->category.c_str(), + timeStr, + ((*i).first).c_str(), + item->category.c_str() + ); + } + pthread_mutex_unlock(&mutex); // Free + yresult += string_printf("
URLMimeFilenameCategoryCreatedRemove
%s%s%s%s%surl " \ + "category
\n"); + yresult += string_printf("Delete Cache
\n"); + hh->addResult(yresult, HANDLED_READY); + hh->SendHTMLFooter(); +} +//------------------------------------------------------------------------- +// y-Call : clear cache +//------------------------------------------------------------------------- +void CmodCache::yCacheClear(CyhookHandler *hh) +{ + std::string result=""; + if(hh->ParamList["category"] != "") + { + RemoveCategoryFromCache(hh->ParamList["category"]); + result = string_printf("Category (%s) removed from cache.
", hh->ParamList["category"].c_str()); + } + else if(hh->ParamList["url"] != "") + { + RemoveURLFromCache(hh->ParamList["url"]); + result = string_printf("URL (%s) removed from cache.
", hh->ParamList["url"].c_str()); + } + else + { + DeleteCache(); + result = string_printf("Cache deleted.
"); + } + hh->SendHTMLHeader("Cache deletion"); + hh->WriteLn(result); + hh->SendHTMLFooter(); + +} + diff --git a/src/nhttpd/yhttpd_mods/mod_cache.h b/src/nhttpd/yhttpd_mods/mod_cache.h new file mode 100644 index 000000000..c953163d6 --- /dev/null +++ b/src/nhttpd/yhttpd_mods/mod_cache.h @@ -0,0 +1,56 @@ +//============================================================================= +// YHTTPD +// CacheManager +//----------------------------------------------------------------------------- +//============================================================================= +#ifndef __yhttpd_mod_cache_h__ +#define __yhttpd_mod_cache_h__ + +// system +#include +// c++ +#include +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "yhook.h" + +//----------------------------------------------------------------------------- +typedef struct +{ + std::string filename; + std::string mime_type; + std::string category; + time_t created; +} TCache; + +typedef std::map TCacheList; + +//----------------------------------------------------------------------------- +class CmodCache : public Cyhook +{ +private: + static TCacheList CacheList; + std::string cache_directory; + void yshowCacheInfo(CyhookHandler *hh); + void yCacheClear(CyhookHandler *hh); +public: + static pthread_mutex_t mutex; + + CmodCache(){}; + ~CmodCache(void){}; + + void AddToCache(CyhookHandler *hh, std::string url, std::string content, std::string mime_type, std::string cartegory="none"); + static void RemoveURLFromCache(std::string url); + static void RemoveCategoryFromCache(std::string category); + static void DeleteCache(void); + + // Hooks + virtual THandleStatus Hook_PrepareResponse(CyhookHandler *hh); + virtual THandleStatus Hook_SendResponse(CyhookHandler *hh); + virtual std::string getHookVersion(void) {return std::string("$Revision: 1.1 $");} + virtual std::string getHookName(void) {return std::string("mod_cache");} + virtual THandleStatus Hook_ReadConfig(CConfigFile *Config, CStringList &ConfigList); +}; + +#endif /* __yhttpd_mod_cache_h__ */ diff --git a/src/nhttpd/yhttpd_mods/mod_sendfile.cpp b/src/nhttpd/yhttpd_mods/mod_sendfile.cpp new file mode 100644 index 000000000..d355f4634 --- /dev/null +++ b/src/nhttpd/yhttpd_mods/mod_sendfile.cpp @@ -0,0 +1,214 @@ +//============================================================================= +// YHTTPD +// Module: SendFile (mod_sendfile) +//----------------------------------------------------------------------------- +// Send a File (main) with given path and filename. +// It procuced a Response-Header (SendHeader). +// It supports Client caching mechanism "If-Modified-Since". +//----------------------------------------------------------------------------- +// RFC 2616 / 14.25 If-Modified-Since +// +// The If-Modified-Since request-header field is used with a method to +// make it conditional: if the requested variant has not been modified +// since the time specified in this field, an entity will not be +// returned from the server; instead, a 304 (not modified) response will +// be returned without any message-body. +// +// If-Modified-Since = "If-Modified-Since" ":" HTTP-date +// An example of the field is: +// +// If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT +// +// A GET method with an If-Modified-Since header and no Range header +// requests that the identified entity be transferred only if it has +// been modified since the date given by the If-Modified-Since header. +// The algorithm for determining this includes the following cases: +// +// a) If the request would normally result in anything other than a +// 200 (OK) status, or if the passed If-Modified-Since date is +// invalid, the response is exactly the same as for a normal GET. +// A date which is later than the server's current time is +// invalid. +// +// b) If the variant has been modified since the If-Modified-Since +// date, the response is exactly the same as for a normal GET. +// +// c) If the variant has not been modified since a valid If- +// Modified-Since date, the server SHOULD return a 304 (Not +// Modified) response. +// +// yjogol: ASSUMPTION Date-Format is ONLY RFC 1123 compatible! +//============================================================================= + +// system +#include +#include +#include +#include +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "helper.h" +#include "mod_sendfile.h" + +//============================================================================= +// Initialization of static variables +//============================================================================= +CStringList CmodSendfile::sendfileTypes; + +//============================================================================= +// Constructor & Destructor & Initialization +//============================================================================= + +//----------------------------------------------------------------------------- +// HOOK: Response Prepare Handler +// Response Prepare Check. +//----------------------------------------------------------------------------- +THandleStatus CmodSendfile::Hook_PrepareResponse(CyhookHandler *hh) +{ + hh->status = HANDLED_NONE; + + int filed; + log_level_printf(4,"mod_sendfile prepare hook start url:%s\n",hh->UrlData["fullurl"].c_str()); + std::string mime = sendfileTypes[hh->UrlData["fileext"]]; + if(mime != "") + { + //TODO: Check allowed directories / actually in GetFileName + // build filename + std::string fullfilename = GetFileName(hh, hh->UrlData["path"], hh->UrlData["filename"]); + + if( (filed = OpenFile(hh, fullfilename) ) != -1 ) //can access file? + { + struct stat statbuf; + hh->LastModified = (time_t)0; + // It is a regular file? + fstat(filed,&statbuf); + if (S_ISREG(statbuf.st_mode)) + { + // get file size and modify date + hh->ContentLength = statbuf.st_size; + hh->LastModified = statbuf.st_mtime; + } + close(filed); + + // check If-Modified-Since + time_t if_modified_since = (time_t)-1; + if(hh->HeaderList["If-Modified-Since"] != "") + { + struct tm mod; + if(strptime(hh->HeaderList["If-Modified-Since"].c_str(), RFC1123FMT, &mod) != NULL) + { + mod.tm_isdst = 0; // daylight saving flag! + if_modified_since = mktime(&mod); + } + } + + // normalize obj_last_modified to GMT + struct tm *tmp = gmtime(&(hh->LastModified)); + time_t LastModifiedGMT = mktime(tmp); + bool modified = (if_modified_since == (time_t)-1) || (if_modified_since < LastModifiedGMT); + + // Send normal or not-modified header + if(modified) + { + hh->SendFile(fullfilename); + hh->ResponseMimeType = mime; + } + else + hh->SetHeader(HTTP_NOT_MODIFIED, mime, HANDLED_READY); + } + else + { + aprintf("mod_sendfile: File not found. url:(%s)\n", hh->UrlData["url"].c_str()); + hh->SetError(HTTP_NOT_FOUND); + } + } + log_level_printf(4,"mod_sendfile prepare hook end status:%d\n",(int)hh->status); + + return hh->status; +} + +//----------------------------------------------------------------------------- +// HOOK: Hook_ReadConfig +// This hook ist called from ReadConfig +//----------------------------------------------------------------------------- +THandleStatus CmodSendfile::Hook_ReadConfig(CConfigFile *Config, CStringList &ConfigList) +{ + std::string exttypes = Config->getString("mod_sendfile.mime_types", HTTPD_SENDFILE_EXT); + ConfigList["mod_sendfile.mime_types"] = exttypes; + + bool ende = false; + std::string item, ext, mime; + sendfileTypes.clear(); + while(!ende) + { + if(!ySplitStringExact(exttypes,",",item,exttypes)) + ende = true; + if(ySplitStringExact(item,":",ext,mime)) + { + ext = trim(ext); + sendfileTypes[ext] = trim(mime); + } + } + return HANDLED_CONTINUE; +} + +//----------------------------------------------------------------------------- +// Send File: Build Filename +// First Look at PublicDocumentRoot than PrivateDocumentRoot than pure path +//----------------------------------------------------------------------------- +std::string CmodSendfile::GetFileName(CyhookHandler *hh, std::string path, std::string filename) +{ + std::string tmpfilename; + if(path[path.length()-1] != '/') + tmpfilename = path + "/" + filename; + else + tmpfilename = path + filename; + + if( access(std::string(hh->WebserverConfigList["PublicDocumentRoot"] + tmpfilename).c_str(),4) == 0) + tmpfilename = hh->WebserverConfigList["PublicDocumentRoot"] + tmpfilename; + else if(access(std::string(hh->WebserverConfigList["PrivatDocumentRoot"] + tmpfilename).c_str(),4) == 0) + tmpfilename = hh->WebserverConfigList["PrivatDocumentRoot"] + tmpfilename; +#ifdef Y_CONFIG_FEATUE_SENDFILE_CAN_ACCESS_ALL + else if(access(tmpfilename.c_str(),4) == 0) + ; +#endif + else + { + return ""; + } + return tmpfilename; +} +//----------------------------------------------------------------------------- +// Send File: Open File and check file type +//----------------------------------------------------------------------------- +int CmodSendfile::OpenFile(CyhookHandler *hh, std::string fullfilename) +{ + int fd= -1; + std::string tmpstring; + if(fullfilename.length() > 0) + { + fd = open( fullfilename.c_str(), O_RDONLY ); + if (fd<=0) + { + aprintf("cannot open file %s: ", fullfilename.c_str()); + dperror(""); + } + } + return fd; +} +//----------------------------------------------------------------------------- +// Send File: Determine MIME-Type fro File-Extention +//----------------------------------------------------------------------------- +std::string CmodSendfile::GetContentType(std::string ext) +{ + std::string ctype = "text/plain"; + ext = string_tolower(ext); + for (unsigned int i = 0;i < (sizeof(MimeFileExtensions)/sizeof(MimeFileExtensions[0])); i++) + if (MimeFileExtensions[i].fileext == ext) + { + ctype = MimeFileExtensions[i].mime; + break; + } + return ctype; +} diff --git a/src/nhttpd/yhttpd_mods/mod_sendfile.h b/src/nhttpd/yhttpd_mods/mod_sendfile.h new file mode 100644 index 000000000..1a2773856 --- /dev/null +++ b/src/nhttpd/yhttpd_mods/mod_sendfile.h @@ -0,0 +1,39 @@ +//============================================================================= +// YHTTPD +// SendFile +//----------------------------------------------------------------------------- +//============================================================================= +#ifndef __yhttpd_mod_sendfile_h__ +#define __yhttpd_mod_sendfile_h__ + +// system +#include +// c++ +#include +// yhttpd +#include "yconfig.h" +#include "ytypes_globals.h" +#include "yhook.h" + +//----------------------------------------------------------------------------- +class CmodSendfile : public Cyhook +{ +private: +protected: + int OpenFile(CyhookHandler *hh, std::string fullfilename); + std::string GetFileName(CyhookHandler *hh, std::string path, std::string filename); + std::string GetContentType(std::string ext); + static CStringList sendfileTypes; +public: + CmodSendfile(){}; + ~CmodSendfile(void){}; + + // Hooks + virtual THandleStatus Hook_PrepareResponse(CyhookHandler *hh); +// virtual THandleStatus Hook_SendResponse(CyhookHandler *hh); + virtual std::string getHookName(void) {return std::string("mod_sendfile");} + virtual std::string getHookVersion(void) {return std::string("$Revision: 1.1 $");} + virtual THandleStatus Hook_ReadConfig(CConfigFile *Config, CStringList &ConfigList); +}; + +#endif /* __yhttpd_mod_sendfile_h__ */ diff --git a/src/nhttpd/yhttpd_mods/mod_testhook.cpp b/src/nhttpd/yhttpd_mods/mod_testhook.cpp new file mode 100644 index 000000000..6f3195203 --- /dev/null +++ b/src/nhttpd/yhttpd_mods/mod_testhook.cpp @@ -0,0 +1,17 @@ +//============================================================================= +// YHTTPD +// TestHook +//============================================================================= + +#include "mod_testhook.h" + +THandleStatus CTesthook::Hook_SendResponse(CyhookHandler *hh) +{ + THandleStatus status = HANDLED_NONE; + if(hh->UrlData["filename"] == "test2") + { + hh->yresult = "test it 2222\n"; + status = HANDLED_READY; + } + return status; +} diff --git a/src/nhttpd/yhttpd_mods/mod_testhook.h b/src/nhttpd/yhttpd_mods/mod_testhook.h new file mode 100644 index 000000000..a92f9ed98 --- /dev/null +++ b/src/nhttpd/yhttpd_mods/mod_testhook.h @@ -0,0 +1,21 @@ +//============================================================================= +// YHTTPD +// TestHook +//============================================================================= +#ifndef TESTHOOK_H_ +#define TESTHOOK_H_ + + +#include "yhook.h" +class CTesthook : public Cyhook +{ +public: + THandleStatus Hook_SendResponse(CyhookHandler *hh); + CTesthook(){}; + ~CTesthook(){}; + + virtual std::string getHookName(void) {return std::string("Testhook");} + +}; +#endif /*TESTHOOK_H_*/ + diff --git a/src/nhttpd/yhttpd_mods/mod_weblog.cpp b/src/nhttpd/yhttpd_mods/mod_weblog.cpp new file mode 100644 index 000000000..41cc37230 --- /dev/null +++ b/src/nhttpd/yhttpd_mods/mod_weblog.cpp @@ -0,0 +1,364 @@ +//============================================================================= +// YHTTPD +// mod_weblog : Logging of HTTPD-Requests/Responses +//----------------------------------------------------------------------------- +// Normally +//============================================================================= +#include +#include +#include + +#include "mod_weblog.h" +#include "helper.h" + +//============================================================================= +// Initialization of static variables +//============================================================================= + pthread_mutex_t CmWebLog::WebLog_mutex = PTHREAD_MUTEX_INITIALIZER; + FILE *CmWebLog::WebLogFile = NULL; + int CmWebLog::RefCounter = 0; + std::string CmWebLog::WebLogFilename=LOG_FILE; + std::string CmWebLog::LogFormat =LOG_FORMAT; +//============================================================================= +// Constructor & Destructor +//============================================================================= +CmWebLog::CmWebLog(void) +{ + pthread_mutex_lock(&WebLog_mutex); // yea, its mine + RefCounter++; + pthread_mutex_unlock(&WebLog_mutex); +} +//----------------------------------------------------------------------------- +CmWebLog::~CmWebLog(void) +{ + pthread_mutex_lock(&WebLog_mutex); // yea, its mine + --RefCounter; + if(RefCounter <= 0) + CloseLogFile(); + pthread_mutex_unlock(&WebLog_mutex); +} +//============================================================================= +// HOOKS +//============================================================================= +//----------------------------------------------------------------------------- +// HOOK: Hook_EndConnection +//----------------------------------------------------------------------------- +THandleStatus CmWebLog::Hook_EndConnection(CyhookHandler *hh) +{ + if(LogFormat == "CLF") + AddLogEntry_CLF(hh); + else if(LogFormat == "ELF") + AddLogEntry_ELF(hh); + return HANDLED_CONTINUE; // even on Log-Error: continue +} + +//----------------------------------------------------------------------------- +// HOOK: Hook_ReadConfig +// This hook ist called from ReadConfig +//----------------------------------------------------------------------------- +THandleStatus CmWebLog::Hook_ReadConfig(CConfigFile *Config, CStringList &ConfigList) +{ + LogFormat = Config->getString("mod_weblog.log_format", LOG_FORMAT); + WebLogFilename = Config->getString("mod_weblog.logfile", LOG_FILE); + return HANDLED_CONTINUE; +} +//----------------------------------------------------------------------------- +bool CmWebLog::OpenLogFile() +{ + if(WebLogFilename == "") + return false; + if(WebLogFile == NULL) + { + bool isNew = false; + pthread_mutex_lock(&WebLog_mutex); // yeah, its mine + if(access(WebLogFilename.c_str(), 4) != 0) + isNew = true; + WebLogFile = fopen(WebLogFilename.c_str(),"a"); + if(isNew) + { + if(LogFormat == "ELF") + { + printf("#Version: 1.0\n"); + printf("#Remarks: yhttpd" WEBSERVERNAME "\n"); + printf("#Fields: c-ip username date time x-request cs-uri sc-status cs-method bytes time-taken x-time-request x-time-response cached\n"); + } + } + pthread_mutex_unlock(&WebLog_mutex); + } + return (WebLogFile != NULL); +} +//----------------------------------------------------------------------------- +void CmWebLog::CloseLogFile() +{ + if(WebLogFile != NULL) + { + pthread_mutex_lock(&WebLog_mutex); // yeah, its mine + fclose(WebLogFile); + WebLogFile = NULL; + pthread_mutex_unlock(&WebLog_mutex); + } +} +//----------------------------------------------------------------------------- +#define bufferlen 1024*8 +bool CmWebLog::printf(const char *fmt, ...) +{ + if(!OpenLogFile()) + return false; + bool success = false; + char buffer[bufferlen]; + if(WebLogFile != NULL) + { + pthread_mutex_lock(&WebLog_mutex); // yeah, its mine + va_list arglist; + va_start( arglist, fmt ); + if(arglist) + vsnprintf( buffer, bufferlen, fmt, arglist ); + va_end(arglist); + unsigned int len = strlen(buffer); + success = (fwrite(buffer, len, 1, WebLogFile) == len); + fflush(WebLogFile); + pthread_mutex_unlock(&WebLog_mutex); + } + return success; +} + +//----------------------------------------------------------------------------- +// CLF - Common Logfile Format +// +// Example: 127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 +// +// The common logfile format is as follows: +// remotehost rfc931 authuser [date] "request" status bytes +// +// remotehost: Remote hostname (or IP number if DNS hostname is not available, or if DNSLookup is Off. +// rfc931: The remote logname of the user. +// authuser: The username as which the user has authenticated himself. +// [date]: Date and time of the request. +// "request": The request line exactly as it came from the client. +// status: The HTTP status code returned to the client. +// bytes: The content-length of the document transferred. +//----------------------------------------------------------------------------- +void CmWebLog::AddLogEntry_CLF(CyhookHandler *hh) +{ + std::string cs_method; + switch (hh->Method) + { + case M_GET: cs_method = "GET"; break; + case M_POST: cs_method = "POST"; break; + case M_HEAD: cs_method = "HEAD"; break; + + default: + cs_method = "unknown"; + break; + } + std::string c_ip = hh->UrlData["clientaddr"].c_str(); + std::string request_startline = hh->UrlData["startline"].c_str(); + int s_status = hh->httpStatus; + int bytes = hh->GetContentLength(); + + struct tm *time_now; + time_t now = time(NULL); + char request_time[80]; + + time_now = localtime(&now); + strftime(request_time, 80, "[%d/%b/%Y:%H:%M:%S]", time_now); + + printf("%s - - %s \"%s\" %d %d\n", + c_ip.c_str(), + request_time, + request_startline.c_str(), + s_status, + bytes); +} + +//----------------------------------------------------------------------------- +/* + Definition: (ELF) Extended Log File Format + W3C Working Draft WD-logfile-960323 (http://www.w3.org/pub/WWW/TR/WD-logfile-960323.html) + + An extended log file contains a sequence of lines containing ASCII + characters terminated by either the sequence LF or CRLF. + Log file generators should follow the line termination convention for + the platform on which they are executed. Analyzers should accept either form. + Each line may contain either a directive or an entry. + + Entries consist of a sequence of fields relating to a single HTTP + transaction. Fields are separated by whitespace, the use of tab characters + for this purpose is encouraged. If a field is unused in a particular + entry dash "-" marks the omitted field. Directives record information about + the logging process itself. + + Lines beginning with the # character contain directives. + The following directives are defined: + + - Version: . + The version of the extended log file format used. + This draft defines version 1.0. + - Fields: [...] + Specifies the fields recorded in the log. + - Software: string + Identifies the software which generated the log. + - Start-Date: