demux/ebml: interpret zero-length elements as their default value
An EBML element is permitted to have a zero-length data payload. It's then interpreted as the element's RFC declared default value, or zero. Before this change all zero-length elements were initialized to empty or rejected in case of uint. Fixes: #18351
This commit is contained in:
1 parent
52bb166f30
commit
e167836802
3 files changed
+77
-37
No files matched your search
+48
-31
@@ -28,13 +28,13 @@ from math import ldexp
|
|||||||
|
|
||||||
elements_ebml = (
|
elements_ebml = (
|
||||||
"EBML, 1a45dfa3, sub", (
|
"EBML, 1a45dfa3, sub", (
|
||||||
"EBMLVersion, 4286, uint",
|
"EBMLVersion, 4286, uint, default=1",
|
||||||
"EBMLReadVersion, 42f7, uint",
|
"EBMLReadVersion, 42f7, uint, default=1",
|
||||||
"EBMLMaxIDLength, 42f2, uint",
|
"EBMLMaxIDLength, 42f2, uint, default=4",
|
||||||
"EBMLMaxSizeLength, 42f3, uint",
|
"EBMLMaxSizeLength, 42f3, uint, default=8",
|
||||||
"DocType, 4282, str",
|
"DocType, 4282, str",
|
||||||
"DocTypeVersion, 4287, uint",
|
"DocTypeVersion, 4287, uint, default=1",
|
||||||
"DocTypeReadVersion, 4285, uint",
|
"DocTypeReadVersion, 4285, uint, default=1",
|
||||||
),
|
),
|
||||||
|
|
||||||
"CRC32, bf, binary",
|
"CRC32, bf, binary",
|
||||||
@@ -55,7 +55,7 @@ elements_matroska = (
|
|||||||
"SegmentUID, 73a4, binary, length=16",
|
"SegmentUID, 73a4, binary, length=16",
|
||||||
"PrevUID, 3cb923, binary, length=16",
|
"PrevUID, 3cb923, binary, length=16",
|
||||||
"NextUID, 3eb923, binary, length=16",
|
"NextUID, 3eb923, binary, length=16",
|
||||||
"TimecodeScale, 2ad7b1, uint",
|
"TimecodeScale, 2ad7b1, uint, default=1000000",
|
||||||
"DateUTC, 4461, sint",
|
"DateUTC, 4461, sint",
|
||||||
"Title, 7ba9, str",
|
"Title, 7ba9, str",
|
||||||
"MuxingApp, 4d80, str",
|
"MuxingApp, 4d80, str",
|
||||||
@@ -72,7 +72,7 @@ elements_matroska = (
|
|||||||
"DiscardPadding, 75A2, sint",
|
"DiscardPadding, 75A2, sint",
|
||||||
"BlockAdditions, 75A1, sub", (
|
"BlockAdditions, 75A1, sub", (
|
||||||
"BlockMore*, A6, sub", (
|
"BlockMore*, A6, sub", (
|
||||||
"BlockAddID, EE, uint",
|
"BlockAddID, EE, uint, default=1",
|
||||||
"BlockAdditional, A5, binary",
|
"BlockAdditional, A5, binary",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -85,34 +85,34 @@ elements_matroska = (
|
|||||||
"TrackNumber, d7, uint",
|
"TrackNumber, d7, uint",
|
||||||
"TrackUID, 73c5, uint",
|
"TrackUID, 73c5, uint",
|
||||||
"TrackType, 83, uint",
|
"TrackType, 83, uint",
|
||||||
"FlagEnabled, b9, uint",
|
"FlagEnabled, b9, uint, default=1",
|
||||||
"FlagDefault, 88, uint",
|
"FlagDefault, 88, uint, default=1",
|
||||||
"FlagForced, 55aa, uint",
|
"FlagForced, 55aa, uint",
|
||||||
"FlagHearingImpaired, 55ab, uint",
|
"FlagHearingImpaired, 55ab, uint",
|
||||||
"FlagVisualImpaired, 55ac, uint",
|
"FlagVisualImpaired, 55ac, uint",
|
||||||
"FlagOriginal, 55ae, uint",
|
"FlagOriginal, 55ae, uint",
|
||||||
"FlagCommentary, 55af, uint",
|
"FlagCommentary, 55af, uint",
|
||||||
"FlagLacing, 9c, uint",
|
"FlagLacing, 9c, uint, default=1",
|
||||||
"MinCache, 6de7, uint",
|
"MinCache, 6de7, uint",
|
||||||
"MaxCache, 6df8, uint",
|
"MaxCache, 6df8, uint",
|
||||||
"DefaultDuration, 23e383, uint",
|
"DefaultDuration, 23e383, uint",
|
||||||
"TrackTimecodeScale, 23314f, float",
|
"TrackTimecodeScale, 23314f, float, default=1",
|
||||||
"MaxBlockAdditionID, 55ee, uint",
|
"MaxBlockAdditionID, 55ee, uint",
|
||||||
"Name, 536e, str",
|
"Name, 536e, str",
|
||||||
"Language, 22b59c, str",
|
"Language, 22b59c, str, default=eng",
|
||||||
"LanguageBCP47, 22b59d, str",
|
"LanguageBCP47, 22b59d, str",
|
||||||
"CodecID, 86, str",
|
"CodecID, 86, str",
|
||||||
"CodecPrivate, 63a2, binary",
|
"CodecPrivate, 63a2, binary",
|
||||||
"CodecName, 258688, str",
|
"CodecName, 258688, str",
|
||||||
"CodecDecodeAll, aa, uint",
|
"CodecDecodeAll, aa, uint, default=1",
|
||||||
"CodecDelay, 56aa, uint",
|
"CodecDelay, 56aa, uint",
|
||||||
"SeekPreRoll, 56bb, uint",
|
"SeekPreRoll, 56bb, uint",
|
||||||
"Video, e0, sub", (
|
"Video, e0, sub", (
|
||||||
"FlagInterlaced, 9a, uint",
|
"FlagInterlaced, 9a, uint",
|
||||||
"PixelWidth, b0, uint",
|
"PixelWidth, b0, uint",
|
||||||
"PixelHeight, ba, uint",
|
"PixelHeight, ba, uint",
|
||||||
"DisplayWidth, 54b0, uint",
|
"DisplayWidth, 54b0, uint, default=context",
|
||||||
"DisplayHeight, 54ba, uint",
|
"DisplayHeight, 54ba, uint, default=context",
|
||||||
"DisplayUnit, 54b2, uint",
|
"DisplayUnit, 54b2, uint",
|
||||||
"PixelCropTop, 54bb, uint",
|
"PixelCropTop, 54bb, uint",
|
||||||
"PixelCropLeft, 54cc, uint",
|
"PixelCropLeft, 54cc, uint",
|
||||||
@@ -122,7 +122,7 @@ elements_matroska = (
|
|||||||
"ColourSpace, 2eb524, binary, length=4",
|
"ColourSpace, 2eb524, binary, length=4",
|
||||||
"StereoMode, 53b8, uint",
|
"StereoMode, 53b8, uint",
|
||||||
"Colour, 55b0, sub", (
|
"Colour, 55b0, sub", (
|
||||||
"MatrixCoefficients, 55B1, uint",
|
"MatrixCoefficients, 55B1, uint, default=2",
|
||||||
"BitsPerChannel, 55B2, uint",
|
"BitsPerChannel, 55B2, uint",
|
||||||
"ChromaSubsamplingHorz, 55B3, uint",
|
"ChromaSubsamplingHorz, 55B3, uint",
|
||||||
"ChromaSubsamplingVert, 55B4, uint",
|
"ChromaSubsamplingVert, 55B4, uint",
|
||||||
@@ -131,8 +131,8 @@ elements_matroska = (
|
|||||||
"ChromaSitingHorz, 55B7, uint",
|
"ChromaSitingHorz, 55B7, uint",
|
||||||
"ChromaSitingVert, 55B8, uint",
|
"ChromaSitingVert, 55B8, uint",
|
||||||
"Range, 55B9, uint",
|
"Range, 55B9, uint",
|
||||||
"TransferCharacteristics, 55BA, uint",
|
"TransferCharacteristics, 55BA, uint, default=2",
|
||||||
"Primaries, 55BB, uint",
|
"Primaries, 55BB, uint, default=2",
|
||||||
"MaxCLL, 55BC, uint",
|
"MaxCLL, 55BC, uint",
|
||||||
"MaxFALL, 55BD, uint",
|
"MaxFALL, 55BD, uint",
|
||||||
"MasteringMetadata, 55D0, sub", (
|
"MasteringMetadata, 55D0, sub", (
|
||||||
@@ -157,15 +157,15 @@ elements_matroska = (
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
"Audio, e1, sub", (
|
"Audio, e1, sub", (
|
||||||
"SamplingFrequency, b5, float",
|
"SamplingFrequency, b5, float, default=8000",
|
||||||
"OutputSamplingFrequency, 78b5, float",
|
"OutputSamplingFrequency, 78b5, float, default=context",
|
||||||
"Channels, 9f, uint",
|
"Channels, 9f, uint, default=1",
|
||||||
"BitDepth, 6264, uint",
|
"BitDepth, 6264, uint",
|
||||||
),
|
),
|
||||||
"ContentEncodings, 6d80, sub", (
|
"ContentEncodings, 6d80, sub", (
|
||||||
"ContentEncoding*, 6240, sub", (
|
"ContentEncoding*, 6240, sub", (
|
||||||
"ContentEncodingOrder, 5031, uint",
|
"ContentEncodingOrder, 5031, uint",
|
||||||
"ContentEncodingScope, 5032, uint",
|
"ContentEncodingScope, 5032, uint, default=1",
|
||||||
"ContentEncodingType, 5033, uint",
|
"ContentEncodingType, 5033, uint",
|
||||||
"ContentCompression, 5034, sub", (
|
"ContentCompression, 5034, sub", (
|
||||||
"ContentCompAlgo, 4254, uint",
|
"ContentCompAlgo, 4254, uint",
|
||||||
@@ -215,12 +215,12 @@ elements_matroska = (
|
|||||||
"ChapterTimeStart, 91, uint",
|
"ChapterTimeStart, 91, uint",
|
||||||
"ChapterTimeEnd, 92, uint",
|
"ChapterTimeEnd, 92, uint",
|
||||||
"ChapterFlagHidden, 98, uint",
|
"ChapterFlagHidden, 98, uint",
|
||||||
"ChapterFlagEnabled, 4598, uint",
|
"ChapterFlagEnabled, 4598, uint, default=1",
|
||||||
"ChapterSegmentUID, 6e67, binary, length=16",
|
"ChapterSegmentUID, 6e67, binary, length=16",
|
||||||
"ChapterSegmentEditionUID, 6ebc, uint",
|
"ChapterSegmentEditionUID, 6ebc, uint",
|
||||||
"ChapterDisplay*, 80, sub", (
|
"ChapterDisplay*, 80, sub", (
|
||||||
"ChapString, 85, str",
|
"ChapString, 85, str",
|
||||||
"ChapLanguage*, 437c, str",
|
"ChapLanguage*, 437c, str, default=eng",
|
||||||
"ChapLanguageBCP47*, 437d, str",
|
"ChapLanguageBCP47*, 437d, str",
|
||||||
"ChapCountry*, 437e, str",
|
"ChapCountry*, 437e, str",
|
||||||
),
|
),
|
||||||
@@ -230,7 +230,7 @@ elements_matroska = (
|
|||||||
"Tags*, 1254c367, sub", (
|
"Tags*, 1254c367, sub", (
|
||||||
"Tag*, 7373, sub", (
|
"Tag*, 7373, sub", (
|
||||||
"Targets, 63c0, sub", (
|
"Targets, 63c0, sub", (
|
||||||
"TargetTypeValue, 68ca, uint",
|
"TargetTypeValue, 68ca, uint, default=50",
|
||||||
"TargetType, 63ca, str",
|
"TargetType, 63ca, str",
|
||||||
"TargetTrackUID, 63c5, uint",
|
"TargetTrackUID, 63c5, uint",
|
||||||
"TargetEditionUID, 63c9, uint",
|
"TargetEditionUID, 63c9, uint",
|
||||||
@@ -239,10 +239,10 @@ elements_matroska = (
|
|||||||
),
|
),
|
||||||
"SimpleTag*, 67c8, sub", (
|
"SimpleTag*, 67c8, sub", (
|
||||||
"TagName, 45a3, str",
|
"TagName, 45a3, str",
|
||||||
"TagLanguage, 447a, str",
|
"TagLanguage, 447a, str, default=und",
|
||||||
"TagLanguageBCP47, 447b, str",
|
"TagLanguageBCP47, 447b, str",
|
||||||
"TagString, 4487, str",
|
"TagString, 4487, str",
|
||||||
"TagDefault, 4484, uint",
|
"TagDefault, 4484, uint, default=1",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -266,7 +266,8 @@ def camelcase_to_words(name):
|
|||||||
|
|
||||||
class MatroskaElement:
|
class MatroskaElement:
|
||||||
|
|
||||||
def __init__(self, name, elid, valtype, namespace, length=None):
|
def __init__(self, name, elid, valtype, namespace, length=None,
|
||||||
|
default=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.definename = f"{namespace}_ID_{name.upper()}"
|
self.definename = f"{namespace}_ID_{name.upper()}"
|
||||||
self.fieldname = camelcase_to_words(name)
|
self.fieldname = camelcase_to_words(name)
|
||||||
@@ -274,6 +275,7 @@ class MatroskaElement:
|
|||||||
self.elid = elid
|
self.elid = elid
|
||||||
self.valtype = valtype
|
self.valtype = valtype
|
||||||
self.length = int(length or "0")
|
self.length = int(length or "0")
|
||||||
|
self.default = default
|
||||||
if valtype == "sub":
|
if valtype == "sub":
|
||||||
self.ebmltype = "EBML_TYPE_SUBELEMENTS"
|
self.ebmltype = "EBML_TYPE_SUBELEMENTS"
|
||||||
self.valname = "struct " + self.structname
|
self.valname = "struct " + self.structname
|
||||||
@@ -292,6 +294,21 @@ class MatroskaElement:
|
|||||||
self.subelements = subelements
|
self.subelements = subelements
|
||||||
self.subids = {x[0].elid for x in subelements}
|
self.subids = {x[0].elid for x in subelements}
|
||||||
|
|
||||||
|
def default_initializer(self):
|
||||||
|
if self.default is None:
|
||||||
|
return "false, {0}"
|
||||||
|
if self.default == "context":
|
||||||
|
return "true, {0}"
|
||||||
|
if self.valtype == "uint":
|
||||||
|
return f"false, {{.u = {int(self.default)}}}"
|
||||||
|
if self.valtype == "sint":
|
||||||
|
return f"false, {{.i = {int(self.default)}}}"
|
||||||
|
if self.valtype == "float":
|
||||||
|
return f"false, {{.f = {float(self.default)}}}"
|
||||||
|
if self.valtype == "str":
|
||||||
|
return f'false, {{.s = "{self.default}"}}'
|
||||||
|
raise SyntaxError("Default not supported for type " + self.valtype)
|
||||||
|
|
||||||
elementd: dict[str, MatroskaElement] = {}
|
elementd: dict[str, MatroskaElement] = {}
|
||||||
elementlist: list[MatroskaElement] = []
|
elementlist: list[MatroskaElement] = []
|
||||||
def parse_elems(elements, namespace):
|
def parse_elems(elements, namespace):
|
||||||
@@ -302,7 +319,7 @@ def parse_elems(elements, namespace):
|
|||||||
attrs = {}
|
attrs = {}
|
||||||
for extra in rest:
|
for extra in rest:
|
||||||
key, sep, value = extra.partition("=")
|
key, sep, value = extra.partition("=")
|
||||||
if not sep or key not in ("length",):
|
if not sep or key not in ("length", "default"):
|
||||||
raise SyntaxError("Invalid element attribute " + extra)
|
raise SyntaxError("Invalid element attribute " + extra)
|
||||||
attrs[key] = value
|
attrs[key] = value
|
||||||
hexid = hexid.lower()
|
hexid = hexid.lower()
|
||||||
@@ -371,7 +388,7 @@ def generate_c_definitions(out):
|
|||||||
printf(out, "#undef N")
|
printf(out, "#undef N")
|
||||||
else:
|
else:
|
||||||
printf(out, f'E("{el.name}", {el.fieldname}, {el.ebmltype}, '
|
printf(out, f'E("{el.name}", {el.fieldname}, {el.ebmltype}, '
|
||||||
f'{el.length})')
|
f'{el.length}, {el.default_initializer()})')
|
||||||
|
|
||||||
def read(s, length):
|
def read(s, length):
|
||||||
t = s.read(length)
|
t = s.read(length)
|
||||||
|
|||||||
+22
-6
@@ -210,8 +210,11 @@ int ebml_resync_cluster(struct mp_log *log, stream_t *s)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static_assert(sizeof(((struct ebml_elem_desc *)0)->defval) == sizeof(((struct ebml_elem_desc *)0)->defval.u),
|
||||||
|
"defval.u must cover the entire union for {0} initialization");
|
||||||
|
|
||||||
#define EVALARGS(F, ...) F(__VA_ARGS__)
|
#define EVALARGS(F, ...) F(__VA_ARGS__)
|
||||||
#define E(str, N, type, length) const struct ebml_elem_desc ebml_ ## N ## _desc = { str, type, length };
|
#define E(str, N, type, length, context, ...) const struct ebml_elem_desc ebml_ ## N ## _desc = { str, type, length, .context_default = context, .defval = __VA_ARGS__ };
|
||||||
#define E_SN(str, count, N) const struct ebml_elem_desc ebml_ ## N ## _desc = { str, EBML_TYPE_SUBELEMENTS, sizeof(struct ebml_ ## N), count, (const struct ebml_field_desc[]){
|
#define E_SN(str, count, N) const struct ebml_elem_desc ebml_ ## N ## _desc = { str, EBML_TYPE_SUBELEMENTS, sizeof(struct ebml_ ## N), count, (const struct ebml_field_desc[]){
|
||||||
#define E_S(str, count) EVALARGS(E_SN, str, count, N)
|
#define E_S(str, count) EVALARGS(E_SN, str, count, N)
|
||||||
#define FN(id, name, multiple, N) { id, multiple, offsetof(struct ebml_ ## N, name), offsetof(struct ebml_ ## N, n_ ## name), &ebml_##name##_desc},
|
#define FN(id, name, multiple, N) { id, multiple, offsetof(struct ebml_ ## N, name), offsetof(struct ebml_ ## N, n_ ## name), &ebml_##name##_desc},
|
||||||
@@ -510,11 +513,13 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
|||||||
else \
|
else \
|
||||||
subelptr = (fieldtype *) fieldptr
|
subelptr = (fieldtype *) fieldptr
|
||||||
GETPTR(uintptr, uint64_t);
|
GETPTR(uintptr, uint64_t);
|
||||||
if (length < 1 || length > 8) {
|
if (length > 8) {
|
||||||
MP_ERR(ctx, "uint invalid length %"PRIu64"\n", length);
|
MP_ERR(ctx, "uint invalid length %"PRIu64"\n", length);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
*uintptr = ebml_parse_uint(data, length);
|
if (!length && ed->context_default)
|
||||||
|
goto skip;
|
||||||
|
*uintptr = length ? ebml_parse_uint(data, length) : ed->defval.u;
|
||||||
MP_TRACE(ctx, "uint %"PRIu64"\n", *uintptr);
|
MP_TRACE(ctx, "uint %"PRIu64"\n", *uintptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -525,7 +530,9 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
|||||||
MP_ERR(ctx, "sint invalid length %"PRIu64"\n", length);
|
MP_ERR(ctx, "sint invalid length %"PRIu64"\n", length);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
*sintptr = ebml_parse_sint(data, length);
|
if (!length && ed->context_default)
|
||||||
|
goto skip;
|
||||||
|
*sintptr = length ? ebml_parse_sint(data, length) : ed->defval.i;
|
||||||
MP_TRACE(ctx, "sint %"PRId64"\n", *sintptr);
|
MP_TRACE(ctx, "sint %"PRId64"\n", *sintptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -536,7 +543,9 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
|||||||
MP_ERR(ctx, "float invalid length %"PRIu64"\n", length);
|
MP_ERR(ctx, "float invalid length %"PRIu64"\n", length);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
*floatptr = ebml_parse_float(data, length);
|
if (!length && ed->context_default)
|
||||||
|
goto skip;
|
||||||
|
*floatptr = length ? ebml_parse_float(data, length) : ed->defval.f;
|
||||||
MP_DBG(ctx, "float %f\n", *floatptr);
|
MP_DBG(ctx, "float %f\n", *floatptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -547,7 +556,13 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
|||||||
}
|
}
|
||||||
char **strptr;
|
char **strptr;
|
||||||
GETPTR(strptr, char *);
|
GETPTR(strptr, char *);
|
||||||
*strptr = talloc_strndup(ctx->talloc_ctx, data, length);
|
if (!length && ed->context_default)
|
||||||
|
goto skip;
|
||||||
|
if (!length && ed->defval.s) {
|
||||||
|
*strptr = talloc_strdup(ctx->talloc_ctx, ed->defval.s);
|
||||||
|
} else {
|
||||||
|
*strptr = talloc_strndup(ctx->talloc_ctx, data, length);
|
||||||
|
}
|
||||||
MP_TRACE(ctx, "string \"%s\"\n", *strptr);
|
MP_TRACE(ctx, "string \"%s\"\n", *strptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -583,6 +598,7 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
|||||||
}
|
}
|
||||||
*countptr += 1;
|
*countptr += 1;
|
||||||
error:
|
error:
|
||||||
|
skip:
|
||||||
data += length;
|
data += length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ struct ebml_elem_desc {
|
|||||||
int size;
|
int size;
|
||||||
int field_count;
|
int field_count;
|
||||||
const struct ebml_field_desc *fields;
|
const struct ebml_field_desc *fields;
|
||||||
|
bool context_default; // default derives from other elements
|
||||||
|
union {
|
||||||
|
uint64_t u;
|
||||||
|
int64_t i;
|
||||||
|
double f;
|
||||||
|
const char *s;
|
||||||
|
} defval; // default value of a zero-length element
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ebml_parse_ctx {
|
struct ebml_parse_ctx {
|
||||||
|
|||||||
Reference in new issue
Block a user