summaryrefslogtreecommitdiff
path: root/apps/gui/skin_engine/skin_parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/gui/skin_engine/skin_parser.c')
-rw-r--r--apps/gui/skin_engine/skin_parser.c2057
1 files changed, 559 insertions, 1498 deletions
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index a62791e397..52e7e1155c 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -8,6 +8,7 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr 10 * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr
11 * 2010 Jonathan Gordon
11 * 12 *
12 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 14 * modify it under the terms of the GNU General Public License
@@ -28,6 +29,10 @@
28#include "plugin.h" 29#include "plugin.h"
29#include "viewport.h" 30#include "viewport.h"
30 31
32#include "skin_buffer.h"
33#include "skin_parser.h"
34#include "tag_table.h"
35
31#ifdef __PCTOOL__ 36#ifdef __PCTOOL__
32#ifdef WPSEDITOR 37#ifdef WPSEDITOR
33#include "proxy.h" 38#include "proxy.h"
@@ -71,377 +76,29 @@
71 76
72#define WPS_ERROR_INVALID_PARAM -1 77#define WPS_ERROR_INVALID_PARAM -1
73 78
74/* which screen are we parsing for? */
75static enum screen_type curr_screen;
76
77/* level of current conditional.
78 -1 means we're not in a conditional. */
79static int level = -1;
80
81/* index of the last WPS_TOKEN_CONDITIONAL_OPTION
82 or WPS_TOKEN_CONDITIONAL_START in current level */
83static int lastcond[WPS_MAX_COND_LEVEL];
84
85/* index of the WPS_TOKEN_CONDITIONAL in current level */
86static int condindex[WPS_MAX_COND_LEVEL];
87
88/* number of condtional options in current level */
89static int numoptions[WPS_MAX_COND_LEVEL];
90
91/* line number, debug only */
92static int line_number;
93
94/* the current viewport */
95static struct skin_viewport *curr_vp;
96/* the current line, linked to the above viewport */
97static struct skin_line *curr_line;
98
99static int follow_lang_direction = 0;
100
101#if defined(DEBUG) || defined(SIMULATOR)
102/* debugging function */
103extern void print_debug_info(struct wps_data *data, int fail, int line);
104extern void debug_skin_usage(void);
105#endif
106
107/* Function for parsing of details for a token. At the moment the
108 function is called, the token type has already been set. The
109 function must fill in the details and possibly add more tokens
110 to the token array. It should return the number of chars that
111 has been consumed.
112
113 wps_bufptr points to the char following the tag (i.e. where
114 details begin).
115 token is the pointer to the 'main' token being parsed
116 */
117typedef int (*wps_tag_parse_func)(const char *wps_bufptr,
118 struct wps_token *token, struct wps_data *wps_data);
119
120struct wps_tag {
121 enum wps_token_type type;
122 const char name[3];
123 unsigned char refresh_type;
124 const wps_tag_parse_func parse_func;
125};
126static int skip_end_of_line(const char *wps_bufptr);
127/* prototypes of all special parse functions : */
128static int parse_timeout(const char *wps_bufptr,
129 struct wps_token *token, struct wps_data *wps_data);
130static int parse_progressbar(const char *wps_bufptr,
131 struct wps_token *token, struct wps_data *wps_data);
132static int parse_dir_level(const char *wps_bufptr,
133 struct wps_token *token, struct wps_data *wps_data);
134static int parse_setting_and_lang(const char *wps_bufptr,
135 struct wps_token *token, struct wps_data *wps_data);
136
137
138static int parse_languagedirection(const char *wps_bufptr,
139 struct wps_token *token, struct wps_data *wps_data)
140{
141 (void)wps_bufptr;
142 (void)token;
143 (void)wps_data;
144 follow_lang_direction = 2; /* 2 because it is decremented immediatly after
145 this token is parsed, after the next token it
146 will be 0 again. */
147 return 0;
148}
149 79
150#ifdef HAVE_LCD_BITMAP 80static bool isdefault(struct skin_tag_parameter *param)
151static int parse_viewport_display(const char *wps_bufptr,
152 struct wps_token *token, struct wps_data *wps_data);
153static int parse_playlistview(const char *wps_bufptr,
154 struct wps_token *token, struct wps_data *wps_data);
155static int parse_viewport(const char *wps_bufptr,
156 struct wps_token *token, struct wps_data *wps_data);
157static int parse_statusbar_enable(const char *wps_bufptr,
158 struct wps_token *token, struct wps_data *wps_data);
159static int parse_statusbar_disable(const char *wps_bufptr,
160 struct wps_token *token, struct wps_data *wps_data);
161static int parse_statusbar_inbuilt(const char *wps_bufptr,
162 struct wps_token *token, struct wps_data *wps_data);
163static int parse_image_display(const char *wps_bufptr,
164 struct wps_token *token, struct wps_data *wps_data);
165static int parse_image_load(const char *wps_bufptr,
166 struct wps_token *token, struct wps_data *wps_data);
167static int parse_font_load(const char *wps_bufptr,
168 struct wps_token *token, struct wps_data *wps_data);
169#endif /*HAVE_LCD_BITMAP */
170#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
171static int parse_viewportcolour(const char *wps_bufptr,
172 struct wps_token *token, struct wps_data *wps_data);
173static int parse_image_special(const char *wps_bufptr,
174 struct wps_token *token, struct wps_data *wps_data);
175#endif
176#ifdef HAVE_ALBUMART
177static int parse_albumart_load(const char *wps_bufptr,
178 struct wps_token *token, struct wps_data *wps_data);
179static int parse_albumart_display(const char *wps_bufptr,
180 struct wps_token *token, struct wps_data *wps_data);
181#endif /* HAVE_ALBUMART */
182#ifdef HAVE_TOUCHSCREEN
183static int parse_touchregion(const char *wps_bufptr,
184 struct wps_token *token, struct wps_data *wps_data);
185#else
186static int fulline_tag_not_supported(const char *wps_bufptr,
187 struct wps_token *token, struct wps_data *wps_data)
188{ 81{
189 (void)token; (void)wps_data; 82 return param->type == DEFAULT;
190 return skip_end_of_line(wps_bufptr);
191} 83}
192#define parse_touchregion fulline_tag_not_supported
193#endif
194#ifdef CONFIG_RTC
195#define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
196#else
197#define WPS_RTC_REFRESH WPS_REFRESH_STATIC
198#endif
199 84
200/* array of available tags - those with more characters have to go first
201 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
202static const struct wps_tag all_tags[] = {
203
204 { WPS_TOKEN_ALIGN_CENTER, "ac", 0, NULL },
205 { WPS_TOKEN_ALIGN_LEFT, "al", 0, NULL },
206 { WPS_TOKEN_ALIGN_LEFT_RTL, "aL", 0, NULL },
207 { WPS_TOKEN_ALIGN_RIGHT, "ar", 0, NULL },
208 { WPS_TOKEN_ALIGN_RIGHT_RTL, "aR", 0, NULL },
209 { WPS_NO_TOKEN, "ax", 0, parse_languagedirection },
210
211 { WPS_TOKEN_BATTERY_PERCENT, "bl", WPS_REFRESH_DYNAMIC, parse_progressbar },
212 { WPS_TOKEN_BATTERY_VOLTS, "bv", WPS_REFRESH_DYNAMIC, NULL },
213 { WPS_TOKEN_BATTERY_TIME, "bt", WPS_REFRESH_DYNAMIC, NULL },
214 { WPS_TOKEN_BATTERY_SLEEPTIME, "bs", WPS_REFRESH_DYNAMIC, NULL },
215#if CONFIG_CHARGING >= CHARGING_MONITOR
216 { WPS_TOKEN_BATTERY_CHARGING, "bc", WPS_REFRESH_DYNAMIC, NULL },
217#endif
218#if CONFIG_CHARGING
219 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED,"bp", WPS_REFRESH_DYNAMIC, NULL },
220#endif
221#ifdef HAVE_USB_POWER
222 { WPS_TOKEN_USB_POWERED, "bu", WPS_REFRESH_DYNAMIC, NULL },
223#endif
224 85
225 { WPS_TOKEN_RTC_PRESENT , "cc", WPS_REFRESH_STATIC, NULL }, 86/* which screen are we parsing for? */
226 { WPS_TOKEN_RTC_DAY_OF_MONTH, "cd", WPS_RTC_REFRESH, NULL }, 87static enum screen_type curr_screen;
227 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED,"ce", WPS_RTC_REFRESH, NULL },
228 { WPS_TOKEN_RTC_12HOUR_CFG, "cf", WPS_RTC_REFRESH, NULL },
229 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", WPS_RTC_REFRESH, NULL },
230 { WPS_TOKEN_RTC_HOUR_24, "ck", WPS_RTC_REFRESH, NULL },
231 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", WPS_RTC_REFRESH, NULL },
232 { WPS_TOKEN_RTC_HOUR_12, "cl", WPS_RTC_REFRESH, NULL },
233 { WPS_TOKEN_RTC_MONTH, "cm", WPS_RTC_REFRESH, NULL },
234 { WPS_TOKEN_RTC_MINUTE, "cM", WPS_RTC_REFRESH, NULL },
235 { WPS_TOKEN_RTC_SECOND, "cS", WPS_RTC_REFRESH, NULL },
236 { WPS_TOKEN_RTC_YEAR_2_DIGITS, "cy", WPS_RTC_REFRESH, NULL },
237 { WPS_TOKEN_RTC_YEAR_4_DIGITS, "cY", WPS_RTC_REFRESH, NULL },
238 { WPS_TOKEN_RTC_AM_PM_UPPER, "cP", WPS_RTC_REFRESH, NULL },
239 { WPS_TOKEN_RTC_AM_PM_LOWER, "cp", WPS_RTC_REFRESH, NULL },
240 { WPS_TOKEN_RTC_WEEKDAY_NAME, "ca", WPS_RTC_REFRESH, NULL },
241 { WPS_TOKEN_RTC_MONTH_NAME, "cb", WPS_RTC_REFRESH, NULL },
242 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", WPS_RTC_REFRESH, NULL },
243 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", WPS_RTC_REFRESH, NULL },
244
245 /* current file */
246 { WPS_TOKEN_FILE_BITRATE, "fb", WPS_REFRESH_STATIC, NULL },
247 { WPS_TOKEN_FILE_CODEC, "fc", WPS_REFRESH_STATIC, NULL },
248 { WPS_TOKEN_FILE_FREQUENCY, "ff", WPS_REFRESH_STATIC, NULL },
249 { WPS_TOKEN_FILE_FREQUENCY_KHZ, "fk", WPS_REFRESH_STATIC, NULL },
250 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", WPS_REFRESH_STATIC, NULL },
251 { WPS_TOKEN_FILE_NAME, "fn", WPS_REFRESH_STATIC, NULL },
252 { WPS_TOKEN_FILE_PATH, "fp", WPS_REFRESH_STATIC, NULL },
253 { WPS_TOKEN_FILE_SIZE, "fs", WPS_REFRESH_STATIC, NULL },
254 { WPS_TOKEN_FILE_VBR, "fv", WPS_REFRESH_STATIC, NULL },
255 { WPS_TOKEN_FILE_DIRECTORY, "d", WPS_REFRESH_STATIC,
256 parse_dir_level },
257
258 /* next file */
259 { WPS_TOKEN_FILE_BITRATE, "Fb", WPS_REFRESH_STATIC, NULL },
260 { WPS_TOKEN_FILE_CODEC, "Fc", WPS_REFRESH_STATIC, NULL },
261 { WPS_TOKEN_FILE_FREQUENCY, "Ff", WPS_REFRESH_STATIC, NULL },
262 { WPS_TOKEN_FILE_FREQUENCY_KHZ, "Fk", WPS_REFRESH_STATIC, NULL },
263 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", WPS_REFRESH_STATIC, NULL },
264 { WPS_TOKEN_FILE_NAME, "Fn", WPS_REFRESH_STATIC, NULL },
265 { WPS_TOKEN_FILE_PATH, "Fp", WPS_REFRESH_STATIC, NULL },
266 { WPS_TOKEN_FILE_SIZE, "Fs", WPS_REFRESH_STATIC, NULL },
267 { WPS_TOKEN_FILE_VBR, "Fv", WPS_REFRESH_STATIC, NULL },
268 { WPS_TOKEN_FILE_DIRECTORY, "D", WPS_REFRESH_STATIC,
269 parse_dir_level },
270
271 /* current metadata */
272 { WPS_TOKEN_METADATA_ARTIST, "ia", WPS_REFRESH_STATIC, NULL },
273 { WPS_TOKEN_METADATA_COMPOSER, "ic", WPS_REFRESH_STATIC, NULL },
274 { WPS_TOKEN_METADATA_ALBUM, "id", WPS_REFRESH_STATIC, NULL },
275 { WPS_TOKEN_METADATA_ALBUM_ARTIST, "iA", WPS_REFRESH_STATIC, NULL },
276 { WPS_TOKEN_METADATA_GROUPING, "iG", WPS_REFRESH_STATIC, NULL },
277 { WPS_TOKEN_METADATA_GENRE, "ig", WPS_REFRESH_STATIC, NULL },
278 { WPS_TOKEN_METADATA_DISC_NUMBER, "ik", WPS_REFRESH_STATIC, NULL },
279 { WPS_TOKEN_METADATA_TRACK_NUMBER, "in", WPS_REFRESH_STATIC, NULL },
280 { WPS_TOKEN_METADATA_TRACK_TITLE, "it", WPS_REFRESH_STATIC, NULL },
281 { WPS_TOKEN_METADATA_VERSION, "iv", WPS_REFRESH_STATIC, NULL },
282 { WPS_TOKEN_METADATA_YEAR, "iy", WPS_REFRESH_STATIC, NULL },
283 { WPS_TOKEN_METADATA_COMMENT, "iC", WPS_REFRESH_STATIC, NULL },
284
285 /* next metadata */
286 { WPS_TOKEN_METADATA_ARTIST, "Ia", WPS_REFRESH_STATIC, NULL },
287 { WPS_TOKEN_METADATA_COMPOSER, "Ic", WPS_REFRESH_STATIC, NULL },
288 { WPS_TOKEN_METADATA_ALBUM, "Id", WPS_REFRESH_STATIC, NULL },
289 { WPS_TOKEN_METADATA_ALBUM_ARTIST, "IA", WPS_REFRESH_STATIC, NULL },
290 { WPS_TOKEN_METADATA_GROUPING, "IG", WPS_REFRESH_STATIC, NULL },
291 { WPS_TOKEN_METADATA_GENRE, "Ig", WPS_REFRESH_STATIC, NULL },
292 { WPS_TOKEN_METADATA_DISC_NUMBER, "Ik", WPS_REFRESH_STATIC, NULL },
293 { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_STATIC, NULL },
294 { WPS_TOKEN_METADATA_TRACK_TITLE, "It", WPS_REFRESH_STATIC, NULL },
295 { WPS_TOKEN_METADATA_VERSION, "Iv", WPS_REFRESH_STATIC, NULL },
296 { WPS_TOKEN_METADATA_YEAR, "Iy", WPS_REFRESH_STATIC, NULL },
297 { WPS_TOKEN_METADATA_COMMENT, "IC", WPS_REFRESH_STATIC, NULL },
298
299#if (CONFIG_CODEC != MAS3507D)
300 { WPS_TOKEN_SOUND_PITCH, "Sp", WPS_REFRESH_DYNAMIC, NULL },
301#endif
302#if (CONFIG_CODEC == SWCODEC)
303 { WPS_TOKEN_SOUND_SPEED, "Ss", WPS_REFRESH_DYNAMIC, NULL },
304#endif
305#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
306 { WPS_TOKEN_VLED_HDD, "lh", WPS_REFRESH_DYNAMIC, NULL },
307#endif
308
309 { WPS_TOKEN_MAIN_HOLD, "mh", WPS_REFRESH_DYNAMIC, NULL },
310
311#ifdef HAS_REMOTE_BUTTON_HOLD
312 { WPS_TOKEN_REMOTE_HOLD, "mr", WPS_REFRESH_DYNAMIC, NULL },
313#else
314 { WPS_TOKEN_UNKNOWN, "mr", 0, NULL },
315#endif
316
317 { WPS_TOKEN_REPEAT_MODE, "mm", WPS_REFRESH_DYNAMIC, NULL },
318 { WPS_TOKEN_PLAYBACK_STATUS, "mp", WPS_REFRESH_DYNAMIC, NULL },
319 { WPS_TOKEN_BUTTON_VOLUME, "mv", WPS_REFRESH_DYNAMIC,
320 parse_timeout },
321
322#ifdef HAVE_LCD_BITMAP
323 { WPS_TOKEN_PEAKMETER, "pm", WPS_REFRESH_PEAK_METER, NULL },
324#else
325 { WPS_TOKEN_PLAYER_PROGRESSBAR, "pf",
326 WPS_REFRESH_DYNAMIC | WPS_REFRESH_PLAYER_PROGRESS, parse_progressbar },
327#endif
328 { WPS_TOKEN_PROGRESSBAR, "pb", WPS_REFRESH_PLAYER_PROGRESS,
329 parse_progressbar },
330
331 { WPS_TOKEN_VOLUME, "pv", WPS_REFRESH_DYNAMIC,
332 parse_progressbar },
333
334 { WPS_TOKEN_TRACK_ELAPSED_PERCENT, "px", WPS_REFRESH_DYNAMIC, NULL },
335 { WPS_TOKEN_TRACK_TIME_ELAPSED, "pc", WPS_REFRESH_DYNAMIC, NULL },
336 { WPS_TOKEN_TRACK_TIME_REMAINING, "pr", WPS_REFRESH_DYNAMIC, NULL },
337 { WPS_TOKEN_TRACK_LENGTH, "pt", WPS_REFRESH_STATIC, NULL },
338 { WPS_TOKEN_TRACK_STARTING, "pS", WPS_REFRESH_DYNAMIC, parse_timeout },
339 { WPS_TOKEN_TRACK_ENDING, "pE", WPS_REFRESH_DYNAMIC, parse_timeout },
340
341 { WPS_TOKEN_PLAYLIST_POSITION, "pp", WPS_REFRESH_STATIC, NULL },
342 { WPS_TOKEN_PLAYLIST_ENTRIES, "pe", WPS_REFRESH_STATIC, NULL },
343 { WPS_TOKEN_PLAYLIST_NAME, "pn", WPS_REFRESH_STATIC, NULL },
344 { WPS_TOKEN_PLAYLIST_SHUFFLE, "ps", WPS_REFRESH_DYNAMIC, NULL },
345
346#ifdef HAVE_TAGCACHE
347 { WPS_TOKEN_DATABASE_PLAYCOUNT, "rp", WPS_REFRESH_DYNAMIC, NULL },
348 { WPS_TOKEN_DATABASE_RATING, "rr", WPS_REFRESH_DYNAMIC, NULL },
349 { WPS_TOKEN_DATABASE_AUTOSCORE, "ra", WPS_REFRESH_DYNAMIC, NULL },
350#endif
351
352#if CONFIG_CODEC == SWCODEC
353 { WPS_TOKEN_REPLAYGAIN, "rg", WPS_REFRESH_STATIC, NULL },
354 { WPS_TOKEN_CROSSFADE, "xf", WPS_REFRESH_DYNAMIC, NULL },
355#endif
356
357 { WPS_TOKEN_HAVE_TUNER, "tp", WPS_REFRESH_STATIC, NULL },
358#if CONFIG_TUNER /* Re-uses the 't' and 'T' prefixes, be careful about doubleups */
359 { WPS_TOKEN_TUNER_TUNED, "tt", WPS_REFRESH_DYNAMIC, NULL },
360 { WPS_TOKEN_TUNER_SCANMODE, "tm", WPS_REFRESH_DYNAMIC, NULL },
361 { WPS_TOKEN_TUNER_STEREO, "ts", WPS_REFRESH_DYNAMIC, NULL },
362 { WPS_TOKEN_TUNER_MINFREQ, "ta", WPS_REFRESH_STATIC, NULL },
363 { WPS_TOKEN_TUNER_MAXFREQ, "tb", WPS_REFRESH_STATIC, NULL },
364 { WPS_TOKEN_TUNER_CURFREQ, "tf", WPS_REFRESH_DYNAMIC, NULL },
365 { WPS_TOKEN_PRESET_ID, "Ti", WPS_REFRESH_STATIC, NULL },
366 { WPS_TOKEN_PRESET_NAME, "Tn", WPS_REFRESH_STATIC, NULL },
367 { WPS_TOKEN_PRESET_FREQ, "Tf", WPS_REFRESH_STATIC, NULL },
368 { WPS_TOKEN_PRESET_COUNT, "Tc", WPS_REFRESH_STATIC, NULL },
369 { WPS_TOKEN_HAVE_RDS, "tx", WPS_REFRESH_STATIC, NULL },
370#ifdef HAVE_RDS_CAP
371 { WPS_TOKEN_RDS_NAME, "ty", WPS_REFRESH_DYNAMIC, NULL },
372 { WPS_TOKEN_RDS_TEXT, "tz", WPS_REFRESH_DYNAMIC, NULL },
373#endif
374#endif /* CONFIG_TUNER */
375
376 { WPS_NO_TOKEN, "s", WPS_REFRESH_SCROLL, NULL },
377 { WPS_TOKEN_SUBLINE_TIMEOUT, "t", 0, parse_timeout },
378 88
379#ifdef HAVE_LCD_BITMAP 89/* the current viewport */
380 { WPS_NO_TOKEN, "we", 0, parse_statusbar_enable }, 90static struct skin_element *curr_viewport_element;
381 { WPS_NO_TOKEN, "wd", 0, parse_statusbar_disable }, 91static struct skin_viewport *curr_vp;
382 { WPS_TOKEN_DRAW_INBUILTBAR, "wi", WPS_REFRESH_DYNAMIC, parse_statusbar_inbuilt },
383 92
384 { WPS_NO_TOKEN, "xl", 0, parse_image_load }, 93struct line *curr_line;
385 94
386 { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", WPS_REFRESH_STATIC, 95static int follow_lang_direction = 0;
387 parse_image_display },
388 96
389 { WPS_TOKEN_IMAGE_DISPLAY, "x", 0, parse_image_load }, 97typedef int (*parse_function)(struct skin_element *element,
390 { WPS_NO_TOKEN, "Fl", 0, parse_font_load }, 98 struct wps_token *token,
391#ifdef HAVE_ALBUMART 99 struct wps_data *wps_data);
392 { WPS_NO_TOKEN, "Cl", 0, parse_albumart_load },
393 { WPS_TOKEN_ALBUMART_DISPLAY, "Cd", WPS_REFRESH_STATIC, parse_albumart_display },
394 { WPS_TOKEN_ALBUMART_FOUND, "C", WPS_REFRESH_STATIC, NULL },
395#endif
396 100
397 { WPS_VIEWPORT_ENABLE, "Vd", WPS_REFRESH_DYNAMIC,
398 parse_viewport_display },
399 { WPS_TOKEN_UIVIEWPORT_ENABLE, "VI", WPS_REFRESH_STATIC,
400 parse_viewport_display },
401#ifdef HAVE_LCD_BITMAP 101#ifdef HAVE_LCD_BITMAP
402 { WPS_VIEWPORT_CUSTOMLIST, "Vp", WPS_REFRESH_STATIC, parse_playlistview },
403 { WPS_TOKEN_LIST_TITLE_TEXT, "Lt", WPS_REFRESH_DYNAMIC, NULL },
404 { WPS_TOKEN_LIST_TITLE_ICON, "Li", WPS_REFRESH_DYNAMIC, NULL },
405#endif
406#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
407 { WPS_TOKEN_VIEWPORT_FGCOLOUR, "Vf", WPS_REFRESH_STATIC, parse_viewportcolour },
408 { WPS_TOKEN_VIEWPORT_BGCOLOUR, "Vb", WPS_REFRESH_STATIC, parse_viewportcolour },
409#endif
410 { WPS_NO_TOKEN, "V", 0, parse_viewport },
411
412#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
413 { WPS_TOKEN_IMAGE_BACKDROP, "X", 0, parse_image_special },
414#endif
415#endif
416
417 { WPS_TOKEN_SETTING, "St", WPS_REFRESH_DYNAMIC,
418 parse_setting_and_lang },
419 { WPS_TOKEN_TRANSLATEDSTRING, "Sx", WPS_REFRESH_STATIC,
420 parse_setting_and_lang },
421 { WPS_TOKEN_LANG_IS_RTL , "Sr", WPS_REFRESH_STATIC, NULL },
422
423 { WPS_TOKEN_LASTTOUCH, "Tl", WPS_REFRESH_DYNAMIC, parse_timeout },
424 { WPS_TOKEN_CURRENT_SCREEN, "cs", WPS_REFRESH_DYNAMIC, NULL },
425 { WPS_NO_TOKEN, "T", 0, parse_touchregion },
426
427
428 /* Recording Tokens */
429 { WPS_TOKEN_HAVE_RECORDING, "Rp", WPS_REFRESH_STATIC, NULL },
430#ifdef HAVE_RECORDING
431 { WPS_TOKEN_IS_RECORDING, "Rr", WPS_REFRESH_DYNAMIC, NULL },
432 { WPS_TOKEN_REC_FREQ, "Rf", WPS_REFRESH_DYNAMIC, NULL },
433 { WPS_TOKEN_REC_ENCODER, "Re", WPS_REFRESH_DYNAMIC, NULL },
434 { WPS_TOKEN_REC_BITRATE, "Rb", WPS_REFRESH_DYNAMIC, NULL },
435 { WPS_TOKEN_REC_MONO, "Rm", WPS_REFRESH_DYNAMIC, NULL },
436 { WPS_TOKEN_REC_SECONDS, "Rs", WPS_REFRESH_DYNAMIC, NULL },
437 { WPS_TOKEN_REC_MINUTES, "Rn", WPS_REFRESH_DYNAMIC, NULL },
438 { WPS_TOKEN_REC_HOURS, "Rh", WPS_REFRESH_DYNAMIC, NULL },
439#endif
440 { WPS_TOKEN_UNKNOWN, "", 0, NULL }
441 /* the array MUST end with an empty string (first char is \0) */
442};
443
444
445/* add a skin_token_list item to the list chain. ALWAYS appended because some of the 102/* add a skin_token_list item to the list chain. ALWAYS appended because some of the
446 * chains require the order to be kept. 103 * chains require the order to be kept.
447 */ 104 */
@@ -459,7 +116,6 @@ static void add_to_ll_chain(struct skin_token_list **list, struct skin_token_lis
459} 116}
460 117
461/* traverse the image linked-list for an image */ 118/* traverse the image linked-list for an image */
462#ifdef HAVE_LCD_BITMAP
463struct gui_img* find_image(char label, struct wps_data *data) 119struct gui_img* find_image(char label, struct wps_data *data)
464{ 120{
465 struct skin_token_list *list = data->images; 121 struct skin_token_list *list = data->images;
@@ -478,10 +134,10 @@ struct gui_img* find_image(char label, struct wps_data *data)
478/* traverse the viewport linked list for a viewport */ 134/* traverse the viewport linked list for a viewport */
479struct skin_viewport* find_viewport(char label, struct wps_data *data) 135struct skin_viewport* find_viewport(char label, struct wps_data *data)
480{ 136{
481 struct skin_token_list *list = data->viewports; 137 struct skin_element *list = data->tree;
482 while (list) 138 while (list)
483 { 139 {
484 struct skin_viewport *vp = (struct skin_viewport *)list->token->value.data; 140 struct skin_viewport *vp = (struct skin_viewport *)list->data;
485 if (vp->label == label) 141 if (vp->label == label)
486 return vp; 142 return vp;
487 list = list->next; 143 list = list->next;
@@ -489,6 +145,7 @@ struct skin_viewport* find_viewport(char label, struct wps_data *data)
489 return NULL; 145 return NULL;
490} 146}
491 147
148#ifdef HAVE_LCD_BITMAP
492 149
493/* create and init a new wpsll item. 150/* create and init a new wpsll item.
494 * passing NULL to token will alloc a new one. 151 * passing NULL to token will alloc a new one.
@@ -498,9 +155,10 @@ struct skin_viewport* find_viewport(char label, struct wps_data *data)
498static struct skin_token_list *new_skin_token_list_item(struct wps_token *token, 155static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
499 void* token_data) 156 void* token_data)
500{ 157{
501 struct skin_token_list *llitem = skin_buffer_alloc(sizeof(struct skin_token_list)); 158 struct skin_token_list *llitem =
159 (struct skin_token_list *)skin_buffer_alloc(sizeof(struct skin_token_list));
502 if (!token) 160 if (!token)
503 token = skin_buffer_alloc(sizeof(struct wps_token)); 161 token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token));
504 if (!llitem || !token) 162 if (!llitem || !token)
505 return NULL; 163 return NULL;
506 llitem->next = NULL; 164 llitem->next = NULL;
@@ -510,108 +168,36 @@ static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
510 return llitem; 168 return llitem;
511} 169}
512 170
513/* Returns the number of chars that should be skipped to jump 171static int parse_statusbar_tags(struct skin_element* element,
514 immediately after the first eol, i.e. to the start of the next line */ 172 struct wps_token *token,
515static int skip_end_of_line(const char *wps_bufptr) 173 struct wps_data *wps_data)
516{
517 line_number++;
518 int skip = 0;
519 while(*(wps_bufptr + skip) != '\n')
520 skip++;
521 return ++skip;
522}
523
524/* Starts a new subline in the current line during parsing */
525static bool skin_start_new_subline(struct skin_line *line, int curr_token)
526{
527 struct skin_subline *subline = skin_buffer_alloc(sizeof(struct skin_subline));
528 if (!subline)
529 return false;
530
531 subline->first_token_idx = curr_token;
532 subline->next = NULL;
533
534 subline->line_type = 0;
535 subline->time_mult = 0;
536
537 line->curr_subline->last_token_idx = curr_token-1;
538 line->curr_subline->next = subline;
539 line->curr_subline = subline;
540 return true;
541}
542
543static bool skin_start_new_line(struct skin_viewport *vp, int curr_token)
544{ 174{
545 struct skin_line *line = skin_buffer_alloc(sizeof(struct skin_line)); 175 (void)element;
546 struct skin_subline *subline = NULL; 176 if (token->type == SKIN_TOKEN_DRAW_INBUILTBAR)
547 if (!line)
548 return false;
549
550 /* init the subline */
551 subline = &line->sublines;
552 subline->first_token_idx = curr_token;
553 subline->next = NULL;
554 subline->line_type = 0;
555 subline->time_mult = 0;
556
557 /* init the new line */
558 line->curr_subline = &line->sublines;
559 line->next = NULL;
560 line->subline_expire_time = 0;
561
562 /* connect to curr_line and vp pointers.
563 * 1) close the previous lines subline
564 * 2) connect to vp pointer
565 * 3) connect to curr_line global pointer
566 */
567 if (curr_line)
568 { 177 {
569 curr_line->curr_subline->last_token_idx = curr_token - 1; 178 token->value.data = (void*)&curr_vp->vp;
570 curr_line->next = line;
571 curr_line->curr_subline = NULL;
572 } 179 }
573 curr_line = line; 180 else
574 if (!vp->lines) 181 {
575 vp->lines = line; 182 struct skin_element *def_vp = wps_data->tree;
576 return true; 183 struct skin_viewport *default_vp = def_vp->data;
577} 184 if (def_vp->params_count == 0)
578 185 {
579#ifdef HAVE_LCD_BITMAP 186 wps_data->wps_sb_tag = true;
580 187 wps_data->show_sb_on_wps = (token->type == SKIN_TOKEN_ENABLE_THEME);
581static int parse_statusbar_enable(const char *wps_bufptr, 188 }
582 struct wps_token *token, 189 if (wps_data->show_sb_on_wps)
583 struct wps_data *wps_data) 190 {
584{ 191 viewport_set_defaults(&default_vp->vp, curr_screen);
585 (void)token; /* Kill warnings */ 192 }
586 wps_data->wps_sb_tag = true; 193 else
587 wps_data->show_sb_on_wps = true; 194 {
588 struct skin_viewport *default_vp = find_viewport(VP_DEFAULT_LABEL, wps_data); 195 viewport_set_fullscreen(&default_vp->vp, curr_screen);
589 viewport_set_defaults(&default_vp->vp, curr_screen); 196 }
590 default_vp->vp.font = FONT_UI; 197 }
591 return skip_end_of_line(wps_bufptr); 198 return 0;
592}
593
594static int parse_statusbar_disable(const char *wps_bufptr,
595 struct wps_token *token,
596 struct wps_data *wps_data)
597{
598 (void)token; /* Kill warnings */
599 wps_data->wps_sb_tag = true;
600 wps_data->show_sb_on_wps = false;
601 struct skin_viewport *default_vp = find_viewport(VP_DEFAULT_LABEL, wps_data);
602 viewport_set_fullscreen(&default_vp->vp, curr_screen);
603 default_vp->vp.font = FONT_UI;
604 return skip_end_of_line(wps_bufptr);
605}
606
607static int parse_statusbar_inbuilt(const char *wps_bufptr,
608 struct wps_token *token, struct wps_data *wps_data)
609{
610 (void)wps_data;
611 token->value.data = (void*)&curr_vp->vp;
612 return skip_end_of_line(wps_bufptr);
613} 199}
614 200
615static int get_image_id(int c) 201static int get_image_id(int c)
616{ 202{
617 if(c >= 'a' && c <= 'z') 203 if(c >= 'a' && c <= 'z')
@@ -625,32 +211,20 @@ static int get_image_id(int c)
625char *get_image_filename(const char *start, const char* bmpdir, 211char *get_image_filename(const char *start, const char* bmpdir,
626 char *buf, int buf_size) 212 char *buf, int buf_size)
627{ 213{
628 const char *end = start; 214 snprintf(buf, buf_size, "%s/%s", bmpdir, start);
629 int bmpdirlen = strlen(bmpdir); 215
630
631 while (*end && *end != ',' && *end != ')')
632 end++;
633 if ( !end || (end - start) >= (buf_size - bmpdirlen - 2) )
634 {
635 buf[0] = '\0';
636 return NULL;
637 }
638
639 strcpy(buf, bmpdir);
640 buf[bmpdirlen] = '/';
641 memcpy( &buf[bmpdirlen + 1], start, end - start);
642 buf[bmpdirlen + 1 + end - start] = 0;
643
644 return buf; 216 return buf;
645} 217}
646 218
647static int parse_image_display(const char *wps_bufptr, 219static int parse_image_display(struct skin_element *element,
648 struct wps_token *token, 220 struct wps_token *token,
649 struct wps_data *wps_data) 221 struct wps_data *wps_data)
650{ 222{
651 char label = wps_bufptr[1]; 223 char *text = element->params[0].data.text;
224 char label = text[0];
225 char sublabel = text[1];
652 int subimage; 226 int subimage;
653 struct gui_img *img;; 227 struct gui_img *img;
654 228
655 /* sanity check */ 229 /* sanity check */
656 img = find_image(label, wps_data); 230 img = find_image(label, wps_data);
@@ -660,7 +234,7 @@ static int parse_image_display(const char *wps_bufptr,
660 return WPS_ERROR_INVALID_PARAM; 234 return WPS_ERROR_INVALID_PARAM;
661 } 235 }
662 236
663 if ((subimage = get_image_id(wps_bufptr[2])) != -1) 237 if ((subimage = get_image_id(sublabel)) != -1)
664 { 238 {
665 if (subimage >= img->num_subimages) 239 if (subimage >= img->num_subimages)
666 return WPS_ERROR_INVALID_PARAM; 240 return WPS_ERROR_INVALID_PARAM;
@@ -674,32 +248,24 @@ static int parse_image_display(const char *wps_bufptr,
674 } 248 }
675} 249}
676 250
677static int parse_image_load(const char *wps_bufptr, 251static int parse_image_load(struct skin_element *element,
678 struct wps_token *token, 252 struct wps_token *token,
679 struct wps_data *wps_data) 253 struct wps_data *wps_data)
680{ 254{
681 const char *ptr = wps_bufptr;
682 const char* filename; 255 const char* filename;
683 const char* id; 256 const char* id;
684 int x,y; 257 int x,y;
685 struct gui_img *img; 258 struct gui_img *img;
686 259
687 /* format: %x|n|filename.bmp|x|y| 260 /* format: %x(n,filename.bmp,x,y)
688 or %xl|n|filename.bmp|x|y| 261 or %xl(n,filename.bmp,x,y)
689 or %xl|n|filename.bmp|x|y|num_subimages| 262 or %xl(n,filename.bmp,x,y,num_subimages)
690 */ 263 */
691 264
692 if (*ptr != '(') 265 id = element->params[0].data.text;
693 return WPS_ERROR_INVALID_PARAM; 266 filename = element->params[1].data.text;
694 267 x = element->params[2].data.number;
695 ptr++; 268 y = element->params[3].data.number;
696
697 if (!(ptr = parse_list("ssdd", NULL, ',', ptr, &id, &filename, &x, &y)))
698 return WPS_ERROR_INVALID_PARAM;
699
700 /* Check there is a terminating ) */
701 if (*ptr != ')' && *ptr != ',')
702 return WPS_ERROR_INVALID_PARAM;
703 269
704 /* check the image number and load state */ 270 /* check the image number and load state */
705 if(find_image(*id, wps_data)) 271 if(find_image(*id, wps_data))
@@ -707,7 +273,7 @@ static int parse_image_load(const char *wps_bufptr,
707 /* Invalid image ID */ 273 /* Invalid image ID */
708 return WPS_ERROR_INVALID_PARAM; 274 return WPS_ERROR_INVALID_PARAM;
709 } 275 }
710 img = skin_buffer_alloc(sizeof(struct gui_img)); 276 img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img));
711 if (!img) 277 if (!img)
712 return WPS_ERROR_INVALID_PARAM; 278 return WPS_ERROR_INVALID_PARAM;
713 /* save a pointer to the filename */ 279 /* save a pointer to the filename */
@@ -717,62 +283,44 @@ static int parse_image_load(const char *wps_bufptr,
717 img->y = y; 283 img->y = y;
718 img->num_subimages = 1; 284 img->num_subimages = 1;
719 img->always_display = false; 285 img->always_display = false;
286 // img->just_drawn = false;
287 img->display = -1;
720 288
721 /* save current viewport */ 289 /* save current viewport */
722 img->vp = &curr_vp->vp; 290 img->vp = &curr_vp->vp;
723 291
724 if (token->type == WPS_TOKEN_IMAGE_DISPLAY) 292 if (token->type == SKIN_TOKEN_IMAGE_DISPLAY)
725 { 293 {
726 img->always_display = true; 294 img->always_display = true;
727 } 295 }
728 else if (*ptr == ',') 296 else if (element->params_count == 5)
729 { 297 {
730 /* Parse the (optional) number of sub-images */ 298 img->num_subimages = element->params[4].data.number;
731 ptr++;
732 img->num_subimages = atoi(ptr);
733 if (img->num_subimages <= 0) 299 if (img->num_subimages <= 0)
734 return WPS_ERROR_INVALID_PARAM; 300 return WPS_ERROR_INVALID_PARAM;
735 /* Check there is a terminating ) */
736 while(isdigit(*ptr))
737 ptr++;
738 if (*ptr != ')')
739 return WPS_ERROR_INVALID_PARAM;
740 } 301 }
741 struct skin_token_list *item = new_skin_token_list_item(NULL, img); 302 struct skin_token_list *item =
303 (struct skin_token_list *)new_skin_token_list_item(NULL, img);
742 if (!item) 304 if (!item)
743 return WPS_ERROR_INVALID_PARAM; 305 return WPS_ERROR_INVALID_PARAM;
744 add_to_ll_chain(&wps_data->images, item); 306 add_to_ll_chain(&wps_data->images, item);
745 307
746 /* Skip the rest of the line */ 308 return 0;
747 return skip_end_of_line(wps_bufptr);
748} 309}
749struct skin_font { 310struct skin_font {
750 int id; /* the id from font_load */ 311 int id; /* the id from font_load */
751 char *name; /* filename without path and extension */ 312 char *name; /* filename without path and extension */
752}; 313};
753static struct skin_font skinfonts[MAXUSERFONTS]; 314static struct skin_font skinfonts[MAXUSERFONTS];
754static int parse_font_load(const char *wps_bufptr, 315static int parse_font_load(struct skin_element *element,
755 struct wps_token *token, struct wps_data *wps_data) 316 struct wps_token *token,
317 struct wps_data *wps_data)
756{ 318{
757 (void)wps_data; (void)token; 319 (void)wps_data; (void)token;
758 const char *ptr = wps_bufptr; 320 int id = element->params[0].data.number;
759 int id; 321 char *filename = element->params[1].data.text;
760 char *filename; 322 char *ptr;
761 323
762 if (*ptr != '(')
763 return WPS_ERROR_INVALID_PARAM;
764
765 ptr++;
766
767 if (!(ptr = parse_list("ds", NULL, ',', ptr, &id, &filename)))
768 return WPS_ERROR_INVALID_PARAM;
769
770 /* Check there is a terminating ) */
771 if (*ptr != ')')
772 return WPS_ERROR_INVALID_PARAM;
773
774 if (id <= FONT_UI || id >= MAXFONTS-1)
775 return WPS_ERROR_INVALID_PARAM;
776#if defined(DEBUG) || defined(SIMULATOR) 324#if defined(DEBUG) || defined(SIMULATOR)
777 if (skinfonts[id-FONT_FIRSTUSERFONT].name != NULL) 325 if (skinfonts[id-FONT_FIRSTUSERFONT].name != NULL)
778 { 326 {
@@ -782,286 +330,65 @@ static int parse_font_load(const char *wps_bufptr,
782 /* make sure the filename contains .fnt, 330 /* make sure the filename contains .fnt,
783 * we dont actually use it, but require it anyway */ 331 * we dont actually use it, but require it anyway */
784 ptr = strchr(filename, '.'); 332 ptr = strchr(filename, '.');
785 if (!ptr || strncmp(ptr, ".fnt)", 5)) 333 if (!ptr || strncmp(ptr, ".fnt", 4))
786 return WPS_ERROR_INVALID_PARAM; 334 return WPS_ERROR_INVALID_PARAM;
787 skinfonts[id-FONT_FIRSTUSERFONT].id = -1; 335 skinfonts[id-FONT_FIRSTUSERFONT].id = -1;
788 skinfonts[id-FONT_FIRSTUSERFONT].name = filename; 336 skinfonts[id-FONT_FIRSTUSERFONT].name = filename;
789 337
790 return skip_end_of_line(wps_bufptr); 338 return 0;
791} 339}
792 340
793 341
794static int parse_viewport_display(const char *wps_bufptr,
795 struct wps_token *token,
796 struct wps_data *wps_data)
797{
798 (void)wps_data;
799 char letter = wps_bufptr[1];
800
801 if (letter < 'a' || letter > 'z')
802 {
803 /* invalid viewport tag */
804 return WPS_ERROR_INVALID_PARAM;
805 }
806 token->value.i = letter;
807 return 3;
808}
809
810#ifdef HAVE_LCD_BITMAP 342#ifdef HAVE_LCD_BITMAP
811static int parse_playlistview_text(struct playlistviewer *viewer,
812 enum info_line_type line, char* text)
813{
814 int cur_string = 0;
815 const struct wps_tag *tag;
816 int taglen = 0;
817 const char *start = text;
818 if (*text != ',')
819 return -1;
820 text++;
821 viewer->lines[line].count = 0;
822 viewer->lines[line].scroll = false;
823 while (*text != ',' && *text != ')')
824 {
825 if (*text == '%') /* it is a token of some type */
826 {
827 text++;
828 taglen = 0;
829 switch(*text)
830 {
831 case '%':
832 case '<':
833 case '|':
834 case '>':
835 case ';':
836 case '#':
837 case '(':
838 case ')':
839 case ',':
840 /* escaped characters */
841 viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_CHARACTER;
842 viewer->lines[line].strings[cur_string][0] = *text;
843 viewer->lines[line].strings[cur_string++][1] = '\0';
844 text++;
845 break;
846 default:
847 for (tag = all_tags;
848 strncmp(text, tag->name, strlen(tag->name)) != 0;
849 tag++) ;
850 /* %s isnt stored as a tag so manually check for it */
851 if (tag->type == WPS_NO_TOKEN)
852 {
853 if (!strncmp(tag->name, "s", 1))
854 {
855 viewer->lines[line].scroll = true;
856 taglen = 1;
857 }
858 }
859 else if (tag->type == WPS_TOKEN_UNKNOWN)
860 {
861 int i = 0;
862 /* just copy the string */
863 viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_STRING;
864 while (i<(MAX_PLAYLISTLINE_STRLEN-1) && text[i] != ',' && text[i] != ')' && text[i] != '%')
865 {
866 viewer->lines[line].strings[cur_string][i] = text[i];
867 i++;
868 }
869 viewer->lines[line].strings[cur_string][i] = '\0';
870 cur_string++;
871 taglen = i;
872 }
873 else
874 {
875 if (tag->parse_func)
876 {
877 /* unsupported tag, reject */
878 return -1;
879 }
880 taglen = strlen(tag->name);
881 viewer->lines[line].tokens[viewer->lines[line].count++] = tag->type;
882 }
883 text += taglen;
884 }
885 }
886 else
887 {
888 /* regular string */
889 int i = 0;
890 /* just copy the string */
891 viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_STRING;
892 while (i<(MAX_PLAYLISTLINE_STRLEN-1) && text[i] != ',' && text[i] != ')' && text[i] != '%')
893 {
894 viewer->lines[line].strings[cur_string][i] = text[i];
895 i++;
896 }
897 viewer->lines[line].strings[cur_string][i] = '\0';
898 cur_string++;
899 text += i;
900 }
901 }
902 return text - start;
903}
904 343
905static int parse_playlistview(const char *wps_bufptr, 344static int parse_playlistview(struct skin_element *element,
906 struct wps_token *token, struct wps_data *wps_data) 345 struct wps_token *token,
346 struct wps_data *wps_data)
907{ 347{
908 (void)wps_data; 348 (void)wps_data;
909 /* %Vp|<use icons>|<start offset>|info line text|no info text| */ 349 struct playlistviewer *viewer =
910 struct playlistviewer *viewer = skin_buffer_alloc(sizeof(struct playlistviewer)); 350 (struct playlistviewer *)skin_buffer_alloc(sizeof(struct playlistviewer));
911 char *ptr = strchr(wps_bufptr, '('); 351 if (!viewer)
912 int length;
913 if (!viewer || !ptr)
914 return WPS_ERROR_INVALID_PARAM; 352 return WPS_ERROR_INVALID_PARAM;
915 viewer->vp = &curr_vp->vp; 353 viewer->vp = &curr_vp->vp;
916 viewer->show_icons = true; 354 viewer->show_icons = true;
917 viewer->start_offset = atoi(ptr+1); 355 viewer->start_offset = element->params[0].data.number;
356 viewer->lines[0] = element->params[1].data.code;
357 viewer->lines[1] = element->params[2].data.code;
358
918 token->value.data = (void*)viewer; 359 token->value.data = (void*)viewer;
919 ptr = strchr(ptr+1, ','); 360
920 length = parse_playlistview_text(viewer, TRACK_HAS_INFO, ptr); 361 return 0;
921 if (length < 0)
922 return WPS_ERROR_INVALID_PARAM;
923 length = parse_playlistview_text(viewer, TRACK_HAS_NO_INFO, ptr+length);
924 if (length < 0)
925 return WPS_ERROR_INVALID_PARAM;
926
927 return skip_end_of_line(wps_bufptr);
928} 362}
929#endif 363#endif
930 364
931static int parse_viewport(const char *wps_bufptr,
932 struct wps_token *token,
933 struct wps_data *wps_data)
934{
935 (void)token; /* Kill warnings */
936 const char *ptr = wps_bufptr;
937
938 struct skin_viewport *skin_vp = skin_buffer_alloc(sizeof(struct skin_viewport));
939
940 /* check for the optional letter to signify its a hideable viewport */
941 /* %Vl|<label>|<rest of tags>| */
942 skin_vp->hidden_flags = 0;
943 skin_vp->label = VP_NO_LABEL;
944 skin_vp->lines = NULL;
945 if (curr_line)
946 {
947 curr_line->curr_subline->last_token_idx = wps_data->num_tokens
948 - (wps_data->num_tokens > 0 ? 1 : 0);
949 }
950
951 curr_line = NULL;
952 if (!skin_start_new_line(skin_vp, wps_data->num_tokens))
953 return WPS_ERROR_INVALID_PARAM;
954
955 if (*ptr == 'i')
956 {
957 if (*(ptr+1) == '(')
958 {
959 char label = *(ptr+2);
960 if (label >= 'a' && label <= 'z')
961 {
962 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
963 skin_vp->label = VP_INFO_LABEL|label;
964 ptr += 3;
965 }
966 else
967 {
968 if (label != '-')
969 return WPS_ERROR_INVALID_PARAM;
970 skin_vp->label = VP_INFO_LABEL|VP_DEFAULT_LABEL;
971 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
972 ptr += 3;
973 }
974 }
975 else
976 return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */
977 }
978 else if (*ptr == 'l')
979 {
980 if (*(ptr+1) == '(')
981 {
982 char label = *(ptr+2);
983 if (label >= 'a' && label <= 'z')
984 {
985 skin_vp->hidden_flags = VP_DRAW_HIDEABLE;
986 skin_vp->label = label;
987 }
988 else
989 return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */
990 ptr += 3;
991 }
992 }
993 if (*ptr != ',' && *ptr != '(')
994 return WPS_ERROR_INVALID_PARAM;
995
996 ptr++;
997 struct viewport *vp = &skin_vp->vp;
998 /* format: %V|x|y|width|height|font| */
999 if (!(ptr = viewport_parse_viewport(vp, curr_screen, ptr, ',')))
1000 return WPS_ERROR_INVALID_PARAM;
1001
1002 /* Check for trailing ) */
1003 if (*ptr != ')')
1004 return WPS_ERROR_INVALID_PARAM;
1005 ptr++;
1006
1007 if (follow_lang_direction && lang_is_rtl())
1008 {
1009 vp->flags |= VP_FLAG_ALIGN_RIGHT;
1010 vp->x = screens[curr_screen].lcdwidth - vp->width - vp->x;
1011 }
1012 else
1013 vp->flags &= ~VP_FLAG_ALIGN_RIGHT; /* ignore right-to-left languages */
1014
1015#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) 365#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1016 skin_vp->start_fgcolour = vp->fg_pattern;
1017 skin_vp->start_bgcolour = vp->bg_pattern;
1018#endif
1019 366
1020 struct skin_token_list *list = new_skin_token_list_item(NULL, skin_vp); 367static int parse_viewportcolour(struct skin_element *element,
1021 if (!list) 368 struct wps_token *token,
1022 return WPS_ERROR_INVALID_PARAM; 369 struct wps_data *wps_data)
1023 add_to_ll_chain(&wps_data->viewports, list);
1024 curr_vp = skin_vp;
1025 /* Skip the rest of the line */
1026 return ptr-wps_bufptr;
1027}
1028#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1029static int parse_viewportcolour(const char *wps_bufptr,
1030 struct wps_token *token, struct wps_data *wps_data)
1031{ 370{
1032 (void)wps_data; 371 (void)wps_data;
1033 const char *ptr = wps_bufptr; 372 struct skin_tag_parameter *param = element->params;
1034 int i; 373 struct viewport_colour *colour =
1035 bool found_text; 374 (struct viewport_colour *)skin_buffer_alloc(sizeof(struct viewport_colour));
1036 struct viewport_colour *colour = skin_buffer_alloc(sizeof(struct viewport_colour)); 375 if (!colour)
1037 uint32_t set;
1038 if (*ptr != '(' || !colour)
1039 return -1;
1040 ptr++;
1041 if (!(ptr = parse_list("c", &set, ',', ptr, &colour->colour)))
1042 return -1;
1043 if (*ptr != ')')
1044 return -1; 376 return -1;
1045 if (!set) 377 if (isdefault(param))
378 {
1046 colour->colour = get_viewport_default_colour(curr_screen, 379 colour->colour = get_viewport_default_colour(curr_screen,
1047 token->type == WPS_TOKEN_VIEWPORT_FGCOLOUR); 380 token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR);
1048 colour->vp = &curr_vp->vp; 381 }
1049 token->value.data = colour; 382 else
1050 /* If there havnt been any text tags between the %V() line and here use
1051 * the colour as the viewport colour. fixes scrolling lines not
1052 * having the correct colour */
1053 i = curr_vp->lines->sublines.first_token_idx;
1054 found_text = false;
1055 while (!found_text && i< curr_vp->lines->sublines.last_token_idx)
1056 { 383 {
1057 if (wps_data->tokens[i++].type != WPS_TOKEN_CHARACTER && 384 if (!parse_color(param->data.text, &colour->colour))
1058 wps_data->tokens[i++].type != WPS_TOKEN_VIEWPORT_FGCOLOUR && 385 return -1;
1059 wps_data->tokens[i++].type != WPS_TOKEN_VIEWPORT_BGCOLOUR )
1060 found_text = true;
1061 } 386 }
1062 if (!found_text) 387 colour->vp = &curr_vp->vp;
388 token->value.data = colour;
389 if (element->line == curr_viewport_element->line)
1063 { 390 {
1064 if (token->type == WPS_TOKEN_VIEWPORT_FGCOLOUR) 391 if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR)
1065 { 392 {
1066 curr_vp->start_fgcolour = colour->colour; 393 curr_vp->start_fgcolour = colour->colour;
1067 curr_vp->vp.fg_pattern = colour->colour; 394 curr_vp->vp.fg_pattern = colour->colour;
@@ -1072,72 +399,54 @@ static int parse_viewportcolour(const char *wps_bufptr,
1072 curr_vp->vp.bg_pattern = colour->colour; 399 curr_vp->vp.bg_pattern = colour->colour;
1073 } 400 }
1074 } 401 }
1075 ptr++; 402 return 0;
1076 return ptr - wps_bufptr;
1077} 403}
1078 404
1079static int parse_image_special(const char *wps_bufptr, 405static int parse_image_special(struct skin_element *element,
1080 struct wps_token *token, 406 struct wps_token *token,
1081 struct wps_data *wps_data) 407 struct wps_data *wps_data)
1082{ 408{
1083 (void)wps_data; /* kill warning */ 409 (void)wps_data; /* kill warning */
1084 (void)token; 410 (void)token;
1085 const char *pos = NULL;
1086 const char *newline;
1087 bool error = false; 411 bool error = false;
1088 412
1089 pos = strchr(wps_bufptr + 1, ')');
1090 newline = strchr(wps_bufptr, '\n');
1091
1092 error = (pos > newline);
1093
1094#if LCD_DEPTH > 1 413#if LCD_DEPTH > 1
1095 if (token->type == WPS_TOKEN_IMAGE_BACKDROP) 414 if (token->type == SKIN_TOKEN_IMAGE_BACKDROP)
1096 { 415 {
416 char *filename = element->params[0].data.text;
1097 /* format: %X|filename.bmp| or %Xd */ 417 /* format: %X|filename.bmp| or %Xd */
1098 if (!strncmp(wps_bufptr, "(d)", 3)) 418 if (!strcmp(filename, "d"))
1099 { 419 {
1100 wps_data->backdrop = NULL; 420 wps_data->backdrop = NULL;
1101 return skip_end_of_line(wps_bufptr); 421 return 0;
1102 } 422 }
1103 else if (!error) 423 else if (!error)
1104 wps_data->backdrop = (char*)wps_bufptr + 1; 424 {
425 wps_data->backdrop = filename;
426 }
1105 } 427 }
1106#endif 428#endif
1107 if (error)
1108 return WPS_ERROR_INVALID_PARAM;
1109 /* Skip the rest of the line */ 429 /* Skip the rest of the line */
1110 return skip_end_of_line(wps_bufptr); 430 return error ? WPS_ERROR_INVALID_PARAM : 0;
1111} 431}
1112#endif 432#endif
1113 433
1114#endif /* HAVE_LCD_BITMAP */ 434#endif /* HAVE_LCD_BITMAP */
1115 435
1116static int parse_setting_and_lang(const char *wps_bufptr, 436static int parse_setting_and_lang(struct skin_element *element,
1117 struct wps_token *token, 437 struct wps_token *token,
1118 struct wps_data *wps_data) 438 struct wps_data *wps_data)
1119{ 439{
1120 /* NOTE: both the string validations that happen in here will 440 /* NOTE: both the string validations that happen in here will
1121 * automatically PASS on checkwps because its too hard to get 441 * automatically PASS on checkwps because its too hard to get
1122 * settings_list.c and englinsh.lang built for it. 442 * settings_list.c and english.lang built for it.
1123 * If that ever changes remove the #ifndef __PCTOOL__'s here 443 * If that ever changes remove the #ifndef __PCTOOL__'s here
1124 */ 444 */
1125 (void)wps_data; 445 (void)wps_data;
1126 const char *ptr = wps_bufptr; 446 char *temp = element->params[0].data.text;
1127 const char *end; 447 int i;
1128 int i = 0;
1129 char temp[64];
1130
1131 /* Find the setting's cfg_name */
1132 if (*ptr != '(')
1133 return WPS_ERROR_INVALID_PARAM;
1134 ptr++;
1135 end = strchr(ptr,')');
1136 if (!end || (size_t)(end-ptr+1) > sizeof temp)
1137 return WPS_ERROR_INVALID_PARAM;
1138 strlcpy(temp, ptr,end-ptr+1);
1139 448
1140 if (token->type == WPS_TOKEN_TRANSLATEDSTRING) 449 if (token->type == SKIN_TOKEN_TRANSLATEDSTRING)
1141 { 450 {
1142#ifndef __PCTOOL__ 451#ifndef __PCTOOL__
1143 i = lang_english_to_id(temp); 452 i = lang_english_to_id(temp);
@@ -1159,170 +468,104 @@ static int parse_setting_and_lang(const char *wps_bufptr,
1159 } 468 }
1160 /* Store the setting number */ 469 /* Store the setting number */
1161 token->value.i = i; 470 token->value.i = i;
1162 471 return 0;
1163 /* Skip the rest of the line */
1164 return end-ptr+2;
1165}
1166
1167
1168static int parse_dir_level(const char *wps_bufptr,
1169 struct wps_token *token,
1170 struct wps_data *wps_data)
1171{
1172 char val[] = { wps_bufptr[1], '\0' };
1173 if (wps_bufptr[0] != '(' || wps_bufptr[2] != ')')
1174 return WPS_ERROR_INVALID_PARAM;
1175 token->value.i = atoi(val);
1176 (void)wps_data; /* Kill warnings */
1177 return 3;
1178} 472}
1179 473
1180static int parse_timeout(const char *wps_bufptr, 474static int parse_timeout_tag(struct skin_element *element,
1181 struct wps_token *token, 475 struct wps_token *token,
1182 struct wps_data *wps_data) 476 struct wps_data *wps_data)
1183{ 477{
1184 int skip = 0; 478 (void)wps_data;
1185 int val = 0; 479 int val = 0;
1186 bool have_point = false; 480 if (element->params_count == 0)
1187 bool have_tenth = false;
1188
1189 (void)wps_data; /* Kill the warning */
1190 if (*wps_bufptr == '(')
1191 {
1192 wps_bufptr++;
1193 skip++;
1194 while ( isdigit(*wps_bufptr) || *wps_bufptr == '.' )
1195 {
1196 if (*wps_bufptr != '.')
1197 {
1198 val *= 10;
1199 val += *wps_bufptr - '0';
1200 if (have_point)
1201 {
1202 have_tenth = true;
1203 wps_bufptr++;
1204 skip++;
1205 break;
1206 }
1207 }
1208 else
1209 have_point = true;
1210
1211 wps_bufptr++;
1212 skip++;
1213 }
1214 if (*wps_bufptr != ')')
1215 return -1;
1216 skip++;
1217 }
1218 if (have_tenth == false)
1219 val *= 10;
1220
1221 if (val == 0 && skip == 0)
1222 { 481 {
1223 /* decide what to do if no value was specified */
1224 switch (token->type) 482 switch (token->type)
1225 { 483 {
1226 case WPS_TOKEN_SUBLINE_TIMEOUT: 484 case SKIN_TOKEN_SUBLINE_TIMEOUT:
1227 return -1; 485 return -1;
1228 case WPS_TOKEN_BUTTON_VOLUME: 486 case SKIN_TOKEN_BUTTON_VOLUME:
1229 case WPS_TOKEN_TRACK_STARTING: 487 case SKIN_TOKEN_TRACK_STARTING:
1230 case WPS_TOKEN_TRACK_ENDING: 488 case SKIN_TOKEN_TRACK_ENDING:
489 case SKIN_TOKEN_LASTTOUCH:
1231 val = 10; 490 val = 10;
1232 break; 491 break;
492 default:
493 break;
1233 } 494 }
1234 } 495 }
496 else
497 val = element->params[0].data.number;
1235 token->value.i = val; 498 token->value.i = val;
1236 499 if (token->type == SKIN_TOKEN_SUBLINE_TIMEOUT)
1237 return skip; 500 curr_line->timeout = val * TIMEOUT_UNIT;
501 return 0;
1238} 502}
1239 503
1240static int parse_progressbar(const char *wps_bufptr, 504static int parse_progressbar_tag(struct skin_element* element,
1241 struct wps_token *token, 505 struct wps_token *token,
1242 struct wps_data *wps_data) 506 struct wps_data *wps_data)
1243{ 507{
1244 /* %pb or %pb|filename|x|y|width|height|
1245 using - for any of the params uses "sane" values */
1246#ifdef HAVE_LCD_BITMAP 508#ifdef HAVE_LCD_BITMAP
1247 enum { 509 struct progressbar *pb;
1248 PB_X = 0, 510 struct skin_token_list *item;
1249 PB_Y,
1250 PB_WIDTH,
1251 PB_HEIGHT,
1252 PB_FILENAME,
1253 };
1254 const char *filename;
1255 int x, y, height, width;
1256 uint32_t set = 0;
1257 const char *ptr = wps_bufptr;
1258 struct progressbar *pb = skin_buffer_alloc(sizeof(struct progressbar));
1259 struct skin_token_list *item = new_skin_token_list_item(token, pb);
1260
1261 if (!pb || !item)
1262 return WPS_ERROR_INVALID_PARAM;
1263
1264 struct viewport *vp = &curr_vp->vp; 511 struct viewport *vp = &curr_vp->vp;
1265 /* we need to know what line number (viewport relative) this pb is, 512 struct skin_tag_parameter *param = element->params;
1266 * so count them... */ 513
1267 int line_num = -1; 514 if (element->params_count == 0 &&
1268 struct skin_line *line = curr_vp->lines; 515 element->tag->type != SKIN_TOKEN_PROGRESSBAR)
1269 while (line) 516 return 0; /* nothing to do */
1270 { 517 pb = (struct progressbar*)skin_buffer_alloc(sizeof(struct progressbar));
1271 line_num++; 518
1272 line = line->next; 519 token->value.data = pb;
1273 } 520
1274 if (curr_vp->label != VP_DEFAULT_LABEL) 521 if (!pb)
1275 line_num--; 522 return WPS_ERROR_INVALID_PARAM;
1276 pb->vp = vp; 523 pb->vp = vp;
1277 pb->have_bitmap_pb = false; 524 pb->have_bitmap_pb = false;
1278 pb->bm.data = NULL; /* no bitmap specified */ 525 pb->bm.data = NULL; /* no bitmap specified */
1279 pb->follow_lang_direction = follow_lang_direction > 0; 526 pb->follow_lang_direction = follow_lang_direction > 0;
1280 pb->draw = false; 527
1281 528 if (element->params_count == 0)
1282 if (*wps_bufptr != '(') /* regular old style */
1283 { 529 {
1284 pb->x = 0; 530 pb->x = 0;
1285 pb->width = vp->width; 531 pb->width = vp->width;
1286 pb->height = SYSFONT_HEIGHT-2; 532 pb->height = SYSFONT_HEIGHT-2;
1287 pb->y = -line_num - 1; /* Will be computed during the rendering */ 533 pb->y = -1; /* Will be computed during the rendering */
1288 if (token->type == WPS_TOKEN_VOLUME || token->type == WPS_TOKEN_BATTERY_PERCENT) 534 pb->type = element->tag->type;
1289 return 0; /* dont add it, let the regular token handling do the work */
1290 pb->type = token->type;
1291 add_to_ll_chain(&wps_data->progressbars, item);
1292 return 0; 535 return 0;
1293 } 536 }
1294 ptr = wps_bufptr + 1; 537
1295 538 item = new_skin_token_list_item(token, pb);
1296 if (!(ptr = parse_list("dddds", &set, ',', ptr, 539 if (!item)
1297 &x, &y, &width, &height, &filename))) 540 return -1;
1298 return WPS_ERROR_INVALID_PARAM; 541 add_to_ll_chain(&wps_data->progressbars, item);
1299 542
1300 if (LIST_VALUE_PARSED(set, PB_FILENAME)) /* filename */ 543 /* (x,y,width,height,filename) */
1301 pb->bm.data = (char*)filename; 544 if (!isdefault(param))
1302 545 pb->x = param->data.number;
1303 if (LIST_VALUE_PARSED(set, PB_X)) /* x */
1304 pb->x = x;
1305 else 546 else
1306 pb->x = vp->x; 547 pb->x = vp->x;
1307 548 param++;
1308 if (LIST_VALUE_PARSED(set, PB_WIDTH)) /* width */ 549
1309 { 550 if (!isdefault(param))
1310 /* A zero width causes a divide-by-zero error later, so reject it */ 551 pb->y = param->data.number;
1311 if (width == 0) 552 else
1312 return WPS_ERROR_INVALID_PARAM; 553 pb->y = -1; /* computed at rendering */
1313 554 param++;
1314 pb->width = width; 555
1315 } 556 if (!isdefault(param))
557 pb->width = param->data.number;
1316 else 558 else
1317 pb->width = vp->width - pb->x; 559 pb->width = vp->width - pb->x;
1318 560 param++;
1319 if (LIST_VALUE_PARSED(set, PB_HEIGHT)) /* height, default to font height */ 561
562 if (!isdefault(param))
1320 { 563 {
1321 /* A zero height makes no sense - reject it */ 564 /* A zero height makes no sense - reject it */
1322 if (height == 0) 565 if (param->data.number == 0)
1323 return WPS_ERROR_INVALID_PARAM; 566 return WPS_ERROR_INVALID_PARAM;
1324 567
1325 pb->height = height; 568 pb->height = param->data.number;
1326 } 569 }
1327 else 570 else
1328 { 571 {
@@ -1337,30 +580,26 @@ static int parse_progressbar(const char *wps_bufptr,
1337#endif 580#endif
1338 } 581 }
1339 } 582 }
1340 583 param++;
1341 if (LIST_VALUE_PARSED(set, PB_Y)) /* y */ 584 if (!isdefault(param))
1342 pb->y = y; 585 pb->bm.data = param->data.text;
1343 else 586
1344 pb->y = -line_num - 1; /* Will be computed during the rendering */ 587
1345 588 if (token->type == SKIN_TOKEN_VOLUME)
1346 if (*ptr != ')') 589 token->type = SKIN_TOKEN_VOLUMEBAR;
1347 return WPS_ERROR_INVALID_PARAM; 590 else if (token->type == SKIN_TOKEN_BATTERY_PERCENT)
1348 591 token->type = SKIN_TOKEN_BATTERY_PERCENTBAR;
1349 add_to_ll_chain(&wps_data->progressbars, item);
1350 if (token->type == WPS_TOKEN_VOLUME)
1351 token->type = WPS_TOKEN_VOLUMEBAR;
1352 else if (token->type == WPS_TOKEN_BATTERY_PERCENT)
1353 token->type = WPS_TOKEN_BATTERY_PERCENTBAR;
1354 pb->type = token->type; 592 pb->type = token->type;
1355 593
1356 return ptr+1-wps_bufptr; 594 return 0;
595
1357#else 596#else
1358 (void)wps_bufptr; 597 (void)element;
1359 if (token->type != WPS_TOKEN_VOLUME && 598 if (token->type == SKIN_TOKEN_PROGRESSBAR ||
1360 token->type != WPS_TOKEN_BATTERY_PERCENTBAR) 599 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR)
1361 { 600 {
1362 wps_data->full_line_progressbar = 601 wps_data->full_line_progressbar =
1363 token->type == WPS_TOKEN_PLAYER_PROGRESSBAR; 602 token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR;
1364 } 603 }
1365 return 0; 604 return 0;
1366 605
@@ -1368,32 +607,32 @@ static int parse_progressbar(const char *wps_bufptr,
1368} 607}
1369 608
1370#ifdef HAVE_ALBUMART 609#ifdef HAVE_ALBUMART
1371static int parse_albumart_load(const char *wps_bufptr, 610static int parse_albumart_load(struct skin_element* element,
1372 struct wps_token *token, 611 struct wps_token *token,
1373 struct wps_data *wps_data) 612 struct wps_data *wps_data)
1374{ 613{
1375 const char *ptr = wps_bufptr;
1376 struct dim dimensions; 614 struct dim dimensions;
1377 int albumart_slot; 615 int albumart_slot;
1378 bool swap_for_rtl = lang_is_rtl() && follow_lang_direction; 616 bool swap_for_rtl = lang_is_rtl() && follow_lang_direction;
1379 struct skin_albumart *aa = skin_buffer_alloc(sizeof(struct skin_albumart)); 617 struct skin_albumart *aa =
618 (struct skin_albumart *)skin_buffer_alloc(sizeof(struct skin_albumart));
1380 (void)token; /* silence warning */ 619 (void)token; /* silence warning */
1381 if (!aa) 620 if (!aa)
1382 return skip_end_of_line(wps_bufptr); 621 return -1;
1383 622
1384 /* reset albumart info in wps */ 623 /* reset albumart info in wps */
1385 aa->width = -1; 624 aa->width = -1;
1386 aa->height = -1; 625 aa->height = -1;
1387 aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ 626 aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1388 aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ 627 aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
1389 aa->vp = &curr_vp->vp;
1390 628
1391 if (*ptr != '(') 629 aa->x = element->params[0].data.number;
1392 return WPS_ERROR_INVALID_PARAM; 630 aa->y = element->params[1].data.number;
1393 ptr++; 631 aa->width = element->params[2].data.number;
1394 /* format: %Cl|x|y|[[l|c|r]mwidth]|[[t|c|b]mheight]| */ 632 aa->height = element->params[3].data.number;
1395 if (!(ptr = parse_list("dddd", NULL,',',ptr, &aa->x, &aa->y, &aa->width, &aa->height))) 633
1396 return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */ 634 aa->vp = &curr_vp->vp;
635 aa->draw_handle = -1;
1397 636
1398 /* if we got here, we parsed everything ok .. ! */ 637 /* if we got here, we parsed everything ok .. ! */
1399 if (aa->width < 0) 638 if (aa->width < 0)
@@ -1410,7 +649,6 @@ static int parse_albumart_load(const char *wps_bufptr,
1410 aa->x = LCD_WIDTH - (aa->x + aa->width); 649 aa->x = LCD_WIDTH - (aa->x + aa->width);
1411 650
1412 aa->state = WPS_ALBUMART_LOAD; 651 aa->state = WPS_ALBUMART_LOAD;
1413 aa->draw = false;
1414 wps_data->albumart = aa; 652 wps_data->albumart = aa;
1415 653
1416 dimensions.width = aa->width; 654 dimensions.width = aa->width;
@@ -1420,11 +658,10 @@ static int parse_albumart_load(const char *wps_bufptr,
1420 658
1421 if (0 <= albumart_slot) 659 if (0 <= albumart_slot)
1422 wps_data->playback_aa_slot = albumart_slot; 660 wps_data->playback_aa_slot = albumart_slot;
1423 661
1424 if (*ptr == ',') 662 if (element->params_count > 4 && !isdefault(&element->params[4]))
1425 { 663 {
1426 ptr++; 664 switch (*element->params[4].data.text)
1427 switch (*ptr)
1428 { 665 {
1429 case 'l': 666 case 'l':
1430 case 'L': 667 case 'L':
@@ -1445,12 +682,10 @@ static int parse_albumart_load(const char *wps_bufptr,
1445 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT; 682 aa->xalign = WPS_ALBUMART_ALIGN_RIGHT;
1446 break; 683 break;
1447 } 684 }
1448 ptr++;
1449 } 685 }
1450 if (*ptr == ',') 686 if (element->params_count > 5 && !isdefault(&element->params[5]))
1451 { 687 {
1452 ptr++; 688 switch (*element->params[5].data.text)
1453 switch (*ptr)
1454 { 689 {
1455 case 't': 690 case 't':
1456 case 'T': 691 case 'T':
@@ -1465,32 +700,10 @@ static int parse_albumart_load(const char *wps_bufptr,
1465 aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM; 700 aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM;
1466 break; 701 break;
1467 } 702 }
1468 ptr++;
1469 } 703 }
1470 if (*ptr != ')') 704 return 0;
1471 return WPS_ERROR_INVALID_PARAM;
1472
1473 return skip_end_of_line(wps_bufptr);
1474} 705}
1475 706
1476static int parse_albumart_display(const char *wps_bufptr,
1477 struct wps_token *token,
1478 struct wps_data *wps_data)
1479{
1480 (void)wps_bufptr;
1481 (void)token;
1482 if (wps_data->albumart)
1483 {
1484 wps_data->albumart->vp = &curr_vp->vp;
1485 }
1486#if 0
1487 /* the old code did this so keep it here for now...
1488 * this is to allow the posibility to showing the next tracks AA! */
1489 if (wps_bufptr+1 == 'n')
1490 return 1;
1491#endif
1492 return 0;
1493};
1494#endif /* HAVE_ALBUMART */ 707#endif /* HAVE_ALBUMART */
1495 708
1496#ifdef HAVE_TOUCHSCREEN 709#ifdef HAVE_TOUCHSCREEN
@@ -1520,8 +733,9 @@ static const struct touchaction touchactions[] = {
1520#endif 733#endif
1521}; 734};
1522 735
1523static int parse_touchregion(const char *wps_bufptr, 736static int parse_touchregion(struct skin_element *element,
1524 struct wps_token *token, struct wps_data *wps_data) 737 struct wps_token *token,
738 struct wps_data *wps_data)
1525{ 739{
1526 (void)token; 740 (void)token;
1527 unsigned i, imax; 741 unsigned i, imax;
@@ -1533,7 +747,7 @@ static int parse_touchregion(const char *wps_bufptr,
1533 int x,y,w,h; 747 int x,y,w,h;
1534 char temp[20]; 748 char temp[20];
1535 749
1536 /* format: %T|x|y|width|height|action| 750 /* format: %T(x,y,width,height,action)
1537 * if action starts with & the area must be held to happen 751 * if action starts with & the area must be held to happen
1538 * action is one of: 752 * action is one of:
1539 * play - play/pause playback 753 * play - play/pause playback
@@ -1554,35 +768,22 @@ static int parse_touchregion(const char *wps_bufptr,
1554 * voldown - decrease volume by one step 768 * voldown - decrease volume by one step
1555 */ 769 */
1556 770
1557 771
1558 if (*ptr != '(') 772 region = (struct touchregion*)skin_buffer_alloc(sizeof(struct touchregion));
1559 return WPS_ERROR_INVALID_PARAM;
1560 ptr++;
1561
1562 if (!(ptr = parse_list("dddds", NULL, ',', ptr, &x, &y, &w, &h, &action)))
1563 return WPS_ERROR_INVALID_PARAM;
1564
1565 /* Check there is a terminating ) */
1566 if (*ptr != ')')
1567 return WPS_ERROR_INVALID_PARAM;
1568
1569 region = skin_buffer_alloc(sizeof(struct touchregion));
1570 if (!region) 773 if (!region)
1571 return WPS_ERROR_INVALID_PARAM; 774 return WPS_ERROR_INVALID_PARAM;
1572 775
1573 /* should probably do some bounds checking here with the viewport... but later */ 776 /* should probably do some bounds checking here with the viewport... but later */
1574 region->action = ACTION_NONE; 777 region->action = ACTION_NONE;
1575 region->x = x; 778 region->x = element->params[0].data.number;
1576 region->y = y; 779 region->y = element->params[1].data.number;
1577 region->width = w; 780 region->width = element->params[2].data.number;
1578 region->height = h; 781 region->height = element->params[3].data.number;
1579 region->wvp = curr_vp; 782 region->wvp = curr_vp;
1580 region->armed = false; 783 region->armed = false;
1581 region->reverse_bar = false; 784 region->reverse_bar = false;
785 action = element->params[4].data.text;
1582 786
1583 end = strchr(action, ')');
1584 if (!end || (size_t)(end-action+1) > sizeof temp)
1585 return WPS_ERROR_INVALID_PARAM;
1586 strlcpy(temp, action, end-action+1); 787 strlcpy(temp, action, end-action+1);
1587 action = temp; 788 action = temp;
1588 789
@@ -1625,449 +826,46 @@ static int parse_touchregion(const char *wps_bufptr,
1625 if (!item) 826 if (!item)
1626 return WPS_ERROR_INVALID_PARAM; 827 return WPS_ERROR_INVALID_PARAM;
1627 add_to_ll_chain(&wps_data->touchregions, item); 828 add_to_ll_chain(&wps_data->touchregions, item);
1628 return skip_end_of_line(wps_bufptr); 829 return 0;
1629} 830}
1630#endif 831#endif
1631 832
1632/* Parse a generic token from the given string. Return the length read */ 833static bool check_feature_tag(const int type)
1633static int parse_token(const char *wps_bufptr, struct wps_data *wps_data)
1634{ 834{
1635 int skip = 0, taglen = 0, ret;
1636 struct wps_token *token = wps_data->tokens + wps_data->num_tokens;
1637 const struct wps_tag *tag;
1638 memset(token, 0, sizeof(*token));
1639
1640 switch(*wps_bufptr)
1641 {
1642
1643 case '%':
1644 case '<':
1645 case '|':
1646 case '>':
1647 case ';':
1648 case '#':
1649 case ')':
1650 case '(':
1651 case ',':
1652 /* escaped characters */
1653 token->type = WPS_TOKEN_CHARACTER;
1654 token->value.c = *wps_bufptr;
1655 taglen = 1;
1656 wps_data->num_tokens++;
1657 break;
1658
1659 case '?':
1660 /* conditional tag */
1661 token->type = WPS_TOKEN_CONDITIONAL;
1662 level++;
1663 condindex[level] = wps_data->num_tokens;
1664 numoptions[level] = 1;
1665 wps_data->num_tokens++;
1666 ret = parse_token(wps_bufptr + 1, wps_data);
1667 if (ret < 0) return ret;
1668 taglen = 1 + ret;
1669 break;
1670
1671 default:
1672 /* find what tag we have */
1673 for (tag = all_tags;
1674 strncmp(wps_bufptr, tag->name, strlen(tag->name)) != 0;
1675 tag++) ;
1676
1677 taglen = (tag->type != WPS_TOKEN_UNKNOWN) ? strlen(tag->name) : 2;
1678 token->type = tag->type;
1679 curr_line->curr_subline->line_type |= tag->refresh_type;
1680
1681 /* if the tag has a special parsing function, we call it */
1682 if (tag->parse_func)
1683 {
1684 ret = tag->parse_func(wps_bufptr + taglen, token, wps_data);
1685 if (ret < 0) return ret;
1686 skip += ret;
1687 }
1688
1689 /* Some tags we don't want to save as tokens */
1690 if (tag->type == WPS_NO_TOKEN)
1691 break;
1692
1693 /* tags that start with 'F', 'I' or 'D' are for the next file */
1694 if ( *(tag->name) == 'I' || *(tag->name) == 'F' ||
1695 *(tag->name) == 'D')
1696 token->next = true;
1697
1698 wps_data->num_tokens++;
1699 break;
1700 }
1701
1702 skip += taglen;
1703 return skip;
1704}
1705
1706
1707/*
1708 * Returns the number of bytes to skip the buf pointer to access the false
1709 * branch in a _binary_ conditional
1710 *
1711 * That is:
1712 * - before the '|' if we have a false branch, (%?<true|false> -> %?<|false>)
1713 * - or before the closing '>' if there's no false branch (%?<true> -> %?<>)
1714 *
1715 * depending on the features of a target it's not called from check_feature_tag,
1716 * hence the __attribute__ or it issues compiler warnings
1717 *
1718 **/
1719
1720static int find_false_branch(const char *wps_bufptr) __attribute__((unused));
1721static int find_false_branch(const char *wps_bufptr)
1722{
1723 const char *buf = wps_bufptr;
1724 /* wps_bufptr is after the opening '<', hence level = 1*/
1725 int level = 1;
1726 char ch;
1727 do
1728 {
1729 ch = *buf;
1730 if (ch == '%')
1731 { /* filter out the characters we check later if they're printed
1732 * as literals */
1733 ch = *(++buf);
1734 if (ch == '<' || ch == '>' || ch == '|')
1735 continue;
1736 /* else: some tags/printed literals we skip over */
1737 }
1738 else if (ch == '<') /* nested conditional */
1739 level++;
1740 else if (ch == '>')
1741 { /* closed our or a nested conditional,
1742 * do NOT skip over the '>' so that wps_parse() sees it for closing
1743 * if it is the closing one for our conditional */
1744 level--;
1745 }
1746 else if (ch == '|' && level == 1)
1747 { /* we found our separator, point before and get out */
1748 break;
1749 }
1750 /* if level is 0, we don't have a false branch */
1751 } while (level > 0 && *(++buf));
1752
1753 return buf - wps_bufptr;
1754}
1755
1756/*
1757 * returns the number of bytes to get the appropriate branch of a binary
1758 * conditional
1759 *
1760 * That means:
1761 * - if a feature is available, it returns 0 to not skip anything
1762 * - if the feature is not available, skip to the false branch and don't
1763 * parse the true branch at all
1764 *
1765 * */
1766static int check_feature_tag(const char *wps_bufptr, const int type)
1767{
1768 (void)wps_bufptr;
1769 switch (type) 835 switch (type)
1770 { 836 {
1771 case WPS_TOKEN_RTC_PRESENT: 837 case SKIN_TOKEN_RTC_PRESENT:
1772#if CONFIG_RTC 838#if CONFIG_RTC
1773 return 0; 839 return true;
1774#else 840#else
1775 return find_false_branch(wps_bufptr); 841 return false;
1776#endif /* CONFIG_RTC */ 842#endif
1777 843 case SKIN_TOKEN_HAVE_RECORDING:
1778 case WPS_TOKEN_HAVE_RECORDING:
1779#ifdef HAVE_RECORDING 844#ifdef HAVE_RECORDING
1780 return 0; 845 return true;
1781#else 846#else
1782 return find_false_branch(wps_bufptr); 847 return false;
1783#endif /* HAVE_RECORDING */ 848#endif
1784 849 case SKIN_TOKEN_HAVE_TUNER:
1785 case WPS_TOKEN_HAVE_TUNER:
1786#if CONFIG_TUNER 850#if CONFIG_TUNER
1787 if (radio_hardware_present()) 851 if (radio_hardware_present())
1788 return 0; 852 return true;
1789#endif /* CONFIG_TUNER */ 853#endif
1790 return find_false_branch(wps_bufptr); 854 return false;
1791 855
1792#if CONFIG_TUNER 856#if CONFIG_TUNER
1793 case WPS_TOKEN_HAVE_RDS: 857 case SKIN_TOKEN_HAVE_RDS:
1794#ifdef HAVE_RDS_CAP 858#ifdef HAVE_RDS_CAP
1795 return 0; 859 return true;
1796#else 860#else
1797 return find_false_branch(wps_bufptr); 861 return false;
1798#endif /* HAVE_RDS_CAP */ 862#endif /* HAVE_RDS_CAP */
1799#endif /* CONFIG_TUNER */ 863#endif /* CONFIG_TUNER */
1800 default: /* not a tag we care about, just don't skip */ 864 default: /* not a tag we care about, just don't skip */
1801 return 0; 865 return true;
1802 }
1803}
1804
1805
1806/* Parses the WPS.
1807 data is the pointer to the structure where the parsed WPS should be stored.
1808 It is initialised.
1809 wps_bufptr points to the string containing the WPS tags */
1810#define TOKEN_BLOCK_SIZE 128
1811static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
1812{
1813 if (!data || !wps_bufptr || !*wps_bufptr)
1814 return false;
1815 enum wps_parse_error fail = PARSE_OK;
1816 int ret;
1817 int max_tokens = TOKEN_BLOCK_SIZE;
1818 size_t buf_free = 0;
1819 line_number = 0;
1820 level = -1;
1821
1822 /* allocate enough RAM for a reasonable skin, grow as needed.
1823 * Free any used RAM before loading the images to be 100% RAM efficient */
1824 data->tokens = (struct wps_token *)skin_buffer_grab(&buf_free);
1825 if (sizeof(struct wps_token)*max_tokens >= buf_free)
1826 return false;
1827 skin_buffer_increment(max_tokens * sizeof(struct wps_token), false);
1828 data->num_tokens = 0;
1829
1830#if LCD_DEPTH > 1
1831 /* Backdrop defaults to the setting unless %X is used, so set it now */
1832 if (global_settings.backdrop_file[0])
1833 {
1834 data->backdrop = "-";
1835 }
1836#endif
1837
1838 while (*wps_bufptr && !fail)
1839 {
1840 if (follow_lang_direction)
1841 follow_lang_direction--;
1842 /* first make sure there is enough room for tokens */
1843 if (max_tokens <= data->num_tokens + 5)
1844 {
1845 int extra_tokens = TOKEN_BLOCK_SIZE;
1846 size_t needed = extra_tokens * sizeof(struct wps_token);
1847 /* do some smarts here to grow the array a bit */
1848 if (skin_buffer_freespace() < needed)
1849 {
1850 fail = PARSE_FAIL_LIMITS_EXCEEDED;
1851 break;
1852 }
1853 skin_buffer_increment(needed, false);
1854 max_tokens += extra_tokens;
1855 }
1856
1857 switch(*wps_bufptr++)
1858 {
1859
1860 /* Regular tag */
1861 case '%':
1862 if ((ret = parse_token(wps_bufptr, data)) < 0)
1863 {
1864 fail = PARSE_FAIL_COND_INVALID_PARAM;
1865 break;
1866 }
1867 else if (level >= WPS_MAX_COND_LEVEL - 1)
1868 {
1869 fail = PARSE_FAIL_LIMITS_EXCEEDED;
1870 break;
1871 }
1872 wps_bufptr += ret;
1873 break;
1874
1875 /* Alternating sublines separator */
1876 case ';':
1877 if (level >= 0) /* there are unclosed conditionals */
1878 {
1879 fail = PARSE_FAIL_UNCLOSED_COND;
1880 break;
1881 }
1882
1883 if (!skin_start_new_subline(curr_line, data->num_tokens))
1884 fail = PARSE_FAIL_LIMITS_EXCEEDED;
1885
1886 break;
1887
1888 /* Conditional list start */
1889 case '<':
1890 if (data->tokens[data->num_tokens-2].type != WPS_TOKEN_CONDITIONAL)
1891 {
1892 fail = PARSE_FAIL_COND_SYNTAX_ERROR;
1893 break;
1894 }
1895 wps_bufptr += check_feature_tag(wps_bufptr,
1896 data->tokens[data->num_tokens-1].type);
1897 data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_START;
1898 lastcond[level] = data->num_tokens++;
1899 break;
1900
1901 /* Conditional list end */
1902 case '>':
1903 if (level < 0) /* not in a conditional, invalid char */
1904 {
1905 fail = PARSE_FAIL_INVALID_CHAR;
1906 break;
1907 }
1908
1909 data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_END;
1910 if (lastcond[level])
1911 data->tokens[lastcond[level]].value.i = data->num_tokens;
1912 else
1913 {
1914 fail = PARSE_FAIL_COND_SYNTAX_ERROR;
1915 break;
1916 }
1917
1918 lastcond[level] = 0;
1919 data->num_tokens++;
1920 data->tokens[condindex[level]].value.i = numoptions[level];
1921 level--;
1922 break;
1923
1924 /* Conditional list option */
1925 case '|':
1926 if (level < 0) /* not in a conditional, invalid char */
1927 {
1928 fail = PARSE_FAIL_INVALID_CHAR;
1929 break;
1930 }
1931
1932 data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_OPTION;
1933 if (lastcond[level])
1934 data->tokens[lastcond[level]].value.i = data->num_tokens;
1935 else
1936 {
1937 fail = PARSE_FAIL_COND_SYNTAX_ERROR;
1938 break;
1939 }
1940
1941 lastcond[level] = data->num_tokens;
1942 numoptions[level]++;
1943 data->num_tokens++;
1944 break;
1945
1946 /* Comment */
1947 case '#':
1948 if (level >= 0) /* there are unclosed conditionals */
1949 {
1950 fail = PARSE_FAIL_UNCLOSED_COND;
1951 break;
1952 }
1953
1954 wps_bufptr += skip_end_of_line(wps_bufptr);
1955 break;
1956
1957 /* End of this line */
1958 case '\n':
1959 if (level >= 0) /* there are unclosed conditionals */
1960 {
1961 fail = PARSE_FAIL_UNCLOSED_COND;
1962 break;
1963 }
1964 /* add a new token for the \n so empty lines are correct */
1965 data->tokens[data->num_tokens].type = WPS_TOKEN_CHARACTER;
1966 data->tokens[data->num_tokens].value.c = '\n';
1967 data->tokens[data->num_tokens].next = false;
1968 data->num_tokens++;
1969
1970 if (!skin_start_new_line(curr_vp, data->num_tokens))
1971 {
1972 fail = PARSE_FAIL_LIMITS_EXCEEDED;
1973 break;
1974 }
1975 line_number++;
1976
1977 break;
1978
1979 /* String */
1980 default:
1981 {
1982 unsigned int len = 1;
1983 const char *string_start = wps_bufptr - 1;
1984
1985 /* find the length of the string */
1986 while (*wps_bufptr && *wps_bufptr != '#' &&
1987 *wps_bufptr != '%' && *wps_bufptr != ';' &&
1988 *wps_bufptr != '<' && *wps_bufptr != '>' &&
1989 *wps_bufptr != '|' && *wps_bufptr != '\n')
1990 {
1991 wps_bufptr++;
1992 len++;
1993 }
1994
1995 /* look if we already have that string */
1996 char *str;
1997 bool found = false;
1998 struct skin_token_list *list = data->strings;
1999 while (list)
2000 {
2001 str = (char*)list->token->value.data;
2002 found = (strlen(str) == len &&
2003 strncmp(string_start, str, len) == 0);
2004 if (found)
2005 break; /* break here because the list item is
2006 used if its found */
2007 list = list->next;
2008 }
2009 /* If a matching string is found, found is true and i is
2010 the index of the string. If not, found is false */
2011
2012 if (!found)
2013 {
2014 /* new string */
2015 str = (char*)skin_buffer_alloc(len+1);
2016 if (!str)
2017 {
2018 fail = PARSE_FAIL_LIMITS_EXCEEDED;
2019 break;
2020 }
2021 strlcpy(str, string_start, len+1);
2022 struct skin_token_list *item =
2023 new_skin_token_list_item(&data->tokens[data->num_tokens], str);
2024 if(!item)
2025 {
2026 fail = PARSE_FAIL_LIMITS_EXCEEDED;
2027 break;
2028 }
2029 add_to_ll_chain(&data->strings, item);
2030 }
2031 else
2032 {
2033 /* another occurrence of an existing string */
2034 data->tokens[data->num_tokens].value.data = list->token->value.data;
2035 }
2036 data->tokens[data->num_tokens].type = WPS_TOKEN_STRING;
2037 data->num_tokens++;
2038 }
2039 break;
2040 }
2041 }
2042
2043 if (!fail && level >= 0) /* there are unclosed conditionals */
2044 fail = PARSE_FAIL_UNCLOSED_COND;
2045
2046 if (*wps_bufptr && !fail)
2047 /* one of the limits of the while loop was exceeded */
2048 fail = PARSE_FAIL_LIMITS_EXCEEDED;
2049
2050 /* Success! */
2051 curr_line->curr_subline->last_token_idx = data->num_tokens;
2052 data->tokens[data->num_tokens++].type = WPS_NO_TOKEN;
2053 /* freeup unused tokens */
2054 skin_buffer_free_from_front(sizeof(struct wps_token)
2055 * (max_tokens - data->num_tokens));
2056
2057#ifdef DEBUG_SKIN_ENGINE
2058 if (debug)
2059 {
2060 print_debug_info(data, fail, line_number);
2061 debug_skin_usage();
2062 } 866 }
2063#else
2064 (void)debug;
2065#endif
2066
2067 return (fail == 0);
2068} 867}
2069 868
2070
2071/* 869/*
2072 * initial setup of wps_data; does reset everything 870 * initial setup of wps_data; does reset everything
2073 * except fields which need to survive, i.e. 871 * except fields which need to survive, i.e.
@@ -2075,6 +873,7 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
2075 **/ 873 **/
2076static void skin_data_reset(struct wps_data *wps_data) 874static void skin_data_reset(struct wps_data *wps_data)
2077{ 875{
876 wps_data->tree = NULL;
2078#ifdef HAVE_LCD_BITMAP 877#ifdef HAVE_LCD_BITMAP
2079 wps_data->images = NULL; 878 wps_data->images = NULL;
2080 wps_data->progressbars = NULL; 879 wps_data->progressbars = NULL;
@@ -2085,8 +884,6 @@ static void skin_data_reset(struct wps_data *wps_data)
2085#ifdef HAVE_TOUCHSCREEN 884#ifdef HAVE_TOUCHSCREEN
2086 wps_data->touchregions = NULL; 885 wps_data->touchregions = NULL;
2087#endif 886#endif
2088 wps_data->viewports = NULL;
2089 wps_data->strings = NULL;
2090#ifdef HAVE_ALBUMART 887#ifdef HAVE_ALBUMART
2091 wps_data->albumart = NULL; 888 wps_data->albumart = NULL;
2092 if (wps_data->playback_aa_slot >= 0) 889 if (wps_data->playback_aa_slot >= 0)
@@ -2095,8 +892,6 @@ static void skin_data_reset(struct wps_data *wps_data)
2095 wps_data->playback_aa_slot = -1; 892 wps_data->playback_aa_slot = -1;
2096 } 893 }
2097#endif 894#endif
2098 wps_data->tokens = NULL;
2099 wps_data->num_tokens = 0;
2100 895
2101#ifdef HAVE_LCD_BITMAP 896#ifdef HAVE_LCD_BITMAP
2102 wps_data->peak_meter_enabled = false; 897 wps_data->peak_meter_enabled = false;
@@ -2119,6 +914,7 @@ static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char
2119{ 914{
2120 (void)wps_data; /* only needed for remote targets */ 915 (void)wps_data; /* only needed for remote targets */
2121 char img_path[MAX_PATH]; 916 char img_path[MAX_PATH];
917 int fd;
2122 get_image_filename(bitmap->data, bmpdir, 918 get_image_filename(bitmap->data, bmpdir,
2123 img_path, sizeof(img_path)); 919 img_path, sizeof(img_path));
2124 920
@@ -2131,14 +927,24 @@ static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char
2131#endif 927#endif
2132 format = FORMAT_ANY|FORMAT_TRANSPARENT; 928 format = FORMAT_ANY|FORMAT_TRANSPARENT;
2133 929
2134 size_t max_buf; 930 fd = open(img_path, O_RDONLY);
2135 char* imgbuf = (char*)skin_buffer_grab(&max_buf); 931 if (fd < 0)
932 return false;
933 size_t buf_size = read_bmp_file(img_path, bitmap, 0,
934 format|FORMAT_RETURN_SIZE, NULL);
935 char* imgbuf = (char*)skin_buffer_alloc(buf_size);
936 if (!imgbuf)
937 {
938 close(fd);
939 return NULL;
940 }
941 lseek(fd, 0, SEEK_SET);
2136 bitmap->data = imgbuf; 942 bitmap->data = imgbuf;
2137 int ret = read_bmp_file(img_path, bitmap, max_buf, format, NULL); 943 int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL);
2138 944
945 close(fd);
2139 if (ret > 0) 946 if (ret > 0)
2140 { 947 {
2141 skin_buffer_increment(ret, true);
2142 return true; 948 return true;
2143 } 949 }
2144 else 950 else
@@ -2204,14 +1010,14 @@ static bool skin_load_fonts(struct wps_data *data)
2204{ 1010{
2205 /* don't spit out after the first failue to aid debugging */ 1011 /* don't spit out after the first failue to aid debugging */
2206 bool success = true; 1012 bool success = true;
2207 struct skin_token_list *vp_list; 1013 struct skin_element *vp_list;
2208 int font_id; 1014 int font_id;
2209 /* walk though each viewport and assign its font */ 1015 /* walk though each viewport and assign its font */
2210 for(vp_list = data->viewports; vp_list; vp_list = vp_list->next) 1016 for(vp_list = data->tree; vp_list; vp_list = vp_list->next)
2211 { 1017 {
2212 /* first, find the viewports that have a non-sys/ui-font font */ 1018 /* first, find the viewports that have a non-sys/ui-font font */
2213 struct skin_viewport *skin_vp = 1019 struct skin_viewport *skin_vp =
2214 (struct skin_viewport*)vp_list->token->value.data; 1020 (struct skin_viewport*)vp_list->data;
2215 struct viewport *vp = &skin_vp->vp; 1021 struct viewport *vp = &skin_vp->vp;
2216 1022
2217 1023
@@ -2250,6 +1056,7 @@ static bool skin_load_fonts(struct wps_data *data)
2250 { 1056 {
2251 DEBUGF("Unable to load font %d: '%s.fnt'\n", 1057 DEBUGF("Unable to load font %d: '%s.fnt'\n",
2252 font_id, font->name); 1058 font_id, font->name);
1059 font->name = NULL; /* to stop trying to load it again if we fail */
2253 success = false; 1060 success = false;
2254 font->name = NULL; 1061 font->name = NULL;
2255 continue; 1062 continue;
@@ -2262,6 +1069,277 @@ static bool skin_load_fonts(struct wps_data *data)
2262} 1069}
2263 1070
2264#endif /* HAVE_LCD_BITMAP */ 1071#endif /* HAVE_LCD_BITMAP */
1072static int convert_viewport(struct wps_data *data, struct skin_element* element)
1073{
1074 struct skin_viewport *skin_vp =
1075 (struct skin_viewport *)skin_buffer_alloc(sizeof(struct skin_viewport));
1076 struct screen *display = &screens[curr_screen];
1077
1078 if (!skin_vp)
1079 return CALLBACK_ERROR;
1080
1081 skin_vp->hidden_flags = 0;
1082 skin_vp->label = VP_NO_LABEL;
1083 element->data = skin_vp;
1084 curr_vp = skin_vp;
1085 curr_viewport_element = element;
1086
1087 viewport_set_defaults(&skin_vp->vp, curr_screen);
1088
1089#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1090 skin_vp->start_fgcolour = skin_vp->vp.fg_pattern;
1091 skin_vp->start_bgcolour = skin_vp->vp.bg_pattern;
1092#endif
1093
1094
1095 struct skin_tag_parameter *param = element->params;
1096 if (element->params_count == 0) /* default viewport */
1097 {
1098 if (!data->tree) /* first viewport in the skin */
1099 data->tree = element;
1100 skin_vp->label = VP_DEFAULT_LABEL;
1101 return CALLBACK_OK;
1102 }
1103
1104 if (element->params_count == 6)
1105 {
1106 if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD)
1107 {
1108 if (isdefault(param))
1109 {
1110 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1111 skin_vp->label = VP_INFO_LABEL|VP_DEFAULT_LABEL;
1112 }
1113 else
1114 {
1115 skin_vp->hidden_flags = VP_NEVER_VISIBLE;
1116 skin_vp->label = VP_INFO_LABEL|param->data.text[0];
1117 }
1118 }
1119 else
1120 {
1121 skin_vp->hidden_flags = VP_DRAW_HIDEABLE|VP_DRAW_HIDDEN;
1122 skin_vp->label = param->data.text[0];
1123 }
1124 param++;
1125 }
1126 /* x */
1127 if (!isdefault(param))
1128 {
1129 skin_vp->vp.x = param->data.number;
1130 if (param->data.number < 0)
1131 skin_vp->vp.x += display->lcdwidth;
1132 }
1133 param++;
1134 /* y */
1135 if (!isdefault(param))
1136 {
1137 skin_vp->vp.y = param->data.number;
1138 if (param->data.number < 0)
1139 skin_vp->vp.y += display->lcdheight;
1140 }
1141 param++;
1142 /* width */
1143 if (!isdefault(param))
1144 {
1145 skin_vp->vp.width = param->data.number;
1146 if (param->data.number < 0)
1147 skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x;
1148 }
1149 else
1150 {
1151 skin_vp->vp.width = display->lcdwidth - skin_vp->vp.x;
1152 }
1153 param++;
1154 /* height */
1155 if (!isdefault(param))
1156 {
1157 skin_vp->vp.height = param->data.number;
1158 if (param->data.number < 0)
1159 skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y;
1160 }
1161 else
1162 {
1163 skin_vp->vp.height = display->lcdheight - skin_vp->vp.y;
1164 }
1165 param++;
1166#ifdef HAVE_LCD_BITMAP
1167 /* font */
1168 if (!isdefault(param))
1169 {
1170 skin_vp->vp.font = param->data.number;
1171 }
1172#endif
1173
1174 return CALLBACK_OK;
1175
1176}
1177
1178int skin_element_callback(struct skin_element* element, void* data)
1179{
1180 struct wps_data *wps_data = (struct wps_data *)data;
1181 struct wps_token *token;
1182 parse_function function = NULL;
1183
1184 switch (element->type)
1185 {
1186 /* IMPORTANT: element params are shared, so copy them if needed
1187 * or use then NOW, dont presume they have a long lifespan
1188 */
1189 case TAG:
1190 {
1191 token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token));
1192 memset(token, 0, sizeof(*token));
1193 token->type = element->tag->type;
1194
1195 if ((element->tag->flags&SKIN_REFRESH_ALL) == SKIN_RTC_REFRESH)
1196 {
1197#ifdef CONFIG_RTC
1198 curr_line->update_mode |= SKIN_REFRESH_DYNAMIC;
1199#else
1200 curr_line->update_mode |= SKIN_REFRESH_STATIC;
1201#endif
1202 }
1203 else
1204 curr_line->update_mode |= element->tag->flags&SKIN_REFRESH_ALL;
1205
1206 element->data = token;
1207
1208 /* Some tags need special handling for the tag, so add them here */
1209 switch (token->type)
1210 {
1211 case SKIN_TOKEN_ALIGN_LANGDIRECTION:
1212 follow_lang_direction = 2;
1213 break;
1214 case SKIN_TOKEN_PROGRESSBAR:
1215 case SKIN_TOKEN_VOLUME:
1216 case SKIN_TOKEN_BATTERY_PERCENT:
1217 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1218 function = parse_progressbar_tag;
1219 break;
1220 case SKIN_TOKEN_SUBLINE_TIMEOUT:
1221 case SKIN_TOKEN_BUTTON_VOLUME:
1222 case SKIN_TOKEN_TRACK_STARTING:
1223 case SKIN_TOKEN_TRACK_ENDING:
1224 case SKIN_TOKEN_LASTTOUCH:
1225 function = parse_timeout_tag;
1226 break;
1227#ifdef HAVE_LCD_BITMAP
1228 case SKIN_TOKEN_DISABLE_THEME:
1229 case SKIN_TOKEN_ENABLE_THEME:
1230 case SKIN_TOKEN_DRAW_INBUILTBAR:
1231 function = parse_statusbar_tags;
1232 break;
1233#endif
1234 case SKIN_TOKEN_FILE_DIRECTORY:
1235 token->value.i = element->params[0].data.number;
1236 break;
1237#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1238 case SKIN_TOKEN_VIEWPORT_FGCOLOUR:
1239 case SKIN_TOKEN_VIEWPORT_BGCOLOUR:
1240 function = parse_viewportcolour;
1241 break;
1242 case SKIN_TOKEN_IMAGE_BACKDROP:
1243 function = parse_image_special;
1244 break;
1245#endif
1246 case SKIN_TOKEN_TRANSLATEDSTRING:
1247 case SKIN_TOKEN_SETTING:
1248 function = parse_setting_and_lang;
1249 break;
1250#ifdef HAVE_LCD_BITMAP
1251 case SKIN_TOKEN_VIEWPORT_CUSTOMLIST:
1252 function = parse_playlistview;
1253 break;
1254 case SKIN_TOKEN_LOAD_FONT:
1255 function = parse_font_load;
1256 break;
1257 case SKIN_TOKEN_VIEWPORT_ENABLE:
1258 case SKIN_TOKEN_UIVIEWPORT_ENABLE:
1259 token->value.i = element->params[0].data.text[0];
1260 break;
1261 case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY:
1262 function = parse_image_display;
1263 break;
1264 case SKIN_TOKEN_IMAGE_PRELOAD:
1265 case SKIN_TOKEN_IMAGE_DISPLAY:
1266 function = parse_image_load;
1267 break;
1268#endif
1269#ifdef HAVE_TOUCHSCREEN
1270 case SKIN_TOKEN_TOUCHREGION:
1271 function = parse_touchregion;
1272 break;
1273#endif
1274#ifdef HAVE_ALBUMART
1275 case SKIN_TOKEN_ALBUMART_DISPLAY:
1276 if (wps_data->albumart)
1277 wps_data->albumart->vp = &curr_vp->vp;
1278 break;
1279 case SKIN_TOKEN_ALBUMART_LOAD:
1280 function = parse_albumart_load;
1281 break;
1282#endif
1283 default:
1284 break;
1285 }
1286 if (function)
1287 {
1288 if (function(element, token, wps_data) < 0)
1289 return CALLBACK_ERROR;
1290 }
1291 /* tags that start with 'F', 'I' or 'D' are for the next file */
1292 if ( *(element->tag->name) == 'I' || *(element->tag->name) == 'F' ||
1293 *(element->tag->name) == 'D')
1294 token->next = true;
1295 if (follow_lang_direction > 0 )
1296 follow_lang_direction--;
1297 break;
1298 }
1299 case VIEWPORT:
1300 return convert_viewport(wps_data, element);
1301 case LINE:
1302 {
1303 struct line *line =
1304 (struct line *)skin_buffer_alloc(sizeof(struct line));
1305 line->update_mode = SKIN_REFRESH_STATIC;
1306 line->timeout = DEFAULT_SUBLINE_TIME_MULTIPLIER * TIMEOUT_UNIT;
1307 curr_line = line;
1308 element->data = line;
1309 }
1310 break;
1311 case LINE_ALTERNATOR:
1312 {
1313 struct line_alternator *alternator =
1314 (struct line_alternator *)skin_buffer_alloc(sizeof(struct line_alternator));
1315 alternator->current_line = 0;
1316#ifndef __PCTOOL__
1317 alternator->last_change_tick = current_tick;
1318#endif
1319 element->data = alternator;
1320 }
1321 break;
1322 case CONDITIONAL:
1323 {
1324 struct conditional *conditional =
1325 (struct conditional *)skin_buffer_alloc(sizeof(struct conditional));
1326 conditional->last_value = -1;
1327 conditional->token = element->data;
1328 element->data = conditional;
1329 if (!check_feature_tag(element->tag->type))
1330 {
1331 return FEATURE_NOT_AVAILABLE;
1332 }
1333 return CALLBACK_OK;
1334 }
1335 case TEXT:
1336 curr_line->update_mode |= SKIN_REFRESH_STATIC;
1337 break;
1338 default:
1339 break;
1340 }
1341 return CALLBACK_OK;
1342}
2265 1343
2266/* to setup up the wps-data from a format-buffer (isfile = false) 1344/* to setup up the wps-data from a format-buffer (isfile = false)
2267 from a (wps-)file (isfile = true)*/ 1345 from a (wps-)file (isfile = true)*/
@@ -2298,37 +1376,13 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2298 } 1376 }
2299#endif 1377#endif
2300 1378
1379
2301 skin_data_reset(wps_data); 1380 skin_data_reset(wps_data);
2302 wps_data->wps_loaded = false; 1381 wps_data->wps_loaded = false;
2303 curr_screen = screen; 1382 curr_screen = screen;
2304
2305 /* alloc default viewport, will be fixed up later */
2306 curr_vp = skin_buffer_alloc(sizeof(struct skin_viewport));
2307 if (!curr_vp)
2308 return false;
2309 struct skin_token_list *list = new_skin_token_list_item(NULL, curr_vp);
2310 if (!list)
2311 return false;
2312 add_to_ll_chain(&wps_data->viewports, list);
2313
2314
2315 /* Initialise the first (default) viewport */
2316 curr_vp->label = VP_DEFAULT_LABEL;
2317 curr_vp->hidden_flags = 0;
2318 curr_vp->lines = NULL;
2319
2320 viewport_set_defaults(&curr_vp->vp, screen);
2321#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
2322 curr_vp->start_fgcolour = curr_vp->vp.fg_pattern;
2323 curr_vp->start_bgcolour = curr_vp->vp.bg_pattern;
2324#endif
2325#ifdef HAVE_LCD_BITMAP
2326 curr_vp->vp.font = FONT_UI;
2327#endif
2328
2329 curr_line = NULL; 1383 curr_line = NULL;
2330 if (!skin_start_new_line(curr_vp, 0)) 1384 curr_vp = NULL;
2331 return false; 1385 curr_viewport_element = NULL;
2332 1386
2333 if (isfile) 1387 if (isfile)
2334 { 1388 {
@@ -2364,9 +1418,15 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2364 { 1418 {
2365 wps_buffer = (char*)buf; 1419 wps_buffer = (char*)buf;
2366 } 1420 }
2367 /* parse the WPS source */ 1421#if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
2368 if (!wps_parse(wps_data, wps_buffer, isfile)) { 1422 wps_data->backdrop = "-";
1423#endif
1424 /* parse the skin source */
1425 skin_buffer_save_position();
1426 wps_data->tree = skin_parse(wps_buffer, skin_element_callback, wps_data);
1427 if (!wps_data->tree) {
2369 skin_data_reset(wps_data); 1428 skin_data_reset(wps_data);
1429 skin_buffer_restore_position();
2370 return false; 1430 return false;
2371 } 1431 }
2372 1432
@@ -2387,6 +1447,7 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2387 !skin_load_fonts(wps_data)) 1447 !skin_load_fonts(wps_data))
2388 { 1448 {
2389 skin_data_reset(wps_data); 1449 skin_data_reset(wps_data);
1450 skin_buffer_restore_position();
2390 return false; 1451 return false;
2391 } 1452 }
2392#endif 1453#endif
@@ -2410,8 +1471,8 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
2410#endif 1471#endif
2411 wps_data->wps_loaded = true; 1472 wps_data->wps_loaded = true;
2412#ifdef DEBUG_SKIN_ENGINE 1473#ifdef DEBUG_SKIN_ENGINE
2413 if (isfile && debug_wps) 1474 // if (isfile && debug_wps)
2414 debug_skin_usage(); 1475 // debug_skin_usage();
2415#endif 1476#endif
2416 return true; 1477 return true;
2417} 1478}