]> git.sesse.net Git - vlc/blob - src/osd/osd_parser.c
All CRLF fixes
[vlc] / src / osd / osd_parser.c
1 /*****************************************************************************
2  * osd_parser.c - The OSD Menu  parser core code.
3  *****************************************************************************
4  * Copyright (C) 2005 M2X
5  * $Id$
6  *
7  * Authors: Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc_config.h>
32 #include <vlc_video.h>
33
34 #include <vlc_keys.h>
35 #include <vlc_image.h>
36 #include <vlc_osd.h>
37
38
39 #undef OSD_MENU_DEBUG
40
41 /*****************************************************************************
42  * Local prototypes
43  *****************************************************************************/
44 static const char *ppsz_button_states[] = { "unselect", "select", "pressed" };
45
46 /* OSD Menu structure support routines */
47 static osd_menu_t   *osd_MenuNew( osd_menu_t *, const char *, int, int );
48 static osd_button_t *osd_ButtonNew( const char *, int, int );
49 static osd_state_t  *osd_StateNew( vlc_object_t *, const char *, const char * );
50
51 static void osd_MenuFree  ( vlc_object_t *, osd_menu_t * );
52 static void osd_ButtonFree( vlc_object_t *, osd_button_t * );
53 static void osd_StatesFree( vlc_object_t *, osd_state_t * );
54
55 static picture_t *osd_LoadImage( vlc_object_t *, const char *);
56
57 /*****************************************************************************
58  * osd_LoadImage: loads the logo image into memory
59  *****************************************************************************/
60 static picture_t *osd_LoadImage( vlc_object_t *p_this, const char *psz_filename )
61 {
62     picture_t *p_pic = NULL;
63     image_handler_t *p_image;
64     video_format_t fmt_in = {0}, fmt_out = {0};
65
66     fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
67     p_image = image_HandlerCreate( p_this );
68     if( p_image )
69     {
70         p_pic = image_ReadUrl( p_image, psz_filename, &fmt_in, &fmt_out );
71         image_HandlerDelete( p_image );
72 #if 0        
73         p_pic = osd_YuvaYuvp( p_this, p_pic );
74 #endif
75     }
76     else msg_Err( p_this, "unable to handle this chroma" );
77
78     return p_pic;
79 }
80
81 /*****************************************************************************
82  * Create a new Menu structure
83  *****************************************************************************/
84 static osd_menu_t *osd_MenuNew( osd_menu_t *p_menu, const char *psz_path, int i_x, int i_y )
85 {
86     if( !p_menu ) return NULL;
87     
88     p_menu->p_state = (osd_menu_state_t *) malloc( sizeof( osd_menu_state_t ) );
89     if( !p_menu->p_state )
90         msg_Err( p_menu, "memory allocation for OSD Menu state failed." );
91
92     if( psz_path != NULL )
93         p_menu->psz_path = strdup( psz_path );
94     else
95         p_menu->psz_path = NULL;
96     p_menu->i_x = i_x;
97     p_menu->i_y = i_y;
98     
99     return p_menu; 
100 }
101
102 /*****************************************************************************
103  * Free the menu
104  *****************************************************************************/
105 static void osd_MenuFree( vlc_object_t *p_this, osd_menu_t *p_menu )
106 {
107     msg_Dbg( p_this, "freeing menu" );
108     osd_ButtonFree( p_this, p_menu->p_button );
109     p_menu->p_button = NULL;
110     p_menu->p_last_button = NULL;
111     if( p_menu->psz_path ) free( p_menu->psz_path );
112     p_menu->psz_path = NULL;
113     if( p_menu->p_state ) free( p_menu->p_state );
114     p_menu->p_state = NULL;
115 }
116
117 /*****************************************************************************
118  * Create a new button
119  *****************************************************************************/
120 static osd_button_t *osd_ButtonNew( const char *psz_action, int i_x, int i_y )
121 {
122     osd_button_t *p_button = NULL;
123     p_button = (osd_button_t*) malloc( sizeof(osd_button_t) );
124     if( !p_button )
125         return NULL;
126     
127     memset( p_button, 0, sizeof(osd_button_t) );
128     p_button->psz_action = strdup(psz_action);
129     p_button->psz_action_down = NULL;
130     p_button->p_feedback = NULL;
131     p_button->i_x = i_x;
132     p_button->i_y = i_y;
133     
134     return p_button;
135 }
136
137 /*****************************************************************************
138  * Free a button
139  *****************************************************************************/ 
140 static void osd_ButtonFree( vlc_object_t *p_this, osd_button_t *p_button )
141 {
142     osd_button_t *p_current = p_button;
143     osd_button_t *p_next = NULL;
144     osd_button_t *p_prev = NULL;
145     
146     /* First walk to the end. */
147     while( p_current->p_next )
148     {
149         p_next = p_current->p_next;
150         p_current = p_next;        
151     }
152     /* Then free end first and walk to the start. */
153     while( p_current->p_prev )
154     {
155         msg_Dbg( p_this, "+ freeing button %s [%p]", p_current->psz_action, p_current );
156         p_prev = p_current->p_prev;
157         p_current = p_prev;
158         if( p_current->p_next )
159         {
160             if( p_current->p_next->psz_name ) 
161                 free( p_current->p_next->psz_name );
162             if( p_current->p_next->psz_action )
163                 free( p_current->p_next->psz_action );
164             if( p_current->p_next->psz_action_down )
165                 free( p_current->p_next->psz_action_down );
166             if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
167                 free( p_current->p_feedback->p_data_orig );
168             if( p_current->p_feedback )
169                 free( p_current->p_feedback );
170             
171             p_current->p_next->psz_action_down = NULL;
172             p_current->p_next->psz_action = NULL;
173             p_current->p_next->psz_name = NULL;
174             p_current->p_feedback = NULL;
175                             
176             /* Free all states first */            
177             if( p_current->p_next->p_states )   
178                 osd_StatesFree( p_this, p_current->p_next->p_states );
179             p_current->p_next->p_states = NULL;          
180             if( p_current->p_next) free( p_current->p_next );
181             p_current->p_next = NULL;  
182         }            
183         
184         if( p_current->p_up )
185         {
186             if( p_current->p_up->psz_name ) 
187                 free( p_current->p_up->psz_name );
188             if( p_current->p_up->psz_action )
189                 free( p_current->p_up->psz_action );
190             if( p_current->p_up->psz_action_down )
191                 free( p_current->p_up->psz_action_down );
192             if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
193                 free( p_current->p_feedback->p_data_orig );
194             if( p_current->p_feedback )
195                 free( p_current->p_feedback );
196             
197             p_current->p_up->psz_action_down = NULL;
198             p_current->p_up->psz_action = NULL;
199             p_current->p_up->psz_name = NULL;
200             p_current->p_feedback = NULL;
201             
202             /* Free all states first */            
203             if( p_current->p_up->p_states )   
204                 osd_StatesFree( p_this, p_current->p_up->p_states );
205             p_current->p_up->p_states = NULL;          
206             if( p_current->p_up ) free( p_current->p_up );
207             p_current->p_up = NULL;          
208         }
209     }    
210     /* Free the last one. */
211     if( p_button ) 
212     {
213         msg_Dbg( p_this, "+ freeing button %s [%p]", p_button->psz_action, p_button );    
214         if( p_button->psz_name ) free( p_button->psz_name );
215         if( p_button->psz_action ) free( p_button->psz_action );
216         if( p_button->psz_action_down ) free( p_button->psz_action_down );   
217         if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
218             free( p_current->p_feedback->p_data_orig );
219         if( p_current->p_feedback )
220             free( p_current->p_feedback );
221         
222         p_button->psz_name = NULL;
223         p_button->psz_action = NULL;
224         p_button->psz_action_down = NULL;
225         p_current->p_feedback = NULL;
226                 
227         if( p_button->p_states )
228             osd_StatesFree( p_this, p_button->p_states );
229         p_button->p_states = NULL;          
230         free( p_button );
231         p_button = NULL;
232     }
233 }
234
235 /*****************************************************************************
236  * Create a new state image
237  *****************************************************************************/
238 static osd_state_t *osd_StateNew( vlc_object_t *p_this, const char *psz_file, const char *psz_state )
239 {
240     osd_state_t *p_state = NULL;
241     p_state = (osd_state_t*) malloc( sizeof(osd_state_t) );
242     if( !p_state )
243         return NULL;
244         
245     memset( p_state, 0, sizeof(osd_state_t) );    
246     p_state->p_pic = osd_LoadImage( p_this, psz_file );
247
248     if( psz_state )
249     {
250         p_state->psz_state = strdup( psz_state );
251         if( strncmp( ppsz_button_states[0], psz_state, strlen(ppsz_button_states[0]) ) == 0 )
252             p_state->i_state = OSD_BUTTON_UNSELECT;
253         else if( strncmp( ppsz_button_states[1], psz_state, strlen(ppsz_button_states[1]) ) == 0 )
254             p_state->i_state = OSD_BUTTON_SELECT;
255         else if( strncmp( ppsz_button_states[2], psz_state, strlen(ppsz_button_states[2]) ) == 0 )
256             p_state->i_state = OSD_BUTTON_PRESSED;
257     }
258     return p_state;
259 }
260
261 /*****************************************************************************
262  * Free state images
263  *****************************************************************************/
264 static void osd_StatesFree( vlc_object_t *p_this, osd_state_t *p_states )
265 {
266     osd_state_t *p_state = p_states;
267     osd_state_t *p_next = NULL;
268     osd_state_t *p_prev = NULL;
269     
270     while( p_state->p_next )
271     {
272         p_next = p_state->p_next;
273         p_state = p_next;
274     }
275     /* Then free end first and walk to the start. */
276     while( p_state->p_prev )
277     {
278         msg_Dbg( p_this, " |- freeing state %s [%p]", p_state->psz_state, p_state );
279         p_prev = p_state->p_prev;
280         p_state = p_prev;
281         if( p_state->p_next )
282         {
283             if( p_state->p_next->p_pic && p_state->p_next->p_pic->p_data_orig )
284                 free( p_state->p_next->p_pic->p_data_orig );
285             if( p_state->p_next->p_pic ) free( p_state->p_next->p_pic );
286             p_state->p_next->p_pic = NULL;      
287             if( p_state->p_next->psz_state ) free( p_state->p_next->psz_state );
288             p_state->p_next->psz_state = NULL;
289             free( p_state->p_next );
290             p_state->p_next = NULL;        
291         }
292     }
293     /* Free the last one. */
294     if( p_states )
295     {
296         msg_Dbg( p_this, " |- freeing state %s [%p]", p_state->psz_state, p_states );
297         if( p_states->p_pic && p_states->p_pic->p_data_orig )
298             free( p_states->p_pic->p_data_orig );
299         if( p_states->p_pic ) free( p_states->p_pic );
300         p_states->p_pic = NULL;
301         if( p_state->psz_state ) free( p_state->psz_state );
302         p_state->psz_state = NULL;
303         free( p_states );
304         p_states = NULL;
305     }
306 }
307
308 /*****************************************************************************
309  * osd_ConfigLoader: Load and parse osd text configurationfile
310  *****************************************************************************/
311 int osd_ConfigLoader( vlc_object_t *p_this, const char *psz_file,
312     osd_menu_t **p_menu )
313 {
314     osd_button_t   *p_current = NULL; /* button currently processed */
315     osd_button_t   *p_prev = NULL;    /* previous processed button */ 
316
317 #define MAX_FILE_PATH 256    
318     FILE       *fd = NULL;
319     int        result = 0;
320     
321     msg_Dbg( p_this, "opening osd definition file %s", psz_file );
322     fd = fopen( psz_file, "r" );
323     if( !fd )  
324     {
325         msg_Err( p_this, "failed opening osd definition file %s", psz_file );
326         return VLC_EGENERIC;
327     }
328     
329     /* Read first line */    
330     if( !feof( fd ) )
331     {
332         char action[25] = "";
333         char path[MAX_FILE_PATH] = "";
334         char *psz_path = NULL;
335         size_t i_len = 0;
336
337         /* override images path ? */
338         psz_path = config_GetPsz( p_this, "osdmenu-file-path" );
339         if( psz_path == NULL )
340         {                                    
341             result = fscanf(fd, "%24s %255s", &action[0], &path[0] );
342         }
343         else
344         {
345             /* psz_path is not null and therefor &path[0] cannot be NULL 
346              * it might be null terminated.
347              */
348             strncpy( &path[0], psz_path, MAX_FILE_PATH );
349             free( psz_path );
350             psz_path = NULL;
351         }
352         /* NULL terminate before asking the length of path[] */
353         path[MAX_FILE_PATH-1] = '\0';
354         i_len = strlen(&path[0]);
355         if( i_len == MAX_FILE_PATH )
356             i_len--; /* truncate to prevent buffer overflow */
357 #if defined(WIN32) || defined(UNDER_CE)
358         if( (i_len > 0) && path[i_len] != '\\' )
359             path[i_len] = '\\';
360 #else        
361         if( (i_len > 0) && path[i_len] != '/' )
362             path[i_len] = '/';
363 #endif
364         path[i_len+1] = '\0';
365         if( result == 0 || result == EOF )
366             goto error;                        
367         msg_Dbg( p_this, "%s=%s", &action[0], &path[0] );
368          
369         if( i_len == 0 )
370             *p_menu = osd_MenuNew( *p_menu, NULL, 0, 0 );
371         else
372             *p_menu = osd_MenuNew( *p_menu, &path[0], 0, 0 );
373     }
374     
375     if( !*p_menu )
376         goto error;
377         
378     /* read successive lines */
379     while( !feof( fd ) )
380     {   
381         osd_state_t   *p_state_current = NULL; /* button state currently processed */
382         osd_state_t   *p_state_prev = NULL;    /* previous state processed button */ 
383         
384         char cmd[25] = "";      
385         char action[25] = "";
386         char state[25]  = "";
387         char file[256]  = "";
388         char path[512]  = "";        
389         int  i_x = 0;
390         int  i_y = 0;
391
392         result = fscanf( fd, "%24s %24s (%d,%d)", &cmd[0], &action[0], &i_x, &i_y );
393         if( result == 0 )
394             goto error;              
395         if( strncmp( &cmd[0], "action", 6 ) != 0 )
396             break;
397         msg_Dbg( p_this, " + %s hotkey=%s (%d,%d)", &cmd[0], &action[0], i_x, i_y );                    
398                 
399         p_prev = p_current;
400         p_current = osd_ButtonNew( &action[0], i_x, i_y );   
401         if( !p_current )
402             goto error;
403         
404         if( p_prev )
405             p_prev->p_next = p_current;            
406         else
407             (*p_menu)->p_button = p_current;            
408         p_current->p_prev = p_prev;
409         
410         /* parse all states */
411         while( !feof( fd ) )
412         {
413             char type[25] = "";
414             
415             result = fscanf( fd, "\t%24s", &state[0] );   
416             if( result == 0 )
417                 goto error;
418             
419             /* FIXME: We only parse one level deep now */    
420             if( strncmp( &state[0], "action", 6 ) == 0 )
421             {
422                 osd_button_t   *p_up = NULL;
423                 
424                 result = fscanf( fd, "%24s (%d,%d)", &action[0], &i_x, &i_y );
425                 if( result == 0 )
426                     goto error;
427                 /* create new button */                
428                 p_up = osd_ButtonNew( &action[0], i_x, i_y );                 
429                 if( !p_up ) 
430                     goto error;
431                 /* Link to list */                    
432                 p_up->p_down = p_current;
433                 p_current->p_up = p_up;                 
434                 msg_Dbg( p_this, " + (menu up) hotkey=%s (%d,%d)", &action[0], i_x, i_y );
435                 /* Parse type state */
436                 result = fscanf( fd, "\t%24s %24s", &cmd[0], &type[0] );   
437                 if( result == 0 )
438                     goto error;
439                 if( strncmp( &cmd[0], "type", 4 ) == 0 )
440                 {  
441                     if( strncmp( &type[0], "volume", 6 ) == 0 )
442                     {
443                         (*p_menu)->p_state->p_volume = p_up;
444                         msg_Dbg( p_this, " + type=%s", &type[0] );
445                     }
446                 }
447                 /* Parse range state */
448                 result = fscanf( fd, "\t%24s", &state[0] );   
449                 if( result == 0 )
450                     goto error;
451                 /* Parse the range state */        
452                 if( strncmp( &state[0], "range", 5 ) == 0 )
453                 {
454                     osd_state_t   *p_range_current = NULL; /* range state currently processed */
455                     osd_state_t   *p_range_prev = NULL;    /* previous state processed range */ 
456                     int i_index = 0;
457                                                             
458                     p_up->b_range = VLC_TRUE;
459     
460                     result = fscanf( fd, "\t%24s", &action[0] );   
461                     if( result == 0 )
462                         goto error;
463                     
464                     result = fscanf( fd, "\t%d", &i_index );   
465                     if( result == 0 )
466                         goto error;
467                                                                                             
468                     msg_Dbg( p_this, " + (menu up) hotkey down %s, file=%s%s", &action[0], (*p_menu)->psz_path, &file[0] );
469                     
470                     if( p_up->psz_action_down ) free( p_up->psz_action_down );
471                     p_up->psz_action_down = strdup( &action[0] );                     
472                     
473                     /* Parse range contstruction :
474                      * range <hotkey> 
475                      *      <state1> <file1>
476                      *
477                      *      <stateN> <fileN>
478                      * end 
479                      */                
480                     while( !feof( fd ) )
481                     {
482                         result = fscanf( fd, "\t%255s", &file[0] );   
483                         if( result == 0 )
484                             goto error;
485                         if( strncmp( &file[0], "end", 3 ) == 0 )
486                             break;
487                         
488                         p_range_prev = p_range_current;
489             
490                         if( (*p_menu)->psz_path )
491                         {
492                             size_t i_path_size = strlen( (*p_menu)->psz_path );
493                             size_t i_file_size = strlen( &file[0] );
494                             
495                             strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
496                             strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
497                             path[ i_path_size + i_file_size ] = '\0';
498                             
499                             p_range_current = osd_StateNew( p_this, &path[0], "pressed" );
500                         }
501                         else /* absolute paths are used. */
502                             p_range_current = osd_StateNew( p_this, &file[0], "pressed" );
503                             
504                         if( !p_range_current || !p_range_current->p_pic )
505                             goto error;
506                             
507                         /* increment the number of ranges for this button */                
508                         p_up->i_ranges++;
509                         
510                         if( p_range_prev )
511                             p_range_prev->p_next = p_range_current;
512                         else
513                             p_up->p_states = p_range_current;                                
514                         p_range_current->p_prev = p_range_prev;
515                         
516                         msg_Dbg( p_this, "  |- range=%d, file=%s%s", 
517                                 p_up->i_ranges, 
518                                 (*p_menu)->psz_path, &file[0] );                        
519                     }
520                     if( i_index > 0 )
521                     { 
522                         osd_state_t *p_range = NULL;
523                         
524                         /* Find the default index for state range */                        
525                         p_range = p_up->p_states;
526                         while( (--i_index > 0) && p_range->p_next )
527                         {
528                             osd_state_t *p_temp = NULL;
529                             p_temp = p_range->p_next;
530                             p_range = p_temp;
531                         }
532                         p_up->p_current_state = p_range;
533                     }                    
534                     else p_up->p_current_state = p_up->p_states;
535                     
536                 }   
537                 result = fscanf( fd, "\t%24s", &state[0] );   
538                 if( result == 0 )
539                     goto error;                    
540                 if( strncmp( &state[0], "end", 3 ) != 0 )
541                     goto error;
542                     
543                 /* Continue at the beginning of the while() */
544                 continue;
545             }
546             
547             /* Parse the range state */        
548             if( strncmp( &state[0], "range", 5 ) == 0 )
549             {
550                 osd_state_t   *p_range_current = NULL; /* range state currently processed */
551                 osd_state_t   *p_range_prev = NULL;    /* previous state processed range */ 
552                 int i_index = 0;
553                                                         
554                 p_current->b_range = VLC_TRUE;
555
556                 result = fscanf( fd, "\t%24s", &action[0] );   
557                 if( result == 0 )
558                     goto error;
559                 
560                 result = fscanf( fd, "\t%d", &i_index );   
561                 if( result == 0 )
562                     goto error;
563                                                                                         
564                 msg_Dbg( p_this, " + hotkey down %s, file=%s%s", &action[0], (*p_menu)->psz_path, &file[0] );                        
565                 if( p_current->psz_action_down ) free( p_current->psz_action_down );
566                 p_current->psz_action_down = strdup( &action[0] );                     
567                 
568                 /* Parse range contstruction :
569                  * range <hotkey> 
570                  *      <state1> <file1>
571                  *
572                  *      <stateN> <fileN>
573                  * end 
574                  */                
575                 while( !feof( fd ) )
576                 {
577                     result = fscanf( fd, "\t%255s", &file[0] );   
578                     if( result == 0 )
579                         goto error;
580                     if( strncmp( &file[0], "end", 3 ) == 0 )
581                         break;
582                     
583                     p_range_prev = p_range_current;
584         
585                     if( (*p_menu)->psz_path )
586                     {
587                         size_t i_path_size = strlen( (*p_menu)->psz_path );
588                         size_t i_file_size = strlen( &file[0] );
589                         
590                         strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
591                         strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
592                         path[ i_path_size + i_file_size ] = '\0';
593                         
594                         p_range_current = osd_StateNew( p_this, &path[0], "pressed" );
595                     }
596                     else /* absolute paths are used. */
597                         p_range_current = osd_StateNew( p_this, &file[0], "pressed" );
598                         
599                     if( !p_range_current || !p_range_current->p_pic )
600                         goto error;
601                         
602                     /* increment the number of ranges for this button */                
603                     p_current->i_ranges++;
604                     
605                     if( p_range_prev )
606                         p_range_prev->p_next = p_range_current;
607                     else
608                         p_current->p_states = p_range_current;                                
609                     p_range_current->p_prev = p_range_prev;
610                     
611                     msg_Dbg( p_this, "  |- range=%d, file=%s%s", 
612                             p_current->i_ranges, 
613                             (*p_menu)->psz_path, &file[0] );                        
614                 }
615                 if( i_index > 0 )
616                 {             
617                     osd_state_t *p_range = NULL;
618                        
619                     /* Find the default index for state range */                        
620                     p_range = p_current->p_states;
621                     while( (--i_index > 0) && p_range->p_next )
622                     {
623                         osd_state_t *p_temp = NULL;
624                         p_temp = p_range->p_next;
625                         p_range = p_temp;
626                     }
627                     p_current->p_current_state = p_range;
628                 }                    
629                 else p_current->p_current_state = p_current->p_states;
630                 /* Continue at the beginning of the while() */
631                 continue;
632             }   
633             if( strncmp( &state[0], "end", 3 ) == 0 )
634                 break;
635                 
636             result = fscanf( fd, "\t%255s", &file[0] );   
637             if( result == 0 )
638                 goto error;                                
639             
640             p_state_prev = p_state_current;
641
642             if( ( strncmp( ppsz_button_states[0], &state[0], strlen(ppsz_button_states[0]) ) != 0 ) &&
643                 ( strncmp( ppsz_button_states[1], &state[0], strlen(ppsz_button_states[1]) ) != 0 ) &&
644                 ( strncmp( ppsz_button_states[2], &state[0], strlen(ppsz_button_states[2]) ) != 0 ) )
645             {
646                 msg_Err( p_this, "invalid button state %s for button %s expected %d: unselect, select or pressed)",
647                                     &state[0], &action[0], strlen(&state[0]));
648                 goto error;
649             }
650             
651             if( (*p_menu)->psz_path )
652             {
653                 size_t i_path_size = strlen( (*p_menu)->psz_path );
654                 size_t i_file_size = strlen( &file[0] );
655                 
656                 strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
657                 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
658                 path[ i_path_size + i_file_size ] = '\0';
659                 
660                 p_state_current = osd_StateNew( p_this, &path[0], &state[0] );
661             }
662             else /* absolute paths are used. */
663                 p_state_current = osd_StateNew( p_this, &file[0], &state[0] );
664                 
665             if( !p_state_current || !p_state_current->p_pic )
666                 goto error;
667                 
668             if( p_state_prev )
669                 p_state_prev->p_next = p_state_current;
670             else
671                 p_current->p_states = p_state_current;                                
672             p_state_current->p_prev = p_state_prev;
673             
674             msg_Dbg( p_this, " |- state=%s, file=%s%s", &state[0], (*p_menu)->psz_path, &file[0] );
675         }
676         p_current->p_current_state = p_current->p_states;
677     }
678
679     /* Find the last button and store its pointer. 
680      * The OSD menu behaves like a roundrobin list.
681      */        
682     p_current = (*p_menu)->p_button;
683     while( p_current && p_current->p_next )
684     {
685         osd_button_t *p_temp = NULL;
686         p_temp = p_current->p_next;
687         p_current = p_temp;
688     }
689     (*p_menu)->p_last_button = p_current;
690     fclose( fd );
691     return 0;
692     
693 #undef MAX_FILE_PATH 
694 error:
695     msg_Err( p_this, "parsing file failed (returned %d)", result );
696     fclose( fd );
697     return 1;        
698 }
699
700 /*****************************************************************************
701  * osd_ConfigUnload: Load and parse osd text configurationfile
702  *****************************************************************************/
703 void osd_ConfigUnload( vlc_object_t *p_this, osd_menu_t **p_osd)
704 {
705     msg_Dbg( p_this, "unloading OSD menu structure" );
706     osd_MenuFree( p_this, *p_osd );
707 }