diff options
Diffstat (limited to 'apps/gui/skin_engine/skin_parser.c')
-rw-r--r-- | apps/gui/skin_engine/skin_parser.c | 2057 |
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? */ | ||
75 | static enum screen_type curr_screen; | ||
76 | |||
77 | /* level of current conditional. | ||
78 | -1 means we're not in a conditional. */ | ||
79 | static int level = -1; | ||
80 | |||
81 | /* index of the last WPS_TOKEN_CONDITIONAL_OPTION | ||
82 | or WPS_TOKEN_CONDITIONAL_START in current level */ | ||
83 | static int lastcond[WPS_MAX_COND_LEVEL]; | ||
84 | |||
85 | /* index of the WPS_TOKEN_CONDITIONAL in current level */ | ||
86 | static int condindex[WPS_MAX_COND_LEVEL]; | ||
87 | |||
88 | /* number of condtional options in current level */ | ||
89 | static int numoptions[WPS_MAX_COND_LEVEL]; | ||
90 | |||
91 | /* line number, debug only */ | ||
92 | static int line_number; | ||
93 | |||
94 | /* the current viewport */ | ||
95 | static struct skin_viewport *curr_vp; | ||
96 | /* the current line, linked to the above viewport */ | ||
97 | static struct skin_line *curr_line; | ||
98 | |||
99 | static int follow_lang_direction = 0; | ||
100 | |||
101 | #if defined(DEBUG) || defined(SIMULATOR) | ||
102 | /* debugging function */ | ||
103 | extern void print_debug_info(struct wps_data *data, int fail, int line); | ||
104 | extern 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 | */ | ||
117 | typedef int (*wps_tag_parse_func)(const char *wps_bufptr, | ||
118 | struct wps_token *token, struct wps_data *wps_data); | ||
119 | |||
120 | struct 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 | }; | ||
126 | static int skip_end_of_line(const char *wps_bufptr); | ||
127 | /* prototypes of all special parse functions : */ | ||
128 | static int parse_timeout(const char *wps_bufptr, | ||
129 | struct wps_token *token, struct wps_data *wps_data); | ||
130 | static int parse_progressbar(const char *wps_bufptr, | ||
131 | struct wps_token *token, struct wps_data *wps_data); | ||
132 | static int parse_dir_level(const char *wps_bufptr, | ||
133 | struct wps_token *token, struct wps_data *wps_data); | ||
134 | static int parse_setting_and_lang(const char *wps_bufptr, | ||
135 | struct wps_token *token, struct wps_data *wps_data); | ||
136 | |||
137 | |||
138 | static 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 | 80 | static bool isdefault(struct skin_tag_parameter *param) |
151 | static int parse_viewport_display(const char *wps_bufptr, | ||
152 | struct wps_token *token, struct wps_data *wps_data); | ||
153 | static int parse_playlistview(const char *wps_bufptr, | ||
154 | struct wps_token *token, struct wps_data *wps_data); | ||
155 | static int parse_viewport(const char *wps_bufptr, | ||
156 | struct wps_token *token, struct wps_data *wps_data); | ||
157 | static int parse_statusbar_enable(const char *wps_bufptr, | ||
158 | struct wps_token *token, struct wps_data *wps_data); | ||
159 | static int parse_statusbar_disable(const char *wps_bufptr, | ||
160 | struct wps_token *token, struct wps_data *wps_data); | ||
161 | static int parse_statusbar_inbuilt(const char *wps_bufptr, | ||
162 | struct wps_token *token, struct wps_data *wps_data); | ||
163 | static int parse_image_display(const char *wps_bufptr, | ||
164 | struct wps_token *token, struct wps_data *wps_data); | ||
165 | static int parse_image_load(const char *wps_bufptr, | ||
166 | struct wps_token *token, struct wps_data *wps_data); | ||
167 | static 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)) | ||
171 | static int parse_viewportcolour(const char *wps_bufptr, | ||
172 | struct wps_token *token, struct wps_data *wps_data); | ||
173 | static int parse_image_special(const char *wps_bufptr, | ||
174 | struct wps_token *token, struct wps_data *wps_data); | ||
175 | #endif | ||
176 | #ifdef HAVE_ALBUMART | ||
177 | static int parse_albumart_load(const char *wps_bufptr, | ||
178 | struct wps_token *token, struct wps_data *wps_data); | ||
179 | static 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 | ||
183 | static int parse_touchregion(const char *wps_bufptr, | ||
184 | struct wps_token *token, struct wps_data *wps_data); | ||
185 | #else | ||
186 | static 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. */ | ||
202 | static 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 }, | 87 | static 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 }, | 90 | static struct skin_element *curr_viewport_element; |
381 | { WPS_NO_TOKEN, "wd", 0, parse_statusbar_disable }, | 91 | static 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 }, | 93 | struct line *curr_line; |
385 | 94 | ||
386 | { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", WPS_REFRESH_STATIC, | 95 | static int follow_lang_direction = 0; |
387 | parse_image_display }, | ||
388 | 96 | ||
389 | { WPS_TOKEN_IMAGE_DISPLAY, "x", 0, parse_image_load }, | 97 | typedef 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 | ||
463 | struct gui_img* find_image(char label, struct wps_data *data) | 119 | struct 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 */ |
479 | struct skin_viewport* find_viewport(char label, struct wps_data *data) | 135 | struct 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) | |||
498 | static struct skin_token_list *new_skin_token_list_item(struct wps_token *token, | 155 | static 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 | 171 | static 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, |
515 | static 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 */ | ||
525 | static 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 | |||
543 | static 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); | |
581 | static 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 | |||
594 | static 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 | |||
607 | static 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 | ||
615 | static int get_image_id(int c) | 201 | static 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) | |||
625 | char *get_image_filename(const char *start, const char* bmpdir, | 211 | char *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 | ||
647 | static int parse_image_display(const char *wps_bufptr, | 219 | static 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 | ||
677 | static int parse_image_load(const char *wps_bufptr, | 251 | static 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 | } |
749 | struct skin_font { | 310 | struct 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 | }; |
753 | static struct skin_font skinfonts[MAXUSERFONTS]; | 314 | static struct skin_font skinfonts[MAXUSERFONTS]; |
754 | static int parse_font_load(const char *wps_bufptr, | 315 | static 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 | ||
794 | static 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 |
811 | static 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 | ||
905 | static int parse_playlistview(const char *wps_bufptr, | 344 | static 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 | ||
931 | static 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); | 367 | static 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)) | ||
1029 | static 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 | ||
1079 | static int parse_image_special(const char *wps_bufptr, | 405 | static 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 | ||
1116 | static int parse_setting_and_lang(const char *wps_bufptr, | 436 | static 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 | |||
1168 | static 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 | ||
1180 | static int parse_timeout(const char *wps_bufptr, | 474 | static 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 | ||
1240 | static int parse_progressbar(const char *wps_bufptr, | 504 | static 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 |
1371 | static int parse_albumart_load(const char *wps_bufptr, | 610 | static 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 | ||
1476 | static 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 | ||
1523 | static int parse_touchregion(const char *wps_bufptr, | 736 | static 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 */ | 833 | static bool check_feature_tag(const int type) |
1633 | static 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 | |||
1720 | static int find_false_branch(const char *wps_bufptr) __attribute__((unused)); | ||
1721 | static 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 | * */ | ||
1766 | static 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 | ||
1811 | static 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 | **/ |
2076 | static void skin_data_reset(struct wps_data *wps_data) | 874 | static 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 */ |
1072 | static 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 | |||
1178 | int 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 | } |