[FFmpeg-cvslog] avformat/matroskadec: Make reading zero-length elements spec-compliant

Andreas Rheinhardt git at videolan.org
Mon Feb 22 05:38:27 EET 2021


ffmpeg | branch: master | Andreas Rheinhardt <andreas.rheinhardt at gmail.com> | Tue Feb 16 16:51:40 2021 +0100| [0a99c3dadc3f9cef922c5c61a2ef4bc58af10a1a] | committer: Andreas Rheinhardt

avformat/matroskadec: Make reading zero-length elements spec-compliant

For a very long time, the payload of integer and float elements had to
have a length > 0. Our parser treated such invalid elements as having a
value zero. But now it has been defined what an EBML element with length
zero means: It is a shorthand for the default value. This has also been
defined for strings (both ASCII and UTF-8). This commit modifies our
parser to support this.

Reviewed-by: Ridley Combs <rcombs at rcombs.me>
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=0a99c3dadc3f9cef922c5c61a2ef4bc58af10a1a
---

 libavformat/matroskadec.c | 50 +++++++++++++++++++++++++++++++----------------
 1 file changed, 33 insertions(+), 17 deletions(-)

diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 069c879404..bfc6641a5f 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -929,12 +929,17 @@ static int ebml_read_length(MatroskaDemuxContext *matroska, AVIOContext *pb,
 
 /*
  * Read the next element as an unsigned int.
- * Returns NEEDS_CHECKING.
+ * Returns NEEDS_CHECKING unless size == 0.
  */
-static int ebml_read_uint(AVIOContext *pb, int size, uint64_t *num)
+static int ebml_read_uint(AVIOContext *pb, int size,
+                          uint64_t default_value, uint64_t *num)
 {
     int n = 0;
 
+    if (size == 0) {
+        *num = default_value;
+        return 0;
+    }
     /* big-endian ordering; build up number */
     *num = 0;
     while (n++ < size)
@@ -945,14 +950,16 @@ static int ebml_read_uint(AVIOContext *pb, int size, uint64_t *num)
 
 /*
  * Read the next element as a signed int.
- * Returns NEEDS_CHECKING.
+ * Returns NEEDS_CHECKING unless size == 0.
  */
-static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num)
+static int ebml_read_sint(AVIOContext *pb, int size,
+                          int64_t default_value, int64_t *num)
 {
     int n = 1;
 
     if (size == 0) {
-        *num = 0;
+        *num = default_value;
+        return 0;
     } else {
         *num = sign_extend(avio_r8(pb), 8);
 
@@ -966,17 +973,19 @@ static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num)
 
 /*
  * Read the next element as a float.
- * Returns NEEDS_CHECKING or < 0 on obvious failure.
+ * Returns 0 if size == 0, NEEDS_CHECKING or < 0 on obvious failure.
  */
-static int ebml_read_float(AVIOContext *pb, int size, double *num)
+static int ebml_read_float(AVIOContext *pb, int size,
+                           double default_value, double *num)
 {
-    if (size == 0)
-        *num = 0;
-    else if (size == 4)
+    if (size == 0) {
+        *num = default_value;
+        return 0;
+    } else if (size == 4) {
         *num = av_int2float(avio_rb32(pb));
-    else if (size == 8)
+    } else if (size == 8) {
         *num = av_int2double(avio_rb64(pb));
-    else
+    } else
         return AVERROR_INVALIDDATA;
 
     return NEEDS_CHECKING;
@@ -986,11 +995,17 @@ static int ebml_read_float(AVIOContext *pb, int size, double *num)
  * Read the next element as an ASCII string.
  * 0 is success, < 0 or NEEDS_CHECKING is failure.
  */
-static int ebml_read_ascii(AVIOContext *pb, int size, char **str)
+static int ebml_read_ascii(AVIOContext *pb, int size,
+                           const char *default_value, char **str)
 {
     char *res;
     int ret;
 
+    if (size == 0 && default_value) {
+        res = av_strdup(default_value);
+        if (!res)
+            return AVERROR(ENOMEM);
+    } else {
     /* EBML strings are usually not 0-terminated, so we allocate one
      * byte more, read the string and NULL-terminate it ourselves. */
     if (!(res = av_malloc(size + 1)))
@@ -1000,6 +1015,7 @@ static int ebml_read_ascii(AVIOContext *pb, int size, char **str)
         return ret < 0 ? ret : NEEDS_CHECKING;
     }
     (res)[size] = '\0';
+    }
     av_free(*str);
     *str = res;
 
@@ -1396,17 +1412,17 @@ static int ebml_parse(MatroskaDemuxContext *matroska,
 
     switch (syntax->type) {
     case EBML_UINT:
-        res = ebml_read_uint(pb, length, data);
+        res = ebml_read_uint(pb, length, syntax->def.u, data);
         break;
     case EBML_SINT:
-        res = ebml_read_sint(pb, length, data);
+        res = ebml_read_sint(pb, length, syntax->def.i, data);
         break;
     case EBML_FLOAT:
-        res = ebml_read_float(pb, length, data);
+        res = ebml_read_float(pb, length, syntax->def.f, data);
         break;
     case EBML_STR:
     case EBML_UTF8:
-        res = ebml_read_ascii(pb, length, data);
+        res = ebml_read_ascii(pb, length, syntax->def.s, data);
         break;
     case EBML_BIN:
         res = ebml_read_binary(pb, length, pos_alt, data);



More information about the ffmpeg-cvslog mailing list