Fix CID: 101 resource leak in osdmenu parser.
[vlc/vlc-skelet.git] / modules / misc / osd / simple.c
blob059d4f00f5606858bcd7f45330c000235dcd29f2
1 /*****************************************************************************
2 * simple.c - The OSD Menu simple parser code.
3 *****************************************************************************
4 * Copyright (C) 2005-2007 M2X
5 * $Id$
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 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc/vlc.h>
33 #include <vlc_vout.h>
34 #include <vlc_config.h>
36 #include <vlc_keys.h>
37 #include <vlc_image.h>
38 #include <vlc_osd.h>
39 #include <vlc_charset.h>
41 #include "osd_menu.h"
43 int osd_parser_simpleOpen( vlc_object_t *p_this );
45 /*****************************************************************************
46 * Simple parser open function
47 *****************************************************************************/
48 int osd_parser_simpleOpen( vlc_object_t *p_this )
50 osd_menu_t *p_menu = (osd_menu_t *) p_this;
51 osd_button_t *p_current = NULL; /* button currently processed */
52 osd_button_t *p_prev = NULL; /* previous processed button */
54 #define MAX_FILE_PATH 256
55 FILE *fd = NULL;
56 int result = 0;
58 if( !p_menu ) return VLC_ENOOBJ;
60 msg_Dbg( p_this, "opening osdmenu definition file %s", p_menu->psz_file );
61 fd = utf8_fopen( p_menu->psz_file, "r" );
62 if( !fd )
64 msg_Err( p_this, "failed to open osdmenu definition file %s",
65 p_menu->psz_file );
66 return VLC_EGENERIC;
69 /* Read first line */
70 if( !feof( fd ) )
72 char action[25] = "";
73 char cmd[25] = "";
74 char path[MAX_FILE_PATH] = "";
75 char *psz_path = NULL;
76 size_t i_len = 0;
77 long pos = 0;
79 result = fscanf(fd, "%24s %255s", &action[0], &path[0] );
81 /* override images path ? */
82 psz_path = config_GetPsz( p_this, "osdmenu-file-path" );
83 if( psz_path )
85 /* psz_path is not null and therefor &path[0] cannot be NULL
86 * it might be null terminated.
88 strncpy( &path[0], psz_path, MAX_FILE_PATH );
89 free( psz_path );
90 psz_path = NULL;
92 /* NULL terminate before asking the length of path[] */
93 path[MAX_FILE_PATH-1] = '\0';
94 i_len = strlen(&path[0]);
95 if( i_len == MAX_FILE_PATH )
96 i_len--; /* truncate to prevent buffer overflow */
97 #if defined(WIN32) || defined(UNDER_CE)
98 if( (i_len > 0) && path[i_len] != '\\' )
99 path[i_len] = '\\';
100 #else
101 if( (i_len > 0) && path[i_len] != '/' )
102 path[i_len] = '/';
103 #endif
104 path[i_len+1] = '\0';
105 if( result == 0 || result == EOF )
106 goto error;
107 msg_Dbg( p_this, "osdmenu dir %s", &path[0] );
109 if( i_len == 0 )
110 p_menu = osd_MenuNew( p_menu, NULL, 0, 0 );
111 else
112 p_menu = osd_MenuNew( p_menu, &path[0], 0, 0 );
114 /* Peek for 'style' argument */
115 pos = ftell( fd );
116 if( pos < 0 )
117 goto error;
119 result = fscanf(fd, "%24s %24s", &cmd[0], &action[0] );
120 if( result == 0 || result == EOF )
121 goto error;
123 msg_Dbg( p_this, "osdmenu %s %s", &cmd[0], &action[0] );
124 if( strncmp( &cmd[0], "style", 5 ) == 0 )
126 if( strncmp( &action[0], "default", 7) == 0 )
128 p_menu->i_style = OSD_MENU_STYLE_SIMPLE;
130 else if( strncmp( &action[0], "concat", 6) == 0 )
132 p_menu->i_style = OSD_MENU_STYLE_CONCAT;
135 else
137 result = fseek( fd, pos, SEEK_SET );
138 if( result < 0 )
139 goto error;
143 if( !p_menu )
144 goto error;
146 /* read successive lines */
147 while( !feof( fd ) )
149 osd_state_t *p_state_current = NULL; /* button state currently processed */
150 osd_state_t *p_state_prev = NULL; /* previous state processed button */
152 char cmd[25] = "";
153 char action[25] = "";
154 char state[25] = "";
155 char file[256] = "";
156 char path[512] = "";
157 int i_x = 0;
158 int i_y = 0;
160 result = fscanf( fd, "%24s %24s (%d,%d)", &cmd[0], &action[0], &i_x, &i_y );
161 if( result == 0 )
162 goto error;
163 if( strncmp( &cmd[0], "action", 6 ) != 0 )
164 break;
165 msg_Dbg( p_this, " + %s hotkey=%s (%d,%d)", &cmd[0], &action[0], i_x, i_y );
167 p_prev = p_current;
168 p_current = osd_ButtonNew( &action[0], i_x, i_y );
169 if( !p_current )
170 goto error;
172 if( p_prev )
173 p_prev->p_next = p_current;
174 else
175 p_menu->p_button = p_current;
176 p_current->p_prev = p_prev;
178 /* parse all states */
179 while( !feof( fd ) )
181 char type[25] = "";
183 result = fscanf( fd, "\t%24s", &state[0] );
184 if( result == 0 )
185 goto error;
187 /* FIXME: We only parse one level deep now */
188 if( strncmp( &state[0], "action", 6 ) == 0 )
190 osd_button_t *p_up = NULL;
192 result = fscanf( fd, "%24s (%d,%d)", &action[0], &i_x, &i_y );
193 if( result == 0 )
194 goto error;
195 /* create new button */
196 p_up = osd_ButtonNew( &action[0], i_x, i_y );
197 if( !p_up )
198 goto error;
199 /* Link to list */
200 p_up->p_down = p_current;
201 p_current->p_up = p_up;
202 msg_Dbg( p_this, " + (menu up) hotkey=%s (%d,%d)", &action[0], i_x, i_y );
203 /* Parse type state */
204 result = fscanf( fd, "\t%24s %24s", &cmd[0], &type[0] );
205 if( result == 0 )
206 goto error;
207 if( strncmp( &cmd[0], "type", 4 ) == 0 )
209 if( strncmp( &type[0], "volume", 6 ) == 0 )
211 p_menu->p_state->p_volume = p_up;
212 msg_Dbg( p_this, " + type=%s", &type[0] );
215 /* Parse range state */
216 result = fscanf( fd, "\t%24s", &state[0] );
217 if( result == 0 )
218 goto error;
219 /* Parse the range state */
220 if( strncmp( &state[0], "range", 5 ) == 0 )
222 osd_state_t *p_range_current = NULL; /* range state currently processed */
223 osd_state_t *p_range_prev = NULL; /* previous state processed range */
224 int i_index = 0;
226 p_up->b_range = true;
228 result = fscanf( fd, "\t%24s", &action[0] );
229 if( result == 0 )
230 goto error;
232 result = fscanf( fd, "\t%d", &i_index );
233 if( result == 0 )
234 goto error;
236 msg_Dbg( p_this, " + (menu up) hotkey down %s, file=%s%s",
237 &action[0], p_menu->psz_path, &file[0] );
239 free( p_up->psz_action_down );
240 p_up->psz_action_down = strdup( &action[0] );
242 /* Parse range contstruction :
243 * range <hotkey>
244 * <state1> <file1>
246 * <stateN> <fileN>
247 * end
249 while( !feof( fd ) )
251 result = fscanf( fd, "\t%255s", &file[0] );
252 if( result == 0 )
253 goto error;
254 if( strncmp( &file[0], "end", 3 ) == 0 )
255 break;
257 p_range_prev = p_range_current;
259 if( p_menu->psz_path )
261 size_t i_path_size = strlen( p_menu->psz_path );
262 size_t i_file_size = strlen( &file[0] );
264 strncpy( &path[0], p_menu->psz_path, i_path_size );
265 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
266 path[ i_path_size + i_file_size ] = '\0';
268 p_range_current = osd_StateNew( p_menu, &path[0], "pressed" );
270 else /* absolute paths are used. */
271 p_range_current = osd_StateNew( p_menu, &file[0], "pressed" );
273 if( !p_range_current )
274 goto error;
276 if( !p_range_current->p_pic )
278 osd_StatesFree( p_menu, p_range_current );
279 goto error;
282 p_range_current->i_x = i_x;
283 p_range_current->i_y = i_y;
285 /* increment the number of ranges for this button */
286 p_up->i_ranges++;
288 if( p_range_prev )
289 p_range_prev->p_next = p_range_current;
290 else
291 p_up->p_states = p_range_current;
292 p_range_current->p_prev = p_range_prev;
294 msg_Dbg( p_this, " |- range=%d, file=%s%s",
295 p_up->i_ranges,
296 p_menu->psz_path, &file[0] );
298 if( i_index > 0 )
300 osd_state_t *p_range = NULL;
302 /* Find the default index for state range */
303 p_range = p_up->p_states;
304 while( (--i_index > 0) && p_range->p_next )
306 osd_state_t *p_temp = NULL;
307 p_temp = p_range->p_next;
308 p_range = p_temp;
310 p_up->p_current_state = p_range;
312 else p_up->p_current_state = p_up->p_states;
315 result = fscanf( fd, "\t%24s", &state[0] );
316 if( result == 0 )
317 goto error;
318 if( strncmp( &state[0], "end", 3 ) != 0 )
319 goto error;
321 /* Continue at the beginning of the while() */
322 continue;
325 /* Parse the range state */
326 if( strncmp( &state[0], "range", 5 ) == 0 )
328 osd_state_t *p_range_current = NULL; /* range state currently processed */
329 osd_state_t *p_range_prev = NULL; /* previous state processed range */
330 int i_index = 0;
332 p_current->b_range = true;
334 result = fscanf( fd, "\t%24s", &action[0] );
335 if( result == 0 )
336 goto error;
338 result = fscanf( fd, "\t%d", &i_index );
339 if( result == 0 )
340 goto error;
342 msg_Dbg( p_this, " + hotkey down %s, file=%s%s",
343 &action[0], p_menu->psz_path, &file[0] );
344 free( p_current->psz_action_down );
345 p_current->psz_action_down = strdup( &action[0] );
347 /* Parse range contstruction :
348 * range <hotkey>
349 * <state1> <file1>
351 * <stateN> <fileN>
352 * end
354 while( !feof( fd ) )
356 result = fscanf( fd, "\t%255s", &file[0] );
357 if( result == 0 )
358 goto error;
359 if( strncmp( &file[0], "end", 3 ) == 0 )
360 break;
362 p_range_prev = p_range_current;
364 if( p_menu->psz_path )
366 size_t i_path_size = strlen( p_menu->psz_path );
367 size_t i_file_size = strlen( &file[0] );
369 strncpy( &path[0], p_menu->psz_path, i_path_size );
370 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
371 path[ i_path_size + i_file_size ] = '\0';
373 p_range_current = osd_StateNew( p_menu, &path[0], "pressed" );
375 else /* absolute paths are used. */
376 p_range_current = osd_StateNew( p_menu, &file[0], "pressed" );
378 if( !p_range_current )
379 goto error;
381 if( !p_range_current->p_pic )
383 osd_StatesFree( p_menu, p_range_current );
384 goto error;
387 p_range_current->i_x = i_x;
388 p_range_current->i_y = i_y;
390 /* increment the number of ranges for this button */
391 p_current->i_ranges++;
393 if( p_range_prev )
394 p_range_prev->p_next = p_range_current;
395 else
396 p_current->p_states = p_range_current;
397 p_range_current->p_prev = p_range_prev;
399 msg_Dbg( p_this, " |- range=%d, file=%s%s",
400 p_current->i_ranges,
401 p_menu->psz_path, &file[0] );
403 if( i_index > 0 )
405 osd_state_t *p_range = NULL;
407 /* Find the default index for state range */
408 p_range = p_current->p_states;
409 while( (--i_index > 0) && p_range->p_next )
411 osd_state_t *p_temp = NULL;
412 p_temp = p_range->p_next;
413 p_range = p_temp;
415 p_current->p_current_state = p_range;
417 else p_current->p_current_state = p_current->p_states;
418 /* Continue at the beginning of the while() */
419 continue;
421 if( strncmp( &state[0], "end", 3 ) == 0 )
422 break;
424 result = fscanf( fd, "\t%255s", &file[0] );
425 if( result == 0 )
426 goto error;
428 p_state_prev = p_state_current;
430 if( ( strncmp( ppsz_button_states[0], &state[0], strlen(ppsz_button_states[0]) ) != 0 ) &&
431 ( strncmp( ppsz_button_states[1], &state[0], strlen(ppsz_button_states[1]) ) != 0 ) &&
432 ( strncmp( ppsz_button_states[2], &state[0], strlen(ppsz_button_states[2]) ) != 0 ) )
434 msg_Err( p_this, "invalid button state %s for button %s "
435 "expected %u: unselect, select or pressed)",
436 &state[0], &action[0], (unsigned)strlen(&state[0]));
437 goto error;
440 if( p_menu->psz_path )
442 size_t i_path_size = strlen( p_menu->psz_path );
443 size_t i_file_size = strlen( &file[0] );
445 strncpy( &path[0], p_menu->psz_path, i_path_size );
446 strncpy( &path[i_path_size], &file[0], 512 - (i_path_size + i_file_size) );
447 path[ i_path_size + i_file_size ] = '\0';
449 p_state_current = osd_StateNew( p_menu, &path[0], &state[0] );
451 else /* absolute paths are used. */
452 p_state_current = osd_StateNew( p_menu, &file[0], &state[0] );
454 if( !p_state_current )
455 goto error;
457 if( !p_state_current->p_pic )
459 osd_StatesFree( p_menu, p_state_current );
460 goto error;
463 p_state_current->i_x = i_x;
464 p_state_current->i_y = i_y;
466 if( p_state_prev )
467 p_state_prev->p_next = p_state_current;
468 else
469 p_current->p_states = p_state_current;
470 p_state_current->p_prev = p_state_prev;
472 msg_Dbg( p_this, " |- state=%s, file=%s%s", &state[0],
473 p_menu->psz_path, &file[0] );
475 p_current->p_current_state = p_current->p_states;
478 /* Find the last button and store its pointer.
479 * The OSD menu behaves like a roundrobin list.
481 p_current = p_menu->p_button;
482 while( p_current && p_current->p_next )
484 osd_button_t *p_temp = NULL;
485 p_temp = p_current->p_next;
486 p_current = p_temp;
488 p_menu->p_last_button = p_current;
489 fclose( fd );
490 return VLC_SUCCESS;
492 #undef MAX_FILE_PATH
493 error:
494 msg_Err( p_menu, "parsing file failed (returned %d)", result );
495 osd_MenuFree( p_menu );
496 fclose( fd );
497 return VLC_EGENERIC;