1 /*****************************************************************************
2 * simple.c - The OSD Menu simple parser code.
3 *****************************************************************************
4 * Copyright (C) 2005-2008 M2X
7 * Authors: Jean-Paul Saman
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
34 #include <vlc_common.h>
36 #include <vlc_config.h>
39 #include <vlc_image.h>
41 #include <vlc_charset.h>
47 int osd_parser_simpleOpen( vlc_object_t *p_this );
49 /*****************************************************************************
50 * Simple parser open function
51 *****************************************************************************/
52 int osd_parser_simpleOpen( vlc_object_t *p_this )
54 osd_menu_t *p_menu = (osd_menu_t *) p_this;
55 osd_button_t *p_current = NULL; /* button currently processed */
56 osd_button_t *p_prev = NULL; /* previous processed button */
61 if( !p_menu ) return VLC_ENOOBJ;
63 msg_Dbg( p_this, "opening osdmenu definition file %s", p_menu->psz_file );
64 fd = utf8_fopen( p_menu->psz_file, "r" );
67 msg_Err( p_this, "failed to open osdmenu definition file %s",
77 char path[PATH_MAX] = "";
78 char *psz_path = NULL;
82 result = fscanf(fd, "%24s %255s", &action[0], &path[0] );
84 /* override images path ? */
85 psz_path = config_GetPsz( p_this, "osdmenu-file-path" );
88 /* psz_path is not null and therefor &path[0] cannot be NULL
89 * it might be null terminated.
91 strncpy( &path[0], psz_path, PATH_MAX );
95 /* NULL terminate before asking the length of path[] */
96 path[PATH_MAX-1] = '\0';
97 i_len = strlen(&path[0]);
98 if( i_len == PATH_MAX )
99 i_len--; /* truncate to prevent buffer overflow */
100 #if defined(WIN32) || defined(UNDER_CE)
101 if( (i_len > 0) && path[i_len] != '\\' )
104 if( (i_len > 0) && path[i_len] != '/' )
107 path[i_len+1] = '\0';
108 if( result == 0 || result == EOF )
110 msg_Dbg( p_this, "osdmenu dir %s", &path[0] );
113 p_menu = osd_MenuNew( p_menu, NULL, 0, 0 );
115 p_menu = osd_MenuNew( p_menu, &path[0], 0, 0 );
117 /* Peek for 'style' argument */
122 result = fscanf(fd, "%24s %24s", &cmd[0], &action[0] );
123 if( result == 0 || result == EOF )
126 msg_Dbg( p_this, "osdmenu %s %s", &cmd[0], &action[0] );
127 if( strncmp( &cmd[0], "style", 5 ) == 0 )
129 if( strncmp( &action[0], "default", 7) == 0 )
131 p_menu->i_style = OSD_MENU_STYLE_SIMPLE;
133 else if( strncmp( &action[0], "concat", 6) == 0 )
135 p_menu->i_style = OSD_MENU_STYLE_CONCAT;
140 result = fseek( fd, pos, SEEK_SET );
149 /* read successive lines */
152 osd_state_t *p_state_current = NULL; /* button state currently processed */
153 osd_state_t *p_state_prev = NULL; /* previous state processed button */
156 char action[25] = "";
159 char path[PATH_MAX] = "";
163 result = fscanf( fd, "%24s %24s (%d,%d)", &cmd[0], &action[0], &i_x, &i_y );
166 if( strncmp( &cmd[0], "action", 6 ) != 0 )
168 msg_Dbg( p_this, " + %s hotkey=%s (%d,%d)", &cmd[0], &action[0], i_x, i_y );
171 p_current = osd_ButtonNew( &action[0], i_x, i_y );
176 p_prev->p_next = p_current;
178 p_menu->p_button = p_current;
179 p_current->p_prev = p_prev;
181 /* parse all states */
186 result = fscanf( fd, "\t%24s", &state[0] );
190 /* FIXME: We only parse one level deep now */
191 if( strncmp( &state[0], "action", 6 ) == 0 )
193 osd_button_t *p_up = NULL;
195 result = fscanf( fd, "%24s (%d,%d)", &action[0], &i_x, &i_y );
198 /* create new button */
199 p_up = osd_ButtonNew( &action[0], i_x, i_y );
203 p_up->p_down = p_current;
204 p_current->p_up = p_up;
205 msg_Dbg( p_this, " + (menu up) hotkey=%s (%d,%d)", &action[0], i_x, i_y );
206 /* Parse type state */
207 result = fscanf( fd, "\t%24s %24s", &cmd[0], &type[0] );
210 if( strncmp( &cmd[0], "type", 4 ) == 0 )
212 if( strncmp( &type[0], "volume", 6 ) == 0 )
214 p_menu->p_state->p_volume = p_up;
215 msg_Dbg( p_this, " + type=%s", &type[0] );
218 /* Parse range state */
219 result = fscanf( fd, "\t%24s", &state[0] );
222 /* Parse the range state */
223 if( strncmp( &state[0], "range", 5 ) == 0 )
225 osd_state_t *p_range_current = NULL; /* range state currently processed */
226 osd_state_t *p_range_prev = NULL; /* previous state processed range */
229 p_up->b_range = true;
231 result = fscanf( fd, "\t%24s", &action[0] );
235 result = fscanf( fd, "\t%d", &i_index );
239 msg_Dbg( p_this, " + (menu up) hotkey down %s, file=%s%s",
240 &action[0], p_menu->psz_path, &file[0] );
242 free( p_up->psz_action_down );
243 p_up->psz_action_down = strdup( &action[0] );
245 /* Parse range contstruction :
254 result = fscanf( fd, "\t%255s", &file[0] );
257 if( strncmp( &file[0], "end", 3 ) == 0 )
260 p_range_prev = p_range_current;
262 if( p_menu->psz_path )
264 size_t i_path_size = strlen( p_menu->psz_path );
265 size_t i_file_size = strlen( &file[0] );
267 if( (i_path_size + i_file_size >= PATH_MAX) ||
268 (i_path_size >= PATH_MAX) )
271 strncpy( &path[0], p_menu->psz_path, i_path_size );
272 strncpy( &path[i_path_size], &file[0],
273 PATH_MAX - (i_path_size + i_file_size) );
274 path[ i_path_size + i_file_size ] = '\0';
276 p_range_current = osd_StateNew( p_menu, &path[0], "pressed" );
278 else /* absolute paths are used. */
279 p_range_current = osd_StateNew( p_menu, &file[0], "pressed" );
281 if( !p_range_current )
284 if( !p_range_current->p_pic )
286 osd_StatesFree( p_menu, p_range_current );
290 p_range_current->i_x = i_x;
291 p_range_current->i_y = i_y;
293 /* increment the number of ranges for this button */
297 p_range_prev->p_next = p_range_current;
299 p_up->p_states = p_range_current;
300 p_range_current->p_prev = p_range_prev;
302 msg_Dbg( p_this, " |- range=%d, file=%s%s",
304 p_menu->psz_path, &file[0] );
308 osd_state_t *p_range = NULL;
310 /* Find the default index for state range */
311 p_range = p_up->p_states;
312 while( (--i_index > 0) && p_range->p_next )
314 osd_state_t *p_temp = NULL;
315 p_temp = p_range->p_next;
318 p_up->p_current_state = p_range;
320 else p_up->p_current_state = p_up->p_states;
323 result = fscanf( fd, "\t%24s", &state[0] );
326 if( strncmp( &state[0], "end", 3 ) != 0 )
329 /* Continue at the beginning of the while() */
333 /* Parse the range state */
334 if( strncmp( &state[0], "range", 5 ) == 0 )
336 osd_state_t *p_range_current = NULL; /* range state currently processed */
337 osd_state_t *p_range_prev = NULL; /* previous state processed range */
340 p_current->b_range = true;
342 result = fscanf( fd, "\t%24s", &action[0] );
346 result = fscanf( fd, "\t%d", &i_index );
350 msg_Dbg( p_this, " + hotkey down %s, file=%s%s",
351 &action[0], p_menu->psz_path, &file[0] );
352 free( p_current->psz_action_down );
353 p_current->psz_action_down = strdup( &action[0] );
355 /* Parse range contstruction :
364 result = fscanf( fd, "\t%255s", &file[0] );
367 if( strncmp( &file[0], "end", 3 ) == 0 )
370 p_range_prev = p_range_current;
372 if( p_menu->psz_path )
374 size_t i_path_size = strlen( p_menu->psz_path );
375 size_t i_file_size = strlen( &file[0] );
377 if( (i_path_size + i_file_size >= PATH_MAX) ||
378 (i_path_size >= PATH_MAX) )
381 strncpy( &path[0], p_menu->psz_path, i_path_size );
382 strncpy( &path[i_path_size], &file[0],
383 PATH_MAX - (i_path_size + i_file_size) );
384 path[ i_path_size + i_file_size ] = '\0';
386 p_range_current = osd_StateNew( p_menu, &path[0], "pressed" );
388 else /* absolute paths are used. */
389 p_range_current = osd_StateNew( p_menu, &file[0], "pressed" );
391 if( !p_range_current )
394 if( !p_range_current->p_pic )
396 osd_StatesFree( p_menu, p_range_current );
400 p_range_current->i_x = i_x;
401 p_range_current->i_y = i_y;
403 /* increment the number of ranges for this button */
404 p_current->i_ranges++;
407 p_range_prev->p_next = p_range_current;
409 p_current->p_states = p_range_current;
410 p_range_current->p_prev = p_range_prev;
412 msg_Dbg( p_this, " |- range=%d, file=%s%s",
414 p_menu->psz_path, &file[0] );
418 osd_state_t *p_range = NULL;
420 /* Find the default index for state range */
421 p_range = p_current->p_states;
422 while( (--i_index > 0) && p_range->p_next )
424 osd_state_t *p_temp = NULL;
425 p_temp = p_range->p_next;
428 p_current->p_current_state = p_range;
430 else p_current->p_current_state = p_current->p_states;
431 /* Continue at the beginning of the while() */
434 if( strncmp( &state[0], "end", 3 ) == 0 )
437 result = fscanf( fd, "\t%255s", &file[0] );
441 p_state_prev = p_state_current;
443 if( ( strncmp( ppsz_button_states[0], &state[0], strlen(ppsz_button_states[0]) ) != 0 ) &&
444 ( strncmp( ppsz_button_states[1], &state[0], strlen(ppsz_button_states[1]) ) != 0 ) &&
445 ( strncmp( ppsz_button_states[2], &state[0], strlen(ppsz_button_states[2]) ) != 0 ) )
447 msg_Err( p_this, "invalid button state %s for button %s "
448 "expected %u: unselect, select or pressed)",
449 &state[0], &action[0], (unsigned)strlen(&state[0]));
453 if( p_menu->psz_path )
455 size_t i_path_size = strlen( p_menu->psz_path );
456 size_t i_file_size = strlen( &file[0] );
458 if( (i_path_size + i_file_size >= PATH_MAX) ||
459 (i_path_size >= PATH_MAX) )
462 strncpy( &path[0], p_menu->psz_path, i_path_size );
463 strncpy( &path[i_path_size], &file[0],
464 PATH_MAX - (i_path_size + i_file_size) );
465 path[ i_path_size + i_file_size ] = '\0';
467 p_state_current = osd_StateNew( p_menu, &path[0], &state[0] );
469 else /* absolute paths are used. */
470 p_state_current = osd_StateNew( p_menu, &file[0], &state[0] );
472 if( !p_state_current )
475 if( !p_state_current->p_pic )
477 osd_StatesFree( p_menu, p_state_current );
481 p_state_current->i_x = i_x;
482 p_state_current->i_y = i_y;
485 p_state_prev->p_next = p_state_current;
487 p_current->p_states = p_state_current;
488 p_state_current->p_prev = p_state_prev;
490 msg_Dbg( p_this, " |- state=%s, file=%s%s", &state[0],
491 p_menu->psz_path, &file[0] );
493 p_current->p_current_state = p_current->p_states;
496 /* Find the last button and store its pointer.
497 * The OSD menu behaves like a roundrobin list.
499 p_current = p_menu->p_button;
500 while( p_current && p_current->p_next )
502 osd_button_t *p_temp = NULL;
503 p_temp = p_current->p_next;
506 p_menu->p_last_button = p_current;
511 msg_Err( p_menu, "parsing file failed (returned %d)", result );
512 osd_MenuFree( p_menu );