2018-03-06 23:09:15 +01:00
|
|
|
#ifndef TAG_PARSER_GENERICFILEELEMENT_H
|
|
|
|
#define TAG_PARSER_GENERICFILEELEMENT_H
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-09-06 19:57:33 +02:00
|
|
|
#include "./exceptions.h"
|
2018-03-07 01:17:50 +01:00
|
|
|
#include "./progressfeedback.h"
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
#include <c++utilities/io/copy.h>
|
|
|
|
|
2019-03-13 19:06:42 +01:00
|
|
|
#include <cstdint>
|
2015-04-22 19:22:01 +02:00
|
|
|
#include <initializer_list>
|
|
|
|
#include <iostream>
|
2018-03-07 01:17:50 +01:00
|
|
|
#include <list>
|
|
|
|
#include <memory>
|
2015-04-22 19:22:01 +02:00
|
|
|
#include <string>
|
|
|
|
|
2019-06-10 22:49:11 +02:00
|
|
|
namespace CppUtilities {
|
2015-04-22 19:22:01 +02:00
|
|
|
class BinaryReader;
|
|
|
|
class BinaryWriter;
|
2019-06-12 20:40:45 +02:00
|
|
|
} // namespace CppUtilities
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-06 23:09:15 +01:00
|
|
|
namespace TagParser {
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-05 17:49:29 +01:00
|
|
|
class Diagnostics;
|
2015-06-07 00:18:28 +02:00
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
2018-06-03 20:38:32 +02:00
|
|
|
* \class TagParser::FileElementTraits
|
2015-04-22 19:22:01 +02:00
|
|
|
* \brief Defines traits for the specified \a ImplementationType.
|
|
|
|
*
|
|
|
|
* A template specialization for each GenericFileElement should
|
|
|
|
* be provided.
|
|
|
|
*
|
|
|
|
* For an example of such a specialization see FileElementTraits<Mp4Atom> or FileElementTraits<EbmlElement>.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <typename ImplementationType> class FileElementTraits {
|
|
|
|
};
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
/*!
|
2018-06-03 20:38:32 +02:00
|
|
|
* \class TagParser::GenericFileElement
|
2015-04-22 19:22:01 +02:00
|
|
|
* \brief The GenericFileElement class helps to parse binary files which consist
|
|
|
|
* of an arboreal element strucutre.
|
|
|
|
* \tparam ImplementationType Specifies the type of the actual implementation.
|
2017-03-07 01:52:26 +01:00
|
|
|
* \remarks This template class is intended to be subclassed using
|
|
|
|
* with the "Curiously recurring template pattern".
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> class TAG_PARSER_EXPORT GenericFileElement {
|
2015-04-22 19:22:01 +02:00
|
|
|
friend class FileElementTraits<ImplementationType>;
|
|
|
|
|
|
|
|
public:
|
|
|
|
/*!
|
|
|
|
* \brief Specifies the type of the corresponding container.
|
|
|
|
*/
|
2018-07-11 13:19:43 +02:00
|
|
|
using ContainerType = typename FileElementTraits<ImplementationType>::ContainerType;
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Specifies the type used to store identifiers.
|
|
|
|
*/
|
2018-07-11 13:19:43 +02:00
|
|
|
using IdentifierType = typename FileElementTraits<ImplementationType>::IdentifierType;
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Specifies the type used to store data sizes.
|
|
|
|
*/
|
2018-07-11 13:19:43 +02:00
|
|
|
using DataSizeType = typename FileElementTraits<ImplementationType>::DataSizeType;
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2019-03-13 19:06:42 +01:00
|
|
|
GenericFileElement(ContainerType &container, std::uint64_t startOffset);
|
|
|
|
GenericFileElement(ImplementationType &parent, std::uint64_t startOffset);
|
|
|
|
GenericFileElement(ContainerType &container, std::uint64_t startOffset, std::uint64_t maxSize);
|
2018-03-07 01:17:50 +01:00
|
|
|
GenericFileElement(const GenericFileElement &other) = delete;
|
|
|
|
GenericFileElement(GenericFileElement &other) = delete;
|
|
|
|
GenericFileElement &operator=(const GenericFileElement &other) = delete;
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
ContainerType &container();
|
|
|
|
const ContainerType &container() const;
|
2015-04-22 19:22:01 +02:00
|
|
|
std::iostream &stream();
|
2019-06-10 22:49:11 +02:00
|
|
|
CppUtilities::BinaryReader &reader();
|
|
|
|
CppUtilities::BinaryWriter &writer();
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint64_t startOffset() const;
|
|
|
|
std::uint64_t relativeStartOffset() const;
|
2017-03-07 17:16:17 +01:00
|
|
|
const IdentifierType &id() const;
|
2015-04-22 19:22:01 +02:00
|
|
|
std::string idToString() const;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint32_t idLength() const;
|
|
|
|
std::uint32_t headerSize() const;
|
2017-03-07 17:16:17 +01:00
|
|
|
DataSizeType dataSize() const;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint32_t sizeLength() const;
|
|
|
|
std::uint64_t dataOffset() const;
|
|
|
|
std::uint64_t totalSize() const;
|
|
|
|
std::uint64_t endOffset() const;
|
|
|
|
std::uint64_t maxTotalSize() const;
|
|
|
|
std::uint8_t level() const;
|
2018-03-07 01:17:50 +01:00
|
|
|
ImplementationType *parent();
|
|
|
|
const ImplementationType *parent() const;
|
2019-03-13 19:06:42 +01:00
|
|
|
ImplementationType *parent(std::uint8_t n);
|
|
|
|
const ImplementationType *parent(std::uint8_t n) const;
|
2018-03-07 01:17:50 +01:00
|
|
|
ImplementationType *nextSibling();
|
|
|
|
const ImplementationType *nextSibling() const;
|
|
|
|
ImplementationType *firstChild();
|
|
|
|
const ImplementationType *firstChild() const;
|
|
|
|
ImplementationType *lastChild();
|
|
|
|
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);
|
|
|
|
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;
|
2015-04-22 19:22:01 +02:00
|
|
|
bool isParent() const;
|
|
|
|
bool isPadding() const;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint64_t firstChildOffset() const;
|
2015-04-22 19:22:01 +02:00
|
|
|
bool isParsed() const;
|
|
|
|
void clear();
|
2018-03-05 17:49:29 +01:00
|
|
|
void parse(Diagnostics &diag);
|
|
|
|
void reparse(Diagnostics &diag);
|
2019-03-13 19:06:42 +01:00
|
|
|
void validateSubsequentElementStructure(Diagnostics &diag, std::uint64_t *paddingSize = nullptr);
|
|
|
|
static constexpr std::uint32_t maximumIdLengthSupported();
|
|
|
|
static constexpr std::uint32_t maximumSizeLengthSupported();
|
|
|
|
static constexpr std::uint8_t minimumElementSize();
|
2018-03-05 17:49:29 +01:00
|
|
|
void copyHeader(std::ostream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress);
|
|
|
|
void copyWithoutChilds(std::ostream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress);
|
|
|
|
void copyEntirely(std::ostream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress);
|
2015-11-26 14:26:16 +01:00
|
|
|
void makeBuffer();
|
2015-12-21 00:03:04 +01:00
|
|
|
void discardBuffer();
|
2015-11-26 14:26:16 +01:00
|
|
|
void copyBuffer(std::ostream &targetStream);
|
2018-03-05 17:49:29 +01:00
|
|
|
void copyPreferablyFromBuffer(std::ostream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress);
|
2015-11-26 14:26:16 +01:00
|
|
|
const std::unique_ptr<char[]> &buffer();
|
2019-03-13 19:06:42 +01:00
|
|
|
ImplementationType *denoteFirstChild(std::uint32_t offset);
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
protected:
|
2017-03-07 17:16:17 +01:00
|
|
|
IdentifierType m_id;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint64_t m_startOffset;
|
|
|
|
std::uint64_t m_maxSize;
|
2017-03-07 17:16:17 +01:00
|
|
|
DataSizeType m_dataSize;
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint32_t m_idLength;
|
|
|
|
std::uint32_t m_sizeLength;
|
2018-03-07 01:17:50 +01:00
|
|
|
ImplementationType *m_parent;
|
2017-03-07 17:16:17 +01:00
|
|
|
std::unique_ptr<ImplementationType> m_nextSibling;
|
|
|
|
std::unique_ptr<ImplementationType> m_firstChild;
|
2015-11-26 14:26:16 +01:00
|
|
|
std::unique_ptr<char[]> m_buffer;
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
private:
|
2019-03-13 19:06:42 +01:00
|
|
|
void copyInternal(
|
|
|
|
std::ostream &targetStream, std::uint64_t startOffset, std::uint64_t bytesToCopy, Diagnostics &diag, AbortableProgressFeedback *progress);
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
ContainerType *m_container;
|
2015-04-22 19:22:01 +02:00
|
|
|
bool m_parsed;
|
2018-03-07 01:17:50 +01:00
|
|
|
|
2017-08-18 00:04:57 +02:00
|
|
|
protected:
|
|
|
|
bool m_sizeUnknown;
|
2015-04-22 19:22:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Constructs a new top level file element with the specified \a container at the specified \a startOffset.
|
2015-06-07 00:18:28 +02:00
|
|
|
* \remarks The available size is obtained using the stream of the \a container.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2019-03-13 19:06:42 +01:00
|
|
|
GenericFileElement<ImplementationType>::GenericFileElement(
|
|
|
|
GenericFileElement<ImplementationType>::ContainerType &container, std::uint64_t startOffset)
|
2018-03-07 01:17:50 +01:00
|
|
|
: m_id(IdentifierType())
|
|
|
|
, m_startOffset(startOffset)
|
|
|
|
, m_dataSize(0)
|
2018-03-11 16:14:42 +01:00
|
|
|
, m_idLength(0)
|
2018-03-07 01:17:50 +01:00
|
|
|
, m_sizeLength(0)
|
|
|
|
, m_parent(nullptr)
|
|
|
|
, m_container(&container)
|
|
|
|
, m_parsed(false)
|
|
|
|
, m_sizeUnknown(false)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2017-08-17 20:05:32 +02:00
|
|
|
m_maxSize = container.fileInfo().size();
|
2018-03-07 01:17:50 +01:00
|
|
|
if (m_maxSize > startOffset) {
|
2015-04-22 19:22:01 +02:00
|
|
|
m_maxSize -= startOffset;
|
|
|
|
stream().seekg(startOffset, std::ios_base::beg);
|
|
|
|
} else {
|
|
|
|
m_maxSize = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Constructs a new sub level file element with the specified \a parent at the specified \a startOffset.
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2019-03-13 19:06:42 +01:00
|
|
|
GenericFileElement<ImplementationType>::GenericFileElement(ImplementationType &parent, std::uint64_t startOffset)
|
2018-03-07 01:17:50 +01:00
|
|
|
: m_id(IdentifierType())
|
|
|
|
, m_startOffset(startOffset)
|
|
|
|
, m_maxSize(parent.startOffset() + parent.totalSize() - startOffset)
|
|
|
|
, m_dataSize(0)
|
2018-03-11 16:14:42 +01:00
|
|
|
, m_idLength(0)
|
2018-03-07 01:17:50 +01:00
|
|
|
, m_sizeLength(0)
|
|
|
|
, m_parent(&parent)
|
|
|
|
, m_container(&parent.container())
|
|
|
|
, m_parsed(false)
|
|
|
|
, m_sizeUnknown(false)
|
|
|
|
{
|
|
|
|
}
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Constructs a new sub level file element with the specified \a container, \a startOffset and \a maxSize.
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2018-03-07 01:17:50 +01:00
|
|
|
GenericFileElement<ImplementationType>::GenericFileElement(
|
2019-03-13 19:06:42 +01:00
|
|
|
GenericFileElement<ImplementationType>::ContainerType &container, std::uint64_t startOffset, std::uint64_t maxSize)
|
2018-03-07 01:17:50 +01:00
|
|
|
: m_id(IdentifierType())
|
|
|
|
, m_startOffset(startOffset)
|
|
|
|
, m_maxSize(maxSize)
|
|
|
|
, m_dataSize(0)
|
2018-03-11 16:14:42 +01:00
|
|
|
, m_idLength(0)
|
2018-03-07 01:17:50 +01:00
|
|
|
, m_sizeLength(0)
|
|
|
|
, m_parent(nullptr)
|
|
|
|
, m_container(&container)
|
|
|
|
, m_parsed(false)
|
|
|
|
, m_sizeUnknown(false)
|
|
|
|
{
|
|
|
|
}
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the related container.
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2018-03-07 01:17:50 +01:00
|
|
|
inline typename GenericFileElement<ImplementationType>::ContainerType &GenericFileElement<ImplementationType>::container()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return *m_container;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the related container.
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2017-03-07 17:16:17 +01:00
|
|
|
inline const typename GenericFileElement<ImplementationType>::ContainerType &GenericFileElement<ImplementationType>::container() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return *m_container;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the related stream.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline std::iostream &GenericFileElement<ImplementationType>::stream()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_container->stream();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the related BinaryReader.
|
|
|
|
*/
|
2019-06-10 22:49:11 +02:00
|
|
|
template <class ImplementationType> inline CppUtilities::BinaryReader &GenericFileElement<ImplementationType>::reader()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_container->reader();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the related BinaryWriter.
|
|
|
|
*/
|
2019-06-10 22:49:11 +02:00
|
|
|
template <class ImplementationType> inline CppUtilities::BinaryWriter &GenericFileElement<ImplementationType>::writer()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_container->writer();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the start offset in the related stream.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline std::uint64_t GenericFileElement<ImplementationType>::startOffset() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_startOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the offset of the element in its parent or - if it is a top-level element - in the related stream.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline std::uint64_t GenericFileElement<ImplementationType>::relativeStartOffset() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return parent() ? startOffset() - parent()->startOffset() : startOffset();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the element ID.
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2017-03-07 17:16:17 +01:00
|
|
|
inline const typename GenericFileElement<ImplementationType>::IdentifierType &GenericFileElement<ImplementationType>::id() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns a printable string representation of the element ID.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline std::string GenericFileElement<ImplementationType>::idToString() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return static_cast<ImplementationType *>(this)->idToString();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the length of the id denotation in byte.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline std::uint32_t GenericFileElement<ImplementationType>::idLength() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_idLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the header size of the element in byte.
|
|
|
|
*
|
|
|
|
* This is the sum of the id length and the size length.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline std::uint32_t GenericFileElement<ImplementationType>::headerSize() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_idLength + m_sizeLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the data size of the element in byte.
|
|
|
|
*
|
|
|
|
* This is the size of the element excluding the header.
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2017-03-07 17:16:17 +01:00
|
|
|
inline typename GenericFileElement<ImplementationType>::DataSizeType GenericFileElement<ImplementationType>::dataSize() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_dataSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the length of the size denotation of the element in byte.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline std::uint32_t GenericFileElement<ImplementationType>::sizeLength() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_sizeLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the data offset of the element in the related stream.
|
|
|
|
*
|
|
|
|
* This is the sum of start offset and header size.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline std::uint64_t GenericFileElement<ImplementationType>::dataOffset() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return startOffset() + headerSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the total size of the element.
|
|
|
|
*
|
|
|
|
* This is the sum of the header size and the data size.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline std::uint64_t GenericFileElement<ImplementationType>::totalSize() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return headerSize() + dataSize();
|
|
|
|
}
|
|
|
|
|
2015-11-21 01:07:52 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns the offset of the first byte which doesn't belong to this element anymore.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline std::uint64_t GenericFileElement<ImplementationType>::endOffset() const
|
2015-11-21 01:07:52 +01:00
|
|
|
{
|
|
|
|
return startOffset() + totalSize();
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns maximum total size.
|
2015-06-07 00:18:28 +02:00
|
|
|
*
|
|
|
|
* This is usually the size of the file for top-level elements and
|
|
|
|
* the remaining size of the parent for non-top-level elements.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline std::uint64_t GenericFileElement<ImplementationType>::maxTotalSize() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_maxSize;
|
|
|
|
}
|
|
|
|
|
2017-08-18 00:07:11 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns how deep the element is nested (0 for top-level elements, 1 for children of
|
|
|
|
* top-level elements, ...).
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> std::uint8_t GenericFileElement<ImplementationType>::level() const
|
2017-08-18 00:07:11 +02:00
|
|
|
{
|
2019-03-13 19:06:42 +01:00
|
|
|
std::uint8_t level = 0;
|
2018-03-07 01:17:50 +01:00
|
|
|
for (const ImplementationType *parent = m_parent; parent; ++level, parent = parent->m_parent)
|
|
|
|
;
|
2017-08-18 00:07:11 +02:00
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the parent of the element.
|
|
|
|
*
|
|
|
|
* The returned element has ownership over the current instance.
|
|
|
|
* If the current element is a top level element nullptr is returned.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline ImplementationType *GenericFileElement<ImplementationType>::parent()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the parent of the element.
|
|
|
|
*
|
|
|
|
* The returned element has ownership over the current instance.
|
|
|
|
* If the current element is a top level element nullptr is returned.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline const ImplementationType *GenericFileElement<ImplementationType>::parent() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_parent;
|
|
|
|
}
|
|
|
|
|
2017-08-18 00:07:42 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the n-th parent of the element.
|
|
|
|
* \remarks
|
|
|
|
* - The returned element has ownership (at least indirect) over the current instance.
|
|
|
|
* - Returns nullptr if level() < \a n.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> ImplementationType *GenericFileElement<ImplementationType>::parent(std::uint8_t n)
|
2017-08-18 00:07:42 +02:00
|
|
|
{
|
|
|
|
ImplementationType *parent = static_cast<ImplementationType *>(this);
|
2018-03-07 01:17:50 +01:00
|
|
|
for (; n && parent; --n, parent = parent->m_parent)
|
|
|
|
;
|
2017-08-18 00:07:42 +02:00
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the n-th parent of the element.
|
|
|
|
* \remarks
|
|
|
|
* - The returned element has ownership (at least indirect) over the current instance.
|
|
|
|
* - Returns nullptr if level() < \a n.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline const ImplementationType *GenericFileElement<ImplementationType>::parent(std::uint8_t n) const
|
2017-08-18 00:07:42 +02:00
|
|
|
{
|
|
|
|
return const_cast<GenericFileElement<ImplementationType> *>(this)->parent(n);
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the next sibling of the element.
|
|
|
|
*
|
|
|
|
* The current element keeps ownership over the returned element.
|
|
|
|
* If no next sibling is present nullptr is returned.
|
|
|
|
*
|
|
|
|
* \remarks parse() needs to be called before.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline ImplementationType *GenericFileElement<ImplementationType>::nextSibling()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_nextSibling.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the next sibling of the element.
|
|
|
|
*
|
|
|
|
* The current element keeps ownership over the returned element.
|
|
|
|
* If no next sibling is present nullptr is returned.
|
|
|
|
*
|
|
|
|
* \remarks parse() needs to be called before.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline const ImplementationType *GenericFileElement<ImplementationType>::nextSibling() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_nextSibling.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the first child of the element.
|
|
|
|
*
|
|
|
|
* The current element keeps ownership over the returned element.
|
2019-12-30 22:54:11 +01:00
|
|
|
* If no children are present nullptr is returned.
|
2015-04-22 19:22:01 +02:00
|
|
|
*
|
|
|
|
* \remarks parse() needs to be called before.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline ImplementationType *GenericFileElement<ImplementationType>::firstChild()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_firstChild.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the first child of the element.
|
|
|
|
*
|
|
|
|
* The current element keeps ownership over the returned element.
|
2019-12-30 22:54:11 +01:00
|
|
|
* If no children are present nullptr is returned.
|
2015-04-22 19:22:01 +02:00
|
|
|
*
|
|
|
|
* \remarks parse() needs to be called before.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline const ImplementationType *GenericFileElement<ImplementationType>::firstChild() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_firstChild.get();
|
|
|
|
}
|
|
|
|
|
2017-08-18 00:08:03 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the last child of the element.
|
|
|
|
*
|
|
|
|
* The current element keeps ownership over the returned element.
|
2019-12-30 22:54:11 +01:00
|
|
|
* If no children are present nullptr is returned.
|
2017-08-18 00:08:03 +02:00
|
|
|
*
|
|
|
|
* \remarks parse() needs to be called before.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline ImplementationType *GenericFileElement<ImplementationType>::lastChild()
|
2017-08-18 00:08:03 +02:00
|
|
|
{
|
2018-03-07 01:17:50 +01:00
|
|
|
for (ImplementationType *child = firstChild(); child; child = child->nextSibling()) {
|
|
|
|
if (!child->m_nextSibling) {
|
2017-08-18 00:08:03 +02:00
|
|
|
return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the last child of the element.
|
|
|
|
*
|
|
|
|
* The current element keeps ownership over the returned element.
|
2019-12-30 22:54:11 +01:00
|
|
|
* If no children are present nullptr is returned.
|
2017-08-18 00:08:03 +02:00
|
|
|
*
|
|
|
|
* \remarks parse() needs to be called before.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline const ImplementationType *GenericFileElement<ImplementationType>::lastChild() const
|
2017-08-18 00:08:03 +02:00
|
|
|
{
|
|
|
|
return const_cast<GenericFileElement<ImplementationType> *>(this)->lastChild();
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
2018-03-07 00:16:20 +01:00
|
|
|
* \brief Returns the sub element for the specified path.
|
2015-04-22 19:22:01 +02:00
|
|
|
*
|
|
|
|
* 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>
|
2018-03-07 00:16:20 +01:00
|
|
|
ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(Diagnostics &diag, IdentifierType item)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2018-03-07 00:16:20 +01:00
|
|
|
// ensure element is parsed
|
|
|
|
parse(diag);
|
|
|
|
// return the element if it matches the current and last item in the path
|
2018-03-07 01:17:50 +01:00
|
|
|
if (item == id()) {
|
2018-03-07 00:16:20 +01:00
|
|
|
return static_cast<ImplementationType *>(this);
|
|
|
|
}
|
|
|
|
// check whether a sibling matches the item
|
2018-03-07 01:17:50 +01:00
|
|
|
if (nextSibling()) {
|
2018-03-07 00:16:20 +01:00
|
|
|
return nextSibling()->subelementByPath(diag, item);
|
|
|
|
}
|
|
|
|
return nullptr;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2018-03-07 00:16:20 +01:00
|
|
|
* \brief Returns the sub element for the specified path.
|
2015-04-22 19:22:01 +02:00
|
|
|
*
|
|
|
|
* 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>
|
2018-03-07 00:16:20 +01:00
|
|
|
ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(Diagnostics &diag, IdentifierType item, IdentifierType remainingPath...)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2018-03-07 00:16:20 +01:00
|
|
|
// ensure element is parsed
|
|
|
|
parse(diag);
|
|
|
|
// continue with next item in path if the element matches the current item
|
2018-03-07 01:17:50 +01:00
|
|
|
if (item == id()) {
|
|
|
|
if (!firstChild()) {
|
2018-03-07 00:16:20 +01:00
|
|
|
return nullptr;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
2018-03-07 00:16:20 +01:00
|
|
|
return firstChild()->subelementByPath(diag, remainingPath);
|
|
|
|
}
|
|
|
|
// check whether a sibling matches the current item
|
2018-03-07 01:17:50 +01:00
|
|
|
if (nextSibling()) {
|
2018-03-07 00:16:20 +01:00
|
|
|
return nextSibling()->subelementByPath(diag, item, remainingPath);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-03-07 00:30:08 +01:00
|
|
|
/*!
|
|
|
|
* \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>
|
2018-03-07 01:17:50 +01:00
|
|
|
const ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(
|
|
|
|
Diagnostics &diag, IdentifierType item, IdentifierType remainingPath...) const
|
2018-03-07 00:30:08 +01:00
|
|
|
{
|
|
|
|
return const_cast<GenericFileElement<ImplementationType> *>(this)->subelementByPath(diag, item, remainingPath);
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the first child with 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.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> ImplementationType *GenericFileElement<ImplementationType>::childById(const IdentifierType &id, Diagnostics &diag)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2018-03-05 17:49:29 +01:00
|
|
|
parse(diag); // ensure element is parsed
|
2018-03-07 01:17:50 +01:00
|
|
|
for (ImplementationType *child = firstChild(); child; child = child->nextSibling()) {
|
2018-03-05 17:49:29 +01:00
|
|
|
child->parse(diag);
|
2018-03-07 01:17:50 +01:00
|
|
|
if (child->id() == id) {
|
2015-04-22 19:22:01 +02:00
|
|
|
return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-03-07 00:30:08 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns the first child with 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);
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the first sibling with the specified \a id.
|
|
|
|
*
|
2018-03-07 00:30:08 +01:00
|
|
|
* 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>::siblingById(const IdentifierType &id, Diagnostics &diag)
|
|
|
|
{
|
|
|
|
parse(diag); // ensure element is parsed
|
2018-03-07 01:17:50 +01:00
|
|
|
for (ImplementationType *sibling = nextSibling(); sibling; sibling = sibling->nextSibling()) {
|
2018-03-07 00:30:08 +01:00
|
|
|
sibling->parse(diag);
|
2018-03-07 01:17:50 +01:00
|
|
|
if (sibling->id() == id) {
|
2018-03-07 00:30:08 +01:00
|
|
|
return sibling;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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.
|
2015-04-22 19:22:01 +02:00
|
|
|
*
|
|
|
|
* 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>
|
2018-03-07 00:30:08 +01:00
|
|
|
ImplementationType *GenericFileElement<ImplementationType>::siblingByIdIncludingThis(const IdentifierType &id, Diagnostics &diag)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2018-03-05 17:49:29 +01:00
|
|
|
parse(diag); // ensure element is parsed
|
2018-03-07 01:17:50 +01:00
|
|
|
for (ImplementationType *sibling = static_cast<ImplementationType *>(this); sibling; sibling = sibling->nextSibling()) {
|
2018-03-05 17:49:29 +01:00
|
|
|
sibling->parse(diag);
|
2018-03-07 01:17:50 +01:00
|
|
|
if (sibling->id() == id) {
|
2015-04-22 19:22:01 +02:00
|
|
|
return sibling;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-03-07 00:30:08 +01:00
|
|
|
/*!
|
|
|
|
* \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);
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns an indication whether this instance is a parent element.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline bool GenericFileElement<ImplementationType>::isParent() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return static_cast<const ImplementationType *>(this)->isParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns an indication whether this instance is a padding element.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline bool GenericFileElement<ImplementationType>::isPadding() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return static_cast<const ImplementationType *>(this)->isPadding();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the offset of the first child (relative to the start offset of this element).
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> inline std::uint64_t GenericFileElement<ImplementationType>::firstChildOffset() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return static_cast<const ImplementationType *>(this)->firstChildOffset();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns an indication whether this instance has been parsed yet.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline bool GenericFileElement<ImplementationType>::isParsed() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_parsed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Clears the status of the element.
|
|
|
|
*
|
|
|
|
* Resets id length, data size, size length to zero. Subsequent elements
|
|
|
|
* will be deleted.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> void GenericFileElement<ImplementationType>::clear()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2017-03-07 17:16:17 +01:00
|
|
|
m_id = IdentifierType();
|
2015-04-22 19:22:01 +02:00
|
|
|
//m_startOffset = 0;
|
|
|
|
m_idLength = 0;
|
|
|
|
m_dataSize = 0;
|
|
|
|
m_sizeLength = 0;
|
|
|
|
m_nextSibling = nullptr;
|
|
|
|
m_firstChild = nullptr;
|
|
|
|
m_parsed = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Parses the header information of the element which is read from the related
|
|
|
|
* stream at the start offset.
|
|
|
|
*
|
|
|
|
* The parsed information can accessed using the corresponding methods such as
|
|
|
|
* id() for the elemement id and totalSize() for the element size.
|
|
|
|
*
|
|
|
|
* If the element has already been parsed (isParsed() returns true) this method
|
|
|
|
* does nothing. To force reparsing call reparse().
|
|
|
|
*
|
|
|
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
2018-06-03 20:38:32 +02:00
|
|
|
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
2015-04-22 19:22:01 +02:00
|
|
|
* error occurs.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> void GenericFileElement<ImplementationType>::parse(Diagnostics &diag)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2018-03-07 01:17:50 +01:00
|
|
|
if (!m_parsed) {
|
2018-03-05 17:49:29 +01:00
|
|
|
static_cast<ImplementationType *>(this)->internalParse(diag);
|
2015-04-22 19:22:01 +02:00
|
|
|
m_parsed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Parses the header information of the element which is read from the related
|
|
|
|
* stream at the start offset.
|
|
|
|
*
|
|
|
|
* The parsed information can accessed using the corresponding methods such as
|
|
|
|
* id() for the elemement id and totalSize() for the element size.
|
|
|
|
*
|
|
|
|
* If the element has already been parsed (isParsed() returns true) this method
|
|
|
|
* clears the parsed information and reparses the header.
|
|
|
|
*
|
|
|
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
2018-06-03 20:38:32 +02:00
|
|
|
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
2015-04-22 19:22:01 +02:00
|
|
|
* error occurs.
|
|
|
|
*
|
|
|
|
* \sa parse()
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> void GenericFileElement<ImplementationType>::reparse(Diagnostics &diag)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
clear();
|
2018-03-05 17:49:29 +01:00
|
|
|
static_cast<ImplementationType *>(this)->parse(diag);
|
2015-04-22 19:22:01 +02:00
|
|
|
m_parsed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Parses (see parse()) this and all subsequent elements.
|
|
|
|
*
|
2018-03-05 17:49:29 +01:00
|
|
|
* All diagnostic message will be stored in \a diag.
|
2015-04-22 19:22:01 +02:00
|
|
|
* If padding is found its size will be set to \a paddingSize if not nullptr.
|
|
|
|
*
|
|
|
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
2018-06-03 20:38:32 +02:00
|
|
|
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
2015-04-22 19:22:01 +02:00
|
|
|
* error occurs.
|
|
|
|
*
|
|
|
|
* \sa parse()
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2019-03-13 19:06:42 +01:00
|
|
|
void GenericFileElement<ImplementationType>::validateSubsequentElementStructure(Diagnostics &diag, std::uint64_t *paddingSize)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2018-03-05 17:49:29 +01:00
|
|
|
// validate element itself by just parsing it
|
|
|
|
parse(diag);
|
|
|
|
// validate children
|
2018-03-07 01:17:50 +01:00
|
|
|
if (firstChild()) {
|
2018-03-05 17:49:29 +01:00
|
|
|
try {
|
|
|
|
firstChild()->validateSubsequentElementStructure(diag, paddingSize);
|
2018-03-07 01:17:50 +01:00
|
|
|
} catch (const Failure &) {
|
2018-03-05 17:49:29 +01:00
|
|
|
// ignore critical errors in child structure to continue validating siblings
|
|
|
|
// (critical notifications about the errors should have already been added to diag, so nothing to do)
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
2018-03-07 01:17:50 +01:00
|
|
|
} else if (paddingSize && isPadding()) { // element is padding
|
2018-03-05 17:49:29 +01:00
|
|
|
*paddingSize += totalSize();
|
|
|
|
}
|
|
|
|
// validate siblings
|
2018-03-07 01:17:50 +01:00
|
|
|
if (nextSibling()) {
|
2018-03-05 17:49:29 +01:00
|
|
|
nextSibling()->validateSubsequentElementStructure(diag, paddingSize);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Writes the header informaton of the element to the specified \a targetStream.
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2018-03-05 17:49:29 +01:00
|
|
|
void GenericFileElement<ImplementationType>::copyHeader(std::ostream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2018-03-05 17:49:29 +01:00
|
|
|
copyInternal(targetStream, startOffset(), headerSize(), diag, progress);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2019-12-30 22:54:11 +01:00
|
|
|
* \brief Writes the element without its children to the specified \a targetStream.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2018-03-05 17:49:29 +01:00
|
|
|
void GenericFileElement<ImplementationType>::copyWithoutChilds(std::ostream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2019-03-13 19:06:42 +01:00
|
|
|
if (std::uint32_t firstChildOffset = this->firstChildOffset()) {
|
2018-03-05 17:49:29 +01:00
|
|
|
copyInternal(targetStream, startOffset(), firstChildOffset, diag, progress);
|
2015-04-22 19:22:01 +02:00
|
|
|
} else {
|
2018-03-05 17:49:29 +01:00
|
|
|
copyInternal(targetStream, startOffset(), totalSize(), diag, progress);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2019-12-30 22:54:11 +01:00
|
|
|
* \brief Writes the entire element including all children to the specified \a targetStream.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2018-03-05 17:49:29 +01:00
|
|
|
void GenericFileElement<ImplementationType>::copyEntirely(std::ostream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2018-03-05 17:49:29 +01:00
|
|
|
copyInternal(targetStream, startOffset(), totalSize(), diag, progress);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
2015-12-21 00:03:04 +01:00
|
|
|
/*!
|
|
|
|
* \brief Buffers the element (header and data).
|
|
|
|
* \remarks The element must have been parsed.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> void GenericFileElement<ImplementationType>::makeBuffer()
|
2015-11-26 14:26:16 +01:00
|
|
|
{
|
|
|
|
m_buffer = std::make_unique<char[]>(totalSize());
|
|
|
|
container().stream().seekg(startOffset());
|
|
|
|
container().stream().read(m_buffer.get(), totalSize());
|
|
|
|
}
|
|
|
|
|
2015-12-21 00:03:04 +01:00
|
|
|
/*!
|
|
|
|
* \brief Discards buffered data.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline void GenericFileElement<ImplementationType>::discardBuffer()
|
2015-11-26 14:26:16 +01:00
|
|
|
{
|
2015-12-21 00:03:04 +01:00
|
|
|
m_buffer.reset();
|
2015-11-26 14:26:16 +01:00
|
|
|
}
|
|
|
|
|
2015-12-21 00:03:04 +01:00
|
|
|
/*!
|
|
|
|
* \brief Copies buffered data to \a targetStream.
|
|
|
|
* \remarks Data must have been buffered using the makeBuffer() method.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline void GenericFileElement<ImplementationType>::copyBuffer(std::ostream &targetStream)
|
2015-11-26 14:26:16 +01:00
|
|
|
{
|
|
|
|
targetStream.write(m_buffer.get(), totalSize());
|
|
|
|
}
|
|
|
|
|
2017-06-17 00:29:49 +02:00
|
|
|
/*!
|
|
|
|
* \brief Copies buffered data to \a targetStream if data has been buffered; copies from input stream otherwise.
|
|
|
|
* \remarks So this is copyBuffer() with a fallback to copyEntirely().
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2018-03-07 01:17:50 +01:00
|
|
|
inline void GenericFileElement<ImplementationType>::copyPreferablyFromBuffer(
|
|
|
|
std::ostream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress)
|
2017-06-17 00:29:49 +02:00
|
|
|
{
|
2018-03-05 17:49:29 +01:00
|
|
|
m_buffer ? copyBuffer(targetStream) : copyEntirely(targetStream, diag, progress);
|
2017-06-17 00:29:49 +02:00
|
|
|
}
|
|
|
|
|
2015-12-21 00:03:04 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns buffered data. The returned array is totalSize() bytes long.
|
|
|
|
* \remarks Data must have been buffered using the makeBuffer() method.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline const std::unique_ptr<char[]> &GenericFileElement<ImplementationType>::buffer()
|
2015-11-26 14:26:16 +01:00
|
|
|
{
|
|
|
|
return m_buffer;
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Internally used to perform copies of the atom.
|
|
|
|
*
|
|
|
|
* \sa copyHeaderToStream()
|
|
|
|
* \sa copyAtomWithoutChildsToStream()
|
|
|
|
* \sa copyEntireAtomToStream()
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
2018-03-07 01:17:50 +01:00
|
|
|
void GenericFileElement<ImplementationType>::copyInternal(
|
2019-03-13 19:06:42 +01:00
|
|
|
std::ostream &targetStream, std::uint64_t startOffset, std::uint64_t bytesToCopy, Diagnostics &diag, AbortableProgressFeedback *progress)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
// ensure the header has been parsed correctly
|
|
|
|
try {
|
2018-03-05 17:49:29 +01:00
|
|
|
parse(diag);
|
2018-03-07 01:17:50 +01:00
|
|
|
} catch (const Failure &) {
|
2015-04-22 19:22:01 +02:00
|
|
|
throw InvalidDataException();
|
|
|
|
}
|
|
|
|
auto &stream = container().stream();
|
2018-03-05 17:49:29 +01:00
|
|
|
stream.seekg(startOffset);
|
2019-12-30 23:51:54 +01:00
|
|
|
CppUtilities::CopyHelper<0x10000> copyHelper;
|
2018-03-05 17:49:29 +01:00
|
|
|
if (progress) {
|
2018-03-07 01:17:50 +01:00
|
|
|
copyHelper.callbackCopy(stream, targetStream, bytesToCopy, std::bind(&AbortableProgressFeedback::isAborted, std::ref(progress)),
|
|
|
|
std::bind(&AbortableProgressFeedback::updateStepPercentageFromFraction, std::ref(progress), std::placeholders::_1));
|
2018-03-05 17:49:29 +01:00
|
|
|
} else {
|
|
|
|
copyHelper.copy(stream, targetStream, bytesToCopy);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-07 02:58:29 +02:00
|
|
|
/*!
|
|
|
|
* \brief Denotes the first child to start at the specified \a offset (relative to the start offset of this descriptor).
|
|
|
|
* \remarks A new first child is constructed. A possibly existing subtree is invalidated.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType>
|
|
|
|
ImplementationType *GenericFileElement<ImplementationType>::denoteFirstChild(std::uint32_t relativeFirstChildOffset)
|
2015-07-07 02:58:29 +02:00
|
|
|
{
|
2018-03-07 01:17:50 +01:00
|
|
|
if (relativeFirstChildOffset + minimumElementSize() <= totalSize()) {
|
2017-03-07 17:16:17 +01:00
|
|
|
m_firstChild.reset(new ImplementationType(static_cast<ImplementationType &>(*this), startOffset() + relativeFirstChildOffset));
|
2015-07-07 02:58:29 +02:00
|
|
|
} else {
|
|
|
|
m_firstChild.reset();
|
|
|
|
}
|
|
|
|
return m_firstChild.get();
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the maximum id length supported by the class in byte.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> constexpr std::uint32_t GenericFileElement<ImplementationType>::maximumIdLengthSupported()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2017-03-07 17:16:17 +01:00
|
|
|
return sizeof(IdentifierType);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the maximum size length supported by the class in byte.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> constexpr std::uint32_t GenericFileElement<ImplementationType>::maximumSizeLengthSupported()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2017-03-07 17:16:17 +01:00
|
|
|
return sizeof(DataSizeType);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
2015-07-13 00:57:38 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the mimimum element size.
|
|
|
|
*/
|
2019-03-13 19:06:42 +01:00
|
|
|
template <class ImplementationType> constexpr std::uint8_t GenericFileElement<ImplementationType>::minimumElementSize()
|
2015-07-13 00:57:38 +02:00
|
|
|
{
|
|
|
|
return FileElementTraits<ImplementationType>::minimumElementSize();
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \fn GenericFileElement<ImplementationType>::internalParse()
|
|
|
|
* \brief This method is called to perform parsing.
|
|
|
|
*
|
|
|
|
* It needs to be implemented when subclassing.
|
|
|
|
*
|
|
|
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
2018-06-03 20:38:32 +02:00
|
|
|
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
2015-04-22 19:22:01 +02:00
|
|
|
* error occurs.
|
|
|
|
*
|
|
|
|
* \sa parse()
|
|
|
|
* \sa reparse()
|
|
|
|
*/
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
} // namespace TagParser
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-06 23:09:15 +01:00
|
|
|
#endif // TAG_PARSER_GENERICFILEELEMENT_H
|