Skip to content

Commit

Permalink
Use a callback to select which elements should be written
Browse files Browse the repository at this point in the history
This is more flexible than a flag that applies to all the elements inside a Master.
It can now be filtered by element, based on their ID, position, profile, etc.

A EBML_WRITE_FILTER define is added to be able to check libmatroska 2.0
with this feature or not.
  • Loading branch information
robUx4 committed Dec 19, 2023
1 parent 88667af commit ae7381a
Show file tree
Hide file tree
Showing 22 changed files with 98 additions and 81 deletions.
4 changes: 2 additions & 2 deletions ebml/EbmlBinary.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ class EBML_DLL_API EbmlBinary : public EbmlElement {

bool ValidateSize() const override {return IsFiniteSize() && GetSize() < 0x7FFFFFFF;} // we don't mind about what's inside

filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) override;
filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) override;
filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA) override;
filepos_t UpdateSize(bool bWithDefault = false, bool bForceRender = false) override;
filepos_t UpdateSize(ShouldWrite writeFilter = WriteSkipDefault, bool bForceRender = false) override;

void SetBuffer(const binary *Buffer, const std::uint32_t BufferSize) {
Data = const_cast<binary *>(Buffer);
Expand Down
4 changes: 2 additions & 2 deletions ebml/EbmlCrc32.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ namespace libebml {
DECLARE_EBML_BINARY(EbmlCrc32)
public:
bool ValidateSize() const override {return IsFiniteSize() && (GetSize() == 4);}
filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) override;
filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) override;
filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA) override;
// filepos_t UpdateSize(bool bWithDefault = false);
// filepos_t UpdateSize(ShouldWrite writeFilter = WriteSkipDefault);

