avformat/matroskadec: Accept more unknown-length elements II
authorAndreas Rheinhardt <andreas.rheinhardt@gmail.com>
Thu, 16 May 2019 22:30:18 +0000 (00:30 +0200)
committerJames Almer <jamrial@gmail.com>
Tue, 16 Jul 2019 19:18:09 +0000 (16:18 -0300)
Up until now, one last kind of unknown-length element hasn't been
properly handled: Unknown-length elements that are supposed to be
skipped, i.e. the level 1 elements that might reside after the
clusters.

This commit changes this. To do this, ebml_parse got a mode that
essentially tries to skip everything except when parsing is needed
(namely for unknown-length elements for which parsing is necessary
as they can't be skipped). This mode is selected by using a NULL
as destination where the parsed data should be written to.
It is used to parse the level 1 elements in matroska_parse_cluster.

The syntax list used for parsing must of course include links to
the syntax of all the master elements that might need to be parsed.
In other words: Instead of matroska_clusters (which contained every
level 1 element except clusters as EBML_NONE elements designated to
be skipped) matroska_segment is needed and used; matroska_clusters has
been removed.

Furthermore, matroska_segment has been reordered so that clusters are at
the front as this is now the most common case for this list.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
libavformat/matroskadec.c

index 24d3ef2..31bb693 100644 (file)
@@ -685,6 +685,7 @@ static const EbmlSyntax matroska_seekhead[] = {
 };
 
 static const EbmlSyntax matroska_segment[] = {
+    { MATROSKA_ID_CLUSTER,     EBML_STOP },
     { MATROSKA_ID_INFO,        EBML_LEVEL1, 0, 0, { .n = matroska_info } },
     { MATROSKA_ID_TRACKS,      EBML_LEVEL1, 0, 0, { .n = matroska_tracks } },
     { MATROSKA_ID_ATTACHMENTS, EBML_LEVEL1, 0, 0, { .n = matroska_attachments } },
@@ -692,7 +693,6 @@ static const EbmlSyntax matroska_segment[] = {
     { MATROSKA_ID_CUES,        EBML_LEVEL1, 0, 0, { .n = matroska_index } },
     { MATROSKA_ID_TAGS,        EBML_LEVEL1, 0, 0, { .n = matroska_tags } },
     { MATROSKA_ID_SEEKHEAD,    EBML_LEVEL1, 0, 0, { .n = matroska_seekhead } },
-    { MATROSKA_ID_CLUSTER,     EBML_STOP },
     { 0 }   /* We don't want to go back to level 0, so don't add the parent. */
 };
 
@@ -740,18 +740,6 @@ static const EbmlSyntax matroska_cluster_enter[] = {
     { MATROSKA_ID_CLUSTER,     EBML_NEST, 0, 0, { .n = &matroska_cluster_parsing[2] } },
     { 0 }
 };
-
-static const EbmlSyntax matroska_clusters[] = {
-    { MATROSKA_ID_CLUSTER,     EBML_STOP },
-    { MATROSKA_ID_CUES,        EBML_NONE },
-    { MATROSKA_ID_TAGS,        EBML_NONE },
-    { MATROSKA_ID_INFO,        EBML_NONE },
-    { MATROSKA_ID_TRACKS,      EBML_NONE },
-    { MATROSKA_ID_ATTACHMENTS, EBML_NONE },
-    { MATROSKA_ID_CHAPTERS,    EBML_NONE },
-    { MATROSKA_ID_SEEKHEAD,    EBML_NONE },
-    { 0 } /* We don't want to go back to level 0, so don't add the parent. */
-};
 #undef CHILD_OF
 
 static const char *const matroska_doctypes[] = { "matroska", "webm" };
@@ -1082,6 +1070,7 @@ static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax,
 {
     int i, res;
 
+    if (data) {
     for (i = 0; syntax[i].id; i++)
         switch (syntax[i].type) {
         case EBML_UINT:
@@ -1109,6 +1098,7 @@ static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax,
         matroska->num_levels--;
         return 0;
     }
+    }
 
     do {
         res = ebml_parse(matroska, syntax, data);
@@ -1238,6 +1228,7 @@ static int ebml_parse(MatroskaDemuxContext *matroska,
         update_pos = 0; /* Don't update resync_pos as an error might have happened. */
     }
 
+    if (data) {
     data = (char *) data + syntax->data_offset;
     if (syntax->list_elem_size) {
         EbmlList *list = data;
@@ -1250,6 +1241,7 @@ static int ebml_parse(MatroskaDemuxContext *matroska,
         memset(data, 0, syntax->list_elem_size);
         list->nb_elem++;
     }
+    }
 
     if (syntax->type != EBML_STOP) {
         matroska->current_id = 0;
@@ -1366,6 +1358,9 @@ static int ebml_parse(MatroskaDemuxContext *matroska,
             // of the element as the "last known good" position.
             matroska->resync_pos = pos;
         }
+
+        if (!data && length != EBML_UNKNOWN_LENGTH)
+            goto skip;
     }
 
     switch (syntax->type) {
@@ -1404,6 +1399,7 @@ static int ebml_parse(MatroskaDemuxContext *matroska,
         break;
     case EBML_STOP:
         return 1;
+    skip:
     default:
         if (length) {
             int64_t res2;
@@ -3671,7 +3667,7 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
     av_assert0(matroska->num_levels <= 2);
 
     if (matroska->num_levels == 1) {
-        res = ebml_parse(matroska, matroska_clusters, NULL);
+        res = ebml_parse(matroska, matroska_segment, NULL);
 
         if (res == 1) {
             /* Found a cluster: subtract the size of the ID already read. */