PR #21008 opened by Kacper Michajłow (kasper93)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21008
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21008.patch

This allow to pass DOS path in filter graph string. Although we use `:`
as separator, we can make an exception for DOS path looking string. In
which cases first `:` is allowed to be included in the value.

Fixes drawvg filter, which would otherwise fail to parse `file` option
when DOS path is provided.

Fixes: fate-filter-drawvg-video


From 32c47d9fb67575e9b5667d1f0a6e39a294fac9e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]>
Date: Mon, 24 Nov 2025 21:17:29 +0100
Subject: [PATCH] avutil/opt: support DOS paths in key value parser

This allow to pass DOS path in filter graph string. Although we use `:`
as separator, we can make an exception for DOS path looking string. In
which cases first `:` is allowed to be included in the value.

Fixes drawvg filter, which would otherwise fail to parse `file` option
when DOS path is provided.

Fixes: fate-filter-drawvg-video
---
 libavutil/opt.c       | 32 ++++++++++++++++++++++++++++++++
 libavutil/tests/opt.c |  5 +++++
 tests/ref/fate/opt    | 19 +++++++++++++++++++
 3 files changed, 56 insertions(+)

diff --git a/libavutil/opt.c b/libavutil/opt.c
index fc5834e168..39d9177869 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -41,6 +41,7 @@
 #include "bprint.h"
 #include "version.h"
 
+#include <ctype.h>
 #include <float.h>
 
 #define TYPE_BASE(type) ((type) & ~AV_OPT_TYPE_FLAG_ARRAY)
@@ -1872,6 +1873,31 @@ static int get_key(const char **ropts, const char 
*delim, char **rkey)
     return 0;
 }
 
+#ifdef HAVE_DOS_PATHS
+static int get_dos_path(const char **ropts, const char *delim, char **rval)
+{
+    const char *opts = *ropts;
+    const char *val_start, *val_end;
+
+    if (!isalpha(opts[0]) || opts[1] != ':' || (opts[2] != '\\' && opts[2] != 
'/'))
+        return AVERROR(EINVAL);
+
+    val_start = opts += strspn(opts, WHITESPACES);
+    opts += 2; // skip drive letter and colon
+    while (*opts && !strchr(delim, *opts))
+        opts++;
+    val_end = opts;
+    while (val_end > val_start && strrchr(WHITESPACES, val_end[-1]))
+        val_end--;
+    if (!(*rval = av_malloc(val_end - val_start + 1)))
+        return AVERROR(ENOMEM);
+    memcpy(*rval, val_start, val_end - val_start);
+    (*rval)[val_end - val_start] = 0;
+    *ropts = opts;
+    return 0;
+}
+#endif
+
 int av_opt_get_key_value(const char **ropts,
                          const char *key_val_sep, const char *pairs_sep,
                          unsigned flags,
@@ -1884,6 +1910,12 @@ int av_opt_get_key_value(const char **ropts,
     if ((ret = get_key(&opts, key_val_sep, &key)) < 0 &&
         !(flags & AV_OPT_FLAG_IMPLICIT_KEY))
         return AVERROR(EINVAL);
+#ifdef HAVE_DOS_PATHS
+    // If value looks like a DOS path, try to parse it as a value.
+    if (pairs_sep && strchr(pairs_sep, ':') &&
+        get_dos_path(&opts, pairs_sep, &val) >= 0)
+    {} else
+#endif
     if (!(val = av_get_token(&opts, pairs_sep))) {
         av_free(key);
         return AVERROR(ENOMEM);
diff --git a/libavutil/tests/opt.c b/libavutil/tests/opt.c
index 8ab76c4690..c5bf169310 100644
--- a/libavutil/tests/opt.c
+++ b/libavutil/tests/opt.c
@@ -516,6 +516,11 @@ int main(void)
             ":",
             "=",
             " 5 : hello : size = pal ",
+            "string=C:/dir/hello.txt  ",
+            "string=C:/dir/hello.txt:size=pal",
+            "string=C:\\dir\\hello.txt:size=pal",
+            "string = C:/dir/hello.txt : size = pal",
+            "string = C:\\dir\\hello.txt : size = pal",
             
"a_very_long_option_name_that_will_need_to_be_ellipsized_around_here=42"
         };
         static const char * const shorthand[] = { "num", "string", NULL };
diff --git a/tests/ref/fate/opt b/tests/ref/fate/opt
index 1f82f7e4bd..86f5f7c139 100644
--- a/tests/ref/fate/opt
+++ b/tests/ref/fate/opt
@@ -507,6 +507,25 @@ Setting 'num' to value '5'
 Setting 'string' to value 'hello'
 Setting 'size' to value 'pal'
 OK    ' 5 : hello : size = pal '
+Setting options string 'string=C:/dir/hello.txt  '
+Setting 'string' to value 'C:/dir/hello.txt'
+OK    'string=C:/dir/hello.txt  '
+Setting options string 'string=C:/dir/hello.txt:size=pal'
+Setting 'string' to value 'C:/dir/hello.txt'
+Setting 'size' to value 'pal'
+OK    'string=C:/dir/hello.txt:size=pal'
+Setting options string 'string=C:\dir\hello.txt:size=pal'
+Setting 'string' to value 'C:\dir\hello.txt'
+Setting 'size' to value 'pal'
+OK    'string=C:\dir\hello.txt:size=pal'
+Setting options string 'string = C:/dir/hello.txt : size = pal'
+Setting 'string' to value 'C'
+No option name near '/dir/hello.txt : size = pal'
+Error 'string = C:/dir/hello.txt : size = pal'
+Setting options string 'string = C:\dir\hello.txt : size = pal'
+Setting 'string' to value 'C'
+No option name near '\dir\hello.txt : size = pal'
+Error 'string = C:\dir\hello.txt : size = pal'
 Setting options string 
'a_very_long_option_name_that_will_need_to_be_ellipsized_around_here=42'
 Setting 'a_very_long_option_name_that_will_need_to_be_ellipsized_around_here' 
to value '42'
 Option 'a_very_long_option_name_that_will_need_to_be_ellipsized_around_here' 
not found
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to