avcodec/htmlsubtitles: Replace very slow redundant sscanf() calls by cleaner and...
authorMichael Niedermayer <michael@niedermayer.cc>
Sun, 11 Jun 2017 15:58:45 +0000 (17:58 +0200)
committerMichael Niedermayer <michael@niedermayer.cc>
Thu, 22 Jun 2017 01:06:43 +0000 (03:06 +0200)
This reduces the worst case from O(n²) to O(n) time

Fixes Timeout
Fixes: 2127/clusterfuzz-testcase-minimized-6595787859427328

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 4132218b87cd6fb13abd162e3037ef4563286baa)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
libavcodec/htmlsubtitles.c

index 16295da..70311c6 100644 (file)
@@ -56,6 +56,7 @@ int ff_htmlmarkup_to_ass(void *log_ctx, AVBPrint *dst, const char *in)
     char *param, buffer[128], tmp[128];
     int len, tag_close, sptr = 1, line_start = 1, an = 0, end = 0;
     SrtStack stack[16];
+    int closing_brace_missing = 0;
 
     stack[0].tag[0] = 0;
     strcpy(stack[0].param[PARAM_SIZE],  "{\\fs}");
@@ -83,11 +84,20 @@ int ff_htmlmarkup_to_ass(void *log_ctx, AVBPrint *dst, const char *in)
                         and all microdvd like styles such as {Y:xxx} */
             len = 0;
             an += sscanf(in, "{\\an%*1u}%n", &len) >= 0 && len > 0;
-            if ((an != 1 && (len = 0, sscanf(in, "{\\%*[^}]}%n", &len) >= 0 && len > 0)) ||
-                (len = 0, sscanf(in, "{%*1[CcFfoPSsYy]:%*[^}]}%n", &len) >= 0 && len > 0)) {
-                in += len - 1;
-            } else
-                av_bprint_chars(dst, *in, 1);
+
+            if (!closing_brace_missing) {
+                if (   (an != 1 && in[1] == '\\')
+                    || (in[1] && strchr("CcFfoPSsYy", in[1]) && in[2] == ':')) {
+                    char *bracep = strchr(in+2, '}');
+                    if (bracep) {
+                        in = bracep;
+                        break;
+                    } else
+                        closing_brace_missing = 1;
+                }
+            }
+
+            av_bprint_chars(dst, *in, 1);
             break;
         case '<':
             tag_close = in[1] == '/';