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