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