SOLIB = libpnd.so.1 # canonicle name
SOLIB1 = libpnd.so.1.0.1 # versioned name
XMLOBJ = lib/tinyxml/tinystr.o lib/tinyxml/tinyxml.o lib/tinyxml/tinyxmlerror.o lib/tinyxml/tinyxmlparser.o
-ALLOBJ = pnd_conf.o pnd_container.o pnd_discovery.o pnd_pxml.o pnd_notify.o pnd_locate.o pnd_tinyxml.o
+ALLOBJ = pnd_conf.o pnd_container.o pnd_discovery.o pnd_pxml.o pnd_notify.o pnd_locate.o pnd_tinyxml.o pnd_pndfiles.o
all: ${SOLIB} ${LIB} conftest discotest notifytest locatetest pndnotifyd
Some things to be done..
+- replace brute force memcmp() in pnd pnd with a fancy pants CS alg
+
- review pnd_tinyxml to ensure the PXML_FILENAME is csae insensitive as needed
+- fix pnd_tinyxml.. why does it need 'if ( s )' protection. it assumes some filename weird stuff
+ - why does it need filenames at all for icons/etc?!
+
+- fix is_pxml_valid_app() .. right now it always returns 1!
- make pnd_pndfiles seek of PXML more efficient; fread ( 1, nmemb ) gotta be slow :)
+- make accrused PXML from pnd-buffer growable, not locked at 32k/X size
+
apps/pndnotifyd.c:// TODO: Catch HUP and reparse config
apps/pndnotifyd.c:// TODO: Should perhaps direct all printf's through a vsprintf handler to avoid redundant "if ! g_daemon_mode"
apps/pndnotifyd.c:// TODO: During daemon mode, should perhaps syslog or log errors
// either if the goods are near the end. How big is an average .png for an average icon
// size?
#define PND_PXML_WINDOW_SIZE 4096
+#define PND_PXML_WINDOW_FRACTIONAL ( PND_PXML_WINDOW_SIZE - 10 )
// pnd_seek_pxml should vaguely work like fseek, trying to position at begin of the appended/found PXML
// On return of 0, assuming nothing.
// On 1, assume that the FILE pointer is positioned for next read to pull in the PXML line by line
unsigned char pnd_pnd_seek_pxml ( FILE *f );
+// accrue_pxml will read through the given FILE * until it finds </PXML> (case insensitively)
+// Returns 1 on success (</PXML> found), leaving file pointer after the </PXML>\n
+// Returns 0 on failure (likely file pointer is at the end of the file, having sought out the </PXML>
+unsigned char pnd_pnd_accrue_pxml ( FILE *f, char *target, unsigned int maxlen );
+
+// pnd_match_binbuf will find a case insensitve string within a binary buffer (ie: strcasestr will
+// only work in a non-binary buffer.) Brute force zombies ahead!
+char *pnd_match_binbuf ( char *haystack, unsigned int maxlen, char *needle );
+
#ifdef __cplusplus
} /* "C" */
#endif
#include <stdio.h> /* for FILE etc */
#include <stdlib.h> /* for malloc */
+
+#define __USE_GNU /* for strcasestr */
#include <string.h> /* for making ftw.h happy */
#define _XOPEN_SOURCE 500
int typeflag, struct FTW *ftwbuf )
{
unsigned char valid = 0; // 1 for plaintext PXML, 2 for PND...
+ pnd_pxml_handle pxmlh = 0;
+
+ //printf ( "disco root callback encountered '%s'\n", fpath );
// PXML.xml is a possible application candidate (and not a dir named PXML.xml :)
if ( typeflag & FTW_D ) {
+ //printf ( " .. is dir, skipping\n" );
return ( 0 ); // skip directories and other non-regular files
}
// PND/PNZ file and others may be valid as well .. but lets leave that for now
+ // printf ( "%s %s\n", fpath + ftwbuf -> base, PND_PACKAGE_FILEEXT );
if ( strcasecmp ( fpath + ftwbuf -> base, PXML_FILENAME ) == 0 ) {
valid = 1;
- } else if ( strcasecmp ( fpath + ftwbuf -> base, PND_PACKAGE_FILEEXT "\0" ) == 0 ) {
+ } else if ( strcasestr ( fpath + ftwbuf -> base, PND_PACKAGE_FILEEXT "\0" ) ) {
valid = 2;
}
// if not a file of interest, just keep looking until we run out
if ( ! valid ) {
+ //printf ( " .. bad filename, skipping\n" );
return ( 0 );
}
// potentially a valid application
if ( valid == 1 ) {
// Plaintext PXML file
- //printf ( "disco callback encountered '%s'\n", fpath );
-
- pnd_pxml_handle pxmlh;
+ //printf ( "PXML: disco callback encountered '%s'\n", fpath );
// pick up the PXML if we can
-
pxmlh = pnd_pxml_fetch ( (char*) fpath );
- if ( ! pxmlh ) {
- return ( 0 ); // continue the scan
+ } else if ( valid == 2 ) {
+ // PND ... ??
+ FILE *f;
+ char pxmlbuf [ 32 * 1024 ]; // TBD: assuming 32k pxml accrual buffer is a little lame
+
+ //printf ( "PND: disco callback encountered '%s'\n", fpath );
+
+ // is this a valid .pnd file? The filename is a candidate already, but verify..
+ // .. presence of PXML appended, or at least contained within?
+ // .. presence of an icon appended after PXML?
+
+ // open it up..
+ f = fopen ( fpath, "r" );
+
+ // try to locate the PXML portion
+ if ( ! pnd_pnd_seek_pxml ( f ) ) {
+ fclose ( f );
+ return ( 0 ); // pnd or not, but not to spec. Pwn'd the pnd?
+ }
+
+ // accrue it into a buffer
+ if ( ! pnd_pnd_accrue_pxml ( f, pxmlbuf, 32 * 1024 ) ) {
+ fclose ( f );
+ return ( 0 );
}
+ //printf ( "buffer is %s\n", pxmlbuf );
+ //fflush ( stdout );
+
+ // by now, we have <PXML> .. </PXML>, try to parse..
+ pxmlh = pnd_pxml_fetch_buffer ( (char*) fpath, pxmlbuf );
+
+ }
+
+ // pxmlh is useful?
+ if ( pxmlh ) {
+
// look for any overrides, if requested
pnd_pxml_merge_override ( pxmlh, disco_overrides );
// check for validity and add to resultset if it looks executable
if ( pnd_is_pxml_valid_app ( pxmlh ) ) {
+ char b [ 1024 ]; // TBD: also lame
pnd_disco_t *p;
p = pnd_box_allocinsert ( disco_box, (char*) fpath, sizeof(pnd_disco_t) );
- p -> title_en = strdup ( pnd_pxml_get_app_name ( pxmlh ) );
- p -> icon = strdup ( pnd_pxml_get_icon_path ( pxmlh ) );
- p -> exec = strdup ( pnd_pxml_get_exec_path ( pxmlh ) );
- p -> unique_id = strdup ( pnd_pxml_get_unique_id ( pxmlh ) );
- p -> main_category = strdup ( pnd_pxml_get_primary_category ( pxmlh ) );
- p -> clockspeed = strdup ( pnd_pxml_get_clockspeed ( pxmlh ) );
-
+ if ( pnd_pxml_get_app_name ( pxmlh ) ) {
+ p -> title_en = strdup ( pnd_pxml_get_app_name ( pxmlh ) );
+ }
+ if ( pnd_pxml_get_icon_path ( pxmlh ) ) {
+ p -> icon = strdup ( pnd_pxml_get_icon_path ( pxmlh ) );
+ }
+ if ( pnd_pxml_get_exec_path ( pxmlh ) ) {
+ snprintf ( b, 1024, "pnd_run_magic %s", pnd_pxml_get_exec_path ( pxmlh ) );
+ p -> exec = strdup ( b );
+ }
+ if ( pnd_pxml_get_unique_id ( pxmlh ) ) {
+ p -> unique_id = strdup ( pnd_pxml_get_unique_id ( pxmlh ) );
+ }
+ if ( pnd_pxml_get_primary_category ( pxmlh ) ) {
+ p -> main_category = strdup ( pnd_pxml_get_primary_category ( pxmlh ) );
+ }
+ if ( pnd_pxml_get_clockspeed ( pxmlh ) ) {
+ p -> clockspeed = strdup ( pnd_pxml_get_clockspeed ( pxmlh ) );
+ }
+
+ } else {
+ //printf ( "Invalid PXML; skipping.\n" );
}
// ditch pxml
pnd_pxml_delete ( pxmlh );
- } else if ( valid == 2 ) {
- // PND ... ??
- printf ( "PND: disco callback encountered '%s'\n", fpath );
-
- // is this a valid .pnd file? The filename is a candidate already, but verify..
- // .. presence of PXML appeneded, or at least contained within?
- // .. presence of an icon appended after PXML?
-
- }
+ } // got a pxmlh
return ( 0 ); // continue the tree walk
}
#include <stdio.h> /* for FILE etc */
#include <stdlib.h> /* for malloc */
-#include <string.h> /* for making ftw.h happy */
+#include <ctype.h> /* for isprint */
+
+#define __USE_GNU
+#include <string.h> /* for making strcasestr happy */
#include "pnd_container.h"
#include "pnd_pxml.h"
#include "pnd_pndfiles.h"
unsigned char pnd_pnd_seek_pxml ( FILE *f ) {
- char *b;
- unsigned int len;
+ char *b; // buffer
+ char *match; // match within buffer
+ unsigned int len; // length of file (not suporting 'big files' 2GB..)
+ unsigned int pos; // current tape head
+ unsigned int readable; // amount to read (for small files/chunks)
- b = malloc ( PND_PXML_WINDOW_SIZE );
+ b = malloc ( PND_PXML_WINDOW_SIZE + 1 );
if ( ! b ) {
return ( 0 );
}
- memset ( b, '\0', PND_PXML_WINDOW_SIZE );
+ memset ( b, '\0', PND_PXML_WINDOW_SIZE + 1 );
// determine length of file
fseek ( f, 0, SEEK_END );
-
len = ftell ( f );
-
fseek ( f, 0, SEEK_SET );
/* ready to scan through the file, backwards
*/
- //strcasestr ( b, PXML_TAGHEAD );
-
+ // easy case or no?
+ if ( len <= PND_PXML_WINDOW_SIZE ) {
+ pos = 0;
+ readable = len;
+ } else {
+ pos = len - PND_PXML_WINDOW_SIZE;
+ readable = PND_PXML_WINDOW_SIZE;
+ }
+ while ( 1 ) {
+
+ printf ( "find pxml; pos %u readable %u\n", pos, readable );
+
+ // seek into this blocks position
+ fseek ( f, pos, SEEK_SET );
+
+ // read
+ fread ( b, 1, readable, f );
+
+ // find the head tag here? now, there are serious heavy duty algorithyms for locating
+ // strings within an arbitrary buffer. Thats needs to be done. This is the worst
+ // performing brute force strategy here.
+ if ( ( match = pnd_match_binbuf ( b, readable, PXML_TAGHEAD ) ) ) {
+ fseek ( f, pos + ( match - b ), SEEK_SET );
+ printf ( " match found at %u\n", pos + ( match - b ) );
+ free ( b );
+ return ( 1 );
+ }
+
+ // no match, so we need to back up another chunk; if we can't
+ // back up that much, we're on our last check. if we can't back
+ // up at all, we've already been here and time to fail
+ if ( pos == 0 ) {
+ break; // done, FAIL
+ } else if ( pos > PND_PXML_WINDOW_FRACTIONAL ) {
+ pos -= PND_PXML_WINDOW_FRACTIONAL;
+ readable = PND_PXML_WINDOW_SIZE;
+ } else {
+ readable = PND_PXML_WINDOW_SIZE - pos;
+ memset ( b + pos, '\0', PND_PXML_WINDOW_SIZE - pos );
+ pos = 0;
+ }
+
+ } // while
// exeunt, with alarums
-
free ( b );
+ return ( 0 );
+}
+
+unsigned char pnd_pnd_accrue_pxml ( FILE *f, char *target, unsigned int maxlen ) {
+ char inbuf [ 1024 ]; // TBD: love all these assumptions? noob!
+ char *insert = target;
+ unsigned int l;
+
+ while ( fgets ( inbuf, 1023, f ) ) {
+
+ // copy inbuf onto end of target
+#if 1
+ strncpy ( insert, inbuf, maxlen );
+ // reduce counter for max size so we can avoid buffer overruns
+ l = strlen ( inbuf );
+ maxlen -= l; // reduce
+ insert += l; // increment
+#else
+ strncat ( target, inbuf, maxlen );
+#endif
+
+ if ( strcasestr ( inbuf, PXML_TAGFOOT ) ) {
+ return ( 1 );
+ }
+
+ } // while
+
+ return ( 0 );
+}
+
+char *pnd_match_binbuf ( char *haystack, unsigned int maxlen, char *needle ) {
+ char *end = haystack + maxlen - strlen ( needle );
+ unsigned int needlelen = strlen ( needle );
+
+ while ( haystack < end ) {
+
+ if ( isprint(*haystack) ) {
+
+ if ( strncasecmp ( haystack, needle, needlelen ) == 0 ) {
+ //printf ( "haystack %s\n", haystack );
+ return ( haystack );
+ }
+
+ }
+
+ haystack += 1;
+ }
- return ( 1 );
+ return ( NULL );
}
pnd_pxml_t *p = (pnd_pxml_t*) h;
// for now, lets just verify the exec-path is valid
+
//printf ( "exec is '%s'\n", p -> exec );
+ return ( 1 );
+
+ // even this is complicated by pnd_run.sh semantics .. can't check if it exists
+ // during discovery, since it is not mounted yet..
+#if 0
struct stat buf;
if ( stat ( p -> exec, &buf ) == 0 ) {
return ( 1 ); // path is present
}
+#endif
return ( 0 );
}
char anotherbuffer [ FILENAME_MAX ];
strcpy ( anotherbuffer, pFilename );
char *s = strstr ( anotherbuffer, PXML_FILENAME );
- strcpy ( s, strdup(pElem->GetText()));
- app->icon = strdup(anotherbuffer);
+ if ( s ) {
+ strcpy ( s, strdup(pElem->GetText()));
+ app->icon = strdup(anotherbuffer);
+ }
}
pElem = hRoot.FirstChild( "description" ).FirstChildElement("en").Element();
char anotherbuffer [ FILENAME_MAX ];
strcpy ( anotherbuffer, pFilename );
char *s = strstr ( anotherbuffer, PXML_FILENAME );
- strcpy ( s, strdup(pElem->GetText()));
- app->exec = strdup(anotherbuffer);
+ if ( s ) {
+ strcpy ( s, strdup(pElem->GetText()));
+ app->exec = strdup(anotherbuffer);
+ } else if ( ( s = strrchr ( anotherbuffer, '/' ) ) ) {
+ s += 1;
+ strcpy ( s, strdup(pElem->GetText()));
+ app->exec = strdup(anotherbuffer);
+ }
}
pElem = hRoot.FirstChild( "category" ).FirstChildElement("main").Element();
-<?xml version="1.0"?>
<PXML>
<title>
- <en>Program Title</en>
+ <en>sample 3</en>
<de>Program Title in German Language</de>
<fr>Program Title in French Language</fr>
<it>Program Title in Italian Language</it>
</title>
-<unique_id>127ulysis</unique_id>
+<unique_id>256twinky</unique_id>
<standalone>Yes</standalone>
<startdir>../differentdir</startdir>
</PXML>
+
--- /dev/null
+<?xml version="1.0"?>
+<PXML>
+<title>
+ <en>x86 ls</en>
+ <de>Program Title in German Language</de>
+ <fr>Program Title in French Language</fr>
+ <it>Program Title in Italian Language</it>
+</title>
+
+<unique_id>123456x86ls</unique_id>
+
+<standalone>Yes</standalone>
+
+<icon>program.png</icon>
+
+<description>
+ <en>This is the [b]English Description[/b] of the file.
+ Can use [i]multiple lines[/i] and BBCode.</en>
+ <de>The German Description</de>
+ <it>The Italian Description</it>
+ <fr>The French Description</fr>
+</description>
+
+<previewpic>
+ <pic1>./preview/pic1.jpg</pic1>
+ <pic2>./preview/pic2.jpg</pic2>
+</previewpic>
+
+<author>
+ <name>EvilDragon</name>
+ <website>http://www.openpandora.org</website>
+</author>
+
+<version>
+ <major>1</major>
+ <minor>1</minor>
+ <release>1</release>
+ <build>2</build>
+</version>
+
+<exec>program.exe</exec>
+
+<category>
+ <main>Main category</main>
+ <subcategory1>Subcategory 1</subcategory1>
+ <subcategory2>Subcategory 2</subcategory2>
+</category>
+
+<altcategory>
+ <main>Alternate category</main>
+ <subcategory1>Alternate Subcategory 1</subcategory1>
+ <subcategory2>Alternate Subcategory 2</subcategory2>
+</altcategory>
+
+<osversion>
+ <major>1</major>
+ <minor>1</minor>
+ <release>1</release>
+ <build>2</build>
+</osversion>
+
+<associationitem1>
+ <name>View this Picture</name>
+ <filetype>jpg,bmp,gif</filetype>
+ <parameter>view</parameter>
+</associationitem1>
+
+<associationitem2>
+ <name>Convert this Picture</name>
+ <filetype>jpg,bmp,gif</filetype>
+ <parameter>convert</parameter>
+</associationitem2>
+
+<associationitem3>
+ <name>Watch This Movie</name>
+ <filetype>mpg,avi,wmv</filetype>
+ <parameter>convert</parameter>
+</associationitem3>
+
+<clockspeed>600</clockspeed>
+
+<background>Yes</background>
+
+<startdir>../differentdir</startdir>
+
+</PXML>
--- /dev/null
+#!/bin/bash
+pkgname=$1
+folder=$3
+xml=$2
+mkisofs -o $pkgname.iso -R $folder
+cat $pkgname.iso $xml > $pkgname
+rm $pkgname.iso
#!/bin/bash
#input pnd_run.sh -p "/path/to/foobar.pnd" -e "exe" --a "arguments for exe"
+# -u to skip union mount
+# -b to override basename
#output none
########################### FS NAMES NEED ADJUSTMENT #################
# check if all vars are set to sensible values
# parse arguments
-TEMP=`getopt -o p:e:a:: --long p-long,e-long:,a-long: -- "$@"`
+TEMP=`getopt -o p:e:a:b:u:: --long p-long,e-long:,a-long: -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
case "$1" in
-p|--p-long) echo "pnd set to \`$2'" ;PND=$2;shift 2;;
-e|--e-long) echo "exec set to \`$2'" ;EXENAME=$2;shift 2 ;;
+ -u) echo "u set, no union pls!";UNION=1;shift 2 ;;
+ -b) echo "BASENAME set to $2";BASENAME=$2;shift 2;;
-a|--a-long)
- # a has an optional argument. As we are in quoted mode,
- # an empty parameter will be generated if its optional
- # argument is not found.
case "$2" in
"") echo "no arguments"; shift 2 ;;
*) echo "args set to \`$2'" ;ARGUMENTS=$2;shift 2 ;;
#vars
DFS=$(file -b $PND | awk '{ print $1 }') # is -p a zip iso or folder?
MOUNTPOINT=$(df $PND | grep -vE '^Filesystem' | awk '{ print $6 }') #find out which mountpoint the pnd/folder is on
-BASENAME=$(basename "$PND" | cut -d'.' -f1) #get basename (strip extension if file) for union mountpoints etc, maybe this should be changed to something specified inside the xml
+
+#if -b is set use that as basename, else generate it from PND
+#get basename (strip extension if file) for union mountpoints etc, maybe this should be changed to something specified inside the xml
+if [ ! $BASENAME ]; then BASENAME=$(basename "$PND" | cut -d'.' -f1) ; fi
+
oCWD=$(pwd)
# add sanity check
fi
#create mountpoints
-#echo "
+echo "
#will run:
# create mountpoints
-mkdir -p /mnt/pnd/$BASENAME
-mkdir -p $MOUNTPOINT/appdata/$BASENAME
-mkdir -p /mnt/utmp/$BASENAME
+"
+if [ ! -d /mnt/pnd/$BASENAME ]; then
+echo "mkdir -p /mnt/pnd/$BASENAME "
+fi
+if [ ! -d $MOUNTPOINT/appdata/$BASENAME ]; then
+echo "mkdir -p $MOUNTPOINT/appdata/$BASENAME "
+fi
+if [ ! -d /mnt/utmp/$BASENAME ]; then
+echo "mkdir -p /mnt/utmp/$BASENAME "
+fi
#mount
-$mntline #mount the pnd/folder
-mount -t unionfs -o exec,dirs\=$MOUNTPOINT/appdata/$BASENAME=rw:/mnt/pnd/$BASENAME=ro unionfs /mnt/utmp/$BASENAME #union mount
-
-#start app
-cd /mnt/utmp/$BASENAME
-$EXENAME $ARGUMENTS
-cd $oCWD
-#app exited
+if [ ! $UNION ] ; then
+ mount | grep "on /mnt/utmp/$BASENAME type" > /dev/null
+ if [ ! $? -eq 0 ]; then
+ echo "
+ $mntline #mount the pnd/folder
+ #mount -t unionfs -o exec,dirs\=$MOUNTPOINT/appdata/$BASENAME=rw:/mnt/pnd/$BASENAME=ro unionfs /mnt/utmp/$BASENAME #union mount
+ #aufs, one of those should work, bit unsure.
+ mount -t aufs -o exec,dirs\=$MOUNTPOINT/appdata/$BASENAME=rw:/mnt/pnd/$BASENAME=ro none /mnt/utmp/$BASENAME #aufs?
+ #mount -t aufs -o exec,dirs\=$MOUNTPOINT/appdata/$BASENAME=rw:/mnt/pnd/$BASENAME=ro aufs /mnt/utmp/$BASENAME #aufs?
+ "
+ else
+ echo "doh!"
+ fi
+ echo "
+ #start app
+ cd /mnt/utmp/$BASENAME
+ $EXENAME $ARGUMENTS
+ cd $oCWD
+ #app exited
+ "
+else
+echo "
+ $mntline
+ cd /mnt/pnd/$BASENAME
+ $EXENAME $ARGUMENTS
+ cd $oCWD
+"
+fi
+echo "
#clean up
umount /mnt/utmp/$BASENAME
umount /mnt/pnd/$BASENAME
rmdir /mnt/pnd/$BASENAME
rmdir /mnt/utmp/$BASENAME
-#
\ No newline at end of file
+"