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 = (
|
||||
"EBML, 1a45dfa3, sub", (
|
||||
"EBMLVersion, 4286, uint",
|
||||
"EBMLReadVersion, 42f7, uint",
|
||||
"EBMLMaxIDLength, 42f2, uint",
|
||||
"EBMLMaxSizeLength, 42f3, uint",
|
||||
"EBMLVersion, 4286, uint, default=1",
|
||||
"EBMLReadVersion, 42f7, uint, default=1",
|
||||
"EBMLMaxIDLength, 42f2, uint, default=4",
|
||||
"EBMLMaxSizeLength, 42f3, uint, default=8",
|
||||
"DocType, 4282, str",
|
||||
"DocTypeVersion, 4287, uint",
|
||||
"DocTypeReadVersion, 4285, uint",
|
||||
"DocTypeVersion, 4287, uint, default=1",
|
||||
"DocTypeReadVersion, 4285, uint, default=1",
|
||||
),
|
||||
|
||||
"CRC32, bf, binary",
|
||||
@@ -55,7 +55,7 @@ elements_matroska = (
|
||||
"SegmentUID, 73a4, binary, length=16",
|
||||
"PrevUID, 3cb923, binary, length=16",
|
||||
"NextUID, 3eb923, binary, length=16",
|
||||
"TimecodeScale, 2ad7b1, uint",
|
||||
"TimecodeScale, 2ad7b1, uint, default=1000000",
|
||||
"DateUTC, 4461, sint",
|
||||
"Title, 7ba9, str",
|
||||
"MuxingApp, 4d80, str",
|
||||
@@ -72,7 +72,7 @@ elements_matroska = (
|
||||
"DiscardPadding, 75A2, sint",
|
||||
"BlockAdditions, 75A1, sub", (
|
||||
"BlockMore*, A6, sub", (
|
||||
"BlockAddID, EE, uint",
|
||||
"BlockAddID, EE, uint, default=1",
|
||||
"BlockAdditional, A5, binary",
|
||||
),
|
||||
),
|
||||
@@ -85,34 +85,34 @@ elements_matroska = (
|
||||
"TrackNumber, d7, uint",
|
||||
"TrackUID, 73c5, uint",
|
||||
"TrackType, 83, uint",
|
||||
"FlagEnabled, b9, uint",
|
||||
"FlagDefault, 88, uint",
|
||||
"FlagEnabled, b9, uint, default=1",
|
||||
"FlagDefault, 88, uint, default=1",
|
||||
"FlagForced, 55aa, uint",
|
||||
"FlagHearingImpaired, 55ab, uint",
|
||||
"FlagVisualImpaired, 55ac, uint",
|
||||
"FlagOriginal, 55ae, uint",
|
||||
"FlagCommentary, 55af, uint",
|
||||
"FlagLacing, 9c, uint",
|
||||
"FlagLacing, 9c, uint, default=1",
|
||||
"MinCache, 6de7, uint",
|
||||
"MaxCache, 6df8, uint",
|
||||
"DefaultDuration, 23e383, uint",
|
||||
"TrackTimecodeScale, 23314f, float",
|
||||
"TrackTimecodeScale, 23314f, float, default=1",
|
||||
"MaxBlockAdditionID, 55ee, uint",
|
||||
"Name, 536e, str",
|
||||
"Language, 22b59c, str",
|
||||
"Language, 22b59c, str, default=eng",
|
||||
"LanguageBCP47, 22b59d, str",
|
||||
"CodecID, 86, str",
|
||||
"CodecPrivate, 63a2, binary",
|
||||
"CodecName, 258688, str",
|
||||
"CodecDecodeAll, aa, uint",
|
||||
"CodecDecodeAll, aa, uint, default=1",
|
||||
"CodecDelay, 56aa, uint",
|
||||
"SeekPreRoll, 56bb, uint",
|
||||
"Video, e0, sub", (
|
||||
"FlagInterlaced, 9a, uint",
|
||||
"PixelWidth, b0, uint",
|
||||
"PixelHeight, ba, uint",
|
||||
"DisplayWidth, 54b0, uint",
|
||||
"DisplayHeight, 54ba, uint",
|
||||
"DisplayWidth, 54b0, uint, default=context",
|
||||
"DisplayHeight, 54ba, uint, default=context",
|
||||
"DisplayUnit, 54b2, uint",
|
||||
"PixelCropTop, 54bb, uint",
|
||||
"PixelCropLeft, 54cc, uint",
|
||||
@@ -122,7 +122,7 @@ elements_matroska = (
|
||||
"ColourSpace, 2eb524, binary, length=4",
|
||||
"StereoMode, 53b8, uint",
|
||||
"Colour, 55b0, sub", (
|
||||
"MatrixCoefficients, 55B1, uint",
|
||||
"MatrixCoefficients, 55B1, uint, default=2",
|
||||
"BitsPerChannel, 55B2, uint",
|
||||
"ChromaSubsamplingHorz, 55B3, uint",
|
||||
"ChromaSubsamplingVert, 55B4, uint",
|
||||
@@ -131,8 +131,8 @@ elements_matroska = (
|
||||
"ChromaSitingHorz, 55B7, uint",
|
||||
"ChromaSitingVert, 55B8, uint",
|
||||
"Range, 55B9, uint",
|
||||
"TransferCharacteristics, 55BA, uint",
|
||||
"Primaries, 55BB, uint",
|
||||
"TransferCharacteristics, 55BA, uint, default=2",
|
||||
"Primaries, 55BB, uint, default=2",
|
||||
"MaxCLL, 55BC, uint",
|
||||
"MaxFALL, 55BD, uint",
|
||||
"MasteringMetadata, 55D0, sub", (
|
||||
@@ -157,15 +157,15 @@ elements_matroska = (
|
||||
),
|
||||
),
|
||||
"Audio, e1, sub", (
|
||||
"SamplingFrequency, b5, float",
|
||||
"OutputSamplingFrequency, 78b5, float",
|
||||
"Channels, 9f, uint",
|
||||
"SamplingFrequency, b5, float, default=8000",
|
||||
"OutputSamplingFrequency, 78b5, float, default=context",
|
||||
"Channels, 9f, uint, default=1",
|
||||
"BitDepth, 6264, uint",
|
||||
),
|
||||
"ContentEncodings, 6d80, sub", (
|
||||
"ContentEncoding*, 6240, sub", (
|
||||
"ContentEncodingOrder, 5031, uint",
|
||||
"ContentEncodingScope, 5032, uint",
|
||||
"ContentEncodingScope, 5032, uint, default=1",
|
||||
"ContentEncodingType, 5033, uint",
|
||||
"ContentCompression, 5034, sub", (
|
||||
"ContentCompAlgo, 4254, uint",
|
||||
@@ -215,12 +215,12 @@ elements_matroska = (
|
||||
"ChapterTimeStart, 91, uint",
|
||||
"ChapterTimeEnd, 92, uint",
|
||||
"ChapterFlagHidden, 98, uint",
|
||||
"ChapterFlagEnabled, 4598, uint",
|
||||
"ChapterFlagEnabled, 4598, uint, default=1",
|
||||
"ChapterSegmentUID, 6e67, binary, length=16",
|
||||
"ChapterSegmentEditionUID, 6ebc, uint",
|
||||
"ChapterDisplay*, 80, sub", (
|
||||
"ChapString, 85, str",
|
||||
"ChapLanguage*, 437c, str",
|
||||
"ChapLanguage*, 437c, str, default=eng",
|
||||
"ChapLanguageBCP47*, 437d, str",
|
||||
"ChapCountry*, 437e, str",
|
||||
),
|
||||
@@ -230,7 +230,7 @@ elements_matroska = (
|
||||
"Tags*, 1254c367, sub", (
|
||||
"Tag*, 7373, sub", (
|
||||
"Targets, 63c0, sub", (
|
||||
"TargetTypeValue, 68ca, uint",
|
||||
"TargetTypeValue, 68ca, uint, default=50",
|
||||
"TargetType, 63ca, str",
|
||||
"TargetTrackUID, 63c5, uint",
|
||||
"TargetEditionUID, 63c9, uint",
|
||||
@@ -239,10 +239,10 @@ elements_matroska = (
|
||||
),
|
||||
"SimpleTag*, 67c8, sub", (
|
||||
"TagName, 45a3, str",
|
||||
"TagLanguage, 447a, str",
|
||||
"TagLanguage, 447a, str, default=und",
|
||||
"TagLanguageBCP47, 447b, str",
|
||||
"TagString, 4487, str",
|
||||
"TagDefault, 4484, uint",
|
||||
"TagDefault, 4484, uint, default=1",
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -266,7 +266,8 @@ def camelcase_to_words(name):
|
||||
|
||||
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.definename = f"{namespace}_ID_{name.upper()}"
|
||||
self.fieldname = camelcase_to_words(name)
|
||||
@@ -274,6 +275,7 @@ class MatroskaElement:
|
||||
self.elid = elid
|
||||
self.valtype = valtype
|
||||
self.length = int(length or "0")
|
||||
self.default = default
|
||||
if valtype == "sub":
|
||||
self.ebmltype = "EBML_TYPE_SUBELEMENTS"
|
||||
self.valname = "struct " + self.structname
|
||||
@@ -292,6 +294,21 @@ class MatroskaElement:
|
||||
self.subelements = 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] = {}
|
||||
elementlist: list[MatroskaElement] = []
|
||||
def parse_elems(elements, namespace):
|
||||
@@ -302,7 +319,7 @@ def parse_elems(elements, namespace):
|
||||
attrs = {}
|
||||
for extra in rest:
|
||||
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)
|
||||
attrs[key] = value
|
||||
hexid = hexid.lower()
|
||||
@@ -371,7 +388,7 @@ def generate_c_definitions(out):
|
||||
printf(out, "#undef N")
|
||||
else:
|
||||
printf(out, f'E("{el.name}", {el.fieldname}, {el.ebmltype}, '
|
||||
f'{el.length})')
|
||||
f'{el.length}, {el.default_initializer()})')
|
||||
|
||||
def read(s, 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 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_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},
|
||||
@@ -510,11 +513,13 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
||||
else \
|
||||
subelptr = (fieldtype *) fieldptr
|
||||
GETPTR(uintptr, uint64_t);
|
||||
if (length < 1 || length > 8) {
|
||||
if (length > 8) {
|
||||
MP_ERR(ctx, "uint invalid length %"PRIu64"\n", length);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
|
||||
@@ -547,7 +556,13 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
||||
}
|
||||
char **strptr;
|
||||
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);
|
||||
break;
|
||||
|
||||
@@ -583,6 +598,7 @@ static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target,
|
||||
}
|
||||
*countptr += 1;
|
||||
error:
|
||||
skip:
|
||||
data += length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,13 @@ struct ebml_elem_desc {
|
||||
int size;
|
||||
int field_count;
|
||||
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 {
|
||||
|
||||
Reference in new issue
Block a user