bool IsDefaultValue() const override {
return false;
Expand Down
4 changes: 2 additions & 2 deletions ebml/EbmlDate.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class EBML_DLL_API EbmlDate : public EbmlElement {
/*!
\note no Default date handled
*/
filepos_t UpdateSize(bool /* bWithDefault = false */, bool /* bForceRender = false */) override {
filepos_t UpdateSize(ShouldWrite /* writeFilter */, bool /* bForceRender = false */) override {
if(!ValueIsSet())
SetSize_(0);
else
Expand All @@ -57,7 +57,7 @@ class EBML_DLL_API EbmlDate : public EbmlElement {
}

private:
filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) override;
filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) override;

std::int64_t myDate{0}; ///< internal format of the date

Expand Down
29 changes: 23 additions & 6 deletions ebml/EbmlElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,21 @@ class EBML_DLL_API EbmlSemanticContext {
*/
class EBML_DLL_API EbmlElement {
public:
// callback to tell if the element should be written or not
// \return true if the element should be written
using ShouldWrite = bool (*)(const EbmlElement &);

// write only elements that don't have their default value set
static bool WriteSkipDefault(const EbmlElement &elt) {
if (elt.IsDefaultValue())
return false;
return true;
}

static bool WriteAll(const EbmlElement &elt) {
return true;
}

explicit EbmlElement(std::uint64_t aDefaultSize, bool bValueSet = false);
virtual ~EbmlElement() = default;
EbmlElement& operator=(const EbmlElement&) = delete;
Expand Down Expand Up @@ -319,11 +334,11 @@ class EBML_DLL_API EbmlElement {
return ElementPosition;
}

std::uint64_t ElementSize(bool bWithDefault = false) const; /// return the size of the header+data, before writing
std::uint64_t ElementSize(ShouldWrite writeFilter = WriteSkipDefault) const; /// return the size of the header+data, before writing

filepos_t Render(IOCallback & output, bool bWithDefault = false, bool bKeepPosition = false, bool bForceRender = false);
filepos_t Render(IOCallback & output, ShouldWrite writeFilter = WriteSkipDefault, bool bKeepPosition = false, bool bForceRender = false);

virtual filepos_t UpdateSize(bool bWithDefault = false, bool bForceRender = false) = 0; /// update the Size of the Data stored
virtual filepos_t UpdateSize(ShouldWrite writeFilter = WriteSkipDefault, bool bForceRender = false) = 0; /// update the Size of the Data stored
virtual filepos_t GetSize() const {return Size;} /// return the size of the data stored in the element, on reading

virtual filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA) = 0;
Expand Down Expand Up @@ -354,7 +369,7 @@ class EBML_DLL_API EbmlElement {
/*!
\brief void the content of the element (replace by EbmlVoid)
*/
std::uint64_t VoidMe(IOCallback & output, bool bWithDefault = false) const;
std::uint64_t VoidMe(IOCallback & output, ShouldWrite writeFilter = WriteSkipDefault) const;

bool DefaultISset() const {return DefaultIsSet;}
void ForceNoDefault() {SetDefaultIsSet(false);}
Expand All @@ -380,13 +395,13 @@ class EBML_DLL_API EbmlElement {
*/
static EbmlElement *CreateElementUsingContext(const EbmlId & aID, const EbmlSemanticContext & Context, int & LowLevel, bool IsGlobalContext, bool bAllowDummy = false, unsigned int MaxLowerLevel = 1);

filepos_t RenderHead(IOCallback & output, bool bForceRender, bool bWithDefault = false, bool bKeepPosition = false);
filepos_t RenderHead(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault, bool bKeepPosition = false);
filepos_t MakeRenderHead(IOCallback & output, bool bKeepPosition);

/*!
\brief prepare the data before writing them (in case it's not already done by default)
*/
virtual filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) = 0;
virtual filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) = 0;

/*!
\brief special constructor for cloning
Expand All @@ -413,4 +428,6 @@ class EBML_DLL_API EbmlElement {

} // namespace libebml

#define EBML_WRITE_FILTER 1

#endif // LIBEBML_ELEMENT_H
4 changes: 2 additions & 2 deletions ebml/EbmlFloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ class EBML_DLL_API EbmlFloat : public EbmlElement {
return (GetSize() == 4 || GetSize() == 8);
}

filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) override;
filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) override;
filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA) override;
filepos_t UpdateSize(bool bWithDefault = false, bool bForceRender = false) override;
filepos_t UpdateSize(ShouldWrite writeFilter = WriteSkipDefault, bool bForceRender = false) override;

void SetPrecision(const EbmlFloat::Precision prec = FLOAT_32)
{
Expand Down
6 changes: 3 additions & 3 deletions ebml/EbmlMaster.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ class EBML_DLL_API EbmlMaster : public EbmlElement {
*/
~EbmlMaster() override;

filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) override;
filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) override;
filepos_t ReadData(IOCallback & input, ScopeMode ReadFully) override;
filepos_t UpdateSize(bool bWithDefault = false, bool bForceRender = false) override;
filepos_t UpdateSize(ShouldWrite writeFilter = WriteSkipDefault, bool bForceRender = false) override;

/*!
\brief Set wether the size is finite (size is known in advance when writing, or infinite size is not known on writing)
Expand Down Expand Up @@ -134,7 +134,7 @@ class EBML_DLL_API EbmlMaster : public EbmlElement {
/*!
\brief facility for Master elements to write only the head and force the size later
*/
filepos_t WriteHead(IOCallback & output, int SizeLength, bool bWithDefault = false);
filepos_t WriteHead(IOCallback & output, int SizeLength, ShouldWrite writeFilter = WriteSkipDefault);

void EnableChecksum(bool bIsEnabled = true) { bChecksumUsed = bIsEnabled; }
bool HasChecksum() const {return bChecksumUsed;}
Expand Down
4 changes: 2 additions & 2 deletions ebml/EbmlSInteger.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ class EBML_DLL_API EbmlSInteger : public EbmlElement {
void SetDefaultSize(std::uint64_t nDefaultSize = DEFAULT_INT_SIZE) override {EbmlElement::SetDefaultSize(nDefaultSize); SetSize_(nDefaultSize);}

bool ValidateSize() const override {return IsFiniteSize() && (GetSize() <= 8);}
filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) override;
filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) override;
filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA) override;
filepos_t UpdateSize(bool bWithDefault = false, bool bForceRender = false) override;
filepos_t UpdateSize(ShouldWrite writeFilter = WriteSkipDefault, bool bForceRender = false) override;

