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 size_t curr_size
;
96 static bool single_pass
;
98 static int follow_lang_direction
= 0;
100 #if defined(DEBUG) || defined(SIMULATOR)
101 /* debugging function */
102 extern void print_debug_info(struct wps_data
*data
, int fail
, int line
);
103 extern void debug_skin_usage(void);
106 /* Function for parsing of details for a token. At the moment the
107 function is called, the token type has already been set. The
108 function must fill in the details and possibly add more tokens
109 to the token array. It should return the number of chars that
112 wps_bufptr points to the char following the tag (i.e. where
114 token is the pointer to the 'main' token being parsed
116 typedef int (*wps_tag_parse_func
)(const char *wps_bufptr
,
117 struct wps_token
*token
, struct wps_data
*wps_data
);
120 enum wps_token_type type
;
122 unsigned char refresh_type
;
123 const wps_tag_parse_func parse_func
;
125 static int skip_end_of_line(const char *wps_bufptr
);
126 /* prototypes of all special parse functions : */
127 static int parse_timeout(const char *wps_bufptr
,
128 struct wps_token
*token
, struct wps_data
*wps_data
);
129 static int parse_progressbar(const char *wps_bufptr
,
130 struct wps_token
*token
, struct wps_data
*wps_data
);
131 static int parse_dir_level(const char *wps_bufptr
,
132 struct wps_token
*token
, struct wps_data
*wps_data
);
133 static int parse_setting_and_lang(const char *wps_bufptr
,
134 struct wps_token
*token
, struct wps_data
*wps_data
);
137 static int parse_languagedirection(const char *wps_bufptr
,
138 struct wps_token
*token
, struct wps_data
*wps_data
)
143 follow_lang_direction
= 2; /* 2 because it is decremented immediatly after
144 this token is parsed, after the next token it
149 #ifdef HAVE_LCD_BITMAP
150 static int parse_viewport_display(const char *wps_bufptr
,
151 struct wps_token
*token
, struct wps_data
*wps_data
);
152 static int parse_playlistview(const char *wps_bufptr
,
153 struct wps_token
*token
, struct wps_data
*wps_data
);
154 static int parse_viewport(const char *wps_bufptr
,
155 struct wps_token
*token
, struct wps_data
*wps_data
);
156 static int parse_statusbar_enable(const char *wps_bufptr
,
157 struct wps_token
*token
, struct wps_data
*wps_data
);
158 static int parse_statusbar_disable(const char *wps_bufptr
,
159 struct wps_token
*token
, struct wps_data
*wps_data
);
160 static int parse_statusbar_inbuilt(const char *wps_bufptr
,
161 struct wps_token
*token
, struct wps_data
*wps_data
);
162 static int parse_image_display(const char *wps_bufptr
,
163 struct wps_token
*token
, struct wps_data
*wps_data
);
164 static int parse_image_load(const char *wps_bufptr
,
165 struct wps_token
*token
, struct wps_data
*wps_data
);
166 static int parse_font_load(const char *wps_bufptr
,
167 struct wps_token
*token
, struct wps_data
*wps_data
);
168 #endif /*HAVE_LCD_BITMAP */
169 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
170 static int parse_image_special(const char *wps_bufptr
,
171 struct wps_token
*token
, struct wps_data
*wps_data
);
174 static int parse_albumart_load(const char *wps_bufptr
,
175 struct wps_token
*token
, struct wps_data
*wps_data
);
176 static int parse_albumart_display(const char *wps_bufptr
,
177 struct wps_token
*token
, struct wps_data
*wps_data
);
178 #endif /* HAVE_ALBUMART */
179 #ifdef HAVE_TOUCHSCREEN
180 static int parse_touchregion(const char *wps_bufptr
,
181 struct wps_token
*token
, struct wps_data
*wps_data
);
183 static int fulline_tag_not_supported(const char *wps_bufptr
,
184 struct wps_token
*token
, struct wps_data
*wps_data
)
186 (void)token
; (void)wps_data
;
187 return skip_end_of_line(wps_bufptr
);
189 #define parse_touchregion fulline_tag_not_supported
192 #define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
194 #define WPS_RTC_REFRESH WPS_REFRESH_STATIC
197 /* array of available tags - those with more characters have to go first
198 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
199 static const struct wps_tag all_tags
[] = {
201 { WPS_TOKEN_ALIGN_CENTER
, "ac", 0, NULL
},
202 { WPS_TOKEN_ALIGN_LEFT
, "al", 0, NULL
},
203 { WPS_TOKEN_ALIGN_LEFT_RTL
, "aL", 0, NULL
},
204 { WPS_TOKEN_ALIGN_RIGHT
, "ar", 0, NULL
},
205 { WPS_TOKEN_ALIGN_RIGHT_RTL
, "aR", 0, NULL
},
206 { WPS_NO_TOKEN
, "ax", 0, parse_languagedirection
},
208 { WPS_TOKEN_BATTERY_PERCENT
, "bl", WPS_REFRESH_DYNAMIC
, NULL
},
209 { WPS_TOKEN_BATTERY_VOLTS
, "bv", WPS_REFRESH_DYNAMIC
, NULL
},
210 { WPS_TOKEN_BATTERY_TIME
, "bt", WPS_REFRESH_DYNAMIC
, NULL
},
211 { WPS_TOKEN_BATTERY_SLEEPTIME
, "bs", WPS_REFRESH_DYNAMIC
, NULL
},
212 #if CONFIG_CHARGING >= CHARGING_MONITOR
213 { WPS_TOKEN_BATTERY_CHARGING
, "bc", WPS_REFRESH_DYNAMIC
, NULL
},
216 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED
,"bp", WPS_REFRESH_DYNAMIC
, NULL
},
218 #ifdef HAVE_USB_POWER
219 { WPS_TOKEN_USB_POWERED
, "bu", WPS_REFRESH_DYNAMIC
, NULL
},
222 { WPS_TOKEN_RTC_PRESENT
, "cc", WPS_REFRESH_STATIC
, NULL
},
223 { WPS_TOKEN_RTC_DAY_OF_MONTH
, "cd", WPS_RTC_REFRESH
, NULL
},
224 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
,"ce", WPS_RTC_REFRESH
, NULL
},
225 { WPS_TOKEN_RTC_12HOUR_CFG
, "cf", WPS_RTC_REFRESH
, NULL
},
226 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
, "cH", WPS_RTC_REFRESH
, NULL
},
227 { WPS_TOKEN_RTC_HOUR_24
, "ck", WPS_RTC_REFRESH
, NULL
},
228 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
, "cI", WPS_RTC_REFRESH
, NULL
},
229 { WPS_TOKEN_RTC_HOUR_12
, "cl", WPS_RTC_REFRESH
, NULL
},
230 { WPS_TOKEN_RTC_MONTH
, "cm", WPS_RTC_REFRESH
, NULL
},
231 { WPS_TOKEN_RTC_MINUTE
, "cM", WPS_RTC_REFRESH
, NULL
},
232 { WPS_TOKEN_RTC_SECOND
, "cS", WPS_RTC_REFRESH
, NULL
},
233 { WPS_TOKEN_RTC_YEAR_2_DIGITS
, "cy", WPS_RTC_REFRESH
, NULL
},
234 { WPS_TOKEN_RTC_YEAR_4_DIGITS
, "cY", WPS_RTC_REFRESH
, NULL
},
235 { WPS_TOKEN_RTC_AM_PM_UPPER
, "cP", WPS_RTC_REFRESH
, NULL
},
236 { WPS_TOKEN_RTC_AM_PM_LOWER
, "cp", WPS_RTC_REFRESH
, NULL
},
237 { WPS_TOKEN_RTC_WEEKDAY_NAME
, "ca", WPS_RTC_REFRESH
, NULL
},
238 { WPS_TOKEN_RTC_MONTH_NAME
, "cb", WPS_RTC_REFRESH
, NULL
},
239 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
, "cu", WPS_RTC_REFRESH
, NULL
},
240 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
, "cw", WPS_RTC_REFRESH
, NULL
},
243 { WPS_TOKEN_FILE_BITRATE
, "fb", WPS_REFRESH_STATIC
, NULL
},
244 { WPS_TOKEN_FILE_CODEC
, "fc", WPS_REFRESH_STATIC
, NULL
},
245 { WPS_TOKEN_FILE_FREQUENCY
, "ff", WPS_REFRESH_STATIC
, NULL
},
246 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "fk", WPS_REFRESH_STATIC
, NULL
},
247 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "fm", WPS_REFRESH_STATIC
, NULL
},
248 { WPS_TOKEN_FILE_NAME
, "fn", WPS_REFRESH_STATIC
, NULL
},
249 { WPS_TOKEN_FILE_PATH
, "fp", WPS_REFRESH_STATIC
, NULL
},
250 { WPS_TOKEN_FILE_SIZE
, "fs", WPS_REFRESH_STATIC
, NULL
},
251 { WPS_TOKEN_FILE_VBR
, "fv", WPS_REFRESH_STATIC
, NULL
},
252 { WPS_TOKEN_FILE_DIRECTORY
, "d", WPS_REFRESH_STATIC
,
256 { WPS_TOKEN_FILE_BITRATE
, "Fb", WPS_REFRESH_STATIC
, NULL
},
257 { WPS_TOKEN_FILE_CODEC
, "Fc", WPS_REFRESH_STATIC
, NULL
},
258 { WPS_TOKEN_FILE_FREQUENCY
, "Ff", WPS_REFRESH_STATIC
, NULL
},
259 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "Fk", WPS_REFRESH_STATIC
, NULL
},
260 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "Fm", WPS_REFRESH_STATIC
, NULL
},
261 { WPS_TOKEN_FILE_NAME
, "Fn", WPS_REFRESH_STATIC
, NULL
},
262 { WPS_TOKEN_FILE_PATH
, "Fp", WPS_REFRESH_STATIC
, NULL
},
263 { WPS_TOKEN_FILE_SIZE
, "Fs", WPS_REFRESH_STATIC
, NULL
},
264 { WPS_TOKEN_FILE_VBR
, "Fv", WPS_REFRESH_STATIC
, NULL
},
265 { WPS_TOKEN_FILE_DIRECTORY
, "D", WPS_REFRESH_STATIC
,
268 /* current metadata */
269 { WPS_TOKEN_METADATA_ARTIST
, "ia", WPS_REFRESH_STATIC
, NULL
},
270 { WPS_TOKEN_METADATA_COMPOSER
, "ic", WPS_REFRESH_STATIC
, NULL
},
271 { WPS_TOKEN_METADATA_ALBUM
, "id", WPS_REFRESH_STATIC
, NULL
},
272 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "iA", WPS_REFRESH_STATIC
, NULL
},
273 { WPS_TOKEN_METADATA_GROUPING
, "iG", WPS_REFRESH_STATIC
, NULL
},
274 { WPS_TOKEN_METADATA_GENRE
, "ig", WPS_REFRESH_STATIC
, NULL
},
275 { WPS_TOKEN_METADATA_DISC_NUMBER
, "ik", WPS_REFRESH_STATIC
, NULL
},
276 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "in", WPS_REFRESH_STATIC
, NULL
},
277 { WPS_TOKEN_METADATA_TRACK_TITLE
, "it", WPS_REFRESH_STATIC
, NULL
},
278 { WPS_TOKEN_METADATA_VERSION
, "iv", WPS_REFRESH_STATIC
, NULL
},
279 { WPS_TOKEN_METADATA_YEAR
, "iy", WPS_REFRESH_STATIC
, NULL
},
280 { WPS_TOKEN_METADATA_COMMENT
, "iC", WPS_REFRESH_STATIC
, NULL
},
283 { WPS_TOKEN_METADATA_ARTIST
, "Ia", WPS_REFRESH_STATIC
, NULL
},
284 { WPS_TOKEN_METADATA_COMPOSER
, "Ic", WPS_REFRESH_STATIC
, NULL
},
285 { WPS_TOKEN_METADATA_ALBUM
, "Id", WPS_REFRESH_STATIC
, NULL
},
286 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "IA", WPS_REFRESH_STATIC
, NULL
},
287 { WPS_TOKEN_METADATA_GROUPING
, "IG", WPS_REFRESH_STATIC
, NULL
},
288 { WPS_TOKEN_METADATA_GENRE
, "Ig", WPS_REFRESH_STATIC
, NULL
},
289 { WPS_TOKEN_METADATA_DISC_NUMBER
, "Ik", WPS_REFRESH_STATIC
, NULL
},
290 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "In", WPS_REFRESH_STATIC
, NULL
},
291 { WPS_TOKEN_METADATA_TRACK_TITLE
, "It", WPS_REFRESH_STATIC
, NULL
},
292 { WPS_TOKEN_METADATA_VERSION
, "Iv", WPS_REFRESH_STATIC
, NULL
},
293 { WPS_TOKEN_METADATA_YEAR
, "Iy", WPS_REFRESH_STATIC
, NULL
},
294 { WPS_TOKEN_METADATA_COMMENT
, "IC", WPS_REFRESH_STATIC
, NULL
},
296 #if (CONFIG_CODEC != MAS3507D)
297 { WPS_TOKEN_SOUND_PITCH
, "Sp", WPS_REFRESH_DYNAMIC
, NULL
},
299 #if (CONFIG_CODEC == SWCODEC)
300 { WPS_TOKEN_SOUND_SPEED
, "Ss", WPS_REFRESH_DYNAMIC
, NULL
},
302 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
303 { WPS_TOKEN_VLED_HDD
, "lh", WPS_REFRESH_DYNAMIC
, NULL
},
306 { WPS_TOKEN_MAIN_HOLD
, "mh", WPS_REFRESH_DYNAMIC
, NULL
},
308 #ifdef HAS_REMOTE_BUTTON_HOLD
309 { WPS_TOKEN_REMOTE_HOLD
, "mr", WPS_REFRESH_DYNAMIC
, NULL
},
311 { WPS_TOKEN_UNKNOWN
, "mr", 0, NULL
},
314 { WPS_TOKEN_REPEAT_MODE
, "mm", WPS_REFRESH_DYNAMIC
, NULL
},
315 { WPS_TOKEN_PLAYBACK_STATUS
, "mp", WPS_REFRESH_DYNAMIC
, NULL
},
316 { WPS_TOKEN_BUTTON_VOLUME
, "mv", WPS_REFRESH_DYNAMIC
,
319 #ifdef HAVE_LCD_BITMAP
320 { WPS_TOKEN_PEAKMETER
, "pm", WPS_REFRESH_PEAK_METER
, NULL
},
322 { WPS_TOKEN_PLAYER_PROGRESSBAR
, "pf",
323 WPS_REFRESH_DYNAMIC
| WPS_REFRESH_PLAYER_PROGRESS
, parse_progressbar
},
325 { WPS_TOKEN_PROGRESSBAR
, "pb", WPS_REFRESH_PLAYER_PROGRESS
,
328 { WPS_TOKEN_VOLUME
, "pv", WPS_REFRESH_DYNAMIC
, NULL
},
330 { WPS_TOKEN_TRACK_ELAPSED_PERCENT
, "px", WPS_REFRESH_DYNAMIC
, NULL
},
331 { WPS_TOKEN_TRACK_TIME_ELAPSED
, "pc", WPS_REFRESH_DYNAMIC
, NULL
},
332 { WPS_TOKEN_TRACK_TIME_REMAINING
, "pr", WPS_REFRESH_DYNAMIC
, NULL
},
333 { WPS_TOKEN_TRACK_LENGTH
, "pt", WPS_REFRESH_STATIC
, NULL
},
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
);
756 static int parse_viewport_display(const char *wps_bufptr
,
757 struct wps_token
*token
,
758 struct wps_data
*wps_data
)
761 char letter
= wps_bufptr
[0];
763 if (letter
< 'a' || letter
> 'z')
765 /* invalid viewport tag */
766 return WPS_ERROR_INVALID_PARAM
;
768 token
->value
.i
= letter
;
772 #ifdef HAVE_LCD_BITMAP
773 static int parse_playlistview_text(struct playlistviewer
*viewer
,
774 enum info_line_type line
, char* text
)
777 const struct wps_tag
*tag
;
779 const char *start
= text
;
783 viewer
->lines
[line
].count
= 0;
784 viewer
->lines
[line
].scroll
= false;
787 if (*text
== '%') /* it is a token of some type */
799 /* escaped characters */
800 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = WPS_TOKEN_CHARACTER
;
801 viewer
->lines
[line
].strings
[cur_string
][0] = *text
;
802 viewer
->lines
[line
].strings
[cur_string
++][1] = '\0';
806 strncmp(text
, tag
->name
, strlen(tag
->name
)) != 0;
808 /* %s isnt stored as a tag so manually check for it */
809 if (tag
->type
== WPS_NO_TOKEN
)
811 if (!strncmp(tag
->name
, "s", 1))
813 viewer
->lines
[line
].scroll
= true;
817 else if (tag
->type
== WPS_TOKEN_UNKNOWN
)
820 /* just copy the string */
821 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = WPS_TOKEN_STRING
;
822 while (i
<(MAX_PLAYLISTLINE_STRLEN
-1) && text
[i
] != '|' && text
[i
] != '%')
824 viewer
->lines
[line
].strings
[cur_string
][i
] = text
[i
];
827 viewer
->lines
[line
].strings
[cur_string
][i
] = '\0';
835 /* unsupported tag, reject */
838 taglen
= strlen(tag
->name
);
839 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = tag
->type
;
848 /* just copy the string */
849 viewer
->lines
[line
].tokens
[viewer
->lines
[line
].count
++] = WPS_TOKEN_STRING
;
850 while (i
<(MAX_PLAYLISTLINE_STRLEN
-1) && text
[i
] != '|' && text
[i
] != '%')
852 viewer
->lines
[line
].strings
[cur_string
][i
] = text
[i
];
855 viewer
->lines
[line
].strings
[cur_string
][i
] = '\0';
864 static int parse_playlistview(const char *wps_bufptr
,
865 struct wps_token
*token
, struct wps_data
*wps_data
)
868 /* %Vp|<use icons>|<start offset>|info line text|no info text| */
869 struct playlistviewer
*viewer
= skin_buffer_alloc(sizeof(struct playlistviewer
));
870 char *ptr
= strchr(wps_bufptr
, '|');
873 return WPS_ERROR_INVALID_PARAM
;
874 viewer
->vp
= &curr_vp
->vp
;
875 viewer
->show_icons
= true;
876 viewer
->start_offset
= atoi(ptr
+1);
877 token
->value
.data
= (void*)viewer
;
878 ptr
= strchr(ptr
+1, '|');
879 length
= parse_playlistview_text(viewer
, TRACK_HAS_INFO
, ptr
);
881 return WPS_ERROR_INVALID_PARAM
;
882 length
= parse_playlistview_text(viewer
, TRACK_HAS_NO_INFO
, ptr
+length
);
884 return WPS_ERROR_INVALID_PARAM
;
886 return skip_end_of_line(wps_bufptr
);
890 static int parse_viewport(const char *wps_bufptr
,
891 struct wps_token
*token
,
892 struct wps_data
*wps_data
)
894 (void)token
; /* Kill warnings */
895 const char *ptr
= wps_bufptr
;
897 struct skin_viewport
*skin_vp
= skin_buffer_alloc(sizeof(struct skin_viewport
));
899 /* check for the optional letter to signify its a hideable viewport */
900 /* %Vl|<label>|<rest of tags>| */
901 skin_vp
->hidden_flags
= 0;
902 skin_vp
->label
= VP_NO_LABEL
;
904 skin_vp
->lines
= NULL
;
907 curr_line
->curr_subline
->last_token_idx
= wps_data
->num_tokens
908 - (wps_data
->num_tokens
> 0 ? 1 : 0);
912 if (!skin_start_new_line(skin_vp
, wps_data
->num_tokens
))
913 return WPS_ERROR_INVALID_PARAM
;
917 skin_vp
->label
= VP_INFO_LABEL
;
918 skin_vp
->hidden_flags
= VP_NEVER_VISIBLE
;
921 else if (*ptr
== 'l')
925 char label
= *(ptr
+2);
926 if (label
>= 'a' && label
<= 'z')
928 skin_vp
->hidden_flags
= VP_DRAW_HIDEABLE
;
929 skin_vp
->label
= label
;
932 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
937 return WPS_ERROR_INVALID_PARAM
;
940 struct viewport
*vp
= &skin_vp
->vp
;
941 /* format: %V|x|y|width|height|font|fg_pattern|bg_pattern| */
942 if (!(ptr
= viewport_parse_viewport(vp
, curr_screen
, ptr
, '|')))
943 return WPS_ERROR_INVALID_PARAM
;
945 /* Check for trailing | */
947 return WPS_ERROR_INVALID_PARAM
;
949 if (follow_lang_direction
&& lang_is_rtl())
951 vp
->flags
|= VP_FLAG_ALIGN_RIGHT
;
952 vp
->x
= screens
[curr_screen
].lcdwidth
- vp
->width
- vp
->x
;
955 vp
->flags
&= ~VP_FLAG_ALIGN_RIGHT
; /* ignore right-to-left languages */
957 struct skin_token_list
*list
= new_skin_token_list_item(NULL
, skin_vp
);
959 return WPS_ERROR_INVALID_PARAM
;
960 add_to_ll_chain(&wps_data
->viewports
, list
);
962 /* Skip the rest of the line */
963 return skip_end_of_line(wps_bufptr
);
966 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
967 static int parse_image_special(const char *wps_bufptr
,
968 struct wps_token
*token
,
969 struct wps_data
*wps_data
)
971 (void)wps_data
; /* kill warning */
973 const char *pos
= NULL
;
977 pos
= strchr(wps_bufptr
+ 1, '|');
978 newline
= strchr(wps_bufptr
, '\n');
980 error
= (pos
> newline
);
983 if (token
->type
== WPS_TOKEN_IMAGE_BACKDROP
)
985 /* format: %X|filename.bmp| or %Xd */
986 if (*(wps_bufptr
) == 'd')
988 wps_data
->backdrop
= NULL
;
989 return skip_end_of_line(wps_bufptr
);
992 wps_data
->backdrop
= (char*)wps_bufptr
+ 1;
996 return WPS_ERROR_INVALID_PARAM
;
997 /* Skip the rest of the line */
998 return skip_end_of_line(wps_bufptr
);
1002 #endif /* HAVE_LCD_BITMAP */
1004 static int parse_setting_and_lang(const char *wps_bufptr
,
1005 struct wps_token
*token
,
1006 struct wps_data
*wps_data
)
1008 /* NOTE: both the string validations that happen in here will
1009 * automatically PASS on checkwps because its too hard to get
1010 * settings_list.c and englinsh.lang built for it.
1011 * If that ever changes remove the #ifndef __PCTOOL__'s here
1014 const char *ptr
= wps_bufptr
;
1019 /* Find the setting's cfg_name */
1021 return WPS_ERROR_INVALID_PARAM
;
1023 end
= strchr(ptr
,'|');
1025 return WPS_ERROR_INVALID_PARAM
;
1026 strlcpy(temp
, ptr
,end
-ptr
+1);
1028 if (token
->type
== WPS_TOKEN_TRANSLATEDSTRING
)
1031 i
= lang_english_to_id(temp
);
1033 return WPS_ERROR_INVALID_PARAM
;
1038 /* Find the setting */
1039 for (i
=0; i
<nb_settings
; i
++)
1040 if (settings
[i
].cfg_name
&&
1041 !strncmp(settings
[i
].cfg_name
,ptr
,end
-ptr
) &&
1042 /* prevent matches on cfg_name prefixes */
1043 strlen(settings
[i
].cfg_name
)==(size_t)(end
-ptr
))
1046 if (i
== nb_settings
)
1047 return WPS_ERROR_INVALID_PARAM
;
1050 /* Store the setting number */
1053 /* Skip the rest of the line */
1058 static int parse_dir_level(const char *wps_bufptr
,
1059 struct wps_token
*token
,
1060 struct wps_data
*wps_data
)
1062 char val
[] = { *wps_bufptr
, '\0' };
1063 token
->value
.i
= atoi(val
);
1064 (void)wps_data
; /* Kill warnings */
1068 static int parse_timeout(const char *wps_bufptr
,
1069 struct wps_token
*token
,
1070 struct wps_data
*wps_data
)
1074 bool have_point
= false;
1075 bool have_tenth
= false;
1077 (void)wps_data
; /* Kill the warning */
1079 while ( isdigit(*wps_bufptr
) || *wps_bufptr
== '.' )
1081 if (*wps_bufptr
!= '.')
1084 val
+= *wps_bufptr
- '0';
1100 if (have_tenth
== false)
1103 if (val
== 0 && skip
== 0)
1105 /* decide what to do if no value was specified */
1106 switch (token
->type
)
1108 case WPS_TOKEN_SUBLINE_TIMEOUT
:
1110 case WPS_TOKEN_BUTTON_VOLUME
:
1115 token
->value
.i
= val
;
1120 static int parse_progressbar(const char *wps_bufptr
,
1121 struct wps_token
*token
,
1122 struct wps_data
*wps_data
)
1124 /* %pb or %pb|filename|x|y|width|height|
1125 using - for any of the params uses "sane" values */
1126 #ifdef HAVE_LCD_BITMAP
1134 const char *filename
;
1135 int x
, y
, height
, width
;
1137 const char *ptr
= wps_bufptr
;
1138 struct progressbar
*pb
= skin_buffer_alloc(sizeof(struct progressbar
));
1139 struct skin_token_list
*item
= new_skin_token_list_item(token
, pb
);
1142 return WPS_ERROR_INVALID_PARAM
;
1144 struct viewport
*vp
= &curr_vp
->vp
;
1145 /* we need to know what line number (viewport relative) this pb is,
1146 * so count them... */
1148 struct skin_line
*line
= curr_vp
->lines
;
1154 pb
->have_bitmap_pb
= false;
1155 pb
->bm
.data
= NULL
; /* no bitmap specified */
1156 pb
->follow_lang_direction
= follow_lang_direction
> 0;
1158 if (*wps_bufptr
!= '|') /* regular old style */
1161 pb
->width
= vp
->width
;
1162 pb
->height
= SYSFONT_HEIGHT
-2;
1163 pb
->y
= -line_num
- 1; /* Will be computed during the rendering */
1166 add_to_ll_chain(&wps_data
->progressbars
, item
);
1169 ptr
= wps_bufptr
+ 1;
1171 if (!(ptr
= parse_list("sdddd", &set
, '|', ptr
, &filename
,
1172 &x
, &y
, &width
, &height
)))
1173 return WPS_ERROR_INVALID_PARAM
;
1175 if (LIST_VALUE_PARSED(set
, PB_FILENAME
)) /* filename */
1176 pb
->bm
.data
= (char*)filename
;
1178 if (LIST_VALUE_PARSED(set
, PB_X
)) /* x */
1183 if (LIST_VALUE_PARSED(set
, PB_WIDTH
)) /* width */
1185 /* A zero width causes a divide-by-zero error later, so reject it */
1187 return WPS_ERROR_INVALID_PARAM
;
1192 pb
->width
= vp
->width
- pb
->x
;
1194 if (LIST_VALUE_PARSED(set
, PB_HEIGHT
)) /* height, default to font height */
1196 /* A zero height makes no sense - reject it */
1198 return WPS_ERROR_INVALID_PARAM
;
1200 pb
->height
= height
;
1204 if (vp
->font
> FONT_UI
)
1205 pb
->height
= -1; /* calculate at display time */
1209 pb
->height
= font_get(vp
->font
)->height
;
1216 if (LIST_VALUE_PARSED(set
, PB_Y
)) /* y */
1219 pb
->y
= -line_num
- 1; /* Will be computed during the rendering */
1222 add_to_ll_chain(&wps_data
->progressbars
, item
);
1224 /* Skip the rest of the line */
1225 return skip_end_of_line(wps_bufptr
)-1;
1229 if (*(wps_bufptr
-1) == 'f')
1230 wps_data
->full_line_progressbar
= true;
1232 wps_data
->full_line_progressbar
= false;
1239 #ifdef HAVE_ALBUMART
1240 static int parse_int(const char *newline
, const char **_pos
, int *num
)
1242 *_pos
= parse_list("d", NULL
, '|', *_pos
, num
);
1244 return (!*_pos
|| *_pos
> newline
|| **_pos
!= '|');
1247 static int parse_albumart_load(const char *wps_bufptr
,
1248 struct wps_token
*token
,
1249 struct wps_data
*wps_data
)
1251 const char *_pos
, *newline
;
1253 struct dim dimensions
;
1255 bool swap_for_rtl
= lang_is_rtl() && follow_lang_direction
;
1256 struct skin_albumart
*aa
= skin_buffer_alloc(sizeof(struct skin_albumart
));
1257 (void)token
; /* silence warning */
1259 return skip_end_of_line(wps_bufptr
);
1261 /* reset albumart info in wps */
1264 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
1265 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
1266 aa
->vp
= &curr_vp
->vp
;
1268 /* format: %Cl|x|y|[[l|c|r]mwidth]|[[t|c|b]mheight]| */
1270 newline
= strchr(wps_bufptr
, '\n');
1275 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
1279 /* initial validation and parsing of x component */
1280 if (parse_int(newline
, &_pos
, &aa
->x
))
1281 return WPS_ERROR_INVALID_PARAM
;
1285 /* initial validation and parsing of y component */
1286 if (parse_int(newline
, &_pos
, &aa
->y
))
1287 return WPS_ERROR_INVALID_PARAM
;
1289 /* parsing width field */
1293 /* apply each modifier in turn */
1301 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1303 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1307 aa
->xalign
= WPS_ALBUMART_ALIGN_CENTER
;
1313 aa
->xalign
= WPS_ALBUMART_ALIGN_LEFT
;
1315 aa
->xalign
= WPS_ALBUMART_ALIGN_RIGHT
;
1323 /* simply ignored */
1330 /* extract max width data */
1333 if (parse_int(newline
, &_pos
, &aa
->width
))
1334 return WPS_ERROR_INVALID_PARAM
;
1337 /* parsing height field */
1341 /* apply each modifier in turn */
1348 aa
->yalign
= WPS_ALBUMART_ALIGN_TOP
;
1352 aa
->yalign
= WPS_ALBUMART_ALIGN_CENTER
;
1357 aa
->yalign
= WPS_ALBUMART_ALIGN_BOTTOM
;
1365 /* simply ignored */
1372 /* extract max height data */
1375 if (parse_int(newline
, &_pos
, &aa
->height
))
1376 return WPS_ERROR_INVALID_PARAM
;
1379 /* if we got here, we parsed everything ok .. ! */
1382 else if (aa
->width
> LCD_WIDTH
)
1383 aa
->width
= LCD_WIDTH
;
1387 else if (aa
->height
> LCD_HEIGHT
)
1388 aa
->height
= LCD_HEIGHT
;
1391 aa
->x
= LCD_WIDTH
- (aa
->x
+ aa
->width
);
1393 aa
->state
= WPS_ALBUMART_LOAD
;
1395 wps_data
->albumart
= aa
;
1397 dimensions
.width
= aa
->width
;
1398 dimensions
.height
= aa
->height
;
1400 albumart_slot
= playback_claim_aa_slot(&dimensions
);
1402 if (0 <= albumart_slot
)
1403 wps_data
->playback_aa_slot
= albumart_slot
;
1405 /* Skip the rest of the line */
1406 return skip_end_of_line(wps_bufptr
);
1409 static int parse_albumart_display(const char *wps_bufptr
,
1410 struct wps_token
*token
,
1411 struct wps_data
*wps_data
)
1414 struct wps_token
*prev
= token
-1;
1415 if ((wps_data
->num_tokens
>= 1) && (prev
->type
== WPS_TOKEN_CONDITIONAL
))
1417 token
->type
= WPS_TOKEN_ALBUMART_FOUND
;
1419 else if (wps_data
->albumart
)
1421 wps_data
->albumart
->vp
= &curr_vp
->vp
;
1424 /* the old code did this so keep it here for now...
1425 * this is to allow the posibility to showing the next tracks AA! */
1426 if (wps_bufptr
+1 == 'n')
1431 #endif /* HAVE_ALBUMART */
1433 #ifdef HAVE_TOUCHSCREEN
1435 struct touchaction
{const char* s
; int action
;};
1436 static const struct touchaction touchactions
[] = {
1437 {"play", ACTION_WPS_PLAY
}, {"stop", ACTION_WPS_STOP
},
1438 {"prev", ACTION_WPS_SKIPPREV
}, {"next", ACTION_WPS_SKIPNEXT
},
1439 {"ffwd", ACTION_WPS_SEEKFWD
}, {"rwd", ACTION_WPS_SEEKBACK
},
1440 {"menu", ACTION_WPS_MENU
}, {"browse", ACTION_WPS_BROWSE
},
1441 {"shuffle", ACTION_TOUCH_SHUFFLE
}, {"repmode", ACTION_TOUCH_REPMODE
},
1442 {"quickscreen", ACTION_WPS_QUICKSCREEN
},{"contextmenu", ACTION_WPS_CONTEXT
},
1443 {"playlist", ACTION_WPS_VIEW_PLAYLIST
}, {"pitch", ACTION_WPS_PITCHSCREEN
},
1444 {"voldown", ACTION_WPS_VOLDOWN
}, {"volup", ACTION_WPS_VOLUP
},
1446 static int parse_touchregion(const char *wps_bufptr
,
1447 struct wps_token
*token
, struct wps_data
*wps_data
)
1451 struct touchregion
*region
= NULL
;
1452 const char *ptr
= wps_bufptr
;
1454 const char pb_string
[] = "progressbar";
1455 const char vol_string
[] = "volume";
1458 /* format: %T|x|y|width|height|action|
1459 * if action starts with & the area must be held to happen
1461 * play - play/pause playback
1462 * stop - stop playback, exit the wps
1465 * ffwd - seek forward
1466 * rwd - seek backwards
1467 * menu - go back to the main menu
1468 * browse - go back to the file/db browser
1469 * shuffle - toggle shuffle mode
1470 * repmode - cycle the repeat mode
1471 * quickscreen - go into the quickscreen
1472 * contextmenu - open the context menu
1473 * playlist - go into the playlist
1474 * pitch - go into the pitchscreen
1475 * volup - increase volume by one step
1476 * voldown - decrease volume by one step
1481 return WPS_ERROR_INVALID_PARAM
;
1484 if (!(ptr
= parse_list("dddds", NULL
, '|', ptr
, &x
, &y
, &w
, &h
, &action
)))
1485 return WPS_ERROR_INVALID_PARAM
;
1487 /* Check there is a terminating | */
1489 return WPS_ERROR_INVALID_PARAM
;
1491 region
= skin_buffer_alloc(sizeof(struct touchregion
));
1493 return WPS_ERROR_INVALID_PARAM
;
1495 /* should probably do some bounds checking here with the viewport... but later */
1496 region
->action
= ACTION_NONE
;
1501 region
->wvp
= curr_vp
;
1502 region
->armed
= false;
1504 if(!strncmp(pb_string
, action
, sizeof(pb_string
)-1)
1505 && *(action
+ sizeof(pb_string
)-1) == '|')
1506 region
->type
= WPS_TOUCHREGION_SCROLLBAR
;
1507 else if(!strncmp(vol_string
, action
, sizeof(vol_string
)-1)
1508 && *(action
+ sizeof(vol_string
)-1) == '|')
1509 region
->type
= WPS_TOUCHREGION_VOLUME
;
1512 region
->type
= WPS_TOUCHREGION_ACTION
;
1517 region
->repeat
= true;
1520 region
->repeat
= false;
1523 imax
= ARRAYLEN(touchactions
);
1524 while ((region
->action
== ACTION_NONE
) &&
1527 /* try to match with one of our touchregion screens */
1528 int len
= strlen(touchactions
[i
].s
);
1529 if (!strncmp(touchactions
[i
].s
, action
, len
)
1530 && *(action
+len
) == '|')
1531 region
->action
= touchactions
[i
].action
;
1534 if (region
->action
== ACTION_NONE
)
1535 return WPS_ERROR_INVALID_PARAM
;
1537 struct skin_token_list
*item
= new_skin_token_list_item(NULL
, region
);
1539 return WPS_ERROR_INVALID_PARAM
;
1540 add_to_ll_chain(&wps_data
->touchregions
, item
);
1541 return skip_end_of_line(wps_bufptr
);
1545 /* Parse a generic token from the given string. Return the length read */
1546 static int parse_token(const char *wps_bufptr
, struct wps_data
*wps_data
)
1548 int skip
= 0, taglen
= 0, ret
;
1549 struct wps_token
*token
= wps_data
->tokens
+ wps_data
->num_tokens
;
1550 const struct wps_tag
*tag
;
1551 memset(token
, 0, sizeof(*token
));
1562 /* escaped characters */
1563 token
->type
= WPS_TOKEN_CHARACTER
;
1564 token
->value
.c
= *wps_bufptr
;
1566 wps_data
->num_tokens
++;
1570 /* conditional tag */
1571 token
->type
= WPS_TOKEN_CONDITIONAL
;
1573 condindex
[level
] = wps_data
->num_tokens
;
1574 numoptions
[level
] = 1;
1575 wps_data
->num_tokens
++;
1576 ret
= parse_token(wps_bufptr
+ 1, wps_data
);
1577 if (ret
< 0) return ret
;
1582 /* find what tag we have */
1583 for (tag
= all_tags
;
1584 strncmp(wps_bufptr
, tag
->name
, strlen(tag
->name
)) != 0;
1587 taglen
= (tag
->type
!= WPS_TOKEN_UNKNOWN
) ? strlen(tag
->name
) : 2;
1588 token
->type
= tag
->type
;
1589 curr_line
->curr_subline
->line_type
|= tag
->refresh_type
;
1591 /* if the tag has a special parsing function, we call it */
1592 if (tag
->parse_func
)
1594 ret
= tag
->parse_func(wps_bufptr
+ taglen
, token
, wps_data
);
1595 if (ret
< 0) return ret
;
1599 /* Some tags we don't want to save as tokens */
1600 if (tag
->type
== WPS_NO_TOKEN
)
1603 /* tags that start with 'F', 'I' or 'D' are for the next file */
1604 if ( *(tag
->name
) == 'I' || *(tag
->name
) == 'F' ||
1605 *(tag
->name
) == 'D')
1608 wps_data
->num_tokens
++;
1618 * Returns the number of bytes to skip the buf pointer to access the false
1619 * branch in a _binary_ conditional
1622 * - before the '|' if we have a false branch, (%?<true|false> -> %?<|false>)
1623 * - or before the closing '>' if there's no false branch (%?<true> -> %?<>)
1625 * depending on the features of a target it's not called from check_feature_tag,
1626 * hence the __attribute__ or it issues compiler warnings
1630 static int find_false_branch(const char *wps_bufptr
) __attribute__((unused
));
1631 static int find_false_branch(const char *wps_bufptr
)
1633 const char *buf
= wps_bufptr
;
1634 /* wps_bufptr is after the opening '<', hence level = 1*/
1641 { /* filter out the characters we check later if they're printed
1644 if (ch
== '<' || ch
== '>' || ch
== '|')
1646 /* else: some tags/printed literals we skip over */
1648 else if (ch
== '<') /* nested conditional */
1651 { /* closed our or a nested conditional,
1652 * do NOT skip over the '>' so that wps_parse() sees it for closing
1653 * if it is the closing one for our conditional */
1656 else if (ch
== '|' && level
== 1)
1657 { /* we found our separator, point before and get out */
1660 /* if level is 0, we don't have a false branch */
1661 } while (level
> 0 && *(++buf
));
1663 return buf
- wps_bufptr
;
1667 * returns the number of bytes to get the appropriate branch of a binary
1671 * - if a feature is available, it returns 0 to not skip anything
1672 * - if the feature is not available, skip to the false branch and don't
1673 * parse the true branch at all
1676 static int check_feature_tag(const char *wps_bufptr
, const int type
)
1681 case WPS_TOKEN_RTC_PRESENT
:
1685 return find_false_branch(wps_bufptr
);
1687 case WPS_TOKEN_HAVE_RECORDING
:
1688 #ifdef HAVE_RECORDING
1691 return find_false_branch(wps_bufptr
);
1693 default: /* not a tag we care about, just don't skip */
1700 data is the pointer to the structure where the parsed WPS should be stored.
1702 wps_bufptr points to the string containing the WPS tags */
1703 #define TOKEN_BLOCK_SIZE 128
1704 static bool wps_parse(struct wps_data
*data
, const char *wps_bufptr
, bool debug
)
1706 if (!data
|| !wps_bufptr
|| !*wps_bufptr
)
1708 enum wps_parse_error fail
= PARSE_OK
;
1710 int max_tokens
= TOKEN_BLOCK_SIZE
;
1711 size_t buf_free
= 0;
1715 /* allocate enough RAM for a reasonable skin, grow as needed.
1716 * Free any used RAM before loading the images to be 100% RAM efficient */
1717 data
->tokens
= (struct wps_token
*)skin_buffer_grab(&buf_free
);
1718 if (sizeof(struct wps_token
)*max_tokens
>= buf_free
)
1720 skin_buffer_increment(max_tokens
* sizeof(struct wps_token
), false);
1721 data
->num_tokens
= 0;
1724 /* Backdrop defaults to the setting unless %X is used, so set it now */
1725 if (global_settings
.backdrop_file
[0])
1727 data
->backdrop
= "-";
1731 while (*wps_bufptr
&& !fail
)
1733 if (follow_lang_direction
)
1734 follow_lang_direction
--;
1735 /* first make sure there is enough room for tokens */
1736 if (max_tokens
<= data
->num_tokens
+ 5)
1738 int extra_tokens
= TOKEN_BLOCK_SIZE
;
1739 size_t needed
= extra_tokens
* sizeof(struct wps_token
);
1740 /* do some smarts here to grow the array a bit */
1741 if (skin_buffer_freespace() < needed
)
1743 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1746 skin_buffer_increment(needed
, false);
1747 max_tokens
+= extra_tokens
;
1750 switch(*wps_bufptr
++)
1755 if ((ret
= parse_token(wps_bufptr
, data
)) < 0)
1757 fail
= PARSE_FAIL_COND_INVALID_PARAM
;
1760 else if (level
>= WPS_MAX_COND_LEVEL
- 1)
1762 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1768 /* Alternating sublines separator */
1770 if (level
>= 0) /* there are unclosed conditionals */
1772 fail
= PARSE_FAIL_UNCLOSED_COND
;
1776 if (!skin_start_new_subline(curr_line
, data
->num_tokens
))
1777 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1781 /* Conditional list start */
1783 if (data
->tokens
[data
->num_tokens
-2].type
!= WPS_TOKEN_CONDITIONAL
)
1785 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1788 wps_bufptr
+= check_feature_tag(wps_bufptr
,
1789 data
->tokens
[data
->num_tokens
-1].type
);
1790 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_START
;
1791 lastcond
[level
] = data
->num_tokens
++;
1794 /* Conditional list end */
1796 if (level
< 0) /* not in a conditional, invalid char */
1798 fail
= PARSE_FAIL_INVALID_CHAR
;
1802 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_END
;
1803 if (lastcond
[level
])
1804 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1807 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1811 lastcond
[level
] = 0;
1813 data
->tokens
[condindex
[level
]].value
.i
= numoptions
[level
];
1817 /* Conditional list option */
1819 if (level
< 0) /* not in a conditional, invalid char */
1821 fail
= PARSE_FAIL_INVALID_CHAR
;
1825 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_OPTION
;
1826 if (lastcond
[level
])
1827 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1830 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1834 lastcond
[level
] = data
->num_tokens
;
1835 numoptions
[level
]++;
1841 if (level
>= 0) /* there are unclosed conditionals */
1843 fail
= PARSE_FAIL_UNCLOSED_COND
;
1847 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1850 /* End of this line */
1852 if (level
>= 0) /* there are unclosed conditionals */
1854 fail
= PARSE_FAIL_UNCLOSED_COND
;
1857 /* add a new token for the \n so empty lines are correct */
1858 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CHARACTER
;
1859 data
->tokens
[data
->num_tokens
].value
.c
= '\n';
1860 data
->tokens
[data
->num_tokens
].next
= false;
1863 if (!skin_start_new_line(curr_vp
, data
->num_tokens
))
1865 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1875 unsigned int len
= 1;
1876 const char *string_start
= wps_bufptr
- 1;
1878 /* find the length of the string */
1879 while (*wps_bufptr
&& *wps_bufptr
!= '#' &&
1880 *wps_bufptr
!= '%' && *wps_bufptr
!= ';' &&
1881 *wps_bufptr
!= '<' && *wps_bufptr
!= '>' &&
1882 *wps_bufptr
!= '|' && *wps_bufptr
!= '\n')
1888 /* look if we already have that string */
1891 struct skin_token_list
*list
= data
->strings
;
1894 str
= (char*)list
->token
->value
.data
;
1895 found
= (strlen(str
) == len
&&
1896 strncmp(string_start
, str
, len
) == 0);
1898 break; /* break here because the list item is
1899 used if its found */
1902 /* If a matching string is found, found is true and i is
1903 the index of the string. If not, found is false */
1908 str
= (char*)skin_buffer_alloc(len
+1);
1911 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1914 strlcpy(str
, string_start
, len
+1);
1915 struct skin_token_list
*item
=
1916 new_skin_token_list_item(&data
->tokens
[data
->num_tokens
], str
);
1919 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1922 add_to_ll_chain(&data
->strings
, item
);
1926 /* another occurrence of an existing string */
1927 data
->tokens
[data
->num_tokens
].value
.data
= list
->token
->value
.data
;
1929 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_STRING
;
1936 if (!fail
&& level
>= 0) /* there are unclosed conditionals */
1937 fail
= PARSE_FAIL_UNCLOSED_COND
;
1939 if (*wps_bufptr
&& !fail
)
1940 /* one of the limits of the while loop was exceeded */
1941 fail
= PARSE_FAIL_LIMITS_EXCEEDED
;
1944 curr_line
->curr_subline
->last_token_idx
= data
->num_tokens
;
1945 data
->tokens
[data
->num_tokens
++].type
= WPS_NO_TOKEN
;
1946 /* freeup unused tokens */
1947 skin_buffer_free_from_front(sizeof(struct wps_token
)
1948 * (max_tokens
- data
->num_tokens
));
1950 #if defined(DEBUG) || defined(SIMULATOR)
1953 print_debug_info(data
, fail
, line_number
);
1965 * initial setup of wps_data; does reset everything
1966 * except fields which need to survive, i.e.
1969 static void skin_data_reset(struct wps_data
*wps_data
)
1971 #ifdef HAVE_LCD_BITMAP
1972 wps_data
->images
= NULL
;
1973 wps_data
->progressbars
= NULL
;
1975 #if LCD_DEPTH > 1 || defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1976 wps_data
->backdrop
= NULL
;
1978 #ifdef HAVE_TOUCHSCREEN
1979 wps_data
->touchregions
= NULL
;
1981 wps_data
->viewports
= NULL
;
1982 wps_data
->strings
= NULL
;
1983 #ifdef HAVE_ALBUMART
1984 wps_data
->albumart
= NULL
;
1985 if (wps_data
->playback_aa_slot
>= 0)
1987 playback_release_aa_slot(wps_data
->playback_aa_slot
);
1988 wps_data
->playback_aa_slot
= -1;
1991 wps_data
->tokens
= NULL
;
1992 wps_data
->num_tokens
= 0;
1994 #ifdef HAVE_LCD_BITMAP
1995 wps_data
->peak_meter_enabled
= false;
1996 wps_data
->wps_sb_tag
= false;
1997 wps_data
->show_sb_on_wps
= false;
1998 #else /* HAVE_LCD_CHARCELLS */
2001 for (i
= 0; i
< 8; i
++)
2003 wps_data
->wps_progress_pat
[i
] = 0;
2005 wps_data
->full_line_progressbar
= false;
2007 wps_data
->wps_loaded
= false;
2010 #ifdef HAVE_LCD_BITMAP
2011 static bool load_skin_bmp(struct wps_data
*wps_data
, struct bitmap
*bitmap
, char* bmpdir
)
2013 (void)wps_data
; /* only needed for remote targets */
2014 char img_path
[MAX_PATH
];
2015 get_image_filename(bitmap
->data
, bmpdir
,
2016 img_path
, sizeof(img_path
));
2019 printf("%s\n", img_path
);
2020 /* load the image */
2022 #ifdef HAVE_REMOTE_LCD
2023 if (curr_screen
== SCREEN_REMOTE
)
2024 format
= FORMAT_ANY
|FORMAT_REMOTE
;
2027 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
2030 char* imgbuf
= (char*)skin_buffer_grab(&max_buf
);
2031 bitmap
->data
= imgbuf
;
2032 int ret
= read_bmp_file(img_path
, bitmap
, max_buf
, format
, NULL
);
2038 skin_buffer_increment(ret
, true);
2042 strlcpy(bitmap
->data
, strrchr(img_path
, '/')+1, MAX_PATH
);
2043 //printf("%s\n", bitmap->data);
2050 /* Abort if we can't load an image */
2051 DEBUGF("Couldn't load '%s'\n", img_path
);
2056 static bool load_skin_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
2058 struct skin_token_list
*list
;
2059 bool retval
= true; /* return false if a single image failed to load */
2060 /* do the progressbars */
2061 list
= wps_data
->progressbars
;
2064 struct progressbar
*pb
= (struct progressbar
*)list
->token
->value
.data
;
2067 pb
->have_bitmap_pb
= load_skin_bmp(wps_data
, &pb
->bm
, bmpdir
);
2068 if (!pb
->have_bitmap_pb
) /* no success */
2073 /* regular images */
2074 list
= wps_data
->images
;
2077 struct gui_img
*img
= (struct gui_img
*)list
->token
->value
.data
;
2080 img
->loaded
= load_skin_bmp(wps_data
, &img
->bm
, bmpdir
);
2082 img
->subimage_height
= img
->bm
.height
/ img
->num_subimages
;
2089 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
2090 /* Backdrop load scheme:
2092 * 2) load the backdrop from settings
2094 if (wps_data
->backdrop
)
2096 bool needed
= wps_data
->backdrop
[0] != '-';
2097 wps_data
->backdrop
= skin_backdrop_load(wps_data
->backdrop
,
2098 bmpdir
, curr_screen
);
2099 if (!wps_data
->backdrop
&& needed
)
2102 #endif /* has backdrop support */
2107 static bool skin_load_fonts(struct wps_data
*data
)
2109 /* don't spit out after the first failue to aid debugging */
2110 bool success
= true;
2111 struct skin_token_list
*vp_list
;
2113 /* walk though each viewport and assign its font */
2114 for(vp_list
= data
->viewports
; vp_list
; vp_list
= vp_list
->next
)
2116 /* first, find the viewports that have a non-sys/ui-font font */
2117 struct skin_viewport
*skin_vp
=
2118 (struct skin_viewport
*)vp_list
->token
->value
.data
;
2119 struct viewport
*vp
= &skin_vp
->vp
;
2122 if (vp
->font
<= FONT_UI
)
2123 { /* the usual case -> built-in fonts */
2124 #ifdef HAVE_REMOTE_LCD
2125 if (vp
->font
== FONT_UI
)
2126 vp
->font
+= curr_screen
;
2132 /* now find the corresponding skin_font */
2133 struct skin_font
*font
= &skinfonts
[font_id
-FONT_FIRSTUSERFONT
];
2136 DEBUGF("font %d not specified\n", font_id
);
2141 /* load the font - will handle loading the same font again if
2142 * multiple viewports use the same */
2145 char *dot
= strchr(font
->name
, '.');
2147 font
->id
= skin_font_load(font
->name
);
2152 DEBUGF("Unable to load font %d: '%s.fnt'\n",
2153 font_id
, font
->name
);
2158 /* finally, assign the font_id to the viewport */
2159 vp
->font
= font
->id
;
2164 #endif /* HAVE_LCD_BITMAP */
2166 /* to setup up the wps-data from a format-buffer (isfile = false)
2167 from a (wps-)file (isfile = true)*/
2169 void skin_data_load_finalize(struct wps_data
*data
, const char* buf
)
2172 /* get the bitmap dir */
2173 char bmpdir
[MAX_PATH
];
2174 char *dot
= strrchr(buf
, '.');
2176 strlcpy(bmpdir
, buf
, dot
- buf
+ 1);
2178 /* load the bitmaps that were found by the parsing */
2179 if (!load_skin_bitmaps(data
, bmpdir
)) {
2180 skin_data_reset(data
);
2181 data
->wps_loaded
= false;
2184 #if defined(DEBUG) || defined(SIMULATOR)
2190 int skin_data_load(enum screen_type screen
, struct wps_data
*wps_data
,
2191 const char *buf
, bool isfile
, bool _single_pass
)
2193 if (!wps_data
|| !buf
)
2195 single_pass
= _single_pass
;
2197 printf ("single_pass %d\n", single_pass
);
2198 size_t old_buf_usage
= skin_buffer_usage();
2199 #ifdef HAVE_ALBUMART
2201 struct mp3entry
*curtrack
;
2203 struct skin_albumart old_aa
= {.state
= WPS_ALBUMART_NONE
};
2204 if (wps_data
->albumart
)
2206 old_aa
.state
= wps_data
->albumart
->state
;
2207 old_aa
.height
= wps_data
->albumart
->height
;
2208 old_aa
.width
= wps_data
->albumart
->width
;
2211 #ifdef HAVE_LCD_BITMAP
2213 for (i
=0;i
<MAXUSERFONTS
;i
++)
2215 skinfonts
[i
].id
= -1;
2216 skinfonts
[i
].name
= NULL
;
2219 #ifdef DEBUG_SKIN_ENGINE
2220 if (isfile
&& debug_wps
)
2222 DEBUGF("\n=====================\nLoading '%s'\n=====================\n", buf
);
2226 skin_data_reset(wps_data
);
2227 curr_screen
= screen
;
2229 /* alloc default viewport, will be fixed up later */
2230 curr_vp
= skin_buffer_alloc(sizeof(struct skin_viewport
));
2233 struct skin_token_list
*list
= new_skin_token_list_item(NULL
, curr_vp
);
2236 add_to_ll_chain(&wps_data
->viewports
, list
);
2239 /* Initialise the first (default) viewport */
2240 curr_vp
->label
= VP_DEFAULT_LABEL
;
2242 curr_vp
->hidden_flags
= 0;
2243 curr_vp
->lines
= NULL
;
2245 viewport_set_defaults(&curr_vp
->vp
, screen
);
2246 #ifdef HAVE_LCD_BITMAP
2247 curr_vp
->vp
.font
= FONT_UI
;
2251 if (!skin_start_new_line(curr_vp
, 0))
2256 if (wps_parse(wps_data
, buf
, false))
2258 #ifdef HAVE_LCD_BITMAP
2259 /* load the backdrop */
2260 if (!load_skin_bitmaps(wps_data
, BACKDROP_DIR
)) {
2261 skin_data_reset(wps_data
);
2271 int fd
= open_utf8(buf
, O_RDONLY
);
2276 /* get buffer space from the plugin buffer */
2277 size_t buffersize
= 0;
2278 char *wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
2283 /* copy the file's content to the buffer for parsing,
2284 ensuring that every line ends with a newline char. */
2285 unsigned int start
= 0;
2286 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
2288 start
+= strlen(wps_buffer
+ start
);
2289 if (start
< buffersize
- 1)
2291 wps_buffer
[start
++] = '\n';
2292 wps_buffer
[start
] = 0;
2301 /* parse the WPS source */
2302 if (!wps_parse(wps_data
, wps_buffer
, true)) {
2303 skin_data_reset(wps_data
);
2307 wps_data
->wps_loaded
= true;
2309 #ifdef HAVE_LCD_BITMAP
2310 /* get the bitmap dir */
2311 char bmpdir
[MAX_PATH
];
2312 char *dot
= strrchr(buf
, '.');
2314 strlcpy(bmpdir
, buf
, dot
- buf
+ 1);
2315 /* load the bitmaps that were found by the parsing */
2316 if (!load_skin_bitmaps(wps_data
, bmpdir
)) {
2317 skin_data_reset(wps_data
);
2318 wps_data
->wps_loaded
= false;
2321 if (single_pass
&& !skin_load_fonts(wps_data
))
2323 skin_data_reset(wps_data
);
2324 wps_data
->wps_loaded
= false;
2328 #if defined(HAVE_ALBUMART) && !defined(__PCTOOL__)
2329 status
= audio_status();
2330 if (status
& AUDIO_STATUS_PLAY
)
2332 struct skin_albumart
*aa
= wps_data
->albumart
;
2333 if (aa
&& ((aa
->state
&& !old_aa
.state
) ||
2335 (((old_aa
.height
!= aa
->height
) ||
2336 (old_aa
.width
!= aa
->width
))))))
2338 curtrack
= audio_current_track();
2339 offset
= curtrack
->offset
;
2341 if (!(status
& AUDIO_STATUS_PAUSE
))
2346 #if defined(DEBUG) || defined(SIMULATOR)
2350 //printf("buf %s\n, curr_size %d\n", buf, curr_size);
2351 return skin_buffer_usage() - old_buf_usage
+ curr_size
;