glsl/pp: Validate numbers.
This commit is contained in:
+229
-25
@@ -29,6 +29,13 @@
|
||||
#include "sl_pp_token.h"
|
||||
|
||||
|
||||
static int
|
||||
_is_identifier_char(char c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_tokenise_identifier(struct sl_pp_context *context,
|
||||
const char **pinput,
|
||||
@@ -42,10 +49,7 @@ _tokenise_identifier(struct sl_pp_context *context,
|
||||
info->data.identifier = -1;
|
||||
|
||||
identifier[i++] = *input++;
|
||||
while ((*input >= 'a' && *input <= 'z') ||
|
||||
(*input >= 'A' && *input <= 'Z') ||
|
||||
(*input >= '0' && *input <= '9') ||
|
||||
(*input == '_')) {
|
||||
while (_is_identifier_char(*input)) {
|
||||
if (i >= sizeof(identifier) - 1) {
|
||||
strcpy(context->error_msg, "out of memory");
|
||||
return -1;
|
||||
@@ -64,41 +68,241 @@ _tokenise_identifier(struct sl_pp_context *context,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the number of consecutive decimal digits in the input stream.
|
||||
*/
|
||||
static unsigned int
|
||||
_parse_float_digits(const char *input)
|
||||
{
|
||||
unsigned int eaten = 0;
|
||||
|
||||
while (input[eaten] >= '0' && input[eaten] <= '9') {
|
||||
eaten++;
|
||||
}
|
||||
return eaten;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try to match one of the following patterns for the fractional part
|
||||
* of a floating point number.
|
||||
*
|
||||
* digits . [digits]
|
||||
* . digits
|
||||
*
|
||||
* Return 0 if the pattern could not be matched, otherwise the number
|
||||
* of eaten characters from the input stream.
|
||||
*/
|
||||
static unsigned int
|
||||
_parse_float_frac(const char *input)
|
||||
{
|
||||
unsigned int eaten;
|
||||
|
||||
if (input[0] == '.') {
|
||||
eaten = _parse_float_digits(&input[1]);
|
||||
if (eaten) {
|
||||
return eaten + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
eaten = _parse_float_digits(input);
|
||||
if (eaten && input[eaten] == '.') {
|
||||
unsigned int trailing;
|
||||
|
||||
trailing = _parse_float_digits(&input[eaten + 1]);
|
||||
if (trailing) {
|
||||
return eaten + trailing + 1;
|
||||
}
|
||||
return eaten + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try to match the following pattern for the exponential part
|
||||
* of a floating point number.
|
||||
*
|
||||
* (e|E) [(+|-)] digits
|
||||
*
|
||||
* Return 0 if the pattern could not be matched, otherwise the number
|
||||
* of eaten characters from the input stream.
|
||||
*/
|
||||
static unsigned int
|
||||
_parse_float_exp(const char *input)
|
||||
{
|
||||
unsigned int eaten, digits;
|
||||
|
||||
if (input[0] != 'e' && input[0] != 'E') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (input[1] == '-' || input[1] == '+') {
|
||||
eaten = 2;
|
||||
} else {
|
||||
eaten = 1;
|
||||
}
|
||||
|
||||
digits = _parse_float_digits(&input[eaten]);
|
||||
if (!digits) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return eaten + digits;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try to match one of the following patterns for a floating point number.
|
||||
*
|
||||
* fract [exp] [(f|F)]
|
||||
* digits exp [(f|F)]
|
||||
*
|
||||
* Return 0 if the pattern could not be matched, otherwise the number
|
||||
* of eaten characters from the input stream.
|
||||
*/
|
||||
static unsigned int
|
||||
_parse_float(const char *input)
|
||||
{
|
||||
unsigned int eaten;
|
||||
|
||||
eaten = _parse_float_frac(input);
|
||||
if (eaten) {
|
||||
unsigned int exponent;
|
||||
|
||||
exponent = _parse_float_exp(&input[eaten]);
|
||||
if (exponent) {
|
||||
eaten += exponent;
|
||||
}
|
||||
|
||||
if (input[eaten] == 'f' || input[eaten] == 'F') {
|
||||
eaten++;
|
||||
}
|
||||
|
||||
return eaten;
|
||||
}
|
||||
|
||||
eaten = _parse_float_digits(input);
|
||||
if (eaten) {
|
||||
unsigned int exponent;
|
||||
|
||||
exponent = _parse_float_exp(&input[eaten]);
|
||||
if (exponent) {
|
||||
eaten += exponent;
|
||||
|
||||
if (input[eaten] == 'f' || input[eaten] == 'F') {
|
||||
eaten++;
|
||||
}
|
||||
|
||||
return eaten;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
_parse_hex(const char *input)
|
||||
{
|
||||
unsigned int n;
|
||||
|
||||
if (input[0] != '0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (input[1] != 'x' && input[1] != 'X') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = 2;
|
||||
while ((input[n] >= '0' && input[n] <= '9') ||
|
||||
(input[n] >= 'a' && input[n] <= 'f') ||
|
||||
(input[n] >= 'A' && input[n] <= 'F')) {
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n > 2) {
|
||||
return n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
_parse_oct(const char *input)
|
||||
{
|
||||
unsigned int n;
|
||||
|
||||
if (input[0] != '0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = 1;
|
||||
while ((input[n] >= '0' && input[n] <= '7')) {
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
_parse_dec(const char *input)
|
||||
{
|
||||
unsigned int n = 0;
|
||||
|
||||
while ((input[n] >= '0' && input[n] <= '9')) {
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_tokenise_number(struct sl_pp_context *context,
|
||||
const char **pinput,
|
||||
struct sl_pp_token_info *info)
|
||||
{
|
||||
const char *input = *pinput;
|
||||
unsigned int eaten;
|
||||
char number[256]; /* XXX: Remove this artifical limit. */
|
||||
unsigned int i = 0;
|
||||
|
||||
eaten = _parse_float(input);
|
||||
if (!eaten) {
|
||||
eaten = _parse_hex(input);
|
||||
if (!eaten) {
|
||||
eaten = _parse_oct(input);
|
||||
if (!eaten) {
|
||||
eaten = _parse_dec(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!eaten || _is_identifier_char(input[eaten])) {
|
||||
strcpy(context->error_msg, "expected a number");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (eaten > sizeof(number) - 1) {
|
||||
strcpy(context->error_msg, "out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(number, input, eaten);
|
||||
number[eaten] = '\0';
|
||||
|
||||
info->token = SL_PP_NUMBER;
|
||||
info->data.number = -1;
|
||||
|
||||
number[i++] = *input++;
|
||||
while ((*input >= '0' && *input <= '9') ||
|
||||
(*input >= 'a' && *input <= 'f') ||
|
||||
(*input >= 'A' && *input <= 'F') ||
|
||||
(*input == 'x') ||
|
||||
(*input == 'X') ||
|
||||
(*input == '+') ||
|
||||
(*input == '-') ||
|
||||
(*input == '.')) {
|
||||
if (i >= sizeof(number) - 1) {
|
||||
strcpy(context->error_msg, "out of memory");
|
||||
return -1;
|
||||
}
|
||||
number[i++] = *input++;
|
||||
}
|
||||
number[i++] = '\0';
|
||||
|
||||
info->data.number = sl_pp_context_add_unique_str(context, number);
|
||||
if (info->data.number == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pinput = input;
|
||||
*pinput = input + eaten;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user