Skip to content

Commit a80ef5e

Browse files
committed
Abort parsing keyframes if an invalid frame/time encountered
1 parent e81f052 commit a80ef5e

2 files changed

Lines changed: 43 additions & 2 deletions

File tree

src/framework/mlt_animation.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "mlt_properties.h"
2727
#include "mlt_tokeniser.h"
2828

29+
#include <ctype.h>
2930
#include <float.h>
3031
#include <math.h>
3132
#include <stdio.h>
@@ -286,6 +287,29 @@ int mlt_animation_parse(
286287
if (!value || !strcmp(value, ""))
287288
continue;
288289

290+
// If the value does not start with a frame, time, or timecode, abort
291+
const char *begin = value;
292+
const char *end = value + strlen(value) - 1;
293+
while (begin < end && isspace((unsigned char) *begin))
294+
++begin;
295+
int digit_found = 0;
296+
int equal_found = 0;
297+
for (const char *p = begin; p <= end; ++p) {
298+
if (isdigit(p[0])) {
299+
digit_found = 1;
300+
continue;
301+
}
302+
if (p[0] == ':' || p[0] == '.' || p[0] == ',' || p[0] == '-' || p[0] == '+')
303+
continue;
304+
if (p[0] == '=' || p[1] == '=')
305+
equal_found = 1;
306+
// Any other character is unexpected and invalid
307+
break;
308+
}
309+
if (!digit_found || !equal_found)
310+
// Unexpected characters found in the time field
311+
break;
312+
289313
// Reset item
290314
item.frame = item.is_key = 0;
291315

src/tests/test_animation/test_animation.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,8 @@ private Q_SLOTS:
351351
// Quotes are removed when using the anim getter.
352352
QCOMPARE(p.anim_get("foo", 0), "50=100; 60=60; 100=0");
353353
// Anim strings may contain delimiters and equal signs if quoted.
354-
p.set("foo", "50=100; 60=\"60; 100=0\";\"hello=world\"");
354+
p.set("foo", "50=100; 60=\"60; 100=0\";0=\"hello=world\"");
355+
QVERIFY(p.is_anim("foo"));
355356
QCOMPARE(p.anim_get("foo", 0), "hello=world");
356357
QCOMPARE(p.anim_get("foo", 50), "100");
357358
QCOMPARE(p.anim_get("foo", 60), "60; 100=0");
@@ -363,14 +364,30 @@ private Q_SLOTS:
363364
// A URL containing '=' in query parameters must not be treated as animation.
364365
const char *url = "https://example.com/video?token=abc123&quality=high";
365366
p.set("foo", url);
366-
QVERIFY(!p.get_animation("foo"));
367+
QVERIFY(!p.is_anim("foo"));
367368
QCOMPARE(p.get("foo"), url);
368369
QCOMPARE(p.anim_get("foo", 0), url);
369370
// Verify the property is not animated.
370371
p.anim_get("foo", 0);
371372
QVERIFY(!p.get_animation("foo"));
372373
}
373374

375+
void ParseUntilJunk()
376+
{
377+
Properties p;
378+
// "foo=bar" is junk and parsing will stop after it
379+
const char *str = "50=100;foo=bar;60=120";
380+
p.set("foo", str);
381+
QVERIFY(p.is_anim("foo"));
382+
QCOMPARE(p.get("foo"), str);
383+
QCOMPARE(p.anim_get("foo", 50), "100");
384+
QCOMPARE(p.anim_get("foo", 60), "100"); // NOT 120
385+
// Verify the property is animated and only has one key.
386+
Animation a = p.get_animation("foo");
387+
QVERIFY(a.is_valid());
388+
QCOMPARE(a.key_count(), 1);
389+
}
390+
374391
void ShiftFramesPositive()
375392
{
376393
Properties p;

0 commit comments

Comments
 (0)