[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