[Matroska] Clear size listeners before adding

Each time save is called registerSizeListener will add
new size listeners. If save is called multiple times this causes the
same delta being add/subtracted multiple times, resulting in incorrect
element sizes.

This can be observed in TestMatroska::testRepeatedSave.
Although the test passes, some sizes are incorrect resulting in the
following messages being printed during the test:

  TagLib: Failed to read VINT size
  TagLib: Failed to parse EMBL ElementID

Signed-off-by: Anthony Brandon <anthony.brandon@gmail.com>
This commit is contained in:
Anthony Brandon
2026-06-24 17:19:46 +02:00
committed by Urs Fleisch
parent e589efd0da
commit 2185b47d5f
3 changed files with 10 additions and 0 deletions

View File

@@ -101,6 +101,11 @@ Matroska::Element::ID Matroska::Element::id() const
return e->id;
}
void Matroska::Element::clearSizeListeners()
{
e->sizeListeners.clear();
}
void Matroska::Element::addSizeListener(Element *element)
{
e->sizeListeners.append(element);

View File

@@ -53,6 +53,7 @@ namespace TagLib {
void setData(const ByteVector &data);
const ByteVector &data() const;
virtual void write(TagLib::File &file);
void clearSizeListeners();
void addSizeListener(Element *element);
void addSizeListeners(const List<Element *> &elements);
bool emitSizeChanged(offset_t delta);

View File

@@ -595,6 +595,7 @@ bool Matroska::File::save(WriteStyle writeStyle)
// Set up listeners, add seek head and segment length to the end
for(auto it = renderList.begin(); it != renderList.end(); ++it) {
(*it)->clearSizeListeners();
for(auto it2 = std::next(it); it2 != renderList.end(); ++it2)
(*it)->addSizeListener(*it2);
if(d->cues)
@@ -605,6 +606,7 @@ bool Matroska::File::save(WriteStyle writeStyle)
}
if(d->cues) {
renderList.append(d->cues.get());
d->cues->clearSizeListeners();
d->cues->addSizeListeners(renderList);
if(d->seekHead) {
d->cues->addSizeListener(d->seekHead.get());
@@ -613,9 +615,11 @@ bool Matroska::File::save(WriteStyle writeStyle)
}
if(d->seekHead) {
renderList.append(d->seekHead.get());
d->seekHead->clearSizeListeners();
d->seekHead->addSizeListeners(renderList);
d->seekHead->addSizeListener(d->segment.get());
}
d->segment->clearSizeListeners();
d->segment->addSizeListeners(renderList);
renderList.append(d->segment.get());