Improve siblingById() and subelementByPath()

* Use 2 functions instead of flag parameter
* Support const correctness
This commit is contained in:
Martchus 2018-03-07 00:30:08 +01:00
parent 091fa1daf7
commit efa67d6a1a
4 changed files with 129 additions and 27 deletions

View File

@ -103,8 +103,14 @@ public:
const ImplementationType* lastChild() const;
ImplementationType* subelementByPath(Diagnostics &diag, IdentifierType item);
ImplementationType* subelementByPath(Diagnostics &diag, IdentifierType item, IdentifierType remainingPath...);
const ImplementationType* subelementByPath(Diagnostics &diag, IdentifierType item) const;
const ImplementationType* subelementByPath(Diagnostics &diag, IdentifierType item, IdentifierType remainingPath...) const;
ImplementationType* childById(const IdentifierType &id, Diagnostics &diag);
ImplementationType* siblingById(const IdentifierType &id, Diagnostics &diag, bool includeThis = false);
const ImplementationType* childById(const IdentifierType &id, Diagnostics &diag) const;
ImplementationType* siblingById(const IdentifierType &id, Diagnostics &diag);
const ImplementationType* siblingById(const IdentifierType &id, Diagnostics &diag) const;
ImplementationType* siblingByIdIncludingThis(const IdentifierType &id, Diagnostics &diag);
const ImplementationType* siblingByIdIncludingThis(const IdentifierType &id, Diagnostics &diag) const;
bool isParent() const;
bool isPadding() const;
uint64 firstChildOffset() const;
@ -574,6 +580,36 @@ ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(Dia
return nullptr;
}
/*!
* \brief Returns the sub element for the specified path.
*
* The current element keeps ownership over the returned element.
* If no element could be found nullptr is returned.
*
* \throws Throws a parsing exception when a parsing error occurs.
* \throws Throws std::ios_base::failure when an IO error occurs.
*/
template <class ImplementationType>
const ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(Diagnostics &diag, IdentifierType item) const
{
return const_cast<GenericFileElement<ImplementationType> *>(this)->subelementByPath(diag, item);
}
/*!
* \brief Returns the sub element for the specified path.
*
* The current element keeps ownership over the returned element.
* If no element could be found nullptr is returned.
*
* \throws Throws a parsing exception when a parsing error occurs.
* \throws Throws std::ios_base::failure when an IO error occurs.
*/
template <class ImplementationType>
const ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(Diagnostics &diag, IdentifierType item, IdentifierType remainingPath...) const
{
return const_cast<GenericFileElement<ImplementationType> *>(this)->subelementByPath(diag, item, remainingPath);
}
/*!
* \brief Returns the first child with the specified \a id.
*
@ -597,11 +633,22 @@ ImplementationType *GenericFileElement<ImplementationType>::childById(const Iden
}
/*!
* \brief Returns the first sibling with the specified \a id.
* \brief Returns the first child with the specified \a id.
*
* \param id Specifies the id of the sibling to be returned.
* \param includeThis Indicates whether this instance should be returned
* if it has the specified \a id.
* The current element keeps ownership over the returned element.
* If no element could be found nullptr is returned.
*
* \throws Throws a parsing exception when a parsing error occurs.
* \throws Throws std::ios_base::failure when an IO error occurs.
*/
template <class ImplementationType>
const ImplementationType *GenericFileElement<ImplementationType>::childById(const IdentifierType &id, Diagnostics &diag) const
{
return const_cast<GenericFileElement<ImplementationType> *>(this)->childById(id, diag);
}
/*!
* \brief Returns the first sibling with the specified \a id.
*
* The current element keeps ownership over the returned element.
* If no element could be found nullptr is returned.
@ -611,10 +658,10 @@ ImplementationType *GenericFileElement<ImplementationType>::childById(const Iden
* \throws Throws std::ios_base::failure when an IO error occurs.
*/
template <class ImplementationType>
ImplementationType *GenericFileElement<ImplementationType>::siblingById(const IdentifierType &id, Diagnostics &diag, bool includeThis)
ImplementationType *GenericFileElement<ImplementationType>::siblingById(const IdentifierType &id, Diagnostics &diag)
{
parse(diag); // ensure element is parsed
for(ImplementationType *sibling = includeThis ? static_cast<ImplementationType *>(this) : nextSibling(); sibling; sibling = sibling->nextSibling()) {
for(ImplementationType *sibling = nextSibling(); sibling; sibling = sibling->nextSibling()) {
sibling->parse(diag);
if(sibling->id() == id) {
return sibling;
@ -623,6 +670,61 @@ ImplementationType *GenericFileElement<ImplementationType>::siblingById(const Id
return nullptr;
}
/*!
* \brief Returns the first sibling with the specified \a id.
*
* The current element keeps ownership over the returned element.
* If no element could be found nullptr is returned.
* Possibly returns a pointer to the current instance (see \a includeThis).
*
* \throws Throws a parsing exception when a parsing error occurs.
* \throws Throws std::ios_base::failure when an IO error occurs.
*/
template <class ImplementationType>
const ImplementationType *GenericFileElement<ImplementationType>::siblingById(const IdentifierType &id, Diagnostics &diag) const
{
return const_cast<GenericFileElement<ImplementationType> *>(this)->siblingById(id, diag);
}
/*!
* \brief Returns the first sibling with the specified \a id or the current instance if its ID equals \a id.
*
* The current element keeps ownership over the returned element.
* If no element could be found nullptr is returned.
* Possibly returns a pointer to the current instance (see \a includeThis).
*
* \throws Throws a parsing exception when a parsing error occurs.
* \throws Throws std::ios_base::failure when an IO error occurs.
*/
template <class ImplementationType>
ImplementationType *GenericFileElement<ImplementationType>::siblingByIdIncludingThis(const IdentifierType &id, Diagnostics &diag)
{
parse(diag); // ensure element is parsed
for(ImplementationType *sibling = static_cast<ImplementationType *>(this); sibling; sibling = sibling->nextSibling()) {
sibling->parse(diag);
if(sibling->id() == id) {
return sibling;
}
}
return nullptr;
}
/*!
* \brief Returns the first sibling with the specified \a id or the current instance if its ID equals \a id.
*
* The current element keeps ownership over the returned element.
* If no element could be found nullptr is returned.
* Possibly returns a pointer to the current instance (see \a includeThis).
*
* \throws Throws a parsing exception when a parsing error occurs.
* \throws Throws std::ios_base::failure when an IO error occurs.
*/
template <class ImplementationType>
const ImplementationType *GenericFileElement<ImplementationType>::siblingByIdIncludingThis(const IdentifierType &id, Diagnostics &diag) const
{
return const_cast<GenericFileElement<ImplementationType> *>(this)->siblingByIdIncludingThis(id, diag);
}
/*!
* \brief Returns an indication whether this instance is a parent element.
*/

View File

@ -342,7 +342,7 @@ ElementPosition MatroskaContainer::determineElementPosition(uint64 elementId, Di
if(!m_firstElement || m_segmentCount != 1) {
return ElementPosition::Keep;
}
const auto *const segmentElement = m_firstElement->siblingById(MatroskaIds::Segment, diag, true);
const auto *const segmentElement = m_firstElement->siblingByIdIncludingThis(MatroskaIds::Segment, diag);
if(!segmentElement) {
return ElementPosition::Keep;
}

View File

@ -75,7 +75,7 @@ void Mp4Container::internalParseHeader(Diagnostics &diag)
//const string context("parsing header of MP4 container"); will be used when generating notifications
m_firstElement = make_unique<Mp4Atom>(*this, startOffset());
m_firstElement->parse(diag);
Mp4Atom *ftypAtom = m_firstElement->siblingById(Mp4AtomIds::FileType, diag, true);
Mp4Atom *ftypAtom = m_firstElement->siblingByIdIncludingThis(Mp4AtomIds::FileType, diag);
if(ftypAtom) {
stream().seekg(static_cast<iostream::off_type>(ftypAtom->dataOffset()));
m_doctype = reader().readString(4);
@ -100,7 +100,7 @@ void Mp4Container::internalParseTags(Diagnostics &diag)
} catch(const NoDataFoundException &) {
m_tags.pop_back();
}
metaAtom = metaAtom->siblingById(Mp4AtomIds::Meta, diag, false);
metaAtom = metaAtom->siblingById(Mp4AtomIds::Meta, diag);
if(metaAtom) {
surplusMetaAtoms = true;
}
@ -119,7 +119,7 @@ void Mp4Container::internalParseTracks(Diagnostics &diag)
static const string context("parsing tracks of MP4 container");
try {
// get moov atom which holds track information
if(Mp4Atom *moovAtom = firstElement()->siblingById(Mp4AtomIds::Movie, diag, true)) {
if(Mp4Atom *moovAtom = firstElement()->siblingByIdIncludingThis(Mp4AtomIds::Movie, diag)) {
// get mvhd atom which holds overall track information
if(Mp4Atom *mvhdAtom = moovAtom->childById(Mp4AtomIds::MovieHeader, diag)) {
if(mvhdAtom->dataSize() > 0) {
@ -191,7 +191,7 @@ void Mp4Container::internalParseTracks(Diagnostics &diag)
} catch(const Failure &) {
diag.emplace_back(DiagLevel::Critical, argsToString("Unable to parse track ", trackNum, '.'), context);
}
trakAtom = trakAtom->siblingById(Mp4AtomIds::Track, diag, false); // get next trak atom
trakAtom = trakAtom->siblingById(Mp4AtomIds::Track, diag); // get next trak atom
++trackNum;
}
// get overall duration, creation time and modification time if not determined yet
@ -263,7 +263,7 @@ void Mp4Container::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
Mp4Atom *level0Atom, *level1Atom, *level2Atom, *lastAtomToBeWritten;
try {
// file type atom (mandatory)
if((fileTypeAtom = firstElement()->siblingById(Mp4AtomIds::FileType, diag, true))) {
if((fileTypeAtom = firstElement()->siblingByIdIncludingThis(Mp4AtomIds::FileType, diag))) {
// buffer atom
fileTypeAtom->makeBuffer();
} else {
@ -273,13 +273,13 @@ void Mp4Container::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
}
// progressive download information atom (not mandatory)
if((progressiveDownloadInfoAtom = firstElement()->siblingById(Mp4AtomIds::ProgressiveDownloadInformation, diag, true))) {
if((progressiveDownloadInfoAtom = firstElement()->siblingByIdIncludingThis(Mp4AtomIds::ProgressiveDownloadInformation, diag))) {
// buffer atom
progressiveDownloadInfoAtom->makeBuffer();
}
// movie atom (mandatory)
if(!(movieAtom = firstElement()->siblingById(Mp4AtomIds::Movie, diag, true))) {
if(!(movieAtom = firstElement()->siblingByIdIncludingThis(Mp4AtomIds::Movie, diag))) {
// throw error if missing
diag.emplace_back(DiagLevel::Critical, "Mandatory \"moov\"-atom not in the source file found.", context);
throw InvalidDataException();
@ -868,16 +868,16 @@ void Mp4Container::updateOffsets(const std::vector<int64> &oldMdatOffsets, const
}
// update "base-data-offset-present" of "tfhd"-atom (NOT tested properly)
try {
for(Mp4Atom *moofAtom = firstElement()->siblingById(Mp4AtomIds::MovieFragment, diag, false);
moofAtom; moofAtom = moofAtom->siblingById(Mp4AtomIds::MovieFragment, diag, false)) {
for(Mp4Atom *moofAtom = firstElement()->siblingById(Mp4AtomIds::MovieFragment, diag);
moofAtom; moofAtom = moofAtom->siblingById(Mp4AtomIds::MovieFragment, diag)) {
moofAtom->parse(diag);
try {
for(Mp4Atom *trafAtom = moofAtom->childById(Mp4AtomIds::TrackFragment, diag); trafAtom;
trafAtom = trafAtom->siblingById(Mp4AtomIds::TrackFragment, diag, false)) {
trafAtom = trafAtom->siblingById(Mp4AtomIds::TrackFragment, diag)) {
trafAtom->parse(diag);
int tfhdAtomCount = 0;
for(Mp4Atom *tfhdAtom = trafAtom->childById(Mp4AtomIds::TrackFragmentHeader, diag); tfhdAtom;
tfhdAtom = tfhdAtom->siblingById(Mp4AtomIds::TrackFragmentHeader, diag, false)) {
tfhdAtom = tfhdAtom->siblingById(Mp4AtomIds::TrackFragmentHeader, diag)) {
tfhdAtom->parse(diag);
++tfhdAtomCount;
if(tfhdAtom->dataSize() >= 8) {

View File

@ -214,11 +214,11 @@ std::vector<uint64> Mp4Track::readChunkOffsets(bool parseFragments, Diagnostics
// read sample offsets of fragments
if(parseFragments) {
uint64 totalDuration = 0;
for(Mp4Atom *moofAtom = m_trakAtom->container().firstElement()->siblingById(Mp4AtomIds::MovieFragment, diag, true); moofAtom; moofAtom = moofAtom->siblingById(Mp4AtomIds::MovieFragment, diag, false)) {
for(Mp4Atom *moofAtom = m_trakAtom->container().firstElement()->siblingByIdIncludingThis(Mp4AtomIds::MovieFragment, diag); moofAtom; moofAtom = moofAtom->siblingById(Mp4AtomIds::MovieFragment, diag)) {
moofAtom->parse(diag);
for(Mp4Atom *trafAtom = moofAtom->childById(Mp4AtomIds::TrackFragment, diag); trafAtom; trafAtom = trafAtom->siblingById(Mp4AtomIds::TrackFragment, diag, false)) {
for(Mp4Atom *trafAtom = moofAtom->childById(Mp4AtomIds::TrackFragment, diag); trafAtom; trafAtom = trafAtom->siblingById(Mp4AtomIds::TrackFragment, diag)) {
trafAtom->parse(diag);
for(Mp4Atom *tfhdAtom = trafAtom->childById(Mp4AtomIds::TrackFragmentHeader, diag); tfhdAtom; tfhdAtom = tfhdAtom->siblingById(Mp4AtomIds::TrackFragmentHeader, diag, false)) {
for(Mp4Atom *tfhdAtom = trafAtom->childById(Mp4AtomIds::TrackFragmentHeader, diag); tfhdAtom; tfhdAtom = tfhdAtom->siblingById(Mp4AtomIds::TrackFragmentHeader, diag)) {
tfhdAtom->parse(diag);
uint32 calculatedDataSize = 0;
if(tfhdAtom->dataSize() < calculatedDataSize) {
@ -271,7 +271,7 @@ std::vector<uint64> Mp4Track::readChunkOffsets(bool parseFragments, Diagnostics
inputStream().seekg(4, ios_base::cur);
}
}
for(Mp4Atom *trunAtom = trafAtom->childById(Mp4AtomIds::TrackFragmentRun, diag); trunAtom; trunAtom = trunAtom->siblingById(Mp4AtomIds::TrackFragmentRun, diag, false)) {
for(Mp4Atom *trunAtom = trafAtom->childById(Mp4AtomIds::TrackFragmentRun, diag); trunAtom; trunAtom = trunAtom->siblingById(Mp4AtomIds::TrackFragmentRun, diag)) {
uint32 calculatedDataSize = 8;
if(trunAtom->dataSize() < calculatedDataSize) {
diag.emplace_back(DiagLevel::Critical, "trun atom is truncated.", context);
@ -1786,11 +1786,11 @@ void Mp4Track::internalParseHeader(Diagnostics &diag)
// no sample sizes found, search for trun atoms
uint64 totalDuration = 0;
for(Mp4Atom *moofAtom = m_trakAtom->container().firstElement()->siblingById(MovieFragment, diag, true); moofAtom; moofAtom = moofAtom->siblingById(MovieFragment, diag, false)) {
for(Mp4Atom *moofAtom = m_trakAtom->container().firstElement()->siblingByIdIncludingThis(MovieFragment, diag); moofAtom; moofAtom = moofAtom->siblingById(MovieFragment, diag)) {
moofAtom->parse(diag);
for(Mp4Atom *trafAtom = moofAtom->childById(TrackFragment, diag); trafAtom; trafAtom = trafAtom->siblingById(TrackFragment, diag, false)) {
for(Mp4Atom *trafAtom = moofAtom->childById(TrackFragment, diag); trafAtom; trafAtom = trafAtom->siblingById(TrackFragment, diag)) {
trafAtom->parse(diag);
for(Mp4Atom *tfhdAtom = trafAtom->childById(TrackFragmentHeader, diag); tfhdAtom; tfhdAtom = tfhdAtom->siblingById(TrackFragmentHeader, diag, false)) {
for(Mp4Atom *tfhdAtom = trafAtom->childById(TrackFragmentHeader, diag); tfhdAtom; tfhdAtom = tfhdAtom->siblingById(TrackFragmentHeader, diag)) {
tfhdAtom->parse(diag);
uint32 calculatedDataSize = 0;
if(tfhdAtom->dataSize() < calculatedDataSize) {
@ -1842,7 +1842,7 @@ void Mp4Track::internalParseHeader(Diagnostics &diag)
m_istream->seekg(4, ios_base::cur);
}
}
for(Mp4Atom *trunAtom = trafAtom->childById(TrackFragmentRun, diag); trunAtom; trunAtom = trunAtom->siblingById(TrackFragmentRun, diag, false)) {
for(Mp4Atom *trunAtom = trafAtom->childById(TrackFragmentRun, diag); trunAtom; trunAtom = trunAtom->siblingById(TrackFragmentRun, diag)) {
uint32 calculatedDataSize = 8;
if(trunAtom->dataSize() < calculatedDataSize) {
diag.emplace_back(DiagLevel::Critical, "trun atom is truncated.", context);