Index: apps/settings.c =================================================================== --- apps/settings.c (revision 22288) +++ apps/settings.c (working copy) @@ -70,6 +70,7 @@ #include "radio.h" #endif #include "wps.h" +#include "skin_engine/skin_engine.h" #if CONFIG_CODEC == MAS3507D void dac_line_in(bool enable); @@ -818,6 +819,8 @@ if (read_disk) { + /* re-initialize the skin buffer before we start reloading skins */ + skin_buffer_init(); #ifdef HAVE_LCD_BITMAP /* fonts need to be loaded before the WPS */ Index: apps/gui/skin_engine/skin_engine.h =================================================================== --- apps/gui/skin_engine/skin_engine.h (revision 22288) +++ apps/gui/skin_engine/skin_engine.h (working copy) @@ -23,6 +23,8 @@ #ifndef _SKIN_ENGINE_H #define _SKIN_ENGINE_H +#include "skin_buffer.h" + #include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */ Index: apps/gui/skin_engine/wps_debug.c =================================================================== --- apps/gui/skin_engine/wps_debug.c (revision 22288) +++ apps/gui/skin_engine/wps_debug.c (working copy) @@ -23,6 +23,7 @@ #include #include +#include "wps.h" #include "wps_internals.h" #ifdef __PCTOOL__ #ifdef WPSEDITOR Index: apps/gui/skin_engine/skin_parser.c =================================================================== --- apps/gui/skin_engine/skin_parser.c (revision 22288) +++ apps/gui/skin_engine/skin_parser.c (working copy) @@ -355,6 +355,40 @@ /* the array MUST end with an empty string (first char is \0) */ }; + +/* add a wpsll item to the list chain. ALWAYS appended because some of the + * chains require the order to be kept. + */ +static void add_to_ll_chain(struct skin_token_list **list, struct skin_token_list *item) +{ + if (*list == NULL) + *list = item; + else + { + struct skin_token_list *t = *list; + while (t->next) + t = t->next; + t->next = item; + } +} +/* create and init a new wpsll item. + * passing NULL to token will alloc a new one. + */ +static struct skin_token_list *new_skin_token_list_item(struct wps_token *token, + void* token_data) +{ + struct skin_token_list *llitem = skin_buffer_alloc(sizeof(struct skin_token_list)); + if (!token) + token = skin_buffer_alloc(sizeof(struct wps_token)); + if (!llitem || !token) + return NULL; + llitem->next = NULL; + llitem->token = token; + if (token_data) + llitem->token->value.data = token_data; + return llitem; +} + /* Returns the number of chars that should be skipped to jump immediately after the first eol, i.e. to the start of the next line */ static int skip_end_of_line(const char *wps_bufptr) @@ -406,37 +440,6 @@ return skip_end_of_line(wps_bufptr); } -static bool load_bitmap(struct wps_data *wps_data, - char* filename, - struct bitmap *bm) -{ - int format; -#ifdef HAVE_REMOTE_LCD - if (wps_data->remote_wps) - format = FORMAT_ANY|FORMAT_REMOTE; - else -#endif - format = FORMAT_ANY|FORMAT_TRANSPARENT; - - int ret = read_bmp_file(filename, bm, - wps_data->img_buf_free, - format,NULL); - - if (ret > 0) - { -#if LCD_DEPTH == 16 - if (ret % 2) ret++; - /* Always consume an even number of bytes */ -#endif - wps_data->img_buf_ptr += ret; - wps_data->img_buf_free -= ret; - - return true; - } - else - return false; -} - static int get_image_id(int c) { if(c >= 'a' && c <= 'z') @@ -472,9 +475,9 @@ struct wps_token *token, struct wps_data *wps_data) { - (void)wps_data; int n = get_image_id(wps_bufptr[0]); int subimage; + struct gui_img *img;; if (n == -1) { @@ -484,8 +487,9 @@ if ((subimage = get_image_id(wps_bufptr[1])) != -1) { + img = find_image(n, wps_data); /* Sanity check */ - if (subimage >= wps_data->img[n].num_subimages) + if (!img || subimage >= img->num_subimages) return WPS_ERROR_INVALID_PARAM; /* Store sub-image number to display in high bits */ @@ -508,6 +512,7 @@ const char* id; const char *newline; int x,y; + struct gui_img *img; /* format: %x|n|filename.bmp|x|y| or %xl|n|filename.bmp|x|y| @@ -530,24 +535,25 @@ n = get_image_id(*id); /* check the image number and load state */ - if(n < 0 || n >= MAX_IMAGES || wps_data->img[n].loaded) + if(n < 0 || find_image(n, wps_data)) { /* Invalid image ID */ return WPS_ERROR_INVALID_PARAM; } - + img = skin_buffer_alloc(sizeof(struct gui_img)); /* save a pointer to the filename */ - bmp_names[n] = filename; + img->bm.data = (char*)filename; + img->id = n; + img->x = x; + img->y = y; + img->num_subimages = 1; - wps_data->img[n].x = x; - wps_data->img[n].y = y; - /* save current viewport */ - wps_data->img[n].vp = &wps_data->viewports[wps_data->num_viewports].vp; + img->vp = &wps_data->viewports[wps_data->num_viewports].vp; if (token->type == WPS_TOKEN_IMAGE_DISPLAY) { - wps_data->img[n].always_display = true; + img->always_display = true; } else { @@ -556,11 +562,13 @@ newline = strchr(ptr, '\n'); pos = strchr(ptr, '|'); if (pos && pos < newline) - wps_data->img[n].num_subimages = atoi(ptr); + img->num_subimages = atoi(ptr); - if (wps_data->img[n].num_subimages <= 0) + if (img->num_subimages <= 0) return WPS_ERROR_INVALID_PARAM; } + struct skin_token_list *item = new_skin_token_list_item(NULL, img); + add_to_ll_chain(&wps_data->images, item); /* Skip the rest of the line */ return skip_end_of_line(wps_bufptr); @@ -781,7 +789,6 @@ struct wps_token *token, struct wps_data *wps_data) { - (void)token; /* Kill warnings */ /* %pb or %pb|filename|x|y|width|height| using - for any of the params uses "sane" values */ #ifdef HAVE_LCD_BITMAP @@ -796,7 +803,9 @@ int x, y, height, width; uint32_t set = 0; const char *ptr = wps_bufptr; - struct progressbar *pb; + struct progressbar *pb = skin_buffer_alloc(sizeof(struct progressbar)); + struct skin_token_list *item = new_skin_token_list_item(token, pb); + struct viewport *vp = &wps_data->viewports[wps_data->num_viewports].vp; #ifndef __PCTOOL__ int font_height = font_get(vp->font)->height; @@ -806,11 +815,8 @@ int line_num = wps_data->num_lines - wps_data->viewports[wps_data->num_viewports].first_line; - if (wps_data->progressbar_count >= MAX_PROGRESSBARS) - return WPS_ERROR_INVALID_PARAM; - - pb = &wps_data->progressbar[wps_data->progressbar_count]; pb->have_bitmap_pb = false; + pb->bm.data = NULL; /* no bitmap specified */ if (*wps_bufptr != '|') /* regular old style */ { @@ -820,7 +826,7 @@ pb->y = -line_num - 1; /* Will be computed during the rendering */ wps_data->viewports[wps_data->num_viewports].pb = pb; - wps_data->progressbar_count++; + add_to_ll_chain(&wps_data->progressbars, item); return 0; } ptr = wps_bufptr + 1; @@ -830,7 +836,7 @@ return WPS_ERROR_INVALID_PARAM; if (LIST_VALUE_PARSED(set, PB_FILENAME)) /* filename */ - bmp_names[PROGRESSBAR_BMP+wps_data->progressbar_count] = filename; + pb->bm.data = (char*)filename; if (LIST_VALUE_PARSED(set, PB_X)) /* x */ pb->x = x; @@ -865,7 +871,7 @@ pb->y = -line_num - 1; /* Will be computed during the rendering */ wps_data->viewports[wps_data->num_viewports].pb = pb; - wps_data->progressbar_count++; + add_to_ll_chain(&wps_data->progressbars, item); /* Skip the rest of the line */ return skip_end_of_line(wps_bufptr)-1; @@ -1480,54 +1486,74 @@ } #ifdef HAVE_LCD_BITMAP +static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char* bmpdir) +{ + bool loaded = false; + char img_path[MAX_PATH]; + get_image_filename(bitmap->data, bmpdir, + img_path, sizeof(img_path)); + + /* load the image */ + int format; +#ifdef HAVE_REMOTE_LCD + if (wps_data->remote_wps) + format = FORMAT_ANY|FORMAT_REMOTE; + else +#endif + format = FORMAT_ANY|FORMAT_TRANSPARENT; + + size_t max_buf; + char* imgbuf = (char*)skin_buffer_grab(&max_buf); + bitmap->data = imgbuf; + int ret = read_bmp_file(img_path, bitmap, max_buf, format, NULL); + if (ret > 0) + { + skin_buffer_increment(ret); + loaded = true; + } + else + { + /* Abort if we can't load an image */ + DEBUGF("ERR: Failed to load image - %s\n",img_path); + loaded = false; + } + return loaded; +} + static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir) { - char img_path[MAX_PATH]; - struct bitmap *bitmap; - bool *loaded; - int n; - for (n = 0; n < BACKDROP_BMP; n++) + struct skin_token_list *list; + /* do the progressbars */ + list = wps_data->progressbars; + while (list) { - if (bmp_names[n]) + struct progressbar *pb = (struct progressbar*)list->token->value.data; + if (pb->bm.data) { - get_image_filename(bmp_names[n], bmpdir, - img_path, sizeof(img_path)); - - if (n >= PROGRESSBAR_BMP ) { - /* progressbar bitmap */ - bitmap = &wps_data->progressbar[n-PROGRESSBAR_BMP].bm; - loaded = &wps_data->progressbar[n-PROGRESSBAR_BMP].have_bitmap_pb; - } else { - /* regular bitmap */ - bitmap = &wps_data->img[n].bm; - loaded = &wps_data->img[n].loaded; - } - - /* load the image */ - bitmap->data = wps_data->img_buf_ptr; - if (load_bitmap(wps_data, img_path, bitmap)) - { - *loaded = true; - - /* Calculate and store height if this image has sub-images */ - if (n < MAX_IMAGES) - wps_data->img[n].subimage_height = wps_data->img[n].bm.height / - wps_data->img[n].num_subimages; - } - else - { - /* Abort if we can't load an image */ - DEBUGF("ERR: Failed to load image %d - %s\n",n,img_path); - return false; - } + pb->have_bitmap_pb = load_skin_bmp(wps_data, &pb->bm, bmpdir); } + list = list->next; + } + /* regular images */ + list = wps_data->images; + while (list) + { + struct gui_img *img = (struct gui_img*)list->token->value.data; + if (img->bm.data) + { + img->loaded = load_skin_bmp(wps_data, &img->bm, bmpdir); + if (img->loaded) + img->subimage_height = img->bm.height / img->num_subimages; + } + list = list->next; } #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) if (bmp_names[BACKDROP_BMP]) { int screen = SCREEN_MAIN; + char img_path[MAX_PATH]; get_image_filename(bmp_names[BACKDROP_BMP], bmpdir, img_path, sizeof(img_path)); #if defined(HAVE_REMOTE_LCD) Index: apps/gui/skin_engine/skin_buffer.h =================================================================== --- apps/gui/skin_engine/skin_buffer.h (revision 0) +++ apps/gui/skin_engine/skin_buffer.h (revision 0) @@ -0,0 +1,51 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: wps_parser.c 19880 2009-01-29 20:49:43Z mcuelenaere $ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * Copyright (C) 2009 Jonathan Gordon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _SKIN_BUFFER_H_ +#define _SKIN_BUFFER_H_ + + +#include +#include +#include + +/* int the global buffer */ +void skin_buffer_init(void); + +/* get the number of bytes currently being used */ +size_t skin_buffer_usage(void); + +/* Allocate size bytes from the buffer */ +void* skin_buffer_alloc(size_t size); + + +/* Get a pointer to the skin buffer and the count of how much is free + * used to do your own buffer management. + * Any memory used will be overwritten next time wps_buffer_alloc() + * is called unless skin_buffer_increment() is called first + */ +void* skin_buffer_grab(size_t *freespace); + +/* Use after skin_buffer_grab() to specify how much buffer was used */ +void skin_buffer_increment(size_t used); + +#endif /* _SKIN_BUFFER_H_ */ Index: apps/gui/skin_engine/wps_parser.c =================================================================== --- apps/gui/skin_engine/wps_parser.c (revision 22288) +++ apps/gui/skin_engine/wps_parser.c (working copy) @@ -1,1697 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include -#include -#include -#include "file.h" -#include "misc.h" -#include "plugin.h" -#include "viewport.h" - -#ifdef __PCTOOL__ -#ifdef WPSEDITOR -#include "proxy.h" -#include "sysfont.h" -#else -#include "checkwps.h" -#include "audio.h" -#define DEBUGF printf -#endif /*WPSEDITOR*/ -#else -#include "debug.h" -#endif /*__PCTOOL__*/ - -#include -#include -#include "font.h" - -#include "wps_internals.h" -#include "skin_engine.h" -#include "settings.h" -#include "settings_list.h" - -#ifdef HAVE_LCD_BITMAP -#include "bmp.h" -#endif - -#include "backdrop.h" - -#define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps" -#define RWPS_DEFAULTCFG WPS_DIR "/rockbox_default.rwps" - -#define WPS_ERROR_INVALID_PARAM -1 - -/* level of current conditional. - -1 means we're not in a conditional. */ -static int level = -1; - -/* index of the last WPS_TOKEN_CONDITIONAL_OPTION - or WPS_TOKEN_CONDITIONAL_START in current level */ -static int lastcond[WPS_MAX_COND_LEVEL]; - -/* index of the WPS_TOKEN_CONDITIONAL in current level */ -static int condindex[WPS_MAX_COND_LEVEL]; - -/* number of condtional options in current level */ -static int numoptions[WPS_MAX_COND_LEVEL]; - -/* the current line in the file */ -static int line; - -#ifdef HAVE_LCD_BITMAP - -#if LCD_DEPTH > 1 -#define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS+1) /* WPS images + pbar bitmap + backdrop */ -#else -#define MAX_BITMAPS (MAX_IMAGES+MAX_PROGRESSBARS) /* WPS images + pbar bitmap */ -#endif - -#define PROGRESSBAR_BMP MAX_IMAGES -#define BACKDROP_BMP (MAX_BITMAPS-1) - -/* pointers to the bitmap filenames in the WPS source */ -static const char *bmp_names[MAX_BITMAPS]; - -#endif /* HAVE_LCD_BITMAP */ - -#if defined(DEBUG) || defined(SIMULATOR) -/* debugging function */ -extern void print_debug_info(struct wps_data *data, int fail, int line); -#endif - -static void wps_reset(struct wps_data *data); - -/* Function for parsing of details for a token. At the moment the - function is called, the token type has already been set. The - function must fill in the details and possibly add more tokens - to the token array. It should return the number of chars that - has been consumed. - - wps_bufptr points to the char following the tag (i.e. where - details begin). - token is the pointer to the 'main' token being parsed - */ -typedef int (*wps_tag_parse_func)(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); - -struct wps_tag { - enum wps_token_type type; - const char name[3]; - unsigned char refresh_type; - const wps_tag_parse_func parse_func; -}; -static int skip_end_of_line(const char *wps_bufptr); -/* prototypes of all special parse functions : */ -static int parse_timeout(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_progressbar(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_dir_level(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_setting(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); - -#ifdef HAVE_LCD_BITMAP -static int parse_viewport_display(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_viewport(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_statusbar_enable(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_statusbar_disable(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_image_display(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_image_load(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -#endif /*HAVE_LCD_BITMAP */ -#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) -static int parse_image_special(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -#endif -#ifdef HAVE_ALBUMART -static int parse_albumart_load(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -static int parse_albumart_conditional(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -#endif /* HAVE_ALBUMART */ -#ifdef HAVE_TOUCHSCREEN -static int parse_touchregion(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data); -#else -static int fulline_tag_not_supported(const char *wps_bufptr, - struct wps_token *token, struct wps_data *wps_data) -{ - (void)token; (void)wps_data; - return skip_end_of_line(wps_bufptr); -} -#define parse_touchregion fulline_tag_not_supported -#endif -#ifdef CONFIG_RTC -#define WPS_RTC_REFRESH WPS_REFRESH_DYNAMIC -#else -#define WPS_RTC_REFRESH WPS_REFRESH_STATIC -#endif - -/* array of available tags - those with more characters have to go first - (e.g. "xl" and "xd" before "x"). It needs to end with the unknown token. */ -static const struct wps_tag all_tags[] = { - - { WPS_TOKEN_ALIGN_CENTER, "ac", 0, NULL }, - { WPS_TOKEN_ALIGN_LEFT, "al", 0, NULL }, - { WPS_TOKEN_ALIGN_RIGHT, "ar", 0, NULL }, - - { WPS_TOKEN_BATTERY_PERCENT, "bl", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_BATTERY_VOLTS, "bv", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_BATTERY_TIME, "bt", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_BATTERY_SLEEPTIME, "bs", WPS_REFRESH_DYNAMIC, NULL }, -#if CONFIG_CHARGING >= CHARGING_MONITOR - { WPS_TOKEN_BATTERY_CHARGING, "bc", WPS_REFRESH_DYNAMIC, NULL }, -#endif -#if CONFIG_CHARGING - { WPS_TOKEN_BATTERY_CHARGER_CONNECTED,"bp", WPS_REFRESH_DYNAMIC, NULL }, -#endif - - { WPS_TOKEN_RTC_PRESENT , "cc", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_RTC_DAY_OF_MONTH, "cd", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED,"ce", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_12HOUR_CFG, "cf", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED, "cH", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_HOUR_24, "ck", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED, "cI", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_HOUR_12, "cl", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_MONTH, "cm", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_MINUTE, "cM", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_SECOND, "cS", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_YEAR_2_DIGITS, "cy", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_YEAR_4_DIGITS, "cY", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_AM_PM_UPPER, "cP", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_AM_PM_LOWER, "cp", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_WEEKDAY_NAME, "ca", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_MONTH_NAME, "cb", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON, "cu", WPS_RTC_REFRESH, NULL }, - { WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN, "cw", WPS_RTC_REFRESH, NULL }, - - /* current file */ - { WPS_TOKEN_FILE_BITRATE, "fb", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_CODEC, "fc", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_FREQUENCY, "ff", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_FREQUENCY_KHZ, "fk", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "fm", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_NAME, "fn", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_PATH, "fp", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_SIZE, "fs", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_VBR, "fv", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_DIRECTORY, "d", WPS_REFRESH_STATIC, - parse_dir_level }, - - /* next file */ - { WPS_TOKEN_FILE_BITRATE, "Fb", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_CODEC, "Fc", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_FREQUENCY, "Ff", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_FREQUENCY_KHZ, "Fk", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_NAME_WITH_EXTENSION, "Fm", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_NAME, "Fn", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_PATH, "Fp", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_SIZE, "Fs", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_VBR, "Fv", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_FILE_DIRECTORY, "D", WPS_REFRESH_STATIC, - parse_dir_level }, - - /* current metadata */ - { WPS_TOKEN_METADATA_ARTIST, "ia", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_COMPOSER, "ic", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_ALBUM, "id", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_ALBUM_ARTIST, "iA", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_GROUPING, "iG", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_GENRE, "ig", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_DISC_NUMBER, "ik", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_TRACK_NUMBER, "in", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_TRACK_TITLE, "it", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_VERSION, "iv", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_YEAR, "iy", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_COMMENT, "iC", WPS_REFRESH_STATIC, NULL }, - - /* next metadata */ - { WPS_TOKEN_METADATA_ARTIST, "Ia", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_COMPOSER, "Ic", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_ALBUM, "Id", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_ALBUM_ARTIST, "IA", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_GROUPING, "IG", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_GENRE, "Ig", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_DISC_NUMBER, "Ik", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_TRACK_NUMBER, "In", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_TRACK_TITLE, "It", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_VERSION, "Iv", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_YEAR, "Iy", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_METADATA_COMMENT, "IC", WPS_REFRESH_STATIC, NULL }, - -#if (CONFIG_CODEC != MAS3507D) - { WPS_TOKEN_SOUND_PITCH, "Sp", WPS_REFRESH_DYNAMIC, NULL }, -#endif - -#if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD) - { WPS_TOKEN_VLED_HDD, "lh", WPS_REFRESH_DYNAMIC, NULL }, -#endif - - { WPS_TOKEN_MAIN_HOLD, "mh", WPS_REFRESH_DYNAMIC, NULL }, - -#ifdef HAS_REMOTE_BUTTON_HOLD - { WPS_TOKEN_REMOTE_HOLD, "mr", WPS_REFRESH_DYNAMIC, NULL }, -#else - { WPS_TOKEN_UNKNOWN, "mr", 0, NULL }, -#endif - - { WPS_TOKEN_REPEAT_MODE, "mm", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_PLAYBACK_STATUS, "mp", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_BUTTON_VOLUME, "mv", WPS_REFRESH_DYNAMIC, - parse_timeout }, - -#ifdef HAVE_LCD_BITMAP - { WPS_TOKEN_PEAKMETER, "pm", WPS_REFRESH_PEAK_METER, NULL }, -#else - { WPS_TOKEN_PLAYER_PROGRESSBAR, "pf", - WPS_REFRESH_DYNAMIC | WPS_REFRESH_PLAYER_PROGRESS, parse_progressbar }, -#endif - { WPS_TOKEN_PROGRESSBAR, "pb", WPS_REFRESH_PLAYER_PROGRESS, - parse_progressbar }, - - { WPS_TOKEN_VOLUME, "pv", WPS_REFRESH_DYNAMIC, NULL }, - - { WPS_TOKEN_TRACK_ELAPSED_PERCENT, "px", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_TRACK_TIME_ELAPSED, "pc", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_TRACK_TIME_REMAINING, "pr", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_TRACK_LENGTH, "pt", WPS_REFRESH_STATIC, NULL }, - - { WPS_TOKEN_PLAYLIST_POSITION, "pp", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_PLAYLIST_ENTRIES, "pe", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_PLAYLIST_NAME, "pn", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_PLAYLIST_SHUFFLE, "ps", WPS_REFRESH_DYNAMIC, NULL }, - -#ifdef HAVE_TAGCACHE - { WPS_TOKEN_DATABASE_PLAYCOUNT, "rp", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_DATABASE_RATING, "rr", WPS_REFRESH_DYNAMIC, NULL }, - { WPS_TOKEN_DATABASE_AUTOSCORE, "ra", WPS_REFRESH_DYNAMIC, NULL }, -#endif - -#if CONFIG_CODEC == SWCODEC - { WPS_TOKEN_REPLAYGAIN, "rg", WPS_REFRESH_STATIC, NULL }, - { WPS_TOKEN_CROSSFADE, "xf", WPS_REFRESH_DYNAMIC, NULL }, -#endif - - { WPS_NO_TOKEN, "s", WPS_REFRESH_SCROLL, NULL }, - { WPS_TOKEN_SUBLINE_TIMEOUT, "t", 0, parse_timeout }, - -#ifdef HAVE_LCD_BITMAP - { WPS_NO_TOKEN, "we", 0, parse_statusbar_enable }, - { WPS_NO_TOKEN, "wd", 0, parse_statusbar_disable }, - - { WPS_NO_TOKEN, "xl", 0, parse_image_load }, - - { WPS_TOKEN_IMAGE_PRELOAD_DISPLAY, "xd", WPS_REFRESH_STATIC, - parse_image_display }, - - { WPS_TOKEN_IMAGE_DISPLAY, "x", 0, parse_image_load }, -#ifdef HAVE_ALBUMART - { WPS_NO_TOKEN, "Cl", 0, parse_albumart_load }, - { WPS_TOKEN_ALBUMART_DISPLAY, "C", WPS_REFRESH_STATIC, - parse_albumart_conditional }, -#endif - - { WPS_VIEWPORT_ENABLE, "Vd", WPS_REFRESH_DYNAMIC, - parse_viewport_display }, - { WPS_NO_TOKEN, "V", 0, parse_viewport }, - -#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) - { WPS_TOKEN_IMAGE_BACKDROP, "X", 0, parse_image_special }, -#endif -#endif - - { WPS_TOKEN_SETTING, "St", WPS_REFRESH_DYNAMIC, parse_setting }, - - { WPS_TOKEN_LASTTOUCH, "Tl", WPS_REFRESH_DYNAMIC, parse_timeout }, - { WPS_NO_TOKEN, "T", 0, parse_touchregion }, - - { WPS_TOKEN_UNKNOWN, "", 0, NULL } - /* the array MUST end with an empty string (first char is \0) */ -}; - -/* Returns the number of chars that should be skipped to jump - immediately after the first eol, i.e. to the start of the next line */ -static int skip_end_of_line(const char *wps_bufptr) -{ - line++; - int skip = 0; - while(*(wps_bufptr + skip) != '\n') - skip++; - return ++skip; -} - -/* Starts a new subline in the current line during parsing */ -static void wps_start_new_subline(struct wps_data *data) -{ - data->num_sublines++; - data->sublines[data->num_sublines].first_token_idx = data->num_tokens; - data->lines[data->num_lines].num_sublines++; -} - -#ifdef HAVE_LCD_BITMAP - -static int parse_statusbar_enable(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - (void)token; /* Kill warnings */ - wps_data->wps_sb_tag = true; - wps_data->show_sb_on_wps = true; - if (wps_data->viewports[0].vp.y == 0) - { - wps_data->viewports[0].vp.y = STATUSBAR_HEIGHT; - wps_data->viewports[0].vp.height -= STATUSBAR_HEIGHT; - } - return skip_end_of_line(wps_bufptr); -} - -static int parse_statusbar_disable(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - (void)token; /* Kill warnings */ - wps_data->wps_sb_tag = true; - wps_data->show_sb_on_wps = false; - if (wps_data->viewports[0].vp.y == STATUSBAR_HEIGHT) - { - wps_data->viewports[0].vp.y = 0; - wps_data->viewports[0].vp.height += STATUSBAR_HEIGHT; - } - return skip_end_of_line(wps_bufptr); -} - -static bool load_bitmap(struct wps_data *wps_data, - char* filename, - struct bitmap *bm) -{ - int format; -#ifdef HAVE_REMOTE_LCD - if (wps_data->remote_wps) - format = FORMAT_ANY|FORMAT_REMOTE; - else -#endif - format = FORMAT_ANY|FORMAT_TRANSPARENT; - - int ret = read_bmp_file(filename, bm, - wps_data->img_buf_free, - format,NULL); - - if (ret > 0) - { -#if LCD_DEPTH == 16 - if (ret % 2) ret++; - /* Always consume an even number of bytes */ -#endif - wps_data->img_buf_ptr += ret; - wps_data->img_buf_free -= ret; - - return true; - } - else - return false; -} - -static int get_image_id(int c) -{ - if(c >= 'a' && c <= 'z') - return c - 'a'; - else if(c >= 'A' && c <= 'Z') - return c - 'A' + 26; - else - return -1; -} - -static char *get_image_filename(const char *start, const char* bmpdir, - char *buf, int buf_size) -{ - const char *end = strchr(start, '|'); - - if ( !end || (end - start) >= (buf_size - (int)ROCKBOX_DIR_LEN - 2) ) - { - buf = "\0"; - return NULL; - } - - int bmpdirlen = strlen(bmpdir); - - strcpy(buf, bmpdir); - buf[bmpdirlen] = '/'; - memcpy( &buf[bmpdirlen + 1], start, end - start); - buf[bmpdirlen + 1 + end - start] = 0; - - return buf; -} - -static int parse_image_display(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - (void)wps_data; - int n = get_image_id(wps_bufptr[0]); - int subimage; - - if (n == -1) - { - /* invalid picture display tag */ - return WPS_ERROR_INVALID_PARAM; - } - - if ((subimage = get_image_id(wps_bufptr[1])) != -1) - { - /* Sanity check */ - if (subimage >= wps_data->img[n].num_subimages) - return WPS_ERROR_INVALID_PARAM; - - /* Store sub-image number to display in high bits */ - token->value.i = n | (subimage << 8); - return 2; /* We have consumed 2 bytes */ - } else { - token->value.i = n; - return 1; /* We have consumed 1 byte */ - } -} - -static int parse_image_load(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - int n; - const char *ptr = wps_bufptr; - const char *pos; - const char* filename; - const char* id; - const char *newline; - int x,y; - - /* format: %x|n|filename.bmp|x|y| - or %xl|n|filename.bmp|x|y| - or %xl|n|filename.bmp|x|y|num_subimages| - */ - - if (*ptr != '|') - return WPS_ERROR_INVALID_PARAM; - - ptr++; - - if (!(ptr = parse_list("ssdd", NULL, '|', ptr, &id, &filename, &x, &y))) - return WPS_ERROR_INVALID_PARAM; - - /* Check there is a terminating | */ - if (*ptr != '|') - return WPS_ERROR_INVALID_PARAM; - - /* get the image ID */ - n = get_image_id(*id); - - /* check the image number and load state */ - if(n < 0 || n >= MAX_IMAGES || wps_data->img[n].loaded) - { - /* Invalid image ID */ - return WPS_ERROR_INVALID_PARAM; - } - - /* save a pointer to the filename */ - bmp_names[n] = filename; - - wps_data->img[n].x = x; - wps_data->img[n].y = y; - - /* save current viewport */ - wps_data->img[n].vp = &wps_data->viewports[wps_data->num_viewports].vp; - - if (token->type == WPS_TOKEN_IMAGE_DISPLAY) - { - wps_data->img[n].always_display = true; - } - else - { - /* Parse the (optional) number of sub-images */ - ptr++; - newline = strchr(ptr, '\n'); - pos = strchr(ptr, '|'); - if (pos && pos < newline) - wps_data->img[n].num_subimages = atoi(ptr); - - if (wps_data->img[n].num_subimages <= 0) - return WPS_ERROR_INVALID_PARAM; - } - - /* Skip the rest of the line */ - return skip_end_of_line(wps_bufptr); -} - -static int parse_viewport_display(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - (void)wps_data; - char letter = wps_bufptr[0]; - - if (letter < 'a' || letter > 'z') - { - /* invalid viewport tag */ - return WPS_ERROR_INVALID_PARAM; - } - token->value.i = letter; - return 1; -} - -static int parse_viewport(const char *wps_bufptr, - struct wps_token *token, - struct wps_data *wps_data) -{ - (void)token; /* Kill warnings */ - const char *ptr = wps_bufptr; - - const int screen = -#ifdef HAVE_REMOTE_LCD - wps_data->remote_wps ? SCREEN_REMOTE : -#endif - SCREEN_MAIN; - - if (wps_data->num_viewports >= WPS_MAX_VIEWPORTS) - return WPS_ERROR_INVALID_PARAM; - - wps_data->num_viewports++; - /* check for the optional letter to signify its a hideable viewport */ - /* %Vl|