1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
30 #define FONT_SYSFIXED 0
45 #ifdef HAVE_LCD_BITMAP
53 #define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps"
54 #define RWPS_DEFAULTCFG WPS_DIR "/rockbox_default.rwps"
56 #define WPS_ERROR_INVALID_PARAM -1
58 #define PARSE_FAIL_UNCLOSED_COND 1
59 #define PARSE_FAIL_INVALID_CHAR 2
60 #define PARSE_FAIL_COND_SYNTAX_ERROR 3
61 #define PARSE_FAIL_COND_INVALID_PARAM 4
63 /* level of current conditional.
64 -1 means we're not in a conditional. */
65 static int level
= -1;
67 /* index of the last WPS_TOKEN_CONDITIONAL_OPTION
68 or WPS_TOKEN_CONDITIONAL_START in current level */
69 static int lastcond
[WPS_MAX_COND_LEVEL
];
71 /* index of the WPS_TOKEN_CONDITIONAL in current level */
72 static int condindex
[WPS_MAX_COND_LEVEL
];
74 /* number of condtional options in current level */
75 static int numoptions
[WPS_MAX_COND_LEVEL
];
77 /* the current line in the file */
80 #ifdef HAVE_LCD_BITMAP
83 #define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS+1) /* WPS images + pbar bitmap + backdrop */
85 #define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS) /* WPS images + pbar bitmap */
88 #define PROGRESSBAR_BMP MAX_IMAGES
89 #define BACKDROP_BMP (MAX_BITMAPS-1)
91 /* pointers to the bitmap filenames in the WPS source */
92 static const char *bmp_names
[MAX_BITMAPS
];
94 #endif /* HAVE_LCD_BITMAP */
97 /* debugging function */
98 extern void print_debug_info(struct wps_data
*data
, int fail
, int line
);
101 static void wps_reset(struct wps_data
*data
);
103 /* Function for parsing of details for a token. At the moment the
104 function is called, the token type has already been set. The
105 function must fill in the details and possibly add more tokens
106 to the token array. It should return the number of chars that
109 wps_bufptr points to the char following the tag (i.e. where
111 token is the pointer to the 'main' token being parsed
113 typedef int (*wps_tag_parse_func
)(const char *wps_bufptr
,
114 struct wps_token
*token
, struct wps_data
*wps_data
);
117 enum wps_token_type type
;
119 unsigned char refresh_type
;
120 const wps_tag_parse_func parse_func
;
123 /* prototypes of all special parse functions : */
124 static int parse_subline_timeout(const char *wps_bufptr
,
125 struct wps_token
*token
, struct wps_data
*wps_data
);
126 static int parse_progressbar(const char *wps_bufptr
,
127 struct wps_token
*token
, struct wps_data
*wps_data
);
128 static int parse_dir_level(const char *wps_bufptr
,
129 struct wps_token
*token
, struct wps_data
*wps_data
);
131 #ifdef HAVE_LCD_BITMAP
132 static int parse_viewport_display(const char *wps_bufptr
,
133 struct wps_token
*token
, struct wps_data
*wps_data
);
134 static int parse_viewport(const char *wps_bufptr
,
135 struct wps_token
*token
, struct wps_data
*wps_data
);
136 static int parse_statusbar_enable(const char *wps_bufptr
,
137 struct wps_token
*token
, struct wps_data
*wps_data
);
138 static int parse_statusbar_disable(const char *wps_bufptr
,
139 struct wps_token
*token
, struct wps_data
*wps_data
);
140 static int parse_image_display(const char *wps_bufptr
,
141 struct wps_token
*token
, struct wps_data
*wps_data
);
142 static int parse_image_load(const char *wps_bufptr
,
143 struct wps_token
*token
, struct wps_data
*wps_data
);
144 #endif /*HAVE_LCD_BITMAP */
145 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
146 static int parse_image_special(const char *wps_bufptr
,
147 struct wps_token
*token
, struct wps_data
*wps_data
);
150 static int parse_albumart_load(const char *wps_bufptr
,
151 struct wps_token
*token
, struct wps_data
*wps_data
);
152 static int parse_albumart_conditional(const char *wps_bufptr
,
153 struct wps_token
*token
, struct wps_data
*wps_data
);
154 #endif /* HAVE_ALBUMART */
157 #define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
159 #define WPS_RTC_REFRESH WPS_REFRESH_STATIC
162 /* array of available tags - those with more characters have to go first
163 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
164 static const struct wps_tag all_tags
[] = {
166 { WPS_TOKEN_ALIGN_CENTER
, "ac", 0, NULL
},
167 { WPS_TOKEN_ALIGN_LEFT
, "al", 0, NULL
},
168 { WPS_TOKEN_ALIGN_RIGHT
, "ar", 0, NULL
},
170 { WPS_TOKEN_BATTERY_PERCENT
, "bl", WPS_REFRESH_DYNAMIC
, NULL
},
171 { WPS_TOKEN_BATTERY_VOLTS
, "bv", WPS_REFRESH_DYNAMIC
, NULL
},
172 { WPS_TOKEN_BATTERY_TIME
, "bt", WPS_REFRESH_DYNAMIC
, NULL
},
173 { WPS_TOKEN_BATTERY_SLEEPTIME
, "bs", WPS_REFRESH_DYNAMIC
, NULL
},
174 #if CONFIG_CHARGING >= CHARGING_MONITOR
175 { WPS_TOKEN_BATTERY_CHARGING
, "bc", WPS_REFRESH_DYNAMIC
, NULL
},
178 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED
,"bp", WPS_REFRESH_DYNAMIC
, NULL
},
181 { WPS_TOKEN_RTC_DAY_OF_MONTH
, "cd", WPS_RTC_REFRESH
, NULL
},
182 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
,"ce", WPS_RTC_REFRESH
, NULL
},
183 { WPS_TOKEN_RTC_12HOUR_CFG
, "cf", WPS_RTC_REFRESH
, NULL
},
184 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
, "cH", WPS_RTC_REFRESH
, NULL
},
185 { WPS_TOKEN_RTC_HOUR_24
, "ck", WPS_RTC_REFRESH
, NULL
},
186 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
, "cI", WPS_RTC_REFRESH
, NULL
},
187 { WPS_TOKEN_RTC_HOUR_12
, "cl", WPS_RTC_REFRESH
, NULL
},
188 { WPS_TOKEN_RTC_MONTH
, "cm", WPS_RTC_REFRESH
, NULL
},
189 { WPS_TOKEN_RTC_MINUTE
, "cM", WPS_RTC_REFRESH
, NULL
},
190 { WPS_TOKEN_RTC_SECOND
, "cS", WPS_RTC_REFRESH
, NULL
},
191 { WPS_TOKEN_RTC_YEAR_2_DIGITS
, "cy", WPS_RTC_REFRESH
, NULL
},
192 { WPS_TOKEN_RTC_YEAR_4_DIGITS
, "cY", WPS_RTC_REFRESH
, NULL
},
193 { WPS_TOKEN_RTC_AM_PM_UPPER
, "cP", WPS_RTC_REFRESH
, NULL
},
194 { WPS_TOKEN_RTC_AM_PM_LOWER
, "cp", WPS_RTC_REFRESH
, NULL
},
195 { WPS_TOKEN_RTC_WEEKDAY_NAME
, "ca", WPS_RTC_REFRESH
, NULL
},
196 { WPS_TOKEN_RTC_MONTH_NAME
, "cb", WPS_RTC_REFRESH
, NULL
},
197 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
, "cu", WPS_RTC_REFRESH
, NULL
},
198 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
, "cw", WPS_RTC_REFRESH
, NULL
},
201 { WPS_TOKEN_FILE_BITRATE
, "fb", WPS_REFRESH_STATIC
, NULL
},
202 { WPS_TOKEN_FILE_CODEC
, "fc", WPS_REFRESH_STATIC
, NULL
},
203 { WPS_TOKEN_FILE_FREQUENCY
, "ff", WPS_REFRESH_STATIC
, NULL
},
204 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "fk", WPS_REFRESH_STATIC
, NULL
},
205 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "fm", WPS_REFRESH_STATIC
, NULL
},
206 { WPS_TOKEN_FILE_NAME
, "fn", WPS_REFRESH_STATIC
, NULL
},
207 { WPS_TOKEN_FILE_PATH
, "fp", WPS_REFRESH_STATIC
, NULL
},
208 { WPS_TOKEN_FILE_SIZE
, "fs", WPS_REFRESH_STATIC
, NULL
},
209 { WPS_TOKEN_FILE_VBR
, "fv", WPS_REFRESH_STATIC
, NULL
},
210 { WPS_TOKEN_FILE_DIRECTORY
, "d", WPS_REFRESH_STATIC
,
214 { WPS_TOKEN_FILE_BITRATE
, "Fb", WPS_REFRESH_DYNAMIC
, NULL
},
215 { WPS_TOKEN_FILE_CODEC
, "Fc", WPS_REFRESH_DYNAMIC
, NULL
},
216 { WPS_TOKEN_FILE_FREQUENCY
, "Ff", WPS_REFRESH_DYNAMIC
, NULL
},
217 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "Fk", WPS_REFRESH_DYNAMIC
, NULL
},
218 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "Fm", WPS_REFRESH_DYNAMIC
, NULL
},
219 { WPS_TOKEN_FILE_NAME
, "Fn", WPS_REFRESH_DYNAMIC
, NULL
},
220 { WPS_TOKEN_FILE_PATH
, "Fp", WPS_REFRESH_DYNAMIC
, NULL
},
221 { WPS_TOKEN_FILE_SIZE
, "Fs", WPS_REFRESH_DYNAMIC
, NULL
},
222 { WPS_TOKEN_FILE_VBR
, "Fv", WPS_REFRESH_DYNAMIC
, NULL
},
223 { WPS_TOKEN_FILE_DIRECTORY
, "D", WPS_REFRESH_DYNAMIC
,
226 /* current metadata */
227 { WPS_TOKEN_METADATA_ARTIST
, "ia", WPS_REFRESH_STATIC
, NULL
},
228 { WPS_TOKEN_METADATA_COMPOSER
, "ic", WPS_REFRESH_STATIC
, NULL
},
229 { WPS_TOKEN_METADATA_ALBUM
, "id", WPS_REFRESH_STATIC
, NULL
},
230 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "iA", WPS_REFRESH_STATIC
, NULL
},
231 { WPS_TOKEN_METADATA_GROUPING
, "iG", WPS_REFRESH_STATIC
, NULL
},
232 { WPS_TOKEN_METADATA_GENRE
, "ig", WPS_REFRESH_STATIC
, NULL
},
233 { WPS_TOKEN_METADATA_DISC_NUMBER
, "ik", WPS_REFRESH_STATIC
, NULL
},
234 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "in", WPS_REFRESH_STATIC
, NULL
},
235 { WPS_TOKEN_METADATA_TRACK_TITLE
, "it", WPS_REFRESH_STATIC
, NULL
},
236 { WPS_TOKEN_METADATA_VERSION
, "iv", WPS_REFRESH_STATIC
, NULL
},
237 { WPS_TOKEN_METADATA_YEAR
, "iy", WPS_REFRESH_STATIC
, NULL
},
238 { WPS_TOKEN_METADATA_COMMENT
, "iC", WPS_REFRESH_STATIC
, NULL
},
241 { WPS_TOKEN_METADATA_ARTIST
, "Ia", WPS_REFRESH_DYNAMIC
, NULL
},
242 { WPS_TOKEN_METADATA_COMPOSER
, "Ic", WPS_REFRESH_DYNAMIC
, NULL
},
243 { WPS_TOKEN_METADATA_ALBUM
, "Id", WPS_REFRESH_DYNAMIC
, NULL
},
244 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "IA", WPS_REFRESH_DYNAMIC
, NULL
},
245 { WPS_TOKEN_METADATA_GROUPING
, "IG", WPS_REFRESH_DYNAMIC
, NULL
},
246 { WPS_TOKEN_METADATA_GENRE
, "Ig", WPS_REFRESH_DYNAMIC
, NULL
},
247 { WPS_TOKEN_METADATA_DISC_NUMBER
, "Ik", WPS_REFRESH_DYNAMIC
, NULL
},
248 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "In", WPS_REFRESH_DYNAMIC
, NULL
},
249 { WPS_TOKEN_METADATA_TRACK_TITLE
, "It", WPS_REFRESH_DYNAMIC
, NULL
},
250 { WPS_TOKEN_METADATA_VERSION
, "Iv", WPS_REFRESH_DYNAMIC
, NULL
},
251 { WPS_TOKEN_METADATA_YEAR
, "Iy", WPS_REFRESH_DYNAMIC
, NULL
},
252 { WPS_TOKEN_METADATA_COMMENT
, "IC", WPS_REFRESH_DYNAMIC
, NULL
},
254 #if (CONFIG_CODEC != MAS3507D)
255 { WPS_TOKEN_SOUND_PITCH
, "Sp", WPS_REFRESH_DYNAMIC
, NULL
},
258 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
259 { WPS_TOKEN_VLED_HDD
, "lh", WPS_REFRESH_DYNAMIC
, NULL
},
262 { WPS_TOKEN_MAIN_HOLD
, "mh", WPS_REFRESH_DYNAMIC
, NULL
},
264 #ifdef HAS_REMOTE_BUTTON_HOLD
265 { WPS_TOKEN_REMOTE_HOLD
, "mr", WPS_REFRESH_DYNAMIC
, NULL
},
267 { WPS_TOKEN_UNKNOWN
, "mr", 0, NULL
},
270 { WPS_TOKEN_REPEAT_MODE
, "mm", WPS_REFRESH_DYNAMIC
, NULL
},
271 { WPS_TOKEN_PLAYBACK_STATUS
, "mp", WPS_REFRESH_DYNAMIC
, NULL
},
273 #ifdef HAVE_LCD_BITMAP
274 { WPS_TOKEN_PEAKMETER
, "pm", WPS_REFRESH_PEAK_METER
, NULL
},
276 { WPS_TOKEN_PLAYER_PROGRESSBAR
, "pf",
277 WPS_REFRESH_DYNAMIC
| WPS_REFRESH_PLAYER_PROGRESS
, parse_progressbar
},
279 { WPS_TOKEN_PROGRESSBAR
, "pb", WPS_REFRESH_PLAYER_PROGRESS
,
282 { WPS_TOKEN_VOLUME
, "pv", WPS_REFRESH_DYNAMIC
, NULL
},
284 { WPS_TOKEN_TRACK_ELAPSED_PERCENT
, "px", WPS_REFRESH_DYNAMIC
, NULL
},
285 { WPS_TOKEN_TRACK_TIME_ELAPSED
, "pc", WPS_REFRESH_DYNAMIC
, NULL
},
286 { WPS_TOKEN_TRACK_TIME_REMAINING
, "pr", WPS_REFRESH_DYNAMIC
, NULL
},
287 { WPS_TOKEN_TRACK_LENGTH
, "pt", WPS_REFRESH_STATIC
, NULL
},
289 { WPS_TOKEN_PLAYLIST_POSITION
, "pp", WPS_REFRESH_STATIC
, NULL
},
290 { WPS_TOKEN_PLAYLIST_ENTRIES
, "pe", WPS_REFRESH_STATIC
, NULL
},
291 { WPS_TOKEN_PLAYLIST_NAME
, "pn", WPS_REFRESH_STATIC
, NULL
},
292 { WPS_TOKEN_PLAYLIST_SHUFFLE
, "ps", WPS_REFRESH_DYNAMIC
, NULL
},
295 { WPS_TOKEN_DATABASE_PLAYCOUNT
, "rp", WPS_REFRESH_DYNAMIC
, NULL
},
296 { WPS_TOKEN_DATABASE_RATING
, "rr", WPS_REFRESH_DYNAMIC
, NULL
},
297 { WPS_TOKEN_DATABASE_AUTOSCORE
, "ra", WPS_REFRESH_DYNAMIC
, NULL
},
300 #if CONFIG_CODEC == SWCODEC
301 { WPS_TOKEN_REPLAYGAIN
, "rg", WPS_REFRESH_STATIC
, NULL
},
302 { WPS_TOKEN_CROSSFADE
, "xf", WPS_REFRESH_DYNAMIC
, NULL
},
305 { WPS_NO_TOKEN
, "s", WPS_REFRESH_SCROLL
, NULL
},
306 { WPS_TOKEN_SUBLINE_TIMEOUT
, "t", 0, parse_subline_timeout
},
308 #ifdef HAVE_LCD_BITMAP
309 { WPS_NO_TOKEN
, "we", 0, parse_statusbar_enable
},
310 { WPS_NO_TOKEN
, "wd", 0, parse_statusbar_disable
},
312 { WPS_NO_TOKEN
, "xl", 0, parse_image_load
},
314 { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
, "xd", WPS_REFRESH_STATIC
,
315 parse_image_display
},
317 { WPS_TOKEN_IMAGE_DISPLAY
, "x", 0, parse_image_load
},
319 { WPS_NO_TOKEN
, "Cl", 0, parse_albumart_load
},
320 { WPS_TOKEN_ALBUMART_DISPLAY
, "C", WPS_REFRESH_STATIC
,
321 parse_albumart_conditional
},
324 { WPS_VIEWPORT_ENABLE
, "Vd", WPS_REFRESH_DYNAMIC
,
325 parse_viewport_display
},
326 { WPS_NO_TOKEN
, "V", 0, parse_viewport
},
328 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
329 { WPS_TOKEN_IMAGE_BACKDROP
, "X", 0, parse_image_special
},
333 { WPS_TOKEN_UNKNOWN
, "", 0, NULL
}
334 /* the array MUST end with an empty string (first char is \0) */
337 /* Returns the number of chars that should be skipped to jump
338 immediately after the first eol, i.e. to the start of the next line */
339 static int skip_end_of_line(const char *wps_bufptr
)
343 while(*(wps_bufptr
+ skip
) != '\n')
348 /* Starts a new subline in the current line during parsing */
349 static void wps_start_new_subline(struct wps_data
*data
)
351 data
->num_sublines
++;
352 data
->sublines
[data
->num_sublines
].first_token_idx
= data
->num_tokens
;
353 data
->lines
[data
->num_lines
].num_sublines
++;
356 #ifdef HAVE_LCD_BITMAP
358 static int parse_statusbar_enable(const char *wps_bufptr
,
359 struct wps_token
*token
,
360 struct wps_data
*wps_data
)
362 (void)token
; /* Kill warnings */
363 wps_data
->wps_sb_tag
= true;
364 wps_data
->show_sb_on_wps
= true;
365 if (wps_data
->viewports
[0].vp
.y
== 0)
367 wps_data
->viewports
[0].vp
.y
= STATUSBAR_HEIGHT
;
368 wps_data
->viewports
[0].vp
.height
-= STATUSBAR_HEIGHT
;
370 return skip_end_of_line(wps_bufptr
);
373 static int parse_statusbar_disable(const char *wps_bufptr
,
374 struct wps_token
*token
,
375 struct wps_data
*wps_data
)
377 (void)token
; /* Kill warnings */
378 wps_data
->wps_sb_tag
= true;
379 wps_data
->show_sb_on_wps
= false;
380 if (wps_data
->viewports
[0].vp
.y
== STATUSBAR_HEIGHT
)
382 wps_data
->viewports
[0].vp
.y
= 0;
383 wps_data
->viewports
[0].vp
.height
+= STATUSBAR_HEIGHT
;
385 return skip_end_of_line(wps_bufptr
);
388 static bool load_bitmap(struct wps_data
*wps_data
,
393 #ifdef HAVE_REMOTE_LCD
394 if (wps_data
->remote_wps
)
395 format
= FORMAT_ANY
|FORMAT_REMOTE
;
398 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
400 int ret
= read_bmp_file(filename
, bm
,
401 wps_data
->img_buf_free
,
408 /* Always consume an even number of bytes */
410 wps_data
->img_buf_ptr
+= ret
;
411 wps_data
->img_buf_free
-= ret
;
419 static int get_image_id(int c
)
421 if(c
>= 'a' && c
<= 'z')
423 else if(c
>= 'A' && c
<= 'Z')
429 static char *get_image_filename(const char *start
, const char* bmpdir
,
430 char *buf
, int buf_size
)
432 const char *end
= strchr(start
, '|');
434 if ( !end
|| (end
- start
) >= (buf_size
- ROCKBOX_DIR_LEN
- 2) )
440 int bmpdirlen
= strlen(bmpdir
);
443 buf
[bmpdirlen
] = '/';
444 memcpy( &buf
[bmpdirlen
+ 1], start
, end
- start
);
445 buf
[bmpdirlen
+ 1 + end
- start
] = 0;
450 static int parse_image_display(const char *wps_bufptr
,
451 struct wps_token
*token
,
452 struct wps_data
*wps_data
)
455 int n
= get_image_id(wps_bufptr
[0]);
460 /* invalid picture display tag */
461 return WPS_ERROR_INVALID_PARAM
;
464 if ((subimage
= get_image_id(wps_bufptr
[1])) != -1)
467 if (subimage
>= wps_data
->img
[n
].num_subimages
)
468 return WPS_ERROR_INVALID_PARAM
;
470 /* Store sub-image number to display in high bits */
471 token
->value
.i
= n
| (subimage
<< 8);
472 return 2; /* We have consumed 2 bytes */
475 return 1; /* We have consumed 1 byte */
479 static int parse_image_load(const char *wps_bufptr
,
480 struct wps_token
*token
,
481 struct wps_data
*wps_data
)
484 const char *ptr
= wps_bufptr
;
486 const char* filename
;
491 /* format: %x|n|filename.bmp|x|y|
492 or %xl|n|filename.bmp|x|y|
493 or %xl|n|filename.bmp|x|y|num_subimages|
497 return WPS_ERROR_INVALID_PARAM
;
501 if (!(ptr
= parse_list("ssdd", NULL
, '|', ptr
, &id
, &filename
, &x
, &y
)))
502 return WPS_ERROR_INVALID_PARAM
;
504 /* Check there is a terminating | */
506 return WPS_ERROR_INVALID_PARAM
;
508 /* get the image ID */
509 n
= get_image_id(*id
);
511 /* check the image number and load state */
512 if(n
< 0 || n
>= MAX_IMAGES
|| wps_data
->img
[n
].loaded
)
514 /* Invalid image ID */
515 return WPS_ERROR_INVALID_PARAM
;
518 /* save a pointer to the filename */
519 bmp_names
[n
] = filename
;
521 wps_data
->img
[n
].x
= x
;
522 wps_data
->img
[n
].y
= y
;
524 /* save current viewport */
525 wps_data
->img
[n
].vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
527 if (token
->type
== WPS_TOKEN_IMAGE_DISPLAY
)
529 wps_data
->img
[n
].always_display
= true;
533 /* Parse the (optional) number of sub-images */
535 newline
= strchr(ptr
, '\n');
536 pos
= strchr(ptr
, '|');
537 if (pos
&& pos
< newline
)
538 wps_data
->img
[n
].num_subimages
= atoi(ptr
);
540 if (wps_data
->img
[n
].num_subimages
<= 0)
541 return WPS_ERROR_INVALID_PARAM
;
544 /* Skip the rest of the line */
545 return skip_end_of_line(wps_bufptr
);
548 static int parse_viewport_display(const char *wps_bufptr
,
549 struct wps_token
*token
,
550 struct wps_data
*wps_data
)
553 char letter
= wps_bufptr
[0];
555 if (letter
< 'a' || letter
> 'z')
557 /* invalid viewport tag */
558 return WPS_ERROR_INVALID_PARAM
;
560 token
->value
.i
= letter
;
564 static int parse_viewport(const char *wps_bufptr
,
565 struct wps_token
*token
,
566 struct wps_data
*wps_data
)
568 (void)token
; /* Kill warnings */
569 const char *ptr
= wps_bufptr
;
582 int lcd_width
= LCD_WIDTH
, lcd_height
= LCD_HEIGHT
;
583 #ifdef HAVE_REMOTE_LCD
584 if (wps_data
->remote_wps
)
586 lcd_width
= LCD_REMOTE_WIDTH
;
587 lcd_height
= LCD_REMOTE_HEIGHT
;
591 if (wps_data
->num_viewports
>= WPS_MAX_VIEWPORTS
)
592 return WPS_ERROR_INVALID_PARAM
;
594 wps_data
->num_viewports
++;
595 /* check for the optional letter to signify its a hideable viewport */
596 /* %Vl|<label>|<rest of tags>| */
597 wps_data
->viewports
[wps_data
->num_viewports
].hidden_flags
= 0;
603 char label
= *(ptr
+2);
604 if (label
>= 'a' && label
<= 'z')
606 wps_data
->viewports
[wps_data
->num_viewports
].hidden_flags
= VP_DRAW_HIDEABLE
;
607 wps_data
->viewports
[wps_data
->num_viewports
].label
= label
;
610 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
615 return WPS_ERROR_INVALID_PARAM
;
618 vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
619 /* format: %V|x|y|width|height|font|fg_pattern|bg_pattern| */
621 /* Set the defaults for fields not user-specified */
622 vp
->drawmode
= DRMODE_SOLID
;
624 /* Work out the depth of this display */
625 #ifdef HAVE_REMOTE_LCD
626 depth
= (wps_data
->remote_wps
? LCD_REMOTE_DEPTH
: LCD_DEPTH
);
631 #ifdef HAVE_LCD_COLOR
634 if (!(ptr
= parse_list("dddddcc", &set
, '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
635 &vp
->height
, &vp
->font
, &vp
->fg_pattern
,&vp
->bg_pattern
)))
636 return WPS_ERROR_INVALID_PARAM
;
640 #if (LCD_DEPTH == 2) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2)
642 /* Default to black on white */
645 if (!(ptr
= parse_list("dddddgg", &set
, '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
646 &vp
->height
, &vp
->font
, &vp
->fg_pattern
, &vp
->bg_pattern
)))
647 return WPS_ERROR_INVALID_PARAM
;
651 #if (LCD_DEPTH == 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 1)
654 if (!(ptr
= parse_list("ddddd", &set
, '|', ptr
, &vp
->x
, &vp
->y
,
655 &vp
->width
, &vp
->height
, &vp
->font
)))
656 return WPS_ERROR_INVALID_PARAM
;
662 /* Check for trailing | */
664 return WPS_ERROR_INVALID_PARAM
;
666 if (!LIST_VALUE_PARSED(set
, PL_X
) || !LIST_VALUE_PARSED(set
, PL_Y
))
667 return WPS_ERROR_INVALID_PARAM
;
670 if (!LIST_VALUE_PARSED(set
, PL_WIDTH
))
671 vp
->width
= lcd_width
- vp
->x
;
672 if (!LIST_VALUE_PARSED(set
, PL_HEIGHT
))
673 vp
->height
= lcd_height
- vp
->y
;
675 /* Default to using the user font if the font was an invalid number */
676 if (!LIST_VALUE_PARSED(set
, PL_FONT
) ||
677 ((vp
->font
!= FONT_SYSFIXED
) && (vp
->font
!= FONT_UI
)))
680 /* Validate the viewport dimensions - we know that the numbers are
681 non-negative integers */
682 if ((vp
->x
>= lcd_width
) ||
683 ((vp
->x
+ vp
->width
) > lcd_width
) ||
684 (vp
->y
>= lcd_height
) ||
685 ((vp
->y
+ vp
->height
) > lcd_height
))
687 return WPS_ERROR_INVALID_PARAM
;
690 #ifdef HAVE_LCD_COLOR
693 if (!LIST_VALUE_PARSED(set
, PL_FG
))
694 vp
->fg_pattern
= global_settings
.fg_color
;
695 if (!LIST_VALUE_PARSED(set
, PL_BG
))
696 vp
->bg_pattern
= global_settings
.bg_color
;
700 wps_data
->viewports
[wps_data
->num_viewports
-1].last_line
= wps_data
->num_lines
- 1;
702 wps_data
->viewports
[wps_data
->num_viewports
].first_line
= wps_data
->num_lines
;
704 if (wps_data
->num_sublines
< WPS_MAX_SUBLINES
)
706 wps_data
->lines
[wps_data
->num_lines
].first_subline_idx
=
707 wps_data
->num_sublines
;
709 wps_data
->sublines
[wps_data
->num_sublines
].first_token_idx
=
710 wps_data
->num_tokens
;
713 /* Skip the rest of the line */
714 return skip_end_of_line(wps_bufptr
);
718 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
719 static int parse_image_special(const char *wps_bufptr
,
720 struct wps_token
*token
,
721 struct wps_data
*wps_data
)
723 (void)wps_data
; /* kill warning */
725 const char *pos
= NULL
;
728 pos
= strchr(wps_bufptr
+ 1, '|');
729 newline
= strchr(wps_bufptr
, '\n');
732 return WPS_ERROR_INVALID_PARAM
;
734 if (token
->type
== WPS_TOKEN_IMAGE_BACKDROP
)
736 /* format: %X|filename.bmp| */
737 bmp_names
[BACKDROP_BMP
] = wps_bufptr
+ 1;
741 /* Skip the rest of the line */
742 return skip_end_of_line(wps_bufptr
);
746 #endif /* HAVE_LCD_BITMAP */
748 static int parse_dir_level(const char *wps_bufptr
,
749 struct wps_token
*token
,
750 struct wps_data
*wps_data
)
752 char val
[] = { *wps_bufptr
, '\0' };
753 token
->value
.i
= atoi(val
);
754 (void)wps_data
; /* Kill warnings */
758 static int parse_subline_timeout(const char *wps_bufptr
,
759 struct wps_token
*token
,
760 struct wps_data
*wps_data
)
764 bool have_point
= false;
765 bool have_tenth
= false;
767 (void)wps_data
; /* Kill the warning */
769 while ( isdigit(*wps_bufptr
) || *wps_bufptr
== '.' )
771 if (*wps_bufptr
!= '.')
774 val
+= *wps_bufptr
- '0';
790 if (have_tenth
== false)
793 token
->value
.i
= val
;
798 static int parse_progressbar(const char *wps_bufptr
,
799 struct wps_token
*token
,
800 struct wps_data
*wps_data
)
802 (void)token
; /* Kill warnings */
803 /* %pb or %pb|filename|x|y|width|height|
804 using - for any of the params uses "sane" values */
805 #ifdef HAVE_LCD_BITMAP
813 const char *filename
;
814 int x
, y
, height
, width
;
816 const char *ptr
= wps_bufptr
;
817 struct progressbar
*pb
;
818 struct viewport
*vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
819 int font_height
= font_get(vp
->font
)->height
;
820 int line_y_pos
= font_height
*(wps_data
->num_lines
-
821 wps_data
->viewports
[wps_data
->num_viewports
].first_line
);
823 if (wps_data
->progressbar_count
+1 >= MAX_PROGRESSBARS
)
824 return WPS_ERROR_INVALID_PARAM
;
826 pb
= &wps_data
->progressbar
[wps_data
->progressbar_count
];
827 pb
->have_bitmap_pb
= false;
829 if (*wps_bufptr
!= '|') /* regular old style */
832 pb
->width
= vp
->width
;
833 pb
->height
= SYSFONT_HEIGHT
-2;
834 pb
->y
= line_y_pos
+ (font_height
-pb
->height
)/2;
836 wps_data
->viewports
[wps_data
->num_viewports
].pb
=
837 &wps_data
->progressbar
[wps_data
->progressbar_count
];
838 wps_data
->progressbar_count
++;
841 ptr
= wps_bufptr
+ 1;
843 if (!(ptr
= parse_list("sdddd", &set
, '|', ptr
, &filename
,
844 &x
, &y
, &width
, &height
)))
845 return WPS_ERROR_INVALID_PARAM
;
846 if (LIST_VALUE_PARSED(set
, PB_FILENAME
)) /* filename */
847 bmp_names
[PROGRESSBAR_BMP
+wps_data
->progressbar_count
] = filename
;
848 if (LIST_VALUE_PARSED(set
, PB_X
)) /* x */
852 if (LIST_VALUE_PARSED(set
, PB_WIDTH
)) /* width */
855 pb
->width
= vp
->width
- pb
->x
;
856 if (LIST_VALUE_PARSED(set
, PB_HEIGHT
)) /* height, default to font height */
859 pb
->height
= font_height
;
860 if (LIST_VALUE_PARSED(set
, PB_Y
)) /* y */
863 pb
->y
= line_y_pos
+ (font_height
-pb
->height
)/2;
864 wps_data
->progressbar
[wps_data
->progressbar_count
].have_bitmap_pb
= false;
865 wps_data
->viewports
[wps_data
->num_viewports
].pb
=
866 &wps_data
->progressbar
[wps_data
->progressbar_count
];
867 wps_data
->progressbar_count
++;
868 /* Skip the rest of the line */
869 return skip_end_of_line(wps_bufptr
)-1;
872 if (*(wps_bufptr
-1) == 'f')
873 wps_data
->full_line_progressbar
= true;
875 wps_data
->full_line_progressbar
= false;
883 static int parse_albumart_load(const char *wps_bufptr
,
884 struct wps_token
*token
,
885 struct wps_data
*wps_data
)
887 const char *_pos
, *newline
;
889 const short xalign_mask
= WPS_ALBUMART_ALIGN_LEFT
|
890 WPS_ALBUMART_ALIGN_CENTER
|
891 WPS_ALBUMART_ALIGN_RIGHT
;
892 const short yalign_mask
= WPS_ALBUMART_ALIGN_TOP
|
893 WPS_ALBUMART_ALIGN_CENTER
|
894 WPS_ALBUMART_ALIGN_BOTTOM
;
896 (void)token
; /* silence warning */
898 /* reset albumart info in wps */
899 wps_data
->wps_uses_albumart
= WPS_ALBUMART_NONE
;
900 wps_data
->albumart_max_width
= -1;
901 wps_data
->albumart_max_height
= -1;
902 wps_data
->albumart_xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
903 wps_data
->albumart_yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
905 /* format: %Cl|x|y|[[l|c|r][d|i|s]mwidth]|[[t|c|b][d|i|s]mheight]| */
907 newline
= strchr(wps_bufptr
, '\n');
909 /* initial validation and parsing of x and y components */
910 if (*wps_bufptr
!= '|')
911 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
913 _pos
= wps_bufptr
+ 1;
915 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl|@ */
916 wps_data
->albumart_x
= atoi(_pos
);
918 _pos
= strchr(_pos
, '|');
919 if (!_pos
|| _pos
> newline
|| !isdigit(*(++_pos
)))
920 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl|7\n or %Cl|7|@ */
922 wps_data
->albumart_y
= atoi(_pos
);
924 _pos
= strchr(_pos
, '|');
925 if (!_pos
|| _pos
> newline
)
926 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no | after y coordinate
929 /* parsing width field */
933 /* apply each modifier in turn */
940 wps_data
->albumart_xalign
=
941 (wps_data
->albumart_xalign
& xalign_mask
) |
942 WPS_ALBUMART_ALIGN_LEFT
;
946 wps_data
->albumart_xalign
=
947 (wps_data
->albumart_xalign
& xalign_mask
) |
948 WPS_ALBUMART_ALIGN_CENTER
;
953 wps_data
->albumart_xalign
=
954 (wps_data
->albumart_xalign
& xalign_mask
) |
955 WPS_ALBUMART_ALIGN_RIGHT
;
959 wps_data
->albumart_xalign
|= WPS_ALBUMART_DECREASE
;
963 wps_data
->albumart_xalign
|= WPS_ALBUMART_INCREASE
;
967 wps_data
->albumart_xalign
|=
968 (WPS_ALBUMART_DECREASE
| WPS_ALBUMART_INCREASE
);
975 /* extract max width data */
978 if (!isdigit(*_pos
)) /* malformed token: e.g. %Cl|7|59|# */
979 return WPS_ERROR_INVALID_PARAM
;
981 wps_data
->albumart_max_width
= atoi(_pos
);
983 _pos
= strchr(_pos
, '|');
984 if (!_pos
|| _pos
> newline
)
985 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no | after width field
986 e.g. %Cl|7|59|200\n */
989 /* parsing height field */
993 /* apply each modifier in turn */
1000 wps_data
->albumart_yalign
=
1001 (wps_data
->albumart_yalign
& yalign_mask
) |
1002 WPS_ALBUMART_ALIGN_TOP
;
1006 wps_data
->albumart_yalign
=
1007 (wps_data
->albumart_yalign
& yalign_mask
) |
1008 WPS_ALBUMART_ALIGN_CENTER
;
1013 wps_data
->albumart_yalign
=
1014 (wps_data
->albumart_yalign
& yalign_mask
) |
1015 WPS_ALBUMART_ALIGN_BOTTOM
;
1019 wps_data
->albumart_yalign
|= WPS_ALBUMART_DECREASE
;
1023 wps_data
->albumart_yalign
|= WPS_ALBUMART_INCREASE
;
1027 wps_data
->albumart_yalign
|=
1028 (WPS_ALBUMART_DECREASE
| WPS_ALBUMART_INCREASE
);
1035 /* extract max height data */
1038 if (!isdigit(*_pos
))
1039 return WPS_ERROR_INVALID_PARAM
; /* malformed token e.g. %Cl|7|59|200|@ */
1041 wps_data
->albumart_max_height
= atoi(_pos
);
1043 _pos
= strchr(_pos
, '|');
1044 if (!_pos
|| _pos
> newline
)
1045 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no closing |
1046 e.g. %Cl|7|59|200|200\n */
1049 /* if we got here, we parsed everything ok .. ! */
1050 if (wps_data
->albumart_max_width
< 0)
1051 wps_data
->albumart_max_width
= 0;
1052 else if (wps_data
->albumart_max_width
> LCD_WIDTH
)
1053 wps_data
->albumart_max_width
= LCD_WIDTH
;
1055 if (wps_data
->albumart_max_height
< 0)
1056 wps_data
->albumart_max_height
= 0;
1057 else if (wps_data
->albumart_max_height
> LCD_HEIGHT
)
1058 wps_data
->albumart_max_height
= LCD_HEIGHT
;
1060 wps_data
->wps_uses_albumart
= WPS_ALBUMART_LOAD
;
1062 /* Skip the rest of the line */
1063 return skip_end_of_line(wps_bufptr
);
1066 static int parse_albumart_conditional(const char *wps_bufptr
,
1067 struct wps_token
*token
,
1068 struct wps_data
*wps_data
)
1070 struct wps_token
*prevtoken
= token
;
1072 if (wps_data
->num_tokens
>= 1 && prevtoken
->type
== WPS_TOKEN_CONDITIONAL
)
1074 /* This %C is part of a %?C construct.
1075 It's either %?C<blah> or %?Cn<blah> */
1076 token
->type
= WPS_TOKEN_ALBUMART_FOUND
;
1077 if (*wps_bufptr
== 'n' && *(wps_bufptr
+ 1) == '<')
1082 else if (*wps_bufptr
== '<')
1088 token
->type
= WPS_NO_TOKEN
;
1094 /* This %C tag is in a conditional construct. */
1095 wps_data
->albumart_cond_index
= condindex
[level
];
1099 #endif /* HAVE_ALBUMART */
1102 /* Parse a generic token from the given string. Return the length read */
1103 static int parse_token(const char *wps_bufptr
, struct wps_data
*wps_data
)
1105 int skip
= 0, taglen
= 0, ret
;
1106 struct wps_token
*token
= wps_data
->tokens
+ wps_data
->num_tokens
;
1107 const struct wps_tag
*tag
;
1118 /* escaped characters */
1119 token
->type
= WPS_TOKEN_CHARACTER
;
1120 token
->value
.c
= *wps_bufptr
;
1122 wps_data
->num_tokens
++;
1126 /* conditional tag */
1127 token
->type
= WPS_TOKEN_CONDITIONAL
;
1129 condindex
[level
] = wps_data
->num_tokens
;
1130 numoptions
[level
] = 1;
1131 wps_data
->num_tokens
++;
1132 ret
= parse_token(wps_bufptr
+ 1, wps_data
);
1133 if (ret
< 0) return ret
;
1138 /* find what tag we have */
1139 for (tag
= all_tags
;
1140 strncmp(wps_bufptr
, tag
->name
, strlen(tag
->name
)) != 0;
1143 taglen
= (tag
->type
!= WPS_TOKEN_UNKNOWN
) ? strlen(tag
->name
) : 2;
1144 token
->type
= tag
->type
;
1145 wps_data
->sublines
[wps_data
->num_sublines
].line_type
|=
1148 /* if the tag has a special parsing function, we call it */
1149 if (tag
->parse_func
)
1151 ret
= tag
->parse_func(wps_bufptr
+ taglen
, token
, wps_data
);
1152 if (ret
< 0) return ret
;
1156 /* Some tags we don't want to save as tokens */
1157 if (tag
->type
== WPS_NO_TOKEN
)
1160 /* tags that start with 'F', 'I' or 'D' are for the next file */
1161 if ( *(tag
->name
) == 'I' || *(tag
->name
) == 'F' ||
1162 *(tag
->name
) == 'D')
1165 wps_data
->num_tokens
++;
1174 data is the pointer to the structure where the parsed WPS should be stored.
1176 wps_bufptr points to the string containing the WPS tags */
1177 static bool wps_parse(struct wps_data
*data
, const char *wps_bufptr
)
1179 if (!data
|| !wps_bufptr
|| !*wps_bufptr
)
1182 char *stringbuf
= data
->string_buffer
;
1183 int stringbuf_used
= 0;
1189 while(*wps_bufptr
&& !fail
&& data
->num_tokens
< WPS_MAX_TOKENS
- 1
1190 && data
->num_viewports
< WPS_MAX_VIEWPORTS
1191 && data
->num_lines
< WPS_MAX_LINES
)
1193 switch(*wps_bufptr
++)
1198 if ((ret
= parse_token(wps_bufptr
, data
)) < 0)
1200 fail
= PARSE_FAIL_COND_INVALID_PARAM
;
1206 /* Alternating sublines separator */
1208 if (level
>= 0) /* there are unclosed conditionals */
1210 fail
= PARSE_FAIL_UNCLOSED_COND
;
1214 if (data
->num_sublines
+1 < WPS_MAX_SUBLINES
)
1215 wps_start_new_subline(data
);
1217 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1221 /* Conditional list start */
1223 if (data
->tokens
[data
->num_tokens
-2].type
!= WPS_TOKEN_CONDITIONAL
)
1225 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1229 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_START
;
1230 lastcond
[level
] = data
->num_tokens
++;
1233 /* Conditional list end */
1235 if (level
< 0) /* not in a conditional, invalid char */
1237 fail
= PARSE_FAIL_INVALID_CHAR
;
1241 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_END
;
1242 if (lastcond
[level
])
1243 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1246 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1250 lastcond
[level
] = 0;
1252 data
->tokens
[condindex
[level
]].value
.i
= numoptions
[level
];
1256 /* Conditional list option */
1258 if (level
< 0) /* not in a conditional, invalid char */
1260 fail
= PARSE_FAIL_INVALID_CHAR
;
1264 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_OPTION
;
1265 if (lastcond
[level
])
1266 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1269 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1273 lastcond
[level
] = data
->num_tokens
;
1274 numoptions
[level
]++;
1280 if (level
>= 0) /* there are unclosed conditionals */
1282 fail
= PARSE_FAIL_UNCLOSED_COND
;
1286 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1289 /* End of this line */
1291 if (level
>= 0) /* there are unclosed conditionals */
1293 fail
= PARSE_FAIL_UNCLOSED_COND
;
1298 wps_start_new_subline(data
);
1299 data
->num_lines
++; /* Start a new line */
1301 if ((data
->num_lines
< WPS_MAX_LINES
) &&
1302 (data
->num_sublines
< WPS_MAX_SUBLINES
))
1304 data
->lines
[data
->num_lines
].first_subline_idx
=
1307 data
->sublines
[data
->num_sublines
].first_token_idx
=
1316 unsigned int len
= 1;
1317 const char *string_start
= wps_bufptr
- 1;
1319 /* find the length of the string */
1320 while (*wps_bufptr
&& *wps_bufptr
!= '#' &&
1321 *wps_bufptr
!= '%' && *wps_bufptr
!= ';' &&
1322 *wps_bufptr
!= '<' && *wps_bufptr
!= '>' &&
1323 *wps_bufptr
!= '|' && *wps_bufptr
!= '\n')
1329 /* look if we already have that string */
1333 for (i
= 0, str
= data
->strings
, found
= false;
1334 i
< data
->num_strings
&&
1335 !(found
= (strlen(*str
) == len
&&
1336 strncmp(string_start
, *str
, len
) == 0));
1338 /* If a matching string is found, found is true and i is
1339 the index of the string. If not, found is false */
1341 /* If it's NOT a duplicate, do nothing if we already have
1342 too many unique strings */
1344 (stringbuf_used
< STRING_BUFFER_SIZE
- 1 &&
1345 data
->num_strings
< WPS_MAX_STRINGS
))
1352 if (stringbuf_used
+ len
> STRING_BUFFER_SIZE
- 1)
1353 len
= STRING_BUFFER_SIZE
- stringbuf_used
- 1;
1355 strncpy(stringbuf
, string_start
, len
);
1356 *(stringbuf
+ len
) = '\0';
1358 data
->strings
[data
->num_strings
] = stringbuf
;
1359 stringbuf
+= len
+ 1;
1360 stringbuf_used
+= len
+ 1;
1361 data
->tokens
[data
->num_tokens
].value
.i
=
1363 data
->num_strings
++;
1367 /* another ocurrence of an existing string */
1368 data
->tokens
[data
->num_tokens
].value
.i
= i
;
1370 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_STRING
;
1378 if (!fail
&& level
>= 0) /* there are unclosed conditionals */
1379 fail
= PARSE_FAIL_UNCLOSED_COND
;
1381 data
->viewports
[data
->num_viewports
].last_line
= data
->num_lines
- 1;
1383 /* We have finished with the last viewport, so increment count */
1384 data
->num_viewports
++;
1387 print_debug_info(data
, fail
, line
);
1393 #ifdef HAVE_LCD_BITMAP
1394 /* Clear the WPS image cache */
1395 static void wps_images_clear(struct wps_data
*data
)
1398 /* set images to unloaded and not displayed */
1399 for (i
= 0; i
< MAX_IMAGES
; i
++)
1401 data
->img
[i
].loaded
= false;
1402 data
->img
[i
].display
= -1;
1403 data
->img
[i
].always_display
= false;
1404 data
->img
[i
].num_subimages
= 1;
1409 /* initial setup of wps_data */
1410 void wps_data_init(struct wps_data
*wps_data
)
1412 #ifdef HAVE_LCD_BITMAP
1413 wps_images_clear(wps_data
);
1414 wps_data
->wps_sb_tag
= false;
1415 wps_data
->show_sb_on_wps
= false;
1416 wps_data
->img_buf_ptr
= wps_data
->img_buf
; /* where in image buffer */
1417 wps_data
->img_buf_free
= IMG_BUFSIZE
; /* free space in image buffer */
1418 wps_data
->peak_meter_enabled
= false;
1420 wps_data
->progressbar_count
= 0;
1421 #else /* HAVE_LCD_CHARCELLS */
1423 for (i
= 0; i
< 8; i
++)
1425 wps_data
->wps_progress_pat
[i
] = 0;
1427 wps_data
->full_line_progressbar
= false;
1429 wps_data
->wps_loaded
= false;
1432 static void wps_reset(struct wps_data
*data
)
1434 #ifdef HAVE_REMOTE_LCD
1435 bool rwps
= data
->remote_wps
; /* remember whether the data is for a RWPS */
1437 memset(data
, 0, sizeof(*data
));
1438 #ifdef HAVE_ALBUMART
1439 data
->wps_uses_albumart
= WPS_ALBUMART_NONE
;
1441 wps_data_init(data
);
1442 #ifdef HAVE_REMOTE_LCD
1443 data
->remote_wps
= rwps
;
1447 #ifdef HAVE_LCD_BITMAP
1449 static bool load_wps_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
1451 char img_path
[MAX_PATH
];
1452 struct bitmap
*bitmap
;
1455 for (n
= 0; n
< BACKDROP_BMP
; n
++)
1459 get_image_filename(bmp_names
[n
], bmpdir
,
1460 img_path
, sizeof(img_path
));
1462 if (n
>= PROGRESSBAR_BMP
) {
1463 /* progressbar bitmap */
1464 bitmap
= &wps_data
->progressbar
[n
-PROGRESSBAR_BMP
].bm
;
1465 loaded
= &wps_data
->progressbar
[n
-PROGRESSBAR_BMP
].have_bitmap_pb
;
1467 /* regular bitmap */
1468 bitmap
= &wps_data
->img
[n
].bm
;
1469 loaded
= &wps_data
->img
[n
].loaded
;
1472 /* load the image */
1473 bitmap
->data
= wps_data
->img_buf_ptr
;
1474 if (load_bitmap(wps_data
, img_path
, bitmap
))
1478 /* Calculate and store height if this image has sub-images */
1480 wps_data
->img
[n
].subimage_height
= wps_data
->img
[n
].bm
.height
/
1481 wps_data
->img
[n
].num_subimages
;
1485 /* Abort if we can't load an image */
1486 DEBUGF("ERR: Failed to load image %d - %s\n",n
,img_path
);
1492 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1493 if (bmp_names
[BACKDROP_BMP
])
1495 get_image_filename(bmp_names
[BACKDROP_BMP
], bmpdir
,
1496 img_path
, sizeof(img_path
));
1498 #if defined(HAVE_REMOTE_LCD)
1499 /* We only need to check LCD type if there is a remote LCD */
1500 if (!wps_data
->remote_wps
)
1503 /* Load backdrop for the main LCD */
1504 if (!load_wps_backdrop(img_path
))
1507 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1510 /* Load backdrop for the remote LCD */
1511 if (!load_remote_wps_backdrop(img_path
))
1516 #endif /* has backdrop support */
1518 /* If we got here, everything was OK */
1522 #endif /* HAVE_LCD_BITMAP */
1524 /* Skip leading UTF-8 BOM, if present. */
1525 static char *skip_utf8_bom(char *buf
)
1527 unsigned char *s
= (unsigned char *)buf
;
1529 if(s
[0] == 0xef && s
[1] == 0xbb && s
[2] == 0xbf)
1537 /* to setup up the wps-data from a format-buffer (isfile = false)
1538 from a (wps-)file (isfile = true)*/
1539 bool wps_data_load(struct wps_data
*wps_data
,
1540 struct screen
*display
,
1544 if (!wps_data
|| !buf
)
1547 wps_reset(wps_data
);
1549 /* Initialise the first (default) viewport */
1550 wps_data
->viewports
[0].vp
.x
= 0;
1551 wps_data
->viewports
[0].vp
.width
= display
->width
;
1552 if (!global_settings
.statusbar
)
1554 wps_data
->viewports
[0].vp
.y
= 0;
1555 wps_data
->viewports
[0].vp
.height
= display
->height
;
1559 wps_data
->viewports
[0].vp
.y
= STATUSBAR_HEIGHT
;
1560 wps_data
->viewports
[0].vp
.height
= display
->height
- STATUSBAR_HEIGHT
;
1562 #ifdef HAVE_LCD_BITMAP
1563 wps_data
->viewports
[0].vp
.font
= FONT_UI
;
1564 wps_data
->viewports
[0].vp
.drawmode
= DRMODE_SOLID
;
1567 if (display
->depth
> 1)
1569 wps_data
->viewports
[0].vp
.fg_pattern
= display
->get_foreground();
1570 wps_data
->viewports
[0].vp
.bg_pattern
= display
->get_background();
1575 return wps_parse(wps_data
, buf
);
1580 * Hardcode loading WPS_DEFAULTCFG to cause a reset ideally this
1581 * wants to be a virtual file. Feel free to modify dirbrowse()
1582 * if you're feeling brave.
1585 if (! strcmp(buf
, WPS_DEFAULTCFG
) )
1587 global_settings
.wps_file
[0] = 0;
1591 #ifdef HAVE_REMOTE_LCD
1592 if (! strcmp(buf
, RWPS_DEFAULTCFG
) )
1594 global_settings
.rwps_file
[0] = 0;
1598 #endif /* __PCTOOL__ */
1600 int fd
= open(buf
, O_RDONLY
);
1605 /* get buffer space from the plugin buffer */
1606 size_t buffersize
= 0;
1607 char *wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
1612 /* copy the file's content to the buffer for parsing,
1613 ensuring that every line ends with a newline char. */
1614 unsigned int start
= 0;
1615 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
1617 start
+= strlen(wps_buffer
+ start
);
1618 if (start
< buffersize
- 1)
1620 wps_buffer
[start
++] = '\n';
1621 wps_buffer
[start
] = 0;
1630 #ifdef HAVE_LCD_BITMAP
1631 /* Set all filename pointers to NULL */
1632 memset(bmp_names
, 0, sizeof(bmp_names
));
1635 /* Skip leading UTF-8 BOM, if present. */
1636 wps_buffer
= skip_utf8_bom(wps_buffer
);
1638 /* parse the WPS source */
1639 if (!wps_parse(wps_data
, wps_buffer
)) {
1640 wps_reset(wps_data
);
1644 wps_data
->wps_loaded
= true;
1646 #ifdef HAVE_LCD_BITMAP
1647 /* get the bitmap dir */
1648 char bmpdir
[MAX_PATH
];
1650 char *dot
= strrchr(buf
, '.');
1651 bmpdirlen
= dot
- buf
;
1652 strncpy(bmpdir
, buf
, dot
- buf
);
1653 bmpdir
[bmpdirlen
] = 0;
1655 /* load the bitmaps that were found by the parsing */
1656 if (!load_wps_bitmaps(wps_data
, bmpdir
)) {
1657 wps_reset(wps_data
);
1665 int wps_subline_index(struct wps_data
*data
, int line
, int subline
)
1667 return data
->lines
[line
].first_subline_idx
+ subline
;
1670 int wps_first_token_index(struct wps_data
*data
, int line
, int subline
)
1672 int first_subline_idx
= data
->lines
[line
].first_subline_idx
;
1673 return data
->sublines
[first_subline_idx
+ subline
].first_token_idx
;
1676 int wps_last_token_index(struct wps_data
*data
, int line
, int subline
)
1678 int first_subline_idx
= data
->lines
[line
].first_subline_idx
;
1679 int idx
= first_subline_idx
+ subline
;
1680 if (idx
< data
->num_sublines
- 1)
1682 /* This subline ends where the next begins */
1683 return data
->sublines
[idx
+1].first_token_idx
- 1;
1687 /* The last subline goes to the end */
1688 return data
->num_tokens
- 1;