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 ****************************************************************************/
28 #define FONT_SYSFIXED 0
44 #ifdef HAVE_LCD_BITMAP
52 #define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps"
53 #define RWPS_DEFAULTCFG WPS_DIR "/rockbox_default.rwps"
55 #define WPS_ERROR_INVALID_PARAM -1
57 #define PARSE_FAIL_UNCLOSED_COND 1
58 #define PARSE_FAIL_INVALID_CHAR 2
59 #define PARSE_FAIL_COND_SYNTAX_ERROR 3
60 #define PARSE_FAIL_COND_INVALID_PARAM 4
62 /* level of current conditional.
63 -1 means we're not in a conditional. */
64 static int level
= -1;
66 /* index of the last WPS_TOKEN_CONDITIONAL_OPTION
67 or WPS_TOKEN_CONDITIONAL_START in current level */
68 static int lastcond
[WPS_MAX_COND_LEVEL
];
70 /* index of the WPS_TOKEN_CONDITIONAL in current level */
71 static int condindex
[WPS_MAX_COND_LEVEL
];
73 /* number of condtional options in current level */
74 static int numoptions
[WPS_MAX_COND_LEVEL
];
76 /* the current line in the file */
79 #ifdef HAVE_LCD_BITMAP
82 #define MAX_BITMAPS (MAX_IMAGES+2) /* WPS images + pbar bitmap + backdrop */
84 #define MAX_BITMAPS (MAX_IMAGES+1) /* WPS images + pbar bitmap */
87 #define PROGRESSBAR_BMP MAX_IMAGES
88 #define BACKDROP_BMP (MAX_IMAGES+1)
90 /* pointers to the bitmap filenames in the WPS source */
91 static const char *bmp_names
[MAX_BITMAPS
];
93 #endif /* HAVE_LCD_BITMAP */
96 /* debugging function */
97 extern void print_debug_info(struct wps_data
*data
, int fail
, int line
);
100 static void wps_reset(struct wps_data
*data
);
102 /* Function for parsing of details for a token. At the moment the
103 function is called, the token type has already been set. The
104 function must fill in the details and possibly add more tokens
105 to the token array. It should return the number of chars that
108 wps_bufptr points to the char following the tag (i.e. where
110 token is the pointer to the 'main' token being parsed
112 typedef int (*wps_tag_parse_func
)(const char *wps_bufptr
,
113 struct wps_token
*token
, struct wps_data
*wps_data
);
116 enum wps_token_type type
;
118 unsigned char refresh_type
;
119 const wps_tag_parse_func parse_func
;
122 /* prototypes of all special parse functions : */
123 static int parse_subline_timeout(const char *wps_bufptr
,
124 struct wps_token
*token
, struct wps_data
*wps_data
);
125 static int parse_progressbar(const char *wps_bufptr
,
126 struct wps_token
*token
, struct wps_data
*wps_data
);
127 static int parse_dir_level(const char *wps_bufptr
,
128 struct wps_token
*token
, struct wps_data
*wps_data
);
130 #ifdef HAVE_LCD_BITMAP
131 static int parse_viewport(const char *wps_bufptr
,
132 struct wps_token
*token
, struct wps_data
*wps_data
);
133 static int parse_leftmargin(const char *wps_bufptr
,
134 struct wps_token
*token
, struct wps_data
*wps_data
);
135 static int parse_image_special(const char *wps_bufptr
,
136 struct wps_token
*token
, struct wps_data
*wps_data
);
137 static int parse_statusbar_enable(const char *wps_bufptr
,
138 struct wps_token
*token
, struct wps_data
*wps_data
);
139 static int parse_statusbar_disable(const char *wps_bufptr
,
140 struct wps_token
*token
, struct wps_data
*wps_data
);
141 static int parse_image_display(const char *wps_bufptr
,
142 struct wps_token
*token
, struct wps_data
*wps_data
);
143 static int parse_image_load(const char *wps_bufptr
,
144 struct wps_token
*token
, struct wps_data
*wps_data
);
145 #endif /*HAVE_LCD_BITMAP */
147 static int parse_albumart_load(const char *wps_bufptr
,
148 struct wps_token
*token
, struct wps_data
*wps_data
);
149 static int parse_albumart_conditional(const char *wps_bufptr
,
150 struct wps_token
*token
, struct wps_data
*wps_data
);
151 #endif /* HAVE_ALBUMART */
154 #define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
156 #define WPS_RTC_REFRESH WPS_REFRESH_STATIC
159 /* array of available tags - those with more characters have to go first
160 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
161 static const struct wps_tag all_tags
[] = {
163 { WPS_TOKEN_ALIGN_CENTER
, "ac", 0, NULL
},
164 { WPS_TOKEN_ALIGN_LEFT
, "al", 0, NULL
},
165 { WPS_TOKEN_ALIGN_RIGHT
, "ar", 0, NULL
},
167 { WPS_TOKEN_BATTERY_PERCENT
, "bl", WPS_REFRESH_DYNAMIC
, NULL
},
168 { WPS_TOKEN_BATTERY_VOLTS
, "bv", WPS_REFRESH_DYNAMIC
, NULL
},
169 { WPS_TOKEN_BATTERY_TIME
, "bt", WPS_REFRESH_DYNAMIC
, NULL
},
170 { WPS_TOKEN_BATTERY_SLEEPTIME
, "bs", WPS_REFRESH_DYNAMIC
, NULL
},
171 #if CONFIG_CHARGING >= CHARGING_MONITOR
172 { WPS_TOKEN_BATTERY_CHARGING
, "bc", WPS_REFRESH_DYNAMIC
, NULL
},
175 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED
,"bp", WPS_REFRESH_DYNAMIC
, NULL
},
178 { WPS_TOKEN_RTC_DAY_OF_MONTH
, "cd", WPS_RTC_REFRESH
, NULL
},
179 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
,"ce", WPS_RTC_REFRESH
, NULL
},
180 { WPS_TOKEN_RTC_12HOUR_CFG
, "cf", WPS_RTC_REFRESH
, NULL
},
181 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
, "cH", WPS_RTC_REFRESH
, NULL
},
182 { WPS_TOKEN_RTC_HOUR_24
, "ck", WPS_RTC_REFRESH
, NULL
},
183 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
, "cI", WPS_RTC_REFRESH
, NULL
},
184 { WPS_TOKEN_RTC_HOUR_12
, "cl", WPS_RTC_REFRESH
, NULL
},
185 { WPS_TOKEN_RTC_MONTH
, "cm", WPS_RTC_REFRESH
, NULL
},
186 { WPS_TOKEN_RTC_MINUTE
, "cM", WPS_RTC_REFRESH
, NULL
},
187 { WPS_TOKEN_RTC_SECOND
, "cS", WPS_RTC_REFRESH
, NULL
},
188 { WPS_TOKEN_RTC_YEAR_2_DIGITS
, "cy", WPS_RTC_REFRESH
, NULL
},
189 { WPS_TOKEN_RTC_YEAR_4_DIGITS
, "cY", WPS_RTC_REFRESH
, NULL
},
190 { WPS_TOKEN_RTC_AM_PM_UPPER
, "cP", WPS_RTC_REFRESH
, NULL
},
191 { WPS_TOKEN_RTC_AM_PM_LOWER
, "cp", WPS_RTC_REFRESH
, NULL
},
192 { WPS_TOKEN_RTC_WEEKDAY_NAME
, "ca", WPS_RTC_REFRESH
, NULL
},
193 { WPS_TOKEN_RTC_MONTH_NAME
, "cb", WPS_RTC_REFRESH
, NULL
},
194 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
, "cu", WPS_RTC_REFRESH
, NULL
},
195 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
, "cw", WPS_RTC_REFRESH
, NULL
},
198 { WPS_TOKEN_FILE_BITRATE
, "fb", WPS_REFRESH_STATIC
, NULL
},
199 { WPS_TOKEN_FILE_CODEC
, "fc", WPS_REFRESH_STATIC
, NULL
},
200 { WPS_TOKEN_FILE_FREQUENCY
, "ff", WPS_REFRESH_STATIC
, NULL
},
201 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "fk", WPS_REFRESH_STATIC
, NULL
},
202 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "fm", WPS_REFRESH_STATIC
, NULL
},
203 { WPS_TOKEN_FILE_NAME
, "fn", WPS_REFRESH_STATIC
, NULL
},
204 { WPS_TOKEN_FILE_PATH
, "fp", WPS_REFRESH_STATIC
, NULL
},
205 { WPS_TOKEN_FILE_SIZE
, "fs", WPS_REFRESH_STATIC
, NULL
},
206 { WPS_TOKEN_FILE_VBR
, "fv", WPS_REFRESH_STATIC
, NULL
},
207 { WPS_TOKEN_FILE_DIRECTORY
, "d", WPS_REFRESH_STATIC
,
211 { WPS_TOKEN_FILE_BITRATE
, "Fb", WPS_REFRESH_DYNAMIC
, NULL
},
212 { WPS_TOKEN_FILE_CODEC
, "Fc", WPS_REFRESH_DYNAMIC
, NULL
},
213 { WPS_TOKEN_FILE_FREQUENCY
, "Ff", WPS_REFRESH_DYNAMIC
, NULL
},
214 { WPS_TOKEN_FILE_FREQUENCY_KHZ
, "Fk", WPS_REFRESH_DYNAMIC
, NULL
},
215 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION
, "Fm", WPS_REFRESH_DYNAMIC
, NULL
},
216 { WPS_TOKEN_FILE_NAME
, "Fn", WPS_REFRESH_DYNAMIC
, NULL
},
217 { WPS_TOKEN_FILE_PATH
, "Fp", WPS_REFRESH_DYNAMIC
, NULL
},
218 { WPS_TOKEN_FILE_SIZE
, "Fs", WPS_REFRESH_DYNAMIC
, NULL
},
219 { WPS_TOKEN_FILE_VBR
, "Fv", WPS_REFRESH_DYNAMIC
, NULL
},
220 { WPS_TOKEN_FILE_DIRECTORY
, "D", WPS_REFRESH_DYNAMIC
,
223 /* current metadata */
224 { WPS_TOKEN_METADATA_ARTIST
, "ia", WPS_REFRESH_STATIC
, NULL
},
225 { WPS_TOKEN_METADATA_COMPOSER
, "ic", WPS_REFRESH_STATIC
, NULL
},
226 { WPS_TOKEN_METADATA_ALBUM
, "id", WPS_REFRESH_STATIC
, NULL
},
227 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "iA", WPS_REFRESH_STATIC
, NULL
},
228 { WPS_TOKEN_METADATA_GROUPING
, "iG", WPS_REFRESH_STATIC
, NULL
},
229 { WPS_TOKEN_METADATA_GENRE
, "ig", WPS_REFRESH_STATIC
, NULL
},
230 { WPS_TOKEN_METADATA_DISC_NUMBER
, "ik", WPS_REFRESH_STATIC
, NULL
},
231 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "in", WPS_REFRESH_STATIC
, NULL
},
232 { WPS_TOKEN_METADATA_TRACK_TITLE
, "it", WPS_REFRESH_STATIC
, NULL
},
233 { WPS_TOKEN_METADATA_VERSION
, "iv", WPS_REFRESH_STATIC
, NULL
},
234 { WPS_TOKEN_METADATA_YEAR
, "iy", WPS_REFRESH_STATIC
, NULL
},
235 { WPS_TOKEN_METADATA_COMMENT
, "iC", WPS_REFRESH_STATIC
, NULL
},
238 { WPS_TOKEN_METADATA_ARTIST
, "Ia", WPS_REFRESH_DYNAMIC
, NULL
},
239 { WPS_TOKEN_METADATA_COMPOSER
, "Ic", WPS_REFRESH_DYNAMIC
, NULL
},
240 { WPS_TOKEN_METADATA_ALBUM
, "Id", WPS_REFRESH_DYNAMIC
, NULL
},
241 { WPS_TOKEN_METADATA_ALBUM_ARTIST
, "IA", WPS_REFRESH_DYNAMIC
, NULL
},
242 { WPS_TOKEN_METADATA_GROUPING
, "IG", WPS_REFRESH_DYNAMIC
, NULL
},
243 { WPS_TOKEN_METADATA_GENRE
, "Ig", WPS_REFRESH_DYNAMIC
, NULL
},
244 { WPS_TOKEN_METADATA_DISC_NUMBER
, "Ik", WPS_REFRESH_DYNAMIC
, NULL
},
245 { WPS_TOKEN_METADATA_TRACK_NUMBER
, "In", WPS_REFRESH_DYNAMIC
, NULL
},
246 { WPS_TOKEN_METADATA_TRACK_TITLE
, "It", WPS_REFRESH_DYNAMIC
, NULL
},
247 { WPS_TOKEN_METADATA_VERSION
, "Iv", WPS_REFRESH_DYNAMIC
, NULL
},
248 { WPS_TOKEN_METADATA_YEAR
, "Iy", WPS_REFRESH_DYNAMIC
, NULL
},
249 { WPS_TOKEN_METADATA_COMMENT
, "IC", WPS_REFRESH_DYNAMIC
, NULL
},
251 #if (CONFIG_CODEC != MAS3507D)
252 { WPS_TOKEN_SOUND_PITCH
, "Sp", WPS_REFRESH_DYNAMIC
, NULL
},
255 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
256 { WPS_TOKEN_VLED_HDD
, "lh", WPS_REFRESH_DYNAMIC
, NULL
},
259 { WPS_TOKEN_MAIN_HOLD
, "mh", WPS_REFRESH_DYNAMIC
, NULL
},
261 #ifdef HAS_REMOTE_BUTTON_HOLD
262 { WPS_TOKEN_REMOTE_HOLD
, "mr", WPS_REFRESH_DYNAMIC
, NULL
},
264 { WPS_TOKEN_UNKNOWN
, "mr", 0, NULL
},
267 { WPS_TOKEN_REPEAT_MODE
, "mm", WPS_REFRESH_DYNAMIC
, NULL
},
268 { WPS_TOKEN_PLAYBACK_STATUS
, "mp", WPS_REFRESH_DYNAMIC
, NULL
},
270 #ifdef HAVE_LCD_BITMAP
271 { WPS_TOKEN_LEFTMARGIN
, "m", 0, parse_leftmargin
},
274 #ifdef HAVE_LCD_BITMAP
275 { WPS_TOKEN_PEAKMETER
, "pm", WPS_REFRESH_PEAK_METER
, NULL
},
277 { WPS_TOKEN_PLAYER_PROGRESSBAR
, "pf",
278 WPS_REFRESH_DYNAMIC
| WPS_REFRESH_PLAYER_PROGRESS
, parse_progressbar
},
280 { WPS_TOKEN_PROGRESSBAR
, "pb", WPS_REFRESH_PLAYER_PROGRESS
,
283 { WPS_TOKEN_VOLUME
, "pv", WPS_REFRESH_DYNAMIC
, NULL
},
285 { WPS_TOKEN_TRACK_ELAPSED_PERCENT
, "px", WPS_REFRESH_DYNAMIC
, NULL
},
286 { WPS_TOKEN_TRACK_TIME_ELAPSED
, "pc", WPS_REFRESH_DYNAMIC
, NULL
},
287 { WPS_TOKEN_TRACK_TIME_REMAINING
, "pr", WPS_REFRESH_DYNAMIC
, NULL
},
288 { WPS_TOKEN_TRACK_LENGTH
, "pt", WPS_REFRESH_STATIC
, NULL
},
290 { WPS_TOKEN_PLAYLIST_POSITION
, "pp", WPS_REFRESH_STATIC
, NULL
},
291 { WPS_TOKEN_PLAYLIST_ENTRIES
, "pe", WPS_REFRESH_STATIC
, NULL
},
292 { WPS_TOKEN_PLAYLIST_NAME
, "pn", WPS_REFRESH_STATIC
, NULL
},
293 { WPS_TOKEN_PLAYLIST_SHUFFLE
, "ps", WPS_REFRESH_DYNAMIC
, NULL
},
296 { WPS_TOKEN_DATABASE_PLAYCOUNT
, "rp", WPS_REFRESH_DYNAMIC
, NULL
},
297 { WPS_TOKEN_DATABASE_RATING
, "rr", WPS_REFRESH_DYNAMIC
, NULL
},
298 { WPS_TOKEN_DATABASE_AUTOSCORE
, "ra", WPS_REFRESH_DYNAMIC
, NULL
},
301 #if CONFIG_CODEC == SWCODEC
302 { WPS_TOKEN_REPLAYGAIN
, "rg", WPS_REFRESH_STATIC
, NULL
},
303 { WPS_TOKEN_CROSSFADE
, "xf", WPS_REFRESH_DYNAMIC
, NULL
},
306 { WPS_NO_TOKEN
, "s", WPS_REFRESH_SCROLL
, NULL
},
307 { WPS_TOKEN_SUBLINE_TIMEOUT
, "t", 0, parse_subline_timeout
},
309 #ifdef HAVE_LCD_BITMAP
310 { WPS_NO_TOKEN
, "we", 0, parse_statusbar_enable
},
311 { WPS_NO_TOKEN
, "wd", 0, parse_statusbar_disable
},
313 { WPS_NO_TOKEN
, "xl", 0, parse_image_load
},
315 { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY
, "xd", WPS_REFRESH_STATIC
,
316 parse_image_display
},
318 { WPS_TOKEN_IMAGE_DISPLAY
, "x", 0, parse_image_load
},
319 { WPS_TOKEN_IMAGE_PROGRESS_BAR
, "P", 0, parse_image_special
},
321 { WPS_NO_TOKEN
, "Cl", 0, parse_albumart_load
},
322 { WPS_TOKEN_ALBUMART_DISPLAY
, "C", WPS_REFRESH_STATIC
,
323 parse_albumart_conditional
},
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 return skip_end_of_line(wps_bufptr
);
368 static int parse_statusbar_disable(const char *wps_bufptr
,
369 struct wps_token
*token
,
370 struct wps_data
*wps_data
)
372 (void)token
; /* Kill warnings */
373 wps_data
->wps_sb_tag
= true;
374 wps_data
->show_sb_on_wps
= false;
375 return skip_end_of_line(wps_bufptr
);
378 static bool load_bitmap(struct wps_data
*wps_data
,
383 #ifdef HAVE_REMOTE_LCD
384 if (wps_data
->remote_wps
)
385 format
= FORMAT_ANY
|FORMAT_REMOTE
;
388 format
= FORMAT_ANY
|FORMAT_TRANSPARENT
;
390 int ret
= read_bmp_file(filename
, bm
,
391 wps_data
->img_buf_free
,
398 /* Always consume an even number of bytes */
400 wps_data
->img_buf_ptr
+= ret
;
401 wps_data
->img_buf_free
-= ret
;
409 static int get_image_id(int c
)
411 if(c
>= 'a' && c
<= 'z')
413 else if(c
>= 'A' && c
<= 'Z')
419 static char *get_image_filename(const char *start
, const char* bmpdir
,
420 char *buf
, int buf_size
)
422 const char *end
= strchr(start
, '|');
424 if ( !end
|| (end
- start
) >= (buf_size
- ROCKBOX_DIR_LEN
- 2) )
430 int bmpdirlen
= strlen(bmpdir
);
433 buf
[bmpdirlen
] = '/';
434 memcpy( &buf
[bmpdirlen
+ 1], start
, end
- start
);
435 buf
[bmpdirlen
+ 1 + end
- start
] = 0;
440 static int parse_image_display(const char *wps_bufptr
,
441 struct wps_token
*token
,
442 struct wps_data
*wps_data
)
445 int n
= get_image_id(wps_bufptr
[0]);
450 /* invalid picture display tag */
451 return WPS_ERROR_INVALID_PARAM
;
454 if ((subimage
= get_image_id(wps_bufptr
[1])) != -1)
457 if (subimage
>= wps_data
->img
[n
].num_subimages
)
458 return WPS_ERROR_INVALID_PARAM
;
460 /* Store sub-image number to display in high bits */
461 token
->value
.i
= n
| (subimage
<< 8);
462 return 2; /* We have consumed 2 bytes */
465 return 1; /* We have consumed 1 byte */
469 static int parse_image_load(const char *wps_bufptr
,
470 struct wps_token
*token
,
471 struct wps_data
*wps_data
)
474 const char *ptr
= wps_bufptr
;
476 const char* filename
;
481 /* format: %x|n|filename.bmp|x|y|
482 or %xl|n|filename.bmp|x|y|
483 or %xl|n|filename.bmp|x|y|num_subimages|
487 return WPS_ERROR_INVALID_PARAM
;
491 if (!(ptr
= parse_list("ssdd", '|', ptr
, &id
, &filename
, &x
, &y
)))
492 return WPS_ERROR_INVALID_PARAM
;
494 /* Check there is a terminating | */
496 return WPS_ERROR_INVALID_PARAM
;
498 /* get the image ID */
499 n
= get_image_id(*id
);
501 /* check the image number and load state */
502 if(n
< 0 || n
>= MAX_IMAGES
|| wps_data
->img
[n
].loaded
)
504 /* Invalid image ID */
505 return WPS_ERROR_INVALID_PARAM
;
508 /* save a pointer to the filename */
509 bmp_names
[n
] = filename
;
511 wps_data
->img
[n
].x
= x
;
512 wps_data
->img
[n
].y
= y
;
514 /* save current viewport */
515 wps_data
->img
[n
].vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
517 if (token
->type
== WPS_TOKEN_IMAGE_DISPLAY
)
519 wps_data
->img
[n
].always_display
= true;
523 /* Parse the (optional) number of sub-images */
525 newline
= strchr(ptr
, '\n');
526 pos
= strchr(ptr
, '|');
527 if (pos
&& pos
< newline
)
528 wps_data
->img
[n
].num_subimages
= atoi(ptr
);
530 if (wps_data
->img
[n
].num_subimages
<= 0)
531 return WPS_ERROR_INVALID_PARAM
;
534 /* Skip the rest of the line */
535 return skip_end_of_line(wps_bufptr
);
538 static int parse_viewport(const char *wps_bufptr
,
539 struct wps_token
*token
,
540 struct wps_data
*wps_data
)
542 const char *ptr
= wps_bufptr
;
546 (void)token
; /* Kill warnings */
548 if (*wps_bufptr
!= '|')
549 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
551 ptr
= wps_bufptr
+ 1;
552 /* format: %V|x|y|width|height|fg_pattern|bg_pattern| */
554 if (wps_data
->num_viewports
>= WPS_MAX_VIEWPORTS
)
555 return WPS_ERROR_INVALID_PARAM
;
557 wps_data
->num_viewports
++;
558 vp
= &wps_data
->viewports
[wps_data
->num_viewports
].vp
;
560 /* Set the defaults for fields not user-specified */
561 vp
->drawmode
= DRMODE_SOLID
;
565 /* Work out the depth of this display */
566 #ifdef HAVE_REMOTE_LCD
567 depth
= (wps_data
->remote_wps
? LCD_REMOTE_DEPTH
: LCD_DEPTH
);
572 #ifdef HAVE_LCD_COLOR
575 if (!(ptr
= parse_list("dddddcc", '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
576 &vp
->height
, &vp
->font
, &vp
->fg_pattern
,&vp
->bg_pattern
)))
577 return WPS_ERROR_INVALID_PARAM
;
581 #if (LCD_DEPTH == 2) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2)
583 if (!(ptr
= parse_list("dddddgg", '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
584 &vp
->height
, &vp
->font
, &vp
->fg_pattern
, &vp
->bg_pattern
)))
585 return WPS_ERROR_INVALID_PARAM
;
589 #if (LCD_DEPTH == 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 1)
592 if (!(ptr
= parse_list("ddddd", '|', ptr
, &vp
->x
, &vp
->y
, &vp
->width
,
593 &vp
->height
, &vp
->font
)))
594 return WPS_ERROR_INVALID_PARAM
;
600 /* Check for trailing | */
602 return WPS_ERROR_INVALID_PARAM
;
604 /* Default to using the user font if the font was an invalid number */
605 if ((vp
->font
!= FONT_SYSFIXED
) && (vp
->font
!= FONT_UI
))
608 /* Validate the viewport dimensions - we know that the numbers are
609 non-negative integers */
610 #ifdef HAVE_REMOTE_LCD
611 if (wps_data
->remote_wps
)
613 if ((vp
->x
>= LCD_REMOTE_WIDTH
) ||
614 ((vp
->x
+ vp
->width
) > LCD_REMOTE_WIDTH
) ||
615 (vp
->y
>= LCD_REMOTE_HEIGHT
) ||
616 ((vp
->y
+ vp
->height
) > LCD_REMOTE_HEIGHT
))
618 return WPS_ERROR_INVALID_PARAM
;
624 if ((vp
->x
>= LCD_WIDTH
) ||
625 ((vp
->x
+ vp
->width
) > LCD_WIDTH
) ||
626 (vp
->y
>= LCD_HEIGHT
) ||
627 ((vp
->y
+ vp
->height
) > LCD_HEIGHT
))
629 return WPS_ERROR_INVALID_PARAM
;
633 wps_data
->viewports
[wps_data
->num_viewports
-1].last_line
= wps_data
->num_lines
- 1;
635 wps_data
->viewports
[wps_data
->num_viewports
].first_line
= wps_data
->num_lines
;
637 if (wps_data
->num_sublines
< WPS_MAX_SUBLINES
)
639 wps_data
->lines
[wps_data
->num_lines
].first_subline_idx
=
640 wps_data
->num_sublines
;
642 wps_data
->sublines
[wps_data
->num_sublines
].first_token_idx
=
643 wps_data
->num_tokens
;
646 /* Skip the rest of the line */
647 return skip_end_of_line(wps_bufptr
);
651 static int parse_image_special(const char *wps_bufptr
,
652 struct wps_token
*token
,
653 struct wps_data
*wps_data
)
655 (void)wps_data
; /* kill warning */
656 const char *pos
= NULL
;
659 pos
= strchr(wps_bufptr
+ 1, '|');
660 newline
= strchr(wps_bufptr
, '\n');
663 return WPS_ERROR_INVALID_PARAM
;
665 if (token
->type
== WPS_TOKEN_IMAGE_PROGRESS_BAR
)
667 /* format: %P|filename.bmp| */
668 bmp_names
[PROGRESSBAR_BMP
] = wps_bufptr
+ 1;
671 else if (token
->type
== WPS_TOKEN_IMAGE_BACKDROP
)
673 /* format: %X|filename.bmp| */
674 bmp_names
[BACKDROP_BMP
] = wps_bufptr
+ 1;
678 /* Skip the rest of the line */
679 return skip_end_of_line(wps_bufptr
);
682 #endif /* HAVE_LCD_BITMAP */
684 static int parse_dir_level(const char *wps_bufptr
,
685 struct wps_token
*token
,
686 struct wps_data
*wps_data
)
688 char val
[] = { *wps_bufptr
, '\0' };
689 token
->value
.i
= atoi(val
);
690 (void)wps_data
; /* Kill warnings */
694 static int parse_subline_timeout(const char *wps_bufptr
,
695 struct wps_token
*token
,
696 struct wps_data
*wps_data
)
700 bool have_point
= false;
701 bool have_tenth
= false;
703 (void)wps_data
; /* Kill the warning */
705 while ( isdigit(*wps_bufptr
) || *wps_bufptr
== '.' )
707 if (*wps_bufptr
!= '.')
710 val
+= *wps_bufptr
- '0';
726 if (have_tenth
== false)
729 token
->value
.i
= val
;
734 static int parse_progressbar(const char *wps_bufptr
,
735 struct wps_token
*token
,
736 struct wps_data
*wps_data
)
738 (void)token
; /* Kill warnings */
739 #ifdef HAVE_LCD_BITMAP
742 &wps_data
->progress_height
,
743 &wps_data
->progress_start
,
744 &wps_data
->progress_end
,
745 &wps_data
->progress_top
};
747 /* default values : */
748 wps_data
->progress_height
= 6;
749 wps_data
->progress_start
= 0;
750 wps_data
->progress_end
= 0;
751 wps_data
->progress_top
= -1;
754 char *newline
= strchr(wps_bufptr
, '\n');
755 char *prev
= strchr(wps_bufptr
, '|');
756 if (prev
&& prev
< newline
) {
757 char *next
= strchr(prev
+1, '|');
758 while (i
< 4 && next
&& next
< newline
)
760 *(vals
[i
++]) = atoi(++prev
);
761 prev
= strchr(prev
, '|');
762 next
= strchr(++next
, '|');
765 if (wps_data
->progress_height
< 3)
766 wps_data
->progress_height
= 3;
767 if (wps_data
->progress_end
< wps_data
->progress_start
+ 3)
768 wps_data
->progress_end
= 0;
771 return newline
- wps_bufptr
;
775 if (*(wps_bufptr
-1) == 'f')
776 wps_data
->full_line_progressbar
= true;
778 wps_data
->full_line_progressbar
= false;
786 static int parse_albumart_load(const char *wps_bufptr
,
787 struct wps_token
*token
,
788 struct wps_data
*wps_data
)
790 const char *_pos
, *newline
;
792 const short xalign_mask
= WPS_ALBUMART_ALIGN_LEFT
|
793 WPS_ALBUMART_ALIGN_CENTER
|
794 WPS_ALBUMART_ALIGN_RIGHT
;
795 const short yalign_mask
= WPS_ALBUMART_ALIGN_TOP
|
796 WPS_ALBUMART_ALIGN_CENTER
|
797 WPS_ALBUMART_ALIGN_BOTTOM
;
799 (void)token
; /* silence warning */
801 /* reset albumart info in wps */
802 wps_data
->wps_uses_albumart
= WPS_ALBUMART_NONE
;
803 wps_data
->albumart_max_width
= -1;
804 wps_data
->albumart_max_height
= -1;
805 wps_data
->albumart_xalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
806 wps_data
->albumart_yalign
= WPS_ALBUMART_ALIGN_CENTER
; /* default */
808 /* format: %Cl|x|y|[[l|c|r][d|i|s]mwidth]|[[t|c|b][d|i|s]mheight]| */
810 newline
= strchr(wps_bufptr
, '\n');
812 /* initial validation and parsing of x and y components */
813 if (*wps_bufptr
!= '|')
814 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl7 */
816 _pos
= wps_bufptr
+ 1;
818 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl|@ */
819 wps_data
->albumart_x
= atoi(_pos
);
821 _pos
= strchr(_pos
, '|');
822 if (!_pos
|| _pos
> newline
|| !isdigit(*(++_pos
)))
823 return WPS_ERROR_INVALID_PARAM
; /* malformed token: e.g. %Cl|7\n or %Cl|7|@ */
825 wps_data
->albumart_y
= atoi(_pos
);
827 _pos
= strchr(_pos
, '|');
828 if (!_pos
|| _pos
> newline
)
829 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no | after y coordinate
832 /* parsing width field */
836 /* apply each modifier in turn */
843 wps_data
->albumart_xalign
=
844 (wps_data
->albumart_xalign
& xalign_mask
) |
845 WPS_ALBUMART_ALIGN_LEFT
;
849 wps_data
->albumart_xalign
=
850 (wps_data
->albumart_xalign
& xalign_mask
) |
851 WPS_ALBUMART_ALIGN_CENTER
;
856 wps_data
->albumart_xalign
=
857 (wps_data
->albumart_xalign
& xalign_mask
) |
858 WPS_ALBUMART_ALIGN_RIGHT
;
862 wps_data
->albumart_xalign
|= WPS_ALBUMART_DECREASE
;
866 wps_data
->albumart_xalign
|= WPS_ALBUMART_INCREASE
;
870 wps_data
->albumart_xalign
|=
871 (WPS_ALBUMART_DECREASE
| WPS_ALBUMART_INCREASE
);
878 /* extract max width data */
881 if (!isdigit(*_pos
)) /* malformed token: e.g. %Cl|7|59|# */
882 return WPS_ERROR_INVALID_PARAM
;
884 wps_data
->albumart_max_width
= atoi(_pos
);
886 _pos
= strchr(_pos
, '|');
887 if (!_pos
|| _pos
> newline
)
888 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no | after width field
889 e.g. %Cl|7|59|200\n */
892 /* parsing height field */
896 /* apply each modifier in turn */
903 wps_data
->albumart_yalign
=
904 (wps_data
->albumart_yalign
& yalign_mask
) |
905 WPS_ALBUMART_ALIGN_TOP
;
909 wps_data
->albumart_yalign
=
910 (wps_data
->albumart_yalign
& yalign_mask
) |
911 WPS_ALBUMART_ALIGN_CENTER
;
916 wps_data
->albumart_yalign
=
917 (wps_data
->albumart_yalign
& yalign_mask
) |
918 WPS_ALBUMART_ALIGN_BOTTOM
;
922 wps_data
->albumart_yalign
|= WPS_ALBUMART_DECREASE
;
926 wps_data
->albumart_yalign
|= WPS_ALBUMART_INCREASE
;
930 wps_data
->albumart_yalign
|=
931 (WPS_ALBUMART_DECREASE
| WPS_ALBUMART_INCREASE
);
938 /* extract max height data */
942 return WPS_ERROR_INVALID_PARAM
; /* malformed token e.g. %Cl|7|59|200|@ */
944 wps_data
->albumart_max_height
= atoi(_pos
);
946 _pos
= strchr(_pos
, '|');
947 if (!_pos
|| _pos
> newline
)
948 return WPS_ERROR_INVALID_PARAM
; /* malformed token: no closing |
949 e.g. %Cl|7|59|200|200\n */
952 /* if we got here, we parsed everything ok .. ! */
953 if (wps_data
->albumart_max_width
< 0)
954 wps_data
->albumart_max_width
= 0;
955 else if (wps_data
->albumart_max_width
> LCD_WIDTH
)
956 wps_data
->albumart_max_width
= LCD_WIDTH
;
958 if (wps_data
->albumart_max_height
< 0)
959 wps_data
->albumart_max_height
= 0;
960 else if (wps_data
->albumart_max_height
> LCD_HEIGHT
)
961 wps_data
->albumart_max_height
= LCD_HEIGHT
;
963 wps_data
->wps_uses_albumart
= WPS_ALBUMART_LOAD
;
965 /* Skip the rest of the line */
966 return skip_end_of_line(wps_bufptr
);
969 static int parse_albumart_conditional(const char *wps_bufptr
,
970 struct wps_token
*token
,
971 struct wps_data
*wps_data
)
973 struct wps_token
*prevtoken
= token
;
975 if (wps_data
->num_tokens
>= 1 && prevtoken
->type
== WPS_TOKEN_CONDITIONAL
)
977 /* This %C is part of a %?C construct.
978 It's either %?C<blah> or %?Cn<blah> */
979 token
->type
= WPS_TOKEN_ALBUMART_FOUND
;
980 if (*wps_bufptr
== 'n' && *(wps_bufptr
+ 1) == '<')
985 else if (*wps_bufptr
== '<')
991 token
->type
= WPS_NO_TOKEN
;
997 /* This %C tag is in a conditional construct. */
998 wps_data
->albumart_cond_index
= condindex
[level
];
1002 #endif /* HAVE_ALBUMART */
1004 #ifdef HAVE_LCD_BITMAP
1005 static int parse_leftmargin(const char *wps_bufptr
, struct wps_token
*token
,
1006 struct wps_data
*wps_data
)
1010 const char *newline
;
1012 (void)wps_data
; /* Kill the warning */
1014 /* valid tag looks like %m|12| */
1015 if(*wps_bufptr
== '|')
1018 newline
= strchr(wps_bufptr
, '\n');
1019 if(isdigit(*p
) && (pend
= strchr(p
, '|')) && pend
< newline
)
1021 token
->value
.i
= atoi(p
);
1022 return pend
- wps_bufptr
+ 1;
1026 /* invalid tag syntax */
1027 return WPS_ERROR_INVALID_PARAM
;
1032 /* Parse a generic token from the given string. Return the length read */
1033 static int parse_token(const char *wps_bufptr
, struct wps_data
*wps_data
)
1035 int skip
= 0, taglen
= 0, ret
;
1036 struct wps_token
*token
= wps_data
->tokens
+ wps_data
->num_tokens
;
1037 const struct wps_tag
*tag
;
1048 /* escaped characters */
1049 token
->type
= WPS_TOKEN_CHARACTER
;
1050 token
->value
.c
= *wps_bufptr
;
1052 wps_data
->num_tokens
++;
1056 /* conditional tag */
1057 token
->type
= WPS_TOKEN_CONDITIONAL
;
1059 condindex
[level
] = wps_data
->num_tokens
;
1060 numoptions
[level
] = 1;
1061 wps_data
->num_tokens
++;
1062 ret
= parse_token(wps_bufptr
+ 1, wps_data
);
1063 if (ret
< 0) return ret
;
1068 /* find what tag we have */
1069 for (tag
= all_tags
;
1070 strncmp(wps_bufptr
, tag
->name
, strlen(tag
->name
)) != 0;
1073 taglen
= (tag
->type
!= WPS_TOKEN_UNKNOWN
) ? strlen(tag
->name
) : 2;
1074 token
->type
= tag
->type
;
1075 wps_data
->sublines
[wps_data
->num_sublines
].line_type
|=
1078 /* if the tag has a special parsing function, we call it */
1079 if (tag
->parse_func
)
1081 ret
= tag
->parse_func(wps_bufptr
+ taglen
, token
, wps_data
);
1082 if (ret
< 0) return ret
;
1086 /* Some tags we don't want to save as tokens */
1087 if (tag
->type
== WPS_NO_TOKEN
)
1090 /* tags that start with 'F', 'I' or 'D' are for the next file */
1091 if ( *(tag
->name
) == 'I' || *(tag
->name
) == 'F' ||
1092 *(tag
->name
) == 'D')
1095 wps_data
->num_tokens
++;
1104 data is the pointer to the structure where the parsed WPS should be stored.
1106 wps_bufptr points to the string containing the WPS tags */
1107 static bool wps_parse(struct wps_data
*data
, const char *wps_bufptr
)
1109 if (!data
|| !wps_bufptr
|| !*wps_bufptr
)
1112 char *stringbuf
= data
->string_buffer
;
1113 int stringbuf_used
= 0;
1119 while(*wps_bufptr
&& !fail
&& data
->num_tokens
< WPS_MAX_TOKENS
- 1
1120 && data
->num_viewports
< WPS_MAX_VIEWPORTS
1121 && data
->num_lines
< WPS_MAX_LINES
)
1123 switch(*wps_bufptr
++)
1128 if ((ret
= parse_token(wps_bufptr
, data
)) < 0)
1130 fail
= PARSE_FAIL_COND_INVALID_PARAM
;
1136 /* Alternating sublines separator */
1138 if (level
>= 0) /* there are unclosed conditionals */
1140 fail
= PARSE_FAIL_UNCLOSED_COND
;
1144 if (data
->num_sublines
+1 < WPS_MAX_SUBLINES
)
1145 wps_start_new_subline(data
);
1147 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1151 /* Conditional list start */
1153 if (data
->tokens
[data
->num_tokens
-2].type
!= WPS_TOKEN_CONDITIONAL
)
1155 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1159 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_START
;
1160 lastcond
[level
] = data
->num_tokens
++;
1163 /* Conditional list end */
1165 if (level
< 0) /* not in a conditional, invalid char */
1167 fail
= PARSE_FAIL_INVALID_CHAR
;
1171 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_END
;
1172 if (lastcond
[level
])
1173 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1176 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1180 lastcond
[level
] = 0;
1182 data
->tokens
[condindex
[level
]].value
.i
= numoptions
[level
];
1186 /* Conditional list option */
1188 if (level
< 0) /* not in a conditional, invalid char */
1190 fail
= PARSE_FAIL_INVALID_CHAR
;
1194 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_CONDITIONAL_OPTION
;
1195 if (lastcond
[level
])
1196 data
->tokens
[lastcond
[level
]].value
.i
= data
->num_tokens
;
1199 fail
= PARSE_FAIL_COND_SYNTAX_ERROR
;
1203 lastcond
[level
] = data
->num_tokens
;
1204 numoptions
[level
]++;
1210 if (level
>= 0) /* there are unclosed conditionals */
1212 fail
= PARSE_FAIL_UNCLOSED_COND
;
1216 wps_bufptr
+= skip_end_of_line(wps_bufptr
);
1219 /* End of this line */
1221 if (level
>= 0) /* there are unclosed conditionals */
1223 fail
= PARSE_FAIL_UNCLOSED_COND
;
1228 wps_start_new_subline(data
);
1229 data
->num_lines
++; /* Start a new line */
1231 if ((data
->num_lines
< WPS_MAX_LINES
) &&
1232 (data
->num_sublines
< WPS_MAX_SUBLINES
))
1234 data
->lines
[data
->num_lines
].first_subline_idx
=
1237 data
->sublines
[data
->num_sublines
].first_token_idx
=
1246 unsigned int len
= 1;
1247 const char *string_start
= wps_bufptr
- 1;
1249 /* find the length of the string */
1250 while (*wps_bufptr
&& *wps_bufptr
!= '#' &&
1251 *wps_bufptr
!= '%' && *wps_bufptr
!= ';' &&
1252 *wps_bufptr
!= '<' && *wps_bufptr
!= '>' &&
1253 *wps_bufptr
!= '|' && *wps_bufptr
!= '\n')
1259 /* look if we already have that string */
1263 for (i
= 0, str
= data
->strings
, found
= false;
1264 i
< data
->num_strings
&&
1265 !(found
= (strlen(*str
) == len
&&
1266 strncmp(string_start
, *str
, len
) == 0));
1268 /* If a matching string is found, found is true and i is
1269 the index of the string. If not, found is false */
1271 /* If it's NOT a duplicate, do nothing if we already have
1272 too many unique strings */
1274 (stringbuf_used
< STRING_BUFFER_SIZE
- 1 &&
1275 data
->num_strings
< WPS_MAX_STRINGS
))
1282 if (stringbuf_used
+ len
> STRING_BUFFER_SIZE
- 1)
1283 len
= STRING_BUFFER_SIZE
- stringbuf_used
- 1;
1285 strncpy(stringbuf
, string_start
, len
);
1286 *(stringbuf
+ len
) = '\0';
1288 data
->strings
[data
->num_strings
] = stringbuf
;
1289 stringbuf
+= len
+ 1;
1290 stringbuf_used
+= len
+ 1;
1291 data
->tokens
[data
->num_tokens
].value
.i
=
1293 data
->num_strings
++;
1297 /* another ocurrence of an existing string */
1298 data
->tokens
[data
->num_tokens
].value
.i
= i
;
1300 data
->tokens
[data
->num_tokens
].type
= WPS_TOKEN_STRING
;
1308 if (!fail
&& level
>= 0) /* there are unclosed conditionals */
1309 fail
= PARSE_FAIL_UNCLOSED_COND
;
1311 data
->viewports
[data
->num_viewports
].last_line
= data
->num_lines
- 1;
1313 /* We have finished with the last viewport, so increment count */
1314 data
->num_viewports
++;
1317 print_debug_info(data
, fail
, line
);
1323 #ifdef HAVE_LCD_BITMAP
1324 /* Clear the WPS image cache */
1325 static void wps_images_clear(struct wps_data
*data
)
1328 /* set images to unloaded and not displayed */
1329 for (i
= 0; i
< MAX_IMAGES
; i
++)
1331 data
->img
[i
].loaded
= false;
1332 data
->img
[i
].display
= -1;
1333 data
->img
[i
].always_display
= false;
1334 data
->img
[i
].num_subimages
= 1;
1336 data
->progressbar
.have_bitmap_pb
= false;
1340 /* initial setup of wps_data */
1341 void wps_data_init(struct wps_data
*wps_data
)
1343 #ifdef HAVE_LCD_BITMAP
1344 wps_images_clear(wps_data
);
1345 wps_data
->wps_sb_tag
= false;
1346 wps_data
->show_sb_on_wps
= false;
1347 wps_data
->img_buf_ptr
= wps_data
->img_buf
; /* where in image buffer */
1348 wps_data
->img_buf_free
= IMG_BUFSIZE
; /* free space in image buffer */
1349 wps_data
->peak_meter_enabled
= false;
1350 #else /* HAVE_LCD_CHARCELLS */
1352 for (i
= 0; i
< 8; i
++)
1354 wps_data
->wps_progress_pat
[i
] = 0;
1356 wps_data
->full_line_progressbar
= false;
1358 wps_data
->wps_loaded
= false;
1361 static void wps_reset(struct wps_data
*data
)
1363 #ifdef HAVE_REMOTE_LCD
1364 bool rwps
= data
->remote_wps
; /* remember whether the data is for a RWPS */
1366 memset(data
, 0, sizeof(*data
));
1367 #ifdef HAVE_ALBUMART
1368 data
->wps_uses_albumart
= WPS_ALBUMART_NONE
;
1370 wps_data_init(data
);
1371 #ifdef HAVE_REMOTE_LCD
1372 data
->remote_wps
= rwps
;
1376 #ifdef HAVE_LCD_BITMAP
1378 static bool load_wps_bitmaps(struct wps_data
*wps_data
, char *bmpdir
)
1380 char img_path
[MAX_PATH
];
1381 struct bitmap
*bitmap
;
1384 for (n
= 0; n
< BACKDROP_BMP
; n
++)
1388 get_image_filename(bmp_names
[n
], bmpdir
,
1389 img_path
, sizeof(img_path
));
1391 if (n
== PROGRESSBAR_BMP
) {
1392 /* progressbar bitmap */
1393 bitmap
= &wps_data
->progressbar
.bm
;
1394 loaded
= &wps_data
->progressbar
.have_bitmap_pb
;
1396 /* regular bitmap */
1397 bitmap
= &wps_data
->img
[n
].bm
;
1398 loaded
= &wps_data
->img
[n
].loaded
;
1401 /* load the image */
1402 bitmap
->data
= wps_data
->img_buf_ptr
;
1403 if (load_bitmap(wps_data
, img_path
, bitmap
))
1407 /* Calculate and store height if this image has sub-images */
1409 wps_data
->img
[n
].subimage_height
= wps_data
->img
[n
].bm
.height
/
1410 wps_data
->img
[n
].num_subimages
;
1414 /* Abort if we can't load an image */
1415 DEBUGF("ERR: Failed to load image %d - %s\n",n
,img_path
);
1421 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
1422 if (bmp_names
[BACKDROP_BMP
])
1424 get_image_filename(bmp_names
[BACKDROP_BMP
], bmpdir
,
1425 img_path
, sizeof(img_path
));
1427 #if defined(HAVE_REMOTE_LCD)
1428 /* We only need to check LCD type if there is a remote LCD */
1429 if (!wps_data
->remote_wps
)
1432 /* Load backdrop for the main LCD */
1433 if (!load_wps_backdrop(img_path
))
1436 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1439 /* Load backdrop for the remote LCD */
1440 if (!load_remote_wps_backdrop(img_path
))
1445 #endif /* has backdrop support */
1447 /* If we got here, everything was OK */
1451 #endif /* HAVE_LCD_BITMAP */
1453 /* Skip leading UTF-8 BOM, if present. */
1454 static char *skip_utf8_bom(char *buf
)
1456 unsigned char *s
= (unsigned char *)buf
;
1458 if(s
[0] == 0xef && s
[1] == 0xbb && s
[2] == 0xbf)
1466 /* to setup up the wps-data from a format-buffer (isfile = false)
1467 from a (wps-)file (isfile = true)*/
1468 bool wps_data_load(struct wps_data
*wps_data
,
1469 struct screen
*display
,
1473 if (!wps_data
|| !buf
)
1476 wps_reset(wps_data
);
1478 /* Initialise the first (default) viewport */
1479 wps_data
->viewports
[0].vp
.x
= 0;
1480 wps_data
->viewports
[0].vp
.y
= 0;
1481 wps_data
->viewports
[0].vp
.width
= display
->width
;
1482 wps_data
->viewports
[0].vp
.height
= display
->height
;
1483 #ifdef HAVE_LCD_BITMAP
1484 wps_data
->viewports
[0].vp
.font
= FONT_UI
;
1485 wps_data
->viewports
[0].vp
.drawmode
= DRMODE_SOLID
;
1487 wps_data
->viewports
[0].vp
.xmargin
= display
->getxmargin();
1488 wps_data
->viewports
[0].vp
.ymargin
= display
->getymargin();
1490 if (display
->depth
> 1)
1492 wps_data
->viewports
[0].vp
.fg_pattern
= display
->get_foreground();
1493 wps_data
->viewports
[0].vp
.bg_pattern
= display
->get_background();
1498 return wps_parse(wps_data
, buf
);
1503 * Hardcode loading WPS_DEFAULTCFG to cause a reset ideally this
1504 * wants to be a virtual file. Feel free to modify dirbrowse()
1505 * if you're feeling brave.
1508 if (! strcmp(buf
, WPS_DEFAULTCFG
) )
1510 global_settings
.wps_file
[0] = 0;
1514 #ifdef HAVE_REMOTE_LCD
1515 if (! strcmp(buf
, RWPS_DEFAULTCFG
) )
1517 global_settings
.rwps_file
[0] = 0;
1521 #endif /* __PCTOOL__ */
1523 int fd
= open(buf
, O_RDONLY
);
1528 /* get buffer space from the plugin buffer */
1529 size_t buffersize
= 0;
1530 char *wps_buffer
= (char *)plugin_get_buffer(&buffersize
);
1535 /* copy the file's content to the buffer for parsing,
1536 ensuring that every line ends with a newline char. */
1537 unsigned int start
= 0;
1538 while(read_line(fd
, wps_buffer
+ start
, buffersize
- start
) > 0)
1540 start
+= strlen(wps_buffer
+ start
);
1541 if (start
< buffersize
- 1)
1543 wps_buffer
[start
++] = '\n';
1544 wps_buffer
[start
] = 0;
1553 #ifdef HAVE_LCD_BITMAP
1554 /* Set all filename pointers to NULL */
1555 memset(bmp_names
, 0, sizeof(bmp_names
));
1558 /* Skip leading UTF-8 BOM, if present. */
1559 wps_buffer
= skip_utf8_bom(wps_buffer
);
1561 /* parse the WPS source */
1562 if (!wps_parse(wps_data
, wps_buffer
)) {
1563 wps_reset(wps_data
);
1567 wps_data
->wps_loaded
= true;
1569 #ifdef HAVE_LCD_BITMAP
1570 /* get the bitmap dir */
1571 char bmpdir
[MAX_PATH
];
1573 char *dot
= strrchr(buf
, '.');
1574 bmpdirlen
= dot
- buf
;
1575 strncpy(bmpdir
, buf
, dot
- buf
);
1576 bmpdir
[bmpdirlen
] = 0;
1578 /* load the bitmaps that were found by the parsing */
1579 if (!load_wps_bitmaps(wps_data
, bmpdir
)) {
1580 wps_reset(wps_data
);
1588 int wps_subline_index(struct wps_data
*data
, int line
, int subline
)
1590 return data
->lines
[line
].first_subline_idx
+ subline
;
1593 int wps_first_token_index(struct wps_data
*data
, int line
, int subline
)
1595 int first_subline_idx
= data
->lines
[line
].first_subline_idx
;
1596 return data
->sublines
[first_subline_idx
+ subline
].first_token_idx
;
1599 int wps_last_token_index(struct wps_data
*data
, int line
, int subline
)
1601 int first_subline_idx
= data
->lines
[line
].first_subline_idx
;
1602 int idx
= first_subline_idx
+ subline
;
1603 if (idx
< data
->num_sublines
- 1)
1605 /* This subline ends where the next begins */
1606 return data
->sublines
[idx
+1].first_token_idx
- 1;
1610 /* The last subline goes to the end */
1611 return data
->num_tokens
- 1;