bool IsSmallerThan(const EbmlElement *Cmp) const override;

Expand Down
4 changes: 2 additions & 2 deletions ebml/EbmlString.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ class EBML_DLL_API EbmlString : public EbmlElement {
explicit EbmlString(const std::string & aDefaultValue);

bool ValidateSize() const override {return IsFiniteSize() && GetSize() < 0x7FFFFFFF;} // any size is possible
filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) override;
filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) override;
filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA) override;
filepos_t UpdateSize(bool bWithDefault = false, bool bForceRender = false) override;
filepos_t UpdateSize(ShouldWrite writeFilter = WriteSkipDefault, bool bForceRender = false) override;

EbmlString & operator=(const std::string &);
using EbmlElement::operator const EbmlId &;
Expand Down
4 changes: 2 additions & 2 deletions ebml/EbmlUInteger.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ class EBML_DLL_API EbmlUInteger : public EbmlElement {
void SetDefaultSize(std::uint64_t nDefaultSize = DEFAULT_UINT_SIZE) override {EbmlElement::SetDefaultSize(nDefaultSize); SetSize_(nDefaultSize);}

bool ValidateSize() const override {return IsFiniteSize() && (GetSize() <= 8);}
filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) override;
filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) override;
filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA) override;
filepos_t UpdateSize(bool bWithDefault = false, bool bForceRender = false) override;
filepos_t UpdateSize(ShouldWrite writeFilter = WriteSkipDefault, bool bForceRender = false) override;

bool IsSmallerThan(const EbmlElement *Cmp) const override;

Expand Down
4 changes: 2 additions & 2 deletions ebml/EbmlUnicodeString.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ class EBML_DLL_API EbmlUnicodeString : public EbmlElement {
explicit EbmlUnicodeString(const UTFstring & DefaultValue);

bool ValidateSize() const override {return IsFiniteSize();} // any size is possible
filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) override;
filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) override;
filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA) override;
filepos_t UpdateSize(bool bWithDefault = false, bool bForceRender = false) override;
filepos_t UpdateSize(ShouldWrite writeFilter = WriteSkipDefault, bool bForceRender = false) override;

EbmlUnicodeString & operator=(const UTFstring &); ///< platform dependant code
using EbmlElement::operator const EbmlId &;
Expand Down
6 changes: 3 additions & 3 deletions ebml/EbmlVoid.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@ DECLARE_EBML_BINARY(EbmlVoid)
/*!
\note overwrite to write fake data
*/
filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false) override;
filepos_t RenderData(IOCallback & output, bool bForceRender, ShouldWrite writeFilter = WriteSkipDefault) override;

/*!
\brief Replace the void element content (written) with this one
*/
std::uint64_t ReplaceWith(EbmlElement & EltToReplaceWith, IOCallback & output, bool ComeBackAfterward = true, bool bWithDefault = false);
std::uint64_t ReplaceWith(EbmlElement & EltToReplaceWith, IOCallback & output, bool ComeBackAfterward = true, ShouldWrite writeFilter = WriteSkipDefault);

/*!
\brief Void the content of an element
*/
std::uint64_t Overwrite(const EbmlElement & EltToVoid, IOCallback & output, bool ComeBackAfterward = true, bool bWithDefault = false);
std::uint64_t Overwrite(const EbmlElement & EltToVoid, IOCallback & output, bool ComeBackAfterward = true, ShouldWrite writeFilter = WriteSkipDefault);

