diff --git a/apps/SOURCES b/apps/SOURCES
index 58186d2..760a371 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -94,7 +94,6 @@ gui/yesno.c
 gui/viewport.c
 
 gui/skin_engine/skin_backdrops.c
-gui/skin_engine/skin_buffer.c
 gui/skin_engine/wps_debug.c
 gui/skin_engine/skin_display.c
 #ifdef HAVE_LCD_BITMAP
diff --git a/apps/gui/skin_engine/skin_buffer.c b/apps/gui/skin_engine/skin_buffer.c
deleted file mode 100644
index d503b83..0000000
--- a/apps/gui/skin_engine/skin_buffer.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * 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.
- *
- ****************************************************************************/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "config.h"
-#include "buffer.h"
-#include "settings.h"
-#include "screen_access.h"
-#include "skin_engine.h"
-#include "wps_internals.h"
-#include "skin_tokens.h"
-#include "skin_buffer.h"
-#include "skin_fonts.h"
-
-/* skin buffer management.
- * This module is used to allocate space in a single global skin buffer for
- * tokens for both/all screens.
- *
- * This is mostly just copy/paste from firmware/buffer.c
- *
- *
- * 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 skin1|tokens s2|images s2|---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!
- *
- */
-
-
-#ifdef HAVE_LCD_BITMAP
-#define MAIN_BUFFER ((2*LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \
-                    + (SKINNABLE_SCREENS_COUNT * LCD_BACKDROP_BYTES))
-
-#if (NB_SCREENS > 1)
-#define REMOTE_BUFFER (2*(LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \
-                      + (SKINNABLE_SCREENS_COUNT * REMOTE_LCD_BACKDROP_BYTES))
-#else
-#define REMOTE_BUFFER 0
-#endif
-
-
-#define SKIN_BUFFER_SIZE (MAIN_BUFFER + REMOTE_BUFFER + SKIN_FONT_SIZE) + \
-                         (WPS_MAX_TOKENS * sizeof(struct wps_token))
-#endif
-
-#ifdef HAVE_LCD_CHARCELLS
-#define SKIN_BUFFER_SIZE (LCD_HEIGHT * LCD_WIDTH) * 64 + \
-                         (WPS_MAX_TOKENS * sizeof(struct wps_token))
-#endif
-
-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 == NULL)
-    {
-        buf_size = SKIN_BUFFER_SIZE;/* global_settings.skin_buf_size */
-
-        buffer = buffer_alloc(buf_size);
-        buffer_front = buffer;
-        buffer_back = bufer + buf_size;
-    }
-    else
-#endif
-    {
-        /* reset the buffer.... */
-        buffer_front = buffer;
-        buffer_back = buffer + buf_size;
-    }
-}
-
-/* get the number of bytes currently being used */
-size_t skin_buffer_usage(void)
-{
-    return buf_size - (buffer_back-buffer_front);
-}
-
-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)
-{
-    if (skin_buffer_freespace() <= size)
-    {
-        return NULL;
-    }
-    buffer_back -= size;
-    /* 32-bit aligned */
-    buffer_back = (void *)(((unsigned long)buffer_back) & ~3);
-
-    memset(buffer_back, 0, size);
-    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_front;
-}
-
-/* Use after skin_buffer_grab() to specify how much buffer was used */
-void skin_buffer_increment(size_t used, bool align)
-{
-    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
deleted file mode 100644
index 521631f..0000000
--- a/apps/gui/skin_engine/skin_buffer.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * 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 <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-/* int the global buffer */
-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);
-
-
-/* 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);
-
-/* 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 b9254d9..6711053 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -69,6 +69,21 @@
 #include "backdrop.h"
 #include "statusbar-skinned.h"
 
+#include "skin_parser.h"
+#include "tag_table.h"
+
+
+static bool isdefault(struct skin_tag_parameter *param)
+{
+    return param->type == DEFAULT;
+}
+
+
+#define EAT_NEWLINE 666
+
+
+
+
 #define WPS_ERROR_INVALID_PARAM         -1
 
 /* which screen are we parsing for? */
@@ -78,16 +93,6 @@ static enum screen_type curr_screen;
    -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];
-
 /* line number, debug only */
 static int line_number;
 
@@ -104,6 +109,10 @@ extern void print_debug_info(struct wps_data *data, int fail, int line);
 extern void debug_skin_usage(void);
 #endif
 
