From 0b54a848982a5985c285e42ac5057745503d1a49 Mon Sep 17 00:00:00 2001 From: skeezix Date: Sun, 28 Feb 2010 22:52:09 -0500 Subject: [PATCH] Large change, to support multiple applications within a single PXML.xml file. genpxml script was updated to generate properly formed new XML test apps were updated to comply pnd_run will attempt to run all subapps right now, for lack of a better idea :) pndnotifyd will generate all the icons and .desktop files for all subapps, and it should all work --- apps/pnd_info.c | 35 +- apps/pnd_run.c | 51 ++- apps/pndnotifyd.c | 2 +- apps/pndvalidator.c | 35 +- include/pnd_discovery.h | 1 + include/pnd_pxml.h | 7 +- include/pnd_pxml_names.h | 3 + include/pnd_tinyxml.h | 3 +- include/pnd_utility.h | 7 +- lib/pnd_desktop.c | 9 +- lib/pnd_discovery.c | 30 +- lib/pnd_pxml.c | 42 +- lib/pnd_tinyxml.cpp | 540 +++++++++++++------------ lib/pnd_utility.c | 10 +- test/rawpxmltest.c | 84 ++-- testdata/apps/sampleappX/PXML.xml | 25 ++ testdata/apps/sampleappX/PXML.xml.bak2 | 145 +++++++ testdata/apps/sampleappX/program.exe | 0 testdata/apps/sampleappX/zeldaicon.png | Bin 0 -> 14866 bytes testdata/scripts/genpxml.sh | 58 +-- 20 files changed, 696 insertions(+), 391 deletions(-) create mode 100644 testdata/apps/sampleappX/PXML.xml create mode 100644 testdata/apps/sampleappX/PXML.xml.bak2 create mode 100644 testdata/apps/sampleappX/program.exe create mode 100644 testdata/apps/sampleappX/zeldaicon.png diff --git a/apps/pnd_info.c b/apps/pnd_info.c index a2acb4b..86908bf 100644 --- a/apps/pnd_info.c +++ b/apps/pnd_info.c @@ -78,36 +78,45 @@ int main ( int argc, char *argv[] ) { } pnd_pxml_handle h = NULL; + pnd_pxml_handle *apps = NULL; if ( pnd_pnd_seek_pxml ( f ) ) { if ( pnd_pnd_accrue_pxml ( f, pxmlbuf, pxmlbuflen ) ) { - h = pnd_pxml_fetch_buffer ( "pnd_run", pxmlbuf ); + apps = pnd_pxml_fetch_buffer ( "pnd_run", pxmlbuf ); } } fclose ( f ); - if ( ! h ) { + if ( ! apps ) { printf ( "ERROR: Couldn't pull PXML.xml from the pndfile.\n" ); exit ( 0 ); } - // display sections - for ( i = 0; i < sections; i++ ) { - char *t; + // iterate across apps + while ( *apps ) { + h = *apps; + + // display sections + for ( i = 0; i < sections; i++ ) { + char *t; + + if ( strcasecmp ( section [ i ], "description" ) == 0 ) { - if ( strcasecmp ( section [ i ], "description" ) == 0 ) { + printf ( "Section: %s\n", section [ i ] ); - printf ( "Section: %s\n", section [ i ] ); + if ( ( t = pnd_pxml_get_description_en ( h ) ) ) { + printf ( "%s\n", t ); + } else { + printf ( "Not supplied by PXML.xml in the pnd-file\n" ); + } - if ( ( t = pnd_pxml_get_description_en ( h ) ) ) { - printf ( "%s\n", t ); - } else { - printf ( "Not supplied by PXML.xml in the pnd-file\n" ); } - } + } // for - } // for + // next + apps++; + } // while return ( 0 ); } // main diff --git a/apps/pnd_run.c b/apps/pnd_run.c index c012ac6..5baabd4 100644 --- a/apps/pnd_run.c +++ b/apps/pnd_run.c @@ -139,40 +139,49 @@ int main ( int argc, char *argv[] ) { } pnd_pxml_handle h = NULL; + pnd_pxml_handle *apps = NULL; if ( pnd_pnd_seek_pxml ( f ) ) { if ( pnd_pnd_accrue_pxml ( f, pxmlbuf, pxmlbuflen ) ) { - h = pnd_pxml_fetch_buffer ( "pnd_run", pxmlbuf ); + apps = pnd_pxml_fetch_buffer ( "pnd_run", pxmlbuf ); } } fclose ( f ); - if ( ! h ) { + if ( ! apps ) { printf ( "ERROR: Couldn't pull PXML.xml from the pndfile.\n" ); exit ( 0 ); } - // attempt to invoke - unsigned int options = 0; - if ( no_x11 ) { - options |= PND_EXEC_OPTION_NOX11; - } + // attempt to invoke.. all of the subapps? just first one? - unsigned int clock = 200; - if ( pnd_pxml_get_clockspeed ( h ) ) { - clock = atoi ( pnd_pxml_get_clockspeed ( h ) ); - } + while ( *apps ) { + h = *apps; - if ( ! pnd_apps_exec ( pnd_run, pndfile, - pnd_pxml_get_unique_id ( h ), - pnd_pxml_get_exec ( h ), - pnd_pxml_get_startdir ( h ), - clock, - options ) - ) - { - printf ( "ERROR: PXML.xml data is bad\n" ); - } + unsigned int options = 0; + if ( no_x11 ) { + options |= PND_EXEC_OPTION_NOX11; + } + + unsigned int clock = 200; + if ( pnd_pxml_get_clockspeed ( h ) ) { + clock = atoi ( pnd_pxml_get_clockspeed ( h ) ); + } + + if ( ! pnd_apps_exec ( pnd_run, pndfile, + pnd_pxml_get_unique_id ( h ), + pnd_pxml_get_exec ( h ), + pnd_pxml_get_startdir ( h ), + clock, + options ) + ) + { + printf ( "ERROR: PXML.xml data is bad\n" ); + } + + // next + apps++; + } // while return ( 0 ); } // main diff --git a/apps/pndnotifyd.c b/apps/pndnotifyd.c index b9b350e..07769e5 100644 --- a/apps/pndnotifyd.c +++ b/apps/pndnotifyd.c @@ -661,7 +661,7 @@ void process_discoveries ( pnd_box_handle applist, char *emitdesktoppath, char * // check if icon already exists (from a previous extraction say); if so, we needn't // do it again char existingpath [ FILENAME_MAX ]; - sprintf ( existingpath, "%s/%s.png", emiticonpath, d -> unique_id ); + sprintf ( existingpath, "%s/%s#%u.png", emiticonpath, d -> unique_id, d -> subapp_number ); struct stat dirs; if ( stat ( existingpath, &dirs ) == 0 ) { diff --git a/apps/pndvalidator.c b/apps/pndvalidator.c index 4307b31..b21ab46 100644 --- a/apps/pndvalidator.c +++ b/apps/pndvalidator.c @@ -68,33 +68,44 @@ int main ( int argc, char *argv[] ) { // actually do useful work // - pnd_pxml_handle pxmlh; + pnd_pxml_handle *pxmlapps; - pxmlh = pnd_pxml_get_by_path ( fullpath ); + pxmlapps = pnd_pxml_get_by_path ( fullpath ); - if ( ! pxmlh ) { + if ( ! pxmlapps ) { printf ( "ERROR: PXML could not be extracted meaningfully.\n" ); return ( 0 ); } - printf ( "Got back a meaningful PXML structure.\n" ); + printf ( "Got back a meaningful list of PXMLs.\n" ); - /* check the content - */ + pnd_pxml_handle h = *pxmlapps; + + while ( h ) { + + /* check the content + */ - // check for required fields + // check for required fields - // exec-path? + // exec-path? - // app name? + // app name? - // unique ID + // unique ID - // package-name (shortname) + // package-name (shortname) + + // free up that particular pxml_handle within the return-list + + // next + pxmlapps++; + h = pxmlapps; + } // while /* done! */ - pnd_pxml_delete ( pxmlh ); + pnd_pxml_delete ( pxmlapps ); return ( 0 ); } diff --git a/include/pnd_discovery.h b/include/pnd_discovery.h index e4b11b4..b8aaa2b 100644 --- a/include/pnd_discovery.h +++ b/include/pnd_discovery.h @@ -49,6 +49,7 @@ typedef struct { char *object_path; // directory containing pnd or PXML.xml (does not include filename) char *object_filename; // filename within object_path of the app: the PXML.xml or awesomeapp.pnd file itself unsigned int pnd_icon_pos; // offset to the byte after end of PXML in a pnd file (should be icon if present) + unsigned char subapp_number; // # of app within PXML (ie: 0, 1, 2, 3, up to the number of apps within the PXML) // strdup'd from PXML -- hey, who was the idiot who thought it was a reat idea not to just re-use the pxml-struct? char *title_en; char *desc_en; diff --git a/include/pnd_pxml.h b/include/pnd_pxml.h index 01e32d5..2ef0e80 100644 --- a/include/pnd_pxml.h +++ b/include/pnd_pxml.h @@ -12,14 +12,16 @@ extern "C" { #define PXML_TAGHEAD "" /* case insensitive */ +#define PXML_MAXAPPS 20 /* max number of 's within a single PXML */ + // use this handle to interact with PXML; this hides the mechanics of parsing a PXML file so that // it can be upgraded with impacting applications typedef void* pnd_pxml_handle; /* pxml_fetch() will return NULL on fail, otherwise a valid handle which may be further queried */ -pnd_pxml_handle pnd_pxml_fetch ( char *fullpath ); -pnd_pxml_handle pnd_pxml_fetch_buffer ( char *filename, char *buffer ); +pnd_pxml_handle *pnd_pxml_fetch ( char *fullpath ); +pnd_pxml_handle *pnd_pxml_fetch_buffer ( char *filename, char *buffer ); void pnd_pxml_delete ( pnd_pxml_handle h ); /* overrides() allow for customization of a PXML that persists; ie: An application might be sitting @@ -101,6 +103,7 @@ typedef struct typedef struct { + unsigned char subapp_number; // 0 for 'only app'; 1+ for # .. first is 1. pnd_localized_string_t *titles; int titles_c; int titles_alloc_c; diff --git a/include/pnd_pxml_names.h b/include/pnd_pxml_names.h index 39f72d2..c476c21 100644 --- a/include/pnd_pxml_names.h +++ b/include/pnd_pxml_names.h @@ -8,6 +8,9 @@ extern "C" { /* ...*/ #define PND_PXML_ATTRNAME_UID "id" +/* */ +#define PND_PXML_APP "application" + /* */ #define PND_PXML_ENAME_TITLE "title" #define PND_PXML_ATTRNAME_TITLELANG "lang" diff --git a/include/pnd_tinyxml.h b/include/pnd_tinyxml.h index efa4371..81965d3 100644 --- a/include/pnd_tinyxml.h +++ b/include/pnd_tinyxml.h @@ -6,8 +6,7 @@ extern "C" { #endif -unsigned char pnd_pxml_load ( const char* pFilename, pnd_pxml_t *app ); -unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t *app ); +unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t **apps ); #ifdef __cplusplus } diff --git a/include/pnd_utility.h b/include/pnd_utility.h index f9dce27..3be73d2 100644 --- a/include/pnd_utility.h +++ b/include/pnd_utility.h @@ -19,11 +19,8 @@ char *pnd_expand_tilde ( char *freeable_buffer ); // arbtrary execute function; fire and forget really void pnd_exec_no_wait_1 ( char *fullpath, char *arg1 ); -// pnd_pxml_get_always() will work against a PXML.xml file or a foo.pnd app-bundle and return -// the resulting PXML structure, or fail; ie: It should be handy to avoid the user having to -// do the 'what type is this, and if-this-or-that' themselves. -// NOTE: Does _NOT_ automatically pick up PXML-overrides; you can call that function if you want -pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath ); +// NOTE: Does _NOT_ automatically pick up PXML-overrides; you can call that function if you want +pnd_pxml_handle *pnd_pxml_get_by_path ( char *fullpath ); // determine_mountpoint() will examine a path, and return the mountpoint that this path // is sitting on; returns 1 on success, meaning the target was populated. diff --git a/lib/pnd_desktop.c b/lib/pnd_desktop.c index 199825f..51992c4 100644 --- a/lib/pnd_desktop.c +++ b/lib/pnd_desktop.c @@ -11,6 +11,7 @@ #include "pnd_pndfiles.h" #include "pnd_conf.h" #include "pnd_desktop.h" +#include "pnd_logger.h" unsigned char pnd_emit_dotdesktop ( char *targetpath, char *pndrun, pnd_disco_t *p ) { char filename [ FILENAME_MAX ]; @@ -23,24 +24,28 @@ unsigned char pnd_emit_dotdesktop ( char *targetpath, char *pndrun, pnd_disco_t // validation if ( ! p -> unique_id ) { + pnd_log ( PND_LOG_DEFAULT, "Can't emit dotdesktop for %s, missing unique-id\n", targetpath ); return ( 0 ); } if ( ! p -> exec ) { + pnd_log ( PND_LOG_DEFAULT, "Can't emit dotdesktop for %s, missing exec\n", targetpath ); return ( 0 ); } if ( ! targetpath ) { + pnd_log ( PND_LOG_DEFAULT, "Can't emit dotdesktop for %s, missing target path\n", targetpath ); return ( 0 ); } if ( ! pndrun ) { + pnd_log ( PND_LOG_DEFAULT, "Can't emit dotdesktop for %s, missing pnd_run.sh\n", targetpath ); return ( 0 ); } // set up - sprintf ( filename, "%s/%s.desktop", targetpath, p -> unique_id ); + sprintf ( filename, "%s/%s#%u.desktop", targetpath, p -> unique_id, p -> subapp_number ); // emit @@ -195,7 +200,7 @@ unsigned char pnd_emit_icon ( char *targetpath, pnd_disco_t *p ) { } // determine filename for target - sprintf ( buffer, "%s/%s.png", targetpath, p -> unique_id ); // target + sprintf ( buffer, "%s/%s#%u.png", targetpath, p -> unique_id, p -> subapp_number ); // target /* first.. open the source file, by type of application: * are we looking through a pnd file or a dir? diff --git a/lib/pnd_discovery.c b/lib/pnd_discovery.c index 73ed18e..88a1126 100644 --- a/lib/pnd_discovery.c +++ b/lib/pnd_discovery.c @@ -47,6 +47,8 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb, { unsigned char valid = pnd_object_type_unknown; pnd_pxml_handle pxmlh = 0; + pnd_pxml_handle *pxmlapps = NULL; + pnd_pxml_handle *pxmlappiter; unsigned int pxml_close_pos = 0; unsigned char logit = pnd_log_do_buried_logging(); @@ -84,7 +86,7 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb, //printf ( "PXML: disco callback encountered '%s'\n", fpath ); // pick up the PXML if we can - pxmlh = pnd_pxml_fetch ( (char*) fpath ); + pxmlapps = pnd_pxml_fetch ( (char*) fpath ); } else if ( valid == pnd_object_type_pnd ) { // PND ... ?? @@ -147,7 +149,7 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb, #endif // by now, we have <PXML> .. </PXML>, try to parse.. - pxmlh = pnd_pxml_fetch_buffer ( (char*) fpath, pxmlbuf ); + pxmlapps = pnd_pxml_fetch_buffer ( (char*) fpath, pxmlbuf ); // done with file fclose ( f ); @@ -155,7 +157,19 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb, } // pxmlh is useful? - if ( pxmlh ) { + if ( ! pxmlapps ) { + return ( 0 ); // continue tree walk + } + + // iterate across apps in the PXML + pxmlappiter = pxmlapps; + while ( 1 ) { + pxmlh = *pxmlappiter; + pxmlappiter++; + + if ( ! pxmlh ) { + break; // all done + } // look for any overrides, if requested pnd_pxml_merge_override ( pxmlh, disco_overrides ); @@ -166,6 +180,8 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb, char *fixpxml; char *z; + pnd_log ( PND_LOG_DEFAULT, "Setting up discovered app %u\n", ((pnd_pxml_t*) pxmlh) -> subapp_number ); + p = pnd_box_allocinsert ( disco_box, (char*) fpath, sizeof(pnd_disco_t) ); // base paths @@ -181,6 +197,9 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb, p -> object_filename = strdup ( fixpxml + 1 ); } + // subapp-number + p -> subapp_number = ((pnd_pxml_t*) pxmlh) -> subapp_number; + // png icon path p -> pnd_icon_pos = pxml_close_pos; @@ -250,7 +269,10 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb, // ditch pxml pnd_pxml_delete ( pxmlh ); - } // got a pxmlh + } // while pxmlh is good + + // free up the applist + free ( pxmlapps ); return ( 0 ); // continue the tree walk } diff --git a/lib/pnd_pxml.c b/lib/pnd_pxml.c index 6f981a2..09a7fb6 100644 --- a/lib/pnd_pxml.c +++ b/lib/pnd_pxml.c @@ -11,30 +11,47 @@ #include "pnd_pathiter.h" #include "pnd_tinyxml.h" -pnd_pxml_handle pnd_pxml_fetch ( char *fullpath ) { +pnd_pxml_handle *pnd_pxml_fetch ( char *fullpath ) { + FILE *f; + char *b; + unsigned int len; - pnd_pxml_t *p = malloc ( sizeof(pnd_pxml_t) ); + f = fopen ( fullpath, "r" ); - memset ( p, '\0', sizeof(pnd_pxml_t) ); + if ( ! f ) { + return ( 0 ); + } + + fseek ( f, 0, SEEK_END ); + + len = ftell ( f ); + + fseek ( f, 0, SEEK_SET ); + + b = (char*) malloc ( len ); - if ( ! pnd_pxml_load ( fullpath, p ) ) { + if ( ! b ) { + fclose ( f ); return ( 0 ); } - return ( p ); -} + fread ( b, 1, len, f ); + + fclose ( f ); -pnd_pxml_handle pnd_pxml_fetch_buffer ( char *filename, char *buffer ) { + return ( pnd_pxml_fetch_buffer ( fullpath, b ) ); +} - pnd_pxml_t *p = malloc ( sizeof(pnd_pxml_t) ); +pnd_pxml_handle *pnd_pxml_fetch_buffer ( char *filename, char *buffer ) { - memset ( p, '\0', sizeof(pnd_pxml_t) ); + pnd_pxml_t **p = malloc ( sizeof(pnd_pxml_t*) * PXML_MAXAPPS ); + memset ( p, '\0', sizeof(pnd_pxml_t*) * PXML_MAXAPPS ); if ( ! pnd_pxml_parse ( filename, buffer, strlen ( buffer ), p ) ) { return ( 0 ); } - return ( p ); + return ( (pnd_pxml_handle*) p ); } void pnd_pxml_delete ( pnd_pxml_handle h ) { @@ -226,6 +243,8 @@ signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) { // the pxml includes a unique-id; use this value to attempt to find an // override in the given searchpath signed char retval = 0; + +#if 0 // TODO: Unfinished entirely now pnd_pxml_handle mergeh; if ( ! pnd_pxml_get_unique_id ( h ) ) { @@ -241,10 +260,12 @@ signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) { strncat ( buffer, ".xml", FILENAME_MAX ); //printf ( " Path to seek merges: '%s'\n", buffer ); + // TODO: handle multiple subapps! mergeh = pnd_pxml_fetch ( buffer ); if ( mergeh ) { + // TODO: handle all the various data bits if ( pnd_pxml_get_app_name_en ( mergeh ) ) { pnd_pxml_set_app_name ( h, pnd_pxml_get_app_name_en ( mergeh ) ); } @@ -254,6 +275,7 @@ signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) { } SEARCHPATH_POST +#endif return ( retval ); } diff --git a/lib/pnd_tinyxml.cpp b/lib/pnd_tinyxml.cpp index b11d450..59f7e4d 100644 --- a/lib/pnd_tinyxml.cpp +++ b/lib/pnd_tinyxml.cpp @@ -1,44 +1,15 @@ +#include <stdio.h> #include "tinyxml/tinyxml.h" #include "../include/pnd_pxml.h" #include "pnd_tinyxml.h" +#include "pnd_logger.h" //Easily change the tag names if required (globally in this file): #include "pnd_pxml_names.h" extern "C" { -unsigned char pnd_pxml_load ( const char* pFilename, pnd_pxml_t *app ) { - FILE *f; - char *b; - unsigned int len; - - f = fopen ( pFilename, "r" ); - - if ( ! f ) { - return ( 0 ); - } - - fseek ( f, 0, SEEK_END ); - - len = ftell ( f ); - - fseek ( f, 0, SEEK_SET ); - - b = (char*) malloc ( len ); - - if ( ! b ) { - fclose ( f ); - return ( 0 ); - } - - fread ( b, 1, len, f ); - - fclose ( f ); - - return ( pnd_pxml_parse ( pFilename, b, len, app ) ); -} - char *pnd_pxml_get_attribute(TiXmlElement *elem, const char *name) { const char *value = elem->Attribute(name); @@ -48,43 +19,45 @@ char *pnd_pxml_get_attribute(TiXmlElement *elem, const char *name) return NULL; } -unsigned char pnd_pxml_parse_titles(const TiXmlHandle hRoot, pnd_pxml_t *app) -{ - TiXmlElement *pElem; - app->titles_alloc_c = 4; //TODO: adjust this based on how many titles a PXML usually has. Power of 2. +unsigned char pnd_pxml_parse_titles(const TiXmlHandle hRoot, pnd_pxml_t *app) { + TiXmlElement *pElem; + app->titles_alloc_c = 4; //TODO: adjust this based on how many titles a PXML usually has. Power of 2. - app->titles = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->titles_alloc_c); - if (!app->titles) return (0); //errno = NOMEM + app->titles = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->titles_alloc_c); + if (!app->titles) return (0); //errno = NOMEM - //Go through all title tags and load them. - for (pElem = hRoot.FirstChild(PND_PXML_ENAME_TITLE).Element(); pElem; - pElem = pElem->NextSiblingElement(PND_PXML_ENAME_TITLE)) - { + //Go through all title tags and load them. + for (pElem = hRoot.FirstChild(PND_PXML_ENAME_TITLE).Element(); pElem; + pElem = pElem->NextSiblingElement(PND_PXML_ENAME_TITLE)) + { - if ( ! pElem->GetText() ) { - continue; - } + if ( ! pElem->GetText() ) { + continue; + } - char *text = strdup(pElem->GetText()); - if (!text) continue; + char *text = strdup(pElem->GetText()); + if (!text) continue; - char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_TITLELANG); - if (!lang) continue; + char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_TITLELANG); + if (!lang) continue; - app->titles_c++; - if (app->titles_c > app->titles_alloc_c) //we don't have enough strings allocated - { - app->titles_alloc_c <<= 1; - app->titles = (pnd_localized_string_t *)realloc((void*)app->titles, app->titles_alloc_c); - if (!app->titles) return (0); //errno = ENOMEM - } + app->titles_c++; + if (app->titles_c > app->titles_alloc_c) //we don't have enough strings allocated + { + app->titles_alloc_c <<= 1; + app->titles = (pnd_localized_string_t *)realloc((void*)app->titles, app->titles_alloc_c); + if (!app->titles) return (0); //errno = ENOMEM + } - pnd_localized_string_t *title = &app->titles[app->titles_c - 1]; - title->language = lang; - title->string = text; - } + pnd_localized_string_t *title = &app->titles[app->titles_c - 1]; + title->language = lang; + title->string = text; - return (1); + pnd_log ( PND_LOG_DEFAULT, (char*)" Title/Lang: %s/%s\n", text, lang ); + + } + + return ( 1 ); } unsigned char pnd_pxml_parse_descriptions(const TiXmlHandle hRoot, pnd_pxml_t *app) @@ -128,231 +101,298 @@ unsigned char pnd_pxml_parse_descriptions(const TiXmlHandle hRoot, pnd_pxml_t *a return (1); } -unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t *app ) { - //Load the XML document - TiXmlDocument doc; - doc.Parse(buffer); +unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t **apps ) { - TiXmlElement *pElem = NULL; + //Load the XML document + TiXmlDocument doc; + doc.Parse(buffer); - //Find the root element - TiXmlHandle hDoc(&doc); - TiXmlHandle hRoot(0); + unsigned char appwrappermode = 0; // >=1 -> using <application>...</application> wrapper + unsigned char appcount = 0; + pnd_pxml_t *app = NULL; - pElem = hDoc.FirstChild("PXML").Element(); - if (!pElem) return (0); - hRoot = TiXmlHandle(pElem); + TiXmlElement *pElem = NULL; + TiXmlElement *appElem = NULL; - //Get unique ID first. - app->unique_id = pnd_pxml_get_attribute(hRoot.Element(), PND_PXML_ATTRNAME_UID); + //Find the root element + TiXmlHandle hDoc(&doc); + TiXmlHandle hRoot(0); - //Everything related to the title: - pnd_pxml_parse_titles(hRoot, app); + pElem = hDoc.FirstChild("PXML").Element(); + if (!pElem) return (0); - //Everything description-related: - pnd_pxml_parse_descriptions(hRoot, app); + // new Strategy; really, we want multiple app support within a PXML, without the lameness of + // multiple <PXML>..</PXML> within a single PXML.xml file. As such, we should have an app within + // an <application>..</application> wrapper level, with the ID on that. Further, the icon and + // .desktop filenames can have a # appended which is the application-count-# within the PXML, + // so that they can have their own .desktop and icon without collisions, but still use the + // same unique-id if they want to. + // To avoid breaking existing PXML's (even though we're pre-launch), can detect if ID + // is present in PXML line or not; if not, assume application mode? + hRoot = TiXmlHandle(pElem); - //Everything launcher-related in one tag: - if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_EXEC).Element()) ) - { - app->background = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECBG); //if this returns NULL, the struct is filled with NULL. No need to check. - app->standalone = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECSTAL); - app->exec = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECCMD); - app->startdir = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECWD); - app->exec_no_x11 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECNOX11); - } + if ( hRoot.FirstChild(PND_PXML_APP).Element() != NULL ) { + appwrappermode = 1; + appElem = hRoot.FirstChild(PND_PXML_APP).Element(); + hRoot = TiXmlHandle ( appElem ); + } - //The app icon: - if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_ICON).Element()) ) + // until we run out of applications in the PXML.. + while ( 1 ) { + + pnd_log ( PND_LOG_DEFAULT, (char*)" App #%u inside of PXML %s\n", appcount, pFilename ); + + // create the buffer to hold the pxml + apps [ appcount ] = (pnd_pxml_t*) malloc ( sizeof(pnd_pxml_t) ); + memset ( apps [ appcount ], '\0', sizeof(pnd_pxml_t) ); + + // due to old code, just make life easier a minute.. + app = apps [ appcount ]; + if ( appwrappermode ) { + app -> subapp_number = appcount; + } else { + app -> subapp_number = 0; + } + + //Get unique ID first. + if ( appwrappermode ) { + app->unique_id = pnd_pxml_get_attribute(appElem, PND_PXML_ATTRNAME_UID); + pnd_log ( PND_LOG_DEFAULT, (char*)" Subapp #%u has unique_id %s\n", appcount, app -> unique_id ); + } else { + app->unique_id = pnd_pxml_get_attribute(hRoot.Element(), PND_PXML_ATTRNAME_UID); + pnd_log ( PND_LOG_DEFAULT, (char*)" Only-app #%u has unique_id %s\n", appcount, app -> unique_id ); + } + + //Everything related to the title: + pnd_pxml_parse_titles(hRoot, app); + + //Everything description-related: + pnd_pxml_parse_descriptions(hRoot, app); + + //Everything launcher-related in one tag: + if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_EXEC).Element()) ) + { + app->background = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECBG); //if this returns NULL, the struct is filled with NULL. No need to check. + app->standalone = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECSTAL); + app->exec = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECCMD); + app->startdir = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECWD); + app->exec_no_x11 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECNOX11); + } + + //The app icon: + if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_ICON).Element()) ) { + app->icon = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ICONSRC); + } + + //The preview pics: + if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_PREVPICS).Element()) ) + { + //TODO: Change this if pnd_pxml_t gains the feature of more pics than 2. + if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_PREVPIC)) ) + { + app->previewpic1 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC); + + if ( (pElem = pElem->NextSiblingElement(PND_PXML_ENAME_PREVPIC)) ) { - app->icon = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ICONSRC); + app->previewpic2 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC); } - - //The preview pics: - if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_PREVPICS).Element()) ) + } + } //previewpic + + //The author info: + if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_AUTHOR).Element()) ) + { + app->author_name = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORNAME); + app->author_website = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORWWW); + //TODO: Uncomment this if the author gets email support. + //app->author_email = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHOREMAIL)); + } + + //The version info: + if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_VERSION).Element()) ) + { + app->version_major = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMAJOR); + app->version_minor = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMINOR); + app->version_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERREL); + app->version_build = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERBUILD); + } + + //The OS version info: + if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_OSVERSION).Element()) ) + { + app->osversion_major = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMAJOR); + app->osversion_minor = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMINOR); + app->osversion_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERREL); + app->osversion_build = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERBUILD); + } + + int i; //For now, we need to keep track of the index of categories. + //Categories: + if ( (pElem = hRoot.FirstChildElement(PND_PXML_NODENAME_CATS).Element()) ) //First, enter the "categories" node. + { + i = 0; + + //Goes through all the top-level categories and their sub-categories. i helps limit these to 2. + for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_CAT); pElem && i < 2; + pElem = pElem->NextSiblingElement(PND_PXML_ENAME_CAT), i++) + { + //TODO: Fix pnd_pxml_t so that there can be more than 2 category 'trees' and more than 2 subcategories. Then this can be removed. + switch (i) { - //TODO: Change this if pnd_pxml_t gains the feature of more pics than 2. - if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_PREVPIC)) ) - { - app->previewpic1 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC); - - if ( (pElem = pElem->NextSiblingElement(PND_PXML_ENAME_PREVPIC)) ) - { - app->previewpic2 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC); - } - } - } //previewpic + case 0: //first category counts as the main cat for now + app->main_category = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME); + break; - //The author info: - if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_AUTHOR).Element()) ) - { - app->author_name = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORNAME); - app->author_website = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORWWW); - //TODO: Uncomment this if the author gets email support. - //app->author_email = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHOREMAIL)); + case 1: //...second as the alternative + app->altcategory = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME); } - //The version info: - if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_VERSION).Element()) ) + TiXmlElement *pSubCatElem; //the sub-elements for a main category. + int j = 0; //the subcategory index within this category + + //Goes through all the subcategories within this category. j helps limit these to 2. + for (pSubCatElem = pElem->FirstChildElement(PND_PXML_ENAME_SUBCAT); pSubCatElem && j < 2; + pSubCatElem = pSubCatElem->NextSiblingElement(PND_PXML_ENAME_SUBCAT), j++) { - app->version_major = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMAJOR); - app->version_minor = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMINOR); - app->version_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERREL); - app->version_build = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERBUILD); + char *subcat = pnd_pxml_get_attribute(pSubCatElem, PND_PXML_ATTRNAME_SUBCATNAME); + if (!(subcat)) continue; + + //TODO: This is ugly. Fix pnd_pxml_t so that there can be more than 2 category 'trees' and more than 2 subcategories. Then this can be removed. + switch (j | (i << 1)) + { + case 0: + app->subcategory1 = subcat; + break; + case 1: + app->subcategory2 = subcat; + break; + case 2: + app->altsubcategory1 = subcat; + break; + case 3: + app->altsubcategory2 = subcat; + } } - - //The OS version info: - if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_OSVERSION).Element()) ) + } + } + + //All file associations: + //Step into the associations node + if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_ASSOCS).Element()) ) + { + i = 0; + //Go through all associations. i serves as index; since the format only supports 3 associations we need to keep track of the number. + for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_ASSOC); pElem && i < 3; + pElem = pElem->NextSiblingElement(PND_PXML_ENAME_ASSOC), i++) + { + char *name = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCNAME); + char *filetype = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCFTYPE); + char *paramter = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCARGS); + + if (!(name && filetype && paramter)) continue; + + switch(i) //TODO: same problem here: only 3 associations supported { - app->osversion_major = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMAJOR); - app->osversion_minor = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMINOR); - app->osversion_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERREL); - app->osversion_build = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERBUILD); + case 0: + { + app->associationitem1_name = name; + app->associationitem1_filetype = filetype; + app->associationitem1_parameter = paramter; + break; } - - int i; //For now, we need to keep track of the index of categories. - //Categories: - if ( (pElem = hRoot.FirstChildElement(PND_PXML_NODENAME_CATS).Element()) ) //First, enter the "categories" node. + case 1: { - i = 0; - - //Goes through all the top-level categories and their sub-categories. i helps limit these to 2. - for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_CAT); pElem && i < 2; - pElem = pElem->NextSiblingElement(PND_PXML_ENAME_CAT), i++) - { - //TODO: Fix pnd_pxml_t so that there can be more than 2 category 'trees' and more than 2 subcategories. Then this can be removed. - switch (i) - { - case 0: //first category counts as the main cat for now - app->main_category = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME); - break; - - case 1: //...second as the alternative - app->altcategory = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME); - } - - TiXmlElement *pSubCatElem; //the sub-elements for a main category. - int j = 0; //the subcategory index within this category - - //Goes through all the subcategories within this category. j helps limit these to 2. - for (pSubCatElem = pElem->FirstChildElement(PND_PXML_ENAME_SUBCAT); pSubCatElem && j < 2; - pSubCatElem = pSubCatElem->NextSiblingElement(PND_PXML_ENAME_SUBCAT), j++) - { - char *subcat = pnd_pxml_get_attribute(pSubCatElem, PND_PXML_ATTRNAME_SUBCATNAME); - if (!(subcat)) continue; - - //TODO: This is ugly. Fix pnd_pxml_t so that there can be more than 2 category 'trees' and more than 2 subcategories. Then this can be removed. - switch (j | (i << 1)) - { - case 0: - app->subcategory1 = subcat; - break; - case 1: - app->subcategory2 = subcat; - break; - case 2: - app->altsubcategory1 = subcat; - break; - case 3: - app->altsubcategory2 = subcat; - } - } - } + app->associationitem2_name = name; + app->associationitem2_filetype = filetype; + app->associationitem2_parameter = paramter; + break; } - - //All file associations: - //Step into the associations node - if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_ASSOCS).Element()) ) + case 2: { - i = 0; - //Go through all associations. i serves as index; since the format only supports 3 associations we need to keep track of the number. - for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_ASSOC); pElem && i < 3; - pElem = pElem->NextSiblingElement(PND_PXML_ENAME_ASSOC), i++) - { - char *name = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCNAME); - char *filetype = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCFTYPE); - char *paramter = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCARGS); - - if (!(name && filetype && paramter)) continue; - - switch(i) //TODO: same problem here: only 3 associations supported - { - case 0: - { - app->associationitem1_name = name; - app->associationitem1_filetype = filetype; - app->associationitem1_parameter = paramter; - break; - } - case 1: - { - app->associationitem2_name = name; - app->associationitem2_filetype = filetype; - app->associationitem2_parameter = paramter; - break; - } - case 2: - { - app->associationitem3_name = name; - app->associationitem3_filetype = filetype; - app->associationitem3_parameter = paramter; - } - } - } + app->associationitem3_name = name; + app->associationitem3_filetype = filetype; + app->associationitem3_parameter = paramter; } - - //Performance related things (aka: Clockspeed XD): - pElem = hRoot.FirstChild(PND_PXML_ENAME_CLOCK).Element(); - if (pElem) - { - app->clockspeed = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CLOCKFREQ); } - - // Package - pElem = hRoot.FirstChild ( PND_PXML_ENAME_PACKAGE ).Element(); - if ( pElem ) { - app -> package_name = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_NAME ); - app -> package_release_date = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_DATE ); + } + } + + //Performance related things (aka: Clockspeed XD): + pElem = hRoot.FirstChild(PND_PXML_ENAME_CLOCK).Element(); + if (pElem) + { + app->clockspeed = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CLOCKFREQ); + } + + // Package + pElem = hRoot.FirstChild ( PND_PXML_ENAME_PACKAGE ).Element(); + if ( pElem ) { + app -> package_name = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_NAME ); + app -> package_release_date = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_DATE ); + } + + // mkdir request + if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_MKDIR).Element()) ) { + + // seek <dir> + if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_MKDIR)) ) { + char *t; + + if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) { + // first <dir>, so just replace it wholesale; we use strdup so we can free() easily later, consistently. Mmm, leak seems imminent. + app -> mkdir_sp = strdup ( t ); } - // mkdir request - if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_MKDIR).Element()) ) { - - // seek <dir> - if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_MKDIR)) ) { - char *t; - - if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) { - // first <dir>, so just replace it wholesale; we use strdup so we can free() easily later, consistently. Mmm, leak seems imminent. - app -> mkdir_sp = strdup ( t ); - } - - while ( ( pElem = pElem -> NextSiblingElement ( PND_PXML_ENAME_MKDIR ) ) ) { + while ( ( pElem = pElem -> NextSiblingElement ( PND_PXML_ENAME_MKDIR ) ) ) { - if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) { - char *foo = (char*) malloc ( strlen ( app -> mkdir_sp ) + strlen ( t ) + 1 /*:*/ + 1 /*\0*/ ); + if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) { + char *foo = (char*) malloc ( strlen ( app -> mkdir_sp ) + strlen ( t ) + 1 /*:*/ + 1 /*\0*/ ); - if ( foo ) { - sprintf ( foo, "%s:%s", app -> mkdir_sp, t ); - free ( app -> mkdir_sp ); - app -> mkdir_sp = foo; - } // assuming we got ram, lets cat it all together + if ( foo ) { + sprintf ( foo, "%s:%s", app -> mkdir_sp, t ); + free ( app -> mkdir_sp ); + app -> mkdir_sp = foo; + } // assuming we got ram, lets cat it all together - } // got another elem? + } // got another elem? - } // while + } // while - } // found a <dir> + } // found a <dir> #if 0 - if ( app -> mkdir_sp ) { - printf ( "mkdir: %s\n", app -> mkdir_sp ); - } + if ( app -> mkdir_sp ) { + printf ( "mkdir: %s\n", app -> mkdir_sp ); + } #endif - } // mkdir + } // mkdir - return (1); + // if in <application> mode, do we find another app? + if ( appwrappermode ) { + appElem = appElem -> NextSiblingElement ( PND_PXML_APP ); + if ( ! appElem ) { + pnd_log ( PND_LOG_DEFAULT, (char*)" No more applications within PXML\n" ); + break; // no more applications + } + // got another application.. + //pnd_log ( PND_LOG_DEFAULT, " Found another applications within PXML\n" ); + appwrappermode++; + hRoot = TiXmlHandle ( appElem ); + + appcount++; + + if ( appcount == PXML_MAXAPPS ) { + return ( 1 ); // thats all we can handle; we're not going to auto-extend this + } + + } else { + break; // single-app old PXML + } + + } // while finding apps + + return (1); } } // extern C diff --git a/lib/pnd_utility.c b/lib/pnd_utility.c index 5009b51..6c521b9 100644 --- a/lib/pnd_utility.c +++ b/lib/pnd_utility.c @@ -173,9 +173,9 @@ void pnd_exec_no_wait_1 ( char *fullpath, char *arg1 ) { return; } -pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath ) { +pnd_pxml_handle *pnd_pxml_get_by_path ( char *fullpath ) { unsigned char valid = pnd_object_type_unknown; - pnd_pxml_handle pxmlh = 0; + pnd_pxml_handle *pxmlapps = 0; // WARN: this is way too close to callback in pnd_disco .. should be refactored! @@ -192,7 +192,7 @@ pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath ) { // potentially a valid application if ( valid == pnd_object_type_directory ) { - pxmlh = pnd_pxml_fetch ( (char*) fullpath ); + pxmlapps = pnd_pxml_fetch ( (char*) fullpath ); } else if ( valid == pnd_object_type_pnd ) { FILE *f; @@ -214,7 +214,7 @@ pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath ) { } // by now, we have <PXML> .. </PXML>, try to parse.. - pxmlh = pnd_pxml_fetch_buffer ( (char*) fullpath, pxmlbuf ); + pxmlapps = pnd_pxml_fetch_buffer ( (char*) fullpath, pxmlbuf ); // done with file fclose ( f ); @@ -223,7 +223,7 @@ pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath ) { // .. - return ( pxmlh ); + return ( pxmlapps ); } unsigned char pnd_determine_mountpoint ( char *fullpath, char *r_mountpoint, unsigned char mountpoint_len ) { diff --git a/test/rawpxmltest.c b/test/rawpxmltest.c index 26e3a96..06545ba 100644 --- a/test/rawpxmltest.c +++ b/test/rawpxmltest.c @@ -15,58 +15,66 @@ int main (int argc, char **argv) return 1; } - pnd_pxml_handle h = pnd_pxml_fetch(argv[1]); + pnd_pxml_handle *apps = pnd_pxml_fetch(argv[1]); + pnd_pxml_handle h; - if (!h) - { - printf("Could not load file \"%s\"\n", argv[1]); - return 1; - } + while ( *apps ) { + h = *apps; + + if (!h) + { + printf("Could not load file \"%s\"\n", argv[1]); + return 1; + } + + char *data; //for all values - char *data; //for all values + if ( (data = pnd_pxml_get_app_name_en(h)) ) printf("Appname(en): %s\n", data); + if ( (data = pnd_pxml_get_app_name_de(h)) ) printf("Appname(de): %s\n", data); + if ( (data = pnd_pxml_get_app_name_it(h)) ) printf("Appname(it): %s\n", data); + if ( (data = pnd_pxml_get_app_name_fr(h)) ) printf("Appname(fr): %s\n", data); - if ( (data = pnd_pxml_get_app_name_en(h)) ) printf("Appname(en): %s\n", data); - if ( (data = pnd_pxml_get_app_name_de(h)) ) printf("Appname(de): %s\n", data); - if ( (data = pnd_pxml_get_app_name_it(h)) ) printf("Appname(it): %s\n", data); - if ( (data = pnd_pxml_get_app_name_fr(h)) ) printf("Appname(fr): %s\n", data); + if ( (data = pnd_pxml_get_unique_id(h)) ) printf("UID: %s\n", data); - if ( (data = pnd_pxml_get_unique_id(h)) ) printf("UID: %s\n", data); + if ( (data = pnd_pxml_get_standalone(h)) ) printf("Standalone: %s\n", data); - if ( (data = pnd_pxml_get_standalone(h)) ) printf("Standalone: %s\n", data); + if ( (data = pnd_pxml_get_icon(h)) ) printf("Icon: %s\n", data); - if ( (data = pnd_pxml_get_icon(h)) ) printf("Icon: %s\n", data); + if ( (data = pnd_pxml_get_description_en(h)) ) printf("Description(en): %s\n", data); + if ( (data = pnd_pxml_get_description_de(h)) ) printf("Description(de): %s\n", data); + if ( (data = pnd_pxml_get_description_it(h)) ) printf("Description(it): %s\n", data); + if ( (data = pnd_pxml_get_description_fr(h)) ) printf("Description(fr): %s\n", data); - if ( (data = pnd_pxml_get_description_en(h)) ) printf("Description(en): %s\n", data); - if ( (data = pnd_pxml_get_description_de(h)) ) printf("Description(de): %s\n", data); - if ( (data = pnd_pxml_get_description_it(h)) ) printf("Description(it): %s\n", data); - if ( (data = pnd_pxml_get_description_fr(h)) ) printf("Description(fr): %s\n", data); + if ( (data = pnd_pxml_get_previewpic1(h)) ) printf("Pic1: %s\n", data); + if ( (data = pnd_pxml_get_previewpic2(h)) ) printf("Pic2: %s\n", data); - if ( (data = pnd_pxml_get_previewpic1(h)) ) printf("Pic1: %s\n", data); - if ( (data = pnd_pxml_get_previewpic2(h)) ) printf("Pic2: %s\n", data); + if ( (data = pnd_pxml_get_author_name(h)) ) printf("Author name: %s\n", data); + if ( (data = pnd_pxml_get_author_website(h)) ) printf("Author website: %s\n", data); - if ( (data = pnd_pxml_get_author_name(h)) ) printf("Author name: %s\n", data); - if ( (data = pnd_pxml_get_author_website(h)) ) printf("Author website: %s\n", data); + if ( (data = pnd_pxml_get_version_major(h)) ) printf("Version major: %s\n", data); + if ( (data = pnd_pxml_get_version_minor(h)) ) printf("Version minor: %s\n", data); + if ( (data = pnd_pxml_get_version_release(h)) ) printf("Version release: %s\n", data); + if ( (data = pnd_pxml_get_version_build(h)) ) printf("Version build: %s\n", data); - if ( (data = pnd_pxml_get_version_major(h)) ) printf("Version major: %s\n", data); - if ( (data = pnd_pxml_get_version_minor(h)) ) printf("Version minor: %s\n", data); - if ( (data = pnd_pxml_get_version_release(h)) ) printf("Version release: %s\n", data); - if ( (data = pnd_pxml_get_version_build(h)) ) printf("Version build: %s\n", data); + if ( (data = pnd_pxml_get_osversion_major(h)) ) printf("OSVersion major: %s\n", data); + if ( (data = pnd_pxml_get_osversion_minor(h)) ) printf("OSVersion minor: %s\n", data); + if ( (data = pnd_pxml_get_osversion_release(h)) ) printf("OSVersion release: %s\n", data); + if ( (data = pnd_pxml_get_osversion_build(h)) ) printf("OSVersion build: %s\n", data); - if ( (data = pnd_pxml_get_osversion_major(h)) ) printf("OSVersion major: %s\n", data); - if ( (data = pnd_pxml_get_osversion_minor(h)) ) printf("OSVersion minor: %s\n", data); - if ( (data = pnd_pxml_get_osversion_release(h)) ) printf("OSVersion release: %s\n", data); - if ( (data = pnd_pxml_get_osversion_build(h)) ) printf("OSVersion build: %s\n", data); + if ( (data = pnd_pxml_get_exec(h)) ) printf("Application exec: %s\n", data); - if ( (data = pnd_pxml_get_exec(h)) ) printf("Application exec: %s\n", data); + if ( (data = pnd_pxml_get_main_category(h)) ) printf("Category 1: %s\n", data); + if ( (data = pnd_pxml_get_subcategory1(h)) ) printf("Category 1 sub 1: %s\n", data); + if ( (data = pnd_pxml_get_subcategory2(h)) ) printf("Category 1 sub 2: %s\n", data); + if ( (data = pnd_pxml_get_altcategory(h)) ) printf("Category 2: %s\n", data); + if ( (data = pnd_pxml_get_altsubcategory1(h)) ) printf("Category 2 sub 1: %s\n", data); + if ( (data = pnd_pxml_get_altsubcategory2(h)) ) printf("Category 2 sub 2: %s\n", data); - if ( (data = pnd_pxml_get_main_category(h)) ) printf("Category 1: %s\n", data); - if ( (data = pnd_pxml_get_subcategory1(h)) ) printf("Category 1 sub 1: %s\n", data); - if ( (data = pnd_pxml_get_subcategory2(h)) ) printf("Category 1 sub 2: %s\n", data); - if ( (data = pnd_pxml_get_altcategory(h)) ) printf("Category 2: %s\n", data); - if ( (data = pnd_pxml_get_altsubcategory1(h)) ) printf("Category 2 sub 1: %s\n", data); - if ( (data = pnd_pxml_get_altsubcategory2(h)) ) printf("Category 2 sub 2: %s\n", data); + pnd_pxml_delete(h); - pnd_pxml_delete(h); + // next + apps++; + } // while return 0; } diff --git a/testdata/apps/sampleappX/PXML.xml b/testdata/apps/sampleappX/PXML.xml new file mode 100644 index 0000000..29e18fd --- /dev/null +++ b/testdata/apps/sampleappX/PXML.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<PXML xmlns="http://openpandora.org/namespaces/PXML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PXML_schema.xsd"> + + <application id="jeff.sample.X"> + <title lang="en_US">Sample App X - Fullscreen + + This is the English Description of the file. + + + + + Sample App X - Windowed + + This is the English Description of the file. + + + + + Sample App X - Other ID + + This is the English Description of the file. + + + + diff --git a/testdata/apps/sampleappX/PXML.xml.bak2 b/testdata/apps/sampleappX/PXML.xml.bak2 new file mode 100644 index 0000000..fa62c13 --- /dev/null +++ b/testdata/apps/sampleappX/PXML.xml.bak2 @@ -0,0 +1,145 @@ + + + + + Sample App X1 + Sample App X1 - German + + + + This is the English Description of the file. + This would be the German description. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ......kfujl........ + ......qwe......fwer..... + + + + + + Sample App X2 + Sample App X2 - German + + + + This is the English Description of the file. + This would be the German description. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ......kfujl........ + ......qwe......fwer..... + + + + + + Sample App X3 + Sample App X3 - German + + + + This is the English Description of the file. + This would be the German description. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ......kfujl........ + ......qwe......fwer..... + + + + + diff --git a/testdata/apps/sampleappX/program.exe b/testdata/apps/sampleappX/program.exe new file mode 100644 index 0000000..e69de29 diff --git a/testdata/apps/sampleappX/zeldaicon.png b/testdata/apps/sampleappX/zeldaicon.png new file mode 100644 index 0000000000000000000000000000000000000000..140a39386bfe401a5c2d8406bfd0caf568318f08 GIT binary patch literal 14866 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 #<|oyxycV^Z26=k++2w7qH+;7A97fyhppC3v)rE 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

v;u8cxhX+l~3hEj$>wWI`e}tM2dAlDCK>6pd z32Gw4Xm)fGqhSCDf-%G-fSm#hVJA(~mLQ^l4?<|16c7qpAw42M5KU=BJ0VIdHbN&V zT!)qkahw2n4H$t;kR@n=(2N{$B7>@eN&yTGjImbPEUlV07M!ou^^Xl5g(}; z7oiywt{D{u_BBF-;5CF1KR*p0A4(%�`vKtA}`Dug(XoLrPuM38z|z|mj~fUi0fN`(@V3J4>vBt=l9VEm3cK;5Lbhiz@p zZF*dBK!(|hjQ1T-v$O)7L&F&+F3tzdO%7X{AGIK)Y>C6>W=E|ESx^(?bJ)fbIATXQ z!ejPXm>;mUM)`+w=#Z1Wy1NU)GZ{LBJzsBxK&@bZt&jlCut3d-AV4EBSThPSC`>yp zTqhpBM!DNqX4Kzy|ta zgpY>$W2hk_6+tjtBRXs|Hbg<|0(3xeA^x;FAVb_u&D#Sw;^~e`iag878PQGM(TNU! z1U5Ds(x%3LJG->)ZFlPH68YHKq1g^CEp|!a-#_^Xvt5R@R^W23#s zhLG3+BO`p>XJqJ=5C_U|ANUvi`5=7C-WC&6bRF!#4B()LD<+%(vCYQ=rXmsn#OzG~ zeH-xcKr=K}^Kd)t?t0kO<&cXr3Icd5frA|$0XpzFnvMgOW&lKuVFnO4w;O5tJWRl+ zj*ZPubq#iY!42x4ZNW>&8Qe^UfrI^SLp{>M*cjGsiNnUmJ2W&Lf`arM92ooeYuH%p zIy!(OFm=ep#LUA3cNdP0>N`7uAe^UrNk==^@L4Wtv^!M-(-20%*#M9@HgR09mVwi|DBRl~|^ucl^TR3w(ru(5Yzc{#tLoPmG# zR^Q%kr@jtC21XuMZHWU01|}{p?|kyf*x9oTH8m|88^)nSXb(Adg~ju(e1&~8He0v<%0O^v7l4I~<1pP~K%1A^`B z+Gk*7>F)964f4-reRb_i7B7pjXQ!T%17q(_hOVs*LstvD;Nrdd`di|Vf#Cs^fP3~b zjvUpnu-LD!ze`K&kdYBXTSLvtoS}L2u%#J3)hx_*>FEF}(QOQ!Dr}jWAqws{CqQ=G zZ)t%d==;EV6-YC4b6kbm`hbb)L1O}yU(j@@Ms$yX9*v>91AHTo-``=hh zzkdB%3f_6y#n7?0W*F$~)lg&T*`U1B!r;SM_UY+u3H)kHfS@gL$M~S%8=w{bz39GO zbfjB;-wU?0bGv>X&@()2WQwa8+FIc8kf|}_&_QiW%isOs_vE$kh54BDG{grr6O%pK zdYa}|JNNHp=weQ-t+`7_2Nv$p(b*DkoVx;8R$;RZdkpjec=a9FF0O5EMqj&uP50mY ztnJ42u%Qv-=utW{?$puRtE+QRSNG}PzKj>qzr68HS{9daaQ}W?-J@n^`*aOe|sSVfG)!nJ7iHM8 z|95<;y1PqP`wr~Z(;@gSkE*X2*v;6ZgB}uWXa5iMA2zEQ86DC?_B=Q+I!^ulva-Il zb;rR2hf#m&=Jo4D%2aX;+04W?*M=hppZN*SO$~dBS$iM&&MR?K2 zd`Uwc{oAjlvmG!08@@JQ3zIh6NgqR}+dp?}UhcM^gp_^zjBIQ_`1oUZ&>!D<$16C1 zv2PdQMMDEB198Yu$moncd-iE*ZSaD#2uKICb+^;ue|CPaw)P#MToosEzK1(o(idW= z00{XGeE-h$8Mwff0FRiy{QOr>;8j@6fD$uUsNDAJX(B7_R#!h_Yz(EqkHE_zL%oB# z+Ju)wM~^Ue?I1IP-8;y^|1EZ6(tuEh6u{WMd;gImjGa3fyLO?V+Hr6nJ{f!WV8j@E z_mcB__W##9vy;(1*pF8m@p^ - - '$BASENAMEnoex' - '$BASENAMEnoex' - German (lol!) + + + + + '$BASENAMEnoex' + '$BASENAMEnoex' - German (lol!) - + - en_US Automatically generated pxml from'$(pwd)' exe='$BASENAME' - de_DE Automatisch generiertes pxml aus'$(pwd)' exe='$BASENAME' + en_US Automatically generated pxml from'$(pwd)' exe='$BASENAME' + de_DE Automatisch generiertes pxml aus'$(pwd)' exe='$BASENAME' - ' + ' #add all images in the folder as preview pics for image in $(file -i -0 * | grep -a image | cut -d" " -f1) do -echo "" +echo " " done -echo ' - - - - - - - - - - - - - - - - - +echo ' + + + + + + + + + + + + + + + + + + + + ' \ No newline at end of file -- 2.39.5