Refreshed pnd_run and sudoers scripts from wiki
[pandora-libraries.git] / lib / pnd_tinyxml.cpp
1
2 #include "tinyxml/tinyxml.h"
3 #include "../include/pnd_pxml.h"
4 #include "pnd_tinyxml.h"
5
6 //Easily change the tag names if required (globally in this file):
7 #include "pnd_pxml_names.h"
8
9 extern "C" {
10
11 unsigned char pnd_pxml_load ( const char* pFilename, pnd_pxml_t *app ) {
12   FILE *f;
13   char *b;
14   unsigned int len;
15
16   f = fopen ( pFilename, "r" );
17
18   if ( ! f ) {
19     return ( 0 );
20   }
21
22   fseek ( f, 0, SEEK_END );
23
24   len = ftell ( f );
25
26   fseek ( f, 0, SEEK_SET );
27
28   b = (char*) malloc ( len );
29
30   if ( ! b ) {
31     fclose ( f );
32     return ( 0 );
33   }
34
35   fread ( b, 1, len, f );
36
37   return ( pnd_pxml_parse ( pFilename, b, len, app ) );
38 }
39
40 char *pnd_pxml_get_attribute(TiXmlElement *elem, const char *name)
41 {
42         const char *value = elem->Attribute(name);
43         if (value)
44                 return strdup(value);
45         else
46                 return NULL;
47 }
48
49 unsigned char pnd_pxml_parse_titles(const TiXmlHandle hRoot, pnd_pxml_t *app)
50 {
51         TiXmlElement *pElem;
52         app->titles_alloc_c = 4;  //TODO: adjust this based on how many titles a PXML usually has. Power of 2.
53
54         app->titles = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->titles_alloc_c);
55         if (!app->titles) return (0); //errno = NOMEM
56
57         //Go through all title tags and load them.
58         for (pElem = hRoot.FirstChild(PND_PXML_ENAME_TITLE).Element(); pElem;
59                 pElem = pElem->NextSiblingElement(PND_PXML_ENAME_TITLE))
60         {
61
62           if ( ! pElem->GetText() ) {
63             continue;
64           }
65
66                 char *text = strdup(pElem->GetText());
67                 if (!text) continue;
68
69                 char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_TITLELANG);
70                 if (!lang) continue;
71
72                 app->titles_c++;
73                 if (app->titles_c > app->titles_alloc_c) //we don't have enough strings allocated
74                 {
75                         app->titles_alloc_c <<= 1;
76                         app->titles = (pnd_localized_string_t *)realloc((void*)app->titles, app->titles_alloc_c);
77                         if (!app->titles) return (0); //errno = ENOMEM
78                 }
79
80                 pnd_localized_string_t *title = &app->titles[app->titles_c - 1];
81                 title->language = lang;
82                 title->string = text;
83         }
84
85         return (1);
86 }
87
88 unsigned char pnd_pxml_parse_descriptions(const TiXmlHandle hRoot, pnd_pxml_t *app)
89 {
90         TiXmlElement *pElem;
91         app->descriptions_alloc_c = 4; //TODO: adjust this based on how many descriptions a PXML usually has. Power of 2.
92
93         app->descriptions = (pnd_localized_string_t *)malloc(sizeof(pnd_localized_string_t) * app->descriptions_alloc_c);
94         if (!app->descriptions) 
95         {
96                 app->descriptions_alloc_c = 0;
97                 return (0); //errno = NOMEM
98         }
99
100         for (pElem = hRoot.FirstChild(PND_PXML_ENAME_DESCRIPTION).Element(); pElem; 
101                 pElem = pElem->NextSiblingElement(PND_PXML_ENAME_DESCRIPTION))
102         {
103
104           if ( ! pElem->GetText() ) {
105             continue;
106           }
107
108                 char *text = strdup(pElem->GetText());
109                 if (!text) continue;
110
111                 char *lang = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_DESCRLANG);
112                 if (!lang) continue;
113
114                 app->descriptions_c++;
115                 if (app->descriptions_c > app->descriptions_alloc_c) //we don't have enough strings allocated
116                 {
117                         app->descriptions_alloc_c <<= 1;
118                         app->descriptions = (pnd_localized_string_t*)realloc((void*)app->descriptions, app->descriptions_alloc_c);
119                         if (!app->descriptions) return (0); //errno = ENOMEM
120                 }
121
122                 pnd_localized_string_t *description = &app->descriptions[app->descriptions_c - 1];
123                 description->language = lang;
124                 description->string = text;
125         }
126         return (1);
127 }
128
129 unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int length, pnd_pxml_t *app ) {
130         //Load the XML document
131         TiXmlDocument doc;
132         doc.Parse(buffer);
133
134         TiXmlElement *pElem = NULL;
135
136         //Find the root element
137         TiXmlHandle hDoc(&doc);
138         TiXmlHandle hRoot(0);
139
140         pElem = hDoc.FirstChild("PXML").Element();
141         if (!pElem) return (0);
142         hRoot = TiXmlHandle(pElem);
143
144         //Get unique ID first.
145         app->unique_id = pnd_pxml_get_attribute(hRoot.Element(), PND_PXML_ATTRNAME_UID);
146
147         //Everything related to the title:
148         pnd_pxml_parse_titles(hRoot, app);
149
150         //Everything description-related:
151         pnd_pxml_parse_descriptions(hRoot, app);
152
153         //Everything launcher-related in one tag:
154         if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_EXEC).Element()) )
155         {
156                 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.
157                 app->standalone = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECSTAL);
158                 app->exec       = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECCMD);
159                 app->startdir   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECWD);
160                 app->exec_no_x11     = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_EXECNOX11);
161         }
162
163         //The app icon:
164         if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_ICON).Element()) )
165         {
166                 app->icon       = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ICONSRC);
167         }
168
169         //The preview pics:
170         if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_PREVPICS).Element()) )
171         {
172                 //TODO: Change this if pnd_pxml_t gains the feature of more pics than 2.
173                 if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_PREVPIC)) )
174                 {
175                         app->previewpic1 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC);
176
177                         if ( (pElem = pElem->NextSiblingElement(PND_PXML_ENAME_PREVPIC)) )
178                         {
179                                 app->previewpic2 = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_PREVPICSRC);
180                         }
181                 }       
182         } //previewpic
183
184         //The author info:
185         if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_AUTHOR).Element()) )
186         {
187                 app->author_name    = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORNAME);
188                 app->author_website = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHORWWW);
189                 //TODO: Uncomment this if the author gets email support.
190                 //app->author_email = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_AUTHOREMAIL));
191         }
192
193         //The version info:
194         if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_VERSION).Element()) )
195         {
196                 app->version_major   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMAJOR);
197                 app->version_minor   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERMINOR);
198                 app->version_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERREL);
199                 app->version_build   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_VERBUILD);
200         }
201
202         //The OS version info:
203         if ( (pElem = hRoot.FirstChild(PND_PXML_ENAME_OSVERSION).Element()) )
204         {
205                 app->osversion_major   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMAJOR);
206                 app->osversion_minor   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERMINOR);
207                 app->osversion_release = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERREL);
208                 app->osversion_build   = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_OSVERBUILD);
209         }
210
211         int i; //For now, we need to keep track of the index of categories.
212         //Categories:
213         if ( (pElem = hRoot.FirstChildElement(PND_PXML_NODENAME_CATS).Element()) ) //First, enter the "categories" node.
214         {
215                 i = 0;
216
217                 //Goes through all the top-level categories and their sub-categories. i helps limit these to 2.
218                 for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_CAT); pElem && i < 2; 
219                         pElem = pElem->NextSiblingElement(PND_PXML_ENAME_CAT), i++)
220                 {
221                         //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.
222                         switch (i)
223                         {
224                         case 0: //first category counts as the main cat for now
225                                 app->main_category = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME);
226                                 break;
227
228                         case 1: //...second as the alternative
229                                 app->altcategory = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CATNAME);
230                         }
231
232                         TiXmlElement *pSubCatElem; //the sub-elements for a main category.
233                         int j = 0; //the subcategory index within this category
234
235                         //Goes through all the subcategories within this category. j helps limit these to 2.
236                         for (pSubCatElem = pElem->FirstChildElement(PND_PXML_ENAME_SUBCAT); pSubCatElem && j < 2;
237                                 pSubCatElem = pSubCatElem->NextSiblingElement(PND_PXML_ENAME_SUBCAT), j++)
238                         {
239                                 char *subcat = pnd_pxml_get_attribute(pSubCatElem, PND_PXML_ATTRNAME_SUBCATNAME);
240                                 if (!(subcat)) continue;
241
242                                 //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.
243                                 switch (j & (i << 1))
244                                 {
245                                 case 0:
246                                         app->subcategory1 = subcat;
247                                         break;
248                                 case 1:
249                                         app->subcategory2 = subcat;
250                                         break;
251                                 case 2:
252                                         app->altsubcategory1 = subcat;
253                                         break;
254                                 case 3:
255                                         app->altsubcategory2 = subcat;
256                                 }
257                         }
258                 }
259         }
260
261         //All file associations:
262         //Step into the associations node
263         if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_ASSOCS).Element()) )
264         {
265                 i = 0;
266                 //Go through all associations. i serves as index; since the format only supports 3 associations we need to keep track of the number.
267                 for (pElem = pElem->FirstChildElement(PND_PXML_ENAME_ASSOC); pElem && i < 3; 
268                         pElem = pElem->NextSiblingElement(PND_PXML_ENAME_ASSOC), i++)
269                 {
270                         char *name = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCNAME);
271                         char *filetype = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCFTYPE);
272                         char *paramter = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_ASSOCARGS);
273
274                         if (!(name && filetype && paramter)) continue;
275
276                         switch(i) //TODO: same problem here: only 3 associations supported
277                         {
278                                 case 0:
279                                 {
280                                         app->associationitem1_name      = name;
281                                         app->associationitem1_filetype  = filetype;
282                                         app->associationitem1_parameter = paramter;
283                                         break;
284                                 }
285                                 case 1:
286                                 {
287                                         app->associationitem2_name      = name;
288                                         app->associationitem2_filetype  = filetype;
289                                         app->associationitem2_parameter = paramter;
290                                         break;
291                                 }
292                                 case 2:
293                                 {
294                                         app->associationitem3_name      = name;
295                                         app->associationitem3_filetype  = filetype;
296                                         app->associationitem3_parameter = paramter;
297                                 }
298                         }
299                 }
300         }
301
302         //Performance related things (aka: Clockspeed XD):
303         pElem = hRoot.FirstChild(PND_PXML_ENAME_CLOCK).Element();
304         if (pElem)
305         {       
306                 app->clockspeed = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_CLOCKFREQ);
307         }
308
309         // Package
310         pElem = hRoot.FirstChild ( PND_PXML_ENAME_PACKAGE ).Element();
311         if ( pElem ) {  
312           app -> package_name = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_NAME );
313           app -> package_release_date = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_DATE );
314         }
315
316         return (1);
317 }
318
319 } // extern C