3 #include "tinyxml/tinyxml.h"
4 #include "../include/pnd_pxml.h"
5 #include "pnd_tinyxml.h"
6 #include "pnd_logger.h"
8 //Easily change the tag names if required (globally in this file):
9 #include "pnd_pxml_names.h"
13 char *pnd_pxml_get_attribute(TiXmlElement *elem, const char *name)
15 const char *value = elem->Attribute(name);
22 unsigned char pnd_pxml_parse_titles(const TiXmlHandle hRoot, pnd_pxml_t *app) {
24 app->titles_alloc_c = 4; //TODO: adjust this based on how many titles a PXML usually has. Power of 2.
26 app->titles = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->titles_alloc_c);
27 if (!app->titles) return (0); //errno = NOMEM
29 //Go through all title tags and load them.
30 for (pElem = hRoot.FirstChild(PND_PXML_ENAME_TITLE).Element(); pElem;
31 pElem = pElem->NextSiblingElement(PND_PXML_ENAME_TITLE))
34 if ( ! pElem->GetText() ) {
38 char *text = strdup(pElem->GetText());
41 char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_TITLELANG);
45 if (app->titles_c > app->titles_alloc_c) //we don't have enough strings allocated
47 app->titles_alloc_c <<= 1;
48 app->titles = (pnd_localized_string_t *)realloc((void*)app->titles, app->titles_alloc_c);
49 if (!app->titles) return (0); //errno = ENOMEM
52 pnd_localized_string_t *title = &app->titles[app->titles_c - 1];
53 title->language = lang;
56 //pnd_log ( PND_LOG_DEFAULT, (char*)" Title/Lang: %s/%s\n", text, lang );
63 unsigned char pnd_pxml_parse_descriptions(const TiXmlHandle hRoot, pnd_pxml_t *app)
66 app->descriptions_alloc_c = 4; //TODO: adjust this based on how many descriptions a PXML usually has. Power of 2.
68 app->descriptions = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->descriptions_alloc_c);
69 if (!app->descriptions)
71 app->descriptions_alloc_c = 0;
72 return (0); //errno = NOMEM
75 for (pElem = hRoot.FirstChild(PND_PXML_ENAME_DESCRIPTION).Element(); pElem;
76 pElem = pElem->NextSiblingElement(PND_PXML_ENAME_DESCRIPTION))
79 if ( ! pElem->GetText() ) {
83 char *text = strdup(pElem->GetText());
86 char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_DESCRLANG);
89 app->descriptions_c++;
90 if (app->descriptions_c > app->descriptions_alloc_c) //we don't have enough strings allocated
92 app->descriptions_alloc_c <<= 1;
93 app->descriptions = (pnd_localized_string_t*)realloc((void*)app->descriptions, app->descriptions_alloc_c * sizeof(pnd_localized_string_t) );
94 if (!app->descriptions) return (0); //errno = ENOMEM
97 pnd_localized_string_t *description = &app->descriptions[app->descriptions_c - 1];
98 description->language = lang;
99 description->string = text;
105 unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t **apps ) {
107 //Load the XML document
111 unsigned char appwrappermode = 0; // >=1 -> using <application>...</application> wrapper
112 unsigned char appcount = 0;
113 pnd_pxml_t *app = NULL;
115 TiXmlElement *pElem = NULL;
116 TiXmlElement *appElem = NULL;
118 //Find the root element
119 TiXmlHandle hDoc(&doc);
120 TiXmlHandle hRoot(0);
122 pElem = hDoc.FirstChild("PXML").Element();
123 if (!pElem) return (0);
125 // new Strategy; really, we want multiple app support within a PXML, without the lameness of
126 // multiple <PXML>..</PXML> within a single PXML.xml file. As such, we should have an app within
127 // an <application>..</application> wrapper level, with the ID on that. Further, the icon and
128 // .desktop filenames can have a # appended which is the application-count-# within the PXML,
129 // so that they can have their own .desktop and icon without collisions, but still use the
130 // same unique-id if they want to.
131 // To avoid breaking existing PXML's (even though we're pre-launch), can detect if ID
132 // is present in PXML line or not; if not, assume application mode?
133 hRoot = TiXmlHandle(pElem);
135 if ( hRoot.FirstChild(PND_PXML_APP).Element() != NULL ) {
137 appElem = hRoot.FirstChild(PND_PXML_APP).Element();
138 hRoot = TiXmlHandle ( appElem );
141 // until we run out of applications in the PXML..
144 //pnd_log ( PND_LOG_DEFAULT, (char*)" App #%u inside of PXML %s\n", appcount, pFilename );
146 // create the buffer to hold the pxml
147 apps [ appcount ] = (pnd_pxml_t*) malloc ( sizeof(pnd_pxml_t) );
148 memset ( apps [ appcount ], '\0', sizeof(pnd_pxml_t) );
150 // due to old code, just make life easier a minute..
151 app = apps [ appcount ];
152 if ( appwrappermode ) {
153 app -> subapp_number = appcount;
155 app -> subapp_number = 0;
158 //Get unique ID first.
159 if ( appwrappermode ) {
160 app->unique_id = pnd_pxml_get_attribute(appElem, PND_PXML_ATTRNAME_UID);
161 //pnd_log ( PND_LOG_DEFAULT, (char*)" Subapp #%u has unique_id %s\n", appcount, app -> unique_id );
162 app->appdata_dirname = pnd_pxml_get_attribute(appElem, PND_PXML_ATTRNAME_APPDATANAME);
164 app->unique_id = pnd_pxml_get_attribute(hRoot.Element(), PND_PXML_ATTRNAME_UID);
165 //pnd_log ( PND_LOG_DEFAULT, (char*)" Only-app #%u has unique_id %s\n", appcount, app -> unique_id );
168 //Everything related to the title:
169 pnd_pxml_parse_titles(hRoot, app);
171 //Everything description-related:
172 pnd_pxml_parse_descriptions(hRoot, app);
174 //Everything launcher-related in one tag:
175 if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_EXEC).Element()) )
177 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.
178 app->standalone = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECSTAL);
179 app->exec = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECCMD);
180 app->startdir = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECWD);
181 app->exec_no_x11 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECNOX11);
182 app->execargs = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECARGS);
186 if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_ICON).Element()) ) {
187 app->icon = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ICONSRC);
191 if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_INFO).Element()) )
193 app-> info_name = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_INFONAME );
194 app-> info_filename = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_INFOSRC );
195 app-> info_type = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_INFOTYPE );
199 if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_PREVPICS).Element()) )
201 //TODO: Change this if pnd_pxml_t gains the feature of more pics than 2.
202 if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_PREVPIC)) )
204 app->previewpic1 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC);
206 if ( (pElem = pElem->NextSiblingElement(PND_PXML_ENAME_PREVPIC)) )
208 app->previewpic2 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC);
214 if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_AUTHOR).Element()) )
216 app->author_name = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORNAME);
217 app->author_website = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORWWW);
218 //TODO: Uncomment this if the author gets email support.
219 //app->author_email = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHOREMAIL));
223 if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_VERSION).Element()) )
225 app->version_major = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMAJOR);
226 app->version_minor = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMINOR);
227 app->version_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERREL);
228 app->version_build = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERBUILD);
231 //The OS version info:
232 if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_OSVERSION).Element()) )
234 app->osversion_major = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMAJOR);
235 app->osversion_minor = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMINOR);
236 app->osversion_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERREL);
237 app->osversion_build = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERBUILD);
240 int i; //For now, we need to keep track of the index of categories.
242 if ( (pElem = hRoot.FirstChildElement(PND_PXML_NODENAME_CATS).Element()) ) //First, enter the "categories" node.
246 //Goes through all the top-level categories and their sub-categories. i helps limit these to 2.
247 for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_CAT); pElem && i < 2;
248 pElem = pElem->NextSiblingElement(PND_PXML_ENAME_CAT), i++)
250 //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.
253 case 0: //first category counts as the main cat for now
254 app->main_category = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME);
257 case 1: //...second as the alternative
258 app->altcategory = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME);
261 TiXmlElement *pSubCatElem; //the sub-elements for a main category.
262 int j = 0; //the subcategory index within this category
264 //Goes through all the subcategories within this category. j helps limit these to 2.
265 for (pSubCatElem = pElem->FirstChildElement(PND_PXML_ENAME_SUBCAT); pSubCatElem && j < 2;
266 pSubCatElem = pSubCatElem->NextSiblingElement(PND_PXML_ENAME_SUBCAT), j++)
268 char *subcat = pnd_pxml_get_attribute(pSubCatElem, PND_PXML_ATTRNAME_SUBCATNAME);
269 if (!(subcat)) continue;
271 //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.
272 switch (j | (i << 1))
275 app->subcategory1 = subcat;
278 app->subcategory2 = subcat;
281 app->altsubcategory1 = subcat;
284 app->altsubcategory2 = subcat;
290 //All file associations:
291 //Step into the associations node
292 if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_ASSOCS).Element()) )
295 //Go through all associations. i serves as index; since the format only supports 3 associations we need to keep track of the number.
296 for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_ASSOC); pElem && i < 3;
297 pElem = pElem->NextSiblingElement(PND_PXML_ENAME_ASSOC), i++)
299 char *name = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCNAME);
300 char *filetype = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCFTYPE);
301 char *paramter = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCARGS);
303 if (!(name && filetype && paramter)) continue;
305 switch(i) //TODO: same problem here: only 3 associations supported
309 app->associationitem1_name = name;
310 app->associationitem1_filetype = filetype;
311 app->associationitem1_parameter = paramter;
316 app->associationitem2_name = name;
317 app->associationitem2_filetype = filetype;
318 app->associationitem2_parameter = paramter;
323 app->associationitem3_name = name;
324 app->associationitem3_filetype = filetype;
325 app->associationitem3_parameter = paramter;
331 //Performance related things (aka: Clockspeed XD):
332 pElem = hRoot.FirstChild(PND_PXML_ENAME_CLOCK).Element();
335 app->clockspeed = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CLOCKFREQ);
339 pElem = hRoot.FirstChild ( PND_PXML_ENAME_PACKAGE ).Element();
341 app -> package_name = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_NAME );
342 app -> package_release_date = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_DATE );
346 if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_MKDIR).Element()) ) {
349 if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_MKDIR)) ) {
352 if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) {
353 // first <dir>, so just replace it wholesale; we use strdup so we can free() easily later, consistently. Mmm, leak seems imminent.
354 app -> mkdir_sp = strdup ( t );
357 while ( ( pElem = pElem -> NextSiblingElement ( PND_PXML_ENAME_MKDIR ) ) ) {
359 if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) {
360 char *foo = (char*) malloc ( strlen ( app -> mkdir_sp ) + strlen ( t ) + 1 /*:*/ + 1 /*\0*/ );
363 sprintf ( foo, "%s:%s", app -> mkdir_sp, t );
364 free ( app -> mkdir_sp );
365 app -> mkdir_sp = foo;
366 } // assuming we got ram, lets cat it all together
368 } // got another elem?
375 if ( app -> mkdir_sp ) {
376 printf ( "mkdir: %s\n", app -> mkdir_sp );
382 // if in <application> mode, do we find another app?
383 if ( appwrappermode ) {
384 appElem = appElem -> NextSiblingElement ( PND_PXML_APP );
386 //pnd_log ( PND_LOG_DEFAULT, (char*)" No more applications within PXML\n" );
387 break; // no more applications
389 // got another application..
390 //pnd_log ( PND_LOG_DEFAULT, " Found another applications within PXML\n" );
392 hRoot = TiXmlHandle ( appElem );
396 if ( appcount == PXML_MAXAPPS ) {
397 return ( 1 ); // thats all we can handle; we're not going to auto-extend this
401 break; // single-app old PXML
404 } // while finding apps