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