Skip to content

Commit 57dfaa4

Browse files
committed
Improve animation-string detection in mlt_property_is_anim
Fix false positives where plain strings containing '=' were treated as animated properties. - replace the naive "contains '='" check with keyframe-aware parsing - require an unquoted key=value token whose key parses as a frame/time token - support optional single-character keyframe-type markers before '=' (e.g. |, !, ~, $, -, and easing markers A-D/a-z) - ignore separators inside quoted payloads so normal string values remain valid - document the updated detection rules in the API comment This preserves valid animation strings while preventing non-animated text (such as URL/query-like values) from being misclassified as animation.
1 parent 0543668 commit 57dfaa4

1 file changed

Lines changed: 78 additions & 1 deletion

File tree

src/framework/mlt_property.c

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "mlt_animation.h"
3030
#include "mlt_properties.h"
3131

32+
#include <ctype.h>
3233
#include <float.h>
3334
#include <locale.h>
3435
#include <math.h>
@@ -2106,18 +2107,94 @@ mlt_properties mlt_property_get_properties(mlt_property self)
21062107
return properties;
21072108
}
21082109

2110+
static int is_keyframe_type_marker(char c)
2111+
{
2112+
switch (c) {
2113+
case '|':
2114+
case '!':
2115+
case '~':
2116+
case '$':
2117+
case '-':
2118+
return 1;
2119+
default:
2120+
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'D');
2121+
}
2122+
}
2123+
2124+
static int is_keyframe_token(const char *begin, const char *end)
2125+
{
2126+
while (begin < end && isspace((unsigned char) *begin))
2127+
++begin;
2128+
while (end > begin && isspace((unsigned char) end[-1]))
2129+
--end;
2130+
if (begin >= end)
2131+
return 0;
2132+
2133+
if (end - begin > 1 && is_keyframe_type_marker(end[-1]))
2134+
--end;
2135+
2136+
int has_digit = 0;
2137+
int trailing_unit_seen = 0;
2138+
for (const char *p = begin; p < end; ++p) {
2139+
unsigned char c = (unsigned char) *p;
2140+
if (isdigit(c)) {
2141+
has_digit = 1;
2142+
continue;
2143+
}
2144+
if (c == ':' || c == '.' || c == ',' || c == '-' || c == '+')
2145+
continue;
2146+
if (isalpha(c) && p == end - 1 && !trailing_unit_seen && has_digit) {
2147+
trailing_unit_seen = 1;
2148+
continue;
2149+
}
2150+
return 0;
2151+
}
2152+
return has_digit;
2153+
}
2154+
21092155
/** Check if a property is animated.
21102156
*
21112157
* This is not a thread-safe function because it is used internally by
21122158
* mlt_property_s under a lock. However, external callers should protect it.
2159+
*
2160+
* A property counts as animated when it already has an animation object or
2161+
* when its serialized string contains at least one unquoted keyframe item of
2162+
* the form key=value, where key looks like a frame or time token. This also
2163+
* accepts the optional single-character keyframe-type marker that serialized
2164+
* animations place immediately before '='.
2165+
*
2166+
* This intentionally does not treat every '=' as animation syntax. Plain
2167+
* strings may legitimately contain '=' or ';' characters, and those continue
2168+
* to work as ordinary string values. Quoted string payloads inside animation
2169+
* strings also continue to work: text between double quotes is ignored while
2170+
* scanning for separators, matching the documented requirement to quote string
2171+
* values that contain animation delimiters.
2172+
*
21132173
* \public \memberof mlt_property_s
21142174
* \param self a property
21152175
* \return true if the property is animated
21162176
*/
21172177

21182178
int mlt_property_is_anim(mlt_property self)
21192179
{
2120-
return self->animation || (self->prop_string && strchr(self->prop_string, '='));
2180+
if (self->animation)
2181+
return 1;
2182+
if (!self->prop_string)
2183+
return 0;
2184+
2185+
const char *token_start = self->prop_string;
2186+
int in_quotes = 0;
2187+
for (const char *p = self->prop_string; *p; ++p) {
2188+
if (*p == '"' && (p == self->prop_string || p[-1] != '\\')) {
2189+
in_quotes = !in_quotes;
2190+
continue;
2191+
}
2192+
if (!in_quotes && *p == '=')
2193+
return is_keyframe_token(token_start, p);
2194+
if (!in_quotes && *p == ';')
2195+
token_start = p + 1;
2196+
}
2197+
return 0;
21212198
}
21222199

21232200
/** Check if a property is a color.

0 commit comments

Comments
 (0)