@@ -142,6 +142,40 @@ double av_strtod(const char *numstr, char **tail)
return d;
}
+static int parse_string_literal(Parser *p, char **tail, char **literal_str)
+{
+ char *parse_str = p->s;
+ char *next = parse_str;
+ char *literal = NULL;
+ int nbyte;
+
+ if(parse_str[0] == '\'' || parse_str[0] == '"') {
+
+ next = strchr(parse_str + 1, parse_str[0]);
+
+ if(next == NULL) {
+ av_log(p, AV_LOG_ERROR, "Unterminated string in '%s'\n", parse_str);
+ return AVERROR(EINVAL);
+ } else {
+ nbyte = next - parse_str; /* Includes space for \0 */
+ literal = av_mallocz(nbyte);
+ if (!literal)
+ return AVERROR(ENOMEM);
+
+ strncpy(literal, parse_str+1, nbyte-1);
+ literal[nbyte-1] = '\0';
+ next++; /* step past the ending quote */
+ }
+ }
+
+ /* if requested, fill in tail with the position after the last parsed
+ character */
+ if (tail)
+ *tail = next;
+ *literal_str = literal;
+ return 0;
+}
+
#define IS_IDENTIFIER_CHAR(c) ((c) - '0' <= 9U || (c) - 'a' <= 25U || (c) - 'A' <= 25U || (c) == '_')
static int strmatch(const char *s, const char *prefix)
@@ -154,17 +188,27 @@ static int strmatch(const char *s, const char *prefix)
return !IS_IDENTIFIER_CHAR(s[i]);
}
+
+struct AVGetExprBuffer {
+ int ndata;
+ char *data;
+};
+
struct AVExpr {
enum {
- e_value, e_const, e_func0, e_func1, e_func2,
+ e_value, e_const, e_string, e_buffer, e_func0, e_func1, e_func2,
e_squish, e_gauss, e_ld, e_isnan, e_isinf,
e_mod, e_max, e_min, e_eq, e_gt, e_gte, e_lte, e_lt,
e_pow, e_mul, e_div, e_add,
e_last, e_st, e_while, e_taylor, e_root, e_floor, e_ceil, e_trunc, e_round,
e_sqrt, e_not, e_random, e_hypot, e_gcd,
e_if, e_ifnot, e_print, e_bitand, e_bitor, e_between, e_clip, e_atan2, e_lerp,
+ e_get,
} type;
- double value; // is sign in other types
+ union {
+ double value; // is sign in other types
+ void *pointer;
+ };
union {
int const_index;
double (*func0)(double);
@@ -300,6 +344,12 @@ static double eval_expr(Parser *p, AVExpr *e)
p->var[0] = var0;
return -low_v<high_v ? low : high;
}
+ case e_get: {
+ struct AVGetExprBuffer * buffer = (struct AVGetExprBuffer * )e->param[1]->pointer;
+ int index = (int)eval_expr(p, e->param[0]);
+ index = (index < 0)?0:((index >= buffer->ndata)?buffer->ndata-1:index);
+ return e->value * buffer->data[index];
+ }
default: {
double d = eval_expr(p, e->param[0]);
double d2 = eval_expr(p, e->param[1]);
@@ -345,11 +395,23 @@ static int parse_primary(AVExpr **e, Parser *p)
{
AVExpr *d = av_mallocz(sizeof(AVExpr));
char *next = p->s, *s0 = p->s;
+ char * literal_str;
int ret, i;
if (!d)
return AVERROR(ENOMEM);
+ if((ret = parse_string_literal(p, &next, &literal_str)) != 0)
+ return ret;
+
+ if(literal_str != NULL) {
+ d->type = e_string;
+ d->pointer = literal_str;
+ p->s = next;
+ *e = d;
+ return 0;
+ }
+
/* number */
d->value = av_strtod(p->s, &next);
if (next != p->s) {
@@ -470,6 +532,7 @@ static int parse_primary(AVExpr **e, Parser *p)
else if (strmatch(next, "clip" )) d->type = e_clip;
else if (strmatch(next, "atan2" )) d->type = e_atan2;
else if (strmatch(next, "lerp" )) d->type = e_lerp;
+ else if (strmatch(next, "get" )) d->type = e_get;
else {
for (i=0; p->func1_names && p->func1_names[i]; i++) {
if (strmatch(next, p->func1_names[i])) {
@@ -637,12 +700,55 @@ static int parse_expr(AVExpr **e, Parser *p)
return 0;
}
+
+static int init_get_expr(AVExpr *e)
+{
+ FILE * fp;
+ char * fname = (char *)e->pointer;
+ struct AVGetExprBuffer * buffer;
+ int nbyte;
+
+ if((fp = fopen(fname, "rb")) == NULL)
+ return 0;
+ fseek(fp, 0, SEEK_END);
+ nbyte = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ buffer = av_malloc(nbyte + sizeof(struct AVGetExprBuffer));
+ if(buffer == NULL)
+ {
+ fclose(fp);
+ return 0;
+ }
+
+ buffer->ndata = nbyte;
+ buffer->data = (char *)(buffer + 1); /* Add sizeof the struct */
+
+ if(fread(buffer->data, nbyte, 1, fp) != 1)
+ {
+ fclose(fp);
+ av_free(buffer);
+ return 0;
+ }
+
+ e->pointer = buffer;
+ e->type = e_buffer;
+ av_free(fname);
+ fclose(fp);
+
+ return 1;
+}
+
static int verify_expr(AVExpr *e)
{
if (!e) return 0;
switch (e->type) {
case e_value:
case e_const: return 1;
+ /* string and buffer types are currently only exposed to e_get.
+ So if we got here, something is wrong. */
+ case e_string:
+ case e_buffer: return 0;
case e_func0:
case e_func1:
case e_squish:
@@ -672,6 +778,14 @@ static int verify_expr(AVExpr *e)
return verify_expr(e->param[0]) &&
verify_expr(e->param[1]) &&
verify_expr(e->param[2]);
+ case e_get:
+ if(!e->param[1] || e->param[1]->type != e_string)
+ return 0;
+ /* Since there is no separate init for the expression, and nothing
+ other than get currently needs initialization, initializing
+ from verify_expr() was the least amount of new code. */
+ return verify_expr(e->param[0]) && init_get_expr(e->param[1]);
+
default: return verify_expr(e->param[0]) && verify_expr(e->param[1]) && !e->param[2];
}
}