Merged in changes from dflemstr (thanks!)
[pandora-libraries.git] / lib / pnd_pxml.c
1
2 #include <stdio.h> /* for FILE */
3 #include <stdlib.h> /* for malloc */
4 #include <string.h> /* for string ops */
5
6 #include <sys/types.h> /* for stat */
7 #include <sys/stat.h> /* for stat */
8 #include <unistd.h> /* for stat */
9
10 #include "pnd_pxml.h"
11 #include "pnd_pathiter.h"
12 #include "pnd_tinyxml.h"
13
14 pnd_pxml_handle pnd_pxml_fetch ( char *fullpath ) {
15
16   pnd_pxml_t *p = malloc ( sizeof(pnd_pxml_t) );
17
18   memset ( p, '\0', sizeof(pnd_pxml_t) );
19
20   if ( ! pnd_pxml_load ( fullpath, p ) ) {
21     return ( 0 );
22   }
23
24   return ( p );
25 }
26
27 pnd_pxml_handle pnd_pxml_fetch_buffer ( char *filename, char *buffer ) {
28
29   pnd_pxml_t *p = malloc ( sizeof(pnd_pxml_t) );
30
31   memset ( p, '\0', sizeof(pnd_pxml_t) );
32
33   if ( ! pnd_pxml_parse ( filename, buffer, strlen ( buffer ), p ) ) {
34     return ( 0 );
35   }
36
37   return ( p );
38 }
39
40 void pnd_pxml_delete ( pnd_pxml_handle h ) {
41   pnd_pxml_t *p = (pnd_pxml_t*) h;
42
43   int i;
44   if (p->titles) {
45     for (i = 0; i < p->titles_c; i++)
46     {
47       free(p->titles[i].language);
48       free(p->titles[i].string);
49     }
50     free(p->titles);
51   }
52
53   if (p->descriptions) {
54     for (i = 0; i < p->descriptions_c; i++)
55     {
56       free(p->descriptions[i].language);
57       free(p->descriptions[i].string);
58     }
59     free(p->descriptions);
60   }
61
62   if ( p -> standalone ) {
63     free ( p -> standalone );
64   }
65   if ( p -> icon ) {
66     free ( p -> icon );
67   }
68   if ( p -> previewpic1 ) {
69     free ( p -> previewpic1 );
70   }
71   if ( p -> previewpic2 ) {
72     free ( p -> previewpic2 );
73   }
74   if ( p -> author_name ) {
75     free ( p -> author_name );
76   }
77   if ( p -> author_website ) {
78     free ( p -> author_website );
79   }
80   if ( p -> version_major ) {
81     free ( p -> version_major );
82   }
83   if ( p -> version_minor ) {
84     free ( p -> version_minor );
85   }
86   if ( p -> version_release ) {
87     free ( p -> version_release );
88   }
89   if ( p -> version_build ) {
90     free ( p -> version_build );
91   }
92   if ( p -> exec ) {
93     free ( p -> exec );
94   }
95   if ( p -> main_category ) {
96     free ( p -> main_category );
97   }
98   if ( p -> subcategory1 ) {
99     free ( p -> subcategory1 );
100   }
101   if ( p -> subcategory2 ) {
102     free ( p -> subcategory2 );
103   }
104   if ( p -> altcategory ) {
105     free ( p -> altcategory );
106   }
107   if ( p -> altsubcategory1 ) {
108     free ( p -> altsubcategory1 );
109   }
110   if ( p -> altsubcategory2 ) {
111     free ( p -> altsubcategory2 );
112   }
113   if ( p -> osversion_major ) {
114     free ( p -> osversion_major );
115   }
116   if ( p -> osversion_minor ) {
117     free ( p -> osversion_minor );
118   }
119   if ( p -> osversion_release ) {
120     free ( p -> osversion_release );
121   }
122   if ( p -> osversion_build ) {
123     free ( p -> osversion_build );
124   }
125   if ( p -> associationitem1_name ) {
126     free ( p -> associationitem1_name );
127   }
128   if ( p -> associationitem1_filetype ) {
129     free ( p -> associationitem1_filetype );
130   }
131   if ( p -> associationitem1_parameter ) {
132     free ( p -> associationitem1_parameter );
133   }
134   if ( p -> associationitem2_name ) {
135     free ( p -> associationitem2_name );
136   }
137   if ( p -> associationitem2_filetype ) {
138     free ( p -> associationitem2_filetype );
139   }
140   if ( p -> associationitem2_parameter ) {
141     free ( p -> associationitem2_parameter );
142   }
143   if ( p -> associationitem3_name ) {
144     free ( p -> associationitem3_name );
145   }
146   if ( p -> associationitem1_filetype ) {
147     free ( p -> associationitem3_filetype );
148   }
149   if ( p -> associationitem1_parameter ) {
150     free ( p -> associationitem3_parameter );
151   }
152   if ( p -> clockspeed ) {
153     free ( p -> clockspeed );
154   }
155   if ( p -> background ) {
156     free ( p -> background );
157   }
158   if ( p -> startdir ) {
159     free ( p -> startdir );
160   }
161
162   free(p); /*very important!*/
163
164   return;
165 }
166
167 void pnd_pxml_set_app_name ( pnd_pxml_handle h, char *v ) {
168   /* 
169    * Please do not use this function if it can be avoided; it is only here for compatibility.
170    * The function might fail on low memory, and there's no way for the user to know when this happens.
171    */
172   pnd_pxml_t *p = (pnd_pxml_t*) h;
173   char has_en_field = 0;
174   int i;
175
176   if (!v) return; /*TODO: add error information? Make it possible to set the string to NULL?*/
177
178   for (i = 0; i < p->titles_c; i++)
179   {
180     if (strncmp("en", p->titles[i].language, 2) == 0) /*strict comparison; match "en_US", "en_GB" etc... All these are set.*/
181     {
182       free(p->titles[i].string);
183       p->titles[i].string = strdup(v);
184       has_en_field = 1;
185     }
186   }
187
188   if (!has_en_field)
189   {
190     p->titles_c++;
191     if (p->titles_c > p->titles_alloc_c) //we don't have enough strings allocated
192     {
193       p->titles_alloc_c <<= 1;
194       p->titles = (pnd_localized_string_t *)realloc((void*)p->titles, p->titles_alloc_c);
195       if (!p->titles) return; //errno = ENOMEM
196     }
197     p->titles[p->titles_c - 1].language = "en_US";
198     p->titles[p->titles_c - 1].string = strdup(v);
199   }
200
201   return;
202 }
203
204 unsigned char pnd_is_pxml_valid_app ( pnd_pxml_handle h ) {
205   //pnd_pxml_t *p = (pnd_pxml_t*) h; //unused atm
206
207   // for now, lets just verify the exec-path is valid
208
209   //printf ( "exec is '%s'\n", p -> exec );
210
211   return ( 1 );
212
213   // even this is complicated by pnd_run.sh semantics .. can't check if it exists
214   // during discovery, since it is not mounted yet..
215 #if 0
216   struct stat buf;
217   if ( stat ( p -> exec, &buf ) == 0 ) {
218     return ( 1 ); // path is present
219   }
220 #endif
221
222   return ( 0 );
223 }
224
225 signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) {
226   // the pxml includes a unique-id; use this value to attempt to find an
227   // override in the given searchpath
228   signed char retval = 0;
229   pnd_pxml_handle mergeh;
230
231   if ( ! pnd_pxml_get_unique_id ( h ) ) {
232     return ( -1 ); // no unique-id present, so can't use it to name potential override files
233   }
234
235   SEARCHPATH_PRE
236   {
237
238     // do it
239     strncat ( buffer, "/", FILENAME_MAX );
240     strncat ( buffer, pnd_pxml_get_unique_id ( h ), FILENAME_MAX );
241     strncat ( buffer, ".xml", FILENAME_MAX );
242     //printf ( "  Path to seek merges: '%s'\n", buffer );
243
244     mergeh = pnd_pxml_fetch ( buffer );
245
246     if ( mergeh ) {
247
248       if ( pnd_pxml_get_app_name_en ( mergeh ) ) {
249         pnd_pxml_set_app_name ( h, pnd_pxml_get_app_name_en ( mergeh ) );
250       }
251
252       pnd_pxml_delete ( mergeh );
253     }
254
255   }
256   SEARCHPATH_POST
257
258   return ( retval );
259 }
260
261 char *pnd_pxml_get_best_localized_string(pnd_localized_string_t strings[], int strings_c, char *iso_lang)
262 {
263   int i;
264   int similarity_weight = 0xff; /*Set to something Really Bad in the beginning*/
265   char *best_match = NULL;
266
267   for(i = 0; i < strings_c; i++)
268   {
269     int new_weight = abs(strcmp(strings[i].language, iso_lang));
270     if (new_weight < similarity_weight)
271     {
272       similarity_weight = new_weight;
273       best_match = strings[i].string;
274     }
275   }
276
277   if ( best_match ) {
278     return strdup(best_match);
279   }
280
281   return ( NULL );
282 }
283
284 char *pnd_pxml_get_app_name ( pnd_pxml_handle h, char *iso_lang ) {
285   pnd_pxml_t *p = (pnd_pxml_t *) h;
286   return pnd_pxml_get_best_localized_string(p->titles, p->titles_c, iso_lang);
287 }
288
289 char *pnd_pxml_get_app_name_en ( pnd_pxml_handle h ) {
290   return pnd_pxml_get_app_name(h, "en");
291 }
292
293 char *pnd_pxml_get_app_name_de ( pnd_pxml_handle h ) {
294   return pnd_pxml_get_app_name(h, "de");
295 }
296
297 char *pnd_pxml_get_app_name_it ( pnd_pxml_handle h ) {
298   return pnd_pxml_get_app_name(h, "it");
299 }
300
301 char *pnd_pxml_get_app_name_fr ( pnd_pxml_handle h ) {
302   return pnd_pxml_get_app_name(h, "fr");
303 }
304
305 char *pnd_pxml_get_unique_id ( pnd_pxml_handle h ) {
306   pnd_pxml_t *p = (pnd_pxml_t*) h;
307   return ( p -> unique_id );
308 }
309
310 char *pnd_pxml_get_standalone ( pnd_pxml_handle h ) {
311   pnd_pxml_t *p = (pnd_pxml_t*) h;
312   return ( p -> standalone );
313 }
314
315 char *pnd_pxml_get_icon ( pnd_pxml_handle h ) {
316   pnd_pxml_t *p = (pnd_pxml_t*) h;
317   return ( p -> icon );
318 }
319
320 char *pnd_pxml_get_app_description ( pnd_pxml_handle h, char *iso_lang ) {
321   pnd_pxml_t *p = (pnd_pxml_t *) h;
322   return pnd_pxml_get_best_localized_string(p->descriptions, p->descriptions_c, iso_lang);
323 }
324
325 char *pnd_pxml_get_description_en ( pnd_pxml_handle h ) {
326   return pnd_pxml_get_app_description(h, "en");
327 }
328
329 char *pnd_pxml_get_description_de ( pnd_pxml_handle h ) {
330   return pnd_pxml_get_app_description(h, "de");
331 }
332
333 char *pnd_pxml_get_description_it ( pnd_pxml_handle h ) {
334   return pnd_pxml_get_app_description(h, "it");
335 }
336
337 char *pnd_pxml_get_description_fr ( pnd_pxml_handle h ) {
338   return pnd_pxml_get_app_description(h, "fr");
339 }
340
341 char *pnd_pxml_get_previewpic1 ( pnd_pxml_handle h ) {
342   pnd_pxml_t *p = (pnd_pxml_t*) h;
343   return ( p -> previewpic1 );
344 }
345
346 char *pnd_pxml_get_previewpic2 ( pnd_pxml_handle h ) {
347   pnd_pxml_t *p = (pnd_pxml_t*) h;
348   return ( p -> previewpic2 );
349 }
350
351 char *pnd_pxml_get_author_name ( pnd_pxml_handle h ) {
352   pnd_pxml_t *p = (pnd_pxml_t*) h;
353   return ( p -> author_name );
354 }
355
356 char *pnd_pxml_get_author_website ( pnd_pxml_handle h ) {
357   pnd_pxml_t *p = (pnd_pxml_t*) h;
358   return ( p -> author_website );
359 }
360
361 char *pnd_pxml_get_version_major ( pnd_pxml_handle h ) {
362   pnd_pxml_t *p = (pnd_pxml_t*) h;
363   return ( p -> version_major );
364 }
365
366 char *pnd_pxml_get_version_minor ( pnd_pxml_handle h ) {
367   pnd_pxml_t *p = (pnd_pxml_t*) h;
368   return ( p -> version_minor );
369 }
370
371 char *pnd_pxml_get_version_release ( pnd_pxml_handle h ) {
372   pnd_pxml_t *p = (pnd_pxml_t*) h;
373   return ( p -> version_release );
374 }
375
376 char *pnd_pxml_get_version_build ( pnd_pxml_handle h ) {
377   pnd_pxml_t *p = (pnd_pxml_t*) h;
378   return ( p -> version_build );
379 }
380
381 char *pnd_pxml_get_exec ( pnd_pxml_handle h ) {
382   pnd_pxml_t *p = (pnd_pxml_t*) h;
383   return ( p -> exec );
384 }
385
386 char *pnd_pxml_get_main_category ( pnd_pxml_handle h ) {
387   pnd_pxml_t *p = (pnd_pxml_t*) h;
388   return ( p -> main_category );
389 }
390
391 char *pnd_pxml_get_subcategory1 ( pnd_pxml_handle h ) {
392   pnd_pxml_t *p = (pnd_pxml_t*) h;
393   return ( p -> subcategory1 );
394 }
395
396 char *pnd_pxml_get_subcategory2 ( pnd_pxml_handle h ) {
397   pnd_pxml_t *p = (pnd_pxml_t*) h;
398   return ( p -> subcategory2 );
399 }
400
401 char *pnd_pxml_get_altcategory ( pnd_pxml_handle h ) {
402   pnd_pxml_t *p = (pnd_pxml_t*) h;
403   return ( p -> altcategory );
404 }
405
406 char *pnd_pxml_get_altsubcategory1 ( pnd_pxml_handle h ) {
407   pnd_pxml_t *p = (pnd_pxml_t*) h;
408   return ( p -> altsubcategory1 );
409 }
410
411 char *pnd_pxml_get_altsubcategory2 ( pnd_pxml_handle h ) {
412   pnd_pxml_t *p = (pnd_pxml_t*) h;
413   return ( p -> altsubcategory2 );
414 }
415
416 char *pnd_pxml_get_osversion_major ( pnd_pxml_handle h ) {
417   pnd_pxml_t *p = (pnd_pxml_t*) h;
418   return ( p -> osversion_major );
419 }
420
421 char *pnd_pxml_get_osversion_minor ( pnd_pxml_handle h ) {
422   pnd_pxml_t *p = (pnd_pxml_t*) h;
423   return ( p -> osversion_minor );
424 }
425
426 char *pnd_pxml_get_osversion_release ( pnd_pxml_handle h ) {
427   pnd_pxml_t *p = (pnd_pxml_t*) h;
428   return ( p -> osversion_release );
429 }
430
431 char *pnd_pxml_get_osversion_build ( pnd_pxml_handle h ) {
432   pnd_pxml_t *p = (pnd_pxml_t*) h;
433   return ( p -> osversion_build );
434 }
435
436 char *pnd_pxml_get_associationitem1_name ( pnd_pxml_handle h ) {
437   pnd_pxml_t *p = (pnd_pxml_t*) h;
438   return ( p -> associationitem1_name );
439 }
440
441 char *pnd_pxml_get_associationitem1_filetype ( pnd_pxml_handle h ) {
442   pnd_pxml_t *p = (pnd_pxml_t*) h;
443   return ( p -> associationitem1_filetype );
444 }
445
446 char *pnd_pxml_get_associationitem1_parameter ( pnd_pxml_handle h ) {
447   pnd_pxml_t *p = (pnd_pxml_t*) h;
448   return ( p -> associationitem1_parameter );
449 }
450
451 char *pnd_pxml_get_associationitem2_name ( pnd_pxml_handle h ) {
452   pnd_pxml_t *p = (pnd_pxml_t*) h;
453   return ( p -> associationitem2_name );
454 }
455
456 char *pnd_pxml_get_associationitem2_filetype ( pnd_pxml_handle h ) {
457   pnd_pxml_t *p = (pnd_pxml_t*) h;
458   return ( p -> associationitem2_filetype );
459 }
460
461 char *pnd_pxml_get_associationitem2_parameter ( pnd_pxml_handle h ) {
462   pnd_pxml_t *p = (pnd_pxml_t*) h;
463   return ( p -> associationitem2_parameter );
464 }
465
466 char *pnd_pxml_get_associationitem3_name ( pnd_pxml_handle h ) {
467   pnd_pxml_t *p = (pnd_pxml_t*) h;
468   return ( p -> associationitem3_name );
469 }
470
471 char *pnd_pxml_get_associationitem3_filetype ( pnd_pxml_handle h ) {
472   pnd_pxml_t *p = (pnd_pxml_t*) h;
473   return ( p -> associationitem3_filetype );
474 }
475
476 char *pnd_pxml_get_associationitem3_parameter ( pnd_pxml_handle h ) {
477   pnd_pxml_t *p = (pnd_pxml_t*) h;
478   return ( p -> associationitem3_parameter );
479 }
480
481 char *pnd_pxml_get_clockspeed ( pnd_pxml_handle h ) {
482   pnd_pxml_t *p = (pnd_pxml_t*) h;
483   return ( p -> clockspeed );
484 }
485
486 char *pnd_pxml_get_background ( pnd_pxml_handle h ) {
487   pnd_pxml_t *p = (pnd_pxml_t*) h;
488   return ( p -> background );
489 }
490
491 char *pnd_pxml_get_startdir ( pnd_pxml_handle h ) {
492   pnd_pxml_t *p = (pnd_pxml_t*) h;
493   return ( p -> startdir );
494 }