+
+int convert_elements(struct wps_data *data, struct skin_element* tree, struct skin_element* parent);
+int count_elements(struct skin_element* tree);
+
 /* 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
@@ -152,8 +161,6 @@ static int parse_viewport_display(const char *wps_bufptr,
         struct wps_token *token, struct wps_data *wps_data);
 static int parse_playlistview(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,
@@ -407,7 +414,7 @@ static const struct wps_tag all_tags[] = {
     { WPS_TOKEN_VIEWPORT_FGCOLOUR,        "Vf", WPS_REFRESH_STATIC, parse_viewportcolour },
     { WPS_TOKEN_VIEWPORT_BGCOLOUR,        "Vb", WPS_REFRESH_STATIC, parse_viewportcolour },
 #endif
-    { WPS_NO_TOKEN,                       "V",   0,    parse_viewport      },
+ //   { 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 },
@@ -515,10 +522,7 @@ static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
 static int skip_end_of_line(const char *wps_bufptr)
 {
     line_number++;
-    int skip = 0;
-    while(*(wps_bufptr + skip) != '\n')
-        skip++;
-    return ++skip;
+    return EAT_NEWLINE;
 }
 
 /* Starts a new subline in the current line during parsing */
@@ -711,7 +715,9 @@ static int parse_image_load(const char *wps_bufptr,
     if (!img)
         return WPS_ERROR_INVALID_PARAM;
     /* save a pointer to the filename */
-    img->bm.data = (char*)filename;
+    /* nasty but necessary */
+    img->bm.data = skin_buffer_alloc(strlen(filename));
+    strcpy(img->bm.data, filename);
     img->label = *id;
     img->x = x;
     img->y = y;
@@ -785,7 +791,8 @@ static int parse_font_load(const char *wps_bufptr,
     if (!ptr || strncmp(ptr, ".fnt)", 5))
         return WPS_ERROR_INVALID_PARAM;
     skinfonts[id-FONT_FIRSTUSERFONT].id = -1;
-    skinfonts[id-FONT_FIRSTUSERFONT].name = filename;
+    skinfonts[id-FONT_FIRSTUSERFONT].name = skin_buffer_alloc(strlen(filename));
+    strcpy(skinfonts[id-FONT_FIRSTUSERFONT].name, filename);
 
     return skip_end_of_line(wps_bufptr);
 }
@@ -927,7 +934,7 @@ static int parse_playlistview(const char *wps_bufptr,
     return skip_end_of_line(wps_bufptr);
 }
 #endif
-
+#if 0 // REMOVE ME
 static int parse_viewport(const char *wps_bufptr,
                           struct wps_token *token,
                           struct wps_data *wps_data)
@@ -1025,6 +1032,7 @@ static int parse_viewport(const char *wps_bufptr,
     /* Skip the rest of the line */
     return ptr-wps_bufptr;
 }
+#endif
 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
 static int parse_viewportcolour(const char *wps_bufptr,
         struct wps_token *token, struct wps_data *wps_data)
@@ -1101,7 +1109,11 @@ static int parse_image_special(const char *wps_bufptr,
             return skip_end_of_line(wps_bufptr);
         }
         else if (!error)
-            wps_data->backdrop = (char*)wps_bufptr + 1;
+        {
+            /* nasty but necessary */
+            wps_data->backdrop = skin_buffer_alloc(strlen(wps_bufptr+1));
+            strcpy(wps_data->backdrop, wps_bufptr+1);
+        }
     }
 #endif
     if (error)
