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+2) /* WPS images + pbar bitmap + backdrop */
85 #define MAX_BITMAPS (MAX_IMAGES+1) /* WPS images + pbar bitmap */
88 #define PROGRESSBAR_BMP MAX_IMAGES
89 #define BACKDROP_BMP (MAX_IMAGES+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(const char *wps_bufptr
,
133 struct wps_token
*token
, struct wps_data
*wps_data
);
134 static int parse_leftmargin(const char *wps_bufptr
,
135 struct wps_token
*token
, struct wps_data
*wps_data
);
136 static int parse_image_special(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 */
148 static int parse_albumart_load(const char *wps_bufptr
,
149 struct wps_token
*token
, struct wps_data
*wps_data
);
150 static int parse_albumart_conditional(const char *wps_bufptr
,
151 struct wps_token
*token
, struct wps_data
*wps_data
);
152 #endif /* HAVE_ALBUMART */
155 #define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
157 #define WPS_RTC_REFRESH WPS_REFRESH_STATIC
160 /* array of available tags - those with more characters have to go first
161 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
162 static const struct wps_tag all_tags
[] = {
164 { WPS_TOKEN_ALIGN_CENTER
, "ac", 0, NULL
},
165 { WPS_TOKEN_ALIGN_LEFT
, "al", 0, NULL
},
166 { WPS_TOKEN_ALIGN_RIGHT
, "ar", 0, NULL
},
168 { WPS_TOKEN_BATTERY_PERCENT
, "bl", WPS_REFRESH_DYNAMIC
, NULL
},
169 { WPS_TOKEN_BATTERY_VOLTS
, "bv", WPS_REFRESH_DYNAMIC
, NULL
},
170 { WPS_TOKEN_BATTERY_TIME
, "bt", WPS_REFRESH_DYNAMIC
, NULL
},
171 { WPS_TOKEN_BATTERY_SLEEPTIME
, "bs", WPS_REFRESH_DYNAMIC
, NULL
},
172 #if CONFIG_CHARGING >= CHARGING_MONITOR
173 { WPS_TOKEN_BATTERY_CHARGING
, "bc", WPS_REFRESH_DYNAMIC
, NULL
},
176 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED
,"bp", WPS_REFRESH_DYNAMIC
, NULL
},
179 { WPS_TOKEN_RTC_DAY_OF_MONTH
, "cd", WPS_RTC_REFRESH
, NULL
},
180 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
,"ce", WPS_RTC_REFRESH
, NULL
},
181 { WPS_TOKEN_RTC_12HOUR_CFG
, "cf", WPS_RTC_REFRESH
, NULL
},
182 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
, "cH", WPS_RTC_REFRESH
, NULL
},
183 { WPS_TOKEN_RTC_HOUR_24
, "ck", WPS_RTC_REFRESH
, NULL
},
184 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
, "cI", WPS_RTC_REFRESH
, NULL
},
185 { WPS_TOKEN_RTC_HOUR_12
, "cl", WPS_RTC_REFRESH
, NULL
},
186 { WPS_TOKEN_RTC_MONTH
, "cm", WPS_RTC_REFRESH
, NULL
},
187 { WPS_TOKEN_RTC_MINUTE
, "cM", WPS_RTC_REFRESH
, NULL
},
188 { WPS_TOKEN_RTC_SECOND
, "cS", WPS_RTC_REFRESH
, NULL
},
189 { WPS_TOKEN_RTC_YEAR_2_DIGITS
, "cy", WPS_RTC_REFRESH
, NULL
},
190 { WPS_TOKEN_RTC_YEAR_4_DIGITS
, "cY", WPS_RTC_REFRESH
, NULL
},
191 { WPS_TOKEN_RTC_AM_PM_UPPER
, "cP", WPS_RTC_REFRESH
, NULL
},
192 { WPS_TOKEN_RTC_AM_PM_LOWER
, "cp", WPS_RTC_REFRESH
, NULL
},
193 { WPS_TOKEN_RTC_WEEKDAY_NAME
, "ca", WPS_RTC_REFRESH
, NULL
},
194 { WPS_TOKEN_RTC_MONTH_NAME
, "cb", WPS_RTC_REFRESH
, NULL
},
195 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
, "cu", WPS_RTC_REFRESH
, NULL
},
196 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
, "cw", WPS_RTC_REFRESH
, NULL
},
199 { WPS_TOKEN_FILE_BITRATE
, "fb", WPS_REFRESH_STATIC
, NULL
},
200 { WPS_TOKEN_FILE_CODEC
, "fc", WPS_REFRESH_STATIC
, NULL
},
201 { WPS_TOKEN_FILE_FREQUENCY
, "ff", WPS_REFRESH_STATIC
, NULL
},
202 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "fk", WPS_REFRESH_STATIC
, NULL
},
203 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "fm", WPS_REFRESH_STATIC
, NULL
},
204 { WPS_TOKEN_FILE_NAME
, "fn", WPS_REFRESH_STATIC
, NULL
},
205 { WPS_TOKEN_FILE_PATH
, "fp", WPS_REFRESH_STATIC
, NULL
},
206 { WPS_TOKEN_FILE_SIZE
, "fs", WPS_REFRESH_STATIC
, NULL
},
207 { WPS_TOKEN_FILE_VBR
, "fv", WPS_REFRESH_STATIC
, NULL
},
208 { WPS_TOKEN_FILE_DIRECTORY
, "d", WPS_REFRESH_STATIC
,
212 { WPS_TOKEN_FILE_BITRATE
, "Fb", WPS_REFRESH_DYNAMIC
, NULL
},
213 { WPS_TOKEN_FILE_CODEC
, "Fc", WPS_REFRESH_DYNAMIC
, NULL
},
214 { WPS_TOKEN_FILE_FREQUENCY
, "Ff", WPS_REFRESH_DYNAMIC
, NULL
},
215 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "Fk", WPS_REFRESH_DYNAMIC
, NULL
},
216 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "Fm", WPS_REFRESH_DYNAMIC
, NULL
},
217 { WPS_TOKEN_FILE_NAME
, "Fn", WPS_REFRESH_DYNAMIC
, NULL
},
218 { WPS_TOKEN_FILE_PATH
, "Fp", WPS_REFRESH_DYNAMIC
, NULL
},
219 { WPS_TOKEN_FILE_SIZE
, "Fs", WPS_REFRESH_DYNAMIC
, NULL
},
220 { WPS_TOKEN_FILE_VBR
, "Fv", WPS_REFRESH_DYNAMIC
, NULL
},
221 { WPS_TOKEN_FILE_DIRECTORY
, "D", WPS_REFRESH_DYNAMIC
,
224 /* current metadata */
225 { WPS_TOKEN_METADATA_ARTIST
, "ia", WPS_REFRESH_STATIC
, NULL
},
226 { WPS_TOKEN_METADATA_COMPOSER
, "ic", WPS_REFRESH_STATIC
, NULL
},
227 { WPS_TOKEN_METADATA_ALBUM
, "id", WPS_REFRESH_STATIC
, NULL
},
228 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "iA", WPS_REFRESH_STATIC
, NULL
},
229 { WPS_TOKEN_METADATA_GROUPING
, "iG", WPS_REFRESH_STATIC
, NULL
},
230 { WPS_TOKEN_METADATA_GENRE
, "ig", WPS_REFRESH_STATIC
, NULL
},
231 { WPS_TOKEN_METADATA_DISC_NUMBER
, "ik", WPS_REFRESH_STATIC
, NULL
},
232 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "in", WPS_REFRESH_STATIC
, NULL
},
233 { WPS_TOKEN_METADATA_TRACK_TITLE
, "it", WPS_REFRESH_STATIC
, NULL
},
234 { WPS_TOKEN_METADATA_VERSION
, "iv", WPS_REFRESH_STATIC
, NULL
},
235 { WPS_TOKEN_METADATA_YEAR
, "iy", WPS_REFRESH_STATIC
, NULL
},
236 { WPS_TOKEN_METADATA_COMMENT
, "iC", WPS_REFRESH_STATIC
, NULL
},
239 { WPS_TOKEN_METADATA_ARTIST
, "Ia", WPS_REFRESH_DYNAMIC
, NULL
},
240 { WPS_TOKEN_METADATA_COMPOSER
, "Ic", WPS_REFRESH_DYNAMIC
, NULL
},
241 { WPS_TOKEN_METADATA_ALBUM
, "Id", WPS_REFRESH_DYNAMIC
, NULL
},
242 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "IA", WPS_REFRESH_DYNAMIC
, NULL
},
243 { WPS_TOKEN_METADATA_GROUPING
, "IG", WPS_REFRESH_DYNAMIC
, NULL
},
244 { WPS_TOKEN_METADATA_GENRE
, "Ig", WPS_REFRESH_DYNAMIC
, NULL
},
245 { WPS_TOKEN_METADATA_DISC_NUMBER
, "Ik", WPS_REFRESH_DYNAMIC
, NULL
},
246 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "In", WPS_REFRESH_DYNAMIC
, NULL
},
247 { WPS_TOKEN_METADATA_TRACK_TITLE
, "It", WPS_REFRESH_DYNAMIC
, NULL
},
248 { WPS_TOKEN_METADATA_VERSION
, "Iv", WPS_REFRESH_DYNAMIC
, NULL
},
249 { WPS_TOKEN_METADATA_YEAR
, "Iy", WPS_REFRESH_DYNAMIC
, NULL
},
250 { WPS_TOKEN_METADATA_COMMENT
, "IC", WPS_REFRESH_DYNAMIC
, NULL
},
252 #if (CONFIG_CODEC != MAS3507D)
253 { WPS_TOKEN_SOUND_PITCH
, "Sp", WPS_REFRESH_DYNAMIC
, NULL
},
256 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
257 { WPS_TOKEN_VLED_HDD
, "lh", WPS_REFRESH_DYNAMIC
, NULL
},
260 { WPS_TOKEN_MAIN_HOLD
, "mh", WPS_REFRESH_DYNAMIC
, NULL
},
262 #ifdef HAS_REMOTE_BUTTON_HOLD
263 { WPS_TOKEN_REMOTE_HOLD
, "mr", WPS_REFRESH_DYNAMIC
, NULL
},
265 { WPS_TOKEN_UNKNOWN
, "mr", 0, NULL
},
268 { WPS_TOKEN_REPEAT_MODE
, "mm", WPS_REFRESH_DYNAMIC
, NULL
},
269 { WPS_TOKEN_PLAYBACK_STATUS
, "mp", WPS_REFRESH_DYNAMIC
, NULL
},
271 #ifdef HAVE_LCD_BITMAP
272 { WPS_TOKEN_LEFTMARGIN
, "m", 0, parse_leftmargin
},
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
},
320 { WPS_TOKEN_IMAGE_PROGRESS_BAR
, "P", 0, parse_image_special
},
322 { WPS_NO_TOKEN
, "Cl", 0, parse_albumart_load
},
323 { WPS_TOKEN_ALBUMART_DISPLAY
, "C", WPS_REFRESH_STATIC
,
324 parse_albumart_conditional
},
327 { WPS_NO_TOKEN
, "V", 0, parse_viewport
},
329 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
330 { WPS_TOKEN_IMAGE_BACKDROP
, "X", 0, parse_image_special
},
334 { WPS_TOKEN_UNKNOWN
, "", 0, NULL
}
335 /* the array MUST end with an empty string (first char is \0) */
338 /* Returns the number of chars that should be skipped to jump
339 immediately after the first eol, i.e. to the start of the next line */
340 static int skip_end_of_line(const char *wps_bufptr
)
344 while(*(wps_bufptr
+ skip
) != '\n')
349 /* Starts a new subline in the current line during parsing */
350 static void wps_start_new_subline(struct wps_data
*data
)
352 data
->num_sublines
++;
353 data
->sublines
[data
->num_sublines
].first_token_idx
= data
->num_tokens
;
354 data
->lines
[data
->num_lines
].num_sublines
++;
357 #ifdef HAVE_LCD_BITMAP
359 static int parse_statusbar_enable(const char *wps_bufptr
,
360 struct wps_token
*token
,
361 struct wps_data
*wps_data
)
363 (void)token
; /* Kill warnings */
364 wps_data
->wps_sb_tag
= true;
365 wps_data
->show_sb_on_wps
= true;
366 return skip_end_of_line(wps_bufptr
);
369 static int parse_statusbar_disable(const char *wps_bufptr
,
370 struct wps_token
*token
,
371 struct wps_data
*wps_data
)
373 (void)token
; /* Kill warnings */
374 wps_data
->wps_sb_tag
= true;
375 wps_data
->show_sb_on_wps
= false;
376 return skip_end_of_line(wps_bufptr
);
379 static bool load_bitmap(struct wps_data
*wps_data
,
384 #ifdef HAVE_REMOTE_LCD
385 if (wps_data
->remote_wps
)
386 format
= FORMAT_ANY
|FORMAT_REMOTE
;
389 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
391 int ret
= read_bmp_file(filename
, bm
,
392 wps_data
->img_buf_free
,
399 /* Always consume an even number of bytes */
401 wps_data
->img_buf_ptr
+= ret
;
402 wps_data
->img_buf_free
-= ret
;
410 static int get_image_id(int c
)
412 if(c
>= 'a' && c
<= 'z')
414 else if(c
>= 'A' && c
<= 'Z')
420 static char *get_image_filename(const char *start
, const char* bmpdir
,
421 char *buf
, int buf_size
)
423 const char *end
= strchr(start
, '|');
425 if ( !end
|| (end
- start
) >= (buf_size
- ROCKBOX_DIR_LEN
- 2) )
431 int bmpdirlen
= strlen(bmpdir
);
434 buf
[bmpdirlen
] = '/';
435 memcpy( &buf
[bmpdirlen
+ 1], start
, end
- start
);
436 buf
[bmpdirlen
+ 1 + end
- start
] = 0;
441 static int parse_image_display(const char *wps_bufptr
,
442 struct wps_token
*token
,
443 struct wps_data
*wps_data
)
446 int n
= get_image_id(wps_bufptr
[0]);
451 /* invalid picture display tag */
452 return WPS_ERROR_INVALID_PARAM
;
455 if ((subimage
= get_image_id(wps_bufptr
[1])) != -1)
458 if (subimage
>= wps_data
->img
[n
].num_subimages
)
459 return WPS_ERROR_INVALID_PARAM
;
461 /* Store sub-image number to display in high bits */
462 token
->value
.i
= n
| (subimage
<< 8);
463 return 2; /* We have consumed 2 bytes */
466 return 1; /* We have consumed 1 byte */
470 static int parse_image_load(const char *wps_bufptr
,
471 struct wps_token
*token
,
472 struct wps_data
*wps_data
)
475 const char *ptr
= wps_bufptr
;
477 const char* filename
;
482 /* format: %x|n|filename.bmp|x|y|
483 or %xl|n|filename.bmp|x|y|
484 or %xl|n|filename.bmp|x|y|num_subimages|
488 return WPS_ERROR_INVALID_PARAM
;
492 if (!(ptr
= parse_list("ssdd", NULL
, '|', ptr
, &id
, &filename
, &x
, &y
)))
493 return WPS_ERROR_INVALID_PARAM
;
495 /* Check there is a terminating | */
497 return WPS_ERROR_INVALID_PARAM
;
499 /* get the image ID */
500 n
= get_image_id(*id
);
502 /* check the image number and load state */
503 if(n
< 0 || n
>= MAX_IMAGES
|| wps_data
->img
[n
].loaded
)
505 /* Invalid image ID */
506 return WPS_ERROR_INVALID_PARAM
;
509 /* save a pointer to the filename */
510 bmp_names
[n
] = filename
;
512 wps_data
->img
[n
].x
= x
;
513 wps_data
->img
[n
].y
= y
;
515 /* save current viewport */
516 wps_data
->img
[n
].vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
518 if (token
->type
== WPS_TOKEN_IMAGE_DISPLAY
)
520 wps_data
->img
[n
].always_display
= true;
524 /* Parse the (optional) number of sub-images */
526 newline
= strchr(ptr
, '\n');
527 pos
= strchr(ptr
, '|');
528 if (pos
&& pos
< newline
)
529 wps_data
->img
[n
].num_subimages
= atoi(ptr
);
531 if (wps_data
->img
[n
].num_subimages
<= 0)
532 return WPS_ERROR_INVALID_PARAM
;
535 /* Skip the rest of the line */
536 return skip_end_of_line(wps_bufptr
);
539 static int parse_viewport(const char *wps_bufptr
,
540 struct wps_token
*token
,
541 struct wps_data
*wps_data
)
543 (void)token
; /* Kill warnings */
544 const char *ptr
= wps_bufptr
;
557 int lcd_width
= LCD_WIDTH
, lcd_height
= LCD_HEIGHT
;
558 #ifdef HAVE_REMOTE_LCD
559 if (wps_data
->remote_wps
)
561 lcd_width
= LCD_REMOTE_WIDTH
;
562 lcd_height
= LCD_REMOTE_HEIGHT
;
566 if (*wps_bufptr
!= '|')
567 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
569 ptr
= wps_bufptr
+ 1;
570 /* format: %V|x|y|width|height|font|fg_pattern|bg_pattern| */
572 if (wps_data
->num_viewports
>= WPS_MAX_VIEWPORTS
)
573 return WPS_ERROR_INVALID_PARAM
;
575 wps_data
->num_viewports
++;
576 vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
578 /* Set the defaults for fields not user-specified */
579 vp
->drawmode
= DRMODE_SOLID
;
583 /* Work out the depth of this display */
584 #ifdef HAVE_REMOTE_LCD
585 depth
= (wps_data
->remote_wps
? LCD_REMOTE_DEPTH
: LCD_DEPTH
);
590 #ifdef HAVE_LCD_COLOR
593 if (!(ptr
= parse_list("dddddcc", &valid
, '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
594 &vp
->height
, &vp
->font
, &vp
->fg_pattern
,&vp
->bg_pattern
)))
595 return WPS_ERROR_INVALID_PARAM
;
599 #if (LCD_DEPTH == 2) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2)
601 /* Default to black on white */
604 if (!(ptr
= parse_list("dddddgg", &valid
, '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
605 &vp
->height
, &vp
->font
, &vp
->fg_pattern
, &vp
->bg_pattern
)))
606 return WPS_ERROR_INVALID_PARAM
;
610 #if (LCD_DEPTH == 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 1)
613 if (!(ptr
= parse_list("ddddd", &valid
, '|', ptr
, &vp
->x
, &vp
->y
,
614 &vp
->width
, &vp
->height
, &vp
->font
)))
615 return WPS_ERROR_INVALID_PARAM
;
621 /* Check for trailing | */
623 return WPS_ERROR_INVALID_PARAM
;
625 if ((valid
&(1<<PL_X
)) == 0 || (valid
&(1<<PL_Y
)) == 0)
626 return WPS_ERROR_INVALID_PARAM
;
629 if ((valid
&(1<<PL_WIDTH
)) == 0)
630 vp
->width
= lcd_width
- vp
->x
;
631 if ((valid
&(1<<PL_HEIGHT
)) == 0)
632 vp
->height
= lcd_height
- vp
->y
;
634 /* Default to using the user font if the font was an invalid number */
635 if (((valid
&(1<<PL_FONT
)) == 0) ||
636 ((vp
->font
!= FONT_SYSFIXED
) && (vp
->font
!= FONT_UI
)))
639 /* Validate the viewport dimensions - we know that the numbers are
640 non-negative integers */
641 if ((vp
->x
>= lcd_width
) ||
642 ((vp
->x
+ vp
->width
) > lcd_width
) ||
643 (vp
->y
>= lcd_height
) ||
644 ((vp
->y
+ vp
->height
) > lcd_height
))
646 return WPS_ERROR_INVALID_PARAM
;
649 #ifdef HAVE_LCD_COLOR
652 if ((valid
&(1<<PL_FG
)) == 0)
653 vp
->fg_pattern
= global_settings
.fg_color
;
654 if ((valid
&(1<<PL_BG
)) == 0)
655 vp
->bg_pattern
= global_settings
.bg_color
;
659 wps_data
->viewports
[wps_data
->num_viewports
-1].last_line
= wps_data
->num_lines
- 1;
661 wps_data
->viewports
[wps_data
->num_viewports
].first_line
= wps_data
->num_lines
;
663 if (wps_data
->num_sublines
< WPS_MAX_SUBLINES
)
665 wps_data
->lines
[wps_data
->num_lines
].first_subline_idx
=
666 wps_data
->num_sublines
;
668 wps_data
->sublines
[wps_data
->num_sublines
].first_token_idx
=
669 wps_data
->num_tokens
;
672 /* Skip the rest of the line */
673 return skip_end_of_line(wps_bufptr
);
677 static int parse_image_special(const char *wps_bufptr
,
678 struct wps_token
*token
,
679 struct wps_data
*wps_data
)
681 (void)wps_data
; /* kill warning */
682 const char *pos
= NULL
;
685 pos
= strchr(wps_bufptr
+ 1, '|');
686 newline
= strchr(wps_bufptr
, '\n');
689 return WPS_ERROR_INVALID_PARAM
;
691 if (token
->type
== WPS_TOKEN_IMAGE_PROGRESS_BAR
)
693 /* format: %P|filename.bmp| */
694 bmp_names
[PROGRESSBAR_BMP
] = wps_bufptr
+ 1;
697 else if (token
->type
== WPS_TOKEN_IMAGE_BACKDROP
)
699 /* format: %X|filename.bmp| */
700 bmp_names
[BACKDROP_BMP
] = wps_bufptr
+ 1;
704 /* Skip the rest of the line */
705 return skip_end_of_line(wps_bufptr
);
708 #endif /* HAVE_LCD_BITMAP */
710 static int parse_dir_level(const char *wps_bufptr
,
711 struct wps_token
*token
,
712 struct wps_data
*wps_data
)
714 char val
[] = { *wps_bufptr
, '\0' };
715 token
->value
.i
= atoi(val
);
716 (void)wps_data
; /* Kill warnings */
720 static int parse_subline_timeout(const char *wps_bufptr
,
721 struct wps_token
*token
,
722 struct wps_data
*wps_data
)
726 bool have_point
= false;
727 bool have_tenth
= false;
729 (void)wps_data
; /* Kill the warning */
731 while ( isdigit(*wps_bufptr
) || *wps_bufptr
== '.' )
733 if (*wps_bufptr
!= '.')
736 val
+= *wps_bufptr
- '0';
752 if (have_tenth
== false)
755 token
->value
.i
= val
;
760 static int parse_progressbar(const char *wps_bufptr
,
761 struct wps_token
*token
,
762 struct wps_data
*wps_data
)
764 (void)token
; /* Kill warnings */
765 #ifdef HAVE_LCD_BITMAP
768 &wps_data
->progress_height
,
769 &wps_data
->progress_start
,
770 &wps_data
->progress_end
,
771 &wps_data
->progress_top
};
773 /* default values : */
774 wps_data
->progress_height
= 6;
775 wps_data
->progress_start
= 0;
776 wps_data
->progress_end
= 0;
777 wps_data
->progress_top
= -1;
780 char *newline
= strchr(wps_bufptr
, '\n');
781 char *prev
= strchr(wps_bufptr
, '|');
782 if (prev
&& prev
< newline
) {
783 char *next
= strchr(prev
+1, '|');
784 while (i
< 4 && next
&& next
< newline
)
786 *(vals
[i
++]) = atoi(++prev
);
787 prev
= strchr(prev
, '|');
788 next
= strchr(++next
, '|');
791 if (wps_data
->progress_height
< 3)
792 wps_data
->progress_height
= 3;
793 if (wps_data
->progress_end
< wps_data
->progress_start
+ 3)
794 wps_data
->progress_end
= 0;
797 return newline
- wps_bufptr
;
801 if (*(wps_bufptr
-1) == 'f')
802 wps_data
->full_line_progressbar
= true;
804 wps_data
->full_line_progressbar
= false;
812 static int parse_albumart_load(const char *wps_bufptr
,
813 struct wps_token
*token
,
814 struct wps_data
*wps_data
)
816 const char *_pos
, *newline
;
818 const short xalign_mask
= WPS_ALBUMART_ALIGN_LEFT
|
819 WPS_ALBUMART_ALIGN_CENTER
|
820 WPS_ALBUMART_ALIGN_RIGHT
;
821 const short yalign_mask
= WPS_ALBUMART_ALIGN_TOP
|
822 WPS_ALBUMART_ALIGN_CENTER
|
823 WPS_ALBUMART_ALIGN_BOTTOM
;
825 (void)token
; /* silence warning */
827 /* reset albumart info in wps */
828 wps_data
->wps_uses_albumart
= WPS_ALBUMART_NONE
;
829 wps_data
->albumart_max_width
= -1;
830 wps_data
->albumart_max_height
= -1;
831 wps_data
->albumart_xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
832 wps_data
->albumart_yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
834 /* format: %Cl|x|y|[[l|c|r][d|i|s]mwidth]|[[t|c|b][d|i|s]mheight]| */
836 newline
= strchr(wps_bufptr
, '\n');
838 /* initial validation and parsing of x and y components */
839 if (*wps_bufptr
!= '|')
840 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
842 _pos
= wps_bufptr
+ 1;
844 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl|@ */
845 wps_data
->albumart_x
= atoi(_pos
);
847 _pos
= strchr(_pos
, '|');
848 if (!_pos
|| _pos
> newline
|| !isdigit(*(++_pos
)))
849 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl|7\n or %Cl|7|@ */
851 wps_data
->albumart_y
= atoi(_pos
);
853 _pos
= strchr(_pos
, '|');
854 if (!_pos
|| _pos
> newline
)
855 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no | after y coordinate
858 /* parsing width field */
862 /* apply each modifier in turn */
869 wps_data
->albumart_xalign
=
870 (wps_data
->albumart_xalign
& xalign_mask
) |
871 WPS_ALBUMART_ALIGN_LEFT
;
875 wps_data
->albumart_xalign
=
876 (wps_data
->albumart_xalign
& xalign_mask
) |
877 WPS_ALBUMART_ALIGN_CENTER
;
882 wps_data
->albumart_xalign
=
883 (wps_data
->albumart_xalign
& xalign_mask
) |
884 WPS_ALBUMART_ALIGN_RIGHT
;
888 wps_data
->albumart_xalign
|= WPS_ALBUMART_DECREASE
;
892 wps_data
->albumart_xalign
|= WPS_ALBUMART_INCREASE
;
896 wps_data
->albumart_xalign
|=
897 (WPS_ALBUMART_DECREASE
| WPS_ALBUMART_INCREASE
);
904 /* extract max width data */
907 if (!isdigit(*_pos
)) /* malformed token: e.g. %Cl|7|59|# */
908 return WPS_ERROR_INVALID_PARAM
;
910 wps_data
->albumart_max_width
= atoi(_pos
);
912 _pos
= strchr(_pos
, '|');
913 if (!_pos
|| _pos
> newline
)
914 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no | after width field
915 e.g. %Cl|7|59|200\n */
918 /* parsing height field */
922 /* apply each modifier in turn */
929 wps_data
->albumart_yalign
=
930 (wps_data
->albumart_yalign
& yalign_mask
) |
931 WPS_ALBUMART_ALIGN_TOP
;
935 wps_data
->albumart_yalign
=
936 (wps_data
->albumart_yalign
& yalign_mask
) |
937 WPS_ALBUMART_ALIGN_CENTER
;
942 wps_data
->albumart_yalign
=
943 (wps_data
->albumart_yalign
& yalign_mask
) |
944 WPS_ALBUMART_ALIGN_BOTTOM
;
948 wps_data
->albumart_yalign
|= WPS_ALBUMART_DECREASE
;
952 wps_data
->albumart_yalign
|= WPS_ALBUMART_INCREASE
;
956 wps_data
->albumart_yalign
|=
957 (WPS_ALBUMART_DECREASE
| WPS_ALBUMART_INCREASE
);
964 /* extract max height data */
968 return WPS_ERROR_INVALID_PARAM
; /* malformed token e.g. %Cl|7|59|200|@ */
970 wps_data
->albumart_max_height
= atoi(_pos
);
972 _pos
= strchr(_pos
, '|');
973 if (!_pos
|| _pos
> newline
)
974 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no closing |
975 e.g. %Cl|7|59|200|200\n */
978 /* if we got here, we parsed everything ok .. ! */
979 if (wps_data
->albumart_max_width
< 0)
980 wps_data
->albumart_max_width
= 0;
981 else if (wps_data
->albumart_max_width
> LCD_WIDTH
)
982 wps_data
->albumart_max_width
= LCD_WIDTH
;
984 if (wps_data
->albumart_max_height
< 0)
985 wps_data
->albumart_max_height
= 0;
986 else if (wps_data
->albumart_max_height
> LCD_HEIGHT
)
987 wps_data
->albumart_max_height
= LCD_HEIGHT
;
989 wps_data
->wps_uses_albumart
= WPS_ALBUMART_LOAD
;
991 /* Skip the rest of the line */
992 return skip_end_of_line(wps_bufptr
);
995 static int parse_albumart_conditional(const char *wps_bufptr
,
996 struct wps_token
*token
,
997 struct wps_data
*wps_data
)
999 struct wps_token
*prevtoken
= token
;
1001 if (wps_data
->num_tokens
>= 1 && prevtoken
->type
== WPS_TOKEN_CONDITIONAL
)
1003 /* This %C is part of a %?C construct.
1004 It's either %?C<blah> or %?Cn<blah> */
1005 token
->type
= WPS_TOKEN_ALBUMART_FOUND
;
1006 if (*wps_bufptr
== 'n' && *(wps_bufptr
+ 1) == '<')
1011 else if (*wps_bufptr
== '<')
1017 token
->type
= WPS_NO_TOKEN
;
1023 /* This %C tag is in a conditional construct. */
1024 wps_data
->albumart_cond_index
= condindex
[level
];
1028 #endif /* HAVE_ALBUMART */
1030 #ifdef HAVE_LCD_BITMAP
1031 static int parse_leftmargin(const char *wps_bufptr
, struct wps_token
*token
,
1032 struct wps_data
*wps_data
)
1036 const char *newline
;
1038 (void)wps_data
; /* Kill the warning */
1040 /* valid tag looks like %m|12| */
1041 if(*wps_bufptr
== '|')
1044 newline
= strchr(wps_bufptr
, '\n');
1045 if(isdigit(*p
) && (pend
= strchr(p
, '|')) && pend
< newline
)
1047 token
->value
.i
= atoi(p
);
1048 return pend
- wps_bufptr
+ 1;
1052 /* invalid tag syntax */
1053 return WPS_ERROR_INVALID_PARAM
;
1058 /* Parse a generic token from the given string. Return the length read */
1059 static int parse_token(const char *wps_bufptr
, struct wps_data
*wps_data
)
1061 int skip
= 0, taglen
= 0, ret
;
1062 struct wps_token
*token
= wps_data
->tokens
+ wps_data
->num_tokens
;
1063 const struct wps_tag
*tag
;
1074 /* escaped characters */
1075 token
->type
= WPS_TOKEN_CHARACTER
;
1076 token
->value
.c
= *wps_bufptr
;
1078 wps_data
->num_tokens
++;
1082 /* conditional tag */
1083 token
->type
= WPS_TOKEN_CONDITIONAL
;
1085 condindex
[level
] = wps_data
->num_tokens
;
1086 numoptions
[level
] = 1;
1087 wps_data
->num_tokens
++;
1088 ret
= parse_token(wps_bufptr
+ 1, wps_data
);
1089 if (ret
< 0) return ret
;
1094 /* find what tag we have */
1095 for (tag
= all_tags
;
1096 strncmp(wps_bufptr
, tag
->name
, strlen(tag
->name
)) != 0;
1099 taglen
= (tag
->type
!= WPS_TOKEN_UNKNOWN
) ? strlen(tag
->name
) : 2;
1100 token
->type
= tag
->type
;
1101 wps_data
->sublines
[wps_data
->num_sublines
].line_type
|=
1104 /* if the tag has a special parsing function, we call it */
1105 if (tag
->parse_func
)
1107 ret
= tag
->parse_func(wps_bufptr
+ taglen
, token
, wps_data
);
1108 if (ret
< 0) return ret
;
1112 /* Some tags we don't want to save as tokens */
1113 if (tag
->type
== WPS_NO_TOKEN
)
1116 /* tags that start with 'F', 'I' or 'D' are for the next file */
1117 if ( *(tag
->name
) == 'I' || *(tag
->name
) == 'F' ||
1118 *(tag
->name
) == 'D')
1121 wps_data
->num_tokens
++;
1130 data is the pointer to the structure where the parsed WPS should be stored.
1132 wps_bufptr points to the string containing the WPS tags */
1133 static bool wps_parse(struct wps_data
*data
, const char *wps_bufptr
)
1135 if (!data
|| !wps_bufptr
|| !*wps_bufptr
)
1138 char *stringbuf
= data
->string_buffer
;
1139 int stringbuf_used
= 0;
1145 while(*wps_bufptr
&& !fail
&& data
->num_tokens
< WPS_MAX_TOKENS
- 1
1146 && data
->num_viewports
< WPS_MAX_VIEWPORTS
1147 && data
->num_lines
< WPS_MAX_LINES
)
1149 switch(*wps_bufptr
++)
1154 if ((ret
= parse_token(wps_bufptr
, data
)) < 0)
1156 fail
= PARSE_FAIL_COND_INVALID_PARAM
;
1162 /* Alternating sublines separator */
1164 if (level
>= 0) /* there are unclosed conditionals */
1166 fail
= PARSE_FAIL_UNCLOSED_COND
;
1170 if (data
->num_sublines
+1 < WPS_MAX_SUBLINES
)
1171 wps_start_new_subline(data
);
1173 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1177 /* Conditional list start */
1179 if (data
->tokens
[data
->num_tokens
-2].type
!= WPS_TOKEN_CONDITIONAL
)
1181 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1185 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_START
;
1186 lastcond
[level
] = data
->num_tokens
++;
1189 /* Conditional list end */
1191 if (level
< 0) /* not in a conditional, invalid char */
1193 fail
= PARSE_FAIL_INVALID_CHAR
;
1197 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_END
;
1198 if (lastcond
[level
])
1199 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1202 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1206 lastcond
[level
] = 0;
1208 data
->tokens
[condindex
[level
]].value
.i
= numoptions
[level
];
1212 /* Conditional list option */
1214 if (level
< 0) /* not in a conditional, invalid char */
1216 fail
= PARSE_FAIL_INVALID_CHAR
;
1220 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_OPTION
;
1221 if (lastcond
[level
])
1222 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1225 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1229 lastcond
[level
] = data
->num_tokens
;
1230 numoptions
[level
]++;
1236 if (level
>= 0) /* there are unclosed conditionals */
1238 fail
= PARSE_FAIL_UNCLOSED_COND
;
1242 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1245 /* End of this line */
1247 if (level
>= 0) /* there are unclosed conditionals */
1249 fail
= PARSE_FAIL_UNCLOSED_COND
;
1254 wps_start_new_subline(data
);
1255 data
->num_lines
++; /* Start a new line */
1257 if ((data
->num_lines
< WPS_MAX_LINES
) &&
1258 (data
->num_sublines
< WPS_MAX_SUBLINES
))
1260 data
->lines
[data
->num_lines
].first_subline_idx
=
1263 data
->sublines
[data
->num_sublines
].first_token_idx
=
1272 unsigned int len
= 1;
1273 const char *string_start
= wps_bufptr
- 1;
1275 /* find the length of the string */
1276 while (*wps_bufptr
&& *wps_bufptr
!= '#' &&
1277 *wps_bufptr
!= '%' && *wps_bufptr
!= ';' &&
1278 *wps_bufptr
!= '<' && *wps_bufptr
!= '>' &&
1279 *wps_bufptr
!= '|' && *wps_bufptr
!= '\n')
1285 /* look if we already have that string */
1289 for (i
= 0, str
= data
->strings
, found
= false;
1290 i
< data
->num_strings
&&
1291 !(found
= (strlen(*str
) == len
&&
1292 strncmp(string_start
, *str
, len
) == 0));
1294 /* If a matching string is found, found is true and i is
1295 the index of the string. If not, found is false */
1297 /* If it's NOT a duplicate, do nothing if we already have
1298 too many unique strings */
1300 (stringbuf_used
< STRING_BUFFER_SIZE
- 1 &&
1301 data
->num_strings
< WPS_MAX_STRINGS
))
1308 if (stringbuf_used
+ len
> STRING_BUFFER_SIZE
- 1)
1309 len
= STRING_BUFFER_SIZE
- stringbuf_used
- 1;
1311 strncpy(stringbuf
, string_start
, len
);
1312 *(stringbuf
+ len
) = '\0';
1314 data
->strings
[data
->num_strings
] = stringbuf
;
1315 stringbuf
+= len
+ 1;
1316 stringbuf_used
+= len
+ 1;
1317 data
->tokens
[data
->num_tokens
].value
.i
=
1319 data
->num_strings
++;
1323 /* another ocurrence of an existing string */
1324 data
->tokens
[data
->num_tokens
].value
.i
= i
;
1326 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_STRING
;
1334 if (!fail
&& level
>= 0) /* there are unclosed conditionals */
1335 fail
= PARSE_FAIL_UNCLOSED_COND
;
1337 data
->viewports
[data
->num_viewports
].last_line
= data
->num_lines
- 1;
1339 /* We have finished with the last viewport, so increment count */
1340 data
->num_viewports
++;
1343 print_debug_info(data
, fail
, line
);
1349 #ifdef HAVE_LCD_BITMAP
1350 /* Clear the WPS image cache */
1351 static void wps_images_clear(struct wps_data
*data
)
1354 /* set images to unloaded and not displayed */
1355 for (i
= 0; i
< MAX_IMAGES
; i
++)
1357 data
->img
[i
].loaded
= false;
1358 data
->img
[i
].display
= -1;
1359 data
->img
[i
].always_display
= false;
1360 data
->img
[i
].num_subimages
= 1;
1362 data
->progressbar
.have_bitmap_pb
= false;
1366 /* initial setup of wps_data */
1367 void wps_data_init(struct wps_data
*wps_data
)
1369 #ifdef HAVE_LCD_BITMAP
1370 wps_images_clear(wps_data
);
1371 wps_data
->wps_sb_tag
= false;
1372 wps_data
->show_sb_on_wps
= false;
1373 wps_data
->img_buf_ptr
= wps_data
->img_buf
; /* where in image buffer */
1374 wps_data
->img_buf_free
= IMG_BUFSIZE
; /* free space in image buffer */
1375 wps_data
->peak_meter_enabled
= false;
1376 #else /* HAVE_LCD_CHARCELLS */
1378 for (i
= 0; i
< 8; i
++)
1380 wps_data
->wps_progress_pat
[i
] = 0;
1382 wps_data
->full_line_progressbar
= false;
1384 wps_data
->wps_loaded
= false;
1387 static void wps_reset(struct wps_data
*data
)
1389 #ifdef HAVE_REMOTE_LCD
1390 bool rwps
= data
->remote_wps
; /* remember whether the data is for a RWPS */
1392 memset(data
, 0, sizeof(*data
));
1393 #ifdef HAVE_ALBUMART
1394 data
->wps_uses_albumart
= WPS_ALBUMART_NONE
;
1396 wps_data_init(data
);
1397 #ifdef HAVE_REMOTE_LCD
1398 data
->remote_wps
= rwps
;
1402 #ifdef HAVE_LCD_BITMAP
1404 static bool load_wps_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
1406 char img_path
[MAX_PATH
];
1407 struct bitmap
*bitmap
;
1410 for (n
= 0; n
< BACKDROP_BMP
; n
++)
1414 get_image_filename(bmp_names
[n
], bmpdir
,
1415 img_path
, sizeof(img_path
));
1417 if (n
== PROGRESSBAR_BMP
) {
1418 /* progressbar bitmap */
1419 bitmap
= &wps_data
->progressbar
.bm
;
1420 loaded
= &wps_data
->progressbar
.have_bitmap_pb
;
1422 /* regular bitmap */
1423 bitmap
= &wps_data
->img
[n
].bm
;
1424 loaded
= &wps_data
->img
[n
].loaded
;
1427 /* load the image */
1428 bitmap
->data
= wps_data
->img_buf_ptr
;
1429 if (load_bitmap(wps_data
, img_path
, bitmap
))
1433 /* Calculate and store height if this image has sub-images */
1435 wps_data
->img
[n
].subimage_height
= wps_data
->img
[n
].bm
.height
/
1436 wps_data
->img
[n
].num_subimages
;
1440 /* Abort if we can't load an image */
1441 DEBUGF("ERR: Failed to load image %d - %s\n",n
,img_path
);
1447 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1448 if (bmp_names
[BACKDROP_BMP
])
1450 get_image_filename(bmp_names
[BACKDROP_BMP
], bmpdir
,
1451 img_path
, sizeof(img_path
));
1453 #if defined(HAVE_REMOTE_LCD)
1454 /* We only need to check LCD type if there is a remote LCD */
1455 if (!wps_data
->remote_wps
)
1458 /* Load backdrop for the main LCD */
1459 if (!load_wps_backdrop(img_path
))
1462 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1465 /* Load backdrop for the remote LCD */
1466 if (!load_remote_wps_backdrop(img_path
))
1471 #endif /* has backdrop support */
1473 /* If we got here, everything was OK */
1477 #endif /* HAVE_LCD_BITMAP */
1479 /* Skip leading UTF-8 BOM, if present. */
1480 static char *skip_utf8_bom(char *buf
)
1482 unsigned char *s
= (unsigned char *)buf
;
1484 if(s
[0] == 0xef && s
[1] == 0xbb && s
[2] == 0xbf)
1492 /* to setup up the wps-data from a format-buffer (isfile = false)
1493 from a (wps-)file (isfile = true)*/
1494 bool wps_data_load(struct wps_data
*wps_data
,
1495 struct screen
*display
,
1499 if (!wps_data
|| !buf
)
1502 wps_reset(wps_data
);
1504 /* Initialise the first (default) viewport */
1505 wps_data
->viewports
[0].vp
.x
= 0;
1506 wps_data
->viewports
[0].vp
.y
= 0;
1507 wps_data
->viewports
[0].vp
.width
= display
->width
;
1508 wps_data
->viewports
[0].vp
.height
= display
->height
;
1509 #ifdef HAVE_LCD_BITMAP
1510 wps_data
->viewports
[0].vp
.font
= FONT_UI
;
1511 wps_data
->viewports
[0].vp
.drawmode
= DRMODE_SOLID
;
1513 wps_data
->viewports
[0].vp
.xmargin
= display
->getxmargin();
1514 wps_data
->viewports
[0].vp
.ymargin
= display
->getymargin();
1516 if (display
->depth
> 1)
1518 wps_data
->viewports
[0].vp
.fg_pattern
= display
->get_foreground();
1519 wps_data
->viewports
[0].vp
.bg_pattern
= display
->get_background();
1524 return wps_parse(wps_data
, buf
);
1529 * Hardcode loading WPS_DEFAULTCFG to cause a reset ideally this
1530 * wants to be a virtual file. Feel free to modify dirbrowse()
1531 * if you're feeling brave.
1534 if (! strcmp(buf
, WPS_DEFAULTCFG
) )
1536 global_settings
.wps_file
[0] = 0;
1540 #ifdef HAVE_REMOTE_LCD
1541 if (! strcmp(buf
, RWPS_DEFAULTCFG
) )
1543 global_settings
.rwps_file
[0] = 0;
1547 #endif /* __PCTOOL__ */
1549 int fd
= open(buf
, O_RDONLY
);
1554 /* get buffer space from the plugin buffer */
1555 size_t buffersize
= 0;
1556 char *wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
1561 /* copy the file's content to the buffer for parsing,
1562 ensuring that every line ends with a newline char. */
1563 unsigned int start
= 0;
1564 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
1566 start
+= strlen(wps_buffer
+ start
);
1567 if (start
< buffersize
- 1)
1569 wps_buffer
[start
++] = '\n';
1570 wps_buffer
[start
] = 0;
1579 #ifdef HAVE_LCD_BITMAP
1580 /* Set all filename pointers to NULL */
1581 memset(bmp_names
, 0, sizeof(bmp_names
));
1584 /* Skip leading UTF-8 BOM, if present. */
1585 wps_buffer
= skip_utf8_bom(wps_buffer
);
1587 /* parse the WPS source */
1588 if (!wps_parse(wps_data
, wps_buffer
)) {
1589 wps_reset(wps_data
);
1593 wps_data
->wps_loaded
= true;
1595 #ifdef HAVE_LCD_BITMAP
1596 /* get the bitmap dir */
1597 char bmpdir
[MAX_PATH
];
1599 char *dot
= strrchr(buf
, '.');
1600 bmpdirlen
= dot
- buf
;
1601 strncpy(bmpdir
, buf
, dot
- buf
);
1602 bmpdir
[bmpdirlen
] = 0;
1604 /* load the bitmaps that were found by the parsing */
1605 if (!load_wps_bitmaps(wps_data
, bmpdir
)) {
1606 wps_reset(wps_data
);
1614 int wps_subline_index(struct wps_data
*data
, int line
, int subline
)
1616 return data
->lines
[line
].first_subline_idx
+ subline
;
1619 int wps_first_token_index(struct wps_data
*data
, int line
, int subline
)
1621 int first_subline_idx
= data
->lines
[line
].first_subline_idx
;
1622 return data
->sublines
[first_subline_idx
+ subline
].first_token_idx
;
1625 int wps_last_token_index(struct wps_data
*data
, int line
, int subline
)
1627 int first_subline_idx
= data
->lines
[line
].first_subline_idx
;
1628 int idx
= first_subline_idx
+ subline
;
1629 if (idx
< data
->num_sublines
- 1)
1631 /* This subline ends where the next begins */
1632 return data
->sublines
[idx
+1].first_token_idx
- 1;
1636 /* The last subline goes to the end */
1637 return data
->num_tokens
- 1;