Mercurial > libavcodec.hg
comparison eval.c @ 11801:026edf66e3a9 libavcodec
Make ff_parse_expr() and ff_parse_and_eval_expr() return an int
containing an error code.
Allow these functions to convey the reason of the failure to the
calling function, failure which is not always due to a parsing error
but it may depend for example on a memory problem.
Also fix several potential memleaks.
| author | stefano |
|---|---|
| date | Tue, 01 Jun 2010 08:07:07 +0000 |
| parents | c6368258b694 |
| children | 5880d90f2b99 |
comparison
equal
deleted
inserted
replaced
| 11800:966aa6b53dcf | 11801:026edf66e3a9 |
|---|---|
| 165 } | 165 } |
| 166 } | 166 } |
| 167 return NAN; | 167 return NAN; |
| 168 } | 168 } |
| 169 | 169 |
| 170 static AVExpr * parse_expr(Parser *p); | 170 static int parse_expr(AVExpr **e, Parser *p); |
| 171 | 171 |
| 172 void ff_free_expr(AVExpr * e) { | 172 void ff_free_expr(AVExpr * e) { |
| 173 if (!e) return; | 173 if (!e) return; |
| 174 ff_free_expr(e->param[0]); | 174 ff_free_expr(e->param[0]); |
| 175 ff_free_expr(e->param[1]); | 175 ff_free_expr(e->param[1]); |
| 176 av_freep(&e); | 176 av_freep(&e); |
| 177 } | 177 } |
| 178 | 178 |
| 179 static AVExpr * parse_primary(Parser *p) { | 179 static int parse_primary(AVExpr **e, Parser *p) |
| 180 { | |
| 180 AVExpr * d = av_mallocz(sizeof(AVExpr)); | 181 AVExpr * d = av_mallocz(sizeof(AVExpr)); |
| 181 char *next= p->s; | 182 char *next= p->s; |
| 182 int i; | 183 int ret, i; |
| 183 | 184 |
| 184 if (!d) | 185 if (!d) |
| 185 return NULL; | 186 return AVERROR(ENOMEM); |
| 186 | 187 |
| 187 /* number */ | 188 /* number */ |
| 188 d->value = av_strtod(p->s, &next); | 189 d->value = av_strtod(p->s, &next); |
| 189 if(next != p->s){ | 190 if(next != p->s){ |
| 190 d->type = e_value; | 191 d->type = e_value; |
| 191 p->s= next; | 192 p->s= next; |
| 192 return d; | 193 *e = d; |
| 194 return 0; | |
| 193 } | 195 } |
| 194 d->value = 1; | 196 d->value = 1; |
| 195 | 197 |
| 196 /* named constants */ | 198 /* named constants */ |
| 197 for(i=0; p->const_name && p->const_name[i]; i++){ | 199 for(i=0; p->const_name && p->const_name[i]; i++){ |
| 198 if(strmatch(p->s, p->const_name[i])){ | 200 if(strmatch(p->s, p->const_name[i])){ |
| 199 p->s+= strlen(p->const_name[i]); | 201 p->s+= strlen(p->const_name[i]); |
| 200 d->type = e_const; | 202 d->type = e_const; |
| 201 d->a.const_index = i; | 203 d->a.const_index = i; |
| 202 return d; | 204 *e = d; |
| 205 return 0; | |
| 203 } | 206 } |
| 204 } | 207 } |
| 205 | 208 |
| 206 p->s= strchr(p->s, '('); | 209 p->s= strchr(p->s, '('); |
| 207 if(p->s==NULL){ | 210 if(p->s==NULL){ |
| 208 av_log(p, AV_LOG_ERROR, "undefined constant or missing (\n"); | 211 av_log(p, AV_LOG_ERROR, "undefined constant or missing (\n"); |
| 209 p->s= next; | 212 p->s= next; |
| 210 ff_free_expr(d); | 213 ff_free_expr(d); |
| 211 return NULL; | 214 return AVERROR(EINVAL); |
| 212 } | 215 } |
| 213 p->s++; // "(" | 216 p->s++; // "(" |
| 214 if (*next == '(') { // special case do-nothing | 217 if (*next == '(') { // special case do-nothing |
| 215 av_freep(&d); | 218 av_freep(&d); |
| 216 d = parse_expr(p); | 219 if ((ret = parse_expr(&d, p)) < 0) |
| 220 return ret; | |
| 217 if(p->s[0] != ')'){ | 221 if(p->s[0] != ')'){ |
| 218 av_log(p, AV_LOG_ERROR, "missing )\n"); | 222 av_log(p, AV_LOG_ERROR, "missing )\n"); |
| 219 ff_free_expr(d); | 223 ff_free_expr(d); |
| 220 return NULL; | 224 return AVERROR(EINVAL); |
| 221 } | 225 } |
| 222 p->s++; // ")" | 226 p->s++; // ")" |
| 223 return d; | 227 *e = d; |
| 224 } | 228 return 0; |
| 225 d->param[0] = parse_expr(p); | 229 } |
| 230 if ((ret = parse_expr(&(d->param[0]), p)) < 0) { | |
| 231 ff_free_expr(d); | |
| 232 return ret; | |
| 233 } | |
| 226 if(p->s[0]== ','){ | 234 if(p->s[0]== ','){ |
| 227 p->s++; // "," | 235 p->s++; // "," |
| 228 d->param[1] = parse_expr(p); | 236 parse_expr(&d->param[1], p); |
| 229 } | 237 } |
| 230 if(p->s[0] != ')'){ | 238 if(p->s[0] != ')'){ |
| 231 av_log(p, AV_LOG_ERROR, "missing )\n"); | 239 av_log(p, AV_LOG_ERROR, "missing )\n"); |
| 232 ff_free_expr(d); | 240 ff_free_expr(d); |
| 233 return NULL; | 241 return AVERROR(EINVAL); |
| 234 } | 242 } |
| 235 p->s++; // ")" | 243 p->s++; // ")" |
| 236 | 244 |
| 237 d->type = e_func0; | 245 d->type = e_func0; |
| 238 if( strmatch(next, "sinh" ) ) d->a.func0 = sinh; | 246 if( strmatch(next, "sinh" ) ) d->a.func0 = sinh; |
| 263 else { | 271 else { |
| 264 for(i=0; p->func1_name && p->func1_name[i]; i++){ | 272 for(i=0; p->func1_name && p->func1_name[i]; i++){ |
| 265 if(strmatch(next, p->func1_name[i])){ | 273 if(strmatch(next, p->func1_name[i])){ |
| 266 d->a.func1 = p->func1[i]; | 274 d->a.func1 = p->func1[i]; |
| 267 d->type = e_func1; | 275 d->type = e_func1; |
| 268 return d; | 276 *e = d; |
| 277 return 0; | |
| 269 } | 278 } |
| 270 } | 279 } |
| 271 | 280 |
| 272 for(i=0; p->func2_name && p->func2_name[i]; i++){ | 281 for(i=0; p->func2_name && p->func2_name[i]; i++){ |
| 273 if(strmatch(next, p->func2_name[i])){ | 282 if(strmatch(next, p->func2_name[i])){ |
| 274 d->a.func2 = p->func2[i]; | 283 d->a.func2 = p->func2[i]; |
| 275 d->type = e_func2; | 284 d->type = e_func2; |
| 276 return d; | 285 *e = d; |
| 286 return 0; | |
| 277 } | 287 } |
| 278 } | 288 } |
| 279 | 289 |
| 280 av_log(p, AV_LOG_ERROR, "unknown function\n"); | 290 av_log(p, AV_LOG_ERROR, "unknown function\n"); |
| 281 ff_free_expr(d); | 291 ff_free_expr(d); |
| 282 return NULL; | 292 return AVERROR(EINVAL); |
| 283 } | 293 } |
| 284 | 294 |
| 285 return d; | 295 *e = d; |
| 296 return 0; | |
| 286 } | 297 } |
| 287 | 298 |
| 288 static AVExpr * new_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1){ | 299 static AVExpr * new_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1){ |
| 289 AVExpr * e = av_mallocz(sizeof(AVExpr)); | 300 AVExpr * e = av_mallocz(sizeof(AVExpr)); |
| 290 if (!e) | 301 if (!e) |
| 294 e->param[0] =p0 ; | 305 e->param[0] =p0 ; |
| 295 e->param[1] =p1 ; | 306 e->param[1] =p1 ; |
| 296 return e; | 307 return e; |
| 297 } | 308 } |
| 298 | 309 |
| 299 static AVExpr * parse_pow(Parser *p, int *sign){ | 310 static int parse_pow(AVExpr **e, Parser *p, int *sign) |
| 311 { | |
| 300 *sign= (*p->s == '+') - (*p->s == '-'); | 312 *sign= (*p->s == '+') - (*p->s == '-'); |
| 301 p->s += *sign&1; | 313 p->s += *sign&1; |
| 302 return parse_primary(p); | 314 return parse_primary(e, p); |
| 303 } | 315 } |
| 304 | 316 |
| 305 static AVExpr * parse_factor(Parser *p){ | 317 static int parse_factor(AVExpr **e, Parser *p) |
| 306 int sign, sign2; | 318 { |
| 307 AVExpr * e = parse_pow(p, &sign); | 319 int sign, sign2, ret; |
| 320 AVExpr *e0, *e1, *e2; | |
| 321 if ((ret = parse_pow(&e0, p, &sign)) < 0) | |
| 322 return ret; | |
| 308 while(p->s[0]=='^'){ | 323 while(p->s[0]=='^'){ |
| 324 e1 = e0; | |
| 309 p->s++; | 325 p->s++; |
| 310 e= new_eval_expr(e_pow, 1, e, parse_pow(p, &sign2)); | 326 if ((ret = parse_pow(&e2, p, &sign2)) < 0) { |
| 311 if (!e) | 327 ff_free_expr(e1); |
| 312 return NULL; | 328 return ret; |
| 313 if (e->param[1]) e->param[1]->value *= (sign2|1); | 329 } |
| 314 } | 330 e0 = new_eval_expr(e_pow, 1, e1, e2); |
| 315 if (e) e->value *= (sign|1); | 331 if (!e0) { |
| 316 return e; | 332 ff_free_expr(e1); |
| 317 } | 333 ff_free_expr(e2); |
| 318 | 334 return AVERROR(ENOMEM); |
| 319 static AVExpr * parse_term(Parser *p){ | 335 } |
| 320 AVExpr * e = parse_factor(p); | 336 if (e0->param[1]) e0->param[1]->value *= (sign2|1); |
| 337 } | |
| 338 if (e0) e0->value *= (sign|1); | |
| 339 | |
| 340 *e = e0; | |
| 341 return 0; | |
| 342 } | |
| 343 | |
| 344 static int parse_term(AVExpr **e, Parser *p) | |
| 345 { | |
| 346 int ret; | |
| 347 AVExpr *e0, *e1, *e2; | |
| 348 if ((ret = parse_factor(&e0, p)) < 0) | |
| 349 return ret; | |
| 321 while(p->s[0]=='*' || p->s[0]=='/'){ | 350 while(p->s[0]=='*' || p->s[0]=='/'){ |
| 322 int c= *p->s++; | 351 int c= *p->s++; |
| 323 e= new_eval_expr(c == '*' ? e_mul : e_div, 1, e, parse_factor(p)); | 352 e1 = e0; |
| 324 if (!e) | 353 if ((ret = parse_factor(&e2, p)) < 0) { |
| 325 return NULL; | 354 ff_free_expr(e1); |
| 326 } | 355 return ret; |
| 327 return e; | 356 } |
| 328 } | 357 e0 = new_eval_expr(c == '*' ? e_mul : e_div, 1, e1, e2); |
| 329 | 358 if (!e0) { |
| 330 static AVExpr * parse_subexpr(Parser *p) { | 359 ff_free_expr(e1); |
| 331 AVExpr * e = parse_term(p); | 360 ff_free_expr(e2); |
| 361 return AVERROR(ENOMEM); | |
| 362 } | |
| 363 } | |
| 364 *e = e0; | |
| 365 return 0; | |
| 366 } | |
| 367 | |
| 368 static int parse_subexpr(AVExpr **e, Parser *p) | |
| 369 { | |
| 370 int ret; | |
| 371 AVExpr *e0, *e1, *e2; | |
| 372 if ((ret = parse_term(&e0, p)) < 0) | |
| 373 return ret; | |
| 332 while(*p->s == '+' || *p->s == '-') { | 374 while(*p->s == '+' || *p->s == '-') { |
| 333 e= new_eval_expr(e_add, 1, e, parse_term(p)); | 375 e1 = e0; |
| 334 if (!e) | 376 if ((ret = parse_term(&e2, p)) < 0) { |
| 335 return NULL; | 377 ff_free_expr(e1); |
| 378 return ret; | |
| 379 } | |
| 380 e0 = new_eval_expr(e_add, 1, e1, e2); | |
| 381 if (!e0) { | |
| 382 ff_free_expr(e1); | |
| 383 ff_free_expr(e2); | |
| 384 return AVERROR(ENOMEM); | |
| 385 } | |
| 336 }; | 386 }; |
| 337 | 387 |
| 338 return e; | 388 *e = e0; |
| 339 } | 389 return 0; |
| 340 | 390 } |
| 341 static AVExpr * parse_expr(Parser *p) { | 391 |
| 342 AVExpr * e; | 392 static int parse_expr(AVExpr **e, Parser *p) |
| 343 | 393 { |
| 394 int ret; | |
| 395 AVExpr *e0, *e1, *e2; | |
| 344 if(p->stack_index <= 0) //protect against stack overflows | 396 if(p->stack_index <= 0) //protect against stack overflows |
| 345 return NULL; | 397 return AVERROR(EINVAL); |
| 346 p->stack_index--; | 398 p->stack_index--; |
| 347 | 399 |
| 348 e = parse_subexpr(p); | 400 if ((ret = parse_subexpr(&e0, p)) < 0) |
| 349 | 401 return ret; |
| 350 while(*p->s == ';') { | 402 while(*p->s == ';') { |
| 403 e1 = e0; | |
| 404 if ((ret = parse_subexpr(&e2, p)) < 0) { | |
| 405 ff_free_expr(e1); | |
| 406 return ret; | |
| 407 } | |
| 351 p->s++; | 408 p->s++; |
| 352 e= new_eval_expr(e_last, 1, e, parse_subexpr(p)); | 409 e0 = new_eval_expr(e_last, 1, e1, e2); |
| 353 if (!e) | 410 if (!e0) { |
| 354 return NULL; | 411 ff_free_expr(e1); |
| 412 ff_free_expr(e2); | |
| 413 return AVERROR(ENOMEM); | |
| 414 } | |
| 355 }; | 415 }; |
| 356 | 416 |
| 357 p->stack_index++; | 417 p->stack_index++; |
| 358 | 418 *e = e0; |
| 359 return e; | 419 return 0; |
| 360 } | 420 } |
| 361 | 421 |
| 362 static int verify_expr(AVExpr * e) { | 422 static int verify_expr(AVExpr * e) { |
| 363 if (!e) return 0; | 423 if (!e) return 0; |
| 364 switch (e->type) { | 424 switch (e->type) { |
| 371 case e_gauss: return verify_expr(e->param[0]); | 431 case e_gauss: return verify_expr(e->param[0]); |
| 372 default: return verify_expr(e->param[0]) && verify_expr(e->param[1]); | 432 default: return verify_expr(e->param[0]) && verify_expr(e->param[1]); |
| 373 } | 433 } |
| 374 } | 434 } |
| 375 | 435 |
| 376 AVExpr *ff_parse_expr(const char *s, | 436 int ff_parse_expr(AVExpr **expr, const char *s, |
| 377 const char * const *const_name, | 437 const char * const *const_name, |
| 378 const char * const *func1_name, double (* const *func1)(void *, double), | 438 const char * const *func1_name, double (* const *func1)(void *, double), |
| 379 const char * const *func2_name, double (* const *func2)(void *, double, double), | 439 const char * const *func2_name, double (* const *func2)(void *, double, double), |
| 380 int log_offset, void *log_ctx) | 440 int log_offset, void *log_ctx) |
| 381 { | 441 { |
| 382 Parser p; | 442 Parser p; |
| 383 AVExpr *e = NULL; | 443 AVExpr *e = NULL; |
| 384 char *w = av_malloc(strlen(s) + 1); | 444 char *w = av_malloc(strlen(s) + 1); |
| 385 char *wp = w; | 445 char *wp = w; |
| 446 int ret = 0; | |
| 386 | 447 |
| 387 if (!w) | 448 if (!w) |
| 388 goto end; | 449 return AVERROR(ENOMEM); |
| 389 | 450 |
| 390 while (*s) | 451 while (*s) |
| 391 if (!isspace(*s++)) *wp++ = s[-1]; | 452 if (!isspace(*s++)) *wp++ = s[-1]; |
| 392 *wp++ = 0; | 453 *wp++ = 0; |
| 393 | 454 |
| 400 p.func2 = func2; | 461 p.func2 = func2; |
| 401 p.func2_name = func2_name; | 462 p.func2_name = func2_name; |
| 402 p.log_offset = log_offset; | 463 p.log_offset = log_offset; |
| 403 p.log_ctx = log_ctx; | 464 p.log_ctx = log_ctx; |
| 404 | 465 |
| 405 e = parse_expr(&p); | 466 if ((ret = parse_expr(&e, &p)) < 0) |
| 467 goto end; | |
| 406 if (!verify_expr(e)) { | 468 if (!verify_expr(e)) { |
| 407 ff_free_expr(e); | 469 ff_free_expr(e); |
| 408 e = NULL; | 470 ret = AVERROR(EINVAL); |
| 409 } | 471 goto end; |
| 472 } | |
| 473 *expr = e; | |
| 410 end: | 474 end: |
| 411 av_free(w); | 475 av_free(w); |
| 412 return e; | 476 return ret; |
| 413 } | 477 } |
| 414 | 478 |
| 415 double ff_eval_expr(AVExpr * e, const double *const_value, void *opaque) { | 479 double ff_eval_expr(AVExpr * e, const double *const_value, void *opaque) { |
| 416 Parser p; | 480 Parser p; |
| 417 | 481 |
| 418 p.const_value= const_value; | 482 p.const_value= const_value; |
| 419 p.opaque = opaque; | 483 p.opaque = opaque; |
| 420 return eval_expr(&p, e); | 484 return eval_expr(&p, e); |
| 421 } | 485 } |
| 422 | 486 |
| 423 double ff_parse_and_eval_expr(const char *s, | 487 int ff_parse_and_eval_expr(double *d, const char *s, |
| 424 const char * const *const_name, const double *const_value, | 488 const char * const *const_name, const double *const_value, |
| 425 const char * const *func1_name, double (* const *func1)(void *, double), | 489 const char * const *func1_name, double (* const *func1)(void *, double), |
| 426 const char * const *func2_name, double (* const *func2)(void *, double, double), | 490 const char * const *func2_name, double (* const *func2)(void *, double, double), |
| 427 void *opaque, int log_offset, void *log_ctx) | 491 void *opaque, int log_offset, void *log_ctx) |
| 428 { | 492 { |
| 429 AVExpr *e = ff_parse_expr(s, const_name, func1_name, func1, func2_name, func2, log_offset, log_ctx); | 493 AVExpr *e = NULL; |
| 430 double d; | 494 int ret = ff_parse_expr(&e, s, const_name, func1_name, func1, func2_name, func2, log_offset, log_ctx); |
| 431 if (!e) return NAN; | 495 |
| 432 d = ff_eval_expr(e, const_value, opaque); | 496 if (ret < 0) { |
| 497 *d = NAN; | |
| 498 return ret; | |
| 499 } | |
| 500 *d = ff_eval_expr(e, const_value, opaque); | |
| 433 ff_free_expr(e); | 501 ff_free_expr(e); |
| 434 return d; | 502 return isnan(*d) ? AVERROR(EINVAL) : 0; |
| 435 } | 503 } |
| 436 | 504 |
| 437 #ifdef TEST | 505 #ifdef TEST |
| 438 #undef printf | 506 #undef printf |
| 439 static double const_values[]={ | 507 static double const_values[]={ |
| 446 "E", | 514 "E", |
| 447 0 | 515 0 |
| 448 }; | 516 }; |
| 449 int main(void){ | 517 int main(void){ |
| 450 int i; | 518 int i; |
| 451 printf("%f == 12.7\n", ff_parse_and_eval_expr("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL)); | 519 double d; |
| 452 printf("%f == 0.931322575\n", ff_parse_and_eval_expr("80G/80Gi", const_names, const_values, NULL, NULL, NULL, NULL, NULL, NULL)); | 520 ff_parse_and_eval_expr(&d, "1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL); |
| 521 printf("%f == 12.7\n", d); | |
| 522 ff_parse_and_eval_expr(&d, "80G/80Gi", const_names, const_values, NULL, NULL, NULL, NULL, NULL, NULL); | |
| 523 printf("%f == 0.931322575\n", d); | |
| 453 | 524 |
| 454 for(i=0; i<1050; i++){ | 525 for(i=0; i<1050; i++){ |
| 455 START_TIMER | 526 START_TIMER |
| 456 ff_parse_and_eval_expr("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL); | 527 ff_parse_and_eval_expr(&d, "1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL); |
| 457 STOP_TIMER("ff_parse_and_eval_expr") | 528 STOP_TIMER("ff_parse_and_eval_expr") |
| 458 } | 529 } |
| 459 return 0; | 530 return 0; |
| 460 } | 531 } |
| 461 #endif | 532 #endif |