@@ -1298,7 +1310,11 @@ static int parse_progressbar(const char *wps_bufptr,
         return WPS_ERROR_INVALID_PARAM;
 
     if (LIST_VALUE_PARSED(set, PB_FILENAME)) /* filename */
-        pb->bm.data = (char*)filename;
+    {
+        /* nasty but necessary */
+        pb->bm.data = skin_buffer_alloc(strlen(filename));
+        strcpy(pb->bm.data, filename);
+    }
 
     if (LIST_VALUE_PARSED(set, PB_X)) /* x */
         pb->x = x;
@@ -1628,7 +1644,7 @@ static int parse_touchregion(const char *wps_bufptr,
     return skip_end_of_line(wps_bufptr);
 }
 #endif
-
+#if 0 // REMOVE ME
 /* Parse a generic token from the given string. Return the length read */
 static int parse_token(const char *wps_bufptr, struct wps_data *wps_data)
 {
@@ -1702,90 +1718,30 @@ static int parse_token(const char *wps_bufptr, struct wps_data *wps_data)
     skip += taglen;
     return skip;
 }
+#endif
 
-
-/*
- * Returns the number of bytes to skip the buf pointer to access the false
- * branch in a _binary_ conditional
- *
- * That is:
- *  - before the '|' if we have a false branch, (%?<true|false> -> %?<|false>)
- *  - or before the closing '>' if there's no false branch (%?<true> -> %?<>)
- *
- * depending on the features of a target it's not called from check_feature_tag,
- * hence the __attribute__ or it issues compiler warnings
- *
- **/
-
-static int find_false_branch(const char *wps_bufptr) __attribute__((unused));
-static int find_false_branch(const char *wps_bufptr)
-{
-    const char *buf = wps_bufptr;
-    /* wps_bufptr is after the opening '<', hence level = 1*/
-    int level = 1;
-    char ch;
-    do
-    {
-        ch = *buf;
-        if (ch == '%')
-        {   /* filter out the characters we check later if they're printed
-             * as literals */
-            ch = *(++buf);
-            if (ch == '<' || ch == '>' || ch == '|')
-                continue;
-            /* else: some tags/printed literals we skip over */
-        }
-        else if (ch == '<') /* nested conditional */
-            level++;
-        else if (ch == '>')
-        {   /* closed our or a nested conditional,
-             * do NOT skip over the '>' so that wps_parse() sees it for closing
-             * if it is the closing one for our conditional */
-            level--;
-        }
-        else if (ch == '|' && level == 1)
-        {   /* we found our separator, point before and get out */
-            break;
-        }
-    /* if level is 0, we don't have a false branch */
-    } while (level > 0 && *(++buf));
-
-    return buf - wps_bufptr;
-}
-
-/*
- * returns the number of bytes to get the appropriate branch of a binary
- * conditional
- *
- * That means:
- *  - if a feature is available, it returns 0 to not skip anything
- *  - if the feature is not available, skip to the false branch and don't
- *    parse the true branch at all
- *
- * */
-static int check_feature_tag(const char *wps_bufptr, const int type)
+static int check_feature_tag(const int type)
 {
-    (void)wps_bufptr;
     switch (type)
     {
         case WPS_TOKEN_RTC_PRESENT:
 #if CONFIG_RTC
             return 0;
 #else
-            return find_false_branch(wps_bufptr);
+            return 1;
 #endif
         case WPS_TOKEN_HAVE_RECORDING:
 #ifdef HAVE_RECORDING
             return 0;
 #else
-            return find_false_branch(wps_bufptr);
+            return 1;
 #endif
         case WPS_TOKEN_HAVE_TUNER:
 #if CONFIG_TUNER
             if (radio_hardware_present())
                 return 0;
 #endif
-            return find_false_branch(wps_bufptr);
+            return 1;
 
         default: /* not a tag we care about, just don't skip */
             return 0;
@@ -1793,29 +1749,27 @@ static int check_feature_tag(const char *wps_bufptr, const int type)
 }
 
 
-/* Parses the WPS.
-   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
+int max_tokens;
+/* Convert the tree to a token array so it is useable */
 static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
 {
     if (!data || !wps_bufptr || !*wps_bufptr)
         return false;
     enum wps_parse_error fail = PARSE_OK;
+    struct skin_element *tree = data->tree;
     int ret;
-    int max_tokens = TOKEN_BLOCK_SIZE;
-    size_t buf_free = 0;
+    max_tokens = count_elements(tree);
+    
     line_number = 0;
     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)
+    data->tokens = (struct wps_token *)skin_buffer_alloc(sizeof(struct wps_token)*max_tokens);
+    if (!data->tokens)
         return false;
-    skin_buffer_increment(max_tokens * sizeof(struct wps_token), false);
     data->num_tokens = 0;
+    
 
 #if LCD_DEPTH > 1
     /* Backdrop defaults to the setting unless %X is used, so set it now */
@@ -1825,25 +1779,14 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
     }
 #endif
 
+    convert_elements(data, tree, NULL);
+    
+#if 0 // OLD CODE!
     while (*wps_bufptr && !fail)
     {
         if (follow_lang_direction)
             follow_lang_direction--;
-        /* first make sure there is enough room for tokens */
-        if (max_tokens <= data->num_tokens + 5)
-        {
-            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++)
         {
 
@@ -2029,24 +1972,18 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
                 break;
         }
     }
-
+#endif
     if (!fail && level >= 0) /* there are unclosed conditionals */
         fail = PARSE_FAIL_UNCLOSED_COND;
 
-    if (*wps_bufptr && !fail)
-        /* one of the limits of the while loop was exceeded */
-        fail = PARSE_FAIL_LIMITS_EXCEEDED;
-
     /* Success! */
     curr_line->curr_subline->last_token_idx = data->num_tokens;
     data->tokens[data->num_tokens++].type = WPS_NO_TOKEN;
-    /* freeup unused tokens */
-    skin_buffer_free_from_front(sizeof(struct wps_token)
-                                * (max_tokens - data->num_tokens));
 
 #if defined(DEBUG) || defined(SIMULATOR)
     if (debug)
     {
+        DEBUGF("used tokens: %d/%d\n",  data->num_tokens, max_tokens);
         print_debug_info(data, fail, line_number);
         debug_skin_usage();
     }
@@ -2109,6 +2046,7 @@ static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char
 {
     (void)wps_data; /* only needed for remote targets */
     char img_path[MAX_PATH];
+    size_t needed_size;
     get_image_filename(bitmap->data, bmpdir,
                        img_path, sizeof(img_path));
 
@@ -2120,15 +2058,17 @@ static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char
     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);
+        
+    needed_size = read_bmp_file(img_path, bitmap, 0, format|FORMAT_RETURN_SIZE, NULL);
+        
+    bitmap->data = skin_buffer_alloc(needed_size);
+    if (bitmap->data == NULL)
+        return false;
+        
+    int ret = read_bmp_file(img_path, bitmap, needed_size, format, NULL);
 
     if (ret > 0)
     {
-        skin_buffer_increment(ret, true);
         return true;
     }
     else
@@ -2350,6 +2290,8 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
     {
         wps_buffer = (char*)buf;
     }
+    
+    wps_data->tree = skin_parse(wps_buffer);
     /* parse the WPS source */
     if (!wps_parse(wps_data, wps_buffer, isfile)) {
         skin_data_reset(wps_data);
@@ -2401,3 +2343,357 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
 #endif
     return true;
 }
+
+static int convert_viewport(struct wps_data *data, struct skin_element* element)
+{
+    struct skin_viewport *skin_vp = skin_buffer_alloc(sizeof(struct skin_viewport));
+    struct screen *display = &screens[curr_screen];
+    /* Steps:
+     * 1) allocate a new skin_vp
+     * 2) close the last viewports last line (i.e curr_line->curr_subline)
+     * 3) setup this viewport
+     * 4) link this viewport into the list
+     */
+    
+    skin_vp->hidden_flags = 0;
+    skin_vp->label = VP_NO_LABEL;
+    skin_vp->lines  = NULL;
+    if (curr_line)
+    {
+        /* Need to make sure the previous subline isnt empty */
+        if (curr_line->curr_subline->first_token_idx == data->num_tokens)
+        {
+            struct wps_token *token = data->tokens + data->num_tokens;
+            memset(token, 0, sizeof(*token));
+            token->type = WPS_TOKEN_CHARACTER;
+            token->value.i = '\n';
+            data->num_tokens++;
+        }
+        curr_line->curr_subline->last_token_idx = data->num_tokens-1;
+    }
+    viewport_set_defaults(&skin_vp->vp, curr_screen);
+
+    curr_line = NULL;
+    struct skin_tag_parameter *param = element->params;
+    if (element->params_count == 6)
+    {
+        if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD)
+        {
+            if (isdefault(param))
+            {
+                skin_vp->hidden_flags = VP_NEVER_VISIBLE;
+                skin_vp->label = VP_INFO_LABEL|VP_DEFAULT_LABEL;
+            }
+            else
+            {
+                skin_vp->hidden_flags = VP_NEVER_VISIBLE;
+                skin_vp->label = VP_INFO_LABEL|param->data.text[0];
+            }
+        }
+        else
+        {
+                skin_vp->hidden_flags = VP_DRAW_HIDEABLE;
+                skin_vp->label = param->data.text[0];
+        }
+        param++;
+    }
+    /* x */
+    if (!isdefault(param))
+    {
+        skin_vp->vp.x = param->data.numeric;
+        if (param->data.numeric < 0)
+            skin_vp->vp.x += display->lcdwidth;
+    }
+    param++;
+    /* y */
+    if (!isdefault(param))
+    {
+        skin_vp->vp.y = param->data.numeric;
+        if (param->data.numeric < 0)
+            skin_vp->vp.y += display->lcdheight;
+    }
+    param++;
+    /* width */
+    if (!isdefault(param))
+    {
+        skin_vp->vp.width = param->data.numeric;
+        if (param->data.numeric < 0)
+            skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x;
+    }
+    param++;
+    /* height */
+    if (!isdefault(param))
+    {
+        skin_vp->vp.height = param->data.numeric;
+        if (param->data.numeric < 0)
+            skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y;
+    }
+    param++;
+    /* font */
+    if (!isdefault(param))
+    {
+        skin_vp->vp.font = param->data.numeric;
+    }
+#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
+    skin_vp->start_fgcolour = skin_vp->vp.fg_pattern;
+    skin_vp->start_bgcolour = skin_vp->vp.bg_pattern;
+#endif
+
+    struct skin_token_list *list = new_skin_token_list_item(NULL, skin_vp);
+    if (!list)
+        return WPS_ERROR_INVALID_PARAM;
+    add_to_ll_chain(&data->viewports, list);
+    curr_vp = skin_vp;
+    skin_start_new_line(curr_vp, data->num_tokens);
+    /* Skip the rest of the line */
+    return 1;
+    
+}
+
+int convert_conditional(struct wps_data *data, struct skin_element* conditional)
+{
+    struct skin_element *line, *element = conditional;
+    struct wps_token *token = data->tokens + data->num_tokens;
+    int i, last_option, start;
+
+    memset(token, 0, sizeof(*token));
+    token->type = WPS_TOKEN_CONDITIONAL;
+    token->value.i = element->children_count;
+    level++;
+    data->num_tokens++;
+    element->type = UNKNOWN; /* spoof this so convert_element works */
+    convert_elements(data, element, conditional); /* Should add one token */
+    start = check_feature_tag(token[1].type);
+    token->value.i -= start;
+    
+    last_option = data->num_tokens;
+    for(i = start; i < conditional->children_count; i++)
+    {
+        token = data->tokens + data->num_tokens;
+        memset(token, 0, sizeof(*token));
+        token->type = i==start? WPS_TOKEN_CONDITIONAL_START: WPS_TOKEN_CONDITIONAL_OPTION;
+        data->tokens[last_option].value.i = data->num_tokens;
+        last_option = data->num_tokens;
+        data->num_tokens++;
+        line = conditional->children[i];
+        element = line->children_count ? line->children[0] : NULL;
+        /* convert_elements does the whole line chain so no looping here */
+        convert_elements(data, element, conditional);
+    }
+    token = data->tokens + data->num_tokens;
+    memset(token, 0, sizeof(*token));
+    token->type = WPS_TOKEN_CONDITIONAL_END;
+    data->tokens[last_option].value.i = data->num_tokens;
+    data->num_tokens++;
+    level--;
+    return 0;
+}
+
+int convert_elements(struct wps_data *data, struct skin_element* tree, struct skin_element* parent)
+{
+    int ret = 0;
+    struct skin_element* element = tree;
+    int i;
+    static char text[MAX_PATH];
+    struct wps_token *token;
+    static bool eat_line = false;
+    
+        
+    while (element && !ret)
+    {
+        if (max_tokens <= data->num_tokens)
+        {
+            return -1;
+        }
+        /* Do any preprocessing */
+        switch (element->type)
+        {
+            case COMMENT:
+                eat_line = true;
+                break;
+                
+            /* CAREFUL! in newparser LINE is the bottom level containing individual tags
+                                    SUBLINE contains an array of LINEs
+                        in oldparser lines always have sublines, sublines pointing to the individual tags
+            */
+            case LINE: 
+                break;
+            case SUBLINES:
+                if (parent->type == CONDITIONAL)
+                    return -2; /* unclosed conditional.. remove me later */
+                /* children are handled in the children loop below */
+                break;            
+            case TEXT:
+                token = data->tokens + data->num_tokens;
+                memset(token, 0, sizeof(*token));
+                token->type = WPS_TOKEN_STRING;
+                token->value.data = element->data;
+                data->num_tokens++;
+                break;
+            case VIEWPORT:
+                if (element->params_count == 0)
+                    break;
+                convert_viewport(data, element);
+                break;       
+            case CONDITIONAL:
+                ret = convert_conditional(data, element);
+                if (ret < 0)
+                    return ret;
+                element = element->next;
+                continue;
+                break;
+            case UNKNOWN:
+                if (parent->type != UNKNOWN)
+                    break;
+            case TAG:
+            {
+                const struct wps_tag *tag;
+                token = data->tokens + data->num_tokens;
+                memset(token, 0, sizeof(*token));
+                text[0] = '\0';
+                if (element->params_count > 0)
+                {
+                    for(i=0;i<element->params_count;i++)
+                    {
+                        struct skin_tag_parameter *p = &element->params[i];
+                        char temp[64]; 
+                        switch (p->type)
+                        {
+                            case NUMERIC:
+                                snprintf(temp, sizeof(temp), "%c%d", 
+                                        i==0?'(':',', p->data.numeric);
+                                break;
+                            case STRING:
+                                snprintf(temp, sizeof(temp), "%c%s", 
+                                        i==0?'(':',', p->data.text);
+                                break;
+                            case DEFAULT:
+                                snprintf(temp, sizeof(temp), "%c-", 
+                                        i==0?'(':',');
+                                break;
+                            case CODE:
+                                /* FIXME */
+                                break;
+                        }
+                        strlcat(text, temp, sizeof(text));
+                    }
+                    strlcat(text, ")\n", sizeof(text));
+                }
+                /* find what tag we have */
+                for (tag = all_tags;
+                     strncmp(element->tag->name, tag->name, strlen(tag->name)) != 0;
+                     tag++) ;
+
+                token->type = tag->type;
+                curr_line->curr_subline->line_type |= tag->refresh_type;
+                /* if the tag has a special parsing function, we call it */
+                if (tag->parse_func)
+                {
+                    int retval = tag->parse_func(text, token, data);
+                    if (retval == EAT_NEWLINE)
+                    {
+                        eat_line = true;
+                    }
+                    else if (retval < 0)
+                    {
+                        return -1;
+                    }
+                }
+
+                /* Some tags we don't want to save as tokens */
+                if (tag->type == WPS_NO_TOKEN)
+                    break;
+
+                /* tags that start with 'F', 'I' or 'D' are for the next file */
+                if ( *(tag->name) == 'I' || *(tag->name) == 'F' ||
+                     *(tag->name) == 'D')
+                    token->next = true;
+
+                data->num_tokens++;
+                break;
+            }
+        } /* switch (element->type) */
+        /* Do the children */
+        if (element->type != UNKNOWN)
+        {
+            for (i=0; i<element->children_count; i++)
+            {
+                ret = convert_elements(data, element->children[i], element);
+                if (ret < 0)
+                    return ret;
+            }
+        }
+        /* Do any postprocessing */
+        switch (element->type)
+        {
+            case UNKNOWN:
+                if (parent->type == UNKNOWN)
+                    return 0;
+            case COMMENT:
+                break;
+            case CONDITIONAL:
+                /* Should never get here */
+                break;
+            case LINE:
+                if (!eat_line && parent->type != CONDITIONAL)
+                {
+                    if (parent->type != SUBLINES)
+                    {
+                        line_number++;
+                        if (curr_line->curr_subline->first_token_idx == data->num_tokens)
+                        {
+                            struct wps_token *token = data->tokens + data->num_tokens;
+                            memset(token, 0, sizeof(*token));
+                            token->type = WPS_TOKEN_CHARACTER;
+                            token->value.i = '\n';
+                            data->num_tokens++;
+                        }
+                        skin_start_new_line(curr_vp, data->num_tokens);
+                    }
+                    else
+                    {
+                        skin_start_new_subline(curr_line, data->num_tokens);
+                    }
+                }
+                eat_line = false;
+                break;
+            case SUBLINES:
+                line_number++;
+                break;
+            case VIEWPORT:
+                break;
+            case TEXT:
+            case TAG:
+                break;
+        }
+        
+        element = element->next;
+    }
+    return ret;
+}
+                       
+
+int count_elements(struct skin_element* tree)
+{
+    int count = 0;
+    struct skin_element* element = tree;
+    int i;
+    while (element)
+    {
+        for (i=0; i<element->children_count; i++)
+        {
+            count += count_elements(element->children[i]);
+        }
+        if (element->type == CONDITIONAL)
+        {
+            /* conditionals add a START and END and a OPTION for each one */
+            count += element->children_count + 1;
+        }
+        if (element->type != COMMENT &&
+            element->type != SUBLINES
+            /*element->type != LINE*/)
+            count++;
+        element = element->next;
+    }
+    return count;
+}
diff --git a/apps/gui/skin_engine/wps_debug.c b/apps/gui/skin_engine/wps_debug.c
index a1ebb83..a418589 100644
--- a/apps/gui/skin_engine/wps_debug.c
+++ b/apps/gui/skin_engine/wps_debug.c
@@ -562,7 +562,7 @@ static void dump_skin(struct wps_data *data)
                     DEBUGF(", peakmeter");
                 DEBUGF("\n");
 
