1 /*****************************************************************************
2 * simple.c - The OSD Menu simple parser code.
3 *****************************************************************************
4 * Copyright (C) 2005-2007 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 *****************************************************************************/
30 #include <vlc_config.h>
33 #include <vlc_image.h>
35 #include <vlc_charset.h>
37 /*****************************************************************************
38 * osd_ConfigLoader: Load and parse osd text configurationfile
39 *****************************************************************************/
40 int E_(osd_parser_simpleOpen) ( vlc_object_t *p_this )
42 osd_menu_t *p_menu = (osd_menu_t *) p_this->p_menu;
43 osd_button_t *p_current = NULL; /* button currently processed */
44 osd_button_t *p_prev = NULL; /* previous processed button */
46 #define MAX_FILE_PATH 256
50 msg_Dbg( p_this, "opening osdmenu definition file %s", p_menu->psz_file );
51 fd = utf8_fopen( p_menu->psz_file, "r" );
54 msg_Err( p_this, "failed to open osdmenu definition file %s", p_menu->psz_file );
63 char path[MAX_FILE_PATH] = "";
64 char *psz_path = NULL;
68 result = fscanf(fd, "%24s %255s", &action[0], &path[0] );
70 /* override images path ? */
71 psz_path = config_GetPsz( p_this, "osdmenu-file-path" );
74 /* psz_path is not null and therefor &path[0] cannot be NULL
75 * it might be null terminated.
77 strncpy( &path[0], psz_path, MAX_FILE_PATH );
81 /* NULL terminate before asking the length of path[] */
82 path[MAX_FILE_PATH-1] = '\0';
83 i_len = strlen(&path[0]);
84 if( i_len == MAX_FILE_PATH )
85 i_len--; /* truncate to prevent buffer overflow */
86 #if defined(WIN32) || defined(UNDER_CE)
87 if( (i_len > 0) && path[i_len] != '\\' )
90 if( (i_len > 0) && path[i_len] != '/' )
94 if( result == 0 || result == EOF )
96 msg_Dbg( p_this, "osdmenu dir %s", &path[0] );
99 *p_menu = osd_MenuNew( *p_menu, NULL, 0, 0 );
101 *p_menu = osd_MenuNew( *p_menu, &path[0], 0, 0 );
103 /* Peek for 'style' argument */
108 result = fscanf(fd, "%24s %24s", &cmd[0], &action[0] );
109 if( result == 0 || result == EOF )
112 msg_Dbg( p_this, "osdmenu %s %s", &cmd[0], &action[0] );
113 if( strncmp( &cmd[0], "style", 5 ) == 0 )
115 if( strncmp( &action[0], "default", 7) == 0 )
117 (*p_menu)->i_style = OSD_MENU_STYLE_SIMPLE;
119 else if( strncmp( &action[0], "concat", 6) == 0 )
121 (*p_menu)->i_style = OSD_MENU_STYLE_CONCAT;
126 result = fseek( fd, pos, SEEK_SET );
135 /* read successive lines */
138 osd_state_t *p_state_current = NULL; /* button state currently processed */
139 osd_state_t *p_state_prev = NULL; /* previous state processed button */
142 char action[25] = "";
149 result = fscanf( fd, "%24s %24s (%d,%d)", &cmd[0], &action[0], &i_x, &i_y );
152 if( strncmp( &cmd[0], "action", 6 ) != 0 )
154 msg_Dbg( p_this, " + %s hotkey=%s (%d,%d)", &cmd[0], &action[0], i_x, i_y );
157 p_current = osd_ButtonNew( &action[0], i_x, i_y );
162 p_prev->p_next = p_current;
164 (*p_menu)->p_button = p_current;
165 p_current->p_prev = p_prev;
167 /* parse all states */
172 result = fscanf( fd, "\t%24s", &state[0] );
176 /* FIXME: We only parse one level deep now */
177 if( strncmp( &state[0], "action", 6 ) == 0 )
179 osd_button_t *p_up = NULL;
181 result = fscanf( fd, "%24s (%d,%d)", &action[0], &i_x, &i_y );
184 /* create new button */
185 p_up = osd_ButtonNew( &action[0], i_x, i_y );
189 p_up->p_down = p_current;
190 p_current->p_up = p_up;
191 msg_Dbg( p_this, " + (menu up) hotkey=%s (%d,%d)", &action[0], i_x, i_y );
192 /* Parse type state */
193 result = fscanf( fd, "\t%24s %24s", &cmd[0], &type[0] );
196 if( strncmp( &cmd[0], "type", 4 ) == 0 )
198 if( strncmp( &type[0], "volume", 6 ) == 0 )
200 (*p_menu)->p_state->p_volume = p_up;
201 msg_Dbg( p_this, " + type=%s", &type[0] );
204 /* Parse range state */
205 result = fscanf( fd, "\t%24s", &state[0] );
208 /* Parse the range state */
209 if( strncmp( &state[0], "range", 5 ) == 0 )
211 osd_state_t *p_range_current = NULL; /* range state currently processed */
212 osd_state_t *p_range_prev = NULL; /* previous state processed range */
215 p_up->b_range = VLC_TRUE;
217 result = fscanf( fd, "\t%24s", &action[0] );
221 result = fscanf( fd, "\t%d", &i_index );
225 msg_Dbg( p_this, " + (menu up) hotkey down %s, file=%s%s",
226 &action[0], (*p_menu)->psz_path, &file[0] );
228 if( p_up->psz_action_down ) free( p_up->psz_action_down );
229 p_up->psz_action_down = strdup( &action[0] );
231 /* Parse range contstruction :
240 result = fscanf( fd, "\t%255s", &file[0] );
243 if( strncmp( &file[0], "end", 3 ) == 0 )
246 p_range_prev = p_range_current;
248 if( (*p_menu)->psz_path )
250 size_t i_path_size = strlen( (*p_menu)->psz_path );
251 size_t i_file_size = strlen( &file[0] );
253 strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
254 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
255 path[ i_path_size + i_file_size ] = '\0';
257 p_range_current = osd_StateNew( p_this, &path[0], "pressed" );
259 else /* absolute paths are used. */
260 p_range_current = osd_StateNew( p_this, &file[0], "pressed" );
262 if( !p_range_current || !p_range_current->p_pic )
265 /* increment the number of ranges for this button */
269 p_range_prev->p_next = p_range_current;
271 p_up->p_states = p_range_current;
272 p_range_current->p_prev = p_range_prev;
274 msg_Dbg( p_this, " |- range=%d, file=%s%s",
276 (*p_menu)->psz_path, &file[0] );
280 osd_state_t *p_range = NULL;
282 /* Find the default index for state range */
283 p_range = p_up->p_states;
284 while( (--i_index > 0) && p_range->p_next )
286 osd_state_t *p_temp = NULL;
287 p_temp = p_range->p_next;
290 p_up->p_current_state = p_range;
292 else p_up->p_current_state = p_up->p_states;
295 result = fscanf( fd, "\t%24s", &state[0] );
298 if( strncmp( &state[0], "end", 3 ) != 0 )
301 /* Continue at the beginning of the while() */
305 /* Parse the range state */
306 if( strncmp( &state[0], "range", 5 ) == 0 )
308 osd_state_t *p_range_current = NULL; /* range state currently processed */
309 osd_state_t *p_range_prev = NULL; /* previous state processed range */
312 p_current->b_range = VLC_TRUE;
314 result = fscanf( fd, "\t%24s", &action[0] );
318 result = fscanf( fd, "\t%d", &i_index );
322 msg_Dbg( p_this, " + hotkey down %s, file=%s%s", &action[0], (*p_menu)->psz_path, &file[0] );
323 if( p_current->psz_action_down ) free( p_current->psz_action_down );
324 p_current->psz_action_down = strdup( &action[0] );
326 /* Parse range contstruction :
335 result = fscanf( fd, "\t%255s", &file[0] );
338 if( strncmp( &file[0], "end", 3 ) == 0 )
341 p_range_prev = p_range_current;
343 if( (*p_menu)->psz_path )
345 size_t i_path_size = strlen( (*p_menu)->psz_path );
346 size_t i_file_size = strlen( &file[0] );
348 strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
349 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
350 path[ i_path_size + i_file_size ] = '\0';
352 p_range_current = osd_StateNew( p_this, &path[0], "pressed" );
354 else /* absolute paths are used. */
355 p_range_current = osd_StateNew( p_this, &file[0], "pressed" );
357 if( !p_range_current || !p_range_current->p_pic )
360 /* increment the number of ranges for this button */
361 p_current->i_ranges++;
364 p_range_prev->p_next = p_range_current;
366 p_current->p_states = p_range_current;
367 p_range_current->p_prev = p_range_prev;
369 msg_Dbg( p_this, " |- range=%d, file=%s%s",
371 (*p_menu)->psz_path, &file[0] );
375 osd_state_t *p_range = NULL;
377 /* Find the default index for state range */
378 p_range = p_current->p_states;
379 while( (--i_index > 0) && p_range->p_next )
381 osd_state_t *p_temp = NULL;
382 p_temp = p_range->p_next;
385 p_current->p_current_state = p_range;
387 else p_current->p_current_state = p_current->p_states;
388 /* Continue at the beginning of the while() */
391 if( strncmp( &state[0], "end", 3 ) == 0 )
394 result = fscanf( fd, "\t%255s", &file[0] );
398 p_state_prev = p_state_current;
400 if( ( strncmp( ppsz_button_states[0], &state[0], strlen(ppsz_button_states[0]) ) != 0 ) &&
401 ( strncmp( ppsz_button_states[1], &state[0], strlen(ppsz_button_states[1]) ) != 0 ) &&
402 ( strncmp( ppsz_button_states[2], &state[0], strlen(ppsz_button_states[2]) ) != 0 ) )
404 msg_Err( p_this, "invalid button state %s for button %s "
405 "expected %u: unselect, select or pressed)",
406 &state[0], &action[0], (unsigned)strlen(&state[0]));
410 if( (*p_menu)->psz_path )
412 size_t i_path_size = strlen( (*p_menu)->psz_path );
413 size_t i_file_size = strlen( &file[0] );
415 strncpy( &path[0], (*p_menu)->psz_path, i_path_size );
416 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
417 path[ i_path_size + i_file_size ] = '\0';
419 p_state_current = osd_StateNew( p_this, &path[0], &state[0] );
421 else /* absolute paths are used. */
422 p_state_current = osd_StateNew( p_this, &file[0], &state[0] );
424 if( !p_state_current || !p_state_current->p_pic )
428 p_state_prev->p_next = p_state_current;
430 p_current->p_states = p_state_current;
431 p_state_current->p_prev = p_state_prev;
433 msg_Dbg( p_this, " |- state=%s, file=%s%s", &state[0], (*p_menu)->psz_path, &file[0] );
435 p_current->p_current_state = p_current->p_states;
438 /* Find the last button and store its pointer.
439 * The OSD menu behaves like a roundrobin list.
441 p_current = (*p_menu)->p_button;
442 while( p_current && p_current->p_next )
444 osd_button_t *p_temp = NULL;
445 p_temp = p_current->p_next;
448 (*p_menu)->p_last_button = p_current;
454 msg_Err( p_this, "parsing file failed (returned %d)", result );
455 osd_MenuFree( p_this, *p_menu );