EBML_CONCRETE_CLASS(EbmlVoid)
};
Expand Down
4 changes: 2 additions & 2 deletions src/EbmlBinary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ EbmlBinary::~EbmlBinary() {
EbmlBinary::operator const binary &() const {return *Data;}


filepos_t EbmlBinary::RenderData(IOCallback & output, bool /* bForceRender */, bool /* bWithDefault */)
filepos_t EbmlBinary::RenderData(IOCallback & output, bool /* bForceRender */, ShouldWrite /* writeFilter */)
{
output.writeFully(Data,GetSize());

Expand All @@ -60,7 +60,7 @@ filepos_t EbmlBinary::RenderData(IOCallback & output, bool /* bForceRender */, b
/*!
\note no Default binary value handled
*/
std::uint64_t EbmlBinary::UpdateSize(bool /* bWithDefault */, bool /* bForceRender */)
std::uint64_t EbmlBinary::UpdateSize(ShouldWrite /* writeFilter */, bool /* bForceRender */)
{
return GetSize();
}
Expand Down
4 changes: 2 additions & 2 deletions src/EbmlCrc32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ void EbmlCrc32::AddElementCRC32(EbmlElement &ElementToCRC)
{
// Use a special IOCallback class that Render's to memory instead of to disk
MemIOCallback memoryBuffer;
ElementToCRC.Render(memoryBuffer, true, true);
ElementToCRC.Render(memoryBuffer, WriteAll, true);

const std::uint64_t memSize = memoryBuffer.GetDataBufferSize();
if (memSize > std::numeric_limits<std::uint32_t>::max())
Expand All @@ -181,7 +181,7 @@ bool EbmlCrc32::CheckElementCRC32(EbmlElement &ElementToCRC) const
return CheckCRC(m_crc_final, memoryBuffer.GetDataBuffer(), static_cast<std::uint32_t>(memSize));
}

filepos_t EbmlCrc32::RenderData(IOCallback & output, bool /* bForceRender */, bool /* bWithDefault */)
filepos_t EbmlCrc32::RenderData(IOCallback & output, bool /* bForceRender */, ShouldWrite /* writeFilter */)
{
filepos_t Result = 4;

Expand Down
2 changes: 1 addition & 1 deletion src/EbmlDate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ filepos_t EbmlDate::ReadData(IOCallback & input, ScopeMode ReadFully)
return GetSize();
}

filepos_t EbmlDate::RenderData(IOCallback & output, bool /* bForceRender */, bool /* bWithDefault */)
filepos_t EbmlDate::RenderData(IOCallback & output, bool /* bForceRender */, ShouldWrite /* writeFilter */)
{
assert(GetSize() == 8 || GetSize() == 0);
if (GetSize() == 8) {
Expand Down
26 changes: 13 additions & 13 deletions src/EbmlElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,18 +474,18 @@ EbmlElement *EbmlElement::CreateElementUsingContext(const EbmlId & aID, const Eb
/*!
\todo verify that the size written is the same as the data written
*/
filepos_t EbmlElement::Render(IOCallback & output, bool bWithDefault, bool bKeepPosition, bool bForceRender)
filepos_t EbmlElement::Render(IOCallback & output, ShouldWrite writeFilter, bool bKeepPosition, bool bForceRender)
{
assert(bValueIsSet || (bWithDefault && DefaultISset())); // an element is been rendered without a value set !!!
assert(bValueIsSet || writeFilter(*this)); // an element is been rendered without a value set !!!
// it may be a mandatory element without a default value
if (!bWithDefault && IsDefaultValue()) {
if (!writeFilter(*this)) {
return 0;
}
#if !defined(NDEBUG)
std::uint64_t SupposedSize = UpdateSize(bWithDefault, bForceRender);
std::uint64_t SupposedSize = UpdateSize(writeFilter, bForceRender);
#endif // !NDEBUG
filepos_t result = RenderHead(output, bForceRender, bWithDefault, bKeepPosition);
const std::uint64_t WrittenSize = RenderData(output, bForceRender, bWithDefault);
filepos_t result = RenderHead(output, bForceRender, writeFilter, bKeepPosition);
const std::uint64_t WrittenSize = RenderData(output, bForceRender, writeFilter);
#if !defined(NDEBUG)
if (static_cast<std::int64_t>(SupposedSize) != (0-1))
assert(WrittenSize == SupposedSize);
Expand All @@ -499,12 +499,12 @@ filepos_t EbmlElement::Render(IOCallback & output, bool bWithDefault, bool bKeep
\todo handle exceptions on errors
\todo handle CodeSize bigger than 5 bytes
*/
filepos_t EbmlElement::RenderHead(IOCallback & output, bool bForceRender, bool bWithDefault, bool bKeepPosition)
filepos_t EbmlElement::RenderHead(IOCallback & output, bool bForceRender, ShouldWrite writeFilter, bool bKeepPosition)
{
if (EBML_ID_LENGTH((const EbmlId&)*this) <= 0 || EBML_ID_LENGTH((const EbmlId&)*this) > 4)
return 0;

UpdateSize(bWithDefault, bForceRender);
UpdateSize(writeFilter, bForceRender);

return MakeRenderHead(output, bKeepPosition);
}
Expand All @@ -530,9 +530,9 @@ filepos_t EbmlElement::MakeRenderHead(IOCallback & output, bool bKeepPosition)
return FinalHeadSize;
}

std::uint64_t EbmlElement::ElementSize(bool bWithDefault) const
std::uint64_t EbmlElement::ElementSize(ShouldWrite writeFilter) const
{
if (!bWithDefault && IsDefaultValue())
if (!writeFilter(*this))
return 0; // won't be saved
return Size + EBML_ID_LENGTH((const EbmlId&)*this) + CodedSizeLength(Size, SizeLength, bSizeIsFinite);
}
Expand Down Expand Up @@ -601,21 +601,21 @@ filepos_t EbmlElement::OverwriteData(IOCallback & output, bool bKeepPosition)

auto CurrentPosition = output.getFilePointer();
output.setFilePointer(GetElementPosition() + HeaderSize);
auto Result = RenderData(output, true, bKeepPosition);
auto Result = RenderData(output, true, bKeepPosition ? WriteAll : WriteSkipDefault);
output.setFilePointer(CurrentPosition);
assert(Result == DataSize);
return Result;
}


std::uint64_t EbmlElement::VoidMe(IOCallback & output, bool bWithDefault) const
std::uint64_t EbmlElement::VoidMe(IOCallback & output, ShouldWrite writeFilter) const
{
if (ElementPosition == 0) {
return 0; // the element has not been written
}

EbmlVoid Dummy;
return Dummy.Overwrite(*this, output, true, bWithDefault);
return Dummy.Overwrite(*this, output, true, writeFilter);
}

} // namespace libebml
6 changes: 3 additions & 3 deletions src/EbmlFloat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ EbmlFloat & EbmlFloat::SetValue(double NewValue) {
\todo handle exception on errors
\todo handle 10 bits precision
*/
filepos_t EbmlFloat::RenderData(IOCallback & output, bool /* bForceRender */, bool /* bWithDefault */)
filepos_t EbmlFloat::RenderData(IOCallback & output, bool /* bForceRender */, ShouldWrite /* writeFilter */)
{
assert(GetSize() == 4 || GetSize() == 8);

Expand All @@ -74,9 +74,9 @@ filepos_t EbmlFloat::RenderData(IOCallback & output, bool /* bForceRender */, bo
return GetSize();
}

std::uint64_t EbmlFloat::UpdateSize(bool bWithDefault, bool /* bForceRender */)
std::uint64_t EbmlFloat::UpdateSize(ShouldWrite writeFilter, bool /* bForceRender */)
{
if (!bWithDefault && IsDefaultValue())
if (!writeFilter(*this))
return 0;
return GetSize();
}
Expand Down
Loading

0 comments on commit ae7381a

Please sign in to comment.