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 ****************************************************************************/
27 #define FONT_SYSFIXED 0
46 #ifdef HAVE_LCD_BITMAP
50 #if (LCD_DEPTH > 1) || (defined(HAVE_LCD_REMOTE) && (LCD_REMOTE_DEPTH > 1))
56 #define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps"
57 #define RWPS_DEFAULTCFG WPS_DIR "/rockbox_default.rwps"
59 #define WPS_ERROR_INVALID_PARAM -1
61 #define PARSE_FAIL_UNCLOSED_COND 1
62 #define PARSE_FAIL_INVALID_CHAR 2
63 #define PARSE_FAIL_COND_SYNTAX_ERROR 3
64 #define PARSE_FAIL_COND_INVALID_PARAM 4
66 /* level of current conditional.
67 -1 means we're not in a conditional. */
68 static int level
= -1;
70 /* index of the last WPS_TOKEN_CONDITIONAL_OPTION
71 or WPS_TOKEN_CONDITIONAL_START in current level */
72 static int lastcond
[WPS_MAX_COND_LEVEL
];
74 /* index of the WPS_TOKEN_CONDITIONAL in current level */
75 static int condindex
[WPS_MAX_COND_LEVEL
];
77 /* number of condtional options in current level */
78 static int numoptions
[WPS_MAX_COND_LEVEL
];
80 /* the current line in the file */
83 #ifdef HAVE_LCD_BITMAP
86 #define MAX_BITMAPS (MAX_IMAGES+2) /* WPS images + pbar bitmap + backdrop */
88 #define MAX_BITMAPS (MAX_IMAGES+1) /* WPS images + pbar bitmap */
91 #define PROGRESSBAR_BMP MAX_IMAGES
92 #define BACKDROP_BMP (MAX_IMAGES+1)
94 /* pointers to the bitmap filenames in the WPS source */
95 static const char *bmp_names
[MAX_BITMAPS
];
97 #endif /* HAVE_LCD_BITMAP */
100 /* debugging function */
101 extern void print_debug_info(struct wps_data
*data
, int fail
, int line
);
104 static void wps_reset(struct wps_data
*data
);
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
;
126 /* prototypes of all special parse functions : */
127 static int parse_subline_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
);
134 #ifdef HAVE_LCD_BITMAP
135 static int parse_viewport(const char *wps_bufptr
,
136 struct wps_token
*token
, struct wps_data
*wps_data
);
137 static int parse_leftmargin(const char *wps_bufptr
,
138 struct wps_token
*token
, struct wps_data
*wps_data
);
139 static int parse_image_special(const char *wps_bufptr
,
140 struct wps_token
*token
, struct wps_data
*wps_data
);
141 static int parse_statusbar_enable(const char *wps_bufptr
,
142 struct wps_token
*token
, struct wps_data
*wps_data
);
143 static int parse_statusbar_disable(const char *wps_bufptr
,
144 struct wps_token
*token
, struct wps_data
*wps_data
);
145 static int parse_image_display(const char *wps_bufptr
,
146 struct wps_token
*token
, struct wps_data
*wps_data
);
147 static int parse_image_load(const char *wps_bufptr
,
148 struct wps_token
*token
, struct wps_data
*wps_data
);
149 #endif /*HAVE_LCD_BITMAP */
151 static int parse_albumart_load(const char *wps_bufptr
,
152 struct wps_token
*token
, struct wps_data
*wps_data
);
153 static int parse_albumart_conditional(const char *wps_bufptr
,
154 struct wps_token
*token
, struct wps_data
*wps_data
);
155 #endif /* HAVE_ALBUMART */
158 #define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
160 #define WPS_RTC_REFRESH WPS_REFRESH_STATIC
163 /* array of available tags - those with more characters have to go first
164 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
165 static const struct wps_tag all_tags
[] = {
167 { WPS_TOKEN_ALIGN_CENTER
, "ac", 0, NULL
},
168 { WPS_TOKEN_ALIGN_LEFT
, "al", 0, NULL
},
169 { WPS_TOKEN_ALIGN_RIGHT
, "ar", 0, NULL
},
171 { WPS_TOKEN_BATTERY_PERCENT
, "bl", WPS_REFRESH_DYNAMIC
, NULL
},
172 { WPS_TOKEN_BATTERY_VOLTS
, "bv", WPS_REFRESH_DYNAMIC
, NULL
},
173 { WPS_TOKEN_BATTERY_TIME
, "bt", WPS_REFRESH_DYNAMIC
, NULL
},
174 { WPS_TOKEN_BATTERY_SLEEPTIME
, "bs", WPS_REFRESH_DYNAMIC
, NULL
},
175 #if CONFIG_CHARGING >= CHARGING_MONITOR
176 { WPS_TOKEN_BATTERY_CHARGING
, "bc", WPS_REFRESH_DYNAMIC
, NULL
},
179 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED
,"bp", WPS_REFRESH_DYNAMIC
, NULL
},
182 { WPS_TOKEN_RTC_DAY_OF_MONTH
, "cd", WPS_RTC_REFRESH
, NULL
},
183 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
,"ce", WPS_RTC_REFRESH
, NULL
},
184 { WPS_TOKEN_RTC_12HOUR_CFG
, "cf", WPS_RTC_REFRESH
, NULL
},
185 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
, "cH", WPS_RTC_REFRESH
, NULL
},
186 { WPS_TOKEN_RTC_HOUR_24
, "ck", WPS_RTC_REFRESH
, NULL
},
187 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
, "cI", WPS_RTC_REFRESH
, NULL
},
188 { WPS_TOKEN_RTC_HOUR_12
, "cl", WPS_RTC_REFRESH
, NULL
},
189 { WPS_TOKEN_RTC_MONTH
, "cm", WPS_RTC_REFRESH
, NULL
},
190 { WPS_TOKEN_RTC_MINUTE
, "cM", WPS_RTC_REFRESH
, NULL
},
191 { WPS_TOKEN_RTC_SECOND
, "cS", WPS_RTC_REFRESH
, NULL
},
192 { WPS_TOKEN_RTC_YEAR_2_DIGITS
, "cy", WPS_RTC_REFRESH
, NULL
},
193 { WPS_TOKEN_RTC_YEAR_4_DIGITS
, "cY", WPS_RTC_REFRESH
, NULL
},
194 { WPS_TOKEN_RTC_AM_PM_UPPER
, "cP", WPS_RTC_REFRESH
, NULL
},
195 { WPS_TOKEN_RTC_AM_PM_LOWER
, "cp", WPS_RTC_REFRESH
, NULL
},
196 { WPS_TOKEN_RTC_WEEKDAY_NAME
, "ca", WPS_RTC_REFRESH
, NULL
},
197 { WPS_TOKEN_RTC_MONTH_NAME
, "cb", WPS_RTC_REFRESH
, NULL
},
198 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
, "cu", WPS_RTC_REFRESH
, NULL
},
199 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
, "cw", WPS_RTC_REFRESH
, NULL
},
202 { WPS_TOKEN_FILE_BITRATE
, "fb", WPS_REFRESH_STATIC
, NULL
},
203 { WPS_TOKEN_FILE_CODEC
, "fc", WPS_REFRESH_STATIC
, NULL
},
204 { WPS_TOKEN_FILE_FREQUENCY
, "ff", WPS_REFRESH_STATIC
, NULL
},
205 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "fk", WPS_REFRESH_STATIC
, NULL
},
206 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "fm", WPS_REFRESH_STATIC
, NULL
},
207 { WPS_TOKEN_FILE_NAME
, "fn", WPS_REFRESH_STATIC
, NULL
},
208 { WPS_TOKEN_FILE_PATH
, "fp", WPS_REFRESH_STATIC
, NULL
},
209 { WPS_TOKEN_FILE_SIZE
, "fs", WPS_REFRESH_STATIC
, NULL
},
210 { WPS_TOKEN_FILE_VBR
, "fv", WPS_REFRESH_STATIC
, NULL
},
211 { WPS_TOKEN_FILE_DIRECTORY
, "d", WPS_REFRESH_STATIC
,
215 { WPS_TOKEN_FILE_BITRATE
, "Fb", WPS_REFRESH_DYNAMIC
, NULL
},
216 { WPS_TOKEN_FILE_CODEC
, "Fc", WPS_REFRESH_DYNAMIC
, NULL
},
217 { WPS_TOKEN_FILE_FREQUENCY
, "Ff", WPS_REFRESH_DYNAMIC
, NULL
},
218 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "Fk", WPS_REFRESH_DYNAMIC
, NULL
},
219 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "Fm", WPS_REFRESH_DYNAMIC
, NULL
},
220 { WPS_TOKEN_FILE_NAME
, "Fn", WPS_REFRESH_DYNAMIC
, NULL
},
221 { WPS_TOKEN_FILE_PATH
, "Fp", WPS_REFRESH_DYNAMIC
, NULL
},
222 { WPS_TOKEN_FILE_SIZE
, "Fs", WPS_REFRESH_DYNAMIC
, NULL
},
223 { WPS_TOKEN_FILE_VBR
, "Fv", WPS_REFRESH_DYNAMIC
, NULL
},
224 { WPS_TOKEN_FILE_DIRECTORY
, "D", WPS_REFRESH_DYNAMIC
,
227 /* current metadata */
228 { WPS_TOKEN_METADATA_ARTIST
, "ia", WPS_REFRESH_STATIC
, NULL
},
229 { WPS_TOKEN_METADATA_COMPOSER
, "ic", WPS_REFRESH_STATIC
, NULL
},
230 { WPS_TOKEN_METADATA_ALBUM
, "id", WPS_REFRESH_STATIC
, NULL
},
231 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "iA", WPS_REFRESH_STATIC
, NULL
},
232 { WPS_TOKEN_METADATA_GROUPING
, "iG", WPS_REFRESH_STATIC
, NULL
},
233 { WPS_TOKEN_METADATA_GENRE
, "ig", WPS_REFRESH_STATIC
, NULL
},
234 { WPS_TOKEN_METADATA_DISC_NUMBER
, "ik", WPS_REFRESH_STATIC
, NULL
},
235 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "in", WPS_REFRESH_STATIC
, NULL
},
236 { WPS_TOKEN_METADATA_TRACK_TITLE
, "it", WPS_REFRESH_STATIC
, NULL
},
237 { WPS_TOKEN_METADATA_VERSION
, "iv", WPS_REFRESH_STATIC
, NULL
},
238 { WPS_TOKEN_METADATA_YEAR
, "iy", WPS_REFRESH_STATIC
, NULL
},
239 { WPS_TOKEN_METADATA_COMMENT
, "iC", WPS_REFRESH_STATIC
, NULL
},
242 { WPS_TOKEN_METADATA_ARTIST
, "Ia", WPS_REFRESH_DYNAMIC
, NULL
},
243 { WPS_TOKEN_METADATA_COMPOSER
, "Ic", WPS_REFRESH_DYNAMIC
, NULL
},
244 { WPS_TOKEN_METADATA_ALBUM
, "Id", WPS_REFRESH_DYNAMIC
, NULL
},
245 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "IA", WPS_REFRESH_DYNAMIC
, NULL
},
246 { WPS_TOKEN_METADATA_GROUPING
, "IG", WPS_REFRESH_DYNAMIC
, NULL
},
247 { WPS_TOKEN_METADATA_GENRE
, "Ig", WPS_REFRESH_DYNAMIC
, NULL
},
248 { WPS_TOKEN_METADATA_DISC_NUMBER
, "Ik", WPS_REFRESH_DYNAMIC
, NULL
},
249 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "In", WPS_REFRESH_DYNAMIC
, NULL
},
250 { WPS_TOKEN_METADATA_TRACK_TITLE
, "It", WPS_REFRESH_DYNAMIC
, NULL
},
251 { WPS_TOKEN_METADATA_VERSION
, "Iv", WPS_REFRESH_DYNAMIC
, NULL
},
252 { WPS_TOKEN_METADATA_YEAR
, "Iy", WPS_REFRESH_DYNAMIC
, NULL
},
253 { WPS_TOKEN_METADATA_COMMENT
, "IC", WPS_REFRESH_DYNAMIC
, NULL
},
255 #if (CONFIG_CODEC != MAS3507D)
256 { WPS_TOKEN_SOUND_PITCH
, "Sp", WPS_REFRESH_DYNAMIC
, NULL
},
259 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
260 { WPS_TOKEN_VLED_HDD
, "lh", WPS_REFRESH_DYNAMIC
, NULL
},
263 { WPS_TOKEN_MAIN_HOLD
, "mh", WPS_REFRESH_DYNAMIC
, NULL
},
265 #ifdef HAS_REMOTE_BUTTON_HOLD
266 { WPS_TOKEN_REMOTE_HOLD
, "mr", WPS_REFRESH_DYNAMIC
, NULL
},
268 { WPS_TOKEN_UNKNOWN
, "mr", 0, NULL
},
271 { WPS_TOKEN_REPEAT_MODE
, "mm", WPS_REFRESH_DYNAMIC
, NULL
},
272 { WPS_TOKEN_PLAYBACK_STATUS
, "mp", WPS_REFRESH_DYNAMIC
, NULL
},
274 #ifdef HAVE_LCD_BITMAP
275 { WPS_TOKEN_LEFTMARGIN
, "m", 0, parse_leftmargin
},
278 #ifdef HAVE_LCD_BITMAP
279 { WPS_TOKEN_PEAKMETER
, "pm", WPS_REFRESH_PEAK_METER
, NULL
},
281 { WPS_TOKEN_PLAYER_PROGRESSBAR
, "pf",
282 WPS_REFRESH_DYNAMIC
| WPS_REFRESH_PLAYER_PROGRESS
, parse_progressbar
},
284 { WPS_TOKEN_PROGRESSBAR
, "pb", WPS_REFRESH_PLAYER_PROGRESS
,
287 { WPS_TOKEN_VOLUME
, "pv", WPS_REFRESH_DYNAMIC
, NULL
},
289 { WPS_TOKEN_TRACK_ELAPSED_PERCENT
, "px", WPS_REFRESH_DYNAMIC
, NULL
},
290 { WPS_TOKEN_TRACK_TIME_ELAPSED
, "pc", WPS_REFRESH_DYNAMIC
, NULL
},
291 { WPS_TOKEN_TRACK_TIME_REMAINING
, "pr", WPS_REFRESH_DYNAMIC
, NULL
},
292 { WPS_TOKEN_TRACK_LENGTH
, "pt", WPS_REFRESH_STATIC
, NULL
},
294 { WPS_TOKEN_PLAYLIST_POSITION
, "pp", WPS_REFRESH_STATIC
, NULL
},
295 { WPS_TOKEN_PLAYLIST_ENTRIES
, "pe", WPS_REFRESH_STATIC
, NULL
},
296 { WPS_TOKEN_PLAYLIST_NAME
, "pn", WPS_REFRESH_STATIC
, NULL
},
297 { WPS_TOKEN_PLAYLIST_SHUFFLE
, "ps", WPS_REFRESH_DYNAMIC
, NULL
},
300 { WPS_TOKEN_DATABASE_PLAYCOUNT
, "rp", WPS_REFRESH_DYNAMIC
, NULL
},
301 { WPS_TOKEN_DATABASE_RATING
, "rr", WPS_REFRESH_DYNAMIC
, NULL
},
302 { WPS_TOKEN_DATABASE_AUTOSCORE
, "ra", WPS_REFRESH_DYNAMIC
, NULL
},
305 #if CONFIG_CODEC == SWCODEC
306 { WPS_TOKEN_REPLAYGAIN
, "rg", WPS_REFRESH_STATIC
, NULL
},
307 { WPS_TOKEN_CROSSFADE
, "xf", WPS_REFRESH_DYNAMIC
, NULL
},
310 { WPS_NO_TOKEN
, "s", WPS_REFRESH_SCROLL
, NULL
},
311 { WPS_TOKEN_SUBLINE_TIMEOUT
, "t", 0, parse_subline_timeout
},
313 #ifdef HAVE_LCD_BITMAP
314 { WPS_NO_TOKEN
, "we", 0, parse_statusbar_enable
},
315 { WPS_NO_TOKEN
, "wd", 0, parse_statusbar_disable
},
317 { WPS_NO_TOKEN
, "xl", 0, parse_image_load
},
319 { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
, "xd", WPS_REFRESH_STATIC
,
320 parse_image_display
},
322 { WPS_TOKEN_IMAGE_DISPLAY
, "x", 0, parse_image_load
},
323 { WPS_TOKEN_IMAGE_PROGRESS_BAR
, "P", 0, parse_image_special
},
325 { WPS_NO_TOKEN
, "Cl", 0, parse_albumart_load
},
326 { WPS_TOKEN_ALBUMART_DISPLAY
, "C", WPS_REFRESH_STATIC
,
327 parse_albumart_conditional
},
330 { WPS_NO_TOKEN
, "V", 0, parse_viewport
},
332 #if (LCD_DEPTH > 1) || (defined(HAVE_LCD_REMOTE) && (LCD_REMOTE_DEPTH > 1))
333 { WPS_TOKEN_IMAGE_BACKDROP
, "X", 0, parse_image_special
},
337 { WPS_TOKEN_UNKNOWN
, "", 0, NULL
}
338 /* the array MUST end with an empty string (first char is \0) */
341 /* Returns the number of chars that should be skipped to jump
342 immediately after the first eol, i.e. to the start of the next line */
343 static int skip_end_of_line(const char *wps_bufptr
)
347 while(*(wps_bufptr
+ skip
) != '\n')
352 /* Starts a new subline in the current line during parsing */
353 static void wps_start_new_subline(struct wps_data
*data
)
355 data
->num_sublines
++;
356 data
->sublines
[data
->num_sublines
].first_token_idx
= data
->num_tokens
;
357 data
->lines
[data
->num_lines
].num_sublines
++;
360 #ifdef HAVE_LCD_BITMAP
362 static int parse_statusbar_enable(const char *wps_bufptr
,
363 struct wps_token
*token
,
364 struct wps_data
*wps_data
)
366 (void)token
; /* Kill warnings */
367 wps_data
->wps_sb_tag
= true;
368 wps_data
->show_sb_on_wps
= true;
369 return skip_end_of_line(wps_bufptr
);
372 static int parse_statusbar_disable(const char *wps_bufptr
,
373 struct wps_token
*token
,
374 struct wps_data
*wps_data
)
376 (void)token
; /* Kill warnings */
377 wps_data
->wps_sb_tag
= true;
378 wps_data
->show_sb_on_wps
= false;
379 return skip_end_of_line(wps_bufptr
);
382 static bool load_bitmap(struct wps_data
*wps_data
,
387 #ifdef HAVE_REMOTE_LCD
388 if (wps_data
->remote_wps
)
389 format
= FORMAT_ANY
|FORMAT_REMOTE
;
392 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
394 int ret
= read_bmp_file(filename
, bm
,
395 wps_data
->img_buf_free
,
402 /* Always consume an even number of bytes */
404 wps_data
->img_buf_ptr
+= ret
;
405 wps_data
->img_buf_free
-= ret
;
413 static int get_image_id(int c
)
415 if(c
>= 'a' && c
<= 'z')
417 else if(c
>= 'A' && c
<= 'Z')
423 static char *get_image_filename(const char *start
, const char* bmpdir
,
424 char *buf
, int buf_size
)
426 const char *end
= strchr(start
, '|');
428 if ( !end
|| (end
- start
) >= (buf_size
- ROCKBOX_DIR_LEN
- 2) )
434 int bmpdirlen
= strlen(bmpdir
);
437 buf
[bmpdirlen
] = '/';
438 memcpy( &buf
[bmpdirlen
+ 1], start
, end
- start
);
439 buf
[bmpdirlen
+ 1 + end
- start
] = 0;
444 static int parse_image_display(const char *wps_bufptr
,
445 struct wps_token
*token
,
446 struct wps_data
*wps_data
)
449 int n
= get_image_id(wps_bufptr
[0]);
454 /* invalid picture display tag */
455 return WPS_ERROR_INVALID_PARAM
;
458 if ((subimage
= get_image_id(wps_bufptr
[1])) != -1)
461 if (subimage
>= wps_data
->img
[n
].num_subimages
)
462 return WPS_ERROR_INVALID_PARAM
;
464 /* Store sub-image number to display in high bits */
465 token
->value
.i
= n
| (subimage
<< 8);
466 return 2; /* We have consumed 2 bytes */
469 return 1; /* We have consumed 1 byte */
473 static int parse_image_load(const char *wps_bufptr
,
474 struct wps_token
*token
,
475 struct wps_data
*wps_data
)
478 const char *ptr
= wps_bufptr
;
480 const char* filename
;
485 /* format: %x|n|filename.bmp|x|y|
486 or %xl|n|filename.bmp|x|y|
487 or %xl|n|filename.bmp|x|y|num_subimages|
491 return WPS_ERROR_INVALID_PARAM
;
495 if (!(ptr
= parse_list("ssdd", '|', ptr
, &id
, &filename
, &x
, &y
)))
496 return WPS_ERROR_INVALID_PARAM
;
498 /* Check there is a terminating | */
500 return WPS_ERROR_INVALID_PARAM
;
502 /* get the image ID */
503 n
= get_image_id(*id
);
505 /* check the image number and load state */
506 if(n
< 0 || n
>= MAX_IMAGES
|| wps_data
->img
[n
].loaded
)
508 /* Invalid image ID */
509 return WPS_ERROR_INVALID_PARAM
;
512 /* save a pointer to the filename */
513 bmp_names
[n
] = filename
;
515 wps_data
->img
[n
].x
= x
;
516 wps_data
->img
[n
].y
= y
;
518 /* save current viewport */
519 wps_data
->img
[n
].vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
521 if (token
->type
== WPS_TOKEN_IMAGE_DISPLAY
)
523 wps_data
->img
[n
].always_display
= true;
527 /* Parse the (optional) number of sub-images */
529 newline
= strchr(ptr
, '\n');
530 pos
= strchr(ptr
, '|');
531 if (pos
&& pos
< newline
)
532 wps_data
->img
[n
].num_subimages
= atoi(ptr
);
534 if (wps_data
->img
[n
].num_subimages
<= 0)
535 return WPS_ERROR_INVALID_PARAM
;
538 /* Skip the rest of the line */
539 return skip_end_of_line(wps_bufptr
);
542 static int parse_viewport(const char *wps_bufptr
,
543 struct wps_token
*token
,
544 struct wps_data
*wps_data
)
546 const char *ptr
= wps_bufptr
;
550 (void)token
; /* Kill warnings */
552 if (*wps_bufptr
!= '|')
553 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
555 ptr
= wps_bufptr
+ 1;
556 /* format: %V|x|y|width|height|fg_pattern|bg_pattern| */
558 if (wps_data
->num_viewports
>= WPS_MAX_VIEWPORTS
)
559 return WPS_ERROR_INVALID_PARAM
;
561 wps_data
->num_viewports
++;
562 vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
564 /* Set the defaults for fields not user-specified */
565 vp
->drawmode
= DRMODE_SOLID
;
569 /* Work out the depth of this display */
570 #ifdef HAVE_REMOTE_LCD
571 depth
= (wps_data
->remote_wps
? LCD_REMOTE_DEPTH
: LCD_DEPTH
);
576 #ifdef HAVE_LCD_COLOR
579 if (!(ptr
= parse_list("dddddcc", '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
580 &vp
->height
, &vp
->font
, &vp
->fg_pattern
,&vp
->bg_pattern
)))
581 return WPS_ERROR_INVALID_PARAM
;
585 #if (LCD_DEPTH == 2) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2)
587 if (!(ptr
= parse_list("dddddgg", '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
588 &vp
->height
, &vp
->font
, &vp
->fg_pattern
, &vp
->bg_pattern
)))
589 return WPS_ERROR_INVALID_PARAM
;
593 #if (LCD_DEPTH == 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 1)
596 if (!(ptr
= parse_list("ddddd", '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
597 &vp
->height
, &vp
->font
)))
598 return WPS_ERROR_INVALID_PARAM
;
604 /* Check for trailing | */
606 return WPS_ERROR_INVALID_PARAM
;
608 /* Default to using the user font if the font was an invalid number */
609 if ((vp
->font
!= FONT_SYSFIXED
) && (vp
->font
!= FONT_UI
))
612 /* Validate the viewport dimensions - we know that the numbers are
613 non-negative integers */
614 #ifdef HAVE_REMOTE_LCD
615 if (wps_data
->remote_wps
)
617 if ((vp
->x
>= LCD_REMOTE_WIDTH
) ||
618 ((vp
->x
+ vp
->width
) > LCD_REMOTE_WIDTH
) ||
619 (vp
->y
>= LCD_REMOTE_HEIGHT
) ||
620 ((vp
->y
+ vp
->height
) > LCD_REMOTE_HEIGHT
))
622 return WPS_ERROR_INVALID_PARAM
;
628 if ((vp
->x
>= LCD_WIDTH
) ||
629 ((vp
->x
+ vp
->width
) > LCD_WIDTH
) ||
630 (vp
->y
>= LCD_HEIGHT
) ||
631 ((vp
->y
+ vp
->height
) > LCD_HEIGHT
))
633 return WPS_ERROR_INVALID_PARAM
;
637 wps_data
->viewports
[wps_data
->num_viewports
-1].last_line
= wps_data
->num_lines
- 1;
639 wps_data
->viewports
[wps_data
->num_viewports
].first_line
= wps_data
->num_lines
;
641 if (wps_data
->num_sublines
< WPS_MAX_SUBLINES
)
643 wps_data
->lines
[wps_data
->num_lines
].first_subline_idx
=
644 wps_data
->num_sublines
;
646 wps_data
->sublines
[wps_data
->num_sublines
].first_token_idx
=
647 wps_data
->num_tokens
;
650 /* Skip the rest of the line */
651 return skip_end_of_line(wps_bufptr
);
655 static int parse_image_special(const char *wps_bufptr
,
656 struct wps_token
*token
,
657 struct wps_data
*wps_data
)
659 (void)wps_data
; /* kill warning */
660 const char *pos
= NULL
;
663 pos
= strchr(wps_bufptr
+ 1, '|');
664 newline
= strchr(wps_bufptr
, '\n');
667 return WPS_ERROR_INVALID_PARAM
;
669 if (token
->type
== WPS_TOKEN_IMAGE_PROGRESS_BAR
)
671 /* format: %P|filename.bmp| */
672 bmp_names
[PROGRESSBAR_BMP
] = wps_bufptr
+ 1;
675 else if (token
->type
== WPS_TOKEN_IMAGE_BACKDROP
)
677 /* format: %X|filename.bmp| */
678 bmp_names
[BACKDROP_BMP
] = wps_bufptr
+ 1;
682 /* Skip the rest of the line */
683 return skip_end_of_line(wps_bufptr
);
686 #endif /* HAVE_LCD_BITMAP */
688 static int parse_dir_level(const char *wps_bufptr
,
689 struct wps_token
*token
,
690 struct wps_data
*wps_data
)
692 char val
[] = { *wps_bufptr
, '\0' };
693 token
->value
.i
= atoi(val
);
694 (void)wps_data
; /* Kill warnings */
698 static int parse_subline_timeout(const char *wps_bufptr
,
699 struct wps_token
*token
,
700 struct wps_data
*wps_data
)
704 bool have_point
= false;
705 bool have_tenth
= false;
707 (void)wps_data
; /* Kill the warning */
709 while ( isdigit(*wps_bufptr
) || *wps_bufptr
== '.' )
711 if (*wps_bufptr
!= '.')
714 val
+= *wps_bufptr
- '0';
730 if (have_tenth
== false)
733 token
->value
.i
= val
;
738 static int parse_progressbar(const char *wps_bufptr
,
739 struct wps_token
*token
,
740 struct wps_data
*wps_data
)
742 (void)token
; /* Kill warnings */
743 #ifdef HAVE_LCD_BITMAP
746 &wps_data
->progress_height
,
747 &wps_data
->progress_start
,
748 &wps_data
->progress_end
,
749 &wps_data
->progress_top
};
751 /* default values : */
752 wps_data
->progress_height
= 6;
753 wps_data
->progress_start
= 0;
754 wps_data
->progress_end
= 0;
755 wps_data
->progress_top
= -1;
758 char *newline
= strchr(wps_bufptr
, '\n');
759 char *prev
= strchr(wps_bufptr
, '|');
760 if (prev
&& prev
< newline
) {
761 char *next
= strchr(prev
+1, '|');
762 while (i
< 4 && next
&& next
< newline
)
764 *(vals
[i
++]) = atoi(++prev
);
765 prev
= strchr(prev
, '|');
766 next
= strchr(++next
, '|');
769 if (wps_data
->progress_height
< 3)
770 wps_data
->progress_height
= 3;
771 if (wps_data
->progress_end
< wps_data
->progress_start
+ 3)
772 wps_data
->progress_end
= 0;
775 return newline
- wps_bufptr
;
779 if (*(wps_bufptr
-1) == 'f')
780 wps_data
->full_line_progressbar
= true;
782 wps_data
->full_line_progressbar
= false;
790 static int parse_albumart_load(const char *wps_bufptr
,
791 struct wps_token
*token
,
792 struct wps_data
*wps_data
)
794 const char *_pos
, *newline
;
796 const short xalign_mask
= WPS_ALBUMART_ALIGN_LEFT
|
797 WPS_ALBUMART_ALIGN_CENTER
|
798 WPS_ALBUMART_ALIGN_RIGHT
;
799 const short yalign_mask
= WPS_ALBUMART_ALIGN_TOP
|
800 WPS_ALBUMART_ALIGN_CENTER
|
801 WPS_ALBUMART_ALIGN_BOTTOM
;
803 (void)token
; /* silence warning */
805 /* reset albumart info in wps */
806 wps_data
->wps_uses_albumart
= WPS_ALBUMART_NONE
;
807 wps_data
->albumart_max_width
= -1;
808 wps_data
->albumart_max_height
= -1;
809 wps_data
->albumart_xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
810 wps_data
->albumart_yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
812 /* format: %Cl|x|y|[[l|c|r][d|i|s]mwidth]|[[t|c|b][d|i|s]mheight]| */
814 newline
= strchr(wps_bufptr
, '\n');
816 /* initial validation and parsing of x and y components */
817 if (*wps_bufptr
!= '|')
818 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
820 _pos
= wps_bufptr
+ 1;
822 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl|@ */
823 wps_data
->albumart_x
= atoi(_pos
);
825 _pos
= strchr(_pos
, '|');
826 if (!_pos
|| _pos
> newline
|| !isdigit(*(++_pos
)))
827 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl|7\n or %Cl|7|@ */
829 wps_data
->albumart_y
= atoi(_pos
);
831 _pos
= strchr(_pos
, '|');
832 if (!_pos
|| _pos
> newline
)
833 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no | after y coordinate
836 /* parsing width field */
840 /* apply each modifier in turn */
847 wps_data
->albumart_xalign
=
848 (wps_data
->albumart_xalign
& xalign_mask
) |
849 WPS_ALBUMART_ALIGN_LEFT
;
853 wps_data
->albumart_xalign
=
854 (wps_data
->albumart_xalign
& xalign_mask
) |
855 WPS_ALBUMART_ALIGN_CENTER
;
860 wps_data
->albumart_xalign
=
861 (wps_data
->albumart_xalign
& xalign_mask
) |
862 WPS_ALBUMART_ALIGN_RIGHT
;
866 wps_data
->albumart_xalign
|= WPS_ALBUMART_DECREASE
;
870 wps_data
->albumart_xalign
|= WPS_ALBUMART_INCREASE
;
874 wps_data
->albumart_xalign
|=
875 (WPS_ALBUMART_DECREASE
| WPS_ALBUMART_INCREASE
);
882 /* extract max width data */
885 if (!isdigit(*_pos
)) /* malformed token: e.g. %Cl|7|59|# */
886 return WPS_ERROR_INVALID_PARAM
;
888 wps_data
->albumart_max_width
= atoi(_pos
);
890 _pos
= strchr(_pos
, '|');
891 if (!_pos
|| _pos
> newline
)
892 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no | after width field
893 e.g. %Cl|7|59|200\n */
896 /* parsing height field */
900 /* apply each modifier in turn */
907 wps_data
->albumart_yalign
=
908 (wps_data
->albumart_yalign
& yalign_mask
) |
909 WPS_ALBUMART_ALIGN_TOP
;
913 wps_data
->albumart_yalign
=
914 (wps_data
->albumart_yalign
& yalign_mask
) |
915 WPS_ALBUMART_ALIGN_CENTER
;
920 wps_data
->albumart_yalign
=
921 (wps_data
->albumart_yalign
& yalign_mask
) |
922 WPS_ALBUMART_ALIGN_BOTTOM
;
926 wps_data
->albumart_yalign
|= WPS_ALBUMART_DECREASE
;
930 wps_data
->albumart_yalign
|= WPS_ALBUMART_INCREASE
;
934 wps_data
->albumart_yalign
|=
935 (WPS_ALBUMART_DECREASE
| WPS_ALBUMART_INCREASE
);
942 /* extract max height data */
946 return WPS_ERROR_INVALID_PARAM
; /* malformed token e.g. %Cl|7|59|200|@ */
948 wps_data
->albumart_max_height
= atoi(_pos
);
950 _pos
= strchr(_pos
, '|');
951 if (!_pos
|| _pos
> newline
)
952 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no closing |
953 e.g. %Cl|7|59|200|200\n */
956 /* if we got here, we parsed everything ok .. ! */
957 if (wps_data
->albumart_max_width
< 0)
958 wps_data
->albumart_max_width
= 0;
959 else if (wps_data
->albumart_max_width
> LCD_WIDTH
)
960 wps_data
->albumart_max_width
= LCD_WIDTH
;
962 if (wps_data
->albumart_max_height
< 0)
963 wps_data
->albumart_max_height
= 0;
964 else if (wps_data
->albumart_max_height
> LCD_HEIGHT
)
965 wps_data
->albumart_max_height
= LCD_HEIGHT
;
967 wps_data
->wps_uses_albumart
= WPS_ALBUMART_LOAD
;
969 /* Skip the rest of the line */
970 return skip_end_of_line(wps_bufptr
);
973 static int parse_albumart_conditional(const char *wps_bufptr
,
974 struct wps_token
*token
,
975 struct wps_data
*wps_data
)
977 struct wps_token
*prevtoken
= token
;
979 if (wps_data
->num_tokens
>= 1 && prevtoken
->type
== WPS_TOKEN_CONDITIONAL
)
981 /* This %C is part of a %?C construct.
982 It's either %?C<blah> or %?Cn<blah> */
983 token
->type
= WPS_TOKEN_ALBUMART_FOUND
;
984 if (*wps_bufptr
== 'n' && *(wps_bufptr
+ 1) == '<')
989 else if (*wps_bufptr
== '<')
995 token
->type
= WPS_NO_TOKEN
;
1001 /* This %C tag is in a conditional construct. */
1002 wps_data
->albumart_cond_index
= condindex
[level
];
1006 #endif /* HAVE_ALBUMART */
1008 #ifdef HAVE_LCD_BITMAP
1009 static int parse_leftmargin(const char *wps_bufptr
, struct wps_token
*token
,
1010 struct wps_data
*wps_data
)
1014 const char *newline
;
1016 (void)wps_data
; /* Kill the warning */
1018 /* valid tag looks like %m|12| */
1019 if(*wps_bufptr
== '|')
1022 newline
= strchr(wps_bufptr
, '\n');
1023 if(isdigit(*p
) && (pend
= strchr(p
, '|')) && pend
< newline
)
1025 token
->value
.i
= atoi(p
);
1026 return pend
- wps_bufptr
+ 1;
1030 /* invalid tag syntax */
1031 return WPS_ERROR_INVALID_PARAM
;
1036 /* Parse a generic token from the given string. Return the length read */
1037 static int parse_token(const char *wps_bufptr
, struct wps_data
*wps_data
)
1039 int skip
= 0, taglen
= 0, ret
;
1040 struct wps_token
*token
= wps_data
->tokens
+ wps_data
->num_tokens
;
1041 const struct wps_tag
*tag
;
1052 /* escaped characters */
1053 token
->type
= WPS_TOKEN_CHARACTER
;
1054 token
->value
.c
= *wps_bufptr
;
1056 wps_data
->num_tokens
++;
1060 /* conditional tag */
1061 token
->type
= WPS_TOKEN_CONDITIONAL
;
1063 condindex
[level
] = wps_data
->num_tokens
;
1064 numoptions
[level
] = 1;
1065 wps_data
->num_tokens
++;
1066 ret
= parse_token(wps_bufptr
+ 1, wps_data
);
1067 if (ret
< 0) return ret
;
1072 /* find what tag we have */
1073 for (tag
= all_tags
;
1074 strncmp(wps_bufptr
, tag
->name
, strlen(tag
->name
)) != 0;
1077 taglen
= (tag
->type
!= WPS_TOKEN_UNKNOWN
) ? strlen(tag
->name
) : 2;
1078 token
->type
= tag
->type
;
1079 wps_data
->sublines
[wps_data
->num_sublines
].line_type
|=
1082 /* if the tag has a special parsing function, we call it */
1083 if (tag
->parse_func
)
1085 ret
= tag
->parse_func(wps_bufptr
+ taglen
, token
, wps_data
);
1086 if (ret
< 0) return ret
;
1090 /* Some tags we don't want to save as tokens */
1091 if (tag
->type
== WPS_NO_TOKEN
)
1094 /* tags that start with 'F', 'I' or 'D' are for the next file */
1095 if ( *(tag
->name
) == 'I' || *(tag
->name
) == 'F' ||
1096 *(tag
->name
) == 'D')
1099 wps_data
->num_tokens
++;
1108 data is the pointer to the structure where the parsed WPS should be stored.
1110 wps_bufptr points to the string containing the WPS tags */
1111 static bool wps_parse(struct wps_data
*data
, const char *wps_bufptr
)
1113 if (!data
|| !wps_bufptr
|| !*wps_bufptr
)
1116 char *stringbuf
= data
->string_buffer
;
1117 int stringbuf_used
= 0;
1123 while(*wps_bufptr
&& !fail
&& data
->num_tokens
< WPS_MAX_TOKENS
- 1
1124 && data
->num_viewports
< WPS_MAX_VIEWPORTS
1125 && data
->num_lines
< WPS_MAX_LINES
)
1127 switch(*wps_bufptr
++)
1132 if ((ret
= parse_token(wps_bufptr
, data
)) < 0)
1134 fail
= PARSE_FAIL_COND_INVALID_PARAM
;
1140 /* Alternating sublines separator */
1142 if (level
>= 0) /* there are unclosed conditionals */
1144 fail
= PARSE_FAIL_UNCLOSED_COND
;
1148 if (data
->num_sublines
+1 < WPS_MAX_SUBLINES
)
1149 wps_start_new_subline(data
);
1151 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1155 /* Conditional list start */
1157 if (data
->tokens
[data
->num_tokens
-2].type
!= WPS_TOKEN_CONDITIONAL
)
1159 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1163 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_START
;
1164 lastcond
[level
] = data
->num_tokens
++;
1167 /* Conditional list end */
1169 if (level
< 0) /* not in a conditional, invalid char */
1171 fail
= PARSE_FAIL_INVALID_CHAR
;
1175 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_END
;
1176 if (lastcond
[level
])
1177 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1180 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1184 lastcond
[level
] = 0;
1186 data
->tokens
[condindex
[level
]].value
.i
= numoptions
[level
];
1190 /* Conditional list option */
1192 if (level
< 0) /* not in a conditional, invalid char */
1194 fail
= PARSE_FAIL_INVALID_CHAR
;
1198 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_OPTION
;
1199 if (lastcond
[level
])
1200 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1203 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1207 lastcond
[level
] = data
->num_tokens
;
1208 numoptions
[level
]++;
1214 if (level
>= 0) /* there are unclosed conditionals */
1216 fail
= PARSE_FAIL_UNCLOSED_COND
;
1220 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1223 /* End of this line */
1225 if (level
>= 0) /* there are unclosed conditionals */
1227 fail
= PARSE_FAIL_UNCLOSED_COND
;
1232 wps_start_new_subline(data
);
1233 data
->num_lines
++; /* Start a new line */
1235 if ((data
->num_lines
< WPS_MAX_LINES
) &&
1236 (data
->num_sublines
< WPS_MAX_SUBLINES
))
1238 data
->lines
[data
->num_lines
].first_subline_idx
=
1241 data
->sublines
[data
->num_sublines
].first_token_idx
=
1250 unsigned int len
= 1;
1251 const char *string_start
= wps_bufptr
- 1;
1253 /* find the length of the string */
1254 while (*wps_bufptr
&& *wps_bufptr
!= '#' &&
1255 *wps_bufptr
!= '%' && *wps_bufptr
!= ';' &&
1256 *wps_bufptr
!= '<' && *wps_bufptr
!= '>' &&
1257 *wps_bufptr
!= '|' && *wps_bufptr
!= '\n')
1263 /* look if we already have that string */
1267 for (i
= 0, str
= data
->strings
, found
= false;
1268 i
< data
->num_strings
&&
1269 !(found
= (strlen(*str
) == len
&&
1270 strncmp(string_start
, *str
, len
) == 0));
1272 /* If a matching string is found, found is true and i is
1273 the index of the string. If not, found is false */
1275 /* If it's NOT a duplicate, do nothing if we already have
1276 too many unique strings */
1278 (stringbuf_used
< STRING_BUFFER_SIZE
- 1 &&
1279 data
->num_strings
< WPS_MAX_STRINGS
))
1286 if (stringbuf_used
+ len
> STRING_BUFFER_SIZE
- 1)
1287 len
= STRING_BUFFER_SIZE
- stringbuf_used
- 1;
1289 strncpy(stringbuf
, string_start
, len
);
1290 *(stringbuf
+ len
) = '\0';
1292 data
->strings
[data
->num_strings
] = stringbuf
;
1293 stringbuf
+= len
+ 1;
1294 stringbuf_used
+= len
+ 1;
1295 data
->tokens
[data
->num_tokens
].value
.i
=
1297 data
->num_strings
++;
1301 /* another ocurrence of an existing string */
1302 data
->tokens
[data
->num_tokens
].value
.i
= i
;
1304 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_STRING
;
1312 if (!fail
&& level
>= 0) /* there are unclosed conditionals */
1313 fail
= PARSE_FAIL_UNCLOSED_COND
;
1315 data
->viewports
[data
->num_viewports
].last_line
= data
->num_lines
- 1;
1317 /* We have finished with the last viewport, so increment count */
1318 data
->num_viewports
++;
1321 print_debug_info(data
, fail
, line
);
1330 #ifdef HAVE_LCD_BITMAP
1331 /* Clear the WPS image cache */
1332 static void wps_images_clear(struct wps_data
*data
)
1335 /* set images to unloaded and not displayed */
1336 for (i
= 0; i
< MAX_IMAGES
; i
++)
1338 data
->img
[i
].loaded
= false;
1339 data
->img
[i
].display
= -1;
1340 data
->img
[i
].always_display
= false;
1341 data
->img
[i
].num_subimages
= 1;
1343 data
->progressbar
.have_bitmap_pb
= false;
1347 /* initial setup of wps_data */
1348 void wps_data_init(struct wps_data
*wps_data
)
1350 #ifdef HAVE_LCD_BITMAP
1351 wps_images_clear(wps_data
);
1352 wps_data
->wps_sb_tag
= false;
1353 wps_data
->show_sb_on_wps
= false;
1354 wps_data
->img_buf_ptr
= wps_data
->img_buf
; /* where in image buffer */
1355 wps_data
->img_buf_free
= IMG_BUFSIZE
; /* free space in image buffer */
1356 wps_data
->peak_meter_enabled
= false;
1357 #else /* HAVE_LCD_CHARCELLS */
1359 for (i
= 0; i
< 8; i
++)
1361 wps_data
->wps_progress_pat
[i
] = 0;
1363 wps_data
->full_line_progressbar
= false;
1365 wps_data
->wps_loaded
= false;
1368 static void wps_reset(struct wps_data
*data
)
1370 #ifdef HAVE_REMOTE_LCD
1371 bool rwps
= data
->remote_wps
; /* remember whether the data is for a RWPS */
1373 memset(data
, 0, sizeof(*data
));
1374 #ifdef HAVE_ALBUMART
1375 data
->wps_uses_albumart
= WPS_ALBUMART_NONE
;
1377 wps_data_init(data
);
1378 #ifdef HAVE_REMOTE_LCD
1379 data
->remote_wps
= rwps
;
1383 #ifdef HAVE_LCD_BITMAP
1385 static bool load_wps_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
1387 char img_path
[MAX_PATH
];
1388 struct bitmap
*bitmap
;
1391 for (n
= 0; n
< BACKDROP_BMP
; n
++)
1395 get_image_filename(bmp_names
[n
], bmpdir
,
1396 img_path
, sizeof(img_path
));
1398 if (n
== PROGRESSBAR_BMP
) {
1399 /* progressbar bitmap */
1400 bitmap
= &wps_data
->progressbar
.bm
;
1401 loaded
= &wps_data
->progressbar
.have_bitmap_pb
;
1403 /* regular bitmap */
1404 bitmap
= &wps_data
->img
[n
].bm
;
1405 loaded
= &wps_data
->img
[n
].loaded
;
1408 /* load the image */
1409 bitmap
->data
= wps_data
->img_buf_ptr
;
1410 if (load_bitmap(wps_data
, img_path
, bitmap
))
1414 /* Calculate and store height if this image has sub-images */
1416 wps_data
->img
[n
].subimage_height
= wps_data
->img
[n
].bm
.height
/
1417 wps_data
->img
[n
].num_subimages
;
1421 /* Abort if we can't load an image */
1422 DEBUGF("ERR: Failed to load image %d - %s\n",n
,img_path
);
1428 #if (LCD_DEPTH > 1) || (defined(HAVE_LCD_REMOTE) && (LCD_REMOTE_DEPTH > 1))
1429 if (bmp_names
[BACKDROP_BMP
])
1431 get_image_filename(bmp_names
[BACKDROP_BMP
], bmpdir
,
1432 img_path
, sizeof(img_path
));
1434 #if defined(HAVE_REMOTE_LCD)
1435 /* We only need to check LCD type if there is a remote LCD */
1436 if (!wps_data
->remote_wps
)
1439 /* Load backdrop for the main LCD */
1440 if (!load_wps_backdrop(img_path
))
1443 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1446 /* Load backdrop for the remote LCD */
1447 if (!load_remote_wps_backdrop(img_path
))
1452 #endif /* has backdrop support */
1454 /* If we got here, everything was OK */
1458 #endif /* HAVE_LCD_BITMAP */
1460 /* Skip leading UTF-8 BOM, if present. */
1461 static char *skip_utf8_bom(char *buf
)
1463 unsigned char *s
= (unsigned char *)buf
;
1465 if(s
[0] == 0xef && s
[1] == 0xbb && s
[2] == 0xbf)
1473 /* to setup up the wps-data from a format-buffer (isfile = false)
1474 from a (wps-)file (isfile = true)*/
1475 bool wps_data_load(struct wps_data
*wps_data
,
1476 struct screen
*display
,
1480 if (!wps_data
|| !buf
)
1483 wps_reset(wps_data
);
1485 /* Initialise the first (default) viewport */
1486 wps_data
->viewports
[0].vp
.x
= 0;
1487 wps_data
->viewports
[0].vp
.y
= 0;
1488 wps_data
->viewports
[0].vp
.width
= display
->width
;
1489 wps_data
->viewports
[0].vp
.height
= display
->height
;
1490 #ifdef HAVE_LCD_BITMAP
1491 wps_data
->viewports
[0].vp
.font
= FONT_UI
;
1492 wps_data
->viewports
[0].vp
.drawmode
= DRMODE_SOLID
;
1494 wps_data
->viewports
[0].vp
.xmargin
= display
->getxmargin();
1495 wps_data
->viewports
[0].vp
.ymargin
= display
->getymargin();
1497 if (display
->depth
> 1)
1499 wps_data
->viewports
[0].vp
.fg_pattern
= display
->get_foreground();
1500 wps_data
->viewports
[0].vp
.bg_pattern
= display
->get_background();
1505 return wps_parse(wps_data
, buf
);
1510 * Hardcode loading WPS_DEFAULTCFG to cause a reset ideally this
1511 * wants to be a virtual file. Feel free to modify dirbrowse()
1512 * if you're feeling brave.
1515 if (! strcmp(buf
, WPS_DEFAULTCFG
) )
1517 global_settings
.wps_file
[0] = 0;
1521 #ifdef HAVE_REMOTE_LCD
1522 if (! strcmp(buf
, RWPS_DEFAULTCFG
) )
1524 global_settings
.rwps_file
[0] = 0;
1528 #endif /* __PCTOOL__ */
1530 int fd
= open(buf
, O_RDONLY
);
1535 /* get buffer space from the plugin buffer */
1536 size_t buffersize
= 0;
1537 char *wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
1542 /* copy the file's content to the buffer for parsing,
1543 ensuring that every line ends with a newline char. */
1544 unsigned int start
= 0;
1545 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
1547 start
+= strlen(wps_buffer
+ start
);
1548 if (start
< buffersize
- 1)
1550 wps_buffer
[start
++] = '\n';
1551 wps_buffer
[start
] = 0;
1560 #ifdef HAVE_LCD_BITMAP
1561 /* Set all filename pointers to NULL */
1562 memset(bmp_names
, 0, sizeof(bmp_names
));
1565 /* Skip leading UTF-8 BOM, if present. */
1566 wps_buffer
= skip_utf8_bom(wps_buffer
);
1568 /* parse the WPS source */
1569 if (!wps_parse(wps_data
, wps_buffer
))
1572 wps_data
->wps_loaded
= true;
1574 #ifdef HAVE_LCD_BITMAP
1575 /* get the bitmap dir */
1576 char bmpdir
[MAX_PATH
];
1578 char *dot
= strrchr(buf
, '.');
1579 bmpdirlen
= dot
- buf
;
1580 strncpy(bmpdir
, buf
, dot
- buf
);
1581 bmpdir
[bmpdirlen
] = 0;
1583 /* load the bitmaps that were found by the parsing */
1584 if (!load_wps_bitmaps(wps_data
, bmpdir
))
1591 int wps_subline_index(struct wps_data
*data
, int line
, int subline
)
1593 return data
->lines
[line
].first_subline_idx
+ subline
;
1596 int wps_first_token_index(struct wps_data
*data
, int line
, int subline
)
1598 int first_subline_idx
= data
->lines
[line
].first_subline_idx
;
1599 return data
->sublines
[first_subline_idx
+ subline
].first_token_idx
;
1602 int wps_last_token_index(struct wps_data
*data
, int line
, int subline
)
1604 int first_subline_idx
= data
->lines
[line
].first_subline_idx
;
1605 int idx
= first_subline_idx
+ subline
;
1606 if (idx
< data
->num_sublines
- 1)
1608 /* This subline ends where the next begins */
1609 return data
->sublines
[idx
+1].first_token_idx
- 1;
1613 /* The last subline goes to the end */
1614 return data
->num_tokens
- 1;