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"
55 #include "skin_fonts.h"
57 #ifdef HAVE_LCD_BITMAP
66 #include "statusbar-skinned.h"
68 #define WPS_ERROR_INVALID_PARAM -1
70 /* which screen are we parsing for? */
71 static enum screen_type curr_screen
;
73 /* level of current conditional.
74 -1 means we're not in a conditional. */
75 static int level
= -1;
77 /* index of the last WPS_TOKEN_CONDITIONAL_OPTION
78 or WPS_TOKEN_CONDITIONAL_START in current level */
79 static int lastcond
[WPS_MAX_COND_LEVEL
];
81 /* index of the WPS_TOKEN_CONDITIONAL in current level */
82 static int condindex
[WPS_MAX_COND_LEVEL
];
84 /* number of condtional options in current level */
85 static int numoptions
[WPS_MAX_COND_LEVEL
];
87 /* line number, debug only */
88 static int line_number
;
90 /* the current viewport */
91 static struct skin_viewport
*curr_vp
;
92 /* the current line, linked to the above viewport */
93 static struct skin_line
*curr_line
;
95 static int follow_lang_direction
= 0;
97 #if defined(DEBUG) || defined(SIMULATOR)
98 /* debugging function */
99 extern void print_debug_info(struct wps_data
*data
, int fail
, int line
);
100 extern void debug_skin_usage(void);
103 /* Function for parsing of details for a token. At the moment the
104 function is called, the token type has already been set. The
105 function must fill in the details and possibly add more tokens
106 to the token array. It should return the number of chars that
109 wps_bufptr points to the char following the tag (i.e. where
111 token is the pointer to the 'main' token being parsed
113 typedef int (*wps_tag_parse_func
)(const char *wps_bufptr
,
114 struct wps_token
*token
, struct wps_data
*wps_data
);
117 enum wps_token_type type
;
119 unsigned char refresh_type
;
120 const wps_tag_parse_func parse_func
;
122 static int skip_end_of_line(const char *wps_bufptr
);
123 /* prototypes of all special parse functions : */
124 static int parse_timeout(const char *wps_bufptr
,
125 struct wps_token
*token
, struct wps_data
*wps_data
);
126 static int parse_progressbar(const char *wps_bufptr
,
127 struct wps_token
*token
, struct wps_data
*wps_data
);
128 static int parse_dir_level(const char *wps_bufptr
,
129 struct wps_token
*token
, struct wps_data
*wps_data
);
130 static int parse_setting_and_lang(const char *wps_bufptr
,
131 struct wps_token
*token
, struct wps_data
*wps_data
);
134 static int parse_languagedirection(const char *wps_bufptr
,
135 struct wps_token
*token
, struct wps_data
*wps_data
)
140 follow_lang_direction
= 2; /* 2 because it is decremented immediatly after
141 this token is parsed, after the next token it
146 #ifdef HAVE_LCD_BITMAP
147 static int parse_viewport_display(const char *wps_bufptr
,
148 struct wps_token
*token
, struct wps_data
*wps_data
);
149 static int parse_playlistview(const char *wps_bufptr
,
150 struct wps_token
*token
, struct wps_data
*wps_data
);
151 static int parse_viewport(const char *wps_bufptr
,
152 struct wps_token
*token
, struct wps_data
*wps_data
);
153 static int parse_statusbar_enable(const char *wps_bufptr
,
154 struct wps_token
*token
, struct wps_data
*wps_data
);
155 static int parse_statusbar_disable(const char *wps_bufptr
,
156 struct wps_token
*token
, struct wps_data
*wps_data
);
157 static int parse_statusbar_inbuilt(const char *wps_bufptr
,
158 struct wps_token
*token
, struct wps_data
*wps_data
);
159 static int parse_image_display(const char *wps_bufptr
,
160 struct wps_token
*token
, struct wps_data
*wps_data
);
161 static int parse_image_load(const char *wps_bufptr
,
162 struct wps_token
*token
, struct wps_data
*wps_data
);
163 static int parse_font_load(const char *wps_bufptr
,
164 struct wps_token
*token
, struct wps_data
*wps_data
);
165 #endif /*HAVE_LCD_BITMAP */
166 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
167 static int parse_image_special(const char *wps_bufptr
,
168 struct wps_token
*token
, struct wps_data
*wps_data
);
171 static int parse_albumart_load(const char *wps_bufptr
,
172 struct wps_token
*token
, struct wps_data
*wps_data
);
173 static int parse_albumart_display(const char *wps_bufptr
,
174 struct wps_token
*token
, struct wps_data
*wps_data
);
175 #endif /* HAVE_ALBUMART */
176 #ifdef HAVE_TOUCHSCREEN
177 static int parse_touchregion(const char *wps_bufptr
,
178 struct wps_token
*token
, struct wps_data
*wps_data
);
180 static int fulline_tag_not_supported(const char *wps_bufptr
,
181 struct wps_token
*token
, struct wps_data
*wps_data
)
183 (void)token
; (void)wps_data
;
184 return skip_end_of_line(wps_bufptr
);
186 #define parse_touchregion fulline_tag_not_supported
189 #define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
191 #define WPS_RTC_REFRESH WPS_REFRESH_STATIC
194 /* array of available tags - those with more characters have to go first
195 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
196 static const struct wps_tag all_tags
[] = {
198 { WPS_TOKEN_ALIGN_CENTER
, "ac", 0, NULL
},
199 { WPS_TOKEN_ALIGN_LEFT
, "al", 0, NULL
},
200 { WPS_TOKEN_ALIGN_LEFT_RTL
, "aL", 0, NULL
},
201 { WPS_TOKEN_ALIGN_RIGHT
, "ar", 0, NULL
},
202 { WPS_TOKEN_ALIGN_RIGHT_RTL
, "aR", 0, NULL
},
203 { WPS_NO_TOKEN
, "ax", 0, parse_languagedirection
},
205 { WPS_TOKEN_BATTERY_PERCENT
, "bl", WPS_REFRESH_DYNAMIC
, NULL
},
206 { WPS_TOKEN_BATTERY_VOLTS
, "bv", WPS_REFRESH_DYNAMIC
, NULL
},
207 { WPS_TOKEN_BATTERY_TIME
, "bt", WPS_REFRESH_DYNAMIC
, NULL
},
208 { WPS_TOKEN_BATTERY_SLEEPTIME
, "bs", WPS_REFRESH_DYNAMIC
, NULL
},
209 #if CONFIG_CHARGING >= CHARGING_MONITOR
210 { WPS_TOKEN_BATTERY_CHARGING
, "bc", WPS_REFRESH_DYNAMIC
, NULL
},
213 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED
,"bp", WPS_REFRESH_DYNAMIC
, NULL
},
215 #ifdef HAVE_USB_POWER
216 { WPS_TOKEN_USB_POWERED
, "bu", WPS_REFRESH_DYNAMIC
, NULL
},
219 { WPS_TOKEN_RTC_PRESENT
, "cc", WPS_REFRESH_STATIC
, NULL
},
220 { WPS_TOKEN_RTC_DAY_OF_MONTH
, "cd", WPS_RTC_REFRESH
, NULL
},
221 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
,"ce", WPS_RTC_REFRESH
, NULL
},
222 { WPS_TOKEN_RTC_12HOUR_CFG
, "cf", WPS_RTC_REFRESH
, NULL
},
223 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
, "cH", WPS_RTC_REFRESH
, NULL
},
224 { WPS_TOKEN_RTC_HOUR_24
, "ck", WPS_RTC_REFRESH
, NULL
},
225 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
, "cI", WPS_RTC_REFRESH
, NULL
},
226 { WPS_TOKEN_RTC_HOUR_12
, "cl", WPS_RTC_REFRESH
, NULL
},
227 { WPS_TOKEN_RTC_MONTH
, "cm", WPS_RTC_REFRESH
, NULL
},
228 { WPS_TOKEN_RTC_MINUTE
, "cM", WPS_RTC_REFRESH
, NULL
},
229 { WPS_TOKEN_RTC_SECOND
, "cS", WPS_RTC_REFRESH
, NULL
},
230 { WPS_TOKEN_RTC_YEAR_2_DIGITS
, "cy", WPS_RTC_REFRESH
, NULL
},
231 { WPS_TOKEN_RTC_YEAR_4_DIGITS
, "cY", WPS_RTC_REFRESH
, NULL
},
232 { WPS_TOKEN_RTC_AM_PM_UPPER
, "cP", WPS_RTC_REFRESH
, NULL
},
233 { WPS_TOKEN_RTC_AM_PM_LOWER
, "cp", WPS_RTC_REFRESH
, NULL
},
234 { WPS_TOKEN_RTC_WEEKDAY_NAME
, "ca", WPS_RTC_REFRESH
, NULL
},
235 { WPS_TOKEN_RTC_MONTH_NAME
, "cb", WPS_RTC_REFRESH
, NULL
},
236 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
, "cu", WPS_RTC_REFRESH
, NULL
},
237 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
, "cw", WPS_RTC_REFRESH
, NULL
},
240 { WPS_TOKEN_FILE_BITRATE
, "fb", WPS_REFRESH_STATIC
, NULL
},
241 { WPS_TOKEN_FILE_CODEC
, "fc", WPS_REFRESH_STATIC
, NULL
},
242 { WPS_TOKEN_FILE_FREQUENCY
, "ff", WPS_REFRESH_STATIC
, NULL
},
243 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "fk", WPS_REFRESH_STATIC
, NULL
},
244 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "fm", WPS_REFRESH_STATIC
, NULL
},
245 { WPS_TOKEN_FILE_NAME
, "fn", WPS_REFRESH_STATIC
, NULL
},
246 { WPS_TOKEN_FILE_PATH
, "fp", WPS_REFRESH_STATIC
, NULL
},
247 { WPS_TOKEN_FILE_SIZE
, "fs", WPS_REFRESH_STATIC
, NULL
},
248 { WPS_TOKEN_FILE_VBR
, "fv", WPS_REFRESH_STATIC
, NULL
},
249 { WPS_TOKEN_FILE_DIRECTORY
, "d", WPS_REFRESH_STATIC
,
253 { WPS_TOKEN_FILE_BITRATE
, "Fb", WPS_REFRESH_STATIC
, NULL
},
254 { WPS_TOKEN_FILE_CODEC
, "Fc", WPS_REFRESH_STATIC
, NULL
},
255 { WPS_TOKEN_FILE_FREQUENCY
, "Ff", WPS_REFRESH_STATIC
, NULL
},
256 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "Fk", WPS_REFRESH_STATIC
, NULL
},
257 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "Fm", WPS_REFRESH_STATIC
, NULL
},
258 { WPS_TOKEN_FILE_NAME
, "Fn", WPS_REFRESH_STATIC
, NULL
},
259 { WPS_TOKEN_FILE_PATH
, "Fp", WPS_REFRESH_STATIC
, NULL
},
260 { WPS_TOKEN_FILE_SIZE
, "Fs", WPS_REFRESH_STATIC
, NULL
},
261 { WPS_TOKEN_FILE_VBR
, "Fv", WPS_REFRESH_STATIC
, NULL
},
262 { WPS_TOKEN_FILE_DIRECTORY
, "D", WPS_REFRESH_STATIC
,
265 /* current metadata */
266 { WPS_TOKEN_METADATA_ARTIST
, "ia", WPS_REFRESH_STATIC
, NULL
},
267 { WPS_TOKEN_METADATA_COMPOSER
, "ic", WPS_REFRESH_STATIC
, NULL
},
268 { WPS_TOKEN_METADATA_ALBUM
, "id", WPS_REFRESH_STATIC
, NULL
},
269 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "iA", WPS_REFRESH_STATIC
, NULL
},
270 { WPS_TOKEN_METADATA_GROUPING
, "iG", WPS_REFRESH_STATIC
, NULL
},
271 { WPS_TOKEN_METADATA_GENRE
, "ig", WPS_REFRESH_STATIC
, NULL
},
272 { WPS_TOKEN_METADATA_DISC_NUMBER
, "ik", WPS_REFRESH_STATIC
, NULL
},
273 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "in", WPS_REFRESH_STATIC
, NULL
},
274 { WPS_TOKEN_METADATA_TRACK_TITLE
, "it", WPS_REFRESH_STATIC
, NULL
},
275 { WPS_TOKEN_METADATA_VERSION
, "iv", WPS_REFRESH_STATIC
, NULL
},
276 { WPS_TOKEN_METADATA_YEAR
, "iy", WPS_REFRESH_STATIC
, NULL
},
277 { WPS_TOKEN_METADATA_COMMENT
, "iC", WPS_REFRESH_STATIC
, NULL
},
280 { WPS_TOKEN_METADATA_ARTIST
, "Ia", WPS_REFRESH_STATIC
, NULL
},
281 { WPS_TOKEN_METADATA_COMPOSER
, "Ic", WPS_REFRESH_STATIC
, NULL
},
282 { WPS_TOKEN_METADATA_ALBUM
, "Id", WPS_REFRESH_STATIC
, NULL
},
283 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "IA", WPS_REFRESH_STATIC
, NULL
},
284 { WPS_TOKEN_METADATA_GROUPING
, "IG", WPS_REFRESH_STATIC
, NULL
},
285 { WPS_TOKEN_METADATA_GENRE
, "Ig", WPS_REFRESH_STATIC
, NULL
},
286 { WPS_TOKEN_METADATA_DISC_NUMBER
, "Ik", WPS_REFRESH_STATIC
, NULL
},
287 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "In", WPS_REFRESH_STATIC
, NULL
},
288 { WPS_TOKEN_METADATA_TRACK_TITLE
, "It", WPS_REFRESH_STATIC
, NULL
},
289 { WPS_TOKEN_METADATA_VERSION
, "Iv", WPS_REFRESH_STATIC
, NULL
},
290 { WPS_TOKEN_METADATA_YEAR
, "Iy", WPS_REFRESH_STATIC
, NULL
},
291 { WPS_TOKEN_METADATA_COMMENT
, "IC", WPS_REFRESH_STATIC
, NULL
},
293 #if (CONFIG_CODEC != MAS3507D)
294 { WPS_TOKEN_SOUND_PITCH
, "Sp", WPS_REFRESH_DYNAMIC
, NULL
},
296 #if (CONFIG_CODEC == SWCODEC)
297 { WPS_TOKEN_SOUND_SPEED
, "Ss", WPS_REFRESH_DYNAMIC
, NULL
},
299 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
300 { WPS_TOKEN_VLED_HDD
, "lh", WPS_REFRESH_DYNAMIC
, NULL
},
303 { WPS_TOKEN_MAIN_HOLD
, "mh", WPS_REFRESH_DYNAMIC
, NULL
},
305 #ifdef HAS_REMOTE_BUTTON_HOLD
306 { WPS_TOKEN_REMOTE_HOLD
, "mr", WPS_REFRESH_DYNAMIC
, NULL
},
308 { WPS_TOKEN_UNKNOWN
, "mr", 0, NULL
},
311 { WPS_TOKEN_REPEAT_MODE
, "mm", WPS_REFRESH_DYNAMIC
, NULL
},
312 { WPS_TOKEN_PLAYBACK_STATUS
, "mp", WPS_REFRESH_DYNAMIC
, NULL
},
313 { WPS_TOKEN_BUTTON_VOLUME
, "mv", WPS_REFRESH_DYNAMIC
,
316 #ifdef HAVE_LCD_BITMAP
317 { WPS_TOKEN_PEAKMETER
, "pm", WPS_REFRESH_PEAK_METER
, NULL
},
319 { WPS_TOKEN_PLAYER_PROGRESSBAR
, "pf",
320 WPS_REFRESH_DYNAMIC
| WPS_REFRESH_PLAYER_PROGRESS
, parse_progressbar
},
322 { WPS_TOKEN_PROGRESSBAR
, "pb", WPS_REFRESH_PLAYER_PROGRESS
,
325 { WPS_TOKEN_VOLUME
, "pv", WPS_REFRESH_DYNAMIC
,
328 { WPS_TOKEN_TRACK_ELAPSED_PERCENT
, "px", WPS_REFRESH_DYNAMIC
, NULL
},
329 { WPS_TOKEN_TRACK_TIME_ELAPSED
, "pc", WPS_REFRESH_DYNAMIC
, NULL
},
330 { WPS_TOKEN_TRACK_TIME_REMAINING
, "pr", WPS_REFRESH_DYNAMIC
, NULL
},
331 { WPS_TOKEN_TRACK_LENGTH
, "pt", WPS_REFRESH_STATIC
, NULL
},
332 { WPS_TOKEN_TRACK_STARTING
, "pS", WPS_REFRESH_DYNAMIC
, parse_timeout
},
333 { WPS_TOKEN_TRACK_ENDING
, "pE", WPS_REFRESH_DYNAMIC
, parse_timeout
},
335 { WPS_TOKEN_PLAYLIST_POSITION
, "pp", WPS_REFRESH_STATIC
, NULL
},
336 { WPS_TOKEN_PLAYLIST_ENTRIES
, "pe", WPS_REFRESH_STATIC
, NULL
},
337 { WPS_TOKEN_PLAYLIST_NAME
, "pn", WPS_REFRESH_STATIC
, NULL
},
338 { WPS_TOKEN_PLAYLIST_SHUFFLE
, "ps", WPS_REFRESH_DYNAMIC
, NULL
},
341 { WPS_TOKEN_DATABASE_PLAYCOUNT
, "rp", WPS_REFRESH_DYNAMIC
, NULL
},
342 { WPS_TOKEN_DATABASE_RATING
, "rr", WPS_REFRESH_DYNAMIC
, NULL
},
343 { WPS_TOKEN_DATABASE_AUTOSCORE
, "ra", WPS_REFRESH_DYNAMIC
, NULL
},
346 #if CONFIG_CODEC == SWCODEC
347 { WPS_TOKEN_REPLAYGAIN
, "rg", WPS_REFRESH_STATIC
, NULL
},
348 { WPS_TOKEN_CROSSFADE
, "xf", WPS_REFRESH_DYNAMIC
, NULL
},
351 { WPS_NO_TOKEN
, "s", WPS_REFRESH_SCROLL
, NULL
},
352 { WPS_TOKEN_SUBLINE_TIMEOUT
, "t", 0, parse_timeout
},
354 #ifdef HAVE_LCD_BITMAP
355 { WPS_NO_TOKEN
, "we", 0, parse_statusbar_enable
},
356 { WPS_NO_TOKEN
, "wd", 0, parse_statusbar_disable
},
357 { WPS_TOKEN_DRAW_INBUILTBAR
, "wi", WPS_REFRESH_DYNAMIC
, parse_statusbar_inbuilt
},
359 { WPS_NO_TOKEN
, "xl", 0, parse_image_load
},
361 { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
, "xd", WPS_REFRESH_STATIC
,
362 parse_image_display
},
364 { WPS_TOKEN_IMAGE_DISPLAY
, "x", 0, parse_image_load
},
365 { WPS_NO_TOKEN
, "Fl", 0, parse_font_load
},
367 { WPS_NO_TOKEN
, "Cl", 0, parse_albumart_load
},
368 { WPS_TOKEN_ALBUMART_DISPLAY
, "C", WPS_REFRESH_STATIC
, parse_albumart_display
},
371 { WPS_VIEWPORT_ENABLE
, "Vd", WPS_REFRESH_DYNAMIC
,
372 parse_viewport_display
},
373 #ifdef HAVE_LCD_BITMAP
374 { WPS_VIEWPORT_CUSTOMLIST
, "Vp", WPS_REFRESH_STATIC
, parse_playlistview
},
375 { WPS_TOKEN_LIST_TITLE_TEXT
, "Lt", WPS_REFRESH_DYNAMIC
, NULL
},
376 { WPS_TOKEN_LIST_TITLE_ICON
, "Li", WPS_REFRESH_DYNAMIC
, NULL
},
378 { WPS_NO_TOKEN
, "V", 0, parse_viewport
},
380 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
381 { WPS_TOKEN_IMAGE_BACKDROP
, "X", 0, parse_image_special
},
385 { WPS_TOKEN_SETTING
, "St", WPS_REFRESH_DYNAMIC
,
386 parse_setting_and_lang
},
387 { WPS_TOKEN_TRANSLATEDSTRING
, "Sx", WPS_REFRESH_STATIC
,
388 parse_setting_and_lang
},
389 { WPS_TOKEN_LANG_IS_RTL
, "Sr", WPS_REFRESH_STATIC
, NULL
},
391 { WPS_TOKEN_LASTTOUCH
, "Tl", WPS_REFRESH_DYNAMIC
, parse_timeout
},
392 { WPS_TOKEN_CURRENT_SCREEN
, "cs", WPS_REFRESH_DYNAMIC
, NULL
},
393 { WPS_NO_TOKEN
, "T", 0, parse_touchregion
},
396 /* Recording Tokens */
397 { WPS_TOKEN_HAVE_RECORDING
, "Rp", WPS_REFRESH_STATIC
, NULL
},
398 #ifdef HAVE_RECORDING
399 { WPS_TOKEN_REC_FREQ
, "Rf", WPS_REFRESH_DYNAMIC
, NULL
},
400 { WPS_TOKEN_REC_ENCODER
, "Re", WPS_REFRESH_DYNAMIC
, NULL
},
401 { WPS_TOKEN_REC_BITRATE
, "Rb", WPS_REFRESH_DYNAMIC
, NULL
},
402 { WPS_TOKEN_REC_MONO
, "Rm", WPS_REFRESH_DYNAMIC
, NULL
},
404 { WPS_TOKEN_UNKNOWN
, "", 0, NULL
}
405 /* the array MUST end with an empty string (first char is \0) */
409 /* add a skin_token_list item to the list chain. ALWAYS appended because some of the
410 * chains require the order to be kept.
412 static void add_to_ll_chain(struct skin_token_list
**list
, struct skin_token_list
*item
)
418 struct skin_token_list
*t
= *list
;
425 /* traverse the image linked-list for an image */
426 #ifdef HAVE_LCD_BITMAP
427 struct gui_img
* find_image(char label
, struct wps_data
*data
)
429 struct skin_token_list
*list
= data
->images
;
432 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
433 if (img
->label
== label
)
442 /* traverse the viewport linked list for a viewport */
443 struct skin_viewport
* find_viewport(char label
, struct wps_data
*data
)
445 struct skin_token_list
*list
= data
->viewports
;
448 struct skin_viewport
*vp
= (struct skin_viewport
*)list
->token
->value
.data
;
449 if (vp
->label
== label
)
457 /* create and init a new wpsll item.
458 * passing NULL to token will alloc a new one.
459 * You should only pass NULL for the token when the token type (table above)
460 * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array
462 static struct skin_token_list
*new_skin_token_list_item(struct wps_token
*token
,
465 struct skin_token_list
*llitem
= skin_buffer_alloc(sizeof(struct skin_token_list
));
467 token
= skin_buffer_alloc(sizeof(struct wps_token
));
468 if (!llitem
|| !token
)
471 llitem
->token
= token
;
473 llitem
->token
->value
.data
= token_data
;
477 /* Returns the number of chars that should be skipped to jump
478 immediately after the first eol, i.e. to the start of the next line */
479 static int skip_end_of_line(const char *wps_bufptr
)
483 while(*(wps_bufptr
+ skip
) != '\n')
488 /* Starts a new subline in the current line during parsing */
489 static bool skin_start_new_subline(struct skin_line
*line
, int curr_token
)
491 struct skin_subline
*subline
= skin_buffer_alloc(sizeof(struct skin_subline
));
495 subline
->first_token_idx
= curr_token
;
496 subline
->next
= NULL
;
498 subline
->line_type
= 0;
499 subline
->time_mult
= 0;
501 line
->curr_subline
->last_token_idx
= curr_token
-1;
502 line
->curr_subline
->next
= subline
;
503 line
->curr_subline
= subline
;
507 static bool skin_start_new_line(struct skin_viewport
*vp
, int curr_token
)
509 struct skin_line
*line
= skin_buffer_alloc(sizeof(struct skin_line
));
510 struct skin_subline
*subline
= NULL
;
514 /* init the subline */
515 subline
= &line
->sublines
;
516 subline
->first_token_idx
= curr_token
;
517 subline
->next
= NULL
;
518 subline
->line_type
= 0;
519 subline
->time_mult
= 0;
521 /* init the new line */
522 line
->curr_subline
= &line
->sublines
;
524 line
->subline_expire_time
= 0;
526 /* connect to curr_line and vp pointers.
527 * 1) close the previous lines subline
528 * 2) connect to vp pointer
529 * 3) connect to curr_line global pointer
533 curr_line
->curr_subline
->last_token_idx
= curr_token
- 1;
534 curr_line
->next
= line
;
535 curr_line
->curr_subline
= NULL
;
543 #ifdef HAVE_LCD_BITMAP
545 static int parse_statusbar_enable(const char *wps_bufptr
,
546 struct wps_token
*token
,
547 struct wps_data
*wps_data
)
549 (void)token
; /* Kill warnings */
550 wps_data
->wps_sb_tag
= true;
551 wps_data
->show_sb_on_wps
= true;
552 struct skin_viewport
*default_vp
= find_viewport(VP_DEFAULT_LABEL
, wps_data
);
553 viewport_set_defaults(&default_vp
->vp
, curr_screen
);
554 default_vp
->vp
.font
= FONT_UI
;
555 return skip_end_of_line(wps_bufptr
);
558 static int parse_statusbar_disable(const char *wps_bufptr
,
559 struct wps_token
*token
,
560 struct wps_data
*wps_data
)
562 (void)token
; /* Kill warnings */
563 wps_data
->wps_sb_tag
= true;
564 wps_data
->show_sb_on_wps
= false;
565 struct skin_viewport
*default_vp
= find_viewport(VP_DEFAULT_LABEL
, wps_data
);
566 viewport_set_fullscreen(&default_vp
->vp
, curr_screen
);
567 default_vp
->vp
.font
= FONT_UI
;
568 return skip_end_of_line(wps_bufptr
);
571 static int parse_statusbar_inbuilt(const char *wps_bufptr
,
572 struct wps_token
*token
, struct wps_data
*wps_data
)
575 token
->value
.data
= (void*)&curr_vp
->vp
;
576 return skip_end_of_line(wps_bufptr
);
579 static int get_image_id(int c
)
581 if(c
>= 'a' && c
<= 'z')
583 else if(c
>= 'A' && c
<= 'Z')
589 char *get_image_filename(const char *start
, const char* bmpdir
,
590 char *buf
, int buf_size
)
592 const char *end
= strchr(start
, '|');
593 int bmpdirlen
= strlen(bmpdir
);
595 if ( !end
|| (end
- start
) >= (buf_size
- bmpdirlen
- 2) )
602 buf
[bmpdirlen
] = '/';
603 memcpy( &buf
[bmpdirlen
+ 1], start
, end
- start
);
604 buf
[bmpdirlen
+ 1 + end
- start
] = 0;
609 static int parse_image_display(const char *wps_bufptr
,
610 struct wps_token
*token
,
611 struct wps_data
*wps_data
)
613 char label
= wps_bufptr
[0];
615 struct gui_img
*img
;;
618 img
= find_image(label
, wps_data
);
621 token
->value
.i
= label
; /* so debug works */
622 return WPS_ERROR_INVALID_PARAM
;
625 if ((subimage
= get_image_id(wps_bufptr
[1])) != -1)
627 if (subimage
>= img
->num_subimages
)
628 return WPS_ERROR_INVALID_PARAM
;
630 /* Store sub-image number to display in high bits */
631 token
->value
.i
= label
| (subimage
<< 8);
632 return 2; /* We have consumed 2 bytes */
634 token
->value
.i
= label
;
635 return 1; /* We have consumed 1 byte */
639 static int parse_image_load(const char *wps_bufptr
,
640 struct wps_token
*token
,
641 struct wps_data
*wps_data
)
643 const char *ptr
= wps_bufptr
;
645 const char* filename
;
651 /* format: %x|n|filename.bmp|x|y|
652 or %xl|n|filename.bmp|x|y|
653 or %xl|n|filename.bmp|x|y|num_subimages|
657 return WPS_ERROR_INVALID_PARAM
;
661 if (!(ptr
= parse_list("ssdd", NULL
, '|', ptr
, &id
, &filename
, &x
, &y
)))
662 return WPS_ERROR_INVALID_PARAM
;
664 /* Check there is a terminating | */
666 return WPS_ERROR_INVALID_PARAM
;
668 /* check the image number and load state */
669 if(find_image(*id
, wps_data
))
671 /* Invalid image ID */
672 return WPS_ERROR_INVALID_PARAM
;
674 img
= skin_buffer_alloc(sizeof(struct gui_img
));
676 return WPS_ERROR_INVALID_PARAM
;
677 /* save a pointer to the filename */
678 img
->bm
.data
= (char*)filename
;
682 img
->num_subimages
= 1;
683 img
->always_display
= false;
685 /* save current viewport */
686 img
->vp
= &curr_vp
->vp
;
688 if (token
->type
== WPS_TOKEN_IMAGE_DISPLAY
)
690 img
->always_display
= true;
694 /* Parse the (optional) number of sub-images */
696 newline
= strchr(ptr
, '\n');
697 pos
= strchr(ptr
, '|');
698 if (pos
&& pos
< newline
)
699 img
->num_subimages
= atoi(ptr
);
701 if (img
->num_subimages
<= 0)
702 return WPS_ERROR_INVALID_PARAM
;
704 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, img
);
706 return WPS_ERROR_INVALID_PARAM
;
707 add_to_ll_chain(&wps_data
->images
, item
);
709 /* Skip the rest of the line */
710 return skip_end_of_line(wps_bufptr
);
713 int id
; /* the id from font_load */
714 char *name
; /* filename without path and extension */
716 static struct skin_font skinfonts
[MAXUSERFONTS
];
717 static int parse_font_load(const char *wps_bufptr
,
718 struct wps_token
*token
, struct wps_data
*wps_data
)
720 (void)wps_data
; (void)token
;
721 const char *ptr
= wps_bufptr
;
726 return WPS_ERROR_INVALID_PARAM
;
730 if (!(ptr
= parse_list("ds", NULL
, '|', ptr
, &id
, &filename
)))
731 return WPS_ERROR_INVALID_PARAM
;
733 /* Check there is a terminating | */
735 return WPS_ERROR_INVALID_PARAM
;
737 if (id
<= FONT_UI
|| id
>= MAXFONTS
-1)
738 return WPS_ERROR_INVALID_PARAM
;
739 #if defined(DEBUG) || defined(SIMULATOR)
740 if (skinfonts
[id
-FONT_FIRSTUSERFONT
].name
!= NULL
)
742 DEBUGF("font id %d already being used\n", id
);
745 /* make sure the filename contains .fnt,
746 * we dont actually use it, but require it anyway */
747 ptr
= strchr(filename
, '.');
748 if (!ptr
|| strncmp(ptr
, ".fnt|", 5))
749 return WPS_ERROR_INVALID_PARAM
;
750 skinfonts
[id
-FONT_FIRSTUSERFONT
].id
= -1;
751 skinfonts
[id
-FONT_FIRSTUSERFONT
].name
= filename
;
753 return skip_end_of_line(wps_bufptr
);
757 static int parse_viewport_display(const char *wps_bufptr
,
758 struct wps_token
*token
,
759 struct wps_data
*wps_data
)
762 char letter
= wps_bufptr
[0];
764 if (letter
< 'a' || letter
> 'z')
766 /* invalid viewport tag */
767 return WPS_ERROR_INVALID_PARAM
;
769 token
->value
.i
= letter
;
773 #ifdef HAVE_LCD_BITMAP
774 static int parse_playlistview_text(struct playlistviewer
*viewer
,
775 enum info_line_type line
, char* text
)
778 const struct wps_tag
*tag
;
780 const char *start
= text
;
784 viewer
->lines
[line
].count
= 0;
785 viewer
->lines
[line
].scroll
= false;
788 if (*text
== '%') /* it is a token of some type */
800 /* escaped characters */
801 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = WPS_TOKEN_CHARACTER
;
802 viewer
->lines
[line
].strings
[cur_string
][0] = *text
;
803 viewer
->lines
[line
].strings
[cur_string
++][1] = '\0';
808 strncmp(text
, tag
->name
, strlen(tag
->name
)) != 0;
810 /* %s isnt stored as a tag so manually check for it */
811 if (tag
->type
== WPS_NO_TOKEN
)
813 if (!strncmp(tag
->name
, "s", 1))
815 viewer
->lines
[line
].scroll
= true;
819 else if (tag
->type
== WPS_TOKEN_UNKNOWN
)
822 /* just copy the string */
823 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = WPS_TOKEN_STRING
;
824 while (i
<(MAX_PLAYLISTLINE_STRLEN
-1) && text
[i
] != '|' && text
[i
] != '%')
826 viewer
->lines
[line
].strings
[cur_string
][i
] = text
[i
];
829 viewer
->lines
[line
].strings
[cur_string
][i
] = '\0';
837 /* unsupported tag, reject */
840 taglen
= strlen(tag
->name
);
841 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = tag
->type
;
850 /* just copy the string */
851 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = WPS_TOKEN_STRING
;
852 while (i
<(MAX_PLAYLISTLINE_STRLEN
-1) && text
[i
] != '|' && text
[i
] != '%')
854 viewer
->lines
[line
].strings
[cur_string
][i
] = text
[i
];
857 viewer
->lines
[line
].strings
[cur_string
][i
] = '\0';
866 static int parse_playlistview(const char *wps_bufptr
,
867 struct wps_token
*token
, struct wps_data
*wps_data
)
870 /* %Vp|<use icons>|<start offset>|info line text|no info text| */
871 struct playlistviewer
*viewer
= skin_buffer_alloc(sizeof(struct playlistviewer
));
872 char *ptr
= strchr(wps_bufptr
, '|');
875 return WPS_ERROR_INVALID_PARAM
;
876 viewer
->vp
= &curr_vp
->vp
;
877 viewer
->show_icons
= true;
878 viewer
->start_offset
= atoi(ptr
+1);
879 token
->value
.data
= (void*)viewer
;
880 ptr
= strchr(ptr
+1, '|');
881 length
= parse_playlistview_text(viewer
, TRACK_HAS_INFO
, ptr
);
883 return WPS_ERROR_INVALID_PARAM
;
884 length
= parse_playlistview_text(viewer
, TRACK_HAS_NO_INFO
, ptr
+length
);
886 return WPS_ERROR_INVALID_PARAM
;
888 return skip_end_of_line(wps_bufptr
);
892 static int parse_viewport(const char *wps_bufptr
,
893 struct wps_token
*token
,
894 struct wps_data
*wps_data
)
896 (void)token
; /* Kill warnings */
897 const char *ptr
= wps_bufptr
;
899 struct skin_viewport
*skin_vp
= skin_buffer_alloc(sizeof(struct skin_viewport
));
901 /* check for the optional letter to signify its a hideable viewport */
902 /* %Vl|<label>|<rest of tags>| */
903 skin_vp
->hidden_flags
= 0;
904 skin_vp
->label
= VP_NO_LABEL
;
905 skin_vp
->lines
= NULL
;
908 curr_line
->curr_subline
->last_token_idx
= wps_data
->num_tokens
909 - (wps_data
->num_tokens
> 0 ? 1 : 0);
913 if (!skin_start_new_line(skin_vp
, wps_data
->num_tokens
))
914 return WPS_ERROR_INVALID_PARAM
;
918 skin_vp
->label
= VP_INFO_LABEL
;
919 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
922 else if (*ptr
== 'l')
926 char label
= *(ptr
+2);
927 if (label
>= 'a' && label
<= 'z')
929 skin_vp
->hidden_flags
= VP_DRAW_HIDEABLE
;
930 skin_vp
->label
= label
;
933 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
938 return WPS_ERROR_INVALID_PARAM
;
941 struct viewport
*vp
= &skin_vp
->vp
;
942 /* format: %V|x|y|width|height|font|fg_pattern|bg_pattern| */
943 if (!(ptr
= viewport_parse_viewport(vp
, curr_screen
, ptr
, '|')))
944 return WPS_ERROR_INVALID_PARAM
;
946 /* Check for trailing | */
948 return WPS_ERROR_INVALID_PARAM
;
950 if (follow_lang_direction
&& lang_is_rtl())
952 vp
->flags
|= VP_FLAG_ALIGN_RIGHT
;
953 vp
->x
= screens
[curr_screen
].lcdwidth
- vp
->width
- vp
->x
;
956 vp
->flags
&= ~VP_FLAG_ALIGN_RIGHT
; /* ignore right-to-left languages */
958 struct skin_token_list
*list
= new_skin_token_list_item(NULL
, skin_vp
);
960 return WPS_ERROR_INVALID_PARAM
;
961 add_to_ll_chain(&wps_data
->viewports
, list
);
963 /* Skip the rest of the line */
964 return skip_end_of_line(wps_bufptr
);
967 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
968 static int parse_image_special(const char *wps_bufptr
,
969 struct wps_token
*token
,
970 struct wps_data
*wps_data
)
972 (void)wps_data
; /* kill warning */
974 const char *pos
= NULL
;
978 pos
= strchr(wps_bufptr
+ 1, '|');
979 newline
= strchr(wps_bufptr
, '\n');
981 error
= (pos
> newline
);
984 if (token
->type
== WPS_TOKEN_IMAGE_BACKDROP
)
986 /* format: %X|filename.bmp| or %Xd */
987 if (*(wps_bufptr
) == 'd')
989 wps_data
->backdrop
= NULL
;
990 return skip_end_of_line(wps_bufptr
);
993 wps_data
->backdrop
= (char*)wps_bufptr
+ 1;
997 return WPS_ERROR_INVALID_PARAM
;
998 /* Skip the rest of the line */
999 return skip_end_of_line(wps_bufptr
);
1003 #endif /* HAVE_LCD_BITMAP */
1005 static int parse_setting_and_lang(const char *wps_bufptr
,
1006 struct wps_token
*token
,
1007 struct wps_data
*wps_data
)
1009 /* NOTE: both the string validations that happen in here will
1010 * automatically PASS on checkwps because its too hard to get
1011 * settings_list.c and englinsh.lang built for it.
1012 * If that ever changes remove the #ifndef __PCTOOL__'s here
1015 const char *ptr
= wps_bufptr
;
1020 /* Find the setting's cfg_name */
1022 return WPS_ERROR_INVALID_PARAM
;
1024 end
= strchr(ptr
,'|');
1026 return WPS_ERROR_INVALID_PARAM
;
1027 strlcpy(temp
, ptr
,end
-ptr
+1);
1029 if (token
->type
== WPS_TOKEN_TRANSLATEDSTRING
)
1032 i
= lang_english_to_id(temp
);
1034 return WPS_ERROR_INVALID_PARAM
;
1039 /* Find the setting */
1040 for (i
=0; i
<nb_settings
; i
++)
1041 if (settings
[i
].cfg_name
&&
1042 !strncmp(settings
[i
].cfg_name
,ptr
,end
-ptr
) &&
1043 /* prevent matches on cfg_name prefixes */
1044 strlen(settings
[i
].cfg_name
)==(size_t)(end
-ptr
))
1047 if (i
== nb_settings
)
1048 return WPS_ERROR_INVALID_PARAM
;
1051 /* Store the setting number */
1054 /* Skip the rest of the line */
1059 static int parse_dir_level(const char *wps_bufptr
,
1060 struct wps_token
*token
,
1061 struct wps_data
*wps_data
)
1063 char val
[] = { *wps_bufptr
, '\0' };
1064 token
->value
.i
= atoi(val
);
1065 (void)wps_data
; /* Kill warnings */
1069 static int parse_timeout(const char *wps_bufptr
,
1070 struct wps_token
*token
,
1071 struct wps_data
*wps_data
)
1075 bool have_point
= false;
1076 bool have_tenth
= false;
1078 (void)wps_data
; /* Kill the warning */
1080 while ( isdigit(*wps_bufptr
) || *wps_bufptr
== '.' )
1082 if (*wps_bufptr
!= '.')
1085 val
+= *wps_bufptr
- '0';
1101 if (have_tenth
== false)
1104 if (val
== 0 && skip
== 0)
1106 /* decide what to do if no value was specified */
1107 switch (token
->type
)
1109 case WPS_TOKEN_SUBLINE_TIMEOUT
:
1111 case WPS_TOKEN_BUTTON_VOLUME
:
1112 case WPS_TOKEN_TRACK_STARTING
:
1113 case WPS_TOKEN_TRACK_ENDING
:
1118 token
->value
.i
= val
;
1123 static int parse_progressbar(const char *wps_bufptr
,
1124 struct wps_token
*token
,
1125 struct wps_data
*wps_data
)
1127 /* %pb or %pb|filename|x|y|width|height|
1128 using - for any of the params uses "sane" values */
1129 #ifdef HAVE_LCD_BITMAP
1137 const char *filename
;
1138 int x
, y
, height
, width
;
1140 const char *ptr
= wps_bufptr
;
1141 struct progressbar
*pb
= skin_buffer_alloc(sizeof(struct progressbar
));
1142 struct skin_token_list
*item
= new_skin_token_list_item(token
, pb
);
1145 return WPS_ERROR_INVALID_PARAM
;
1147 struct viewport
*vp
= &curr_vp
->vp
;
1148 /* we need to know what line number (viewport relative) this pb is,
1149 * so count them... */
1151 struct skin_line
*line
= curr_vp
->lines
;
1158 pb
->have_bitmap_pb
= false;
1159 pb
->bm
.data
= NULL
; /* no bitmap specified */
1160 pb
->follow_lang_direction
= follow_lang_direction
> 0;
1163 if (*wps_bufptr
!= '|') /* regular old style */
1166 pb
->width
= vp
->width
;
1167 pb
->height
= SYSFONT_HEIGHT
-2;
1168 pb
->y
= -line_num
- 1; /* Will be computed during the rendering */
1169 if (token
->type
== WPS_TOKEN_VOLUME
)
1170 return 0; /* dont add it, let the regular token handling do the work */
1171 add_to_ll_chain(&wps_data
->progressbars
, item
);
1174 ptr
= wps_bufptr
+ 1;
1176 if (!(ptr
= parse_list("sdddd", &set
, '|', ptr
, &filename
,
1177 &x
, &y
, &width
, &height
)))
1179 /* if we are in a conditional then we probably don't want to fail
1180 * if the above doesnt work. so ASSume the | is breaking the conditional
1181 * and move on. the next token will fail if this is incorrect */
1184 return WPS_ERROR_INVALID_PARAM
;
1187 if (LIST_VALUE_PARSED(set
, PB_FILENAME
)) /* filename */
1188 pb
->bm
.data
= (char*)filename
;
1190 if (LIST_VALUE_PARSED(set
, PB_X
)) /* x */
1195 if (LIST_VALUE_PARSED(set
, PB_WIDTH
)) /* width */
1197 /* A zero width causes a divide-by-zero error later, so reject it */
1199 return WPS_ERROR_INVALID_PARAM
;
1204 pb
->width
= vp
->width
- pb
->x
;
1206 if (LIST_VALUE_PARSED(set
, PB_HEIGHT
)) /* height, default to font height */
1208 /* A zero height makes no sense - reject it */
1210 return WPS_ERROR_INVALID_PARAM
;
1212 pb
->height
= height
;
1216 if (vp
->font
> FONT_UI
)
1217 pb
->height
= -1; /* calculate at display time */
1221 pb
->height
= font_get(vp
->font
)->height
;
1228 if (LIST_VALUE_PARSED(set
, PB_Y
)) /* y */
1231 pb
->y
= -line_num
- 1; /* Will be computed during the rendering */
1233 add_to_ll_chain(&wps_data
->progressbars
, item
);
1234 if (token
->type
== WPS_TOKEN_VOLUME
)
1235 token
->type
= WPS_TOKEN_VOLUMEBAR
;
1236 pb
->type
= token
->type
;
1238 return ptr
+1-wps_bufptr
;
1241 if (token
->type
!= WPS_TOKEN_VOLUME
)
1243 wps_data
->full_line_progressbar
=
1244 token
->type
== WPS_TOKEN_PLAYER_PROGRESSBAR
;
1251 #ifdef HAVE_ALBUMART
1252 static int parse_int(const char *newline
, const char **_pos
, int *num
)
1254 *_pos
= parse_list("d", NULL
, '|', *_pos
, num
);
1256 return (!*_pos
|| *_pos
> newline
|| **_pos
!= '|');
1259 static int parse_albumart_load(const char *wps_bufptr
,
1260 struct wps_token
*token
,
1261 struct wps_data
*wps_data
)
1263 const char *_pos
, *newline
;
1265 struct dim dimensions
;
1267 bool swap_for_rtl
= lang_is_rtl() && follow_lang_direction
;
1268 struct skin_albumart
*aa
= skin_buffer_alloc(sizeof(struct skin_albumart
));
1269 (void)token
; /* silence warning */
1271 return skip_end_of_line(wps_bufptr
);
1273 /* reset albumart info in wps */
1276 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
1277 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
1278 aa
->vp
= &curr_vp
->vp
;
1280 /* format: %Cl|x|y|[[l|c|r]mwidth]|[[t|c|b]mheight]| */
1282 newline
= strchr(wps_bufptr
, '\n');
1287 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
1291 /* initial validation and parsing of x component */
1292 if (parse_int(newline
, &_pos
, &aa
->x
))
1293 return WPS_ERROR_INVALID_PARAM
;
1297 /* initial validation and parsing of y component */
1298 if (parse_int(newline
, &_pos
, &aa
->y
))
1299 return WPS_ERROR_INVALID_PARAM
;
1301 /* parsing width field */
1305 /* apply each modifier in turn */
1313 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1315 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1319 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
;
1325 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1327 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1335 /* simply ignored */
1342 /* extract max width data */
1345 if (parse_int(newline
, &_pos
, &aa
->width
))
1346 return WPS_ERROR_INVALID_PARAM
;
1349 /* parsing height field */
1353 /* apply each modifier in turn */
1360 aa
->yalign
= WPS_ALBUMART_ALIGN_TOP
;
1364 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
;
1369 aa
->yalign
= WPS_ALBUMART_ALIGN_BOTTOM
;
1377 /* simply ignored */
1384 /* extract max height data */
1387 if (parse_int(newline
, &_pos
, &aa
->height
))
1388 return WPS_ERROR_INVALID_PARAM
;
1391 /* if we got here, we parsed everything ok .. ! */
1394 else if (aa
->width
> LCD_WIDTH
)
1395 aa
->width
= LCD_WIDTH
;
1399 else if (aa
->height
> LCD_HEIGHT
)
1400 aa
->height
= LCD_HEIGHT
;
1403 aa
->x
= LCD_WIDTH
- (aa
->x
+ aa
->width
);
1405 aa
->state
= WPS_ALBUMART_LOAD
;
1407 wps_data
->albumart
= aa
;
1409 dimensions
.width
= aa
->width
;
1410 dimensions
.height
= aa
->height
;
1412 albumart_slot
= playback_claim_aa_slot(&dimensions
);
1414 if (0 <= albumart_slot
)
1415 wps_data
->playback_aa_slot
= albumart_slot
;
1417 /* Skip the rest of the line */
1418 return skip_end_of_line(wps_bufptr
);
1421 static int parse_albumart_display(const char *wps_bufptr
,
1422 struct wps_token
*token
,
1423 struct wps_data
*wps_data
)
1426 struct wps_token
*prev
= token
-1;
1427 if ((wps_data
->num_tokens
>= 1) && (prev
->type
== WPS_TOKEN_CONDITIONAL
))
1429 token
->type
= WPS_TOKEN_ALBUMART_FOUND
;
1431 else if (wps_data
->albumart
)
1433 wps_data
->albumart
->vp
= &curr_vp
->vp
;
1436 /* the old code did this so keep it here for now...
1437 * this is to allow the posibility to showing the next tracks AA! */
1438 if (wps_bufptr
+1 == 'n')
1443 #endif /* HAVE_ALBUMART */
1445 #ifdef HAVE_TOUCHSCREEN
1447 struct touchaction
{const char* s
; int action
;};
1448 static const struct touchaction touchactions
[] = {
1449 {"play", ACTION_WPS_PLAY
}, {"stop", ACTION_WPS_STOP
},
1450 {"prev", ACTION_WPS_SKIPPREV
}, {"next", ACTION_WPS_SKIPNEXT
},
1451 {"ffwd", ACTION_WPS_SEEKFWD
}, {"rwd", ACTION_WPS_SEEKBACK
},
1452 {"menu", ACTION_WPS_MENU
}, {"browse", ACTION_WPS_BROWSE
},
1453 {"shuffle", ACTION_TOUCH_SHUFFLE
}, {"repmode", ACTION_TOUCH_REPMODE
},
1454 {"quickscreen", ACTION_WPS_QUICKSCREEN
},{"contextmenu", ACTION_WPS_CONTEXT
},
1455 {"playlist", ACTION_WPS_VIEW_PLAYLIST
}, {"pitch", ACTION_WPS_PITCHSCREEN
},
1456 {"voldown", ACTION_WPS_VOLDOWN
}, {"volup", ACTION_WPS_VOLUP
},
1458 static int parse_touchregion(const char *wps_bufptr
,
1459 struct wps_token
*token
, struct wps_data
*wps_data
)
1463 struct touchregion
*region
= NULL
;
1464 const char *ptr
= wps_bufptr
;
1466 const char pb_string
[] = "progressbar";
1467 const char vol_string
[] = "volume";
1470 /* format: %T|x|y|width|height|action|
1471 * if action starts with & the area must be held to happen
1473 * play - play/pause playback
1474 * stop - stop playback, exit the wps
1477 * ffwd - seek forward
1478 * rwd - seek backwards
1479 * menu - go back to the main menu
1480 * browse - go back to the file/db browser
1481 * shuffle - toggle shuffle mode
1482 * repmode - cycle the repeat mode
1483 * quickscreen - go into the quickscreen
1484 * contextmenu - open the context menu
1485 * playlist - go into the playlist
1486 * pitch - go into the pitchscreen
1487 * volup - increase volume by one step
1488 * voldown - decrease volume by one step
1493 return WPS_ERROR_INVALID_PARAM
;
1496 if (!(ptr
= parse_list("dddds", NULL
, '|', ptr
, &x
, &y
, &w
, &h
, &action
)))
1497 return WPS_ERROR_INVALID_PARAM
;
1499 /* Check there is a terminating | */
1501 return WPS_ERROR_INVALID_PARAM
;
1503 region
= skin_buffer_alloc(sizeof(struct touchregion
));
1505 return WPS_ERROR_INVALID_PARAM
;
1507 /* should probably do some bounds checking here with the viewport... but later */
1508 region
->action
= ACTION_NONE
;
1513 region
->wvp
= curr_vp
;
1514 region
->armed
= false;
1516 if(!strncmp(pb_string
, action
, sizeof(pb_string
)-1)
1517 && *(action
+ sizeof(pb_string
)-1) == '|')
1518 region
->type
= WPS_TOUCHREGION_SCROLLBAR
;
1519 else if(!strncmp(vol_string
, action
, sizeof(vol_string
)-1)
1520 && *(action
+ sizeof(vol_string
)-1) == '|')
1521 region
->type
= WPS_TOUCHREGION_VOLUME
;
1524 region
->type
= WPS_TOUCHREGION_ACTION
;
1529 region
->repeat
= true;
1532 region
->repeat
= false;
1535 imax
= ARRAYLEN(touchactions
);
1536 while ((region
->action
== ACTION_NONE
) &&
1539 /* try to match with one of our touchregion screens */
1540 int len
= strlen(touchactions
[i
].s
);
1541 if (!strncmp(touchactions
[i
].s
, action
, len
)
1542 && *(action
+len
) == '|')
1543 region
->action
= touchactions
[i
].action
;
1546 if (region
->action
== ACTION_NONE
)
1547 return WPS_ERROR_INVALID_PARAM
;
1549 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, region
);
1551 return WPS_ERROR_INVALID_PARAM
;
1552 add_to_ll_chain(&wps_data
->touchregions
, item
);
1553 return skip_end_of_line(wps_bufptr
);
1557 /* Parse a generic token from the given string. Return the length read */
1558 static int parse_token(const char *wps_bufptr
, struct wps_data
*wps_data
)
1560 int skip
= 0, taglen
= 0, ret
;
1561 struct wps_token
*token
= wps_data
->tokens
+ wps_data
->num_tokens
;
1562 const struct wps_tag
*tag
;
1563 memset(token
, 0, sizeof(*token
));
1574 /* escaped characters */
1575 token
->type
= WPS_TOKEN_CHARACTER
;
1576 token
->value
.c
= *wps_bufptr
;
1578 wps_data
->num_tokens
++;
1582 /* conditional tag */
1583 token
->type
= WPS_TOKEN_CONDITIONAL
;
1585 condindex
[level
] = wps_data
->num_tokens
;
1586 numoptions
[level
] = 1;
1587 wps_data
->num_tokens
++;
1588 ret
= parse_token(wps_bufptr
+ 1, wps_data
);
1589 if (ret
< 0) return ret
;
1594 /* find what tag we have */
1595 for (tag
= all_tags
;
1596 strncmp(wps_bufptr
, tag
->name
, strlen(tag
->name
)) != 0;
1599 taglen
= (tag
->type
!= WPS_TOKEN_UNKNOWN
) ? strlen(tag
->name
) : 2;
1600 token
->type
= tag
->type
;
1601 curr_line
->curr_subline
->line_type
|= tag
->refresh_type
;
1603 /* if the tag has a special parsing function, we call it */
1604 if (tag
->parse_func
)
1606 ret
= tag
->parse_func(wps_bufptr
+ taglen
, token
, wps_data
);
1607 if (ret
< 0) return ret
;
1611 /* Some tags we don't want to save as tokens */
1612 if (tag
->type
== WPS_NO_TOKEN
)
1615 /* tags that start with 'F', 'I' or 'D' are for the next file */
1616 if ( *(tag
->name
) == 'I' || *(tag
->name
) == 'F' ||
1617 *(tag
->name
) == 'D')
1620 wps_data
->num_tokens
++;
1630 * Returns the number of bytes to skip the buf pointer to access the false
1631 * branch in a _binary_ conditional
1634 * - before the '|' if we have a false branch, (%?<true|false> -> %?<|false>)
1635 * - or before the closing '>' if there's no false branch (%?<true> -> %?<>)
1637 * depending on the features of a target it's not called from check_feature_tag,
1638 * hence the __attribute__ or it issues compiler warnings
1642 static int find_false_branch(const char *wps_bufptr
) __attribute__((unused
));
1643 static int find_false_branch(const char *wps_bufptr
)
1645 const char *buf
= wps_bufptr
;
1646 /* wps_bufptr is after the opening '<', hence level = 1*/
1653 { /* filter out the characters we check later if they're printed
1656 if (ch
== '<' || ch
== '>' || ch
== '|')
1658 /* else: some tags/printed literals we skip over */
1660 else if (ch
== '<') /* nested conditional */
1663 { /* closed our or a nested conditional,
1664 * do NOT skip over the '>' so that wps_parse() sees it for closing
1665 * if it is the closing one for our conditional */
1668 else if (ch
== '|' && level
== 1)
1669 { /* we found our separator, point before and get out */
1672 /* if level is 0, we don't have a false branch */
1673 } while (level
> 0 && *(++buf
));
1675 return buf
- wps_bufptr
;
1679 * returns the number of bytes to get the appropriate branch of a binary
1683 * - if a feature is available, it returns 0 to not skip anything
1684 * - if the feature is not available, skip to the false branch and don't
1685 * parse the true branch at all
1688 static int check_feature_tag(const char *wps_bufptr
, const int type
)
1693 case WPS_TOKEN_RTC_PRESENT
:
1697 return find_false_branch(wps_bufptr
);
1699 case WPS_TOKEN_HAVE_RECORDING
:
1700 #ifdef HAVE_RECORDING
1703 return find_false_branch(wps_bufptr
);
1705 default: /* not a tag we care about, just don't skip */
1712 data is the pointer to the structure where the parsed WPS should be stored.
1714 wps_bufptr points to the string containing the WPS tags */
1715 #define TOKEN_BLOCK_SIZE 128
1716 static bool wps_parse(struct wps_data
*data
, const char *wps_bufptr
, bool debug
)
1718 if (!data
|| !wps_bufptr
|| !*wps_bufptr
)
1720 enum wps_parse_error fail
= PARSE_OK
;
1722 int max_tokens
= TOKEN_BLOCK_SIZE
;
1723 size_t buf_free
= 0;
1727 /* allocate enough RAM for a reasonable skin, grow as needed.
1728 * Free any used RAM before loading the images to be 100% RAM efficient */
1729 data
->tokens
= (struct wps_token
*)skin_buffer_grab(&buf_free
);
1730 if (sizeof(struct wps_token
)*max_tokens
>= buf_free
)
1732 skin_buffer_increment(max_tokens
* sizeof(struct wps_token
), false);
1733 data
->num_tokens
= 0;
1736 /* Backdrop defaults to the setting unless %X is used, so set it now */
1737 if (global_settings
.backdrop_file
[0])
1739 data
->backdrop
= "-";
1743 while (*wps_bufptr
&& !fail
)
1745 if (follow_lang_direction
)
1746 follow_lang_direction
--;
1747 /* first make sure there is enough room for tokens */
1748 if (max_tokens
<= data
->num_tokens
+ 5)
1750 int extra_tokens
= TOKEN_BLOCK_SIZE
;
1751 size_t needed
= extra_tokens
* sizeof(struct wps_token
);
1752 /* do some smarts here to grow the array a bit */
1753 if (skin_buffer_freespace() < needed
)
1755 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1758 skin_buffer_increment(needed
, false);
1759 max_tokens
+= extra_tokens
;
1762 switch(*wps_bufptr
++)
1767 if ((ret
= parse_token(wps_bufptr
, data
)) < 0)
1769 fail
= PARSE_FAIL_COND_INVALID_PARAM
;
1772 else if (level
>= WPS_MAX_COND_LEVEL
- 1)
1774 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1780 /* Alternating sublines separator */
1782 if (level
>= 0) /* there are unclosed conditionals */
1784 fail
= PARSE_FAIL_UNCLOSED_COND
;
1788 if (!skin_start_new_subline(curr_line
, data
->num_tokens
))
1789 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1793 /* Conditional list start */
1795 if (data
->tokens
[data
->num_tokens
-2].type
!= WPS_TOKEN_CONDITIONAL
)
1797 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1800 wps_bufptr
+= check_feature_tag(wps_bufptr
,
1801 data
->tokens
[data
->num_tokens
-1].type
);
1802 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_START
;
1803 lastcond
[level
] = data
->num_tokens
++;
1806 /* Conditional list end */
1808 if (level
< 0) /* not in a conditional, invalid char */
1810 fail
= PARSE_FAIL_INVALID_CHAR
;
1814 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_END
;
1815 if (lastcond
[level
])
1816 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1819 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1823 lastcond
[level
] = 0;
1825 data
->tokens
[condindex
[level
]].value
.i
= numoptions
[level
];
1829 /* Conditional list option */
1831 if (level
< 0) /* not in a conditional, invalid char */
1833 fail
= PARSE_FAIL_INVALID_CHAR
;
1837 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_OPTION
;
1838 if (lastcond
[level
])
1839 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1842 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1846 lastcond
[level
] = data
->num_tokens
;
1847 numoptions
[level
]++;
1853 if (level
>= 0) /* there are unclosed conditionals */
1855 fail
= PARSE_FAIL_UNCLOSED_COND
;
1859 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1862 /* End of this line */
1864 if (level
>= 0) /* there are unclosed conditionals */
1866 fail
= PARSE_FAIL_UNCLOSED_COND
;
1869 /* add a new token for the \n so empty lines are correct */
1870 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CHARACTER
;
1871 data
->tokens
[data
->num_tokens
].value
.c
= '\n';
1872 data
->tokens
[data
->num_tokens
].next
= false;
1875 if (!skin_start_new_line(curr_vp
, data
->num_tokens
))
1877 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1887 unsigned int len
= 1;
1888 const char *string_start
= wps_bufptr
- 1;
1890 /* find the length of the string */
1891 while (*wps_bufptr
&& *wps_bufptr
!= '#' &&
1892 *wps_bufptr
!= '%' && *wps_bufptr
!= ';' &&
1893 *wps_bufptr
!= '<' && *wps_bufptr
!= '>' &&
1894 *wps_bufptr
!= '|' && *wps_bufptr
!= '\n')
1900 /* look if we already have that string */
1903 struct skin_token_list
*list
= data
->strings
;
1906 str
= (char*)list
->token
->value
.data
;
1907 found
= (strlen(str
) == len
&&
1908 strncmp(string_start
, str
, len
) == 0);
1910 break; /* break here because the list item is
1911 used if its found */
1914 /* If a matching string is found, found is true and i is
1915 the index of the string. If not, found is false */
1920 str
= (char*)skin_buffer_alloc(len
+1);
1923 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1926 strlcpy(str
, string_start
, len
+1);
1927 struct skin_token_list
*item
=
1928 new_skin_token_list_item(&data
->tokens
[data
->num_tokens
], str
);
1931 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1934 add_to_ll_chain(&data
->strings
, item
);
1938 /* another occurrence of an existing string */
1939 data
->tokens
[data
->num_tokens
].value
.data
= list
->token
->value
.data
;
1941 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_STRING
;
1948 if (!fail
&& level
>= 0) /* there are unclosed conditionals */
1949 fail
= PARSE_FAIL_UNCLOSED_COND
;
1951 if (*wps_bufptr
&& !fail
)
1952 /* one of the limits of the while loop was exceeded */
1953 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1956 curr_line
->curr_subline
->last_token_idx
= data
->num_tokens
;
1957 data
->tokens
[data
->num_tokens
++].type
= WPS_NO_TOKEN
;
1958 /* freeup unused tokens */
1959 skin_buffer_free_from_front(sizeof(struct wps_token
)
1960 * (max_tokens
- data
->num_tokens
));
1962 #if defined(DEBUG) || defined(SIMULATOR)
1965 print_debug_info(data
, fail
, line_number
);
1977 * initial setup of wps_data; does reset everything
1978 * except fields which need to survive, i.e.
1981 static void skin_data_reset(struct wps_data
*wps_data
)
1983 #ifdef HAVE_LCD_BITMAP
1984 wps_data
->images
= NULL
;
1985 wps_data
->progressbars
= NULL
;
1987 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1988 wps_data
->backdrop
= NULL
;
1990 #ifdef HAVE_TOUCHSCREEN
1991 wps_data
->touchregions
= NULL
;
1993 wps_data
->viewports
= NULL
;
1994 wps_data
->strings
= NULL
;
1995 #ifdef HAVE_ALBUMART
1996 wps_data
->albumart
= NULL
;
1997 if (wps_data
->playback_aa_slot
>= 0)
1999 playback_release_aa_slot(wps_data
->playback_aa_slot
);
2000 wps_data
->playback_aa_slot
= -1;
2003 wps_data
->tokens
= NULL
;
2004 wps_data
->num_tokens
= 0;
2006 #ifdef HAVE_LCD_BITMAP
2007 wps_data
->peak_meter_enabled
= false;
2008 wps_data
->wps_sb_tag
= false;
2009 wps_data
->show_sb_on_wps
= false;
2010 #else /* HAVE_LCD_CHARCELLS */
2013 for (i
= 0; i
< 8; i
++)
2015 wps_data
->wps_progress_pat
[i
] = 0;
2017 wps_data
->full_line_progressbar
= false;
2019 wps_data
->wps_loaded
= false;
2022 #ifdef HAVE_LCD_BITMAP
2023 static bool load_skin_bmp(struct wps_data
*wps_data
, struct bitmap
*bitmap
, char* bmpdir
)
2025 (void)wps_data
; /* only needed for remote targets */
2026 char img_path
[MAX_PATH
];
2027 get_image_filename(bitmap
->data
, bmpdir
,
2028 img_path
, sizeof(img_path
));
2030 /* load the image */
2032 #ifdef HAVE_REMOTE_LCD
2033 if (curr_screen
== SCREEN_REMOTE
)
2034 format
= FORMAT_ANY
|FORMAT_REMOTE
;
2037 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
2040 char* imgbuf
= (char*)skin_buffer_grab(&max_buf
);
2041 bitmap
->data
= imgbuf
;
2042 int ret
= read_bmp_file(img_path
, bitmap
, max_buf
, format
, NULL
);
2046 skin_buffer_increment(ret
, true);
2051 /* Abort if we can't load an image */
2052 DEBUGF("Couldn't load '%s'\n", img_path
);
2057 static bool load_skin_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
2059 struct skin_token_list
*list
;
2060 bool retval
= true; /* return false if a single image failed to load */
2061 /* do the progressbars */
2062 list
= wps_data
->progressbars
;
2065 struct progressbar
*pb
= (struct progressbar
*)list
->token
->value
.data
;
2068 pb
->have_bitmap_pb
= load_skin_bmp(wps_data
, &pb
->bm
, bmpdir
);
2069 if (!pb
->have_bitmap_pb
) /* no success */
2074 /* regular images */
2075 list
= wps_data
->images
;
2078 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
2081 img
->loaded
= load_skin_bmp(wps_data
, &img
->bm
, bmpdir
);
2083 img
->subimage_height
= img
->bm
.height
/ img
->num_subimages
;
2090 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
2091 /* Backdrop load scheme:
2093 * 2) load the backdrop from settings
2095 if (wps_data
->backdrop
)
2097 bool needed
= wps_data
->backdrop
[0] != '-';
2098 wps_data
->backdrop
= skin_backdrop_load(wps_data
->backdrop
,
2099 bmpdir
, curr_screen
);
2100 if (!wps_data
->backdrop
&& needed
)
2103 #endif /* has backdrop support */
2108 static bool skin_load_fonts(struct wps_data
*data
)
2110 /* don't spit out after the first failue to aid debugging */
2111 bool success
= true;
2112 struct skin_token_list
*vp_list
;
2114 /* walk though each viewport and assign its font */
2115 for(vp_list
= data
->viewports
; vp_list
; vp_list
= vp_list
->next
)
2117 /* first, find the viewports that have a non-sys/ui-font font */
2118 struct skin_viewport
*skin_vp
=
2119 (struct skin_viewport
*)vp_list
->token
->value
.data
;
2120 struct viewport
*vp
= &skin_vp
->vp
;
2123 if (vp
->font
<= FONT_UI
)
2124 { /* the usual case -> built-in fonts */
2125 #ifdef HAVE_REMOTE_LCD
2126 if (vp
->font
== FONT_UI
)
2127 vp
->font
+= curr_screen
;
2133 /* now find the corresponding skin_font */
2134 struct skin_font
*font
= &skinfonts
[font_id
-FONT_FIRSTUSERFONT
];
2137 DEBUGF("font %d not specified\n", font_id
);
2142 /* load the font - will handle loading the same font again if
2143 * multiple viewports use the same */
2146 char *dot
= strchr(font
->name
, '.');
2148 font
->id
= skin_font_load(font
->name
);
2153 DEBUGF("Unable to load font %d: '%s.fnt'\n",
2154 font_id
, font
->name
);
2159 /* finally, assign the font_id to the viewport */
2160 vp
->font
= font
->id
;
2165 #endif /* HAVE_LCD_BITMAP */
2167 /* to setup up the wps-data from a format-buffer (isfile = false)
2168 from a (wps-)file (isfile = true)*/
2169 bool skin_data_load(enum screen_type screen
, struct wps_data
*wps_data
,
2170 const char *buf
, bool isfile
)
2172 char *wps_buffer
= NULL
;
2173 if (!wps_data
|| !buf
)
2175 #ifdef HAVE_ALBUMART
2177 struct mp3entry
*curtrack
;
2179 struct skin_albumart old_aa
= {.state
= WPS_ALBUMART_NONE
};
2180 if (wps_data
->albumart
)
2182 old_aa
.state
= wps_data
->albumart
->state
;
2183 old_aa
.height
= wps_data
->albumart
->height
;
2184 old_aa
.width
= wps_data
->albumart
->width
;
2187 #ifdef HAVE_LCD_BITMAP
2189 for (i
=0;i
<MAXUSERFONTS
;i
++)
2191 skinfonts
[i
].id
= -1;
2192 skinfonts
[i
].name
= NULL
;
2195 #ifdef DEBUG_SKIN_ENGINE
2196 if (isfile
&& debug_wps
)
2198 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf
);
2202 skin_data_reset(wps_data
);
2203 wps_data
->wps_loaded
= false;
2204 curr_screen
= screen
;
2206 /* alloc default viewport, will be fixed up later */
2207 curr_vp
= skin_buffer_alloc(sizeof(struct skin_viewport
));
2210 struct skin_token_list
*list
= new_skin_token_list_item(NULL
, curr_vp
);
2213 add_to_ll_chain(&wps_data
->viewports
, list
);
2216 /* Initialise the first (default) viewport */
2217 curr_vp
->label
= VP_DEFAULT_LABEL
;
2218 curr_vp
->hidden_flags
= 0;
2219 curr_vp
->lines
= NULL
;
2221 viewport_set_defaults(&curr_vp
->vp
, screen
);
2222 #ifdef HAVE_LCD_BITMAP
2223 curr_vp
->vp
.font
= FONT_UI
;
2227 if (!skin_start_new_line(curr_vp
, 0))
2232 int fd
= open_utf8(buf
, O_RDONLY
);
2237 /* get buffer space from the plugin buffer */
2238 size_t buffersize
= 0;
2239 wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
2244 /* copy the file's content to the buffer for parsing,
2245 ensuring that every line ends with a newline char. */
2246 unsigned int start
= 0;
2247 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
2249 start
+= strlen(wps_buffer
+ start
);
2250 if (start
< buffersize
- 1)
2252 wps_buffer
[start
++] = '\n';
2253 wps_buffer
[start
] = 0;
2262 wps_buffer
= (char*)buf
;
2264 /* parse the WPS source */
2265 if (!wps_parse(wps_data
, wps_buffer
, isfile
)) {
2266 skin_data_reset(wps_data
);
2270 #ifdef HAVE_LCD_BITMAP
2271 char bmpdir
[MAX_PATH
];
2274 /* get the bitmap dir */
2275 char *dot
= strrchr(buf
, '.');
2276 strlcpy(bmpdir
, buf
, dot
- buf
+ 1);
2280 snprintf(bmpdir
, MAX_PATH
, "%s", BACKDROP_DIR
);
2282 /* load the bitmaps that were found by the parsing */
2283 if (!load_skin_bitmaps(wps_data
, bmpdir
) ||
2284 !skin_load_fonts(wps_data
))
2286 skin_data_reset(wps_data
);
2290 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
2291 status
= audio_status();
2292 if (status
& AUDIO_STATUS_PLAY
)
2294 struct skin_albumart
*aa
= wps_data
->albumart
;
2295 if (aa
&& ((aa
->state
&& !old_aa
.state
) ||
2297 (((old_aa
.height
!= aa
->height
) ||
2298 (old_aa
.width
!= aa
->width
))))))
2300 curtrack
= audio_current_track();
2301 offset
= curtrack
->offset
;
2303 if (!(status
& AUDIO_STATUS_PAUSE
))
2308 wps_data
->wps_loaded
= true;
2309 #ifdef DEBUG_SKIN_ENGINE
2310 if (isfile
&& debug_wps
)