diff --git a/apps/gui/skin_engine/skin_buffer.c b/apps/gui/skin_engine/skin_buffer.c index 750fec62b3..70716c1c60 100644 --- a/apps/gui/skin_engine/skin_buffer.c +++ b/apps/gui/skin_engine/skin_buffer.c @@ -38,6 +38,15 @@ * MAIN_ and REMOTE_BUFFER are just for reasonable size calibration, * both screens can use the whole buffer as they need; it's not split * between screens + * + * Buffer can be allocated from either "end" of the global buffer. + * items with unknown sizes get allocated from the start (0->) (data) + * items with known sizes get allocated from the end (<-buf_size) (tokens) + * After loading 2 skins the buffer will look like this: + * |tokens skin1|images skin2|---SPACE---|data skin2|data skin1| + * Make sure to never start allocating from the beginning before letting us know + * how much was used. and RESPECT THE buf_free RETURN VALUES! + * */ @@ -55,63 +64,93 @@ #define SKIN_BUFFER_SIZE (MAIN_BUFFER + REMOTE_BUFFER) -static unsigned char buffer_start[SKIN_BUFFER_SIZE], *buffer_pos = NULL; +static unsigned char buffer[SKIN_BUFFER_SIZE]; +static unsigned char *buffer_front = NULL; /* start of the free space, + increases with allocation*/ +static unsigned char *buffer_back = NULL; /* end of the free space + decreases with allocation */ static size_t buf_size = SKIN_BUFFER_SIZE; void skin_buffer_init(void) { #if 0 /* this will go in again later probably */ - if (buffer_start == NULL) + if (buffer == NULL) { buf_size = SKIN_BUFFER_SIZE;/* global_settings.skin_buf_size */ - buffer_start = buffer_alloc(buf_size); - buffer_pos = buffer_start; + buffer = buffer_alloc(buf_size); + buffer_front = buffer; + buffer_back = bufer + buf_size; } else #endif { /* reset the buffer.... */ - buffer_pos = buffer_start; + buffer_front = buffer; + buffer_back = buffer + buf_size; } } /* get the number of bytes currently being used */ size_t skin_buffer_usage(void) { - return buffer_pos-buffer_start; + return buf_size - (buffer_back-buffer_front); } -/* Allocate size bytes from the buffer */ +size_t skin_buffer_freespace(void) +{ + return buffer_back-buffer_front; +} + +/* Allocate size bytes from the buffer + * allocates from the back end (data end) + */ void* skin_buffer_alloc(size_t size) { - void* retval = buffer_pos; - if (skin_buffer_usage()+size >= buf_size) + if (skin_buffer_freespace() <= size) { return NULL; } - buffer_pos += size; + buffer_back -= size; /* 32-bit aligned */ - buffer_pos = (void *)(((unsigned long)buffer_pos + 3) & ~3); - return retval; + buffer_back = (void *)(((unsigned long)buffer_back) & ~3); + return buffer_back; } /* 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 + * + * This is from the start of the buffer, it is YOUR responsility to make + * sure you dont ever use more then *freespace, and bear in mind this will only + * be valid untill skin_buffer_alloc() is next called... + * so call skin_buffer_increment() and skin_buffer_freespace() regularly */ void* skin_buffer_grab(size_t *freespace) { *freespace = buf_size - skin_buffer_usage(); - return buffer_pos; + return buffer_front; } /* Use after skin_buffer_grab() to specify how much buffer was used */ -void skin_buffer_increment(size_t used) +void skin_buffer_increment(size_t used, bool align) { - buffer_pos += used; - /* 32-bit aligned */ - buffer_pos = (void *)(((unsigned long)buffer_pos + 3) & ~3); + buffer_front += used; + if (align) + { + /* 32-bit aligned */ + buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3); + } } +/* free previously skin_buffer_increment()'ed space. This just moves the pointer + * back 'used' bytes so make sure you actually want to do this */ +void skin_buffer_free_from_front(size_t used) +{ + buffer_front -= used; + /* 32-bit aligned */ + buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3); +} + + diff --git a/apps/gui/skin_engine/skin_buffer.h b/apps/gui/skin_engine/skin_buffer.h index 779f575689..7d05c95dd9 100644 --- a/apps/gui/skin_engine/skin_buffer.h +++ b/apps/gui/skin_engine/skin_buffer.h @@ -33,6 +33,7 @@ void skin_buffer_init(void); /* get the number of bytes currently being used */ size_t skin_buffer_usage(void); +size_t skin_buffer_freespace(void); /* Allocate size bytes from the buffer */ void* skin_buffer_alloc(size_t size); @@ -42,10 +43,22 @@ void* skin_buffer_alloc(size_t size); * 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 + * + * This is from the start of the buffer, it is YOUR responsility to make + * sure you dont ever use more then *freespace, and bear in mind this will only + * be valid untill skin_buffer_alloc() is next called... + * so call skin_buffer_increment() and skin_buffer_freespace() regularly */ 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); +/* Use after skin_buffer_grab() to specify how much buffer was used. + * align should always be true unless there is a possibility that you will need + * more space *immediatly* after the previous allocation. (i.e in an array). + * NEVER leave the buffer unaligned */ +void skin_buffer_increment(size_t used, bool align); + +/* free previously skin_buffer_increment()'ed space. This just moves the pointer + * back 'used' bytes so make sure you actually want to do this */ +void skin_buffer_free_from_front(size_t used); #endif /* _SKIN_BUFFER_H_ */ diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c index b7f2ec3091..62ee365128 100644 --- a/apps/gui/skin_engine/skin_parser.c +++ b/apps/gui/skin_engine/skin_parser.c @@ -1274,18 +1274,44 @@ static int parse_token(const char *wps_bufptr, struct wps_data *wps_data) data is the pointer to the structure where the parsed WPS should be stored. It is initialised. wps_bufptr points to the string containing the WPS tags */ +#define TOKEN_BLOCK_SIZE 128 static bool wps_parse(struct wps_data *data, const char *wps_bufptr) { if (!data || !wps_bufptr || !*wps_bufptr) return false; enum wps_parse_error fail = PARSE_OK; int ret; + int max_tokens = TOKEN_BLOCK_SIZE; + size_t buf_free = 0; line = 1; level = -1; + + /* allocate enough RAM for a reasonable skin, grow as needed. + * Free any used RAM before loading the images to be 100% RAM efficient */ + data->tokens = (struct wps_token *)skin_buffer_grab(&buf_free); + if (sizeof(struct wps_token)*max_tokens >= buf_free) + return false; + skin_buffer_increment(max_tokens * sizeof(struct wps_token), false); + data->num_tokens = 0; - while(*wps_bufptr && !fail && data->num_tokens < WPS_MAX_TOKENS - 1 + while(*wps_bufptr && !fail && data->num_lines < WPS_MAX_LINES) { + /* first make sure there is enough room for tokens */ + if (max_tokens -1 == data->num_tokens) + { + int extra_tokens = TOKEN_BLOCK_SIZE; + size_t needed = extra_tokens * sizeof(struct wps_token); + /* do some smarts here to grow the array a bit */ + if (skin_buffer_freespace() < needed) + { + fail = PARSE_FAIL_LIMITS_EXCEEDED; + break; + } + skin_buffer_increment(needed, false); + max_tokens += extra_tokens; + } + switch(*wps_bufptr++) { @@ -1482,6 +1508,10 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr) /* one of the limits of the while loop was exceeded */ fail = PARSE_FAIL_LIMITS_EXCEEDED; + /* Success! */ + /* freeup unused tokens */ + skin_buffer_free_from_front(sizeof(struct wps_token) + * (max_tokens - data->num_tokens)); curr_vp->last_line = data->num_lines - 1; #if defined(DEBUG) || defined(SIMULATOR) @@ -1528,7 +1558,7 @@ static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char if (ret > 0) { - skin_buffer_increment(ret); + skin_buffer_increment(ret, true); loaded = true; } else diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h index 0adae04c42..20a9dde9f9 100644 --- a/apps/gui/skin_engine/wps_internals.h +++ b/apps/gui/skin_engine/wps_internals.h @@ -276,7 +276,7 @@ struct wps_data /* Total number of tokens in the WPS. During WPS parsing, this is the index of the token being parsed. */ int num_tokens; - struct wps_token tokens[WPS_MAX_TOKENS]; + struct wps_token *tokens; struct skin_token_list *strings;