* Make the WPS parser close open conditionals on new sublines and comments as well as new lines.
* Make the displaying code check for invalid conditional constructs in order to avoid some rare cases of infinite looping.
* Make the WPS parser check that it doesn't read more strings than it can.
* Increase the string buffer size (from 512 to 1024, to accomodate the TextBox WPS which uses a lot of unicode characters).


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13162 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/gui/gwps-common.c b/apps/gui/gwps-common.c
index 6c58c1d..b4a2cf9 100644
--- a/apps/gui/gwps-common.c
+++ b/apps/gui/gwps-common.c
@@ -1279,9 +1279,9 @@
     }
 
     int ret = index;
-    do
+    while (data->tokens[ret].value.i != 0
+           && data->tokens[data->tokens[ret].value.i].type != WPS_TOKEN_CONDITIONAL_END)
         ret = data->tokens[ret].value.i;
-    while (data->tokens[ret].type != WPS_TOKEN_CONDITIONAL_END);
 
     /* ret now is the index to the end token for the conditional. */
     return ret;
@@ -1307,6 +1307,10 @@
            && cond_start < data->num_tokens)
         cond_start++;
 
+    /* if the number of options is 0, the conditional is invalid */
+    if (num_options == 0)
+        return cond_start;
+
     /* treat ?xx<true> constructs as if they had 2 options. */
     if (num_options < 2)
         num_options = 2;
diff --git a/apps/gui/gwps.h b/apps/gui/gwps.h
index 7d20bc9..801a379 100644
--- a/apps/gui/gwps.h
+++ b/apps/gui/gwps.h
@@ -76,7 +76,7 @@
 #define WPS_MAX_SUBLINES    (WPS_MAX_LINES*3)
 #define WPS_MAX_TOKENS      1024
 #define WPS_MAX_STRINGS     128
-#define STRING_BUFFER_SIZE  512
+#define STRING_BUFFER_SIZE  1024
 #define WPS_MAX_COND_LEVEL  10
 
 #else
diff --git a/apps/gui/wps_debug.c b/apps/gui/wps_debug.c
index 96f3e57..e7d3f45 100644
--- a/apps/gui/wps_debug.c
+++ b/apps/gui/wps_debug.c
@@ -398,13 +398,16 @@
 void print_wps_strings(struct wps_data *data)
 {
     DEBUGF("Strings:\n");
-    int i, len = 0;
-    for (i=0; i < data->num_strings; i++)
+    int i, len = 0, buf_used = 0;
+    for (i = 0; i < data->num_strings; i++)
     {
         len += strlen(data->strings[i]);
-        DEBUGF("%2d: '%s'\n", i, data->strings[i]);
+        buf_used += strlen(data->strings[i]) + 1;
+        DEBUGF("%2d: (%2d) '%s'\n", i, strlen(data->strings[i]), data->strings[i]);
     }
-    DEBUGF("Total length: %d\n", len);
+    DEBUGF("\n");
+    DEBUGF("Total string length: %d\n", len);
+    DEBUGF("String buffer used: %d out of %d bytes\n", buf_used, STRING_BUFFER_SIZE);
     DEBUGF("\n");
 }
 
