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 ****************************************************************************/
32 #define FONT_SYSFIXED 0
47 #ifdef HAVE_LCD_BITMAP
55 #define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps"
56 #define RWPS_DEFAULTCFG WPS_DIR "/rockbox_default.rwps"
58 #define WPS_ERROR_INVALID_PARAM -1
60 #define PARSE_FAIL_UNCLOSED_COND 1
61 #define PARSE_FAIL_INVALID_CHAR 2
62 #define PARSE_FAIL_COND_SYNTAX_ERROR 3
63 #define PARSE_FAIL_COND_INVALID_PARAM 4
65 /* level of current conditional.
66 -1 means we're not in a conditional. */
67 static int level
= -1;
69 /* index of the last WPS_TOKEN_CONDITIONAL_OPTION
70 or WPS_TOKEN_CONDITIONAL_START in current level */
71 static int lastcond
[WPS_MAX_COND_LEVEL
];
73 /* index of the WPS_TOKEN_CONDITIONAL in current level */
74 static int condindex
[WPS_MAX_COND_LEVEL
];
76 /* number of condtional options in current level */
77 static int numoptions
[WPS_MAX_COND_LEVEL
];
79 /* the current line in the file */
82 #ifdef HAVE_LCD_BITMAP
85 #define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS+1) /* WPS images + pbar bitmap + backdrop */
87 #define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS) /* WPS images + pbar bitmap */
90 #define PROGRESSBAR_BMP MAX_IMAGES
91 #define BACKDROP_BMP (MAX_BITMAPS-1)
93 /* pointers to the bitmap filenames in the WPS source */
94 static const char *bmp_names
[MAX_BITMAPS
];
96 #endif /* HAVE_LCD_BITMAP */
99 /* debugging function */
100 extern void print_debug_info(struct wps_data
*data
, int fail
, int line
);
103 static void wps_reset(struct wps_data
*data
);
105 /* Function for parsing of details for a token. At the moment the
106 function is called, the token type has already been set. The
107 function must fill in the details and possibly add more tokens
108 to the token array. It should return the number of chars that
111 wps_bufptr points to the char following the tag (i.e. where
113 token is the pointer to the 'main' token being parsed
115 typedef int (*wps_tag_parse_func
)(const char *wps_bufptr
,
116 struct wps_token
*token
, struct wps_data
*wps_data
);
119 enum wps_token_type type
;
121 unsigned char refresh_type
;
122 const wps_tag_parse_func parse_func
;
125 /* prototypes of all special parse functions : */
126 static int parse_subline_timeout(const char *wps_bufptr
,
127 struct wps_token
*token
, struct wps_data
*wps_data
);
128 static int parse_progressbar(const char *wps_bufptr
,
129 struct wps_token
*token
, struct wps_data
*wps_data
);
130 static int parse_dir_level(const char *wps_bufptr
,
131 struct wps_token
*token
, struct wps_data
*wps_data
);
133 #ifdef HAVE_LCD_BITMAP
134 static int parse_viewport_display(const char *wps_bufptr
,
135 struct wps_token
*token
, struct wps_data
*wps_data
);
136 static int parse_viewport(const char *wps_bufptr
,
137 struct wps_token
*token
, struct wps_data
*wps_data
);
138 static int parse_statusbar_enable(const char *wps_bufptr
,
139 struct wps_token
*token
, struct wps_data
*wps_data
);
140 static int parse_statusbar_disable(const char *wps_bufptr
,
141 struct wps_token
*token
, struct wps_data
*wps_data
);
142 static int parse_image_display(const char *wps_bufptr
,
143 struct wps_token
*token
, struct wps_data
*wps_data
);
144 static int parse_image_load(const char *wps_bufptr
,
145 struct wps_token
*token
, struct wps_data
*wps_data
);
146 #endif /*HAVE_LCD_BITMAP */
147 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
148 static int parse_image_special(const char *wps_bufptr
,
149 struct wps_token
*token
, struct wps_data
*wps_data
);
152 static int parse_albumart_load(const char *wps_bufptr
,
153 struct wps_token
*token
, struct wps_data
*wps_data
);
154 static int parse_albumart_conditional(const char *wps_bufptr
,
155 struct wps_token
*token
, struct wps_data
*wps_data
);
156 #endif /* HAVE_ALBUMART */
159 #define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
161 #define WPS_RTC_REFRESH WPS_REFRESH_STATIC
164 /* array of available tags - those with more characters have to go first
165 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
166 static const struct wps_tag all_tags
[] = {
168 { WPS_TOKEN_ALIGN_CENTER
, "ac", 0, NULL
},
169 { WPS_TOKEN_ALIGN_LEFT
, "al", 0, NULL
},
170 { WPS_TOKEN_ALIGN_RIGHT
, "ar", 0, NULL
},
172 { WPS_TOKEN_BATTERY_PERCENT
, "bl", WPS_REFRESH_DYNAMIC
, NULL
},
173 { WPS_TOKEN_BATTERY_VOLTS
, "bv", WPS_REFRESH_DYNAMIC
, NULL
},
174 { WPS_TOKEN_BATTERY_TIME
, "bt", WPS_REFRESH_DYNAMIC
, NULL
},
175 { WPS_TOKEN_BATTERY_SLEEPTIME
, "bs", WPS_REFRESH_DYNAMIC
, NULL
},
176 #if CONFIG_CHARGING >= CHARGING_MONITOR
177 { WPS_TOKEN_BATTERY_CHARGING
, "bc", WPS_REFRESH_DYNAMIC
, NULL
},
180 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED
,"bp", WPS_REFRESH_DYNAMIC
, NULL
},
183 { WPS_TOKEN_RTC_DAY_OF_MONTH
, "cd", WPS_RTC_REFRESH
, NULL
},
184 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
,"ce", WPS_RTC_REFRESH
, NULL
},
185 { WPS_TOKEN_RTC_12HOUR_CFG
, "cf", WPS_RTC_REFRESH
, NULL
},
186 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
, "cH", WPS_RTC_REFRESH
, NULL
},
187 { WPS_TOKEN_RTC_HOUR_24
, "ck", WPS_RTC_REFRESH
, NULL
},
188 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
, "cI", WPS_RTC_REFRESH
, NULL
},
189 { WPS_TOKEN_RTC_HOUR_12
, "cl", WPS_RTC_REFRESH
, NULL
},
190 { WPS_TOKEN_RTC_MONTH
, "cm", WPS_RTC_REFRESH
, NULL
},
191 { WPS_TOKEN_RTC_MINUTE
, "cM", WPS_RTC_REFRESH
, NULL
},
192 { WPS_TOKEN_RTC_SECOND
, "cS", WPS_RTC_REFRESH
, NULL
},
193 { WPS_TOKEN_RTC_YEAR_2_DIGITS
, "cy", WPS_RTC_REFRESH
, NULL
},
194 { WPS_TOKEN_RTC_YEAR_4_DIGITS
, "cY", WPS_RTC_REFRESH
, NULL
},
195 { WPS_TOKEN_RTC_AM_PM_UPPER
, "cP", WPS_RTC_REFRESH
, NULL
},
196 { WPS_TOKEN_RTC_AM_PM_LOWER
, "cp", WPS_RTC_REFRESH
, NULL
},
197 { WPS_TOKEN_RTC_WEEKDAY_NAME
, "ca", WPS_RTC_REFRESH
, NULL
},
198 { WPS_TOKEN_RTC_MONTH_NAME
, "cb", WPS_RTC_REFRESH
, NULL
},
199 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
, "cu", WPS_RTC_REFRESH
, NULL
},
200 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
, "cw", WPS_RTC_REFRESH
, NULL
},
203 { WPS_TOKEN_FILE_BITRATE
, "fb", WPS_REFRESH_STATIC
, NULL
},
204 { WPS_TOKEN_FILE_CODEC
, "fc", WPS_REFRESH_STATIC
, NULL
},
205 { WPS_TOKEN_FILE_FREQUENCY
, "ff", WPS_REFRESH_STATIC
, NULL
},
206 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "fk", WPS_REFRESH_STATIC
, NULL
},
207 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "fm", WPS_REFRESH_STATIC
, NULL
},
208 { WPS_TOKEN_FILE_NAME
, "fn", WPS_REFRESH_STATIC
, NULL
},
209 { WPS_TOKEN_FILE_PATH
, "fp", WPS_REFRESH_STATIC
, NULL
},
210 { WPS_TOKEN_FILE_SIZE
, "fs", WPS_REFRESH_STATIC
, NULL
},
211 { WPS_TOKEN_FILE_VBR
, "fv", WPS_REFRESH_STATIC
, NULL
},
212 { WPS_TOKEN_FILE_DIRECTORY
, "d", WPS_REFRESH_STATIC
,
216 { WPS_TOKEN_FILE_BITRATE
, "Fb", WPS_REFRESH_DYNAMIC
, NULL
},
217 { WPS_TOKEN_FILE_CODEC
, "Fc", WPS_REFRESH_DYNAMIC
, NULL
},
218 { WPS_TOKEN_FILE_FREQUENCY
, "Ff", WPS_REFRESH_DYNAMIC
, NULL
},
219 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "Fk", WPS_REFRESH_DYNAMIC
, NULL
},
220 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "Fm", WPS_REFRESH_DYNAMIC
, NULL
},
221 { WPS_TOKEN_FILE_NAME
, "Fn", WPS_REFRESH_DYNAMIC
, NULL
},
222 { WPS_TOKEN_FILE_PATH
, "Fp", WPS_REFRESH_DYNAMIC
, NULL
},
223 { WPS_TOKEN_FILE_SIZE
, "Fs", WPS_REFRESH_DYNAMIC
, NULL
},
224 { WPS_TOKEN_FILE_VBR
, "Fv", WPS_REFRESH_DYNAMIC
, NULL
},
225 { WPS_TOKEN_FILE_DIRECTORY
, "D", WPS_REFRESH_DYNAMIC
,
228 /* current metadata */
229 { WPS_TOKEN_METADATA_ARTIST
, "ia", WPS_REFRESH_STATIC
, NULL
},
230 { WPS_TOKEN_METADATA_COMPOSER
, "ic", WPS_REFRESH_STATIC
, NULL
},
231 { WPS_TOKEN_METADATA_ALBUM
, "id", WPS_REFRESH_STATIC
, NULL
},
232 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "iA", WPS_REFRESH_STATIC
, NULL
},
233 { WPS_TOKEN_METADATA_GROUPING
, "iG", WPS_REFRESH_STATIC
, NULL
},
234 { WPS_TOKEN_METADATA_GENRE
, "ig", WPS_REFRESH_STATIC
, NULL
},
235 { WPS_TOKEN_METADATA_DISC_NUMBER
, "ik", WPS_REFRESH_STATIC
, NULL
},
236 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "in", WPS_REFRESH_STATIC
, NULL
},
237 { WPS_TOKEN_METADATA_TRACK_TITLE
, "it", WPS_REFRESH_STATIC
, NULL
},
238 { WPS_TOKEN_METADATA_VERSION
, "iv", WPS_REFRESH_STATIC
, NULL
},
239 { WPS_TOKEN_METADATA_YEAR
, "iy", WPS_REFRESH_STATIC
, NULL
},
240 { WPS_TOKEN_METADATA_COMMENT
, "iC", WPS_REFRESH_STATIC
, NULL
},
243 { WPS_TOKEN_METADATA_ARTIST
, "Ia", WPS_REFRESH_DYNAMIC
, NULL
},
244 { WPS_TOKEN_METADATA_COMPOSER
, "Ic", WPS_REFRESH_DYNAMIC
, NULL
},
245 { WPS_TOKEN_METADATA_ALBUM
, "Id", WPS_REFRESH_DYNAMIC
, NULL
},
246 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "IA", WPS_REFRESH_DYNAMIC
, NULL
},
247 { WPS_TOKEN_METADATA_GROUPING
, "IG", WPS_REFRESH_DYNAMIC
, NULL
},
248 { WPS_TOKEN_METADATA_GENRE
, "Ig", WPS_REFRESH_DYNAMIC
, NULL
},
249 { WPS_TOKEN_METADATA_DISC_NUMBER
, "Ik", WPS_REFRESH_DYNAMIC
, NULL
},
250 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "In", WPS_REFRESH_DYNAMIC
, NULL
},
251 { WPS_TOKEN_METADATA_TRACK_TITLE
, "It", WPS_REFRESH_DYNAMIC
, NULL
},
252 { WPS_TOKEN_METADATA_VERSION
, "Iv", WPS_REFRESH_DYNAMIC
, NULL
},
253 { WPS_TOKEN_METADATA_YEAR
, "Iy", WPS_REFRESH_DYNAMIC
, NULL
},
254 { WPS_TOKEN_METADATA_COMMENT
, "IC", WPS_REFRESH_DYNAMIC
, NULL
},
256 #if (CONFIG_CODEC != MAS3507D)
257 { WPS_TOKEN_SOUND_PITCH
, "Sp", WPS_REFRESH_DYNAMIC
, NULL
},
260 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
261 { WPS_TOKEN_VLED_HDD
, "lh", WPS_REFRESH_DYNAMIC
, NULL
},
264 { WPS_TOKEN_MAIN_HOLD
, "mh", WPS_REFRESH_DYNAMIC
, NULL
},
266 #ifdef HAS_REMOTE_BUTTON_HOLD
267 { WPS_TOKEN_REMOTE_HOLD
, "mr", WPS_REFRESH_DYNAMIC
, NULL
},
269 { WPS_TOKEN_UNKNOWN
, "mr", 0, NULL
},
272 { WPS_TOKEN_REPEAT_MODE
, "mm", WPS_REFRESH_DYNAMIC
, NULL
},
273 { WPS_TOKEN_PLAYBACK_STATUS
, "mp", WPS_REFRESH_DYNAMIC
, NULL
},
275 #ifdef HAVE_LCD_BITMAP
276 { WPS_TOKEN_PEAKMETER
, "pm", WPS_REFRESH_PEAK_METER
, NULL
},
278 { WPS_TOKEN_PLAYER_PROGRESSBAR
, "pf",
279 WPS_REFRESH_DYNAMIC
| WPS_REFRESH_PLAYER_PROGRESS
, parse_progressbar
},
281 { WPS_TOKEN_PROGRESSBAR
, "pb", WPS_REFRESH_PLAYER_PROGRESS
,
284 { WPS_TOKEN_VOLUME
, "pv", WPS_REFRESH_DYNAMIC
, NULL
},
286 { WPS_TOKEN_TRACK_ELAPSED_PERCENT
, "px", WPS_REFRESH_DYNAMIC
, NULL
},
287 { WPS_TOKEN_TRACK_TIME_ELAPSED
, "pc", WPS_REFRESH_DYNAMIC
, NULL
},
288 { WPS_TOKEN_TRACK_TIME_REMAINING
, "pr", WPS_REFRESH_DYNAMIC
, NULL
},
289 { WPS_TOKEN_TRACK_LENGTH
, "pt", WPS_REFRESH_STATIC
, NULL
},
291 { WPS_TOKEN_PLAYLIST_POSITION
, "pp", WPS_REFRESH_STATIC
, NULL
},
292 { WPS_TOKEN_PLAYLIST_ENTRIES
, "pe", WPS_REFRESH_STATIC
, NULL
},
293 { WPS_TOKEN_PLAYLIST_NAME
, "pn", WPS_REFRESH_STATIC
, NULL
},
294 { WPS_TOKEN_PLAYLIST_SHUFFLE
, "ps", WPS_REFRESH_DYNAMIC
, NULL
},
297 { WPS_TOKEN_DATABASE_PLAYCOUNT
, "rp", WPS_REFRESH_DYNAMIC
, NULL
},
298 { WPS_TOKEN_DATABASE_RATING
, "rr", WPS_REFRESH_DYNAMIC
, NULL
},
299 { WPS_TOKEN_DATABASE_AUTOSCORE
, "ra", WPS_REFRESH_DYNAMIC
, NULL
},
302 #if CONFIG_CODEC == SWCODEC
303 { WPS_TOKEN_REPLAYGAIN
, "rg", WPS_REFRESH_STATIC
, NULL
},
304 { WPS_TOKEN_CROSSFADE
, "xf", WPS_REFRESH_DYNAMIC
, NULL
},
307 { WPS_NO_TOKEN
, "s", WPS_REFRESH_SCROLL
, NULL
},
308 { WPS_TOKEN_SUBLINE_TIMEOUT
, "t", 0, parse_subline_timeout
},
310 #ifdef HAVE_LCD_BITMAP
311 { WPS_NO_TOKEN
, "we", 0, parse_statusbar_enable
},
312 { WPS_NO_TOKEN
, "wd", 0, parse_statusbar_disable
},
314 { WPS_NO_TOKEN
, "xl", 0, parse_image_load
},
316 { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
, "xd", WPS_REFRESH_STATIC
,
317 parse_image_display
},
319 { WPS_TOKEN_IMAGE_DISPLAY
, "x", 0, parse_image_load
},
321 { WPS_NO_TOKEN
, "Cl", 0, parse_albumart_load
},
322 { WPS_TOKEN_ALBUMART_DISPLAY
, "C", WPS_REFRESH_STATIC
,
323 parse_albumart_conditional
},
326 { WPS_VIEWPORT_ENABLE
, "Vd", WPS_REFRESH_DYNAMIC
,
327 parse_viewport_display
},
328 { WPS_NO_TOKEN
, "V", 0, parse_viewport
},
330 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
331 { WPS_TOKEN_IMAGE_BACKDROP
, "X", 0, parse_image_special
},
335 { WPS_TOKEN_UNKNOWN
, "", 0, NULL
}
336 /* the array MUST end with an empty string (first char is \0) */
339 /* Returns the number of chars that should be skipped to jump
340 immediately after the first eol, i.e. to the start of the next line */
341 static int skip_end_of_line(const char *wps_bufptr
)
345 while(*(wps_bufptr
+ skip
) != '\n')
350 /* Starts a new subline in the current line during parsing */
351 static void wps_start_new_subline(struct wps_data
*data
)
353 data
->num_sublines
++;
354 data
->sublines
[data
->num_sublines
].first_token_idx
= data
->num_tokens
;
355 data
->lines
[data
->num_lines
].num_sublines
++;
358 #ifdef HAVE_LCD_BITMAP
360 static int parse_statusbar_enable(const char *wps_bufptr
,
361 struct wps_token
*token
,
362 struct wps_data
*wps_data
)
364 (void)token
; /* Kill warnings */
365 wps_data
->wps_sb_tag
= true;
366 wps_data
->show_sb_on_wps
= true;
367 if (wps_data
->viewports
[0].vp
.y
== 0)
369 wps_data
->viewports
[0].vp
.y
= STATUSBAR_HEIGHT
;
370 wps_data
->viewports
[0].vp
.height
-= STATUSBAR_HEIGHT
;
372 return skip_end_of_line(wps_bufptr
);
375 static int parse_statusbar_disable(const char *wps_bufptr
,
376 struct wps_token
*token
,
377 struct wps_data
*wps_data
)
379 (void)token
; /* Kill warnings */
380 wps_data
->wps_sb_tag
= true;
381 wps_data
->show_sb_on_wps
= false;
382 if (wps_data
->viewports
[0].vp
.y
== STATUSBAR_HEIGHT
)
384 wps_data
->viewports
[0].vp
.y
= 0;
385 wps_data
->viewports
[0].vp
.height
+= STATUSBAR_HEIGHT
;
387 return skip_end_of_line(wps_bufptr
);
390 static bool load_bitmap(struct wps_data
*wps_data
,
395 #ifdef HAVE_REMOTE_LCD
396 if (wps_data
->remote_wps
)
397 format
= FORMAT_ANY
|FORMAT_REMOTE
;
400 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
402 int ret
= read_bmp_file(filename
, bm
,
403 wps_data
->img_buf_free
,
410 /* Always consume an even number of bytes */
412 wps_data
->img_buf_ptr
+= ret
;
413 wps_data
->img_buf_free
-= ret
;
421 static int get_image_id(int c
)
423 if(c
>= 'a' && c
<= 'z')
425 else if(c
>= 'A' && c
<= 'Z')
431 static char *get_image_filename(const char *start
, const char* bmpdir
,
432 char *buf
, int buf_size
)
434 const char *end
= strchr(start
, '|');
436 if ( !end
|| (end
- start
) >= (buf_size
- ROCKBOX_DIR_LEN
- 2) )
442 int bmpdirlen
= strlen(bmpdir
);
445 buf
[bmpdirlen
] = '/';
446 memcpy( &buf
[bmpdirlen
+ 1], start
, end
- start
);
447 buf
[bmpdirlen
+ 1 + end
- start
] = 0;
452 static int parse_image_display(const char *wps_bufptr
,
453 struct wps_token
*token
,
454 struct wps_data
*wps_data
)
457 int n
= get_image_id(wps_bufptr
[0]);
462 /* invalid picture display tag */
463 return WPS_ERROR_INVALID_PARAM
;
466 if ((subimage
= get_image_id(wps_bufptr
[1])) != -1)
469 if (subimage
>= wps_data
->img
[n
].num_subimages
)
470 return WPS_ERROR_INVALID_PARAM
;
472 /* Store sub-image number to display in high bits */
473 token
->value
.i
= n
| (subimage
<< 8);
474 return 2; /* We have consumed 2 bytes */
477 return 1; /* We have consumed 1 byte */
481 static int parse_image_load(const char *wps_bufptr
,
482 struct wps_token
*token
,
483 struct wps_data
*wps_data
)
486 const char *ptr
= wps_bufptr
;
488 const char* filename
;
493 /* format: %x|n|filename.bmp|x|y|
494 or %xl|n|filename.bmp|x|y|
495 or %xl|n|filename.bmp|x|y|num_subimages|
499 return WPS_ERROR_INVALID_PARAM
;
503 if (!(ptr
= parse_list("ssdd", NULL
, '|', ptr
, &id
, &filename
, &x
, &y
)))
504 return WPS_ERROR_INVALID_PARAM
;
506 /* Check there is a terminating | */
508 return WPS_ERROR_INVALID_PARAM
;
510 /* get the image ID */
511 n
= get_image_id(*id
);
513 /* check the image number and load state */
514 if(n
< 0 || n
>= MAX_IMAGES
|| wps_data
->img
[n
].loaded
)
516 /* Invalid image ID */
517 return WPS_ERROR_INVALID_PARAM
;
520 /* save a pointer to the filename */
521 bmp_names
[n
] = filename
;
523 wps_data
->img
[n
].x
= x
;
524 wps_data
->img
[n
].y
= y
;
526 /* save current viewport */
527 wps_data
->img
[n
].vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
529 if (token
->type
== WPS_TOKEN_IMAGE_DISPLAY
)
531 wps_data
->img
[n
].always_display
= true;
535 /* Parse the (optional) number of sub-images */
537 newline
= strchr(ptr
, '\n');
538 pos
= strchr(ptr
, '|');
539 if (pos
&& pos
< newline
)
540 wps_data
->img
[n
].num_subimages
= atoi(ptr
);
542 if (wps_data
->img
[n
].num_subimages
<= 0)
543 return WPS_ERROR_INVALID_PARAM
;
546 /* Skip the rest of the line */
547 return skip_end_of_line(wps_bufptr
);
550 static int parse_viewport_display(const char *wps_bufptr
,
551 struct wps_token
*token
,
552 struct wps_data
*wps_data
)
555 char letter
= wps_bufptr
[0];
557 if (letter
< 'a' || letter
> 'z')
559 /* invalid viewport tag */
560 return WPS_ERROR_INVALID_PARAM
;
562 token
->value
.i
= letter
;
566 static int parse_viewport(const char *wps_bufptr
,
567 struct wps_token
*token
,
568 struct wps_data
*wps_data
)
570 (void)token
; /* Kill warnings */
571 const char *ptr
= wps_bufptr
;
584 int lcd_width
= LCD_WIDTH
, lcd_height
= LCD_HEIGHT
;
585 #ifdef HAVE_REMOTE_LCD
586 if (wps_data
->remote_wps
)
588 lcd_width
= LCD_REMOTE_WIDTH
;
589 lcd_height
= LCD_REMOTE_HEIGHT
;
593 if (wps_data
->num_viewports
>= WPS_MAX_VIEWPORTS
)
594 return WPS_ERROR_INVALID_PARAM
;
596 wps_data
->num_viewports
++;
597 /* check for the optional letter to signify its a hideable viewport */
598 /* %Vl|<label>|<rest of tags>| */
599 wps_data
->viewports
[wps_data
->num_viewports
].hidden_flags
= 0;
605 char label
= *(ptr
+2);
606 if (label
>= 'a' && label
<= 'z')
608 wps_data
->viewports
[wps_data
->num_viewports
].hidden_flags
= VP_DRAW_HIDEABLE
;
609 wps_data
->viewports
[wps_data
->num_viewports
].label
= label
;
612 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
617 return WPS_ERROR_INVALID_PARAM
;
620 vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
621 /* format: %V|x|y|width|height|font|fg_pattern|bg_pattern| */
623 /* Set the defaults for fields not user-specified */
624 vp
->drawmode
= DRMODE_SOLID
;
626 /* Work out the depth of this display */
627 #ifdef HAVE_REMOTE_LCD
628 depth
= (wps_data
->remote_wps
? LCD_REMOTE_DEPTH
: LCD_DEPTH
);
633 #ifdef HAVE_LCD_COLOR
636 if (!(ptr
= parse_list("dddddcc", &set
, '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
637 &vp
->height
, &vp
->font
, &vp
->fg_pattern
,&vp
->bg_pattern
)))
638 return WPS_ERROR_INVALID_PARAM
;
642 #if (LCD_DEPTH == 2) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2)
644 /* Default to black on white */
647 if (!(ptr
= parse_list("dddddgg", &set
, '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
648 &vp
->height
, &vp
->font
, &vp
->fg_pattern
, &vp
->bg_pattern
)))
649 return WPS_ERROR_INVALID_PARAM
;
653 #if (LCD_DEPTH == 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 1)
656 if (!(ptr
= parse_list("ddddd", &set
, '|', ptr
, &vp
->x
, &vp
->y
,
657 &vp
->width
, &vp
->height
, &vp
->font
)))
658 return WPS_ERROR_INVALID_PARAM
;
664 /* Check for trailing | */
666 return WPS_ERROR_INVALID_PARAM
;
668 if (!LIST_VALUE_PARSED(set
, PL_X
) || !LIST_VALUE_PARSED(set
, PL_Y
))
669 return WPS_ERROR_INVALID_PARAM
;
672 if (!LIST_VALUE_PARSED(set
, PL_WIDTH
))
673 vp
->width
= lcd_width
- vp
->x
;
674 if (!LIST_VALUE_PARSED(set
, PL_HEIGHT
))
675 vp
->height
= lcd_height
- vp
->y
;
677 /* Default to using the user font if the font was an invalid number */
678 if (!LIST_VALUE_PARSED(set
, PL_FONT
) ||
679 ((vp
->font
!= FONT_SYSFIXED
) && (vp
->font
!= FONT_UI
)))
682 /* Validate the viewport dimensions - we know that the numbers are
683 non-negative integers */
684 if ((vp
->x
>= lcd_width
) ||
685 ((vp
->x
+ vp
->width
) > lcd_width
) ||
686 (vp
->y
>= lcd_height
) ||
687 ((vp
->y
+ vp
->height
) > lcd_height
))
689 return WPS_ERROR_INVALID_PARAM
;
692 #ifdef HAVE_LCD_COLOR
695 if (!LIST_VALUE_PARSED(set
, PL_FG
))
696 vp
->fg_pattern
= global_settings
.fg_color
;
697 if (!LIST_VALUE_PARSED(set
, PL_BG
))
698 vp
->bg_pattern
= global_settings
.bg_color
;
702 wps_data
->viewports
[wps_data
->num_viewports
-1].last_line
= wps_data
->num_lines
- 1;
704 wps_data
->viewports
[wps_data
->num_viewports
].first_line
= wps_data
->num_lines
;
706 if (wps_data
->num_sublines
< WPS_MAX_SUBLINES
)
708 wps_data
->lines
[wps_data
->num_lines
].first_subline_idx
=
709 wps_data
->num_sublines
;
711 wps_data
->sublines
[wps_data
->num_sublines
].first_token_idx
=
712 wps_data
->num_tokens
;
715 /* Skip the rest of the line */
716 return skip_end_of_line(wps_bufptr
);
720 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
721 static int parse_image_special(const char *wps_bufptr
,
722 struct wps_token
*token
,
723 struct wps_data
*wps_data
)
725 (void)wps_data
; /* kill warning */
727 const char *pos
= NULL
;
730 pos
= strchr(wps_bufptr
+ 1, '|');
731 newline
= strchr(wps_bufptr
, '\n');
734 return WPS_ERROR_INVALID_PARAM
;
736 if (token
->type
== WPS_TOKEN_IMAGE_BACKDROP
)
738 /* format: %X|filename.bmp| */
739 bmp_names
[BACKDROP_BMP
] = wps_bufptr
+ 1;
743 /* Skip the rest of the line */
744 return skip_end_of_line(wps_bufptr
);
748 #endif /* HAVE_LCD_BITMAP */
750 static int parse_dir_level(const char *wps_bufptr
,
751 struct wps_token
*token
,
752 struct wps_data
*wps_data
)
754 char val
[] = { *wps_bufptr
, '\0' };
755 token
->value
.i
= atoi(val
);
756 (void)wps_data
; /* Kill warnings */
760 static int parse_subline_timeout(const char *wps_bufptr
,
761 struct wps_token
*token
,
762 struct wps_data
*wps_data
)
766 bool have_point
= false;
767 bool have_tenth
= false;
769 (void)wps_data
; /* Kill the warning */
771 while ( isdigit(*wps_bufptr
) || *wps_bufptr
== '.' )
773 if (*wps_bufptr
!= '.')
776 val
+= *wps_bufptr
- '0';
792 if (have_tenth
== false)
795 token
->value
.i
= val
;
800 static int parse_progressbar(const char *wps_bufptr
,
801 struct wps_token
*token
,
802 struct wps_data
*wps_data
)
804 (void)token
; /* Kill warnings */
805 /* %pb or %pb|filename|x|y|width|height|
806 using - for any of the params uses "sane" values */
807 #ifdef HAVE_LCD_BITMAP
815 const char *filename
;
816 int x
, y
, height
, width
;
818 const char *ptr
= wps_bufptr
;
819 struct progressbar
*pb
;
820 struct viewport
*vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
821 int font_height
= font_get(vp
->font
)->height
;
822 int line_y_pos
= font_height
*(wps_data
->num_lines
-
823 wps_data
->viewports
[wps_data
->num_viewports
].first_line
);
825 if (wps_data
->progressbar_count
+1 >= MAX_PROGRESSBARS
)
826 return WPS_ERROR_INVALID_PARAM
;
828 pb
= &wps_data
->progressbar
[wps_data
->progressbar_count
];
829 pb
->have_bitmap_pb
= false;
831 if (*wps_bufptr
!= '|') /* regular old style */
834 pb
->width
= vp
->width
;
835 pb
->height
= SYSFONT_HEIGHT
-2;
836 pb
->y
= line_y_pos
+ (font_height
-pb
->height
)/2;
838 wps_data
->viewports
[wps_data
->num_viewports
].pb
=
839 &wps_data
->progressbar
[wps_data
->progressbar_count
];
840 wps_data
->progressbar_count
++;
843 ptr
= wps_bufptr
+ 1;
845 if (!(ptr
= parse_list("sdddd", &set
, '|', ptr
, &filename
,
846 &x
, &y
, &width
, &height
)))
847 return WPS_ERROR_INVALID_PARAM
;
848 if (LIST_VALUE_PARSED(set
, PB_FILENAME
)) /* filename */
849 bmp_names
[PROGRESSBAR_BMP
+wps_data
->progressbar_count
] = filename
;
850 if (LIST_VALUE_PARSED(set
, PB_X
)) /* x */
854 if (LIST_VALUE_PARSED(set
, PB_WIDTH
)) /* width */
857 pb
->width
= vp
->width
- pb
->x
;
858 if (LIST_VALUE_PARSED(set
, PB_HEIGHT
)) /* height, default to font height */
861 pb
->height
= font_height
;
862 if (LIST_VALUE_PARSED(set
, PB_Y
)) /* y */
865 pb
->y
= line_y_pos
+ (font_height
-pb
->height
)/2;
866 wps_data
->progressbar
[wps_data
->progressbar_count
].have_bitmap_pb
= false;
867 wps_data
->viewports
[wps_data
->num_viewports
].pb
=
868 &wps_data
->progressbar
[wps_data
->progressbar_count
];
869 wps_data
->progressbar_count
++;
870 /* Skip the rest of the line */
871 return skip_end_of_line(wps_bufptr
)-1;
874 if (*(wps_bufptr
-1) == 'f')
875 wps_data
->full_line_progressbar
= true;
877 wps_data
->full_line_progressbar
= false;
885 static int parse_albumart_load(const char *wps_bufptr
,
886 struct wps_token
*token
,
887 struct wps_data
*wps_data
)
889 const char *_pos
, *newline
;
891 const short xalign_mask
= WPS_ALBUMART_ALIGN_LEFT
|
892 WPS_ALBUMART_ALIGN_CENTER
|
893 WPS_ALBUMART_ALIGN_RIGHT
;
894 const short yalign_mask
= WPS_ALBUMART_ALIGN_TOP
|
895 WPS_ALBUMART_ALIGN_CENTER
|
896 WPS_ALBUMART_ALIGN_BOTTOM
;
898 (void)token
; /* silence warning */
900 /* reset albumart info in wps */
901 wps_data
->wps_uses_albumart
= WPS_ALBUMART_NONE
;
902 wps_data
->albumart_max_width
= -1;
903 wps_data
->albumart_max_height
= -1;
904 wps_data
->albumart_xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
905 wps_data
->albumart_yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
907 /* format: %Cl|x|y|[[l|c|r][d|i|s]mwidth]|[[t|c|b][d|i|s]mheight]| */
909 newline
= strchr(wps_bufptr
, '\n');
911 /* initial validation and parsing of x and y components */
912 if (*wps_bufptr
!= '|')
913 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
915 _pos
= wps_bufptr
+ 1;
917 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl|@ */
918 wps_data
->albumart_x
= atoi(_pos
);
920 _pos
= strchr(_pos
, '|');
921 if (!_pos
|| _pos
> newline
|| !isdigit(*(++_pos
)))
922 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl|7\n or %Cl|7|@ */
924 wps_data
->albumart_y
= atoi(_pos
);
926 _pos
= strchr(_pos
, '|');
927 if (!_pos
|| _pos
> newline
)
928 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no | after y coordinate
931 /* parsing width field */
935 /* apply each modifier in turn */
942 wps_data
->albumart_xalign
=
943 (wps_data
->albumart_xalign
& xalign_mask
) |
944 WPS_ALBUMART_ALIGN_LEFT
;
948 wps_data
->albumart_xalign
=
949 (wps_data
->albumart_xalign
& xalign_mask
) |
950 WPS_ALBUMART_ALIGN_CENTER
;
955 wps_data
->albumart_xalign
=
956 (wps_data
->albumart_xalign
& xalign_mask
) |
957 WPS_ALBUMART_ALIGN_RIGHT
;
961 wps_data
->albumart_xalign
|= WPS_ALBUMART_DECREASE
;
965 wps_data
->albumart_xalign
|= WPS_ALBUMART_INCREASE
;
969 wps_data
->albumart_xalign
|=
970 (WPS_ALBUMART_DECREASE
| WPS_ALBUMART_INCREASE
);
977 /* extract max width data */
980 if (!isdigit(*_pos
)) /* malformed token: e.g. %Cl|7|59|# */
981 return WPS_ERROR_INVALID_PARAM
;
983 wps_data
->albumart_max_width
= atoi(_pos
);
985 _pos
= strchr(_pos
, '|');
986 if (!_pos
|| _pos
> newline
)
987 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no | after width field
988 e.g. %Cl|7|59|200\n */
991 /* parsing height field */
995 /* apply each modifier in turn */
1002 wps_data
->albumart_yalign
=
1003 (wps_data
->albumart_yalign
& yalign_mask
) |
1004 WPS_ALBUMART_ALIGN_TOP
;
1008 wps_data
->albumart_yalign
=
1009 (wps_data
->albumart_yalign
& yalign_mask
) |
1010 WPS_ALBUMART_ALIGN_CENTER
;
1015 wps_data
->albumart_yalign
=
1016 (wps_data
->albumart_yalign
& yalign_mask
) |
1017 WPS_ALBUMART_ALIGN_BOTTOM
;
1021 wps_data
->albumart_yalign
|= WPS_ALBUMART_DECREASE
;
1025 wps_data
->albumart_yalign
|= WPS_ALBUMART_INCREASE
;
1029 wps_data
->albumart_yalign
|=
1030 (WPS_ALBUMART_DECREASE
| WPS_ALBUMART_INCREASE
);
1037 /* extract max height data */
1040 if (!isdigit(*_pos
))
1041 return WPS_ERROR_INVALID_PARAM
; /* malformed token e.g. %Cl|7|59|200|@ */
1043 wps_data
->albumart_max_height
= atoi(_pos
);
1045 _pos
= strchr(_pos
, '|');
1046 if (!_pos
|| _pos
> newline
)
1047 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no closing |
1048 e.g. %Cl|7|59|200|200\n */
1051 /* if we got here, we parsed everything ok .. ! */
1052 if (wps_data
->albumart_max_width
< 0)
1053 wps_data
->albumart_max_width
= 0;
1054 else if (wps_data
->albumart_max_width
> LCD_WIDTH
)
1055 wps_data
->albumart_max_width
= LCD_WIDTH
;
1057 if (wps_data
->albumart_max_height
< 0)
1058 wps_data
->albumart_max_height
= 0;
1059 else if (wps_data
->albumart_max_height
> LCD_HEIGHT
)
1060 wps_data
->albumart_max_height
= LCD_HEIGHT
;
1062 wps_data
->wps_uses_albumart
= WPS_ALBUMART_LOAD
;
1064 /* Skip the rest of the line */
1065 return skip_end_of_line(wps_bufptr
);
1068 static int parse_albumart_conditional(const char *wps_bufptr
,
1069 struct wps_token
*token
,
1070 struct wps_data
*wps_data
)
1072 struct wps_token
*prevtoken
= token
;
1074 if (wps_data
->num_tokens
>= 1 && prevtoken
->type
== WPS_TOKEN_CONDITIONAL
)
1076 /* This %C is part of a %?C construct.
1077 It's either %?C<blah> or %?Cn<blah> */
1078 token
->type
= WPS_TOKEN_ALBUMART_FOUND
;
1079 if (*wps_bufptr
== 'n' && *(wps_bufptr
+ 1) == '<')
1084 else if (*wps_bufptr
== '<')
1090 token
->type
= WPS_NO_TOKEN
;
1096 /* This %C tag is in a conditional construct. */
1097 wps_data
->albumart_cond_index
= condindex
[level
];
1101 #endif /* HAVE_ALBUMART */
1104 /* Parse a generic token from the given string. Return the length read */
1105 static int parse_token(const char *wps_bufptr
, struct wps_data
*wps_data
)
1107 int skip
= 0, taglen
= 0, ret
;
1108 struct wps_token
*token
= wps_data
->tokens
+ wps_data
->num_tokens
;
1109 const struct wps_tag
*tag
;
1120 /* escaped characters */
1121 token
->type
= WPS_TOKEN_CHARACTER
;
1122 token
->value
.c
= *wps_bufptr
;
1124 wps_data
->num_tokens
++;
1128 /* conditional tag */
1129 token
->type
= WPS_TOKEN_CONDITIONAL
;
1131 condindex
[level
] = wps_data
->num_tokens
;
1132 numoptions
[level
] = 1;
1133 wps_data
->num_tokens
++;
1134 ret
= parse_token(wps_bufptr
+ 1, wps_data
);
1135 if (ret
< 0) return ret
;
1140 /* find what tag we have */
1141 for (tag
= all_tags
;
1142 strncmp(wps_bufptr
, tag
->name
, strlen(tag
->name
)) != 0;
1145 taglen
= (tag
->type
!= WPS_TOKEN_UNKNOWN
) ? strlen(tag
->name
) : 2;
1146 token
->type
= tag
->type
;
1147 wps_data
->sublines
[wps_data
->num_sublines
].line_type
|=
1150 /* if the tag has a special parsing function, we call it */
1151 if (tag
->parse_func
)
1153 ret
= tag
->parse_func(wps_bufptr
+ taglen
, token
, wps_data
);
1154 if (ret
< 0) return ret
;
1158 /* Some tags we don't want to save as tokens */
1159 if (tag
->type
== WPS_NO_TOKEN
)
1162 /* tags that start with 'F', 'I' or 'D' are for the next file */
1163 if ( *(tag
->name
) == 'I' || *(tag
->name
) == 'F' ||
1164 *(tag
->name
) == 'D')
1167 wps_data
->num_tokens
++;
1176 data is the pointer to the structure where the parsed WPS should be stored.
1178 wps_bufptr points to the string containing the WPS tags */
1179 static bool wps_parse(struct wps_data
*data
, const char *wps_bufptr
)
1181 if (!data
|| !wps_bufptr
|| !*wps_bufptr
)
1184 char *stringbuf
= data
->string_buffer
;
1185 int stringbuf_used
= 0;
1191 while(*wps_bufptr
&& !fail
&& data
->num_tokens
< WPS_MAX_TOKENS
- 1
1192 && data
->num_viewports
< WPS_MAX_VIEWPORTS
1193 && data
->num_lines
< WPS_MAX_LINES
)
1195 switch(*wps_bufptr
++)
1200 if ((ret
= parse_token(wps_bufptr
, data
)) < 0)
1202 fail
= PARSE_FAIL_COND_INVALID_PARAM
;
1208 /* Alternating sublines separator */
1210 if (level
>= 0) /* there are unclosed conditionals */
1212 fail
= PARSE_FAIL_UNCLOSED_COND
;
1216 if (data
->num_sublines
+1 < WPS_MAX_SUBLINES
)
1217 wps_start_new_subline(data
);
1219 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1223 /* Conditional list start */
1225 if (data
->tokens
[data
->num_tokens
-2].type
!= WPS_TOKEN_CONDITIONAL
)
1227 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1231 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_START
;
1232 lastcond
[level
] = data
->num_tokens
++;
1235 /* Conditional list end */
1237 if (level
< 0) /* not in a conditional, invalid char */
1239 fail
= PARSE_FAIL_INVALID_CHAR
;
1243 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_END
;
1244 if (lastcond
[level
])
1245 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1248 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1252 lastcond
[level
] = 0;
1254 data
->tokens
[condindex
[level
]].value
.i
= numoptions
[level
];
1258 /* Conditional list option */
1260 if (level
< 0) /* not in a conditional, invalid char */
1262 fail
= PARSE_FAIL_INVALID_CHAR
;
1266 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_OPTION
;
1267 if (lastcond
[level
])
1268 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1271 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1275 lastcond
[level
] = data
->num_tokens
;
1276 numoptions
[level
]++;
1282 if (level
>= 0) /* there are unclosed conditionals */
1284 fail
= PARSE_FAIL_UNCLOSED_COND
;
1288 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1291 /* End of this line */
1293 if (level
>= 0) /* there are unclosed conditionals */
1295 fail
= PARSE_FAIL_UNCLOSED_COND
;
1300 wps_start_new_subline(data
);
1301 data
->num_lines
++; /* Start a new line */
1303 if ((data
->num_lines
< WPS_MAX_LINES
) &&
1304 (data
->num_sublines
< WPS_MAX_SUBLINES
))
1306 data
->lines
[data
->num_lines
].first_subline_idx
=
1309 data
->sublines
[data
->num_sublines
].first_token_idx
=
1318 unsigned int len
= 1;
1319 const char *string_start
= wps_bufptr
- 1;
1321 /* find the length of the string */
1322 while (*wps_bufptr
&& *wps_bufptr
!= '#' &&
1323 *wps_bufptr
!= '%' && *wps_bufptr
!= ';' &&
1324 *wps_bufptr
!= '<' && *wps_bufptr
!= '>' &&
1325 *wps_bufptr
!= '|' && *wps_bufptr
!= '\n')
1331 /* look if we already have that string */
1335 for (i
= 0, str
= data
->strings
, found
= false;
1336 i
< data
->num_strings
&&
1337 !(found
= (strlen(*str
) == len
&&
1338 strncmp(string_start
, *str
, len
) == 0));
1340 /* If a matching string is found, found is true and i is
1341 the index of the string. If not, found is false */
1343 /* If it's NOT a duplicate, do nothing if we already have
1344 too many unique strings */
1346 (stringbuf_used
< STRING_BUFFER_SIZE
- 1 &&
1347 data
->num_strings
< WPS_MAX_STRINGS
))
1354 if (stringbuf_used
+ len
> STRING_BUFFER_SIZE
- 1)
1355 len
= STRING_BUFFER_SIZE
- stringbuf_used
- 1;
1357 strncpy(stringbuf
, string_start
, len
);
1358 *(stringbuf
+ len
) = '\0';
1360 data
->strings
[data
->num_strings
] = stringbuf
;
1361 stringbuf
+= len
+ 1;
1362 stringbuf_used
+= len
+ 1;
1363 data
->tokens
[data
->num_tokens
].value
.i
=
1365 data
->num_strings
++;
1369 /* another ocurrence of an existing string */
1370 data
->tokens
[data
->num_tokens
].value
.i
= i
;
1372 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_STRING
;
1380 if (!fail
&& level
>= 0) /* there are unclosed conditionals */
1381 fail
= PARSE_FAIL_UNCLOSED_COND
;
1383 data
->viewports
[data
->num_viewports
].last_line
= data
->num_lines
- 1;
1385 /* We have finished with the last viewport, so increment count */
1386 data
->num_viewports
++;
1389 print_debug_info(data
, fail
, line
);
1395 #ifdef HAVE_LCD_BITMAP
1396 /* Clear the WPS image cache */
1397 static void wps_images_clear(struct wps_data
*data
)
1400 /* set images to unloaded and not displayed */
1401 for (i
= 0; i
< MAX_IMAGES
; i
++)
1403 data
->img
[i
].loaded
= false;
1404 data
->img
[i
].display
= -1;
1405 data
->img
[i
].always_display
= false;
1406 data
->img
[i
].num_subimages
= 1;
1411 /* initial setup of wps_data */
1412 void wps_data_init(struct wps_data
*wps_data
)
1414 #ifdef HAVE_LCD_BITMAP
1415 wps_images_clear(wps_data
);
1416 wps_data
->wps_sb_tag
= false;
1417 wps_data
->show_sb_on_wps
= false;
1418 wps_data
->img_buf_ptr
= wps_data
->img_buf
; /* where in image buffer */
1419 wps_data
->img_buf_free
= IMG_BUFSIZE
; /* free space in image buffer */
1420 wps_data
->peak_meter_enabled
= false;
1422 wps_data
->progressbar_count
= 0;
1423 #else /* HAVE_LCD_CHARCELLS */
1425 for (i
= 0; i
< 8; i
++)
1427 wps_data
->wps_progress_pat
[i
] = 0;
1429 wps_data
->full_line_progressbar
= false;
1431 wps_data
->wps_loaded
= false;
1434 static void wps_reset(struct wps_data
*data
)
1436 #ifdef HAVE_REMOTE_LCD
1437 bool rwps
= data
->remote_wps
; /* remember whether the data is for a RWPS */
1439 memset(data
, 0, sizeof(*data
));
1440 #ifdef HAVE_ALBUMART
1441 data
->wps_uses_albumart
= WPS_ALBUMART_NONE
;
1443 wps_data_init(data
);
1444 #ifdef HAVE_REMOTE_LCD
1445 data
->remote_wps
= rwps
;
1449 #ifdef HAVE_LCD_BITMAP
1451 static bool load_wps_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
1453 char img_path
[MAX_PATH
];
1454 struct bitmap
*bitmap
;
1457 for (n
= 0; n
< BACKDROP_BMP
; n
++)
1461 get_image_filename(bmp_names
[n
], bmpdir
,
1462 img_path
, sizeof(img_path
));
1464 if (n
>= PROGRESSBAR_BMP
) {
1465 /* progressbar bitmap */
1466 bitmap
= &wps_data
->progressbar
[n
-PROGRESSBAR_BMP
].bm
;
1467 loaded
= &wps_data
->progressbar
[n
-PROGRESSBAR_BMP
].have_bitmap_pb
;
1469 /* regular bitmap */
1470 bitmap
= &wps_data
->img
[n
].bm
;
1471 loaded
= &wps_data
->img
[n
].loaded
;
1474 /* load the image */
1475 bitmap
->data
= wps_data
->img_buf_ptr
;
1476 if (load_bitmap(wps_data
, img_path
, bitmap
))
1480 /* Calculate and store height if this image has sub-images */
1482 wps_data
->img
[n
].subimage_height
= wps_data
->img
[n
].bm
.height
/
1483 wps_data
->img
[n
].num_subimages
;
1487 /* Abort if we can't load an image */
1488 DEBUGF("ERR: Failed to load image %d - %s\n",n
,img_path
);
1494 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1495 if (bmp_names
[BACKDROP_BMP
])
1497 get_image_filename(bmp_names
[BACKDROP_BMP
], bmpdir
,
1498 img_path
, sizeof(img_path
));
1500 #if defined(HAVE_REMOTE_LCD)
1501 /* We only need to check LCD type if there is a remote LCD */
1502 if (!wps_data
->remote_wps
)
1505 /* Load backdrop for the main LCD */
1506 if (!load_wps_backdrop(img_path
))
1509 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1512 /* Load backdrop for the remote LCD */
1513 if (!load_remote_wps_backdrop(img_path
))
1518 #endif /* has backdrop support */
1520 /* If we got here, everything was OK */
1524 #endif /* HAVE_LCD_BITMAP */
1526 /* Skip leading UTF-8 BOM, if present. */
1527 static char *skip_utf8_bom(char *buf
)
1529 unsigned char *s
= (unsigned char *)buf
;
1531 if(s
[0] == 0xef && s
[1] == 0xbb && s
[2] == 0xbf)
1539 /* to setup up the wps-data from a format-buffer (isfile = false)
1540 from a (wps-)file (isfile = true)*/
1541 bool wps_data_load(struct wps_data
*wps_data
,
1542 struct screen
*display
,
1546 if (!wps_data
|| !buf
)
1549 wps_reset(wps_data
);
1551 /* Initialise the first (default) viewport */
1552 wps_data
->viewports
[0].vp
.x
= 0;
1553 wps_data
->viewports
[0].vp
.width
= display
->getwidth();
1554 if (!global_settings
.statusbar
)
1556 wps_data
->viewports
[0].vp
.y
= 0;
1557 wps_data
->viewports
[0].vp
.height
= display
->getheight();
1561 wps_data
->viewports
[0].vp
.y
= STATUSBAR_HEIGHT
;
1562 wps_data
->viewports
[0].vp
.height
= display
->getheight() -
1565 #ifdef HAVE_LCD_BITMAP
1566 wps_data
->viewports
[0].vp
.font
= FONT_UI
;
1567 wps_data
->viewports
[0].vp
.drawmode
= DRMODE_SOLID
;
1570 if (display
->depth
> 1)
1572 wps_data
->viewports
[0].vp
.fg_pattern
= display
->get_foreground();
1573 wps_data
->viewports
[0].vp
.bg_pattern
= display
->get_background();
1578 return wps_parse(wps_data
, buf
);
1583 * Hardcode loading WPS_DEFAULTCFG to cause a reset ideally this
1584 * wants to be a virtual file. Feel free to modify dirbrowse()
1585 * if you're feeling brave.
1588 if (! strcmp(buf
, WPS_DEFAULTCFG
) )
1590 global_settings
.wps_file
[0] = 0;
1594 #ifdef HAVE_REMOTE_LCD
1595 if (! strcmp(buf
, RWPS_DEFAULTCFG
) )
1597 global_settings
.rwps_file
[0] = 0;
1601 #endif /* __PCTOOL__ */
1603 int fd
= open(buf
, O_RDONLY
);
1608 /* get buffer space from the plugin buffer */
1609 size_t buffersize
= 0;
1610 char *wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
1615 /* copy the file's content to the buffer for parsing,
1616 ensuring that every line ends with a newline char. */
1617 unsigned int start
= 0;
1618 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
1620 start
+= strlen(wps_buffer
+ start
);
1621 if (start
< buffersize
- 1)
1623 wps_buffer
[start
++] = '\n';
1624 wps_buffer
[start
] = 0;
1633 #ifdef HAVE_LCD_BITMAP
1634 /* Set all filename pointers to NULL */
1635 memset(bmp_names
, 0, sizeof(bmp_names
));
1638 /* Skip leading UTF-8 BOM, if present. */
1639 wps_buffer
= skip_utf8_bom(wps_buffer
);
1641 /* parse the WPS source */
1642 if (!wps_parse(wps_data
, wps_buffer
)) {
1643 wps_reset(wps_data
);
1647 wps_data
->wps_loaded
= true;
1649 #ifdef HAVE_LCD_BITMAP
1650 /* get the bitmap dir */
1651 char bmpdir
[MAX_PATH
];
1653 char *dot
= strrchr(buf
, '.');
1654 bmpdirlen
= dot
- buf
;
1655 strncpy(bmpdir
, buf
, dot
- buf
);
1656 bmpdir
[bmpdirlen
] = 0;
1658 /* load the bitmaps that were found by the parsing */
1659 if (!load_wps_bitmaps(wps_data
, bmpdir
)) {
1660 wps_reset(wps_data
);
1668 int wps_subline_index(struct wps_data
*data
, int line
, int subline
)
1670 return data
->lines
[line
].first_subline_idx
+ subline
;
1673 int wps_first_token_index(struct wps_data
*data
, int line
, int subline
)
1675 int first_subline_idx
= data
->lines
[line
].first_subline_idx
;
1676 return data
->sublines
[first_subline_idx
+ subline
].first_token_idx
;
1679 int wps_last_token_index(struct wps_data
*data
, int line
, int subline
)
1681 int first_subline_idx
= data
->lines
[line
].first_subline_idx
;
1682 int idx
= first_subline_idx
+ subline
;
1683 if (idx
< data
->num_sublines
- 1)
1685 /* This subline ends where the next begins */
1686 return data
->sublines
[idx
+1].first_token_idx
- 1;
1690 /* The last subline goes to the end */
1691 return data
->num_tokens
- 1;