Use "..." to implement subelementByPath

This commit is contained in:
Martchus 2018-03-07 00:16:20 +01:00
parent 88edd43f8c
commit 091fa1daf7
2 changed files with 31 additions and 27 deletions

View File

@ -101,8 +101,8 @@ public:
const ImplementationType* firstChild() const; const ImplementationType* firstChild() const;
ImplementationType* lastChild(); ImplementationType* lastChild();
const ImplementationType* lastChild() const; const ImplementationType* lastChild() const;
ImplementationType* subelementByPath(const std::initializer_list<IdentifierType> &path, Diagnostics &diag); ImplementationType* subelementByPath(Diagnostics &diag, IdentifierType item);
ImplementationType* subelementByPath(std::list<IdentifierType> &path, Diagnostics &diag); ImplementationType* subelementByPath(Diagnostics &diag, IdentifierType item, IdentifierType remainingPath...);
ImplementationType* childById(const IdentifierType &id, Diagnostics &diag); ImplementationType* childById(const IdentifierType &id, Diagnostics &diag);
ImplementationType* siblingById(const IdentifierType &id, Diagnostics &diag, bool includeThis = false); ImplementationType* siblingById(const IdentifierType &id, Diagnostics &diag, bool includeThis = false);
bool isParent() const; bool isParent() const;
@ -522,7 +522,7 @@ inline const ImplementationType *GenericFileElement<ImplementationType>::lastChi
} }
/*! /*!
* \brief Returns the sub element for the specified \a path. * \brief Returns the sub element for the specified path.
* *
* The current element keeps ownership over the returned element. * The current element keeps ownership over the returned element.
* If no element could be found nullptr is returned. * If no element could be found nullptr is returned.
@ -531,41 +531,45 @@ inline const ImplementationType *GenericFileElement<ImplementationType>::lastChi
* \throws Throws std::ios_base::failure when an IO error occurs. * \throws Throws std::ios_base::failure when an IO error occurs.
*/ */
template <class ImplementationType> template <class ImplementationType>
inline ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(const std::initializer_list<IdentifierType> &path, Diagnostics &diag) ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(Diagnostics &diag, IdentifierType item)
{ {
std::list<GenericFileElement<ImplementationType>::IdentifierType> list(path); // ensure element is parsed
return subelementByPath(list, diag); parse(diag);
// return the element if it matches the current and last item in the path
if(item == id()) {
return static_cast<ImplementationType *>(this);
}
// check whether a sibling matches the item
if(nextSibling()) {
return nextSibling()->subelementByPath(diag, item);
}
return nullptr;
} }
/*! /*!
* \brief Returns the sub element for the specified \a path. * \brief Returns the sub element for the specified path.
* *
* The current element keeps ownership over the returned element. * The current element keeps ownership over the returned element.
* If no element could be found nullptr is returned. * If no element could be found nullptr is returned.
* The specified \a path will modified.
* *
* \throws Throws a parsing exception when a parsing error occurs. * \throws Throws a parsing exception when a parsing error occurs.
* \throws Throws std::ios_base::failure when an IO error occurs. * \throws Throws std::ios_base::failure when an IO error occurs.
*/ */
template <class ImplementationType> template <class ImplementationType>
ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(std::list<IdentifierType> &path, Diagnostics &diag) ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(Diagnostics &diag, IdentifierType item, IdentifierType remainingPath...)
{ {
parse(diag); // ensure element is parsed // ensure element is parsed
if(path.size()) { parse(diag);
if(path.front() == id()) { // continue with next item in path if the element matches the current item
if(path.size() == 1) { if(item == id()) {
return static_cast<ImplementationType *>(this); if(!firstChild()) {
} else { return nullptr;
if(firstChild()) {
path.pop_front();
return firstChild()->subelementByPath(path, diag);
}
}
} else {
if(nextSibling()) {
return nextSibling()->subelementByPath(path, diag);
}
} }
return firstChild()->subelementByPath(diag, remainingPath);
}
// check whether a sibling matches the current item
if(nextSibling()) {
return nextSibling()->subelementByPath(diag, item, remainingPath);
} }
return nullptr; return nullptr;
} }

View File

@ -50,7 +50,7 @@ ElementPosition Mp4Container::determineTagPosition(Diagnostics &diag) const
{ {
if(m_firstElement) { if(m_firstElement) {
const Mp4Atom *mediaDataAtom = m_firstElement->siblingById(Mp4AtomIds::MediaData, diag); const Mp4Atom *mediaDataAtom = m_firstElement->siblingById(Mp4AtomIds::MediaData, diag);
const Mp4Atom *userDataAtom = m_firstElement->subelementByPath({Mp4AtomIds::Movie, Mp4AtomIds::UserData}, diag); const Mp4Atom *userDataAtom = m_firstElement->subelementByPath(diag, Mp4AtomIds::Movie, Mp4AtomIds::UserData);
if(mediaDataAtom && userDataAtom) { if(mediaDataAtom && userDataAtom) {
return userDataAtom->startOffset() < mediaDataAtom->startOffset() ? ElementPosition::BeforeData : ElementPosition::AfterData; return userDataAtom->startOffset() < mediaDataAtom->startOffset() ? ElementPosition::BeforeData : ElementPosition::AfterData;
} }
@ -89,7 +89,7 @@ void Mp4Container::internalParseHeader(Diagnostics &diag)
void Mp4Container::internalParseTags(Diagnostics &diag) void Mp4Container::internalParseTags(Diagnostics &diag)
{ {
const string context("parsing tags of MP4 container"); const string context("parsing tags of MP4 container");
if(Mp4Atom *udtaAtom = firstElement()->subelementByPath({Mp4AtomIds::Movie, Mp4AtomIds::UserData}, diag)) { if(Mp4Atom *udtaAtom = firstElement()->subelementByPath(diag, Mp4AtomIds::Movie, Mp4AtomIds::UserData)) {
Mp4Atom *metaAtom = udtaAtom->childById(Mp4AtomIds::Meta, diag); Mp4Atom *metaAtom = udtaAtom->childById(Mp4AtomIds::Meta, diag);
bool surplusMetaAtoms = false; bool surplusMetaAtoms = false;
while(metaAtom) { while(metaAtom) {
@ -153,7 +153,7 @@ void Mp4Container::internalParseTracks(Diagnostics &diag)
diag.emplace_back(DiagLevel::Critical, "mvhd atom is does not exist.", context); diag.emplace_back(DiagLevel::Critical, "mvhd atom is does not exist.", context);
} }
// get mvex atom which holds default values for fragmented files // get mvex atom which holds default values for fragmented files
if(Mp4Atom *mehdAtom = moovAtom->subelementByPath({Mp4AtomIds::MovieExtends, Mp4AtomIds::MovieExtendsHeader}, diag)) { if(Mp4Atom *mehdAtom = moovAtom->subelementByPath(diag, Mp4AtomIds::MovieExtends, Mp4AtomIds::MovieExtendsHeader)) {
m_fragmented = true; m_fragmented = true;
if(mehdAtom->dataSize() > 0) { if(mehdAtom->dataSize() > 0) {
stream().seekg(static_cast<iostream::off_type>(mehdAtom->dataOffset())); stream().seekg(static_cast<iostream::off_type>(mehdAtom->dataOffset()));