mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-26 02:40:43 -06:00
Bug #638543: Validate counter format strings before using them.
Patch by Matthijs Kooijman: The validation function is a very simple "parser" that simply checks for a single gint64 conversion specification, allowing all modifiers and flags that printf(3) specifies (except for the * width and precision, which need an extra argument). The validation function returns an error message that is used to log a warning and can be used by the GUI later on. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@20056 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
e1c6d28eac
commit
10b45bf554
@ -495,6 +495,7 @@ qof_book_get_counter_format(const QofBook *book, const char *counter_name)
|
||||
KvpFrame *kvp;
|
||||
gchar *format;
|
||||
KvpValue *value;
|
||||
gchar *error;
|
||||
|
||||
if (!book)
|
||||
{
|
||||
@ -517,13 +518,26 @@ qof_book_get_counter_format(const QofBook *book, const char *counter_name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
format = NULL;
|
||||
|
||||
/* Get the format string */
|
||||
value = kvp_frame_get_slot_path (kvp, "counter_formats", counter_name, NULL);
|
||||
if (value)
|
||||
{
|
||||
format = kvp_value_get_string (value);
|
||||
error = qof_book_validate_counter_format(format);
|
||||
if (error != NULL)
|
||||
{
|
||||
PWARN("Invalid counter format string. Format string: '%s' Counter: '%s' Erorr: '%s')", format, counter_name, error);
|
||||
/* Invalid format string */
|
||||
format = NULL;
|
||||
g_free(error);
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
/* If no (valid) format string was found, use the default format
|
||||
* string */
|
||||
if (!format)
|
||||
{
|
||||
/* Use the default format */
|
||||
format = "%.6" G_GINT64_FORMAT;
|
||||
@ -531,6 +545,97 @@ qof_book_get_counter_format(const QofBook *book, const char *counter_name)
|
||||
return format;
|
||||
}
|
||||
|
||||
gchar *
|
||||
qof_book_validate_counter_format(const gchar *p)
|
||||
{
|
||||
const gchar *conv_start, *tmp;
|
||||
|
||||
/* Validate a counter format. This is a very simple "parser" that
|
||||
* simply checks for a single gint64 conversion specification,
|
||||
* allowing all modifiers and flags that printf(3) specifies (except
|
||||
* for the * width and precision, which need an extra argument). */
|
||||
|
||||
/* Skip a prefix of any character except % */
|
||||
while (*p)
|
||||
{
|
||||
/* Skip two adjacent percent marks, which are literal percent
|
||||
* marks */
|
||||
if (p[0] == '%' && p[1] == '%')
|
||||
{
|
||||
p += 2;
|
||||
continue;
|
||||
}
|
||||
/* Break on a single percent mark, which is the start of the
|
||||
* conversion specification */
|
||||
if (*p == '%')
|
||||
break;
|
||||
/* Skip all other characters */
|
||||
p++;
|
||||
}
|
||||
|
||||
if (!*p)
|
||||
return g_strdup("Format string ended without any conversion specification");
|
||||
|
||||
/* Store the start of the conversion for error messages */
|
||||
conv_start = p;
|
||||
|
||||
/* Skip the % */
|
||||
p++;
|
||||
|
||||
/* Skip any number of flag characters */
|
||||
while (*p && strchr("#0- +'I", *p)) p++;
|
||||
|
||||
/* Skip any number of field width digits */
|
||||
while (*p && strchr("0123456789", *p)) p++;
|
||||
|
||||
/* A precision specifier always starts with a dot */
|
||||
if (*p && *p == '.')
|
||||
{
|
||||
/* Skip the . */
|
||||
p++;
|
||||
/* Skip any number of precision digits */
|
||||
while (*p && strchr("0123456789", *p)) p++;
|
||||
}
|
||||
|
||||
if (!*p)
|
||||
return g_strdup_printf("Format string ended during the conversion specification. Conversion seen so far: %s", conv_start);
|
||||
|
||||
/* See if the format string starts with the correct format
|
||||
* specification. */
|
||||
tmp = strstr(p, G_GINT64_FORMAT);
|
||||
if (tmp == NULL)
|
||||
{
|
||||
return g_strdup_printf("Invalid length modifier and/or conversion specifier ('%.2s'), it should be: " G_GINT64_FORMAT, p);
|
||||
} else if (tmp != p) {
|
||||
return g_strdup_printf("Garbage before length modifier and/or conversion specifier: '%*s'", (int)(tmp - p), p);
|
||||
}
|
||||
|
||||
/* Skip length modifier / conversion specifier */
|
||||
p += strlen(G_GINT64_FORMAT);
|
||||
|
||||
/* Skip a suffix of any character except % */
|
||||
while (*p)
|
||||
{
|
||||
/* Skip two adjacent percent marks, which are literal percent
|
||||
* marks */
|
||||
if (p[0] == '%' && p[1] == '%')
|
||||
{
|
||||
p += 2;
|
||||
continue;
|
||||
}
|
||||
/* Break on a single percent mark, which is the start of the
|
||||
* conversion specification */
|
||||
if (*p == '%')
|
||||
return g_strdup_printf("Format string contains unescaped %% signs (or multiple conversion specifications) at '%s'", p);
|
||||
/* Skip all other characters */
|
||||
p++;
|
||||
}
|
||||
|
||||
/* If we end up here, the string was valid, so return no error
|
||||
* message */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Determine whether this book uses trading accounts */
|
||||
gboolean
|
||||
qof_book_use_trading_accounts (const QofBook *book)
|
||||
|
@ -289,6 +289,12 @@ gint64 qof_book_get_counter (QofBook *book, const char *counter_name);
|
||||
*/
|
||||
gchar *qof_book_increment_and_format_counter (QofBook *book, const char *counter_name);
|
||||
|
||||
/** Validate a counter format string. Returns an error message if the
|
||||
* format string was invalid, or NULL if it is ok. The caller should
|
||||
* free the error message with g_free.
|
||||
*/
|
||||
gchar * qof_book_validate_counter_format(const gchar *format);
|
||||
|
||||
/** Get the format string to use for the named counter.
|
||||
* The return value is NULL on error or the format string of the
|
||||
* counter. The string should not be freed.
|
||||
|
Loading…
Reference in New Issue
Block a user