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
,'|');
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 !strncmp(settings
[i
].cfg_name
,ptr
,end
-ptr
) &&
1088 /* prevent matches on cfg_name prefixes */
1089 strlen(settings
[i
].cfg_name
)==(size_t)(end
-ptr
))
1092 if (i
== nb_settings
)
1093 return WPS_ERROR_INVALID_PARAM
;
1096 /* Store the setting number */
1099 /* Skip the rest of the line */
1104 static int parse_dir_level(const char *wps_bufptr
,
1105 struct wps_token
*token
,
1106 struct wps_data
*wps_data
)
1108 char val
[] = { *wps_bufptr
, '\0' };
1109 token
->value
.i
= atoi(val
);
1110 (void)wps_data
; /* Kill warnings */
1114 static int parse_timeout(const char *wps_bufptr
,
1115 struct wps_token
*token
,
1116 struct wps_data
*wps_data
)
1120 bool have_point
= false;
1121 bool have_tenth
= false;
1123 (void)wps_data
; /* Kill the warning */
1125 while ( isdigit(*wps_bufptr
) || *wps_bufptr
== '.' )
1127 if (*wps_bufptr
!= '.')
1130 val
+= *wps_bufptr
- '0';
1146 if (have_tenth
== false)
1149 if (val
== 0 && skip
== 0)
1151 /* decide what to do if no value was specified */
1152 switch (token
->type
)
1154 case WPS_TOKEN_SUBLINE_TIMEOUT
:
1156 case WPS_TOKEN_BUTTON_VOLUME
:
1157 case WPS_TOKEN_TRACK_STARTING
:
1158 case WPS_TOKEN_TRACK_ENDING
:
1163 token
->value
.i
= val
;
1168 static int parse_progressbar(const char *wps_bufptr
,
1169 struct wps_token
*token
,
1170 struct wps_data
*wps_data
)
1172 /* %pb or %pb|filename|x|y|width|height|
1173 using - for any of the params uses "sane" values */
1174 #ifdef HAVE_LCD_BITMAP
1182 const char *filename
;
1183 int x
, y
, height
, width
;
1185 const char *ptr
= wps_bufptr
;
1186 struct progressbar
*pb
= skin_buffer_alloc(sizeof(struct progressbar
));
1187 struct skin_token_list
*item
= new_skin_token_list_item(token
, pb
);
1190 return WPS_ERROR_INVALID_PARAM
;
1192 struct viewport
*vp
= &curr_vp
->vp
;
1193 /* we need to know what line number (viewport relative) this pb is,
1194 * so count them... */
1196 struct skin_line
*line
= curr_vp
->lines
;
1203 pb
->have_bitmap_pb
= false;
1204 pb
->bm
.data
= NULL
; /* no bitmap specified */
1205 pb
->follow_lang_direction
= follow_lang_direction
> 0;
1208 if (*wps_bufptr
!= '|') /* regular old style */
1211 pb
->width
= vp
->width
;
1212 pb
->height
= SYSFONT_HEIGHT
-2;
1213 pb
->y
= -line_num
- 1; /* Will be computed during the rendering */
1214 if (token
->type
== WPS_TOKEN_VOLUME
|| token
->type
== WPS_TOKEN_BATTERY_PERCENT
)
1215 return 0; /* dont add it, let the regular token handling do the work */
1216 add_to_ll_chain(&wps_data
->progressbars
, item
);
1219 ptr
= wps_bufptr
+ 1;
1221 if (!(ptr
= parse_list("sdddd", &set
, '|', ptr
, &filename
,
1222 &x
, &y
, &width
, &height
)))
1224 /* If we are in a conditional then we probably don't want to fail
1225 * if the above doesnt work. So assume the | is breaking the conditional
1226 * and move on. The next token will fail if this is incorrect. */
1229 return WPS_ERROR_INVALID_PARAM
;
1232 if (LIST_VALUE_PARSED(set
, PB_FILENAME
)) /* filename */
1233 pb
->bm
.data
= (char*)filename
;
1235 if (LIST_VALUE_PARSED(set
, PB_X
)) /* x */
1240 if (LIST_VALUE_PARSED(set
, PB_WIDTH
)) /* width */
1242 /* A zero width causes a divide-by-zero error later, so reject it */
1244 return WPS_ERROR_INVALID_PARAM
;
1249 pb
->width
= vp
->width
- pb
->x
;
1251 if (LIST_VALUE_PARSED(set
, PB_HEIGHT
)) /* height, default to font height */
1253 /* A zero height makes no sense - reject it */
1255 return WPS_ERROR_INVALID_PARAM
;
1257 pb
->height
= height
;
1261 if (vp
->font
> FONT_UI
)
1262 pb
->height
= -1; /* calculate at display time */
1266 pb
->height
= font_get(vp
->font
)->height
;
1273 if (LIST_VALUE_PARSED(set
, PB_Y
)) /* y */
1276 pb
->y
= -line_num
- 1; /* Will be computed during the rendering */
1278 add_to_ll_chain(&wps_data
->progressbars
, item
);
1279 if (token
->type
== WPS_TOKEN_VOLUME
)
1280 token
->type
= WPS_TOKEN_VOLUMEBAR
;
1281 else if (token
->type
== WPS_TOKEN_BATTERY_PERCENT
)
1282 token
->type
= WPS_TOKEN_BATTERY_PERCENTBAR
;
1283 pb
->type
= token
->type
;
1285 return ptr
+1-wps_bufptr
;
1288 if (token
->type
!= WPS_TOKEN_VOLUME
&&
1289 token
->type
!= WPS_TOKEN_BATTERY_PERCENTBAR
)
1291 wps_data
->full_line_progressbar
=
1292 token
->type
== WPS_TOKEN_PLAYER_PROGRESSBAR
;
1299 #ifdef HAVE_ALBUMART
1300 static int parse_int(const char *newline
, const char **_pos
, int *num
)
1302 *_pos
= parse_list("d", NULL
, '|', *_pos
, num
);
1304 return (!*_pos
|| *_pos
> newline
|| **_pos
!= '|');
1307 static int parse_albumart_load(const char *wps_bufptr
,
1308 struct wps_token
*token
,
1309 struct wps_data
*wps_data
)
1311 const char *_pos
, *newline
;
1313 struct dim dimensions
;
1315 bool swap_for_rtl
= lang_is_rtl() && follow_lang_direction
;
1316 struct skin_albumart
*aa
= skin_buffer_alloc(sizeof(struct skin_albumart
));
1317 (void)token
; /* silence warning */
1319 return skip_end_of_line(wps_bufptr
);
1321 /* reset albumart info in wps */
1324 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
1325 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
1326 aa
->vp
= &curr_vp
->vp
;
1328 /* format: %Cl|x|y|[[l|c|r]mwidth]|[[t|c|b]mheight]| */
1330 newline
= strchr(wps_bufptr
, '\n');
1335 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
1339 /* initial validation and parsing of x component */
1340 if (parse_int(newline
, &_pos
, &aa
->x
))
1341 return WPS_ERROR_INVALID_PARAM
;
1345 /* initial validation and parsing of y component */
1346 if (parse_int(newline
, &_pos
, &aa
->y
))
1347 return WPS_ERROR_INVALID_PARAM
;
1349 /* parsing width field */
1353 /* apply each modifier in turn */
1361 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1363 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1367 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
;
1373 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1375 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1383 /* simply ignored */
1390 /* extract max width data */
1393 if (parse_int(newline
, &_pos
, &aa
->width
))
1394 return WPS_ERROR_INVALID_PARAM
;
1397 /* parsing height field */
1401 /* apply each modifier in turn */
1408 aa
->yalign
= WPS_ALBUMART_ALIGN_TOP
;
1412 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
;
1417 aa
->yalign
= WPS_ALBUMART_ALIGN_BOTTOM
;
1425 /* simply ignored */
1432 /* extract max height data */
1435 if (parse_int(newline
, &_pos
, &aa
->height
))
1436 return WPS_ERROR_INVALID_PARAM
;
1439 /* if we got here, we parsed everything ok .. ! */
1442 else if (aa
->width
> LCD_WIDTH
)
1443 aa
->width
= LCD_WIDTH
;
1447 else if (aa
->height
> LCD_HEIGHT
)
1448 aa
->height
= LCD_HEIGHT
;
1451 aa
->x
= LCD_WIDTH
- (aa
->x
+ aa
->width
);
1453 aa
->state
= WPS_ALBUMART_LOAD
;
1455 wps_data
->albumart
= aa
;
1457 dimensions
.width
= aa
->width
;
1458 dimensions
.height
= aa
->height
;
1460 albumart_slot
= playback_claim_aa_slot(&dimensions
);
1462 if (0 <= albumart_slot
)
1463 wps_data
->playback_aa_slot
= albumart_slot
;
1465 /* Skip the rest of the line */
1466 return skip_end_of_line(wps_bufptr
);
1469 static int parse_albumart_display(const char *wps_bufptr
,
1470 struct wps_token
*token
,
1471 struct wps_data
*wps_data
)
1474 struct wps_token
*prev
= token
-1;
1475 if ((wps_data
->num_tokens
>= 1) && (prev
->type
== WPS_TOKEN_CONDITIONAL
))
1477 token
->type
= WPS_TOKEN_ALBUMART_FOUND
;
1479 else if (wps_data
->albumart
)
1481 wps_data
->albumart
->vp
= &curr_vp
->vp
;
1484 /* the old code did this so keep it here for now...
1485 * this is to allow the posibility to showing the next tracks AA! */
1486 if (wps_bufptr
+1 == 'n')
1491 #endif /* HAVE_ALBUMART */
1493 #ifdef HAVE_TOUCHSCREEN
1495 struct touchaction
{const char* s
; int action
;};
1496 static const struct touchaction touchactions
[] = {
1497 {"play", ACTION_WPS_PLAY
}, {"stop", ACTION_WPS_STOP
},
1498 {"prev", ACTION_WPS_SKIPPREV
}, {"next", ACTION_WPS_SKIPNEXT
},
1499 {"ffwd", ACTION_WPS_SEEKFWD
}, {"rwd", ACTION_WPS_SEEKBACK
},
1500 {"menu", ACTION_WPS_MENU
}, {"browse", ACTION_WPS_BROWSE
},
1501 {"shuffle", ACTION_TOUCH_SHUFFLE
}, {"repmode", ACTION_TOUCH_REPMODE
},
1502 {"quickscreen", ACTION_WPS_QUICKSCREEN
},{"contextmenu", ACTION_WPS_CONTEXT
},
1503 {"playlist", ACTION_WPS_VIEW_PLAYLIST
}, {"pitch", ACTION_WPS_PITCHSCREEN
},
1504 {"voldown", ACTION_WPS_VOLDOWN
}, {"volup", ACTION_WPS_VOLUP
},
1506 static int parse_touchregion(const char *wps_bufptr
,
1507 struct wps_token
*token
, struct wps_data
*wps_data
)
1511 struct touchregion
*region
= NULL
;
1512 const char *ptr
= wps_bufptr
;
1514 const char pb_string
[] = "progressbar";
1515 const char vol_string
[] = "volume";
1518 /* format: %T|x|y|width|height|action|
1519 * if action starts with & the area must be held to happen
1521 * play - play/pause playback
1522 * stop - stop playback, exit the wps
1525 * ffwd - seek forward
1526 * rwd - seek backwards
1527 * menu - go back to the main menu
1528 * browse - go back to the file/db browser
1529 * shuffle - toggle shuffle mode
1530 * repmode - cycle the repeat mode
1531 * quickscreen - go into the quickscreen
1532 * contextmenu - open the context menu
1533 * playlist - go into the playlist
1534 * pitch - go into the pitchscreen
1535 * volup - increase volume by one step
1536 * voldown - decrease volume by one step
1541 return WPS_ERROR_INVALID_PARAM
;
1544 if (!(ptr
= parse_list("dddds", NULL
, '|', ptr
, &x
, &y
, &w
, &h
, &action
)))
1545 return WPS_ERROR_INVALID_PARAM
;
1547 /* Check there is a terminating | */
1549 return WPS_ERROR_INVALID_PARAM
;
1551 region
= skin_buffer_alloc(sizeof(struct touchregion
));
1553 return WPS_ERROR_INVALID_PARAM
;
1555 /* should probably do some bounds checking here with the viewport... but later */
1556 region
->action
= ACTION_NONE
;
1561 region
->wvp
= curr_vp
;
1562 region
->armed
= false;
1564 if(!strncmp(pb_string
, action
, sizeof(pb_string
)-1)
1565 && *(action
+ sizeof(pb_string
)-1) == '|')
1566 region
->type
= WPS_TOUCHREGION_SCROLLBAR
;
1567 else if(!strncmp(vol_string
, action
, sizeof(vol_string
)-1)
1568 && *(action
+ sizeof(vol_string
)-1) == '|')
1569 region
->type
= WPS_TOUCHREGION_VOLUME
;
1572 region
->type
= WPS_TOUCHREGION_ACTION
;
1577 region
->repeat
= true;
1580 region
->repeat
= false;
1583 imax
= ARRAYLEN(touchactions
);
1584 while ((region
->action
== ACTION_NONE
) &&
1587 /* try to match with one of our touchregion screens */
1588 int len
= strlen(touchactions
[i
].s
);
1589 if (!strncmp(touchactions
[i
].s
, action
, len
)
1590 && *(action
+len
) == '|')
1591 region
->action
= touchactions
[i
].action
;
1594 if (region
->action
== ACTION_NONE
)
1595 return WPS_ERROR_INVALID_PARAM
;
1597 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, region
);
1599 return WPS_ERROR_INVALID_PARAM
;
1600 add_to_ll_chain(&wps_data
->touchregions
, item
);
1601 return skip_end_of_line(wps_bufptr
);
1605 /* Parse a generic token from the given string. Return the length read */
1606 static int parse_token(const char *wps_bufptr
, struct wps_data
*wps_data
)
1608 int skip
= 0, taglen
= 0, ret
;
1609 struct wps_token
*token
= wps_data
->tokens
+ wps_data
->num_tokens
;
1610 const struct wps_tag
*tag
;
1611 memset(token
, 0, sizeof(*token
));
1622 /* escaped characters */
1623 token
->type
= WPS_TOKEN_CHARACTER
;
1624 token
->value
.c
= *wps_bufptr
;
1626 wps_data
->num_tokens
++;
1630 /* conditional tag */
1631 token
->type
= WPS_TOKEN_CONDITIONAL
;
1633 condindex
[level
] = wps_data
->num_tokens
;
1634 numoptions
[level
] = 1;
1635 wps_data
->num_tokens
++;
1636 ret
= parse_token(wps_bufptr
+ 1, wps_data
);
1637 if (ret
< 0) return ret
;
1642 /* find what tag we have */
1643 for (tag
= all_tags
;
1644 strncmp(wps_bufptr
, tag
->name
, strlen(tag
->name
)) != 0;
1647 taglen
= (tag
->type
!= WPS_TOKEN_UNKNOWN
) ? strlen(tag
->name
) : 2;
1648 token
->type
= tag
->type
;
1649 curr_line
->curr_subline
->line_type
|= tag
->refresh_type
;
1651 /* if the tag has a special parsing function, we call it */
1652 if (tag
->parse_func
)
1654 ret
= tag
->parse_func(wps_bufptr
+ taglen
, token
, wps_data
);
1655 if (ret
< 0) return ret
;
1659 /* Some tags we don't want to save as tokens */
1660 if (tag
->type
== WPS_NO_TOKEN
)
1663 /* tags that start with 'F', 'I' or 'D' are for the next file */
1664 if ( *(tag
->name
) == 'I' || *(tag
->name
) == 'F' ||
1665 *(tag
->name
) == 'D')
1668 wps_data
->num_tokens
++;
1678 * Returns the number of bytes to skip the buf pointer to access the false
1679 * branch in a _binary_ conditional
1682 * - before the '|' if we have a false branch, (%?<true|false> -> %?<|false>)
1683 * - or before the closing '>' if there's no false branch (%?<true> -> %?<>)
1685 * depending on the features of a target it's not called from check_feature_tag,
1686 * hence the __attribute__ or it issues compiler warnings
1690 static int find_false_branch(const char *wps_bufptr
) __attribute__((unused
));
1691 static int find_false_branch(const char *wps_bufptr
)
1693 const char *buf
= wps_bufptr
;
1694 /* wps_bufptr is after the opening '<', hence level = 1*/
1701 { /* filter out the characters we check later if they're printed
1704 if (ch
== '<' || ch
== '>' || ch
== '|')
1706 /* else: some tags/printed literals we skip over */
1708 else if (ch
== '<') /* nested conditional */
1711 { /* closed our or a nested conditional,
1712 * do NOT skip over the '>' so that wps_parse() sees it for closing
1713 * if it is the closing one for our conditional */
1716 else if (ch
== '|' && level
== 1)
1717 { /* we found our separator, point before and get out */
1720 /* if level is 0, we don't have a false branch */
1721 } while (level
> 0 && *(++buf
));
1723 return buf
- wps_bufptr
;
1727 * returns the number of bytes to get the appropriate branch of a binary
1731 * - if a feature is available, it returns 0 to not skip anything
1732 * - if the feature is not available, skip to the false branch and don't
1733 * parse the true branch at all
1736 static int check_feature_tag(const char *wps_bufptr
, const int type
)
1741 case WPS_TOKEN_RTC_PRESENT
:
1745 return find_false_branch(wps_bufptr
);
1747 case WPS_TOKEN_HAVE_RECORDING
:
1748 #ifdef HAVE_RECORDING
1751 return find_false_branch(wps_bufptr
);
1753 case WPS_TOKEN_HAVE_TUNER
:
1755 if (radio_hardware_present())
1758 return find_false_branch(wps_bufptr
);
1760 default: /* not a tag we care about, just don't skip */
1767 data is the pointer to the structure where the parsed WPS should be stored.
1769 wps_bufptr points to the string containing the WPS tags */
1770 #define TOKEN_BLOCK_SIZE 128
1771 static bool wps_parse(struct wps_data
*data
, const char *wps_bufptr
, bool debug
)
1773 if (!data
|| !wps_bufptr
|| !*wps_bufptr
)
1775 enum wps_parse_error fail
= PARSE_OK
;
1777 int max_tokens
= TOKEN_BLOCK_SIZE
;
1778 size_t buf_free
= 0;
1782 /* allocate enough RAM for a reasonable skin, grow as needed.
1783 * Free any used RAM before loading the images to be 100% RAM efficient */
1784 data
->tokens
= (struct wps_token
*)skin_buffer_grab(&buf_free
);
1785 if (sizeof(struct wps_token
)*max_tokens
>= buf_free
)
1787 skin_buffer_increment(max_tokens
* sizeof(struct wps_token
), false);
1788 data
->num_tokens
= 0;
1791 /* Backdrop defaults to the setting unless %X is used, so set it now */
1792 if (global_settings
.backdrop_file
[0])
1794 data
->backdrop
= "-";
1798 while (*wps_bufptr
&& !fail
)
1800 if (follow_lang_direction
)
1801 follow_lang_direction
--;
1802 /* first make sure there is enough room for tokens */
1803 if (max_tokens
<= data
->num_tokens
+ 5)
1805 int extra_tokens
= TOKEN_BLOCK_SIZE
;
1806 size_t needed
= extra_tokens
* sizeof(struct wps_token
);
1807 /* do some smarts here to grow the array a bit */
1808 if (skin_buffer_freespace() < needed
)
1810 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1813 skin_buffer_increment(needed
, false);
1814 max_tokens
+= extra_tokens
;
1817 switch(*wps_bufptr
++)
1822 if ((ret
= parse_token(wps_bufptr
, data
)) < 0)
1824 fail
= PARSE_FAIL_COND_INVALID_PARAM
;
1827 else if (level
>= WPS_MAX_COND_LEVEL
- 1)
1829 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1835 /* Alternating sublines separator */
1837 if (level
>= 0) /* there are unclosed conditionals */
1839 fail
= PARSE_FAIL_UNCLOSED_COND
;
1843 if (!skin_start_new_subline(curr_line
, data
->num_tokens
))
1844 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1848 /* Conditional list start */
1850 if (data
->tokens
[data
->num_tokens
-2].type
!= WPS_TOKEN_CONDITIONAL
)
1852 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1855 wps_bufptr
+= check_feature_tag(wps_bufptr
,
1856 data
->tokens
[data
->num_tokens
-1].type
);
1857 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_START
;
1858 lastcond
[level
] = data
->num_tokens
++;
1861 /* Conditional list end */
1863 if (level
< 0) /* not in a conditional, invalid char */
1865 fail
= PARSE_FAIL_INVALID_CHAR
;
1869 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_END
;
1870 if (lastcond
[level
])
1871 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1874 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1878 lastcond
[level
] = 0;
1880 data
->tokens
[condindex
[level
]].value
.i
= numoptions
[level
];
1884 /* Conditional list option */
1886 if (level
< 0) /* not in a conditional, invalid char */
1888 fail
= PARSE_FAIL_INVALID_CHAR
;
1892 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_OPTION
;
1893 if (lastcond
[level
])
1894 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1897 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1901 lastcond
[level
] = data
->num_tokens
;
1902 numoptions
[level
]++;
1908 if (level
>= 0) /* there are unclosed conditionals */
1910 fail
= PARSE_FAIL_UNCLOSED_COND
;
1914 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1917 /* End of this line */
1919 if (level
>= 0) /* there are unclosed conditionals */
1921 fail
= PARSE_FAIL_UNCLOSED_COND
;
1924 /* add a new token for the \n so empty lines are correct */
1925 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CHARACTER
;
1926 data
->tokens
[data
->num_tokens
].value
.c
= '\n';
1927 data
->tokens
[data
->num_tokens
].next
= false;
1930 if (!skin_start_new_line(curr_vp
, data
->num_tokens
))
1932 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1942 unsigned int len
= 1;
1943 const char *string_start
= wps_bufptr
- 1;
1945 /* find the length of the string */
1946 while (*wps_bufptr
&& *wps_bufptr
!= '#' &&
1947 *wps_bufptr
!= '%' && *wps_bufptr
!= ';' &&
1948 *wps_bufptr
!= '<' && *wps_bufptr
!= '>' &&
1949 *wps_bufptr
!= '|' && *wps_bufptr
!= '\n')
1955 /* look if we already have that string */
1958 struct skin_token_list
*list
= data
->strings
;
1961 str
= (char*)list
->token
->value
.data
;
1962 found
= (strlen(str
) == len
&&
1963 strncmp(string_start
, str
, len
) == 0);
1965 break; /* break here because the list item is
1966 used if its found */
1969 /* If a matching string is found, found is true and i is
1970 the index of the string. If not, found is false */
1975 str
= (char*)skin_buffer_alloc(len
+1);
1978 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1981 strlcpy(str
, string_start
, len
+1);
1982 struct skin_token_list
*item
=
1983 new_skin_token_list_item(&data
->tokens
[data
->num_tokens
], str
);
1986 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1989 add_to_ll_chain(&data
->strings
, item
);
1993 /* another occurrence of an existing string */
1994 data
->tokens
[data
->num_tokens
].value
.data
= list
->token
->value
.data
;
1996 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_STRING
;
2003 if (!fail
&& level
>= 0) /* there are unclosed conditionals */
2004 fail
= PARSE_FAIL_UNCLOSED_COND
;
2006 if (*wps_bufptr
&& !fail
)
2007 /* one of the limits of the while loop was exceeded */
2008 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
2011 curr_line
->curr_subline
->last_token_idx
= data
->num_tokens
;
2012 data
->tokens
[data
->num_tokens
++].type
= WPS_NO_TOKEN
;
2013 /* freeup unused tokens */
2014 skin_buffer_free_from_front(sizeof(struct wps_token
)
2015 * (max_tokens
- data
->num_tokens
));
2017 #if defined(DEBUG) || defined(SIMULATOR)
2020 print_debug_info(data
, fail
, line_number
);
2032 * initial setup of wps_data; does reset everything
2033 * except fields which need to survive, i.e.
2036 static void skin_data_reset(struct wps_data
*wps_data
)
2038 #ifdef HAVE_LCD_BITMAP
2039 wps_data
->images
= NULL
;
2040 wps_data
->progressbars
= NULL
;
2042 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
2043 wps_data
->backdrop
= NULL
;
2045 #ifdef HAVE_TOUCHSCREEN
2046 wps_data
->touchregions
= NULL
;
2048 wps_data
->viewports
= NULL
;
2049 wps_data
->strings
= NULL
;
2050 #ifdef HAVE_ALBUMART
2051 wps_data
->albumart
= NULL
;
2052 if (wps_data
->playback_aa_slot
>= 0)
2054 playback_release_aa_slot(wps_data
->playback_aa_slot
);
2055 wps_data
->playback_aa_slot
= -1;
2058 wps_data
->tokens
= NULL
;
2059 wps_data
->num_tokens
= 0;
2061 #ifdef HAVE_LCD_BITMAP
2062 wps_data
->peak_meter_enabled
= false;
2063 wps_data
->wps_sb_tag
= false;
2064 wps_data
->show_sb_on_wps
= false;
2065 #else /* HAVE_LCD_CHARCELLS */
2068 for (i
= 0; i
< 8; i
++)
2070 wps_data
->wps_progress_pat
[i
] = 0;
2072 wps_data
->full_line_progressbar
= false;
2074 wps_data
->wps_loaded
= false;
2077 #ifdef HAVE_LCD_BITMAP
2078 static bool load_skin_bmp(struct wps_data
*wps_data
, struct bitmap
*bitmap
, char* bmpdir
)
2080 (void)wps_data
; /* only needed for remote targets */
2081 char img_path
[MAX_PATH
];
2082 get_image_filename(bitmap
->data
, bmpdir
,
2083 img_path
, sizeof(img_path
));
2085 /* load the image */
2087 #ifdef HAVE_REMOTE_LCD
2088 if (curr_screen
== SCREEN_REMOTE
)
2089 format
= FORMAT_ANY
|FORMAT_REMOTE
;
2092 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
2095 char* imgbuf
= (char*)skin_buffer_grab(&max_buf
);
2096 bitmap
->data
= imgbuf
;
2097 int ret
= read_bmp_file(img_path
, bitmap
, max_buf
, format
, NULL
);
2101 skin_buffer_increment(ret
, true);
2106 /* Abort if we can't load an image */
2107 DEBUGF("Couldn't load '%s'\n", img_path
);
2112 static bool load_skin_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
2114 struct skin_token_list
*list
;
2115 bool retval
= true; /* return false if a single image failed to load */
2116 /* do the progressbars */
2117 list
= wps_data
->progressbars
;
2120 struct progressbar
*pb
= (struct progressbar
*)list
->token
->value
.data
;
2123 pb
->have_bitmap_pb
= load_skin_bmp(wps_data
, &pb
->bm
, bmpdir
);
2124 if (!pb
->have_bitmap_pb
) /* no success */
2129 /* regular images */
2130 list
= wps_data
->images
;
2133 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
2136 img
->loaded
= load_skin_bmp(wps_data
, &img
->bm
, bmpdir
);
2138 img
->subimage_height
= img
->bm
.height
/ img
->num_subimages
;
2145 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
2146 /* Backdrop load scheme:
2148 * 2) load the backdrop from settings
2150 if (wps_data
->backdrop
)
2152 bool needed
= wps_data
->backdrop
[0] != '-';
2153 wps_data
->backdrop
= skin_backdrop_load(wps_data
->backdrop
,
2154 bmpdir
, curr_screen
);
2155 if (!wps_data
->backdrop
&& needed
)
2158 #endif /* has backdrop support */
2163 static bool skin_load_fonts(struct wps_data
*data
)
2165 /* don't spit out after the first failue to aid debugging */
2166 bool success
= true;
2167 struct skin_token_list
*vp_list
;
2169 /* walk though each viewport and assign its font */
2170 for(vp_list
= data
->viewports
; vp_list
; vp_list
= vp_list
->next
)
2172 /* first, find the viewports that have a non-sys/ui-font font */
2173 struct skin_viewport
*skin_vp
=
2174 (struct skin_viewport
*)vp_list
->token
->value
.data
;
2175 struct viewport
*vp
= &skin_vp
->vp
;
2178 if (vp
->font
<= FONT_UI
)
2179 { /* the usual case -> built-in fonts */
2180 #ifdef HAVE_REMOTE_LCD
2181 if (vp
->font
== FONT_UI
)
2182 vp
->font
+= curr_screen
;
2188 /* now find the corresponding skin_font */
2189 struct skin_font
*font
= &skinfonts
[font_id
-FONT_FIRSTUSERFONT
];
2192 DEBUGF("font %d not specified\n", font_id
);
2197 /* load the font - will handle loading the same font again if
2198 * multiple viewports use the same */
2201 char *dot
= strchr(font
->name
, '.');
2203 font
->id
= skin_font_load(font
->name
);
2208 DEBUGF("Unable to load font %d: '%s.fnt'\n",
2209 font_id
, font
->name
);
2214 /* finally, assign the font_id to the viewport */
2215 vp
->font
= font
->id
;
2220 #endif /* HAVE_LCD_BITMAP */
2222 /* to setup up the wps-data from a format-buffer (isfile = false)
2223 from a (wps-)file (isfile = true)*/
2224 bool skin_data_load(enum screen_type screen
, struct wps_data
*wps_data
,
2225 const char *buf
, bool isfile
)
2227 char *wps_buffer
= NULL
;
2228 if (!wps_data
|| !buf
)
2230 #ifdef HAVE_ALBUMART
2232 struct mp3entry
*curtrack
;
2234 struct skin_albumart old_aa
= {.state
= WPS_ALBUMART_NONE
};
2235 if (wps_data
->albumart
)
2237 old_aa
.state
= wps_data
->albumart
->state
;
2238 old_aa
.height
= wps_data
->albumart
->height
;
2239 old_aa
.width
= wps_data
->albumart
->width
;
2242 #ifdef HAVE_LCD_BITMAP
2244 for (i
=0;i
<MAXUSERFONTS
;i
++)
2246 skinfonts
[i
].id
= -1;
2247 skinfonts
[i
].name
= NULL
;
2250 #ifdef DEBUG_SKIN_ENGINE
2251 if (isfile
&& debug_wps
)
2253 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf
);
2257 skin_data_reset(wps_data
);
2258 wps_data
->wps_loaded
= false;
2259 curr_screen
= screen
;
2261 /* alloc default viewport, will be fixed up later */
2262 curr_vp
= skin_buffer_alloc(sizeof(struct skin_viewport
));
2265 struct skin_token_list
*list
= new_skin_token_list_item(NULL
, curr_vp
);
2268 add_to_ll_chain(&wps_data
->viewports
, list
);
2271 /* Initialise the first (default) viewport */
2272 curr_vp
->label
= VP_DEFAULT_LABEL
;
2273 curr_vp
->hidden_flags
= 0;
2274 curr_vp
->lines
= NULL
;
2276 viewport_set_defaults(&curr_vp
->vp
, screen
);
2277 #ifdef HAVE_LCD_BITMAP
2278 curr_vp
->vp
.font
= FONT_UI
;
2282 if (!skin_start_new_line(curr_vp
, 0))
2287 int fd
= open_utf8(buf
, O_RDONLY
);
2292 /* get buffer space from the plugin buffer */
2293 size_t buffersize
= 0;
2294 wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
2299 /* copy the file's content to the buffer for parsing,
2300 ensuring that every line ends with a newline char. */
2301 unsigned int start
= 0;
2302 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
2304 start
+= strlen(wps_buffer
+ start
);
2305 if (start
< buffersize
- 1)
2307 wps_buffer
[start
++] = '\n';
2308 wps_buffer
[start
] = 0;
2317 wps_buffer
= (char*)buf
;
2319 /* parse the WPS source */
2320 if (!wps_parse(wps_data
, wps_buffer
, isfile
)) {
2321 skin_data_reset(wps_data
);
2325 #ifdef HAVE_LCD_BITMAP
2326 char bmpdir
[MAX_PATH
];
2329 /* get the bitmap dir */
2330 char *dot
= strrchr(buf
, '.');
2331 strlcpy(bmpdir
, buf
, dot
- buf
+ 1);
2335 snprintf(bmpdir
, MAX_PATH
, "%s", BACKDROP_DIR
);
2337 /* load the bitmaps that were found by the parsing */
2338 if (!load_skin_bitmaps(wps_data
, bmpdir
) ||
2339 !skin_load_fonts(wps_data
))
2341 skin_data_reset(wps_data
);
2345 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
2346 status
= audio_status();
2347 if (status
& AUDIO_STATUS_PLAY
)
2349 struct skin_albumart
*aa
= wps_data
->albumart
;
2350 if (aa
&& ((aa
->state
&& !old_aa
.state
) ||
2352 (((old_aa
.height
!= aa
->height
) ||
2353 (old_aa
.width
!= aa
->width
))))))
2355 curtrack
= audio_current_track();
2356 offset
= curtrack
->offset
;
2358 if (!(status
& AUDIO_STATUS_PAUSE
))
2363 wps_data
->wps_loaded
= true;
2364 #ifdef DEBUG_SKIN_ENGINE
2365 if (isfile
&& debug_wps
)