@@ -413,7 +416,7 @@
 {
     DEBUGF("Image conditional indexes:\n");
     int i;
-    for (i=0; i < MAX_IMAGES; i++)
+    for (i = 0; i < MAX_IMAGES; i++)
     {
         if (data->img[i].cond_index)
             DEBUGF("%2d: %d\n", i, data->img[i].cond_index);
diff --git a/apps/gui/wps_parser.c b/apps/gui/wps_parser.c
index e72079c..2c7a000 100644
--- a/apps/gui/wps_parser.c
+++ b/apps/gui/wps_parser.c
@@ -270,12 +270,29 @@
 }
 
 /* Starts a new subline in the current line during parsing */
-static void wps_start_new_subline(struct wps_data *data) {
+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++;
 }
 
+static void close_conditionals(struct wps_data *data, int n)
+{
+    int i;
+    for (i = 0; i < n; i++)
+    {
+        data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_END;
+        if (lastcond[level])
+            data->tokens[lastcond[level]].value.i = data->num_tokens;
+
+        lastcond[level] = 0;
+        data->num_tokens++;
+        data->tokens[condindex[level]].value.i = numoptions[level];
+        level--;
+    }
+}
+
 #ifdef HAVE_LCD_BITMAP
 
 static int parse_statusbar_enable(const char *wps_bufptr,
@@ -638,6 +655,7 @@
         return false;
 
     char *current_string = data->string_buffer;
+    int stringbuf_used = 0;
 
     while(*wps_bufptr && data->num_tokens < WPS_MAX_TOKENS - 1
           && data->num_lines < WPS_MAX_LINES)
@@ -652,6 +670,9 @@
 
             /* Alternating sublines separator */
             case ';':
+                if (level >= 0)
+                    close_conditionals(data, level + 1);
+
                 if (data->num_sublines+1 < WPS_MAX_SUBLINES)
                     wps_start_new_subline(data);
                 else
@@ -670,17 +691,7 @@
                 if (level < 0) /* not in a conditional, ignore the char */
                     break;
 
-condlistend:  /* close a conditional. sometimes we want to close them even when
-                 we don't have a closing token, e.g. at the end of a line. */
-
-                data->tokens[data->num_tokens].type = WPS_TOKEN_CONDITIONAL_END;
-                if (lastcond[level])
-                    data->tokens[lastcond[level]].value.i = data->num_tokens;
-
-                lastcond[level] = 0;
-                data->num_tokens++;
-                data->tokens[condindex[level]].value.i = numoptions[level];
-                level--;
+                close_conditionals(data, 1);
                 break;
 
             /* Conditional list option */
@@ -699,19 +710,17 @@
 
             /* Comment */
             case '#':
+                if (level >= 0)
+                    close_conditionals(data, level + 1);
+
                 wps_bufptr += skip_end_of_line(wps_bufptr);
                 break;
 
             /* End of this line */
             case '\n':
                 if (level >= 0)
-                {
-                    /* We have unclosed conditionals, so we
-                       close them before adding the EOL token */
-                    wps_bufptr--;
-                    goto condlistend;
-                    break;
-                }
+                    close_conditionals(data, level + 1);
+
                 wps_start_new_subline(data);
                 data->num_lines++; /* Start a new line */
 
@@ -726,29 +735,36 @@
 
             /* String */
             default:
-                if (data->num_strings < WPS_MAX_STRINGS)
+                if (data->num_strings < WPS_MAX_STRINGS
+                    && stringbuf_used < STRING_BUFFER_SIZE - 1)
                 {
                     data->tokens[data->num_tokens].type = WPS_TOKEN_STRING;
                     data->strings[data->num_strings] = current_string;
-                    data->tokens[data->num_tokens].value.i = data->num_strings++;
+                    data->tokens[data->num_tokens].value.i = data->num_strings;
                     data->num_tokens++;
 
                     /* Copy the first byte */
                     *current_string++ = *(wps_bufptr - 1);
+                    stringbuf_used++;
 
-                    /* continue until we hit something that ends the string */
+                    /* continue until we hit something that ends the string
+                       or we run out of memory */
                     while(wps_bufptr && *wps_bufptr != '#' &&
                           *wps_bufptr != '%' && *wps_bufptr != ';' &&
                           *wps_bufptr != '<' && *wps_bufptr != '>' &&
-                          *wps_bufptr != '|' && *wps_bufptr != '\n')
+                          *wps_bufptr != '|' && *wps_bufptr != '\n' &&
+                          stringbuf_used < STRING_BUFFER_SIZE - 1)
                     {
                         *current_string++ = *wps_bufptr++;
+                        stringbuf_used++;
                     }
 
                     /* null terminate the string */
                     *current_string++ = '\0';
-                }
+                    stringbuf_used++;
 
+                    data->num_strings++;
+                }
                 break;
         }
     }