-                for (i = subline->first_token_idx; i <= subline->last_token_idx; i++)
+                for (i = subline->first_token_idx; i<data->num_tokens && i <= subline->last_token_idx; i++)
                 {
                     struct wps_token *token = &data->tokens[i];
                     get_token_desc(token, buf, sizeof(buf), data);
diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h
index 4ef860a..3d95ebd 100644
--- a/apps/gui/skin_engine/wps_internals.h
+++ b/apps/gui/skin_engine/wps_internals.h
@@ -33,6 +33,9 @@
 
 #include "skin_tokens.h"
 
+#include "skin_parser.h"
+#include "tag_table.h"
+
 
 /* TODO: sort this mess out */
 
@@ -280,6 +283,7 @@ struct skin_albumart {
    viewable content of a wps */
 struct wps_data
 {
+    struct skin_element *tree;
 #ifdef HAVE_LCD_BITMAP
     struct skin_token_list *images;
     struct skin_token_list *progressbars;
diff --git a/apps/gui/theme_settings.c b/apps/gui/theme_settings.c
index 7f4046c..d603a6c 100644
--- a/apps/gui/theme_settings.c
+++ b/apps/gui/theme_settings.c
@@ -67,11 +67,36 @@ static const struct skin_load_setting skins[] = {
 #endif
 };
 
+
+#ifdef HAVE_LCD_BITMAP
+#define MAIN_BUFFER ((2*LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \
+                    + (SKINNABLE_SCREENS_COUNT * LCD_BACKDROP_BYTES))
+
+#if (NB_SCREENS > 1)
+#define REMOTE_BUFFER (2*(LCD_REMOTE_HEIGHT*LCD_REMOTE_WIDTH*LCD_REMOTE_DEPTH/8) \
+                      + (SKINNABLE_SCREENS_COUNT * REMOTE_LCD_BACKDROP_BYTES))
+#else
+#define REMOTE_BUFFER 0
+#endif
+
+
+#define SKIN_BUFFER_SIZE (MAIN_BUFFER + REMOTE_BUFFER + SKIN_FONT_SIZE) + \
+                         (WPS_MAX_TOKENS * sizeof(struct wps_token))
+#endif
+
+#ifdef HAVE_LCD_CHARCELLS
+#define SKIN_BUFFER_SIZE (LCD_HEIGHT * LCD_WIDTH) * 64 + \
+                         (WPS_MAX_TOKENS * sizeof(struct wps_token))
+#endif
+
+static unsigned char skinbuffer[SKIN_BUFFER_SIZE];
+
+
 void settings_apply_skins(void)
 {
     char buf[MAX_PATH];
     /* re-initialize the skin buffer before we start reloading skins */
-    skin_buffer_init();
+    skin_buffer_init(skinbuffer, SKIN_BUFFER_SIZE);
     enum screen_type screen = SCREEN_MAIN;
     unsigned int i;
 #ifdef HAVE_LCD_BITMAP
diff --git a/apps/menus/main_menu.c b/apps/menus/main_menu.c
index 32164ff..1958e9c 100644
--- a/apps/menus/main_menu.c
+++ b/apps/menus/main_menu.c
@@ -51,7 +51,6 @@
 #include "version.h"
 #include "time.h"
 #include "wps.h"
-#include "skin_engine/skin_buffer.h"
 
 static const struct browse_folder_info config = {ROCKBOX_DIR, SHOW_CFG};
 
diff --git a/lib/skin_parser/skin_buffer.c b/lib/skin_parser/skin_buffer.c
index 05cdc0c..a6f1d8f 100644
--- a/lib/skin_parser/skin_buffer.c
+++ b/lib/skin_parser/skin_buffer.c
@@ -25,20 +25,27 @@
 #include <stdlib.h>
 
 #ifdef ROCKBOX
-#define SKIN_BUFFER_SIZE (400*1024) /* Excessivly large for now */
-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_start;
+static unsigned char *buffer;
+static size_t buf_size;
 #endif
 
-void skin_buffer_init(void)
+void skin_buffer_init(char* buf, size_t size)
 {
 #if defined(ROCKBOX)
+    if (buf == NULL)
     {
         /* reset the buffer.... */
-        buffer_front = buffer;
-        //TODO: buf_size = size;
+        buffer = buffer_start;
     }
+    else
+    {
+        /* new buffer */
+        buffer_start = buffer = buf;
+        buf_size = size;
+    }
+#else
+    (void)buf; (void)size;
 #endif
 }
 
@@ -47,10 +54,10 @@ void* skin_buffer_alloc(size_t size)
 {
     void *retval = NULL;
 #ifdef ROCKBOX    
-    retval = buffer_front;
-    buffer_front += size;
+    retval = buffer;
+    buffer += size;
     /* 32-bit aligned */
-    buffer_front = (void *)(((unsigned long)buffer_front + 3) & ~3);
+    buffer = (void *)(((unsigned long)buffer + 3) & ~3);
 #else
     retval = malloc(size);
 #endif
@@ -62,10 +69,10 @@ void* skin_buffer_alloc(size_t size)
 /* get the number of bytes currently being used */
 size_t skin_buffer_usage(void)
 {
-    return buffer_front - buffer;
+    return buffer - buffer_start;
 }
 size_t skin_buffer_freespace(void)
 {
-    return SKIN_BUFFER_SIZE - skin_buffer_usage();
+    return buf_size - skin_buffer_usage();
 }
 #endif
diff --git a/lib/skin_parser/skin_buffer.h b/lib/skin_parser/skin_buffer.h
index ff477da..20ca0a2 100644
--- a/lib/skin_parser/skin_buffer.h
+++ b/lib/skin_parser/skin_buffer.h
@@ -25,7 +25,14 @@
 #include <stdlib.h>
 #ifndef _SKIN_BUFFFER_H_
 #define _SKIN_BUFFFER_H_
-void skin_buffer_init(size_t size);
+
+
+struct skin_element* skin_alloc_element(void);
+struct skin_element** skin_alloc_children(int count);
+struct skin_tag_parameter* skin_alloc_params(int count);
+char* skin_alloc_string(int length);
+
+void skin_buffer_init(char* buf, size_t size);
 /* Allocate size bytes from the buffer */
 void* skin_buffer_alloc(size_t size);
 
diff --git a/lib/skin_parser/skin_parser.c b/lib/skin_parser/skin_parser.c
index b948520..cb935a1 100644
--- a/lib/skin_parser/skin_parser.c
+++ b/lib/skin_parser/skin_parser.c
@@ -52,6 +52,11 @@ static int skin_parse_comment(struct skin_element* element, char** document);
 static struct skin_element* skin_parse_code_as_arg(char** document);
 
 
+static void skip_whitespace(char** document)
+{
+    while(**document == ' ' || **document == '\t')
+        (*document)++;
+}
 
 struct skin_element* skin_parse(const char* document)
 {
diff --git a/lib/skin_parser/skin_parser.h b/lib/skin_parser/skin_parser.h
index 95a22a6..dfcfb5d 100644
--- a/lib/skin_parser/skin_parser.h
+++ b/lib/skin_parser/skin_parser.h
@@ -122,14 +122,8 @@ struct skin_element
 struct skin_element* skin_parse(const char* document);
 
 /* Memory management functions */
-struct skin_element* skin_alloc_element(void);
-struct skin_element** skin_alloc_children(int count);
-struct skin_tag_parameter* skin_alloc_params(int count);
-char* skin_alloc_string(int length);
-
 void skin_free_tree(struct skin_element* root);
 
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/skin_parser/skin_scan.c b/lib/skin_parser/skin_scan.c
index 79f7162..fd74aa2 100644
--- a/lib/skin_parser/skin_scan.c
+++ b/lib/skin_parser/skin_scan.c
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "skin_buffer.h"
 #include "skin_scan.h"
 #include "skin_debug.h"
 #include "symbols.h"
@@ -40,12 +41,6 @@ void skip_comment(char** document)
         (*document)++;
 }
 
-void skip_whitespace(char** document)
-{
-    while(**document == ' ' || **document == '\t')
-        (*document)++;
-}
-
 void skip_arglist(char** document)
 {
     if(**document == ARGLISTOPENSYM)
diff --git a/lib/skin_parser/skin_scan.h b/lib/skin_parser/skin_scan.h
index b1d04a6..72d4475 100644
--- a/lib/skin_parser/skin_scan.h
+++ b/lib/skin_parser/skin_scan.h
@@ -30,7 +30,6 @@ extern "C"
 
 /* Scanning functions */
 void skip_comment(char** document);
-void skip_whitespace(char** document);
 void skip_arglist(char** document);
 void skip_enumlist(char** document);
 char* scan_string(char** document);
