blob: e89f2692cf866872ae52a5fbe2b14cbdf17e196a [file] [log] [blame]
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Nicolas Pennequinab90d582007-04-04 14:41:40 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
Dave Chapmanb9bb7232008-03-26 18:18:22 +000022#include <stdio.h>
23#include <string.h>
Bertrik Sikken28434692008-04-28 16:18:04 +000024#include <stdlib.h>
Dave Chapmanb9bb7232008-03-26 18:18:22 +000025#include "gwps.h"
Dave Chapman78d29f52008-03-26 23:35:34 +000026#include "file.h"
27#include "misc.h"
Nils Wallméniusa21004d2008-05-19 14:37:16 +000028#include "plugin.h"
29
Dave Chapmanb9bb7232008-03-26 18:18:22 +000030#ifdef __PCTOOL__
31#define DEBUGF printf
32#define FONT_SYSFIXED 0
33#define FONT_UI 1
34#else
35#include "debug.h"
36#endif
37
38#ifndef __PCTOOL__
Nicolas Pennequinab90d582007-04-04 14:41:40 +000039#include <ctype.h>
40#include <stdbool.h>
Nicolas Pennequinab90d582007-04-04 14:41:40 +000041#include <string.h>
Dave Chapmanb9bb7232008-03-26 18:18:22 +000042#include "font.h"
43
Nicolas Pennequinab90d582007-04-04 14:41:40 +000044#include "gwps.h"
45#include "settings.h"
Nicolas Pennequinab90d582007-04-04 14:41:40 +000046
47#ifdef HAVE_LCD_BITMAP
48#include "bmp.h"
Nicolas Pennequinab90d582007-04-04 14:41:40 +000049#endif
Nicolas Pennequin1cf2ec32007-04-25 22:08:00 +000050
Nicolas Pennequin1cf2ec32007-04-25 22:08:00 +000051#include "backdrop.h"
Nicolas Pennequinab90d582007-04-04 14:41:40 +000052
Dave Chapmanf0d4fc62007-05-29 19:00:36 +000053#endif
54
Nicolas Pennequinab90d582007-04-04 14:41:40 +000055#define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps"
56#define RWPS_DEFAULTCFG WPS_DIR "/rockbox_default.rwps"
57
Nicolas Pennequin31f76112007-11-14 22:02:41 +000058#define WPS_ERROR_INVALID_PARAM -1
59
60#define PARSE_FAIL_UNCLOSED_COND 1
61#define PARSE_FAIL_INVALID_CHAR 2
62#define PARSE_FAIL_COND_SYNTAX_ERROR 3
63#define PARSE_FAIL_COND_INVALID_PARAM 4
Nicolas Pennequind7fd9892007-04-24 00:57:04 +000064
Nicolas Pennequinab90d582007-04-04 14:41:40 +000065/* level of current conditional.
66 -1 means we're not in a conditional. */
Nicolas Pennequin830a3a42007-04-04 15:47:51 +000067static int level = -1;
Nicolas Pennequinab90d582007-04-04 14:41:40 +000068
69/* index of the last WPS_TOKEN_CONDITIONAL_OPTION
70 or WPS_TOKEN_CONDITIONAL_START in current level */
Nicolas Pennequin830a3a42007-04-04 15:47:51 +000071static int lastcond[WPS_MAX_COND_LEVEL];
Nicolas Pennequinab90d582007-04-04 14:41:40 +000072
73/* index of the WPS_TOKEN_CONDITIONAL in current level */
Nicolas Pennequin830a3a42007-04-04 15:47:51 +000074static int condindex[WPS_MAX_COND_LEVEL];
Nicolas Pennequinab90d582007-04-04 14:41:40 +000075
76/* number of condtional options in current level */
Nicolas Pennequin830a3a42007-04-04 15:47:51 +000077static int numoptions[WPS_MAX_COND_LEVEL];
Nicolas Pennequinab90d582007-04-04 14:41:40 +000078
Nicolas Pennequind7fd9892007-04-24 00:57:04 +000079/* the current line in the file */
80static int line;
81
Nicolas Pennequinab90d582007-04-04 14:41:40 +000082#ifdef HAVE_LCD_BITMAP
Nicolas Pennequin887b31c2007-06-05 14:57:07 +000083
84#if LCD_DEPTH > 1
Jonathan Gordon5a169bb2008-06-23 06:04:17 +000085#define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS+1) /* WPS images + pbar bitmap + backdrop */
Nicolas Pennequin887b31c2007-06-05 14:57:07 +000086#else
Jonathan Gordon5a169bb2008-06-23 06:04:17 +000087#define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS) /* WPS images + pbar bitmap */
Nicolas Pennequin887b31c2007-06-05 14:57:07 +000088#endif
89
90#define PROGRESSBAR_BMP MAX_IMAGES
Jonathan Gordon5a169bb2008-06-23 06:04:17 +000091#define BACKDROP_BMP (MAX_BITMAPS-1)
Nicolas Pennequin887b31c2007-06-05 14:57:07 +000092
Nicolas Pennequinab90d582007-04-04 14:41:40 +000093/* pointers to the bitmap filenames in the WPS source */
Nicolas Pennequinb5f4d902007-06-05 10:42:41 +000094static const char *bmp_names[MAX_BITMAPS];
Nicolas Pennequin887b31c2007-06-05 14:57:07 +000095
96#endif /* HAVE_LCD_BITMAP */
Nicolas Pennequinab90d582007-04-04 14:41:40 +000097
98#ifdef DEBUG
Nicolas Pennequin6ac306a2007-04-24 23:58:57 +000099/* debugging function */
100extern void print_debug_info(struct wps_data *data, int fail, int line);
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000101#endif
102
Nicolas Pennequind7fd9892007-04-24 00:57:04 +0000103static void wps_reset(struct wps_data *data);
104
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000105/* Function for parsing of details for a token. At the moment the
106 function is called, the token type has already been set. The
107 function must fill in the details and possibly add more tokens
108 to the token array. It should return the number of chars that
109 has been consumed.
110
111 wps_bufptr points to the char following the tag (i.e. where
112 details begin).
113 token is the pointer to the 'main' token being parsed
114 */
115typedef int (*wps_tag_parse_func)(const char *wps_bufptr,
116 struct wps_token *token, struct wps_data *wps_data);
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000117
118struct wps_tag {
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000119 enum wps_token_type type;
Dan Everton86c0e3a2007-04-05 10:21:49 +0000120 const char name[3];
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000121 unsigned char refresh_type;
Dan Everton86c0e3a2007-04-05 10:21:49 +0000122 const wps_tag_parse_func parse_func;
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000123};
124
125/* prototypes of all special parse functions : */
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000126static int parse_subline_timeout(const char *wps_bufptr,
127 struct wps_token *token, struct wps_data *wps_data);
128static int parse_progressbar(const char *wps_bufptr,
129 struct wps_token *token, struct wps_data *wps_data);
130static int parse_dir_level(const char *wps_bufptr,
131 struct wps_token *token, struct wps_data *wps_data);
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000132
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000133#ifdef HAVE_LCD_BITMAP
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000134static int parse_viewport_display(const char *wps_bufptr,
135 struct wps_token *token, struct wps_data *wps_data);
Dave Chapmand02c79c2008-03-21 19:38:00 +0000136static int parse_viewport(const char *wps_bufptr,
137 struct wps_token *token, struct wps_data *wps_data);
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000138static int parse_statusbar_enable(const char *wps_bufptr,
139 struct wps_token *token, struct wps_data *wps_data);
140static int parse_statusbar_disable(const char *wps_bufptr,
141 struct wps_token *token, struct wps_data *wps_data);
142static int parse_image_display(const char *wps_bufptr,
143 struct wps_token *token, struct wps_data *wps_data);
144static int parse_image_load(const char *wps_bufptr,
145 struct wps_token *token, struct wps_data *wps_data);
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000146#endif /*HAVE_LCD_BITMAP */
Jonathan Gordon082f50b2008-06-23 06:17:22 +0000147#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
148static int parse_image_special(const char *wps_bufptr,
149 struct wps_token *token, struct wps_data *wps_data);
150#endif
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000151#ifdef HAVE_ALBUMART
152static int parse_albumart_load(const char *wps_bufptr,
153 struct wps_token *token, struct wps_data *wps_data);
154static int parse_albumart_conditional(const char *wps_bufptr,
155 struct wps_token *token, struct wps_data *wps_data);
156#endif /* HAVE_ALBUMART */
157
Brandon Low9a550522007-06-16 20:33:30 +0000158#ifdef CONFIG_RTC
159#define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC
160#else
161#define WPS_RTC_REFRESH WPS_REFRESH_STATIC
162#endif
163
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000164/* array of available tags - those with more characters have to go first
165 (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */
166static const struct wps_tag all_tags[] = {
167
Dan Everton86c0e3a2007-04-05 10:21:49 +0000168 { WPS_TOKEN_ALIGN_CENTER, "ac", 0, NULL },
169 { WPS_TOKEN_ALIGN_LEFT, "al", 0, NULL },
170 { WPS_TOKEN_ALIGN_RIGHT, "ar", 0, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000171
Dan Everton86c0e3a2007-04-05 10:21:49 +0000172 { WPS_TOKEN_BATTERY_PERCENT, "bl", WPS_REFRESH_DYNAMIC, NULL },
173 { WPS_TOKEN_BATTERY_VOLTS, "bv", WPS_REFRESH_DYNAMIC, NULL },
174 { WPS_TOKEN_BATTERY_TIME, "bt", WPS_REFRESH_DYNAMIC, NULL },
175 { WPS_TOKEN_BATTERY_SLEEPTIME, "bs", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000176#if CONFIG_CHARGING >= CHARGING_MONITOR
Dan Everton86c0e3a2007-04-05 10:21:49 +0000177 { WPS_TOKEN_BATTERY_CHARGING, "bc", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000178#endif
179#if CONFIG_CHARGING
Dan Everton86c0e3a2007-04-05 10:21:49 +0000180 { WPS_TOKEN_BATTERY_CHARGER_CONNECTED,"bp", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000181#endif
182
Brandon Low9a550522007-06-16 20:33:30 +0000183 { WPS_TOKEN_RTC_DAY_OF_MONTH, "cd", WPS_RTC_REFRESH, NULL },
184 { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED,"ce", WPS_RTC_REFRESH, NULL },
Jonathan Gordon923cbe32007-11-27 01:41:59 +0000185 { WPS_TOKEN_RTC_12HOUR_CFG, "cf", WPS_RTC_REFRESH, NULL },
Brandon Low9a550522007-06-16 20:33:30 +0000186 { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", WPS_RTC_REFRESH, NULL },
187 { WPS_TOKEN_RTC_HOUR_24, "ck", WPS_RTC_REFRESH, NULL },
188 { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", WPS_RTC_REFRESH, NULL },
189 { WPS_TOKEN_RTC_HOUR_12, "cl", WPS_RTC_REFRESH, NULL },
190 { WPS_TOKEN_RTC_MONTH, "cm", WPS_RTC_REFRESH, NULL },
191 { WPS_TOKEN_RTC_MINUTE, "cM", WPS_RTC_REFRESH, NULL },
192 { WPS_TOKEN_RTC_SECOND, "cS", WPS_RTC_REFRESH, NULL },
193 { WPS_TOKEN_RTC_YEAR_2_DIGITS, "cy", WPS_RTC_REFRESH, NULL },
194 { WPS_TOKEN_RTC_YEAR_4_DIGITS, "cY", WPS_RTC_REFRESH, NULL },
195 { WPS_TOKEN_RTC_AM_PM_UPPER, "cP", WPS_RTC_REFRESH, NULL },
196 { WPS_TOKEN_RTC_AM_PM_LOWER, "cp", WPS_RTC_REFRESH, NULL },
197 { WPS_TOKEN_RTC_WEEKDAY_NAME, "ca", WPS_RTC_REFRESH, NULL },
198 { WPS_TOKEN_RTC_MONTH_NAME, "cb", WPS_RTC_REFRESH, NULL },
199 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", WPS_RTC_REFRESH, NULL },
200 { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", WPS_RTC_REFRESH, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000201
202 /* current file */
Dan Everton86c0e3a2007-04-05 10:21:49 +0000203 { WPS_TOKEN_FILE_BITRATE, "fb", WPS_REFRESH_STATIC, NULL },
204 { WPS_TOKEN_FILE_CODEC, "fc", WPS_REFRESH_STATIC, NULL },
205 { WPS_TOKEN_FILE_FREQUENCY, "ff", WPS_REFRESH_STATIC, NULL },
Nicolas Pennequin5cc98ef2007-05-21 13:41:43 +0000206 { WPS_TOKEN_FILE_FREQUENCY_KHZ, "fk", WPS_REFRESH_STATIC, NULL },
Dan Everton86c0e3a2007-04-05 10:21:49 +0000207 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", WPS_REFRESH_STATIC, NULL },
208 { WPS_TOKEN_FILE_NAME, "fn", WPS_REFRESH_STATIC, NULL },
209 { WPS_TOKEN_FILE_PATH, "fp", WPS_REFRESH_STATIC, NULL },
210 { WPS_TOKEN_FILE_SIZE, "fs", WPS_REFRESH_STATIC, NULL },
211 { WPS_TOKEN_FILE_VBR, "fv", WPS_REFRESH_STATIC, NULL },
Nicolas Pennequinaa220d52007-05-02 17:51:01 +0000212 { WPS_TOKEN_FILE_DIRECTORY, "d", WPS_REFRESH_STATIC,
213 parse_dir_level },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000214
215 /* next file */
Dan Everton86c0e3a2007-04-05 10:21:49 +0000216 { WPS_TOKEN_FILE_BITRATE, "Fb", WPS_REFRESH_DYNAMIC, NULL },
217 { WPS_TOKEN_FILE_CODEC, "Fc", WPS_REFRESH_DYNAMIC, NULL },
218 { WPS_TOKEN_FILE_FREQUENCY, "Ff", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequin392d0792007-05-21 14:04:38 +0000219 { WPS_TOKEN_FILE_FREQUENCY_KHZ, "Fk", WPS_REFRESH_DYNAMIC, NULL },
Dan Everton86c0e3a2007-04-05 10:21:49 +0000220 { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", WPS_REFRESH_DYNAMIC, NULL },
221 { WPS_TOKEN_FILE_NAME, "Fn", WPS_REFRESH_DYNAMIC, NULL },
222 { WPS_TOKEN_FILE_PATH, "Fp", WPS_REFRESH_DYNAMIC, NULL },
223 { WPS_TOKEN_FILE_SIZE, "Fs", WPS_REFRESH_DYNAMIC, NULL },
224 { WPS_TOKEN_FILE_VBR, "Fv", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinaa220d52007-05-02 17:51:01 +0000225 { WPS_TOKEN_FILE_DIRECTORY, "D", WPS_REFRESH_DYNAMIC,
226 parse_dir_level },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000227
228 /* current metadata */
Dan Everton86c0e3a2007-04-05 10:21:49 +0000229 { WPS_TOKEN_METADATA_ARTIST, "ia", WPS_REFRESH_STATIC, NULL },
230 { WPS_TOKEN_METADATA_COMPOSER, "ic", WPS_REFRESH_STATIC, NULL },
231 { WPS_TOKEN_METADATA_ALBUM, "id", WPS_REFRESH_STATIC, NULL },
232 { WPS_TOKEN_METADATA_ALBUM_ARTIST, "iA", WPS_REFRESH_STATIC, NULL },
Dan Evertoneecfe9f2007-08-08 10:19:56 +0000233 { WPS_TOKEN_METADATA_GROUPING, "iG", WPS_REFRESH_STATIC, NULL },
Dan Everton86c0e3a2007-04-05 10:21:49 +0000234 { WPS_TOKEN_METADATA_GENRE, "ig", WPS_REFRESH_STATIC, NULL },
Dan Evertonf4a61f02007-08-03 10:00:42 +0000235 { WPS_TOKEN_METADATA_DISC_NUMBER, "ik", WPS_REFRESH_STATIC, NULL },
Dan Everton86c0e3a2007-04-05 10:21:49 +0000236 { WPS_TOKEN_METADATA_TRACK_NUMBER, "in", WPS_REFRESH_STATIC, NULL },
237 { WPS_TOKEN_METADATA_TRACK_TITLE, "it", WPS_REFRESH_STATIC, NULL },
238 { WPS_TOKEN_METADATA_VERSION, "iv", WPS_REFRESH_STATIC, NULL },
239 { WPS_TOKEN_METADATA_YEAR, "iy", WPS_REFRESH_STATIC, NULL },
Nicolas Pennequinaa220d52007-05-02 17:51:01 +0000240 { WPS_TOKEN_METADATA_COMMENT, "iC", WPS_REFRESH_STATIC, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000241
242 /* next metadata */
Dan Everton86c0e3a2007-04-05 10:21:49 +0000243 { WPS_TOKEN_METADATA_ARTIST, "Ia", WPS_REFRESH_DYNAMIC, NULL },
244 { WPS_TOKEN_METADATA_COMPOSER, "Ic", WPS_REFRESH_DYNAMIC, NULL },
245 { WPS_TOKEN_METADATA_ALBUM, "Id", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinaa220d52007-05-02 17:51:01 +0000246 { WPS_TOKEN_METADATA_ALBUM_ARTIST, "IA", WPS_REFRESH_DYNAMIC, NULL },
Dan Evertoneecfe9f2007-08-08 10:19:56 +0000247 { WPS_TOKEN_METADATA_GROUPING, "IG", WPS_REFRESH_DYNAMIC, NULL },
Dan Everton86c0e3a2007-04-05 10:21:49 +0000248 { WPS_TOKEN_METADATA_GENRE, "Ig", WPS_REFRESH_DYNAMIC, NULL },
Dan Evertonf4a61f02007-08-03 10:00:42 +0000249 { WPS_TOKEN_METADATA_DISC_NUMBER, "Ik", WPS_REFRESH_DYNAMIC, NULL },
Dan Everton86c0e3a2007-04-05 10:21:49 +0000250 { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_DYNAMIC, NULL },
251 { WPS_TOKEN_METADATA_TRACK_TITLE, "It", WPS_REFRESH_DYNAMIC, NULL },
252 { WPS_TOKEN_METADATA_VERSION, "Iv", WPS_REFRESH_DYNAMIC, NULL },
253 { WPS_TOKEN_METADATA_YEAR, "Iy", WPS_REFRESH_DYNAMIC, NULL },
254 { WPS_TOKEN_METADATA_COMMENT, "IC", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000255
Nicolas Pennequin830a3a42007-04-04 15:47:51 +0000256#if (CONFIG_CODEC != MAS3507D)
Dan Everton86c0e3a2007-04-05 10:21:49 +0000257 { WPS_TOKEN_SOUND_PITCH, "Sp", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000258#endif
259
260#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
Dan Everton86c0e3a2007-04-05 10:21:49 +0000261 { WPS_TOKEN_VLED_HDD, "lh", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000262#endif
263
Dan Everton86c0e3a2007-04-05 10:21:49 +0000264 { WPS_TOKEN_MAIN_HOLD, "mh", WPS_REFRESH_DYNAMIC, NULL },
Marianne Arnold74aabc82007-06-25 20:54:11 +0000265
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000266#ifdef HAS_REMOTE_BUTTON_HOLD
Dan Everton86c0e3a2007-04-05 10:21:49 +0000267 { WPS_TOKEN_REMOTE_HOLD, "mr", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinf554e002007-11-14 00:45:04 +0000268#else
269 { WPS_TOKEN_UNKNOWN, "mr", 0, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000270#endif
271
Dan Everton86c0e3a2007-04-05 10:21:49 +0000272 { WPS_TOKEN_REPEAT_MODE, "mm", WPS_REFRESH_DYNAMIC, NULL },
273 { WPS_TOKEN_PLAYBACK_STATUS, "mp", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000274
275#ifdef HAVE_LCD_BITMAP
Nicolas Pennequinaa220d52007-05-02 17:51:01 +0000276 { WPS_TOKEN_PEAKMETER, "pm", WPS_REFRESH_PEAK_METER, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000277#else
Nicolas Pennequinaa220d52007-05-02 17:51:01 +0000278 { WPS_TOKEN_PLAYER_PROGRESSBAR, "pf",
279 WPS_REFRESH_DYNAMIC | WPS_REFRESH_PLAYER_PROGRESS, parse_progressbar },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000280#endif
Nicolas Pennequinaa220d52007-05-02 17:51:01 +0000281 { WPS_TOKEN_PROGRESSBAR, "pb", WPS_REFRESH_PLAYER_PROGRESS,
282 parse_progressbar },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000283
Dan Everton86c0e3a2007-04-05 10:21:49 +0000284 { WPS_TOKEN_VOLUME, "pv", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000285
Nicolas Pennequin29407cb2007-07-25 14:14:47 +0000286 { WPS_TOKEN_TRACK_ELAPSED_PERCENT, "px", WPS_REFRESH_DYNAMIC, NULL },
Dan Everton86c0e3a2007-04-05 10:21:49 +0000287 { 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 },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000290
Dan Everton86c0e3a2007-04-05 10:21:49 +0000291 { 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 },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000295
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000296#ifdef HAVE_TAGCACHE
Dan Everton86c0e3a2007-04-05 10:21:49 +0000297 { WPS_TOKEN_DATABASE_PLAYCOUNT, "rp", WPS_REFRESH_DYNAMIC, NULL },
298 { WPS_TOKEN_DATABASE_RATING, "rr", WPS_REFRESH_DYNAMIC, NULL },
Miika Pekkarinenf53a8f82007-04-15 15:46:46 +0000299 { WPS_TOKEN_DATABASE_AUTOSCORE, "ra", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000300#endif
301
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000302#if CONFIG_CODEC == SWCODEC
Dan Everton86c0e3a2007-04-05 10:21:49 +0000303 { WPS_TOKEN_REPLAYGAIN, "rg", WPS_REFRESH_STATIC, NULL },
Nicolas Pennequin27cbf6b2007-04-12 16:15:34 +0000304 { WPS_TOKEN_CROSSFADE, "xf", WPS_REFRESH_DYNAMIC, NULL },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000305#endif
306
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000307 { WPS_NO_TOKEN, "s", WPS_REFRESH_SCROLL, NULL },
Dan Everton86c0e3a2007-04-05 10:21:49 +0000308 { WPS_TOKEN_SUBLINE_TIMEOUT, "t", 0, parse_subline_timeout },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000309
310#ifdef HAVE_LCD_BITMAP
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000311 { WPS_NO_TOKEN, "we", 0, parse_statusbar_enable },
312 { WPS_NO_TOKEN, "wd", 0, parse_statusbar_disable },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000313
Dan Everton86c0e3a2007-04-05 10:21:49 +0000314 { WPS_NO_TOKEN, "xl", 0, parse_image_load },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000315
Nicolas Pennequinaa220d52007-05-02 17:51:01 +0000316 { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", WPS_REFRESH_STATIC,
317 parse_image_display },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000318
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000319 { WPS_TOKEN_IMAGE_DISPLAY, "x", 0, parse_image_load },
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000320#ifdef HAVE_ALBUMART
321 { WPS_NO_TOKEN, "Cl", 0, parse_albumart_load },
Nicolas Pennequin81dedee2007-11-12 01:31:42 +0000322 { WPS_TOKEN_ALBUMART_DISPLAY, "C", WPS_REFRESH_STATIC,
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000323 parse_albumart_conditional },
324#endif
Dave Chapmand02c79c2008-03-21 19:38:00 +0000325
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000326 { WPS_VIEWPORT_ENABLE, "Vd", WPS_REFRESH_DYNAMIC,
327 parse_viewport_display },
Dave Chapmand02c79c2008-03-21 19:38:00 +0000328 { WPS_NO_TOKEN, "V", 0, parse_viewport },
329
Dave Chapmand746b792008-03-29 01:14:10 +0000330#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000331 { WPS_TOKEN_IMAGE_BACKDROP, "X", 0, parse_image_special },
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000332#endif
333#endif
334
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000335 { WPS_TOKEN_UNKNOWN, "", 0, NULL }
336 /* the array MUST end with an empty string (first char is \0) */
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000337};
338
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000339/* Returns the number of chars that should be skipped to jump
340 immediately after the first eol, i.e. to the start of the next line */
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000341static int skip_end_of_line(const char *wps_bufptr)
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000342{
Nicolas Pennequind7fd9892007-04-24 00:57:04 +0000343 line++;
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000344 int skip = 0;
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000345 while(*(wps_bufptr + skip) != '\n')
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000346 skip++;
347 return ++skip;
348}
349
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000350/* Starts a new subline in the current line during parsing */
Nicolas Pennequin2e1169b2007-04-15 02:59:34 +0000351static void wps_start_new_subline(struct wps_data *data)
352{
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000353 data->num_sublines++;
354 data->sublines[data->num_sublines].first_token_idx = data->num_tokens;
Dave Chapman45b2d882008-03-22 00:31:22 +0000355 data->lines[data->num_lines].num_sublines++;
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000356}
357
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000358#ifdef HAVE_LCD_BITMAP
359
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000360static int parse_statusbar_enable(const char *wps_bufptr,
361 struct wps_token *token,
362 struct wps_data *wps_data)
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000363{
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000364 (void)token; /* Kill warnings */
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000365 wps_data->wps_sb_tag = true;
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000366 wps_data->show_sb_on_wps = true;
Jonathan Gordonbdbdb972008-06-23 13:20:35 +0000367 if (wps_data->viewports[0].vp.y == 0)
368 {
369 wps_data->viewports[0].vp.y = STATUSBAR_HEIGHT;
370 wps_data->viewports[0].vp.height -= STATUSBAR_HEIGHT;
371 }
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000372 return skip_end_of_line(wps_bufptr);
373}
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000374
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000375static int parse_statusbar_disable(const char *wps_bufptr,
376 struct wps_token *token,
377 struct wps_data *wps_data)
378{
379 (void)token; /* Kill warnings */
380 wps_data->wps_sb_tag = true;
381 wps_data->show_sb_on_wps = false;
Jonathan Gordonbdbdb972008-06-23 13:20:35 +0000382 if (wps_data->viewports[0].vp.y == STATUSBAR_HEIGHT)
383 {
384 wps_data->viewports[0].vp.y = 0;
385 wps_data->viewports[0].vp.height += STATUSBAR_HEIGHT;
386 }
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000387 return skip_end_of_line(wps_bufptr);
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000388}
389
390static bool load_bitmap(struct wps_data *wps_data,
391 char* filename,
392 struct bitmap *bm)
393{
Nicolas Pennequin2a2b8d82007-04-25 13:09:56 +0000394 int format;
395#ifdef HAVE_REMOTE_LCD
396 if (wps_data->remote_wps)
397 format = FORMAT_ANY|FORMAT_REMOTE;
398 else
399#endif
400 format = FORMAT_ANY|FORMAT_TRANSPARENT;
401
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000402 int ret = read_bmp_file(filename, bm,
403 wps_data->img_buf_free,
Nicolas Pennequin2a2b8d82007-04-25 13:09:56 +0000404 format);
Dave Chapman3d88edd2008-03-26 20:19:39 +0000405
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000406 if (ret > 0)
407 {
408#if LCD_DEPTH == 16
409 if (ret % 2) ret++;
410 /* Always consume an even number of bytes */
411#endif
412 wps_data->img_buf_ptr += ret;
413 wps_data->img_buf_free -= ret;
414
415 return true;
416 }
417 else
418 return false;
419}
420
421static int get_image_id(int c)
422{
423 if(c >= 'a' && c <= 'z')
424 return c - 'a';
425 else if(c >= 'A' && c <= 'Z')
426 return c - 'A' + 26;
427 else
428 return -1;
429}
430
431static char *get_image_filename(const char *start, const char* bmpdir,
432 char *buf, int buf_size)
433{
434 const char *end = strchr(start, '|');
435
436 if ( !end || (end - start) >= (buf_size - ROCKBOX_DIR_LEN - 2) )
437 {
438 buf = "\0";
439 return NULL;
440 }
441
442 int bmpdirlen = strlen(bmpdir);
443
444 strcpy(buf, bmpdir);
445 buf[bmpdirlen] = '/';
446 memcpy( &buf[bmpdirlen + 1], start, end - start);
447 buf[bmpdirlen + 1 + end - start] = 0;
448
449 return buf;
450}
451
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000452static int parse_image_display(const char *wps_bufptr,
453 struct wps_token *token,
454 struct wps_data *wps_data)
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000455{
Nicolas Pennequin720cfe32007-11-18 15:32:45 +0000456 (void)wps_data;
Dave Chapman15ddd7a2008-03-23 20:31:00 +0000457 int n = get_image_id(wps_bufptr[0]);
458 int subimage;
Nicolas Pennequin32bd59d2007-04-14 16:20:33 +0000459
460 if (n == -1)
461 {
462 /* invalid picture display tag */
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000463 return WPS_ERROR_INVALID_PARAM;
Nicolas Pennequin32bd59d2007-04-14 16:20:33 +0000464 }
465
Dave Chapman15ddd7a2008-03-23 20:31:00 +0000466 if ((subimage = get_image_id(wps_bufptr[1])) != -1)
467 {
Dave Chapman99c09782008-03-24 00:03:05 +0000468 /* Sanity check */
469 if (subimage >= wps_data->img[n].num_subimages)
470 return WPS_ERROR_INVALID_PARAM;
471
Dave Chapman15ddd7a2008-03-23 20:31:00 +0000472 /* Store sub-image number to display in high bits */
473 token->value.i = n | (subimage << 8);
474 return 2; /* We have consumed 2 bytes */
475 } else {
476 token->value.i = n;
477 return 1; /* We have consumed 1 byte */
478 }
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000479}
480
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000481static int parse_image_load(const char *wps_bufptr,
482 struct wps_token *token,
483 struct wps_data *wps_data)
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000484{
485 int n;
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000486 const char *ptr = wps_bufptr;
Dave Chapman15ddd7a2008-03-23 20:31:00 +0000487 const char *pos;
Dave Chapmane92d2c52008-03-21 13:41:35 +0000488 const char* filename;
489 const char* id;
Dave Chapman15ddd7a2008-03-23 20:31:00 +0000490 const char *newline;
Dave Chapmane92d2c52008-03-21 13:41:35 +0000491 int x,y;
492
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000493 /* format: %x|n|filename.bmp|x|y|
Dave Chapman15ddd7a2008-03-23 20:31:00 +0000494 or %xl|n|filename.bmp|x|y|
495 or %xl|n|filename.bmp|x|y|num_subimages|
496 */
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000497
Dave Chapmane92d2c52008-03-21 13:41:35 +0000498 if (*ptr != '|')
499 return WPS_ERROR_INVALID_PARAM;
Nicolas Pennequin27cbf6b2007-04-12 16:15:34 +0000500
Dave Chapmane92d2c52008-03-21 13:41:35 +0000501 ptr++;
502
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000503 if (!(ptr = parse_list("ssdd", NULL, '|', ptr, &id, &filename, &x, &y)))
Dave Chapmane92d2c52008-03-21 13:41:35 +0000504 return WPS_ERROR_INVALID_PARAM;
505
506 /* Check there is a terminating | */
507 if (*ptr != '|')
508 return WPS_ERROR_INVALID_PARAM;
Nicolas Pennequin27cbf6b2007-04-12 16:15:34 +0000509
510 /* get the image ID */
Dave Chapmane92d2c52008-03-21 13:41:35 +0000511 n = get_image_id(*id);
Nicolas Pennequin27cbf6b2007-04-12 16:15:34 +0000512
513 /* check the image number and load state */
514 if(n < 0 || n >= MAX_IMAGES || wps_data->img[n].loaded)
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000515 {
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000516 /* Invalid image ID */
517 return WPS_ERROR_INVALID_PARAM;
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000518 }
519
Dave Chapmane92d2c52008-03-21 13:41:35 +0000520 /* save a pointer to the filename */
521 bmp_names[n] = filename;
Nicolas Pennequin27cbf6b2007-04-12 16:15:34 +0000522
Dave Chapmane92d2c52008-03-21 13:41:35 +0000523 wps_data->img[n].x = x;
524 wps_data->img[n].y = y;
Nicolas Pennequin27cbf6b2007-04-12 16:15:34 +0000525
Dave Chapmand02c79c2008-03-21 19:38:00 +0000526 /* save current viewport */
527 wps_data->img[n].vp = &wps_data->viewports[wps_data->num_viewports].vp;
528
Nicolas Pennequin27cbf6b2007-04-12 16:15:34 +0000529 if (token->type == WPS_TOKEN_IMAGE_DISPLAY)
Dave Chapman15ddd7a2008-03-23 20:31:00 +0000530 {
Nicolas Pennequin27cbf6b2007-04-12 16:15:34 +0000531 wps_data->img[n].always_display = true;
Dave Chapman15ddd7a2008-03-23 20:31:00 +0000532 }
533 else
534 {
535 /* Parse the (optional) number of sub-images */
536 ptr++;
537 newline = strchr(ptr, '\n');
538 pos = strchr(ptr, '|');
539 if (pos && pos < newline)
540 wps_data->img[n].num_subimages = atoi(ptr);
Dave Chapman6d9c3532008-03-24 10:13:47 +0000541
542 if (wps_data->img[n].num_subimages <= 0)
543 return WPS_ERROR_INVALID_PARAM;
Dave Chapman15ddd7a2008-03-23 20:31:00 +0000544 }
Nicolas Pennequin27cbf6b2007-04-12 16:15:34 +0000545
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000546 /* Skip the rest of the line */
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000547 return skip_end_of_line(wps_bufptr);
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000548}
549
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000550static int parse_viewport_display(const char *wps_bufptr,
551 struct wps_token *token,
552 struct wps_data *wps_data)
553{
554 (void)wps_data;
555 char letter = wps_bufptr[0];
556
557 if (letter < 'a' || letter > 'z')
558 {
559 /* invalid viewport tag */
560 return WPS_ERROR_INVALID_PARAM;
561 }
562 token->value.i = letter;
563 return 1;
564}
565
Dave Chapmand02c79c2008-03-21 19:38:00 +0000566static int parse_viewport(const char *wps_bufptr,
567 struct wps_token *token,
568 struct wps_data *wps_data)
569{
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000570 (void)token; /* Kill warnings */
Dave Chapmand02c79c2008-03-21 19:38:00 +0000571 const char *ptr = wps_bufptr;
572 struct viewport* vp;
573 int depth;
Jonathan Gordonae49b382008-06-07 09:01:02 +0000574 uint32_t set = 0;
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000575 enum {
576 PL_X = 0,
577 PL_Y,
578 PL_WIDTH,
579 PL_HEIGHT,
580 PL_FONT,
581 PL_FG,
582 PL_BG,
583 };
584 int lcd_width = LCD_WIDTH, lcd_height = LCD_HEIGHT;
585#ifdef HAVE_REMOTE_LCD
586 if (wps_data->remote_wps)
587 {
588 lcd_width = LCD_REMOTE_WIDTH;
589 lcd_height = LCD_REMOTE_HEIGHT;
590 }
591#endif
Dave Chapmand02c79c2008-03-21 19:38:00 +0000592
Dave Chapmand02c79c2008-03-21 19:38:00 +0000593 if (wps_data->num_viewports >= WPS_MAX_VIEWPORTS)
594 return WPS_ERROR_INVALID_PARAM;
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000595
Dave Chapmand02c79c2008-03-21 19:38:00 +0000596 wps_data->num_viewports++;
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000597 /* check for the optional letter to signify its a hideable viewport */
598 /* %Vl|<label>|<rest of tags>| */
599 wps_data->viewports[wps_data->num_viewports].hidden_flags = 0;
600
601 if (*ptr == 'l')
602 {
603 if (*(ptr+1) == '|')
604 {
605 char label = *(ptr+2);
Jonathan Gordond8e56e32008-06-25 08:08:39 +0000606 if (label >= 'a' && label <= 'z')
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000607 {
608 wps_data->viewports[wps_data->num_viewports].hidden_flags = VP_DRAW_HIDEABLE;
609 wps_data->viewports[wps_data->num_viewports].label = label;
610 }
611 else
612 return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */
613 ptr += 3;
614 }
615 }
616 if (*ptr != '|')
617 return WPS_ERROR_INVALID_PARAM;
618
619 ptr++;
Dave Chapmand02c79c2008-03-21 19:38:00 +0000620 vp = &wps_data->viewports[wps_data->num_viewports].vp;
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000621 /* format: %V|x|y|width|height|font|fg_pattern|bg_pattern| */
Dave Chapmand02c79c2008-03-21 19:38:00 +0000622
623 /* Set the defaults for fields not user-specified */
624 vp->drawmode = DRMODE_SOLID;
Dave Chapmand02c79c2008-03-21 19:38:00 +0000625
626 /* Work out the depth of this display */
627#ifdef HAVE_REMOTE_LCD
628 depth = (wps_data->remote_wps ? LCD_REMOTE_DEPTH : LCD_DEPTH);
629#else
630 depth = LCD_DEPTH;
631#endif
632
633#ifdef HAVE_LCD_COLOR
634 if (depth == 16)
635 {
Jonathan Gordonae49b382008-06-07 09:01:02 +0000636 if (!(ptr = parse_list("dddddcc", &set, '|', ptr, &vp->x, &vp->y, &vp->width,
Dave Chapman0bb2e052008-03-24 18:40:13 +0000637 &vp->height, &vp->font, &vp->fg_pattern,&vp->bg_pattern)))
638 return WPS_ERROR_INVALID_PARAM;
Dave Chapmand02c79c2008-03-21 19:38:00 +0000639 }
640 else
641#endif
642#if (LCD_DEPTH == 2) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 2)
643 if (depth == 2) {
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000644 /* Default to black on white */
645 vp->fg_pattern = 0;
646 vp->bg_pattern = 3;
Jonathan Gordonae49b382008-06-07 09:01:02 +0000647 if (!(ptr = parse_list("dddddgg", &set, '|', ptr, &vp->x, &vp->y, &vp->width,
Dave Chapman0bb2e052008-03-24 18:40:13 +0000648 &vp->height, &vp->font, &vp->fg_pattern, &vp->bg_pattern)))
649 return WPS_ERROR_INVALID_PARAM;
Dave Chapmand02c79c2008-03-21 19:38:00 +0000650 }
651 else
652#endif
653#if (LCD_DEPTH == 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH == 1)
654 if (depth == 1)
655 {
Jonathan Gordonae49b382008-06-07 09:01:02 +0000656 if (!(ptr = parse_list("ddddd", &set, '|', ptr, &vp->x, &vp->y,
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000657 &vp->width, &vp->height, &vp->font)))
Dave Chapman0bb2e052008-03-24 18:40:13 +0000658 return WPS_ERROR_INVALID_PARAM;
Dave Chapmand02c79c2008-03-21 19:38:00 +0000659 }
660 else
661#endif
662 {}
663
Dave Chapman0bb2e052008-03-24 18:40:13 +0000664 /* Check for trailing | */
665 if (*ptr != '|')
666 return WPS_ERROR_INVALID_PARAM;
667
Jonathan Gordonae49b382008-06-07 09:01:02 +0000668 if (!LIST_VALUE_PARSED(set, PL_X) || !LIST_VALUE_PARSED(set, PL_Y))
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000669 return WPS_ERROR_INVALID_PARAM;
670
671 /* fix defaults */
Jonathan Gordonae49b382008-06-07 09:01:02 +0000672 if (!LIST_VALUE_PARSED(set, PL_WIDTH))
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000673 vp->width = lcd_width - vp->x;
Jonathan Gordonae49b382008-06-07 09:01:02 +0000674 if (!LIST_VALUE_PARSED(set, PL_HEIGHT))
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000675 vp->height = lcd_height - vp->y;
676
Dave Chapmand02c79c2008-03-21 19:38:00 +0000677 /* Default to using the user font if the font was an invalid number */
Jonathan Gordonae49b382008-06-07 09:01:02 +0000678 if (!LIST_VALUE_PARSED(set, PL_FONT) ||
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000679 ((vp->font != FONT_SYSFIXED) && (vp->font != FONT_UI)))
Dave Chapmand02c79c2008-03-21 19:38:00 +0000680 vp->font = FONT_UI;
681
682 /* Validate the viewport dimensions - we know that the numbers are
683 non-negative integers */
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000684 if ((vp->x >= lcd_width) ||
685 ((vp->x + vp->width) > lcd_width) ||
686 (vp->y >= lcd_height) ||
687 ((vp->y + vp->height) > lcd_height))
Dave Chapmand02c79c2008-03-21 19:38:00 +0000688 {
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000689 return WPS_ERROR_INVALID_PARAM;
Dave Chapmand02c79c2008-03-21 19:38:00 +0000690 }
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000691
692#ifdef HAVE_LCD_COLOR
693 if (depth == 16)
694 {
Jonathan Gordonae49b382008-06-07 09:01:02 +0000695 if (!LIST_VALUE_PARSED(set, PL_FG))
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000696 vp->fg_pattern = global_settings.fg_color;
Jonathan Gordonae49b382008-06-07 09:01:02 +0000697 if (!LIST_VALUE_PARSED(set, PL_BG))
Magnus Holmgrenc2416bf2008-06-05 15:21:08 +0000698 vp->bg_pattern = global_settings.bg_color;
Jonathan Gordonf002b7d2008-06-05 08:20:39 +0000699 }
Dave Chapman60413d82008-03-25 00:20:59 +0000700#endif
Dave Chapman45b2d882008-03-22 00:31:22 +0000701
702 wps_data->viewports[wps_data->num_viewports-1].last_line = wps_data->num_lines - 1;
703
704 wps_data->viewports[wps_data->num_viewports].first_line = wps_data->num_lines;
Dave Chapmand02c79c2008-03-21 19:38:00 +0000705
706 if (wps_data->num_sublines < WPS_MAX_SUBLINES)
707 {
Dave Chapman45b2d882008-03-22 00:31:22 +0000708 wps_data->lines[wps_data->num_lines].first_subline_idx =
Dave Chapmand02c79c2008-03-21 19:38:00 +0000709 wps_data->num_sublines;
710
711 wps_data->sublines[wps_data->num_sublines].first_token_idx =
712 wps_data->num_tokens;
713 }
714
715 /* Skip the rest of the line */
716 return skip_end_of_line(wps_bufptr);
Dave Chapman45b2d882008-03-22 00:31:22 +0000717}
Dave Chapmand02c79c2008-03-21 19:38:00 +0000718
719
Jonathan Gordon082f50b2008-06-23 06:17:22 +0000720#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000721static int parse_image_special(const char *wps_bufptr,
722 struct wps_token *token,
723 struct wps_data *wps_data)
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000724{
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000725 (void)wps_data; /* kill warning */
Jonathan Gordon082f50b2008-06-23 06:17:22 +0000726 (void)token;
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000727 const char *pos = NULL;
728 const char *newline;
729
730 pos = strchr(wps_bufptr + 1, '|');
731 newline = strchr(wps_bufptr, '\n');
732
733 if (pos > newline)
734 return WPS_ERROR_INVALID_PARAM;
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000735#if LCD_DEPTH > 1
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000736 if (token->type == WPS_TOKEN_IMAGE_BACKDROP)
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000737 {
738 /* format: %X|filename.bmp| */
Nicolas Pennequin887b31c2007-06-05 14:57:07 +0000739 bmp_names[BACKDROP_BMP] = wps_bufptr + 1;
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000740 }
741#endif
742
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000743 /* Skip the rest of the line */
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000744 return skip_end_of_line(wps_bufptr);
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000745}
Jonathan Gordon082f50b2008-06-23 06:17:22 +0000746#endif
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000747
748#endif /* HAVE_LCD_BITMAP */
749
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000750static int parse_dir_level(const char *wps_bufptr,
751 struct wps_token *token,
752 struct wps_data *wps_data)
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000753{
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000754 char val[] = { *wps_bufptr, '\0' };
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000755 token->value.i = atoi(val);
756 (void)wps_data; /* Kill warnings */
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000757 return 1;
758}
759
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000760static int parse_subline_timeout(const char *wps_bufptr,
761 struct wps_token *token,
762 struct wps_data *wps_data)
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000763{
764 int skip = 0;
765 int val = 0;
766 bool have_point = false;
767 bool have_tenth = false;
768
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000769 (void)wps_data; /* Kill the warning */
770
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000771 while ( isdigit(*wps_bufptr) || *wps_bufptr == '.' )
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000772 {
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000773 if (*wps_bufptr != '.')
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000774 {
775 val *= 10;
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000776 val += *wps_bufptr - '0';
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000777 if (have_point)
778 {
779 have_tenth = true;
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000780 wps_bufptr++;
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000781 skip++;
782 break;
783 }
784 }
785 else
786 have_point = true;
787
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000788 wps_bufptr++;
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000789 skip++;
790 }
791
792 if (have_tenth == false)
793 val *= 10;
794
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000795 token->value.i = val;
Nicolas Pennequin3954a512007-04-06 14:18:07 +0000796
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000797 return skip;
798}
799
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000800static int parse_progressbar(const char *wps_bufptr,
801 struct wps_token *token,
802 struct wps_data *wps_data)
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000803{
Nicolas Pennequin07696c12007-04-08 04:01:06 +0000804 (void)token; /* Kill warnings */
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000805 /* %pb or %pb|filename|x|y|width|height|
806 using - for any of the params uses "sane" values */
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000807#ifdef HAVE_LCD_BITMAP
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000808 enum {
809 PB_FILENAME = 0,
810 PB_X,
811 PB_Y,
812 PB_WIDTH,
813 PB_HEIGHT
814 };
815 const char *filename;
Jonathan Gordon082f50b2008-06-23 06:17:22 +0000816 int x, y, height, width;
817 uint32_t set = 0;
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000818 const char *ptr = wps_bufptr;
819 struct progressbar *pb;
820 struct viewport *vp = &wps_data->viewports[wps_data->num_viewports].vp;
821 int font_height = font_get(vp->font)->height;
822 int line_y_pos = font_height*(wps_data->num_lines -
823 wps_data->viewports[wps_data->num_viewports].first_line);
824
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000825 if (wps_data->progressbar_count +1 >= MAX_PROGRESSBARS)
826 return WPS_ERROR_INVALID_PARAM;
827
828 pb = &wps_data->progressbar[wps_data->progressbar_count];
829 pb->have_bitmap_pb = false;
830
831 if (*wps_bufptr != '|') /* regular old style */
832 {
833 pb->x = 0;
834 pb->width = vp->width;
835 pb->height = SYSFONT_HEIGHT-2;
836 pb->y = line_y_pos + (font_height-pb->height)/2;
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000837
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000838 wps_data->viewports[wps_data->num_viewports].pb =
839 &wps_data->progressbar[wps_data->progressbar_count];
840 wps_data->progressbar_count++;
841 return 0;
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000842 }
Jonathan Gordon5a169bb2008-06-23 06:04:17 +0000843 ptr = wps_bufptr + 1;
844
845 if (!(ptr = parse_list("sdddd", &set, '|', ptr, &filename,
846 &x, &y, &width, &height)))
847 return WPS_ERROR_INVALID_PARAM;
848 if (LIST_VALUE_PARSED(set, PB_FILENAME)) /* filename */
849 bmp_names[PROGRESSBAR_BMP+wps_data->progressbar_count] = filename;
850 if (LIST_VALUE_PARSED(set, PB_X)) /* x */
851 pb->x = x;
852 else
853 pb->x = vp->x;
854 if (LIST_VALUE_PARSED(set, PB_WIDTH)) /* width */
855 pb->width = width;
856 else
857 pb->width = vp->width - pb->x;
858 if (LIST_VALUE_PARSED(set, PB_HEIGHT)) /* height, default to font height */
859 pb->height = height;
860 else
861 pb->height = font_height;
862 if (LIST_VALUE_PARSED(set, PB_Y)) /* y */
863 pb->y = y;
864 else
865 pb->y = line_y_pos + (font_height-pb->height)/2;
866 wps_data->progressbar[wps_data->progressbar_count].have_bitmap_pb = false;
867 wps_data->viewports[wps_data->num_viewports].pb =
868 &wps_data->progressbar[wps_data->progressbar_count];
869 wps_data->progressbar_count++;
870 /* Skip the rest of the line */
871 return skip_end_of_line(wps_bufptr)-1;
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000872#else
873
Nicolas Pennequin9cf89602007-04-05 14:09:59 +0000874 if (*(wps_bufptr-1) == 'f')
Nicolas Pennequinab90d582007-04-04 14:41:40 +0000875 wps_data->full_line_progressbar = true;
876 else
877 wps_data->full_line_progressbar = false;
878
879 return 0;
880
881#endif
882}
883
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000884#ifdef HAVE_ALBUMART
885static int parse_albumart_load(const char *wps_bufptr,
886 struct wps_token *token,
887 struct wps_data *wps_data)
888{
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000889 const char *_pos, *newline;
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000890 bool parsing;
891 const short xalign_mask = WPS_ALBUMART_ALIGN_LEFT |
892 WPS_ALBUMART_ALIGN_CENTER |
893 WPS_ALBUMART_ALIGN_RIGHT;
894 const short yalign_mask = WPS_ALBUMART_ALIGN_TOP |
895 WPS_ALBUMART_ALIGN_CENTER |
896 WPS_ALBUMART_ALIGN_BOTTOM;
897
898 (void)token; /* silence warning */
899
900 /* reset albumart info in wps */
901 wps_data->wps_uses_albumart = WPS_ALBUMART_NONE;
902 wps_data->albumart_max_width = -1;
903 wps_data->albumart_max_height = -1;
904 wps_data->albumart_xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
905 wps_data->albumart_yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
906
907 /* format: %Cl|x|y|[[l|c|r][d|i|s]mwidth]|[[t|c|b][d|i|s]mheight]| */
908
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000909 newline = strchr(wps_bufptr, '\n');
910
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000911 /* initial validation and parsing of x and y components */
912 if (*wps_bufptr != '|')
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000913 return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl7 */
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000914
915 _pos = wps_bufptr + 1;
916 if (!isdigit(*_pos))
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000917 return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl|@ */
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000918 wps_data->albumart_x = atoi(_pos);
919
920 _pos = strchr(_pos, '|');
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000921 if (!_pos || _pos > newline || !isdigit(*(++_pos)))
922 return WPS_ERROR_INVALID_PARAM; /* malformed token: e.g. %Cl|7\n or %Cl|7|@ */
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000923
924 wps_data->albumart_y = atoi(_pos);
925
926 _pos = strchr(_pos, '|');
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000927 if (!_pos || _pos > newline)
928 return WPS_ERROR_INVALID_PARAM; /* malformed token: no | after y coordinate
929 e.g. %Cl|7|59\n */
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000930
931 /* parsing width field */
932 parsing = true;
933 while (parsing)
934 {
935 /* apply each modifier in turn */
936 ++_pos;
937 switch (*_pos)
938 {
939 case 'l':
940 case 'L':
941 case '+':
942 wps_data->albumart_xalign =
943 (wps_data->albumart_xalign & xalign_mask) |
944 WPS_ALBUMART_ALIGN_LEFT;
945 break;
946 case 'c':
947 case 'C':
948 wps_data->albumart_xalign =
949 (wps_data->albumart_xalign & xalign_mask) |
950 WPS_ALBUMART_ALIGN_CENTER;
951 break;
952 case 'r':
953 case 'R':
954 case '-':
955 wps_data->albumart_xalign =
956 (wps_data->albumart_xalign & xalign_mask) |
957 WPS_ALBUMART_ALIGN_RIGHT;
958 break;
959 case 'd':
960 case 'D':
961 wps_data->albumart_xalign |= WPS_ALBUMART_DECREASE;
962 break;
963 case 'i':
964 case 'I':
965 wps_data->albumart_xalign |= WPS_ALBUMART_INCREASE;
966 break;
967 case 's':
968 case 'S':
969 wps_data->albumart_xalign |=
970 (WPS_ALBUMART_DECREASE | WPS_ALBUMART_INCREASE);
971 break;
972 default:
973 parsing = false;
974 break;
975 }
976 }
977 /* extract max width data */
978 if (*_pos != '|')
979 {
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000980 if (!isdigit(*_pos)) /* malformed token: e.g. %Cl|7|59|# */
981 return WPS_ERROR_INVALID_PARAM;
982
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000983 wps_data->albumart_max_width = atoi(_pos);
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000984
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000985 _pos = strchr(_pos, '|');
Nicolas Pennequin31f76112007-11-14 22:02:41 +0000986 if (!_pos || _pos > newline)
987 return WPS_ERROR_INVALID_PARAM; /* malformed token: no | after width field
988 e.g. %Cl|7|59|200\n */
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000989 }
990
991 /* parsing height field */
992 parsing = true;
993 while (parsing)
994 {
995 /* apply each modifier in turn */
996 ++_pos;
997 switch (*_pos)
998 {
999 case 't':
1000 case 'T':
1001 case '-':
1002 wps_data->albumart_yalign =
1003 (wps_data->albumart_yalign & yalign_mask) |
1004 WPS_ALBUMART_ALIGN_TOP;
1005 break;
1006 case 'c':
1007 case 'C':
1008 wps_data->albumart_yalign =
1009 (wps_data->albumart_yalign & yalign_mask) |
1010 WPS_ALBUMART_ALIGN_CENTER;
1011 break;
1012 case 'b':
1013 case 'B':
1014 case '+':
1015 wps_data->albumart_yalign =
1016 (wps_data->albumart_yalign & yalign_mask) |
1017 WPS_ALBUMART_ALIGN_BOTTOM;
1018 break;
1019 case 'd':
1020 case 'D':
1021 wps_data->albumart_yalign |= WPS_ALBUMART_DECREASE;
1022 break;
1023 case 'i':
1024 case 'I':
1025 wps_data->albumart_yalign |= WPS_ALBUMART_INCREASE;
1026 break;
1027 case 's':
1028 case 'S':
1029 wps_data->albumart_yalign |=
1030 (WPS_ALBUMART_DECREASE | WPS_ALBUMART_INCREASE);
1031 break;
1032 default:
1033 parsing = false;
1034 break;
1035 }
1036 }
1037 /* extract max height data */
1038 if (*_pos != '|')
1039 {
1040 if (!isdigit(*_pos))
Nicolas Pennequin31f76112007-11-14 22:02:41 +00001041 return WPS_ERROR_INVALID_PARAM; /* malformed token e.g. %Cl|7|59|200|@ */
1042
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +00001043 wps_data->albumart_max_height = atoi(_pos);
Nicolas Pennequin31f76112007-11-14 22:02:41 +00001044
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +00001045 _pos = strchr(_pos, '|');
Nicolas Pennequin31f76112007-11-14 22:02:41 +00001046 if (!_pos || _pos > newline)
1047 return WPS_ERROR_INVALID_PARAM; /* malformed token: no closing |
1048 e.g. %Cl|7|59|200|200\n */
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +00001049 }
1050
1051 /* if we got here, we parsed everything ok .. ! */
1052 if (wps_data->albumart_max_width < 0)
1053 wps_data->albumart_max_width = 0;
1054 else if (wps_data->albumart_max_width > LCD_WIDTH)
1055 wps_data->albumart_max_width = LCD_WIDTH;
1056
1057 if (wps_data->albumart_max_height < 0)
1058 wps_data->albumart_max_height = 0;
1059 else if (wps_data->albumart_max_height > LCD_HEIGHT)
1060 wps_data->albumart_max_height = LCD_HEIGHT;
1061
1062 wps_data->wps_uses_albumart = WPS_ALBUMART_LOAD;
1063
1064 /* Skip the rest of the line */
1065 return skip_end_of_line(wps_bufptr);
1066}
1067
1068static int parse_albumart_conditional(const char *wps_bufptr,
1069 struct wps_token *token,
1070 struct wps_data *wps_data)
1071{
1072 struct wps_token *prevtoken = token;
1073 --prevtoken;
1074 if (wps_data->num_tokens >= 1 && prevtoken->type == WPS_TOKEN_CONDITIONAL)
1075 {
1076 /* This %C is part of a %?C construct.
1077 It's either %?C<blah> or %?Cn<blah> */
1078 token->type = WPS_TOKEN_ALBUMART_FOUND;
1079 if (*wps_bufptr == 'n' && *(wps_bufptr + 1) == '<')
1080 {
1081 token->next = true;
1082 return 1;
1083 }
1084 else if (*wps_bufptr == '<')
1085 {
1086 return 0;
1087 }
1088 else
1089 {
1090 token->type = WPS_NO_TOKEN;
1091 return 0;
1092 }
1093 }
1094 else
Nicolas Pennequin81dedee2007-11-12 01:31:42 +00001095 {
1096 /* This %C tag is in a conditional construct. */
1097 wps_data->albumart_cond_index = condindex[level];
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +00001098 return 0;
Nicolas Pennequin81dedee2007-11-12 01:31:42 +00001099 }
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +00001100};
1101#endif /* HAVE_ALBUMART */
1102
Dave Chapmanf6ef46b2007-11-12 21:34:01 +00001103
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001104/* Parse a generic token from the given string. Return the length read */
Nicolas Pennequin9cf89602007-04-05 14:09:59 +00001105static int parse_token(const char *wps_bufptr, struct wps_data *wps_data)
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001106{
Nicolas Pennequin31f76112007-11-14 22:02:41 +00001107 int skip = 0, taglen = 0, ret;
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001108 struct wps_token *token = wps_data->tokens + wps_data->num_tokens;
1109 const struct wps_tag *tag;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001110
Nicolas Pennequin9cf89602007-04-05 14:09:59 +00001111 switch(*wps_bufptr)
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001112 {
1113
1114 case '%':
1115 case '<':
1116 case '|':
1117 case '>':
1118 case ';':
Nicolas Pennequin2ea39db2007-04-13 11:43:10 +00001119 case '#':
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001120 /* escaped characters */
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001121 token->type = WPS_TOKEN_CHARACTER;
1122 token->value.c = *wps_bufptr;
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001123 taglen = 1;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001124 wps_data->num_tokens++;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001125 break;
1126
1127 case '?':
1128 /* conditional tag */
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001129 token->type = WPS_TOKEN_CONDITIONAL;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001130 level++;
1131 condindex[level] = wps_data->num_tokens;
1132 numoptions[level] = 1;
1133 wps_data->num_tokens++;
Nicolas Pennequin31f76112007-11-14 22:02:41 +00001134 ret = parse_token(wps_bufptr + 1, wps_data);
1135 if (ret < 0) return ret;
1136 taglen = 1 + ret;
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001137 break;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001138
1139 default:
1140 /* find what tag we have */
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001141 for (tag = all_tags;
1142 strncmp(wps_bufptr, tag->name, strlen(tag->name)) != 0;
1143 tag++) ;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001144
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001145 taglen = (tag->type != WPS_TOKEN_UNKNOWN) ? strlen(tag->name) : 2;
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001146 token->type = tag->type;
Nicolas Pennequinaa220d52007-05-02 17:51:01 +00001147 wps_data->sublines[wps_data->num_sublines].line_type |=
1148 tag->refresh_type;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001149
1150 /* if the tag has a special parsing function, we call it */
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001151 if (tag->parse_func)
Nicolas Pennequin31f76112007-11-14 22:02:41 +00001152 {
1153 ret = tag->parse_func(wps_bufptr + taglen, token, wps_data);
1154 if (ret < 0) return ret;
1155 skip += ret;
1156 }
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001157
1158 /* Some tags we don't want to save as tokens */
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001159 if (tag->type == WPS_NO_TOKEN)
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001160 break;
1161
1162 /* tags that start with 'F', 'I' or 'D' are for the next file */
Nicolas Pennequinaa220d52007-05-02 17:51:01 +00001163 if ( *(tag->name) == 'I' || *(tag->name) == 'F' ||
1164 *(tag->name) == 'D')
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001165 token->next = true;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001166
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001167 wps_data->num_tokens++;
1168 break;
1169 }
1170
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001171 skip += taglen;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001172 return skip;
1173}
1174
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001175/* Parses the WPS.
1176 data is the pointer to the structure where the parsed WPS should be stored.
1177 It is initialised.
1178 wps_bufptr points to the string containing the WPS tags */
Nicolas Pennequin9cf89602007-04-05 14:09:59 +00001179static bool wps_parse(struct wps_data *data, const char *wps_bufptr)
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001180{
Nicolas Pennequin9cf89602007-04-05 14:09:59 +00001181 if (!data || !wps_bufptr || !*wps_bufptr)
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001182 return false;
1183
Nicolas Pennequin7e6af152007-04-30 14:08:58 +00001184 char *stringbuf = data->string_buffer;
Nicolas Pennequin2e1169b2007-04-15 02:59:34 +00001185 int stringbuf_used = 0;
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001186 int fail = 0;
Nicolas Pennequin31f76112007-11-14 22:02:41 +00001187 int ret;
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001188 line = 1;
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001189 level = -1;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001190
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001191 while(*wps_bufptr && !fail && data->num_tokens < WPS_MAX_TOKENS - 1
Dave Chapmand02c79c2008-03-21 19:38:00 +00001192 && data->num_viewports < WPS_MAX_VIEWPORTS
Dave Chapman45b2d882008-03-22 00:31:22 +00001193 && data->num_lines < WPS_MAX_LINES)
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001194 {
Nicolas Pennequin9cf89602007-04-05 14:09:59 +00001195 switch(*wps_bufptr++)
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001196 {
1197
1198 /* Regular tag */
1199 case '%':
Nicolas Pennequin31f76112007-11-14 22:02:41 +00001200 if ((ret = parse_token(wps_bufptr, data)) < 0)
1201 {
1202 fail = PARSE_FAIL_COND_INVALID_PARAM;
1203 break;
1204 }
1205 wps_bufptr += ret;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001206 break;
1207
1208 /* Alternating sublines separator */
1209 case ';':
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001210 if (level >= 0) /* there are unclosed conditionals */
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001211 {
1212 fail = PARSE_FAIL_UNCLOSED_COND;
1213 break;
1214 }
Nicolas Pennequin2e1169b2007-04-15 02:59:34 +00001215
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001216 if (data->num_sublines+1 < WPS_MAX_SUBLINES)
1217 wps_start_new_subline(data);
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001218 else
Nicolas Pennequin9cf89602007-04-05 14:09:59 +00001219 wps_bufptr += skip_end_of_line(wps_bufptr);
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001220
1221 break;
1222
1223 /* Conditional list start */
1224 case '<':
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001225 if (data->tokens[data->num_tokens-2].type != WPS_TOKEN_CONDITIONAL)
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001226 {
1227 fail = PARSE_FAIL_COND_SYNTAX_ERROR;
1228 break;
1229 }
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001230
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001231 data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_START;
1232 lastcond[level] = data->num_tokens++;
1233 break;
1234
1235 /* Conditional list end */
1236 case '>':
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001237 if (level < 0) /* not in a conditional, invalid char */
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001238 {
1239 fail = PARSE_FAIL_INVALID_CHAR;
1240 break;
1241 }
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001242
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001243 data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_END;
1244 if (lastcond[level])
1245 data->tokens[lastcond[level]].value.i = data->num_tokens;
Nicolas Pennequin8537cbf2007-11-12 18:43:38 +00001246 else
1247 {
1248 fail = PARSE_FAIL_COND_SYNTAX_ERROR;
1249 break;
1250 }
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001251
1252 lastcond[level] = 0;
1253 data->num_tokens++;
1254 data->tokens[condindex[level]].value.i = numoptions[level];
1255 level--;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001256 break;
1257
1258 /* Conditional list option */
1259 case '|':
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001260 if (level < 0) /* not in a conditional, invalid char */
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001261 {
1262 fail = PARSE_FAIL_INVALID_CHAR;
1263 break;
1264 }
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001265
1266 data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_OPTION;
1267 if (lastcond[level])
1268 data->tokens[lastcond[level]].value.i = data->num_tokens;
Nicolas Pennequin8537cbf2007-11-12 18:43:38 +00001269 else
1270 {
1271 fail = PARSE_FAIL_COND_SYNTAX_ERROR;
1272 break;
1273 }
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001274
1275 lastcond[level] = data->num_tokens;
1276 numoptions[level]++;
1277 data->num_tokens++;
1278 break;
1279
1280 /* Comment */
1281 case '#':
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001282 if (level >= 0) /* there are unclosed conditionals */
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001283 {
1284 fail = PARSE_FAIL_UNCLOSED_COND;
1285 break;
1286 }
Nicolas Pennequin2e1169b2007-04-15 02:59:34 +00001287
Nicolas Pennequin9cf89602007-04-05 14:09:59 +00001288 wps_bufptr += skip_end_of_line(wps_bufptr);
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001289 break;
1290
1291 /* End of this line */
1292 case '\n':
Nicolas Pennequin814d4022007-04-21 19:31:46 +00001293 if (level >= 0) /* there are unclosed conditionals */
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001294 {
1295 fail = PARSE_FAIL_UNCLOSED_COND;
1296 break;
1297 }
Nicolas Pennequin2e1169b2007-04-15 02:59:34 +00001298
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001299 line++;
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001300 wps_start_new_subline(data);
Dave Chapman45b2d882008-03-22 00:31:22 +00001301 data->num_lines++; /* Start a new line */
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001302
Dave Chapman45b2d882008-03-22 00:31:22 +00001303 if ((data->num_lines < WPS_MAX_LINES) &&
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001304 (data->num_sublines < WPS_MAX_SUBLINES))
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001305 {
Dave Chapman45b2d882008-03-22 00:31:22 +00001306 data->lines[data->num_lines].first_subline_idx =
Nicolas Pennequinaa220d52007-05-02 17:51:01 +00001307 data->num_sublines;
1308
1309 data->sublines[data->num_sublines].first_token_idx =
1310 data->num_tokens;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001311 }
1312
1313 break;
1314
1315 /* String */
1316 default:
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001317 {
Nicolas Pennequin7e6af152007-04-30 14:08:58 +00001318 unsigned int len = 1;
1319 const char *string_start = wps_bufptr - 1;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001320
Nicolas Pennequin378a1402007-05-02 11:39:46 +00001321 /* find the length of the string */
Nicolas Pennequinaa220d52007-05-02 17:51:01 +00001322 while (*wps_bufptr && *wps_bufptr != '#' &&
Nicolas Pennequin378a1402007-05-02 11:39:46 +00001323 *wps_bufptr != '%' && *wps_bufptr != ';' &&
1324 *wps_bufptr != '<' && *wps_bufptr != '>' &&
1325 *wps_bufptr != '|' && *wps_bufptr != '\n')
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001326 {
Nicolas Pennequin7e6af152007-04-30 14:08:58 +00001327 wps_bufptr++;
1328 len++;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001329 }
1330
Nicolas Pennequin7e6af152007-04-30 14:08:58 +00001331 /* look if we already have that string */
1332 char **str;
1333 int i;
1334 bool found;
1335 for (i = 0, str = data->strings, found = false;
Peter D'Hoye3494b212007-05-01 23:36:15 +00001336 i < data->num_strings &&
1337 !(found = (strlen(*str) == len &&
Nicolas Pennequin378a1402007-05-02 11:39:46 +00001338 strncmp(string_start, *str, len) == 0));
Peter D'Hoye3494b212007-05-01 23:36:15 +00001339 i++, str++);
1340 /* If a matching string is found, found is true and i is
1341 the index of the string. If not, found is false */
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001342
Peter D'Hoye3494b212007-05-01 23:36:15 +00001343 /* If it's NOT a duplicate, do nothing if we already have
1344 too many unique strings */
1345 if (found ||
Nicolas Pennequin378a1402007-05-02 11:39:46 +00001346 (stringbuf_used < STRING_BUFFER_SIZE - 1 &&
1347 data->num_strings < WPS_MAX_STRINGS))
Nicolas Pennequin7e6af152007-04-30 14:08:58 +00001348 {
Peter D'Hoye3494b212007-05-01 23:36:15 +00001349 if (!found)
1350 {
1351 /* new string */
Nicolas Pennequin378a1402007-05-02 11:39:46 +00001352
1353 /* truncate? */
Peter D'Hoye3494b212007-05-01 23:36:15 +00001354 if (stringbuf_used + len > STRING_BUFFER_SIZE - 1)
1355 len = STRING_BUFFER_SIZE - stringbuf_used - 1;
Nicolas Pennequin378a1402007-05-02 11:39:46 +00001356
Peter D'Hoye3494b212007-05-01 23:36:15 +00001357 strncpy(stringbuf, string_start, len);
Nicolas Pennequin378a1402007-05-02 11:39:46 +00001358 *(stringbuf + len) = '\0';
1359
Peter D'Hoye3494b212007-05-01 23:36:15 +00001360 data->strings[data->num_strings] = stringbuf;
1361 stringbuf += len + 1;
1362 stringbuf_used += len + 1;
Nicolas Pennequinaa220d52007-05-02 17:51:01 +00001363 data->tokens[data->num_tokens].value.i =
1364 data->num_strings;
Peter D'Hoye3494b212007-05-01 23:36:15 +00001365 data->num_strings++;
1366 }
1367 else
1368 {
1369 /* another ocurrence of an existing string */
1370 data->tokens[data->num_tokens].value.i = i;
1371 }
1372 data->tokens[data->num_tokens].type = WPS_TOKEN_STRING;
1373 data->num_tokens++;
Nicolas Pennequin7e6af152007-04-30 14:08:58 +00001374 }
Nicolas Pennequin2e1169b2007-04-15 02:59:34 +00001375 }
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001376 break;
1377 }
1378 }
1379
Nicolas Pennequin8537cbf2007-11-12 18:43:38 +00001380 if (!fail && level >= 0) /* there are unclosed conditionals */
Nicolas Pennequin378a1402007-05-02 11:39:46 +00001381 fail = PARSE_FAIL_UNCLOSED_COND;
1382
Dave Chapman45b2d882008-03-22 00:31:22 +00001383 data->viewports[data->num_viewports].last_line = data->num_lines - 1;
1384
Dave Chapmand02c79c2008-03-21 19:38:00 +00001385 /* We have finished with the last viewport, so increment count */
1386 data->num_viewports++;
1387
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001388#ifdef DEBUG
Nicolas Pennequin6ac306a2007-04-24 23:58:57 +00001389 print_debug_info(data, fail, line);
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001390#endif
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001391
Nicolas Pennequind7fd9892007-04-24 00:57:04 +00001392 return (fail == 0);
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001393}
1394
1395#ifdef HAVE_LCD_BITMAP
1396/* Clear the WPS image cache */
1397static void wps_images_clear(struct wps_data *data)
1398{
1399 int i;
1400 /* set images to unloaded and not displayed */
1401 for (i = 0; i < MAX_IMAGES; i++)
1402 {
1403 data->img[i].loaded = false;
Dave Chapman15ddd7a2008-03-23 20:31:00 +00001404 data->img[i].display = -1;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001405 data->img[i].always_display = false;
Dave Chapman15ddd7a2008-03-23 20:31:00 +00001406 data->img[i].num_subimages = 1;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001407 }
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001408}
1409#endif
1410
1411/* initial setup of wps_data */
1412void wps_data_init(struct wps_data *wps_data)
1413{
1414#ifdef HAVE_LCD_BITMAP
1415 wps_images_clear(wps_data);
1416 wps_data->wps_sb_tag = false;
1417 wps_data->show_sb_on_wps = false;
1418 wps_data->img_buf_ptr = wps_data->img_buf; /* where in image buffer */
1419 wps_data->img_buf_free = IMG_BUFSIZE; /* free space in image buffer */
1420 wps_data->peak_meter_enabled = false;
Jonathan Gordon5a169bb2008-06-23 06:04:17 +00001421 /* progress bars */
1422 wps_data->progressbar_count = 0;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001423#else /* HAVE_LCD_CHARCELLS */
Nicolas Pennequinef5cfb42007-04-08 04:12:55 +00001424 int i;
Nicolas Pennequin07696c12007-04-08 04:01:06 +00001425 for (i = 0; i < 8; i++)
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001426 {
1427 wps_data->wps_progress_pat[i] = 0;
1428 }
1429 wps_data->full_line_progressbar = false;
1430#endif
1431 wps_data->wps_loaded = false;
1432}
1433
1434static void wps_reset(struct wps_data *data)
1435{
Nicolas Pennequin2a2b8d82007-04-25 13:09:56 +00001436#ifdef HAVE_REMOTE_LCD
1437 bool rwps = data->remote_wps; /* remember whether the data is for a RWPS */
1438#endif
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001439 memset(data, 0, sizeof(*data));
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +00001440#ifdef HAVE_ALBUMART
1441 data->wps_uses_albumart = WPS_ALBUMART_NONE;
1442#endif
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001443 wps_data_init(data);
Nicolas Pennequin2a2b8d82007-04-25 13:09:56 +00001444#ifdef HAVE_REMOTE_LCD
1445 data->remote_wps = rwps;
1446#endif
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001447}
1448
1449#ifdef HAVE_LCD_BITMAP
1450
Dave Chapmanb9bb7232008-03-26 18:18:22 +00001451static bool load_wps_bitmaps(struct wps_data *wps_data, char *bmpdir)
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001452{
1453 char img_path[MAX_PATH];
Nicolas Pennequinb5f4d902007-06-05 10:42:41 +00001454 struct bitmap *bitmap;
1455 bool *loaded;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001456 int n;
Nicolas Pennequin887b31c2007-06-05 14:57:07 +00001457 for (n = 0; n < BACKDROP_BMP; n++)
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001458 {
1459 if (bmp_names[n])
1460 {
1461 get_image_filename(bmp_names[n], bmpdir,
1462 img_path, sizeof(img_path));
1463
Jonathan Gordon5a169bb2008-06-23 06:04:17 +00001464 if (n >= PROGRESSBAR_BMP ) {
Nicolas Pennequinb5f4d902007-06-05 10:42:41 +00001465 /* progressbar bitmap */
Jonathan Gordon5a169bb2008-06-23 06:04:17 +00001466 bitmap = &wps_data->progressbar[n-PROGRESSBAR_BMP].bm;
1467 loaded = &wps_data->progressbar[n-PROGRESSBAR_BMP].have_bitmap_pb;
Nicolas Pennequinb5f4d902007-06-05 10:42:41 +00001468 } else {
1469 /* regular bitmap */
1470 bitmap = &wps_data->img[n].bm;
1471 loaded = &wps_data->img[n].loaded;
1472 }
1473
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001474 /* load the image */
Nicolas Pennequinb5f4d902007-06-05 10:42:41 +00001475 bitmap->data = wps_data->img_buf_ptr;
1476 if (load_bitmap(wps_data, img_path, bitmap))
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001477 {
Nicolas Pennequinb5f4d902007-06-05 10:42:41 +00001478 *loaded = true;
Dave Chapman15ddd7a2008-03-23 20:31:00 +00001479
1480 /* Calculate and store height if this image has sub-images */
Dave Chapman99c09782008-03-24 00:03:05 +00001481 if (n < MAX_IMAGES)
Dave Chapman15ddd7a2008-03-23 20:31:00 +00001482 wps_data->img[n].subimage_height = wps_data->img[n].bm.height /
1483 wps_data->img[n].num_subimages;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001484 }
Dave Chapmanb9bb7232008-03-26 18:18:22 +00001485 else
1486 {
1487 /* Abort if we can't load an image */
1488 DEBUGF("ERR: Failed to load image %d - %s\n",n,img_path);
1489 return false;
1490 }
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001491 }
1492 }
1493
Dave Chapmand746b792008-03-29 01:14:10 +00001494#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
Nicolas Pennequin887b31c2007-06-05 14:57:07 +00001495 if (bmp_names[BACKDROP_BMP])
Nicolas Pennequin7fdfa562007-04-25 21:44:56 +00001496 {
Nicolas Pennequin887b31c2007-06-05 14:57:07 +00001497 get_image_filename(bmp_names[BACKDROP_BMP], bmpdir,
Nicolas Pennequin7fdfa562007-04-25 21:44:56 +00001498 img_path, sizeof(img_path));
Dave Chapmanfa1da202008-03-26 19:07:39 +00001499
1500#if defined(HAVE_REMOTE_LCD)
1501 /* We only need to check LCD type if there is a remote LCD */
1502 if (!wps_data->remote_wps)
Nicolas Pennequin2a2b8d82007-04-25 13:09:56 +00001503#endif
Dave Chapmanfa1da202008-03-26 19:07:39 +00001504 {
1505 /* Load backdrop for the main LCD */
Dave Chapmanb9bb7232008-03-26 18:18:22 +00001506 if (!load_wps_backdrop(img_path))
1507 return false;
Dave Chapmanfa1da202008-03-26 19:07:39 +00001508 }
1509#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
1510 else
1511 {
1512 /* Load backdrop for the remote LCD */
1513 if (!load_remote_wps_backdrop(img_path))
1514 return false;
1515 }
1516#endif
Nicolas Pennequin7fdfa562007-04-25 21:44:56 +00001517 }
1518#endif /* has backdrop support */
Dave Chapmanb9bb7232008-03-26 18:18:22 +00001519
1520 /* If we got here, everything was OK */
1521 return true;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001522}
1523
1524#endif /* HAVE_LCD_BITMAP */
1525
Nicolas Pennequin9ce77aa2007-04-08 15:02:26 +00001526/* Skip leading UTF-8 BOM, if present. */
1527static char *skip_utf8_bom(char *buf)
1528{
1529 unsigned char *s = (unsigned char *)buf;
1530
1531 if(s[0] == 0xef && s[1] == 0xbb && s[2] == 0xbf)
1532 {
1533 buf += 3;
1534 }
1535
1536 return buf;
1537}
1538
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001539/* to setup up the wps-data from a format-buffer (isfile = false)
1540 from a (wps-)file (isfile = true)*/
1541bool wps_data_load(struct wps_data *wps_data,
Dave Chapmand02c79c2008-03-21 19:38:00 +00001542 struct screen *display,
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001543 const char *buf,
1544 bool isfile)
1545{
1546 if (!wps_data || !buf)
1547 return false;
1548
1549 wps_reset(wps_data);
1550
Dave Chapmand02c79c2008-03-21 19:38:00 +00001551 /* Initialise the first (default) viewport */
1552 wps_data->viewports[0].vp.x = 0;
Dave Chapmand02c79c2008-03-21 19:38:00 +00001553 wps_data->viewports[0].vp.width = display->width;
Jonathan Gordonbdbdb972008-06-23 13:20:35 +00001554 if (!global_settings.statusbar)
1555 {
1556 wps_data->viewports[0].vp.y = 0;
1557 wps_data->viewports[0].vp.height = display->height;
1558 }
1559 else
1560 {
1561 wps_data->viewports[0].vp.y = STATUSBAR_HEIGHT;
1562 wps_data->viewports[0].vp.height = display->height - STATUSBAR_HEIGHT;
1563 }
Dave Chapmand02c79c2008-03-21 19:38:00 +00001564#ifdef HAVE_LCD_BITMAP
1565 wps_data->viewports[0].vp.font = FONT_UI;
1566 wps_data->viewports[0].vp.drawmode = DRMODE_SOLID;
1567#endif
Dave Chapmand02c79c2008-03-21 19:38:00 +00001568#if LCD_DEPTH > 1
1569 if (display->depth > 1)
1570 {
1571 wps_data->viewports[0].vp.fg_pattern = display->get_foreground();
1572 wps_data->viewports[0].vp.bg_pattern = display->get_background();
1573 }
1574#endif
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001575 if (!isfile)
1576 {
1577 return wps_parse(wps_data, buf);
1578 }
1579 else
1580 {
1581 /*
1582 * Hardcode loading WPS_DEFAULTCFG to cause a reset ideally this
1583 * wants to be a virtual file. Feel free to modify dirbrowse()
1584 * if you're feeling brave.
1585 */
Dave Chapmanf0d4fc62007-05-29 19:00:36 +00001586#ifndef __PCTOOL__
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001587 if (! strcmp(buf, WPS_DEFAULTCFG) )
1588 {
1589 global_settings.wps_file[0] = 0;
1590 return false;
1591 }
1592
1593#ifdef HAVE_REMOTE_LCD
1594 if (! strcmp(buf, RWPS_DEFAULTCFG) )
1595 {
1596 global_settings.rwps_file[0] = 0;
1597 return false;
1598 }
1599#endif
Dave Chapmanf0d4fc62007-05-29 19:00:36 +00001600#endif /* __PCTOOL__ */
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001601
1602 int fd = open(buf, O_RDONLY);
1603
1604 if (fd < 0)
1605 return false;
1606
1607 /* get buffer space from the plugin buffer */
Michael Sevakis26d242a2007-04-21 18:38:25 +00001608 size_t buffersize = 0;
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001609 char *wps_buffer = (char *)plugin_get_buffer(&buffersize);
1610
1611 if (!wps_buffer)
1612 return false;
1613
Nicolas Pennequinaa220d52007-05-02 17:51:01 +00001614 /* copy the file's content to the buffer for parsing,
1615 ensuring that every line ends with a newline char. */
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001616 unsigned int start = 0;
1617 while(read_line(fd, wps_buffer + start, buffersize - start) > 0)
1618 {
1619 start += strlen(wps_buffer + start);
1620 if (start < buffersize - 1)
1621 {
1622 wps_buffer[start++] = '\n';
1623 wps_buffer[start] = 0;
1624 }
1625 }
1626
1627 close(fd);
1628
1629 if (start <= 0)
1630 return false;
1631
1632#ifdef HAVE_LCD_BITMAP
Dave Chapmand02c79c2008-03-21 19:38:00 +00001633 /* Set all filename pointers to NULL */
Dave Chapman65d50de2008-03-23 12:15:52 +00001634 memset(bmp_names, 0, sizeof(bmp_names));
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001635#endif
1636
Nicolas Pennequin9ce77aa2007-04-08 15:02:26 +00001637 /* Skip leading UTF-8 BOM, if present. */
1638 wps_buffer = skip_utf8_bom(wps_buffer);
1639
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001640 /* parse the WPS source */
Nicolas Pennequin19868932008-04-01 17:35:48 +00001641 if (!wps_parse(wps_data, wps_buffer)) {
1642 wps_reset(wps_data);
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001643 return false;
Nicolas Pennequin19868932008-04-01 17:35:48 +00001644 }
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001645
1646 wps_data->wps_loaded = true;
1647
1648#ifdef HAVE_LCD_BITMAP
1649 /* get the bitmap dir */
1650 char bmpdir[MAX_PATH];
1651 size_t bmpdirlen;
1652 char *dot = strrchr(buf, '.');
1653 bmpdirlen = dot - buf;
1654 strncpy(bmpdir, buf, dot - buf);
1655 bmpdir[bmpdirlen] = 0;
1656
1657 /* load the bitmaps that were found by the parsing */
Nicolas Pennequin19868932008-04-01 17:35:48 +00001658 if (!load_wps_bitmaps(wps_data, bmpdir)) {
1659 wps_reset(wps_data);
Dave Chapmanb9bb7232008-03-26 18:18:22 +00001660 return false;
Nicolas Pennequin19868932008-04-01 17:35:48 +00001661 }
Nicolas Pennequinab90d582007-04-04 14:41:40 +00001662#endif
1663 return true;
1664 }
1665}
Dave Chapmanf0d4fc62007-05-29 19:00:36 +00001666
Dave Chapman45b2d882008-03-22 00:31:22 +00001667int wps_subline_index(struct wps_data *data, int line, int subline)
Dave Chapmanf0d4fc62007-05-29 19:00:36 +00001668{
Dave Chapman45b2d882008-03-22 00:31:22 +00001669 return data->lines[line].first_subline_idx + subline;
Dave Chapmanf0d4fc62007-05-29 19:00:36 +00001670}
1671
Dave Chapman45b2d882008-03-22 00:31:22 +00001672int wps_first_token_index(struct wps_data *data, int line, int subline)
Dave Chapmanf0d4fc62007-05-29 19:00:36 +00001673{
Dave Chapman45b2d882008-03-22 00:31:22 +00001674 int first_subline_idx = data->lines[line].first_subline_idx;
Dave Chapmanf0d4fc62007-05-29 19:00:36 +00001675 return data->sublines[first_subline_idx + subline].first_token_idx;
1676}
1677
Dave Chapman45b2d882008-03-22 00:31:22 +00001678int wps_last_token_index(struct wps_data *data, int line, int subline)
Dave Chapmanf0d4fc62007-05-29 19:00:36 +00001679{
Dave Chapman45b2d882008-03-22 00:31:22 +00001680 int first_subline_idx = data->lines[line].first_subline_idx;
Dave Chapmanf0d4fc62007-05-29 19:00:36 +00001681 int idx = first_subline_idx + subline;
1682 if (idx < data->num_sublines - 1)
1683 {
1684 /* This subline ends where the next begins */
1685 return data->sublines[idx+1].first_token_idx - 1;
1686 }
1687 else
1688 {
1689 /* The last subline goes to the end */
1690 return data->num_tokens - 1;
1691 }
1692}