Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework EbmlVoid internals #255

Merged
merged 13 commits into from
Feb 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 43 additions & 23 deletions src/EbmlVoid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,44 @@ filepos_t EbmlVoid::RenderData(IOCallback & output, bool /* bForceRender */, con
return GetSize();
}

// compute the size of the voided data based on the original one
static void SetVoidSize(EbmlVoid & Elt, const std::uint64_t FullSize)
{
// compute the size of the voided data based on the original one
// We don't know the Size length, assume it's the smallest one = 1
// and compute the optimum Size length
const unsigned int InitialSizeLength = CodedSizeLength(FullSize - EBML_ID_LENGTH(Id_EbmlVoid) - 1, 0);
std::uint64_t NewDataLength = FullSize - InitialSizeLength - EBML_ID_LENGTH(Id_EbmlVoid);
unsigned int NewSizeLength = CodedSizeLength(NewDataLength, 0);
if (EBML_ID_LENGTH(Id_EbmlVoid) + NewSizeLength + NewDataLength < FullSize)
{
// the computed size is too small,
// the Size length can be expanded, update the size Length which doesn't imply
// recomputing the whole size again
NewSizeLength = static_cast<decltype(NewSizeLength)>(FullSize - (NewDataLength + EBML_ID_LENGTH(Id_EbmlVoid)));
}
else if (EBML_ID_LENGTH(Id_EbmlVoid) + NewSizeLength + NewDataLength > FullSize)
{
// the computed size is too large, reduce it and keep the same Size length
NewDataLength = FullSize - (NewSizeLength + EBML_ID_LENGTH(Id_EbmlVoid));
}
Elt.SetSizeLength(NewSizeLength);
Elt.SetSize(NewDataLength);
}

std::uint64_t EbmlVoid::ReplaceWith(EbmlElement & EltToReplaceWith, IOCallback & output, bool ComeBackAfterward, const ShouldWrite& writeFilter)
{
EltToReplaceWith.UpdateSize(writeFilter);
if (HeadSize() + GetSize() < EltToReplaceWith.GetSize() + EltToReplaceWith.HeadSize()) {
const auto EltSize = EltToReplaceWith.ElementSize(writeFilter);
if (EltSize == 0)
return INVALID_FILEPOS_T;
const auto CurrentVoidSize = ElementSize(writeFilter);
if (CurrentVoidSize < EltSize) {
// the element can't be written here !
return INVALID_FILEPOS_T;
}
if (HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() == 1) {
const auto NewVoidSize = CurrentVoidSize - EltSize;
if (NewVoidSize == EBML_ID_LENGTH(Id_EbmlVoid)) {
// there is not enough space to put a filling element
return INVALID_FILEPOS_T;
}
Expand All @@ -51,24 +81,18 @@ std::uint64_t EbmlVoid::ReplaceWith(EbmlElement & EltToReplaceWith, IOCallback &
output.setFilePointer(GetElementPosition());
EltToReplaceWith.Render(output, writeFilter);

if (HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() > 1) {
if (NewVoidSize != 0) {
// fill the rest with another void element
EbmlVoid aTmp;
aTmp.SetSize_(HeadSize() + GetSize() - EltToReplaceWith.GetSize() - EltToReplaceWith.HeadSize() - 1); // 1 is the length of the Void ID
const std::size_t HeadBefore = aTmp.HeadSize();
aTmp.SetSize_(aTmp.GetSize() - CodedSizeLength(aTmp.GetSize(), aTmp.GetSizeLength()));
const std::size_t HeadAfter = aTmp.HeadSize();
if (HeadBefore != HeadAfter) {
aTmp.SetSizeLength(CodedSizeLength(aTmp.GetSize(), aTmp.GetSizeLength()) - (HeadAfter - HeadBefore));
}
SetVoidSize(aTmp, NewVoidSize);
aTmp.RenderHead(output, false, writeFilter); // the rest of the data is not rewritten
}

if (ComeBackAfterward) {
output.setFilePointer(CurrentPosition);
}

return GetSize() + HeadSize();
return NewVoidSize;
}

std::uint64_t EbmlVoid::Overwrite(const EbmlElement & EltToVoid, IOCallback & output, bool ComeBackAfterward, const ShouldWrite& writeFilter)
Expand All @@ -78,25 +102,21 @@ std::uint64_t EbmlVoid::Overwrite(const EbmlElement & EltToVoid, IOCallback & ou
// this element has never been written
return 0;
}
if (EltToVoid.GetSize() + EltToVoid.HeadSize() <2) {
const auto EltSize = EltToVoid.ElementSize([](const EbmlElement&){ return true; });
if (EltSize <2) {
// the element can't be written here !
return 0;
}
if (!CanWrite(writeFilter)) {
// Void is filtered out, we can't write it
return 0;
}

const std::uint64_t CurrentPosition = output.getFilePointer();

output.setFilePointer(EltToVoid.GetElementPosition());

// compute the size of the voided data based on the original one
SetSize(EltToVoid.GetSize() + EltToVoid.HeadSize() - 1); // 1 for the ID
SetSize(GetSize() - CodedSizeLength(GetSize(), GetSizeLength()));
// make sure we handle even the strange cases
//std::uint32_t A1 = GetSize() + HeadSize();
//std::uint32_t A2 = EltToVoid.GetSize() + EltToVoid.HeadSize();
if (GetSize() + HeadSize() != EltToVoid.GetSize() + EltToVoid.HeadSize()) {
SetSize(GetSize()-1);
SetSizeLength(CodedSizeLength(GetSize(), GetSizeLength()) + 1);
}
SetVoidSize(*this, EltSize);

if (GetSize() != 0) {
RenderHead(output, false, writeFilter); // the rest of the data is not rewritten
Expand All @@ -106,7 +126,7 @@ std::uint64_t EbmlVoid::Overwrite(const EbmlElement & EltToVoid, IOCallback & ou
output.setFilePointer(CurrentPosition);
}

return EltToVoid.GetSize() + EltToVoid.HeadSize();
return EltSize;
}

} // namespace libebml