rockbox/lib/skin_parser/skin_debug.c
Solomon Peachy b450707955 skins: Fix buffer overflow in skin_error_format_message()
Change-Id: I54849866c163f2ec7ab9c9f76cfe1b267a4bee56
2020-05-04 20:41:12 +02:00

335 lines
8.7 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2010 Robert Bieber
*
* 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 <stdlib.h>
#include <string.h>
#include "skin_parser.h"
#include "skin_debug.h"
#include "tag_table.h"
/* Global variables for debug output */
int debug_indent_level = 0;
extern int skin_line;
extern char* skin_start;
extern char* skin_buffer;
/* Global error variables */
static int error_line;
static int error_col;
static const char *error_line_start;
static char* error_message;
static inline struct skin_element*
get_child(OFFSETTYPE(struct skin_element**) children, int child)
{
struct skin_element **kids = SKINOFFSETTOPTR(skin_buffer, children);
return kids[child];
}
/* Debugging functions */
void skin_error(enum skin_errorcode error, const char* cursor)
{
error_col = 0;
while(cursor > skin_start && *cursor != '\n')
{
cursor--;
error_col++;
}
error_line_start = cursor+1;
error_line = skin_line;
switch(error)
{
case MEMORY_LIMIT_EXCEEDED:
error_line_start = NULL;
printf("Error: Memory limit exceeded at Line %d\n", skin_line);
error_message = "Memory limit exceeded";
break;
case NEWLINE_EXPECTED:
error_message = "Newline expected";
break;
case ILLEGAL_TAG:
error_message = "Illegal tag";
break;
case ARGLIST_EXPECTED:
error_message = "Argument list expected";
break;
case TOO_MANY_ARGS:
error_message = "Too many arguments given";
break;
case DEFAULT_NOT_ALLOWED:
error_message = "Argument can not be set to default";
break;
case UNEXPECTED_NEWLINE:
error_message = "Unexpected newline";
break;
case INSUFFICIENT_ARGS:
error_message = "Not enough arguments";
break;
case INT_EXPECTED:
error_message = "Expected integer";
break;
case DECIMAL_EXPECTED:
error_message = "Expected decimal";
break;
case SEPARATOR_EXPECTED:
error_message = "Expected argument separator";
break;
case CLOSE_EXPECTED:
error_message = "Expected list close";
break;
case MULTILINE_EXPECTED:
error_message = "Expected subline separator";
break;
case GOT_CALLBACK_ERROR:
error_message = "Parser callback returned error";
break;
};
}
int skin_error_line()
{
return error_line;
}
int skin_error_col()
{
return error_col;
}
char* skin_error_message()
{
return error_message;
}
void skin_clear_errors()
{
error_line = 0;
error_col = 0;
error_message = NULL;
}
#if !defined(ROCKBOX) || defined(__PCTOOL__)
void skin_debug_tree(struct skin_element* root)
{
int i;
char *text;
struct skin_element* current = root;
while(current)
{
skin_debug_indent();
switch(current->type)
{
case UNKNOWN:
printf("* Unknown element.. error *\n");
break;
case VIEWPORT:
printf("{ Viewport \n");
debug_indent_level++;
skin_debug_tree(get_child(current->children, 0));
debug_indent_level--;
printf("}");
break;
case TEXT:
text = SKINOFFSETTOPTR(skin_buffer, current->data);
printf("* Plain text on line %d: \"%s\"\n", current->line, text);
break;
case COMMENT:
printf("# Comment on line %d\n ", current->line);
break;
case TAG:
if (current->params_count)
{
printf("( %%%s tag on line %d with %d arguments\n",
current->tag->name,
current->line, current->params_count);
debug_indent_level++;
skin_debug_params(current->params_count, SKINOFFSETTOPTR(skin_buffer, current->params));
debug_indent_level--;
skin_debug_indent();
printf(")\n");
}
else
{
printf("[ %%%s tag on line %d ]\n",
current->tag->name, current->line);
}
break;
case LINE_ALTERNATOR:
printf("[ Alternator on line %d with %d sublines \n", current->line,
current->children_count);
debug_indent_level++;
for(i = 0; i < current->children_count; i++)
{
skin_debug_tree(get_child(current->children, i));
}
debug_indent_level--;
skin_debug_indent();
printf("]\n");
break;
case CONDITIONAL:
printf("< Conditional tag %%?%s on line %d with %d enumerations \n",
current->tag->name, current->line, current->children_count);
debug_indent_level++;
for(i = 0; i < current->children_count; i++)
{
skin_debug_indent();
printf("[ Enumeration %d\n", i);
debug_indent_level++;
skin_debug_tree(get_child(current->children, i));
debug_indent_level--;
skin_debug_indent();
printf("]\n");
}
debug_indent_level--;
skin_debug_indent();
printf(">\n");
break;
case LINE:
printf("[ Logical line on line %d\n", current->line);
debug_indent_level++;
if (current->children)
skin_debug_tree(get_child(current->children, 0));
debug_indent_level--;
skin_debug_indent();
printf("]\n");
break;
}
current = SKINOFFSETTOPTR(skin_buffer, current->next);
}
}
void skin_debug_params(int count, struct skin_tag_parameter params[])
{
int i;
for(i = 0; i < count; i++)
{
skin_debug_indent();
switch(params[i].type)
{
case DEFAULT:
printf("-");
break;
case STRING:
printf("string: \"%s\"", SKINOFFSETTOPTR(skin_buffer, params[i].data.text));
break;
case INTEGER:
printf("integer: %d", params[i].data.number);
break;
case DECIMAL:
printf("decimal: %d.%d", params[i].data.number/10,
params[i].data.number%10);
break;
case CODE:
printf("Skin Code: \n");
debug_indent_level++;
skin_debug_tree(SKINOFFSETTOPTR(skin_buffer, params[i].data.code));
debug_indent_level--;
skin_debug_indent();
break;
}
printf("\n");
}
}
void skin_debug_indent(void)
{
int i;
for(i = 0; i < debug_indent_level; i++)
printf(" ");
}
#endif
#define MIN(a,b) ((a<b)?(a):(b))
void skin_error_format_message(void)
{
int i;
char text[128];
if (!error_line_start)
return;
char* line_end = strchr(error_line_start, '\n');
int len = MIN(line_end - error_line_start, 80);
if (!line_end)
len = strlen(error_line_start);
printf("Error on line %d.\n", error_line);
error_col--;
if (error_col <= 10)
{
strncpy(text, error_line_start, len);
text[len] = '\0';
}
else
{
int j;
/* make it fit nicely.. "<start few chars>...<10 chars><error>" */
strncpy(text, error_line_start, 6);
i = 5;
text[i++] = '.';
text[i++] = '.';
text[i++] = '.';
for (j=error_col-10; j < len && error_line_start[j] && error_line_start[j] != '\n'; j++)
text[i++] = error_line_start[j];
text[i] = '\0';
error_col = 18;
}
printf("%s\n", text);
for (i=0; i<error_col; i++)
text[i] = ' ';
snprintf(&text[i],64, "^ \'%s\' Here", error_message);
printf("%s\n", text);
}