1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
39 #define lang_is_rtl() (false)
51 #include "wps_internals.h"
52 #include "skin_engine.h"
54 #include "settings_list.h"
59 #include "skin_fonts.h"
61 #ifdef HAVE_LCD_BITMAP
70 #include "statusbar-skinned.h"
72 #define WPS_ERROR_INVALID_PARAM -1
74 /* which screen are we parsing for? */
75 static enum screen_type curr_screen
;
77 /* level of current conditional.
78 -1 means we're not in a conditional. */
79 static int level
= -1;
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
];
85 /* index of the WPS_TOKEN_CONDITIONAL in current level */
86 static int condindex
[WPS_MAX_COND_LEVEL
];
88 /* number of condtional options in current level */
89 static int numoptions
[WPS_MAX_COND_LEVEL
];
91 /* line number, debug only */
92 static int line_number
;
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
;
99 static int follow_lang_direction
= 0;
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);
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
113 wps_bufptr points to the char following the tag (i.e. where
115 token is the pointer to the 'main' token being parsed
117 typedef int (*wps_tag_parse_func
)(const char *wps_bufptr
,
118 struct wps_token
*token
, struct wps_data
*wps_data
);
121 enum wps_token_type type
;
123 unsigned char refresh_type
;
124 const wps_tag_parse_func parse_func
;
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
);
138 static int parse_languagedirection(const char *wps_bufptr
,
139 struct wps_token
*token
, struct wps_data
*wps_data
)
144 follow_lang_direction
= 2; /* 2 because it is decremented immediatly after
145 this token is parsed, after the next token it
150 #ifdef HAVE_LCD_BITMAP
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_image_special(const char *wps_bufptr
,
172 struct wps_token
*token
, struct wps_data
*wps_data
);
175 static int parse_albumart_load(const char *wps_bufptr
,
176 struct wps_token
*token
, struct wps_data
*wps_data
);
177 static int parse_albumart_display(const char *wps_bufptr
,
178 struct wps_token
*token
, struct wps_data
*wps_data
);
179 #endif /* HAVE_ALBUMART */
180 #ifdef HAVE_TOUCHSCREEN
181 static int parse_touchregion(const char *wps_bufptr
,
182 struct wps_token
*token
, struct wps_data
*wps_data
);
184 static int fulline_tag_not_supported(const char *wps_bufptr
,
185 struct wps_token
*token
, struct wps_data
*wps_data
)
187 (void)token
; (void)wps_data
;
188 return skip_end_of_line(wps_bufptr
);
190 #define parse_touchregion fulline_tag_not_supported
193 #define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
195 #define WPS_RTC_REFRESH WPS_REFRESH_STATIC
198 /* array of available tags - those with more characters have to go first
199 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
200 static const struct wps_tag all_tags
[] = {
202 { WPS_TOKEN_ALIGN_CENTER
, "ac", 0, NULL
},
203 { WPS_TOKEN_ALIGN_LEFT
, "al", 0, NULL
},
204 { WPS_TOKEN_ALIGN_LEFT_RTL
, "aL", 0, NULL
},
205 { WPS_TOKEN_ALIGN_RIGHT
, "ar", 0, NULL
},
206 { WPS_TOKEN_ALIGN_RIGHT_RTL
, "aR", 0, NULL
},
207 { WPS_NO_TOKEN
, "ax", 0, parse_languagedirection
},
209 { WPS_TOKEN_BATTERY_PERCENT
, "bl", WPS_REFRESH_DYNAMIC
, parse_progressbar
},
210 { WPS_TOKEN_BATTERY_VOLTS
, "bv", WPS_REFRESH_DYNAMIC
, NULL
},
211 { WPS_TOKEN_BATTERY_TIME
, "bt", WPS_REFRESH_DYNAMIC
, NULL
},
212 { WPS_TOKEN_BATTERY_SLEEPTIME
, "bs", WPS_REFRESH_DYNAMIC
, NULL
},
213 #if CONFIG_CHARGING >= CHARGING_MONITOR
214 { WPS_TOKEN_BATTERY_CHARGING
, "bc", WPS_REFRESH_DYNAMIC
, NULL
},
217 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED
,"bp", WPS_REFRESH_DYNAMIC
, NULL
},
219 #ifdef HAVE_USB_POWER
220 { WPS_TOKEN_USB_POWERED
, "bu", WPS_REFRESH_DYNAMIC
, NULL
},
223 { WPS_TOKEN_RTC_PRESENT
, "cc", WPS_REFRESH_STATIC
, NULL
},
224 { WPS_TOKEN_RTC_DAY_OF_MONTH
, "cd", WPS_RTC_REFRESH
, NULL
},
225 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
,"ce", WPS_RTC_REFRESH
, NULL
},
226 { WPS_TOKEN_RTC_12HOUR_CFG
, "cf", WPS_RTC_REFRESH
, NULL
},
227 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
, "cH", WPS_RTC_REFRESH
, NULL
},
228 { WPS_TOKEN_RTC_HOUR_24
, "ck", WPS_RTC_REFRESH
, NULL
},
229 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
, "cI", WPS_RTC_REFRESH
, NULL
},
230 { WPS_TOKEN_RTC_HOUR_12
, "cl", WPS_RTC_REFRESH
, NULL
},
231 { WPS_TOKEN_RTC_MONTH
, "cm", WPS_RTC_REFRESH
, NULL
},
232 { WPS_TOKEN_RTC_MINUTE
, "cM", WPS_RTC_REFRESH
, NULL
},
233 { WPS_TOKEN_RTC_SECOND
, "cS", WPS_RTC_REFRESH
, NULL
},
234 { WPS_TOKEN_RTC_YEAR_2_DIGITS
, "cy", WPS_RTC_REFRESH
, NULL
},
235 { WPS_TOKEN_RTC_YEAR_4_DIGITS
, "cY", WPS_RTC_REFRESH
, NULL
},
236 { WPS_TOKEN_RTC_AM_PM_UPPER
, "cP", WPS_RTC_REFRESH
, NULL
},
237 { WPS_TOKEN_RTC_AM_PM_LOWER
, "cp", WPS_RTC_REFRESH
, NULL
},
238 { WPS_TOKEN_RTC_WEEKDAY_NAME
, "ca", WPS_RTC_REFRESH
, NULL
},
239 { WPS_TOKEN_RTC_MONTH_NAME
, "cb", WPS_RTC_REFRESH
, NULL
},
240 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
, "cu", WPS_RTC_REFRESH
, NULL
},
241 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
, "cw", WPS_RTC_REFRESH
, NULL
},
244 { WPS_TOKEN_FILE_BITRATE
, "fb", WPS_REFRESH_STATIC
, NULL
},
245 { WPS_TOKEN_FILE_CODEC
, "fc", WPS_REFRESH_STATIC
, NULL
},
246 { WPS_TOKEN_FILE_FREQUENCY
, "ff", WPS_REFRESH_STATIC
, NULL
},
247 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "fk", WPS_REFRESH_STATIC
, NULL
},
248 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "fm", WPS_REFRESH_STATIC
, NULL
},
249 { WPS_TOKEN_FILE_NAME
, "fn", WPS_REFRESH_STATIC
, NULL
},
250 { WPS_TOKEN_FILE_PATH
, "fp", WPS_REFRESH_STATIC
, NULL
},
251 { WPS_TOKEN_FILE_SIZE
, "fs", WPS_REFRESH_STATIC
, NULL
},
252 { WPS_TOKEN_FILE_VBR
, "fv", WPS_REFRESH_STATIC
, NULL
},
253 { WPS_TOKEN_FILE_DIRECTORY
, "d", WPS_REFRESH_STATIC
,
257 { WPS_TOKEN_FILE_BITRATE
, "Fb", WPS_REFRESH_STATIC
, NULL
},
258 { WPS_TOKEN_FILE_CODEC
, "Fc", WPS_REFRESH_STATIC
, NULL
},
259 { WPS_TOKEN_FILE_FREQUENCY
, "Ff", WPS_REFRESH_STATIC
, NULL
},
260 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "Fk", WPS_REFRESH_STATIC
, NULL
},
261 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "Fm", WPS_REFRESH_STATIC
, NULL
},
262 { WPS_TOKEN_FILE_NAME
, "Fn", WPS_REFRESH_STATIC
, NULL
},
263 { WPS_TOKEN_FILE_PATH
, "Fp", WPS_REFRESH_STATIC
, NULL
},
264 { WPS_TOKEN_FILE_SIZE
, "Fs", WPS_REFRESH_STATIC
, NULL
},
265 { WPS_TOKEN_FILE_VBR
, "Fv", WPS_REFRESH_STATIC
, NULL
},
266 { WPS_TOKEN_FILE_DIRECTORY
, "D", WPS_REFRESH_STATIC
,
269 /* current metadata */
270 { WPS_TOKEN_METADATA_ARTIST
, "ia", WPS_REFRESH_STATIC
, NULL
},
271 { WPS_TOKEN_METADATA_COMPOSER
, "ic", WPS_REFRESH_STATIC
, NULL
},
272 { WPS_TOKEN_METADATA_ALBUM
, "id", WPS_REFRESH_STATIC
, NULL
},
273 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "iA", WPS_REFRESH_STATIC
, NULL
},
274 { WPS_TOKEN_METADATA_GROUPING
, "iG", WPS_REFRESH_STATIC
, NULL
},
275 { WPS_TOKEN_METADATA_GENRE
, "ig", WPS_REFRESH_STATIC
, NULL
},
276 { WPS_TOKEN_METADATA_DISC_NUMBER
, "ik", WPS_REFRESH_STATIC
, NULL
},
277 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "in", WPS_REFRESH_STATIC
, NULL
},
278 { WPS_TOKEN_METADATA_TRACK_TITLE
, "it", WPS_REFRESH_STATIC
, NULL
},
279 { WPS_TOKEN_METADATA_VERSION
, "iv", WPS_REFRESH_STATIC
, NULL
},
280 { WPS_TOKEN_METADATA_YEAR
, "iy", WPS_REFRESH_STATIC
, NULL
},
281 { WPS_TOKEN_METADATA_COMMENT
, "iC", WPS_REFRESH_STATIC
, NULL
},
284 { WPS_TOKEN_METADATA_ARTIST
, "Ia", WPS_REFRESH_STATIC
, NULL
},
285 { WPS_TOKEN_METADATA_COMPOSER
, "Ic", WPS_REFRESH_STATIC
, NULL
},
286 { WPS_TOKEN_METADATA_ALBUM
, "Id", WPS_REFRESH_STATIC
, NULL
},
287 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "IA", WPS_REFRESH_STATIC
, NULL
},
288 { WPS_TOKEN_METADATA_GROUPING
, "IG", WPS_REFRESH_STATIC
, NULL
},
289 { WPS_TOKEN_METADATA_GENRE
, "Ig", WPS_REFRESH_STATIC
, NULL
},
290 { WPS_TOKEN_METADATA_DISC_NUMBER
, "Ik", WPS_REFRESH_STATIC
, NULL
},
291 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "In", WPS_REFRESH_STATIC
, NULL
},
292 { WPS_TOKEN_METADATA_TRACK_TITLE
, "It", WPS_REFRESH_STATIC
, NULL
},
293 { WPS_TOKEN_METADATA_VERSION
, "Iv", WPS_REFRESH_STATIC
, NULL
},
294 { WPS_TOKEN_METADATA_YEAR
, "Iy", WPS_REFRESH_STATIC
, NULL
},
295 { WPS_TOKEN_METADATA_COMMENT
, "IC", WPS_REFRESH_STATIC
, NULL
},
297 #if (CONFIG_CODEC != MAS3507D)
298 { WPS_TOKEN_SOUND_PITCH
, "Sp", WPS_REFRESH_DYNAMIC
, NULL
},
300 #if (CONFIG_CODEC == SWCODEC)
301 { WPS_TOKEN_SOUND_SPEED
, "Ss", WPS_REFRESH_DYNAMIC
, NULL
},
303 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
304 { WPS_TOKEN_VLED_HDD
, "lh", WPS_REFRESH_DYNAMIC
, NULL
},
307 { WPS_TOKEN_MAIN_HOLD
, "mh", WPS_REFRESH_DYNAMIC
, NULL
},
309 #ifdef HAS_REMOTE_BUTTON_HOLD
310 { WPS_TOKEN_REMOTE_HOLD
, "mr", WPS_REFRESH_DYNAMIC
, NULL
},
312 { WPS_TOKEN_UNKNOWN
, "mr", 0, NULL
},
315 { WPS_TOKEN_REPEAT_MODE
, "mm", WPS_REFRESH_DYNAMIC
, NULL
},
316 { WPS_TOKEN_PLAYBACK_STATUS
, "mp", WPS_REFRESH_DYNAMIC
, NULL
},
317 { WPS_TOKEN_BUTTON_VOLUME
, "mv", WPS_REFRESH_DYNAMIC
,
320 #ifdef HAVE_LCD_BITMAP
321 { WPS_TOKEN_PEAKMETER
, "pm", WPS_REFRESH_PEAK_METER
, NULL
},
323 { WPS_TOKEN_PLAYER_PROGRESSBAR
, "pf",
324 WPS_REFRESH_DYNAMIC
| WPS_REFRESH_PLAYER_PROGRESS
, parse_progressbar
},
326 { WPS_TOKEN_PROGRESSBAR
, "pb", WPS_REFRESH_PLAYER_PROGRESS
,
329 { WPS_TOKEN_VOLUME
, "pv", WPS_REFRESH_DYNAMIC
,
332 { WPS_TOKEN_TRACK_ELAPSED_PERCENT
, "px", WPS_REFRESH_DYNAMIC
, NULL
},
333 { WPS_TOKEN_TRACK_TIME_ELAPSED
, "pc", WPS_REFRESH_DYNAMIC
, NULL
},
334 { WPS_TOKEN_TRACK_TIME_REMAINING
, "pr", WPS_REFRESH_DYNAMIC
, NULL
},
335 { WPS_TOKEN_TRACK_LENGTH
, "pt", WPS_REFRESH_STATIC
, NULL
},
336 { WPS_TOKEN_TRACK_STARTING
, "pS", WPS_REFRESH_DYNAMIC
, parse_timeout
},
337 { WPS_TOKEN_TRACK_ENDING
, "pE", WPS_REFRESH_DYNAMIC
, parse_timeout
},
339 { WPS_TOKEN_PLAYLIST_POSITION
, "pp", WPS_REFRESH_STATIC
, NULL
},
340 { WPS_TOKEN_PLAYLIST_ENTRIES
, "pe", WPS_REFRESH_STATIC
, NULL
},
341 { WPS_TOKEN_PLAYLIST_NAME
, "pn", WPS_REFRESH_STATIC
, NULL
},
342 { WPS_TOKEN_PLAYLIST_SHUFFLE
, "ps", WPS_REFRESH_DYNAMIC
, NULL
},
345 { WPS_TOKEN_DATABASE_PLAYCOUNT
, "rp", WPS_REFRESH_DYNAMIC
, NULL
},
346 { WPS_TOKEN_DATABASE_RATING
, "rr", WPS_REFRESH_DYNAMIC
, NULL
},
347 { WPS_TOKEN_DATABASE_AUTOSCORE
, "ra", WPS_REFRESH_DYNAMIC
, NULL
},
350 #if CONFIG_CODEC == SWCODEC
351 { WPS_TOKEN_REPLAYGAIN
, "rg", WPS_REFRESH_STATIC
, NULL
},
352 { WPS_TOKEN_CROSSFADE
, "xf", WPS_REFRESH_DYNAMIC
, NULL
},
355 { WPS_TOKEN_HAVE_TUNER
, "tp", WPS_REFRESH_STATIC
, NULL
},
356 #if CONFIG_TUNER /* Re-uses the 't' and 'T' prefixes, be careful about doubleups */
357 { WPS_TOKEN_TUNER_TUNED
, "tt", WPS_REFRESH_DYNAMIC
, NULL
},
358 { WPS_TOKEN_TUNER_SCANMODE
, "tm", WPS_REFRESH_DYNAMIC
, NULL
},
359 { WPS_TOKEN_TUNER_STEREO
, "ts", WPS_REFRESH_DYNAMIC
, NULL
},
360 { WPS_TOKEN_TUNER_MINFREQ
, "ta", WPS_REFRESH_STATIC
, NULL
},
361 { WPS_TOKEN_TUNER_MAXFREQ
, "tb", WPS_REFRESH_STATIC
, NULL
},
362 { WPS_TOKEN_TUNER_CURFREQ
, "tf", WPS_REFRESH_DYNAMIC
, NULL
},
363 { WPS_TOKEN_PRESET_ID
, "Ti", WPS_REFRESH_STATIC
, NULL
},
364 { WPS_TOKEN_PRESET_NAME
, "Tn", WPS_REFRESH_STATIC
, NULL
},
365 { WPS_TOKEN_PRESET_FREQ
, "Tf", WPS_REFRESH_STATIC
, NULL
},
366 { WPS_TOKEN_PRESET_COUNT
, "Tc", WPS_REFRESH_STATIC
, NULL
},
367 { WPS_TOKEN_HAVE_RDS
, "tx", WPS_REFRESH_STATIC
, NULL
},
369 { WPS_TOKEN_RDS_NAME
, "ty", WPS_REFRESH_DYNAMIC
, NULL
},
370 { WPS_TOKEN_RDS_TEXT
, "tz", WPS_REFRESH_DYNAMIC
, NULL
},
372 #endif /* CONFIG_TUNER */
374 { WPS_NO_TOKEN
, "s", WPS_REFRESH_SCROLL
, NULL
},
375 { WPS_TOKEN_SUBLINE_TIMEOUT
, "t", 0, parse_timeout
},
377 #ifdef HAVE_LCD_BITMAP
378 { WPS_NO_TOKEN
, "we", 0, parse_statusbar_enable
},
379 { WPS_NO_TOKEN
, "wd", 0, parse_statusbar_disable
},
380 { WPS_TOKEN_DRAW_INBUILTBAR
, "wi", WPS_REFRESH_DYNAMIC
, parse_statusbar_inbuilt
},
382 { WPS_NO_TOKEN
, "xl", 0, parse_image_load
},
384 { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
, "xd", WPS_REFRESH_STATIC
,
385 parse_image_display
},
387 { WPS_TOKEN_IMAGE_DISPLAY
, "x", 0, parse_image_load
},
388 { WPS_NO_TOKEN
, "Fl", 0, parse_font_load
},
390 { WPS_NO_TOKEN
, "Cl", 0, parse_albumart_load
},
391 { WPS_TOKEN_ALBUMART_DISPLAY
, "C", WPS_REFRESH_STATIC
, parse_albumart_display
},
394 { WPS_VIEWPORT_ENABLE
, "Vd", WPS_REFRESH_DYNAMIC
,
395 parse_viewport_display
},
396 { WPS_TOKEN_UIVIEWPORT_ENABLE
, "VI", WPS_REFRESH_STATIC
,
397 parse_viewport_display
},
398 #ifdef HAVE_LCD_BITMAP
399 { WPS_VIEWPORT_CUSTOMLIST
, "Vp", WPS_REFRESH_STATIC
, parse_playlistview
},
400 { WPS_TOKEN_LIST_TITLE_TEXT
, "Lt", WPS_REFRESH_DYNAMIC
, NULL
},
401 { WPS_TOKEN_LIST_TITLE_ICON
, "Li", WPS_REFRESH_DYNAMIC
, NULL
},
403 { WPS_NO_TOKEN
, "V", 0, parse_viewport
},
405 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
406 { WPS_TOKEN_IMAGE_BACKDROP
, "X", 0, parse_image_special
},
410 { WPS_TOKEN_SETTING
, "St", WPS_REFRESH_DYNAMIC
,
411 parse_setting_and_lang
},
412 { WPS_TOKEN_TRANSLATEDSTRING
, "Sx", WPS_REFRESH_STATIC
,
413 parse_setting_and_lang
},
414 { WPS_TOKEN_LANG_IS_RTL
, "Sr", WPS_REFRESH_STATIC
, NULL
},
416 { WPS_TOKEN_LASTTOUCH
, "Tl", WPS_REFRESH_DYNAMIC
, parse_timeout
},
417 { WPS_TOKEN_CURRENT_SCREEN
, "cs", WPS_REFRESH_DYNAMIC
, NULL
},
418 { WPS_NO_TOKEN
, "T", 0, parse_touchregion
},
421 /* Recording Tokens */
422 { WPS_TOKEN_HAVE_RECORDING
, "Rp", WPS_REFRESH_STATIC
, NULL
},
423 #ifdef HAVE_RECORDING
424 { WPS_TOKEN_IS_RECORDING
, "Rr", WPS_REFRESH_DYNAMIC
, NULL
},
425 { WPS_TOKEN_REC_FREQ
, "Rf", WPS_REFRESH_DYNAMIC
, NULL
},
426 { WPS_TOKEN_REC_ENCODER
, "Re", WPS_REFRESH_DYNAMIC
, NULL
},
427 { WPS_TOKEN_REC_BITRATE
, "Rb", WPS_REFRESH_DYNAMIC
, NULL
},
428 { WPS_TOKEN_REC_MONO
, "Rm", WPS_REFRESH_DYNAMIC
, NULL
},
429 { WPS_TOKEN_REC_SECONDS
, "Rs", WPS_REFRESH_DYNAMIC
, NULL
},
430 { WPS_TOKEN_REC_MINUTES
, "Rn", WPS_REFRESH_DYNAMIC
, NULL
},
431 { WPS_TOKEN_REC_HOURS
, "Rh", WPS_REFRESH_DYNAMIC
, NULL
},
433 { WPS_TOKEN_UNKNOWN
, "", 0, NULL
}
434 /* the array MUST end with an empty string (first char is \0) */
438 /* add a skin_token_list item to the list chain. ALWAYS appended because some of the
439 * chains require the order to be kept.
441 static void add_to_ll_chain(struct skin_token_list
**list
, struct skin_token_list
*item
)
447 struct skin_token_list
*t
= *list
;
454 /* traverse the image linked-list for an image */
455 #ifdef HAVE_LCD_BITMAP
456 struct gui_img
* find_image(char label
, struct wps_data
*data
)
458 struct skin_token_list
*list
= data
->images
;
461 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
462 if (img
->label
== label
)
471 /* traverse the viewport linked list for a viewport */
472 struct skin_viewport
* find_viewport(char label
, struct wps_data
*data
)
474 struct skin_token_list
*list
= data
->viewports
;
477 struct skin_viewport
*vp
= (struct skin_viewport
*)list
->token
->value
.data
;
478 if (vp
->label
== label
)
486 /* create and init a new wpsll item.
487 * passing NULL to token will alloc a new one.
488 * You should only pass NULL for the token when the token type (table above)
489 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
491 static struct skin_token_list
*new_skin_token_list_item(struct wps_token
*token
,
494 struct skin_token_list
*llitem
= skin_buffer_alloc(sizeof(struct skin_token_list
));
496 token
= skin_buffer_alloc(sizeof(struct wps_token
));
497 if (!llitem
|| !token
)
500 llitem
->token
= token
;
502 llitem
->token
->value
.data
= token_data
;
506 /* Returns the number of chars that should be skipped to jump
507 immediately after the first eol, i.e. to the start of the next line */
508 static int skip_end_of_line(const char *wps_bufptr
)
512 while(*(wps_bufptr
+ skip
) != '\n')
517 /* Starts a new subline in the current line during parsing */
518 static bool skin_start_new_subline(struct skin_line
*line
, int curr_token
)
520 struct skin_subline
*subline
= skin_buffer_alloc(sizeof(struct skin_subline
));
524 subline
->first_token_idx
= curr_token
;
525 subline
->next
= NULL
;
527 subline
->line_type
= 0;
528 subline
->time_mult
= 0;
530 line
->curr_subline
->last_token_idx
= curr_token
-1;
531 line
->curr_subline
->next
= subline
;
532 line
->curr_subline
= subline
;
536 static bool skin_start_new_line(struct skin_viewport
*vp
, int curr_token
)
538 struct skin_line
*line
= skin_buffer_alloc(sizeof(struct skin_line
));
539 struct skin_subline
*subline
= NULL
;
543 /* init the subline */
544 subline
= &line
->sublines
;
545 subline
->first_token_idx
= curr_token
;
546 subline
->next
= NULL
;
547 subline
->line_type
= 0;
548 subline
->time_mult
= 0;
550 /* init the new line */
551 line
->curr_subline
= &line
->sublines
;
553 line
->subline_expire_time
= 0;
555 /* connect to curr_line and vp pointers.
556 * 1) close the previous lines subline
557 * 2) connect to vp pointer
558 * 3) connect to curr_line global pointer
562 curr_line
->curr_subline
->last_token_idx
= curr_token
- 1;
563 curr_line
->next
= line
;
564 curr_line
->curr_subline
= NULL
;
572 #ifdef HAVE_LCD_BITMAP
574 static int parse_statusbar_enable(const char *wps_bufptr
,
575 struct wps_token
*token
,
576 struct wps_data
*wps_data
)
578 (void)token
; /* Kill warnings */
579 wps_data
->wps_sb_tag
= true;
580 wps_data
->show_sb_on_wps
= true;
581 struct skin_viewport
*default_vp
= find_viewport(VP_DEFAULT_LABEL
, wps_data
);
582 viewport_set_defaults(&default_vp
->vp
, curr_screen
);
583 default_vp
->vp
.font
= FONT_UI
;
584 return skip_end_of_line(wps_bufptr
);
587 static int parse_statusbar_disable(const char *wps_bufptr
,
588 struct wps_token
*token
,
589 struct wps_data
*wps_data
)
591 (void)token
; /* Kill warnings */
592 wps_data
->wps_sb_tag
= true;
593 wps_data
->show_sb_on_wps
= false;
594 struct skin_viewport
*default_vp
= find_viewport(VP_DEFAULT_LABEL
, wps_data
);
595 viewport_set_fullscreen(&default_vp
->vp
, curr_screen
);
596 default_vp
->vp
.font
= FONT_UI
;
597 return skip_end_of_line(wps_bufptr
);
600 static int parse_statusbar_inbuilt(const char *wps_bufptr
,
601 struct wps_token
*token
, struct wps_data
*wps_data
)
604 token
->value
.data
= (void*)&curr_vp
->vp
;
605 return skip_end_of_line(wps_bufptr
);
608 static int get_image_id(int c
)
610 if(c
>= 'a' && c
<= 'z')
612 else if(c
>= 'A' && c
<= 'Z')
618 char *get_image_filename(const char *start
, const char* bmpdir
,
619 char *buf
, int buf_size
)
621 const char *end
= strchr(start
, '|');
622 int bmpdirlen
= strlen(bmpdir
);
624 if ( !end
|| (end
- start
) >= (buf_size
- bmpdirlen
- 2) )
631 buf
[bmpdirlen
] = '/';
632 memcpy( &buf
[bmpdirlen
+ 1], start
, end
- start
);
633 buf
[bmpdirlen
+ 1 + end
- start
] = 0;
638 static int parse_image_display(const char *wps_bufptr
,
639 struct wps_token
*token
,
640 struct wps_data
*wps_data
)
642 char label
= wps_bufptr
[0];
644 struct gui_img
*img
;;
647 img
= find_image(label
, wps_data
);
650 token
->value
.i
= label
; /* so debug works */
651 return WPS_ERROR_INVALID_PARAM
;
654 if ((subimage
= get_image_id(wps_bufptr
[1])) != -1)
656 if (subimage
>= img
->num_subimages
)
657 return WPS_ERROR_INVALID_PARAM
;
659 /* Store sub-image number to display in high bits */
660 token
->value
.i
= label
| (subimage
<< 8);
661 return 2; /* We have consumed 2 bytes */
663 token
->value
.i
= label
;
664 return 1; /* We have consumed 1 byte */
668 static int parse_image_load(const char *wps_bufptr
,
669 struct wps_token
*token
,
670 struct wps_data
*wps_data
)
672 const char *ptr
= wps_bufptr
;
674 const char* filename
;
680 /* format: %x|n|filename.bmp|x|y|
681 or %xl|n|filename.bmp|x|y|
682 or %xl|n|filename.bmp|x|y|num_subimages|
686 return WPS_ERROR_INVALID_PARAM
;
690 if (!(ptr
= parse_list("ssdd", NULL
, '|', ptr
, &id
, &filename
, &x
, &y
)))
691 return WPS_ERROR_INVALID_PARAM
;
693 /* Check there is a terminating | */
695 return WPS_ERROR_INVALID_PARAM
;
697 /* check the image number and load state */
698 if(find_image(*id
, wps_data
))
700 /* Invalid image ID */
701 return WPS_ERROR_INVALID_PARAM
;
703 img
= skin_buffer_alloc(sizeof(struct gui_img
));
705 return WPS_ERROR_INVALID_PARAM
;
706 /* save a pointer to the filename */
707 img
->bm
.data
= (char*)filename
;
711 img
->num_subimages
= 1;
712 img
->always_display
= false;
714 /* save current viewport */
715 img
->vp
= &curr_vp
->vp
;
717 if (token
->type
== WPS_TOKEN_IMAGE_DISPLAY
)
719 img
->always_display
= true;
723 /* Parse the (optional) number of sub-images */
725 newline
= strchr(ptr
, '\n');
726 pos
= strchr(ptr
, '|');
727 if (pos
&& pos
< newline
)
728 img
->num_subimages
= atoi(ptr
);
730 if (img
->num_subimages
<= 0)
731 return WPS_ERROR_INVALID_PARAM
;
733 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, img
);
735 return WPS_ERROR_INVALID_PARAM
;
736 add_to_ll_chain(&wps_data
->images
, item
);
738 /* Skip the rest of the line */
739 return skip_end_of_line(wps_bufptr
);
742 int id
; /* the id from font_load */
743 char *name
; /* filename without path and extension */
745 static struct skin_font skinfonts
[MAXUSERFONTS
];
746 static int parse_font_load(const char *wps_bufptr
,
747 struct wps_token
*token
, struct wps_data
*wps_data
)
749 (void)wps_data
; (void)token
;
750 const char *ptr
= wps_bufptr
;
755 return WPS_ERROR_INVALID_PARAM
;
759 if (!(ptr
= parse_list("ds", NULL
, '|', ptr
, &id
, &filename
)))
760 return WPS_ERROR_INVALID_PARAM
;
762 /* Check there is a terminating | */
764 return WPS_ERROR_INVALID_PARAM
;
766 if (id
<= FONT_UI
|| id
>= MAXFONTS
-1)
767 return WPS_ERROR_INVALID_PARAM
;
768 #if defined(DEBUG) || defined(SIMULATOR)
769 if (skinfonts
[id
-FONT_FIRSTUSERFONT
].name
!= NULL
)
771 DEBUGF("font id %d already being used\n", id
);
774 /* make sure the filename contains .fnt,
775 * we dont actually use it, but require it anyway */
776 ptr
= strchr(filename
, '.');
777 if (!ptr
|| strncmp(ptr
, ".fnt|", 5))
778 return WPS_ERROR_INVALID_PARAM
;
779 skinfonts
[id
-FONT_FIRSTUSERFONT
].id
= -1;
780 skinfonts
[id
-FONT_FIRSTUSERFONT
].name
= filename
;
782 return skip_end_of_line(wps_bufptr
);
786 static int parse_viewport_display(const char *wps_bufptr
,
787 struct wps_token
*token
,
788 struct wps_data
*wps_data
)
791 char letter
= wps_bufptr
[0];
793 if (letter
< 'a' || letter
> 'z')
795 /* invalid viewport tag */
796 return WPS_ERROR_INVALID_PARAM
;
798 token
->value
.i
= letter
;
802 #ifdef HAVE_LCD_BITMAP
803 static int parse_playlistview_text(struct playlistviewer
*viewer
,
804 enum info_line_type line
, char* text
)
807 const struct wps_tag
*tag
;
809 const char *start
= text
;
813 viewer
->lines
[line
].count
= 0;
814 viewer
->lines
[line
].scroll
= false;
817 if (*text
== '%') /* it is a token of some type */
829 /* escaped characters */
830 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = WPS_TOKEN_CHARACTER
;
831 viewer
->lines
[line
].strings
[cur_string
][0] = *text
;
832 viewer
->lines
[line
].strings
[cur_string
++][1] = '\0';
837 strncmp(text
, tag
->name
, strlen(tag
->name
)) != 0;
839 /* %s isnt stored as a tag so manually check for it */
840 if (tag
->type
== WPS_NO_TOKEN
)
842 if (!strncmp(tag
->name
, "s", 1))
844 viewer
->lines
[line
].scroll
= true;
848 else if (tag
->type
== WPS_TOKEN_UNKNOWN
)
851 /* just copy the string */
852 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = WPS_TOKEN_STRING
;
853 while (i
<(MAX_PLAYLISTLINE_STRLEN
-1) && text
[i
] != '|' && text
[i
] != '%')
855 viewer
->lines
[line
].strings
[cur_string
][i
] = text
[i
];
858 viewer
->lines
[line
].strings
[cur_string
][i
] = '\0';
866 /* unsupported tag, reject */
869 taglen
= strlen(tag
->name
);
870 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = tag
->type
;
879 /* just copy the string */
880 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = WPS_TOKEN_STRING
;
881 while (i
<(MAX_PLAYLISTLINE_STRLEN
-1) && text
[i
] != '|' && text
[i
] != '%')
883 viewer
->lines
[line
].strings
[cur_string
][i
] = text
[i
];
886 viewer
->lines
[line
].strings
[cur_string
][i
] = '\0';
895 static int parse_playlistview(const char *wps_bufptr
,
896 struct wps_token
*token
, struct wps_data
*wps_data
)
899 /* %Vp|<use icons>|<start offset>|info line text|no info text| */
900 struct playlistviewer
*viewer
= skin_buffer_alloc(sizeof(struct playlistviewer
));
901 char *ptr
= strchr(wps_bufptr
, '|');
904 return WPS_ERROR_INVALID_PARAM
;
905 viewer
->vp
= &curr_vp
->vp
;
906 viewer
->show_icons
= true;
907 viewer
->start_offset
= atoi(ptr
+1);
908 token
->value
.data
= (void*)viewer
;
909 ptr
= strchr(ptr
+1, '|');
910 length
= parse_playlistview_text(viewer
, TRACK_HAS_INFO
, ptr
);
912 return WPS_ERROR_INVALID_PARAM
;
913 length
= parse_playlistview_text(viewer
, TRACK_HAS_NO_INFO
, ptr
+length
);
915 return WPS_ERROR_INVALID_PARAM
;
917 return skip_end_of_line(wps_bufptr
);
921 static int parse_viewport(const char *wps_bufptr
,
922 struct wps_token
*token
,
923 struct wps_data
*wps_data
)
925 (void)token
; /* Kill warnings */
926 const char *ptr
= wps_bufptr
;
928 struct skin_viewport
*skin_vp
= skin_buffer_alloc(sizeof(struct skin_viewport
));
930 /* check for the optional letter to signify its a hideable viewport */
931 /* %Vl|<label>|<rest of tags>| */
932 skin_vp
->hidden_flags
= 0;
933 skin_vp
->label
= VP_NO_LABEL
;
934 skin_vp
->lines
= NULL
;
937 curr_line
->curr_subline
->last_token_idx
= wps_data
->num_tokens
938 - (wps_data
->num_tokens
> 0 ? 1 : 0);
942 if (!skin_start_new_line(skin_vp
, wps_data
->num_tokens
))
943 return WPS_ERROR_INVALID_PARAM
;
949 char label
= *(ptr
+2);
950 if (label
>= 'a' && label
<= 'z')
952 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
953 skin_vp
->label
= VP_INFO_LABEL
|label
;
958 skin_vp
->label
= VP_INFO_LABEL
|VP_DEFAULT_LABEL
;
959 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
964 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
967 else if (*ptr
== 'l')
971 char label
= *(ptr
+2);
972 if (label
>= 'a' && label
<= 'z')
974 skin_vp
->hidden_flags
= VP_DRAW_HIDEABLE
;
975 skin_vp
->label
= label
;
978 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
983 return WPS_ERROR_INVALID_PARAM
;
986 struct viewport
*vp
= &skin_vp
->vp
;
987 /* format: %V|x|y|width|height|font|fg_pattern|bg_pattern| */
988 if (!(ptr
= viewport_parse_viewport(vp
, curr_screen
, ptr
, '|')))
989 return WPS_ERROR_INVALID_PARAM
;
991 /* Check for trailing | */
993 return WPS_ERROR_INVALID_PARAM
;
995 if (follow_lang_direction
&& lang_is_rtl())
997 vp
->flags
|= VP_FLAG_ALIGN_RIGHT
;
998 vp
->x
= screens
[curr_screen
].lcdwidth
- vp
->width
- vp
->x
;
1001 vp
->flags
&= ~VP_FLAG_ALIGN_RIGHT
; /* ignore right-to-left languages */
1003 struct skin_token_list
*list
= new_skin_token_list_item(NULL
, skin_vp
);
1005 return WPS_ERROR_INVALID_PARAM
;
1006 add_to_ll_chain(&wps_data
->viewports
, list
);
1008 /* Skip the rest of the line */
1009 return skip_end_of_line(wps_bufptr
);
1012 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1013 static int parse_image_special(const char *wps_bufptr
,
1014 struct wps_token
*token
,
1015 struct wps_data
*wps_data
)
1017 (void)wps_data
; /* kill warning */
1019 const char *pos
= NULL
;
1020 const char *newline
;
1023 pos
= strchr(wps_bufptr
+ 1, '|');
1024 newline
= strchr(wps_bufptr
, '\n');
1026 error
= (pos
> newline
);
1029 if (token
->type
== WPS_TOKEN_IMAGE_BACKDROP
)
1031 /* format: %X|filename.bmp| or %Xd */
1032 if (*(wps_bufptr
) == 'd')
1034 wps_data
->backdrop
= NULL
;
1035 return skip_end_of_line(wps_bufptr
);
1038 wps_data
->backdrop
= (char*)wps_bufptr
+ 1;
1042 return WPS_ERROR_INVALID_PARAM
;
1043 /* Skip the rest of the line */
1044 return skip_end_of_line(wps_bufptr
);
1048 #endif /* HAVE_LCD_BITMAP */
1050 static int parse_setting_and_lang(const char *wps_bufptr
,
1051 struct wps_token
*token
,
1052 struct wps_data
*wps_data
)
1054 /* NOTE: both the string validations that happen in here will
1055 * automatically PASS on checkwps because its too hard to get
1056 * settings_list.c and englinsh.lang built for it.
1057 * If that ever changes remove the #ifndef __PCTOOL__'s here
1060 const char *ptr
= wps_bufptr
;
1065 /* Find the setting's cfg_name */
1067 return WPS_ERROR_INVALID_PARAM
;
1069 end
= strchr(ptr
,'|');
1070 if (!end
|| (size_t)(end
-ptr
+1) > sizeof temp
)
1071 return WPS_ERROR_INVALID_PARAM
;
1072 strlcpy(temp
, ptr
,end
-ptr
+1);
1074 if (token
->type
== WPS_TOKEN_TRANSLATEDSTRING
)
1077 i
= lang_english_to_id(temp
);
1079 return WPS_ERROR_INVALID_PARAM
;
1084 /* Find the setting */
1085 for (i
=0; i
<nb_settings
; i
++)
1086 if (settings
[i
].cfg_name
&&
1087 !strcmp(settings
[i
].cfg_name
, temp
))
1090 if (i
== nb_settings
)
1091 return WPS_ERROR_INVALID_PARAM
;
1094 /* Store the setting number */
1097 /* Skip the rest of the line */
1102 static int parse_dir_level(const char *wps_bufptr
,
1103 struct wps_token
*token
,
1104 struct wps_data
*wps_data
)
1106 char val
[] = { *wps_bufptr
, '\0' };
1107 token
->value
.i
= atoi(val
);
1108 (void)wps_data
; /* Kill warnings */
1112 static int parse_timeout(const char *wps_bufptr
,
1113 struct wps_token
*token
,
1114 struct wps_data
*wps_data
)
1118 bool have_point
= false;
1119 bool have_tenth
= false;
1121 (void)wps_data
; /* Kill the warning */
1123 while ( isdigit(*wps_bufptr
) || *wps_bufptr
== '.' )
1125 if (*wps_bufptr
!= '.')
1128 val
+= *wps_bufptr
- '0';
1144 if (have_tenth
== false)
1147 if (val
== 0 && skip
== 0)
1149 /* decide what to do if no value was specified */
1150 switch (token
->type
)
1152 case WPS_TOKEN_SUBLINE_TIMEOUT
:
1154 case WPS_TOKEN_BUTTON_VOLUME
:
1155 case WPS_TOKEN_TRACK_STARTING
:
1156 case WPS_TOKEN_TRACK_ENDING
:
1161 token
->value
.i
= val
;
1166 static int parse_progressbar(const char *wps_bufptr
,
1167 struct wps_token
*token
,
1168 struct wps_data
*wps_data
)
1170 /* %pb or %pb|filename|x|y|width|height|
1171 using - for any of the params uses "sane" values */
1172 #ifdef HAVE_LCD_BITMAP
1180 const char *filename
;
1181 int x
, y
, height
, width
;
1183 const char *ptr
= wps_bufptr
;
1184 struct progressbar
*pb
= skin_buffer_alloc(sizeof(struct progressbar
));
1185 struct skin_token_list
*item
= new_skin_token_list_item(token
, pb
);
1188 return WPS_ERROR_INVALID_PARAM
;
1190 struct viewport
*vp
= &curr_vp
->vp
;
1191 /* we need to know what line number (viewport relative) this pb is,
1192 * so count them... */
1194 struct skin_line
*line
= curr_vp
->lines
;
1201 pb
->have_bitmap_pb
= false;
1202 pb
->bm
.data
= NULL
; /* no bitmap specified */
1203 pb
->follow_lang_direction
= follow_lang_direction
> 0;
1206 if (*wps_bufptr
!= '|') /* regular old style */
1209 pb
->width
= vp
->width
;
1210 pb
->height
= SYSFONT_HEIGHT
-2;
1211 pb
->y
= -line_num
- 1; /* Will be computed during the rendering */
1212 if (token
->type
== WPS_TOKEN_VOLUME
|| token
->type
== WPS_TOKEN_BATTERY_PERCENT
)
1213 return 0; /* dont add it, let the regular token handling do the work */
1214 add_to_ll_chain(&wps_data
->progressbars
, item
);
1217 ptr
= wps_bufptr
+ 1;
1219 if (!(ptr
= parse_list("sdddd", &set
, '|', ptr
, &filename
,
1220 &x
, &y
, &width
, &height
)))
1222 /* If we are in a conditional then we probably don't want to fail
1223 * if the above doesnt work. So assume the | is breaking the conditional
1224 * and move on. The next token will fail if this is incorrect. */
1227 return WPS_ERROR_INVALID_PARAM
;
1230 if (LIST_VALUE_PARSED(set
, PB_FILENAME
)) /* filename */
1231 pb
->bm
.data
= (char*)filename
;
1233 if (LIST_VALUE_PARSED(set
, PB_X
)) /* x */
1238 if (LIST_VALUE_PARSED(set
, PB_WIDTH
)) /* width */
1240 /* A zero width causes a divide-by-zero error later, so reject it */
1242 return WPS_ERROR_INVALID_PARAM
;
1247 pb
->width
= vp
->width
- pb
->x
;
1249 if (LIST_VALUE_PARSED(set
, PB_HEIGHT
)) /* height, default to font height */
1251 /* A zero height makes no sense - reject it */
1253 return WPS_ERROR_INVALID_PARAM
;
1255 pb
->height
= height
;
1259 if (vp
->font
> FONT_UI
)
1260 pb
->height
= -1; /* calculate at display time */
1264 pb
->height
= font_get(vp
->font
)->height
;
1271 if (LIST_VALUE_PARSED(set
, PB_Y
)) /* y */
1274 pb
->y
= -line_num
- 1; /* Will be computed during the rendering */
1276 add_to_ll_chain(&wps_data
->progressbars
, item
);
1277 if (token
->type
== WPS_TOKEN_VOLUME
)
1278 token
->type
= WPS_TOKEN_VOLUMEBAR
;
1279 else if (token
->type
== WPS_TOKEN_BATTERY_PERCENT
)
1280 token
->type
= WPS_TOKEN_BATTERY_PERCENTBAR
;
1281 pb
->type
= token
->type
;
1283 return ptr
+1-wps_bufptr
;
1286 if (token
->type
!= WPS_TOKEN_VOLUME
&&
1287 token
->type
!= WPS_TOKEN_BATTERY_PERCENTBAR
)
1289 wps_data
->full_line_progressbar
=
1290 token
->type
== WPS_TOKEN_PLAYER_PROGRESSBAR
;
1297 #ifdef HAVE_ALBUMART
1298 static int parse_int(const char *newline
, const char **_pos
, int *num
)
1300 *_pos
= parse_list("d", NULL
, '|', *_pos
, num
);
1302 return (!*_pos
|| *_pos
> newline
|| **_pos
!= '|');
1305 static int parse_albumart_load(const char *wps_bufptr
,
1306 struct wps_token
*token
,
1307 struct wps_data
*wps_data
)
1309 const char *_pos
, *newline
;
1311 struct dim dimensions
;
1313 bool swap_for_rtl
= lang_is_rtl() && follow_lang_direction
;
1314 struct skin_albumart
*aa
= skin_buffer_alloc(sizeof(struct skin_albumart
));
1315 (void)token
; /* silence warning */
1317 return skip_end_of_line(wps_bufptr
);
1319 /* reset albumart info in wps */
1322 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
1323 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
1324 aa
->vp
= &curr_vp
->vp
;
1326 /* format: %Cl|x|y|[[l|c|r]mwidth]|[[t|c|b]mheight]| */
1328 newline
= strchr(wps_bufptr
, '\n');
1333 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
1337 /* initial validation and parsing of x component */
1338 if (parse_int(newline
, &_pos
, &aa
->x
))
1339 return WPS_ERROR_INVALID_PARAM
;
1343 /* initial validation and parsing of y component */
1344 if (parse_int(newline
, &_pos
, &aa
->y
))
1345 return WPS_ERROR_INVALID_PARAM
;
1347 /* parsing width field */
1351 /* apply each modifier in turn */
1359 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1361 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1365 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
;
1371 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1373 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1381 /* simply ignored */
1388 /* extract max width data */
1391 if (parse_int(newline
, &_pos
, &aa
->width
))
1392 return WPS_ERROR_INVALID_PARAM
;
1395 /* parsing height field */
1399 /* apply each modifier in turn */
1406 aa
->yalign
= WPS_ALBUMART_ALIGN_TOP
;
1410 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
;
1415 aa
->yalign
= WPS_ALBUMART_ALIGN_BOTTOM
;
1423 /* simply ignored */
1430 /* extract max height data */
1433 if (parse_int(newline
, &_pos
, &aa
->height
))
1434 return WPS_ERROR_INVALID_PARAM
;
1437 /* if we got here, we parsed everything ok .. ! */
1440 else if (aa
->width
> LCD_WIDTH
)
1441 aa
->width
= LCD_WIDTH
;
1445 else if (aa
->height
> LCD_HEIGHT
)
1446 aa
->height
= LCD_HEIGHT
;
1449 aa
->x
= LCD_WIDTH
- (aa
->x
+ aa
->width
);
1451 aa
->state
= WPS_ALBUMART_LOAD
;
1453 wps_data
->albumart
= aa
;
1455 dimensions
.width
= aa
->width
;
1456 dimensions
.height
= aa
->height
;
1458 albumart_slot
= playback_claim_aa_slot(&dimensions
);
1460 if (0 <= albumart_slot
)
1461 wps_data
->playback_aa_slot
= albumart_slot
;
1463 /* Skip the rest of the line */
1464 return skip_end_of_line(wps_bufptr
);
1467 static int parse_albumart_display(const char *wps_bufptr
,
1468 struct wps_token
*token
,
1469 struct wps_data
*wps_data
)
1472 struct wps_token
*prev
= token
-1;
1473 if ((wps_data
->num_tokens
>= 1) && (prev
->type
== WPS_TOKEN_CONDITIONAL
))
1475 token
->type
= WPS_TOKEN_ALBUMART_FOUND
;
1477 else if (wps_data
->albumart
)
1479 wps_data
->albumart
->vp
= &curr_vp
->vp
;
1482 /* the old code did this so keep it here for now...
1483 * this is to allow the posibility to showing the next tracks AA! */
1484 if (wps_bufptr
+1 == 'n')
1489 #endif /* HAVE_ALBUMART */
1491 #ifdef HAVE_TOUCHSCREEN
1493 struct touchaction
{const char* s
; int action
;};
1494 static const struct touchaction touchactions
[] = {
1495 {"play", ACTION_WPS_PLAY
}, {"stop", ACTION_WPS_STOP
},
1496 {"prev", ACTION_WPS_SKIPPREV
}, {"next", ACTION_WPS_SKIPNEXT
},
1497 {"ffwd", ACTION_WPS_SEEKFWD
}, {"rwd", ACTION_WPS_SEEKBACK
},
1498 {"menu", ACTION_WPS_MENU
}, {"browse", ACTION_WPS_BROWSE
},
1499 {"shuffle", ACTION_TOUCH_SHUFFLE
}, {"repmode", ACTION_TOUCH_REPMODE
},
1500 {"quickscreen", ACTION_WPS_QUICKSCREEN
},{"contextmenu", ACTION_WPS_CONTEXT
},
1501 {"playlist", ACTION_WPS_VIEW_PLAYLIST
}, {"pitch", ACTION_WPS_PITCHSCREEN
},
1502 {"voldown", ACTION_WPS_VOLDOWN
}, {"volup", ACTION_WPS_VOLUP
},
1504 static int parse_touchregion(const char *wps_bufptr
,
1505 struct wps_token
*token
, struct wps_data
*wps_data
)
1509 struct touchregion
*region
= NULL
;
1510 const char *ptr
= wps_bufptr
;
1511 const char *action
, *end
;
1512 const char pb_string
[] = "progressbar";
1513 const char vol_string
[] = "volume";
1517 /* format: %T|x|y|width|height|action|
1518 * if action starts with & the area must be held to happen
1520 * play - play/pause playback
1521 * stop - stop playback, exit the wps
1524 * ffwd - seek forward
1525 * rwd - seek backwards
1526 * menu - go back to the main menu
1527 * browse - go back to the file/db browser
1528 * shuffle - toggle shuffle mode
1529 * repmode - cycle the repeat mode
1530 * quickscreen - go into the quickscreen
1531 * contextmenu - open the context menu
1532 * playlist - go into the playlist
1533 * pitch - go into the pitchscreen
1534 * volup - increase volume by one step
1535 * voldown - decrease volume by one step
1540 return WPS_ERROR_INVALID_PARAM
;
1543 if (!(ptr
= parse_list("dddds", NULL
, '|', ptr
, &x
, &y
, &w
, &h
, &action
)))
1544 return WPS_ERROR_INVALID_PARAM
;
1546 /* Check there is a terminating | */
1548 return WPS_ERROR_INVALID_PARAM
;
1550 region
= skin_buffer_alloc(sizeof(struct touchregion
));
1552 return WPS_ERROR_INVALID_PARAM
;
1554 /* should probably do some bounds checking here with the viewport... but later */
1555 region
->action
= ACTION_NONE
;
1560 region
->wvp
= curr_vp
;
1561 region
->armed
= false;
1563 end
= strchr(action
, '|');
1564 if (!end
|| (size_t)(end
-action
+1) > sizeof temp
)
1565 return WPS_ERROR_INVALID_PARAM
;
1566 strlcpy(temp
, action
, end
-action
+1);
1569 if(!strcmp(pb_string
, action
))
1570 region
->type
= WPS_TOUCHREGION_SCROLLBAR
;
1571 else if(!strcmp(vol_string
, action
))
1572 region
->type
= WPS_TOUCHREGION_VOLUME
;
1575 region
->type
= WPS_TOUCHREGION_ACTION
;
1580 region
->repeat
= true;
1583 region
->repeat
= false;
1585 imax
= ARRAYLEN(touchactions
);
1586 for (i
= 0; i
< imax
; i
++)
1588 /* try to match with one of our touchregion screens */
1589 if (!strcmp(touchactions
[i
].s
, action
))
1591 region
->action
= touchactions
[i
].action
;
1595 if (region
->action
== ACTION_NONE
)
1596 return WPS_ERROR_INVALID_PARAM
;
1598 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, region
);
1600 return WPS_ERROR_INVALID_PARAM
;
1601 add_to_ll_chain(&wps_data
->touchregions
, item
);
1602 return skip_end_of_line(wps_bufptr
);
1606 /* Parse a generic token from the given string. Return the length read */
1607 static int parse_token(const char *wps_bufptr
, struct wps_data
*wps_data
)
1609 int skip
= 0, taglen
= 0, ret
;
1610 struct wps_token
*token
= wps_data
->tokens
+ wps_data
->num_tokens
;
1611 const struct wps_tag
*tag
;
1612 memset(token
, 0, sizeof(*token
));
1623 /* escaped characters */
1624 token
->type
= WPS_TOKEN_CHARACTER
;
1625 token
->value
.c
= *wps_bufptr
;
1627 wps_data
->num_tokens
++;
1631 /* conditional tag */
1632 token
->type
= WPS_TOKEN_CONDITIONAL
;
1634 condindex
[level
] = wps_data
->num_tokens
;
1635 numoptions
[level
] = 1;
1636 wps_data
->num_tokens
++;
1637 ret
= parse_token(wps_bufptr
+ 1, wps_data
);
1638 if (ret
< 0) return ret
;
1643 /* find what tag we have */
1644 for (tag
= all_tags
;
1645 strncmp(wps_bufptr
, tag
->name
, strlen(tag
->name
)) != 0;
1648 taglen
= (tag
->type
!= WPS_TOKEN_UNKNOWN
) ? strlen(tag
->name
) : 2;
1649 token
->type
= tag
->type
;
1650 curr_line
->curr_subline
->line_type
|= tag
->refresh_type
;
1652 /* if the tag has a special parsing function, we call it */
1653 if (tag
->parse_func
)
1655 ret
= tag
->parse_func(wps_bufptr
+ taglen
, token
, wps_data
);
1656 if (ret
< 0) return ret
;
1660 /* Some tags we don't want to save as tokens */
1661 if (tag
->type
== WPS_NO_TOKEN
)
1664 /* tags that start with 'F', 'I' or 'D' are for the next file */
1665 if ( *(tag
->name
) == 'I' || *(tag
->name
) == 'F' ||
1666 *(tag
->name
) == 'D')
1669 wps_data
->num_tokens
++;
1679 * Returns the number of bytes to skip the buf pointer to access the false
1680 * branch in a _binary_ conditional
1683 * - before the '|' if we have a false branch, (%?<true|false> -> %?<|false>)
1684 * - or before the closing '>' if there's no false branch (%?<true> -> %?<>)
1686 * depending on the features of a target it's not called from check_feature_tag,
1687 * hence the __attribute__ or it issues compiler warnings
1691 static int find_false_branch(const char *wps_bufptr
) __attribute__((unused
));
1692 static int find_false_branch(const char *wps_bufptr
)
1694 const char *buf
= wps_bufptr
;
1695 /* wps_bufptr is after the opening '<', hence level = 1*/
1702 { /* filter out the characters we check later if they're printed
1705 if (ch
== '<' || ch
== '>' || ch
== '|')
1707 /* else: some tags/printed literals we skip over */
1709 else if (ch
== '<') /* nested conditional */
1712 { /* closed our or a nested conditional,
1713 * do NOT skip over the '>' so that wps_parse() sees it for closing
1714 * if it is the closing one for our conditional */
1717 else if (ch
== '|' && level
== 1)
1718 { /* we found our separator, point before and get out */
1721 /* if level is 0, we don't have a false branch */
1722 } while (level
> 0 && *(++buf
));
1724 return buf
- wps_bufptr
;
1728 * returns the number of bytes to get the appropriate branch of a binary
1732 * - if a feature is available, it returns 0 to not skip anything
1733 * - if the feature is not available, skip to the false branch and don't
1734 * parse the true branch at all
1737 static int check_feature_tag(const char *wps_bufptr
, const int type
)
1742 case WPS_TOKEN_RTC_PRESENT
:
1746 return find_false_branch(wps_bufptr
);
1748 case WPS_TOKEN_HAVE_RECORDING
:
1749 #ifdef HAVE_RECORDING
1752 return find_false_branch(wps_bufptr
);
1754 case WPS_TOKEN_HAVE_TUNER
:
1756 if (radio_hardware_present())
1759 return find_false_branch(wps_bufptr
);
1761 default: /* not a tag we care about, just don't skip */
1768 data is the pointer to the structure where the parsed WPS should be stored.
1770 wps_bufptr points to the string containing the WPS tags */
1771 #define TOKEN_BLOCK_SIZE 128
1772 static bool wps_parse(struct wps_data
*data
, const char *wps_bufptr
, bool debug
)
1774 if (!data
|| !wps_bufptr
|| !*wps_bufptr
)
1776 enum wps_parse_error fail
= PARSE_OK
;
1778 int max_tokens
= TOKEN_BLOCK_SIZE
;
1779 size_t buf_free
= 0;
1783 /* allocate enough RAM for a reasonable skin, grow as needed.
1784 * Free any used RAM before loading the images to be 100% RAM efficient */
1785 data
->tokens
= (struct wps_token
*)skin_buffer_grab(&buf_free
);
1786 if (sizeof(struct wps_token
)*max_tokens
>= buf_free
)
1788 skin_buffer_increment(max_tokens
* sizeof(struct wps_token
), false);
1789 data
->num_tokens
= 0;
1792 /* Backdrop defaults to the setting unless %X is used, so set it now */
1793 if (global_settings
.backdrop_file
[0])
1795 data
->backdrop
= "-";
1799 while (*wps_bufptr
&& !fail
)
1801 if (follow_lang_direction
)
1802 follow_lang_direction
--;
1803 /* first make sure there is enough room for tokens */
1804 if (max_tokens
<= data
->num_tokens
+ 5)
1806 int extra_tokens
= TOKEN_BLOCK_SIZE
;
1807 size_t needed
= extra_tokens
* sizeof(struct wps_token
);
1808 /* do some smarts here to grow the array a bit */
1809 if (skin_buffer_freespace() < needed
)
1811 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1814 skin_buffer_increment(needed
, false);
1815 max_tokens
+= extra_tokens
;
1818 switch(*wps_bufptr
++)
1823 if ((ret
= parse_token(wps_bufptr
, data
)) < 0)
1825 fail
= PARSE_FAIL_COND_INVALID_PARAM
;
1828 else if (level
>= WPS_MAX_COND_LEVEL
- 1)
1830 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1836 /* Alternating sublines separator */
1838 if (level
>= 0) /* there are unclosed conditionals */
1840 fail
= PARSE_FAIL_UNCLOSED_COND
;
1844 if (!skin_start_new_subline(curr_line
, data
->num_tokens
))
1845 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1849 /* Conditional list start */
1851 if (data
->tokens
[data
->num_tokens
-2].type
!= WPS_TOKEN_CONDITIONAL
)
1853 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1856 wps_bufptr
+= check_feature_tag(wps_bufptr
,
1857 data
->tokens
[data
->num_tokens
-1].type
);
1858 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_START
;
1859 lastcond
[level
] = data
->num_tokens
++;
1862 /* Conditional list end */
1864 if (level
< 0) /* not in a conditional, invalid char */
1866 fail
= PARSE_FAIL_INVALID_CHAR
;
1870 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_END
;
1871 if (lastcond
[level
])
1872 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1875 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1879 lastcond
[level
] = 0;
1881 data
->tokens
[condindex
[level
]].value
.i
= numoptions
[level
];
1885 /* Conditional list option */
1887 if (level
< 0) /* not in a conditional, invalid char */
1889 fail
= PARSE_FAIL_INVALID_CHAR
;
1893 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_OPTION
;
1894 if (lastcond
[level
])
1895 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1898 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1902 lastcond
[level
] = data
->num_tokens
;
1903 numoptions
[level
]++;
1909 if (level
>= 0) /* there are unclosed conditionals */
1911 fail
= PARSE_FAIL_UNCLOSED_COND
;
1915 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1918 /* End of this line */
1920 if (level
>= 0) /* there are unclosed conditionals */
1922 fail
= PARSE_FAIL_UNCLOSED_COND
;
1925 /* add a new token for the \n so empty lines are correct */
1926 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CHARACTER
;
1927 data
->tokens
[data
->num_tokens
].value
.c
= '\n';
1928 data
->tokens
[data
->num_tokens
].next
= false;
1931 if (!skin_start_new_line(curr_vp
, data
->num_tokens
))
1933 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1943 unsigned int len
= 1;
1944 const char *string_start
= wps_bufptr
- 1;
1946 /* find the length of the string */
1947 while (*wps_bufptr
&& *wps_bufptr
!= '#' &&
1948 *wps_bufptr
!= '%' && *wps_bufptr
!= ';' &&
1949 *wps_bufptr
!= '<' && *wps_bufptr
!= '>' &&
1950 *wps_bufptr
!= '|' && *wps_bufptr
!= '\n')
1956 /* look if we already have that string */
1959 struct skin_token_list
*list
= data
->strings
;
1962 str
= (char*)list
->token
->value
.data
;
1963 found
= (strlen(str
) == len
&&
1964 strncmp(string_start
, str
, len
) == 0);
1966 break; /* break here because the list item is
1967 used if its found */
1970 /* If a matching string is found, found is true and i is
1971 the index of the string. If not, found is false */
1976 str
= (char*)skin_buffer_alloc(len
+1);
1979 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1982 strlcpy(str
, string_start
, len
+1);
1983 struct skin_token_list
*item
=
1984 new_skin_token_list_item(&data
->tokens
[data
->num_tokens
], str
);
1987 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1990 add_to_ll_chain(&data
->strings
, item
);
1994 /* another occurrence of an existing string */
1995 data
->tokens
[data
->num_tokens
].value
.data
= list
->token
->value
.data
;
1997 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_STRING
;
2004 if (!fail
&& level
>= 0) /* there are unclosed conditionals */
2005 fail
= PARSE_FAIL_UNCLOSED_COND
;
2007 if (*wps_bufptr
&& !fail
)
2008 /* one of the limits of the while loop was exceeded */
2009 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
2012 curr_line
->curr_subline
->last_token_idx
= data
->num_tokens
;
2013 data
->tokens
[data
->num_tokens
++].type
= WPS_NO_TOKEN
;
2014 /* freeup unused tokens */
2015 skin_buffer_free_from_front(sizeof(struct wps_token
)
2016 * (max_tokens
- data
->num_tokens
));
2018 #if defined(DEBUG) || defined(SIMULATOR)
2021 print_debug_info(data
, fail
, line_number
);
2033 * initial setup of wps_data; does reset everything
2034 * except fields which need to survive, i.e.
2037 static void skin_data_reset(struct wps_data
*wps_data
)
2039 #ifdef HAVE_LCD_BITMAP
2040 wps_data
->images
= NULL
;
2041 wps_data
->progressbars
= NULL
;
2043 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
2044 wps_data
->backdrop
= NULL
;
2046 #ifdef HAVE_TOUCHSCREEN
2047 wps_data
->touchregions
= NULL
;
2049 wps_data
->viewports
= NULL
;
2050 wps_data
->strings
= NULL
;
2051 #ifdef HAVE_ALBUMART
2052 wps_data
->albumart
= NULL
;
2053 if (wps_data
->playback_aa_slot
>= 0)
2055 playback_release_aa_slot(wps_data
->playback_aa_slot
);
2056 wps_data
->playback_aa_slot
= -1;
2059 wps_data
->tokens
= NULL
;
2060 wps_data
->num_tokens
= 0;
2062 #ifdef HAVE_LCD_BITMAP
2063 wps_data
->peak_meter_enabled
= false;
2064 wps_data
->wps_sb_tag
= false;
2065 wps_data
->show_sb_on_wps
= false;
2066 #else /* HAVE_LCD_CHARCELLS */
2069 for (i
= 0; i
< 8; i
++)
2071 wps_data
->wps_progress_pat
[i
] = 0;
2073 wps_data
->full_line_progressbar
= false;
2075 wps_data
->wps_loaded
= false;
2078 #ifdef HAVE_LCD_BITMAP
2079 static bool load_skin_bmp(struct wps_data
*wps_data
, struct bitmap
*bitmap
, char* bmpdir
)
2081 (void)wps_data
; /* only needed for remote targets */
2082 char img_path
[MAX_PATH
];
2083 get_image_filename(bitmap
->data
, bmpdir
,
2084 img_path
, sizeof(img_path
));
2086 /* load the image */
2088 #ifdef HAVE_REMOTE_LCD
2089 if (curr_screen
== SCREEN_REMOTE
)
2090 format
= FORMAT_ANY
|FORMAT_REMOTE
;
2093 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
2096 char* imgbuf
= (char*)skin_buffer_grab(&max_buf
);
2097 bitmap
->data
= imgbuf
;
2098 int ret
= read_bmp_file(img_path
, bitmap
, max_buf
, format
, NULL
);
2102 skin_buffer_increment(ret
, true);
2107 /* Abort if we can't load an image */
2108 DEBUGF("Couldn't load '%s'\n", img_path
);
2113 static bool load_skin_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
2115 struct skin_token_list
*list
;
2116 bool retval
= true; /* return false if a single image failed to load */
2117 /* do the progressbars */
2118 list
= wps_data
->progressbars
;
2121 struct progressbar
*pb
= (struct progressbar
*)list
->token
->value
.data
;
2124 pb
->have_bitmap_pb
= load_skin_bmp(wps_data
, &pb
->bm
, bmpdir
);
2125 if (!pb
->have_bitmap_pb
) /* no success */
2130 /* regular images */
2131 list
= wps_data
->images
;
2134 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
2137 img
->loaded
= load_skin_bmp(wps_data
, &img
->bm
, bmpdir
);
2139 img
->subimage_height
= img
->bm
.height
/ img
->num_subimages
;
2146 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
2147 /* Backdrop load scheme:
2149 * 2) load the backdrop from settings
2151 if (wps_data
->backdrop
)
2153 bool needed
= wps_data
->backdrop
[0] != '-';
2154 wps_data
->backdrop
= skin_backdrop_load(wps_data
->backdrop
,
2155 bmpdir
, curr_screen
);
2156 if (!wps_data
->backdrop
&& needed
)
2159 #endif /* has backdrop support */
2164 static bool skin_load_fonts(struct wps_data
*data
)
2166 /* don't spit out after the first failue to aid debugging */
2167 bool success
= true;
2168 struct skin_token_list
*vp_list
;
2170 /* walk though each viewport and assign its font */
2171 for(vp_list
= data
->viewports
; vp_list
; vp_list
= vp_list
->next
)
2173 /* first, find the viewports that have a non-sys/ui-font font */
2174 struct skin_viewport
*skin_vp
=
2175 (struct skin_viewport
*)vp_list
->token
->value
.data
;
2176 struct viewport
*vp
= &skin_vp
->vp
;
2179 if (vp
->font
<= FONT_UI
)
2180 { /* the usual case -> built-in fonts */
2181 #ifdef HAVE_REMOTE_LCD
2182 if (vp
->font
== FONT_UI
)
2183 vp
->font
+= curr_screen
;
2189 /* now find the corresponding skin_font */
2190 struct skin_font
*font
= &skinfonts
[font_id
-FONT_FIRSTUSERFONT
];
2193 DEBUGF("font %d not specified\n", font_id
);
2198 /* load the font - will handle loading the same font again if
2199 * multiple viewports use the same */
2202 char *dot
= strchr(font
->name
, '.');
2204 font
->id
= skin_font_load(font
->name
);
2209 DEBUGF("Unable to load font %d: '%s.fnt'\n",
2210 font_id
, font
->name
);
2215 /* finally, assign the font_id to the viewport */
2216 vp
->font
= font
->id
;
2221 #endif /* HAVE_LCD_BITMAP */
2223 /* to setup up the wps-data from a format-buffer (isfile = false)
2224 from a (wps-)file (isfile = true)*/
2225 bool skin_data_load(enum screen_type screen
, struct wps_data
*wps_data
,
2226 const char *buf
, bool isfile
)
2228 char *wps_buffer
= NULL
;
2229 if (!wps_data
|| !buf
)
2231 #ifdef HAVE_ALBUMART
2233 struct mp3entry
*curtrack
;
2235 struct skin_albumart old_aa
= {.state
= WPS_ALBUMART_NONE
};
2236 if (wps_data
->albumart
)
2238 old_aa
.state
= wps_data
->albumart
->state
;
2239 old_aa
.height
= wps_data
->albumart
->height
;
2240 old_aa
.width
= wps_data
->albumart
->width
;
2243 #ifdef HAVE_LCD_BITMAP
2245 for (i
=0;i
<MAXUSERFONTS
;i
++)
2247 skinfonts
[i
].id
= -1;
2248 skinfonts
[i
].name
= NULL
;
2251 #ifdef DEBUG_SKIN_ENGINE
2252 if (isfile
&& debug_wps
)
2254 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf
);
2258 skin_data_reset(wps_data
);
2259 wps_data
->wps_loaded
= false;
2260 curr_screen
= screen
;
2262 /* alloc default viewport, will be fixed up later */
2263 curr_vp
= skin_buffer_alloc(sizeof(struct skin_viewport
));
2266 struct skin_token_list
*list
= new_skin_token_list_item(NULL
, curr_vp
);
2269 add_to_ll_chain(&wps_data
->viewports
, list
);
2272 /* Initialise the first (default) viewport */
2273 curr_vp
->label
= VP_DEFAULT_LABEL
;
2274 curr_vp
->hidden_flags
= 0;
2275 curr_vp
->lines
= NULL
;
2277 viewport_set_defaults(&curr_vp
->vp
, screen
);
2278 #ifdef HAVE_LCD_BITMAP
2279 curr_vp
->vp
.font
= FONT_UI
;
2283 if (!skin_start_new_line(curr_vp
, 0))
2288 int fd
= open_utf8(buf
, O_RDONLY
);
2293 /* get buffer space from the plugin buffer */
2294 size_t buffersize
= 0;
2295 wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
2300 /* copy the file's content to the buffer for parsing,
2301 ensuring that every line ends with a newline char. */
2302 unsigned int start
= 0;
2303 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
2305 start
+= strlen(wps_buffer
+ start
);
2306 if (start
< buffersize
- 1)
2308 wps_buffer
[start
++] = '\n';
2309 wps_buffer
[start
] = 0;
2318 wps_buffer
= (char*)buf
;
2320 /* parse the WPS source */
2321 if (!wps_parse(wps_data
, wps_buffer
, isfile
)) {
2322 skin_data_reset(wps_data
);
2326 #ifdef HAVE_LCD_BITMAP
2327 char bmpdir
[MAX_PATH
];
2330 /* get the bitmap dir */
2331 char *dot
= strrchr(buf
, '.');
2332 strlcpy(bmpdir
, buf
, dot
- buf
+ 1);
2336 snprintf(bmpdir
, MAX_PATH
, "%s", BACKDROP_DIR
);
2338 /* load the bitmaps that were found by the parsing */
2339 if (!load_skin_bitmaps(wps_data
, bmpdir
) ||
2340 !skin_load_fonts(wps_data
))
2342 skin_data_reset(wps_data
);
2346 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
2347 status
= audio_status();
2348 if (status
& AUDIO_STATUS_PLAY
)
2350 struct skin_albumart
*aa
= wps_data
->albumart
;
2351 if (aa
&& ((aa
->state
&& !old_aa
.state
) ||
2353 (((old_aa
.height
!= aa
->height
) ||
2354 (old_aa
.width
!= aa
->width
))))))
2356 curtrack
= audio_current_track();
2357 offset
= curtrack
->offset
;
2359 if (!(status
& AUDIO_STATUS_PAUSE
))
2364 wps_data
->wps_loaded
= true;
2365 #ifdef DEBUG_SKIN_ENGINE
2366 if (isfile
&& debug_wps
)