Fix even more leaks
[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 #include "pnd_logger.h"
14
15 pnd_pxml_handle *pnd_pxml_fetch ( char *fullpath ) {
16   FILE *f;
17   char *b;
18   unsigned int len;
19   pnd_pxml_handle *h;
20
21   f = fopen ( fullpath, "r" );
22
23   if ( ! f ) {
24     return ( 0 );
25   }
26
27   fseek ( f, 0, SEEK_END );
28
29   len = ftell ( f );
30
31   fseek ( f, 0, SEEK_SET );
32
33   if ( ! len ) {
34     return ( NULL );
35   }
36
37   b = (char*) malloc ( len + 1 );
38
39   if ( ! b ) {
40     fclose ( f );
41     return ( 0 );
42   }
43
44   fread ( b, 1, len, f );
45
46   fclose ( f );
47
48   h = pnd_pxml_fetch_buffer ( fullpath, b );
49   free ( b );
50
51   return ( h );
52 }
53
54 pnd_pxml_handle *pnd_pxml_fetch_buffer ( char *filename, char *buffer ) {
55
56   pnd_pxml_t **p = malloc ( sizeof(pnd_pxml_t*) * PXML_MAXAPPS );
57   memset ( p, '\0', sizeof(pnd_pxml_t*) * PXML_MAXAPPS );
58
59   if ( ! pnd_pxml_parse ( filename, buffer, strlen ( buffer ), p ) ) {
60     return ( 0 );
61   }
62
63   return ( (pnd_pxml_handle*) p );
64 }
65
66 void pnd_pxml_delete ( pnd_pxml_handle h ) {
67   pnd_pxml_t *p = (pnd_pxml_t*) h;
68
69   int i;
70   if (p->titles) {
71     for (i = 0; i < p->titles_c; i++)
72     {
73       free(p->titles[i].language);
74       free(p->titles[i].string);
75     }
76     free(p->titles);
77   }
78
79   if (p->descriptions) {
80     for (i = 0; i < p->descriptions_c; i++)
81     {
82       free(p->descriptions[i].language);
83       free(p->descriptions[i].string);
84     }
85     free(p->descriptions);
86   }
87
88   if ( p -> unique_id ) {
89      free ( p -> unique_id );
90   }
91   if ( p -> package_id ) {
92      free ( p -> package_id );
93   }
94   if ( p -> standalone ) {
95     free ( p -> standalone );
96   }
97   if ( p -> icon ) {
98     free ( p -> icon );
99   }
100   if ( p -> previewpic1 ) {
101     free ( p -> previewpic1 );
102   }
103   if ( p -> previewpic2 ) {
104     free ( p -> previewpic2 );
105   }
106   if ( p -> author_name ) {
107     free ( p -> author_name );
108   }
109   if ( p -> author_website ) {
110     free ( p -> author_website );
111   }
112   if ( p -> version_major ) {
113     free ( p -> version_major );
114   }
115   if ( p -> version_minor ) {
116     free ( p -> version_minor );
117   }
118   if ( p -> version_release ) {
119     free ( p -> version_release );
120   }
121   if ( p -> version_build ) {
122     free ( p -> version_build );
123   }
124   if ( p -> exec ) {
125     free ( p -> exec );
126   }
127   if ( p -> main_category ) {
128     free ( p -> main_category );
129   }
130   if ( p -> subcategory1 ) {
131     free ( p -> subcategory1 );
132   }
133   if ( p -> subcategory2 ) {
134     free ( p -> subcategory2 );
135   }
136   if ( p -> altcategory ) {
137     free ( p -> altcategory );
138   }
139   if ( p -> altsubcategory1 ) {
140     free ( p -> altsubcategory1 );
141   }
142   if ( p -> altsubcategory2 ) {
143     free ( p -> altsubcategory2 );
144   }
145   if ( p -> osversion_major ) {
146     free ( p -> osversion_major );
147   }
148   if ( p -> osversion_minor ) {
149     free ( p -> osversion_minor );
150   }
151   if ( p -> osversion_release ) {
152     free ( p -> osversion_release );
153   }
154   if ( p -> osversion_build ) {
155     free ( p -> osversion_build );
156   }
157   if ( p -> associationitem1_name ) {
158     free ( p -> associationitem1_name );
159   }
160   if ( p -> associationitem1_filetype ) {
161     free ( p -> associationitem1_filetype );
162   }
163   if ( p -> associationitem1_parameter ) {
164     free ( p -> associationitem1_parameter );
165   }
166   if ( p -> associationitem2_name ) {
167     free ( p -> associationitem2_name );
168   }
169   if ( p -> associationitem2_filetype ) {
170     free ( p -> associationitem2_filetype );
171   }
172   if ( p -> associationitem2_parameter ) {
173     free ( p -> associationitem2_parameter );
174   }
175   if ( p -> associationitem3_name ) {
176     free ( p -> associationitem3_name );
177   }
178   if ( p -> associationitem1_filetype ) {
179     free ( p -> associationitem3_filetype );
180   }
181   if ( p -> associationitem1_parameter ) {
182     free ( p -> associationitem3_parameter );
183   }
184   if ( p -> clockspeed ) {
185     free ( p -> clockspeed );
186   }
187   if ( p -> background ) {
188     free ( p -> background );
189   }
190   if ( p -> startdir ) {
191     free ( p -> startdir );
192   }
193   if ( p -> appdata_dirname ) {
194     free ( p -> appdata_dirname );
195   }
196   if ( p -> info_name ) {
197     free ( p -> info_name );
198   }
199   if ( p -> info_filename ) {
200     free ( p -> info_filename );
201   }
202   if ( p -> info_type ) {
203     free ( p -> info_type );
204   }
205   if ( p -> exec_no_x11 ) {
206     free ( p -> exec_no_x11 );
207   }
208   if ( p -> execargs ) {
209     free ( p -> execargs );
210   }
211   if ( p -> mkdir_sp ) {
212     free ( p -> mkdir_sp );
213   }
214   if ( p -> package_version_major ) {
215     free ( p -> package_version_major );
216   }
217   if ( p -> package_version_minor ) {
218     free ( p -> package_version_minor );
219   }
220   if ( p -> package_version_release ) {
221     free ( p -> package_version_release );
222   }
223   if ( p -> package_version_build ) {
224     free ( p -> package_version_build );
225   }
226
227   free(p); /*very important!*/
228
229   return;
230 }
231
232 void pnd_pxml_set_app_name ( pnd_pxml_handle h, char *v ) {
233   /*
234    * Please do not use this function if it can be avoided; it is only here for compatibility.
235    * The function might fail on low memory, and there's no way for the user to know when this happens.
236    */
237   pnd_pxml_t *p = (pnd_pxml_t*) h;
238   char has_en_field = 0;
239   int i;
240
241   if (!v) return; /*TODO: add error information? Make it possible to set the string to NULL?*/
242
243   for (i = 0; i < p->titles_c; i++)
244   {
245     if (strncmp("en", p->titles[i].language, 2) == 0) /*strict comparison; match "en_US", "en_GB" etc... All these are set.*/
246     {
247       free(p->titles[i].string);
248       p->titles[i].string = strdup(v);
249       has_en_field = 1;
250     }
251   }
252
253   if (!has_en_field)
254   {
255     p->titles_c++;
256     if (p->titles_c > p->titles_alloc_c) //we don't have enough strings allocated
257     {
258       p->titles_alloc_c <<= 1;
259       p->titles = (pnd_localized_string_t *)realloc((void*)p->titles, p->titles_alloc_c);
260       if (!p->titles) return; //errno = ENOMEM
261     }
262     p->titles[p->titles_c - 1].language = "en_US";
263     p->titles[p->titles_c - 1].string = strdup(v);
264   }
265
266   return;
267 }
268
269 unsigned char pnd_is_pxml_valid_app ( pnd_pxml_handle h ) {
270   //pnd_pxml_t *p = (pnd_pxml_t*) h; //unused atm
271
272   // for now, lets just verify the exec-path is valid
273
274   //printf ( "exec is '%s'\n", p -> exec );
275
276   return ( 1 );
277
278   // even this is complicated by pnd_run.sh semantics .. can't check if it exists
279   // during discovery, since it is not mounted yet..
280 #if 0
281   struct stat buf;
282   if ( stat ( p -> exec, &buf ) == 0 ) {
283     return ( 1 ); // path is present
284   }
285 #endif
286
287   return ( 0 );
288 }
289
290 signed char pnd_pxml_merge_override ( pnd_pxml_handle h, char *searchpath ) {
291   // the pxml includes a unique-id; use this value to attempt to find an
292   // override in the given searchpath
293   signed char retval = 0;
294
295 #if 0 // TODO: Unfinished entirely now
296   pnd_pxml_handle mergeh;
297
298   if ( ! pnd_pxml_get_unique_id ( h ) ) {
299     return ( -1 ); // no unique-id present, so can't use it to name potential override files
300   }
301
302   SEARCHPATH_PRE
303   {
304
305     // do it
306     strncat ( buffer, "/", FILENAME_MAX );
307     strncat ( buffer, pnd_pxml_get_unique_id ( h ), FILENAME_MAX );
308     strncat ( buffer, ".xml", FILENAME_MAX );
309     //printf ( "  Path to seek merges: '%s'\n", buffer );
310
311     // TODO: handle multiple subapps!
312     mergeh = pnd_pxml_fetch ( buffer );
313
314     if ( mergeh ) {
315
316       // TODO: handle all the various data bits
317       if ( pnd_pxml_get_app_name_en ( mergeh ) ) {
318         pnd_pxml_set_app_name ( h, pnd_pxml_get_app_name_en ( mergeh ) );
319       }
320
321       pnd_pxml_delete ( mergeh );
322     }
323
324   }
325   SEARCHPATH_POST
326 #endif
327
328   return ( retval );
329 }
330
331 char *pnd_pxml_get_best_localized_string(pnd_localized_string_t strings[], int strings_c, char *iso_lang)
332 {
333   int i;
334   int similarity_weight = 0xffff; /*Set to something Really Bad in the beginning*/
335   char *best_match = NULL;
336
337   for(i = 0; i < strings_c; i++)
338   {
339     // factor in the length -- if we're given 'en' and have a string 'en_US', thats better than 'de_something'; if we don't
340     // use length, then en_US and de_FO are same to 'en'.
341     int maxcount = strlen ( strings[i].language ) < strlen ( iso_lang ) ? strlen ( strings[i].language ) : strlen ( iso_lang );
342     int new_weight = abs(strncmp(strings[i].language, iso_lang, maxcount));
343     //pnd_log ( PND_LOG_DEFAULT, "looking for lang %s, looking at lang %s (weight %d, old %d): %s\n",
344     //          iso_lang, strings [ i ].language, new_weight, similarity_weight, strings [ i ].string );
345     if (new_weight < similarity_weight)
346     {
347       similarity_weight = new_weight;
348       best_match = strings[i].string;
349     }
350   }
351
352   if ( best_match ) {
353     //pnd_log ( PND_LOG_DEFAULT, "best match: %s\n", best_match );
354     return strdup(best_match);
355   }
356
357   //pnd_log ( PND_LOG_DEFAULT, "best match: FAIL\n" );
358
359   return ( NULL );
360 }
361
362 char *pnd_pxml_get_package_id ( pnd_pxml_handle h ) {
363   pnd_pxml_t *p = (pnd_pxml_t*) h;
364   return ( p -> package_id );
365 }
366
367 char *pnd_pxml_get_app_name ( pnd_pxml_handle h, char *iso_lang ) {
368   pnd_pxml_t *p = (pnd_pxml_t *) h;
369   return pnd_pxml_get_best_localized_string(p->titles, p->titles_c, iso_lang);
370 }
371
372 char *pnd_pxml_get_app_name_en ( pnd_pxml_handle h ) {
373   return pnd_pxml_get_app_name(h, "en");
374 }
375
376 char *pnd_pxml_get_app_name_de ( pnd_pxml_handle h ) {
377   return pnd_pxml_get_app_name(h, "de");
378 }
379
380 char *pnd_pxml_get_app_name_it ( pnd_pxml_handle h ) {
381   return pnd_pxml_get_app_name(h, "it");
382 }
383
384 char *pnd_pxml_get_app_name_fr ( pnd_pxml_handle h ) {
385   return pnd_pxml_get_app_name(h, "fr");
386 }
387 char *pnd_pxml_get_unique_id ( pnd_pxml_handle h ) {
388   pnd_pxml_t *p = (pnd_pxml_t*) h;
389   return ( p -> unique_id );
390 }
391
392 char *pnd_pxml_get_appdata_dirname ( pnd_pxml_handle h ) {
393   pnd_pxml_t *p = (pnd_pxml_t*) h;
394   return ( p -> appdata_dirname );
395 }
396
397 char *pnd_pxml_get_standalone ( pnd_pxml_handle h ) {
398   pnd_pxml_t *p = (pnd_pxml_t*) h;
399   return ( p -> standalone );
400 }
401
402 char *pnd_pxml_get_icon ( pnd_pxml_handle h ) {
403   pnd_pxml_t *p = (pnd_pxml_t*) h;
404   return ( p -> icon );
405 }
406
407 // this guy's func name is 'out of sync' with the family of functions below; but since it
408 // exists, rather than just remove it and break someones code, will add in the appropriate
409 // function wrapper; the header only specifies the other guy (always did), so the header
410 // was already on the right path.
411 char *pnd_pxml_get_app_description ( pnd_pxml_handle h, char *iso_lang ) {
412   pnd_pxml_t *p = (pnd_pxml_t *) h;
413   return pnd_pxml_get_best_localized_string(p->descriptions, p->descriptions_c, iso_lang);
414 }
415
416 char *pnd_pxml_get_description_en ( pnd_pxml_handle h ) {
417   return pnd_pxml_get_app_description(h, "en");
418 }
419
420 char *pnd_pxml_get_description_de ( pnd_pxml_handle h ) {
421   return pnd_pxml_get_app_description(h, "de");
422 }
423
424 char *pnd_pxml_get_description_it ( pnd_pxml_handle h ) {
425   return pnd_pxml_get_app_description(h, "it");
426 }
427
428 char *pnd_pxml_get_description_fr ( pnd_pxml_handle h ) {
429   return pnd_pxml_get_app_description(h, "fr");
430 }
431
432 // wrapper added so family of function names is consistent; see comment for pnd_pxml_get_app_description() above
433 char *pnd_pxml_get_description ( pnd_pxml_handle h, char *iso_lang) {
434   return ( pnd_pxml_get_app_description ( h, iso_lang ) );
435 }
436
437 char *pnd_pxml_get_previewpic1 ( pnd_pxml_handle h ) {
438   pnd_pxml_t *p = (pnd_pxml_t*) h;
439   return ( p -> previewpic1 );
440 }
441
442 char *pnd_pxml_get_previewpic2 ( pnd_pxml_handle h ) {
443   pnd_pxml_t *p = (pnd_pxml_t*) h;
444   return ( p -> previewpic2 );
445 }
446
447 char *pnd_pxml_get_author_name ( pnd_pxml_handle h ) {
448   pnd_pxml_t *p = (pnd_pxml_t*) h;
449   return ( p -> author_name );
450 }
451
452 char *pnd_pxml_get_author_website ( pnd_pxml_handle h ) {
453   pnd_pxml_t *p = (pnd_pxml_t*) h;
454   return ( p -> author_website );
455 }
456
457 char *pnd_pxml_get_version_major ( pnd_pxml_handle h ) {
458   pnd_pxml_t *p = (pnd_pxml_t*) h;
459   return ( p -> version_major );
460 }
461
462 char *pnd_pxml_get_version_minor ( pnd_pxml_handle h ) {
463   pnd_pxml_t *p = (pnd_pxml_t*) h;
464   return ( p -> version_minor );
465 }
466
467 char *pnd_pxml_get_version_release ( pnd_pxml_handle h ) {
468   pnd_pxml_t *p = (pnd_pxml_t*) h;
469   return ( p -> version_release );
470 }
471
472 char *pnd_pxml_get_version_build ( pnd_pxml_handle h ) {
473   pnd_pxml_t *p = (pnd_pxml_t*) h;
474   return ( p -> version_build );
475 }
476
477 char *pnd_pxml_get_exec ( pnd_pxml_handle h ) {
478   pnd_pxml_t *p = (pnd_pxml_t*) h;
479   return ( p -> exec );
480 }
481
482 char *pnd_pxml_get_execargs ( pnd_pxml_handle h ) {
483   pnd_pxml_t *p = (pnd_pxml_t*) h;
484   return ( p -> execargs );
485 }
486
487 char *pnd_pxml_get_exec_option_no_x11 ( pnd_pxml_handle h ) {
488   pnd_pxml_t *p = (pnd_pxml_t*) h;
489   return ( p -> exec_no_x11 );
490 }
491
492 char *pnd_pxml_get_main_category ( pnd_pxml_handle h ) {
493   pnd_pxml_t *p = (pnd_pxml_t*) h;
494   return ( p -> main_category );
495 }
496
497 char *pnd_pxml_get_subcategory1 ( pnd_pxml_handle h ) {
498   pnd_pxml_t *p = (pnd_pxml_t*) h;
499   return ( p -> subcategory1 );
500 }
501
502 char *pnd_pxml_get_subcategory2 ( pnd_pxml_handle h ) {
503   pnd_pxml_t *p = (pnd_pxml_t*) h;
504   return ( p -> subcategory2 );
505 }
506
507 char *pnd_pxml_get_altcategory ( pnd_pxml_handle h ) {
508   pnd_pxml_t *p = (pnd_pxml_t*) h;
509   return ( p -> altcategory );
510 }
511
512 char *pnd_pxml_get_altsubcategory1 ( pnd_pxml_handle h ) {
513   pnd_pxml_t *p = (pnd_pxml_t*) h;
514   return ( p -> altsubcategory1 );
515 }
516
517 char *pnd_pxml_get_altsubcategory2 ( pnd_pxml_handle h ) {
518   pnd_pxml_t *p = (pnd_pxml_t*) h;
519   return ( p -> altsubcategory2 );
520 }
521
522 char *pnd_pxml_get_osversion_major ( pnd_pxml_handle h ) {
523   pnd_pxml_t *p = (pnd_pxml_t*) h;
524   return ( p -> osversion_major );
525 }
526
527 char *pnd_pxml_get_osversion_minor ( pnd_pxml_handle h ) {
528   pnd_pxml_t *p = (pnd_pxml_t*) h;
529   return ( p -> osversion_minor );
530 }
531
532 char *pnd_pxml_get_osversion_release ( pnd_pxml_handle h ) {
533   pnd_pxml_t *p = (pnd_pxml_t*) h;
534   return ( p -> osversion_release );
535 }
536
537 char *pnd_pxml_get_osversion_build ( pnd_pxml_handle h ) {
538   pnd_pxml_t *p = (pnd_pxml_t*) h;
539   return ( p -> osversion_build );
540 }
541
542 char *pnd_pxml_get_associationitem1_name ( pnd_pxml_handle h ) {
543   pnd_pxml_t *p = (pnd_pxml_t*) h;
544   return ( p -> associationitem1_name );
545 }
546
547 char *pnd_pxml_get_associationitem1_filetype ( pnd_pxml_handle h ) {
548   pnd_pxml_t *p = (pnd_pxml_t*) h;
549   return ( p -> associationitem1_filetype );
550 }
551
552 char *pnd_pxml_get_associationitem1_parameter ( pnd_pxml_handle h ) {
553   pnd_pxml_t *p = (pnd_pxml_t*) h;
554   return ( p -> associationitem1_parameter );
555 }
556
557 char *pnd_pxml_get_associationitem2_name ( pnd_pxml_handle h ) {
558   pnd_pxml_t *p = (pnd_pxml_t*) h;
559   return ( p -> associationitem2_name );
560 }
561
562 char *pnd_pxml_get_associationitem2_filetype ( pnd_pxml_handle h ) {
563   pnd_pxml_t *p = (pnd_pxml_t*) h;
564   return ( p -> associationitem2_filetype );
565 }
566
567 char *pnd_pxml_get_associationitem2_parameter ( pnd_pxml_handle h ) {
568   pnd_pxml_t *p = (pnd_pxml_t*) h;
569   return ( p -> associationitem2_parameter );
570 }
571
572 char *pnd_pxml_get_associationitem3_name ( pnd_pxml_handle h ) {
573   pnd_pxml_t *p = (pnd_pxml_t*) h;
574   return ( p -> associationitem3_name );
575 }
576
577 char *pnd_pxml_get_associationitem3_filetype ( pnd_pxml_handle h ) {
578   pnd_pxml_t *p = (pnd_pxml_t*) h;
579   return ( p -> associationitem3_filetype );
580 }
581
582 char *pnd_pxml_get_associationitem3_parameter ( pnd_pxml_handle h ) {
583   pnd_pxml_t *p = (pnd_pxml_t*) h;
584   return ( p -> associationitem3_parameter );
585 }
586
587 char *pnd_pxml_get_clockspeed ( pnd_pxml_handle h ) {
588   pnd_pxml_t *p = (pnd_pxml_t*) h;
589   return ( p -> clockspeed );
590 }
591
592 char *pnd_pxml_get_background ( pnd_pxml_handle h ) {
593   pnd_pxml_t *p = (pnd_pxml_t*) h;
594   return ( p -> background );
595 }
596
597 char *pnd_pxml_get_startdir ( pnd_pxml_handle h ) {
598   pnd_pxml_t *p = (pnd_pxml_t*) h;
599   return ( p -> startdir );
600 }
601
602 char *pnd_pxml_get_mkdir ( pnd_pxml_handle h ) {
603   pnd_pxml_t *p = (pnd_pxml_t*) h;
604   return ( p -> mkdir_sp );
605 }
606
607 char *pnd_pxml_get_package_version_major ( pnd_pxml_handle h ) {
608    pnd_pxml_t *p = (pnd_pxml_t*) h;
609    return ( p -> package_version_major );
610 }
611
612 char *pnd_pxml_get_package_version_minor ( pnd_pxml_handle h ) {
613    pnd_pxml_t *p = (pnd_pxml_t*) h;
614    return ( p -> package_version_minor );
615 }
616
617 char *pnd_pxml_get_package_version_release ( pnd_pxml_handle h ) {
618    pnd_pxml_t *p = (pnd_pxml_t*) h;
619    return ( p -> package_version_release );
620 }
621
622 char *pnd_pxml_get_package_version_build ( pnd_pxml_handle h ) {
623    pnd_pxml_t *p = (pnd_pxml_t*) h;
624    return ( p -> package_version_build );
625 }
626
627 unsigned char pnd_pxml_is_affirmative ( char *v ) {
628
629   if ( ! v ) {
630     return ( 0 );
631   }
632
633   if ( ( v [ 0 ] == 'Y' ) ||
634        ( v [ 0 ] == 'y' ) ||
635        ( v [ 0 ] == '1' ) )
636   {
637     return ( 0 );
638   }
639
640   return ( 0 );
641 }
642
643 pnd_pxml_x11_req_e pnd_pxml_get_x11 ( char *pxmlvalue ) {
644
645   if ( ! pxmlvalue ) {
646     return ( pnd_pxml_x11_ignored );
647   } else if ( strcasecmp ( pxmlvalue, "req" ) == 0 ) {
648     return ( pnd_pxml_x11_required );
649   } else if ( strcasecmp ( pxmlvalue, "stop" ) == 0 ) {
650     return ( pnd_pxml_x11_stop );
651   } else if ( strcasecmp ( pxmlvalue, "ignore" ) == 0 ) {
652     return ( pnd_pxml_x11_ignored );
653   }
654
655   return ( pnd_pxml_x11_ignored ); // default
656 }
657
658 char *pnd_pxml_get_info_name ( pnd_pxml_handle h ) {
659   pnd_pxml_t *p = (pnd_pxml_t*) h;
660   return ( p -> info_name );
661 }
662
663 char *pnd_pxml_get_info_type ( pnd_pxml_handle h ) {
664   pnd_pxml_t *p = (pnd_pxml_t*) h;
665   return ( p -> info_type );
666 }
667
668 char *pnd_pxml_get_info_src ( pnd_pxml_handle h ) {
669   pnd_pxml_t *p = (pnd_pxml_t*) h;
670   return ( p -> info_filename );
671 }