1#ifndef TAG_PARSER_GENERICFILEELEMENT_H
2#define TAG_PARSER_GENERICFILEELEMENT_H
7#include <c++utilities/io/copy.h>
10#include <initializer_list>
34template <
typename ImplementationType>
class FileElementTraits {};
45 friend class FileElementTraits<ImplementationType>;
73 CppUtilities::BinaryReader &
reader();
74 CppUtilities::BinaryWriter &
writer();
89 const ImplementationType *
parent()
const;
90 ImplementationType *
parent(std::uint8_t n);
91 const ImplementationType *
parent(std::uint8_t n)
const;
101 template <
class IdType,
class... IdTypes>
120 template <
typename TargetStream = std::ostream>
122 template <
typename TargetStream = std::ostream>
124 template <
typename TargetStream = std::ostream>
128 template <
typename TargetStream = std::ostream>
void copyBuffer(TargetStream &targetStream);
129 template <
typename TargetStream = std::ostream>
147 template <
typename TargetStream = std::ostream>
162template <
class ImplementationType>
165 : m_id(IdentifierType())
166 , m_startOffset(startOffset)
171 , m_container(&container)
173 , m_sizeUnknown(false)
187template <
class ImplementationType>
190 , m_startOffset(startOffset)
191 , m_maxSize(parent.startOffset() + parent.totalSize() - startOffset)
196 , m_container(&parent.container())
198 , m_sizeUnknown(false)
205template <
class ImplementationType>
208 : m_id(IdentifierType())
209 , m_startOffset(startOffset)
215 , m_container(&container)
217 , m_sizeUnknown(false)
224template <
class ImplementationType>
233template <
class ImplementationType>
244 return m_container->stream();
252 return m_container->reader();
260 return m_container->writer();
268 return m_startOffset;
276 return parent() ? startOffset() - parent()->startOffset() : startOffset();
282template <
class ImplementationType>
293 return static_cast<ImplementationType *
>(
this)->idToString();
311 return m_idLength + m_sizeLength;
319template <
class ImplementationType>
340 return startOffset() + headerSize();
350 return headerSize() + dataSize();
358 return startOffset() + totalSize();
378 std::uint8_t level = 0;
379 for (
const ImplementationType *parent = m_parent; parent; ++level, parent = parent->m_parent)
414 ImplementationType *parent =
static_cast<ImplementationType *
>(
this);
415 for (; n && parent; --n, parent = parent->m_parent)
441 return m_nextSibling.get();
454 return m_nextSibling.get();
467 return m_firstChild.get();
480 return m_firstChild.get();
493 for (ImplementationType *child = firstChild(); child; child = child->nextSibling()) {
494 if (!child->m_nextSibling) {
523template <
class ImplementationType>
524template <
class IdType>
531 return static_cast<ImplementationType *
>(
this);
535 return nextSibling()->subelementByPath(diag, item);
549template <
class ImplementationType>
550template <
class IdType,
class... IdTypes>
560 return firstChild()->subelementByPath(diag, remainingPath...);
564 return nextSibling()->subelementByPath(diag, item, remainingPath...);
578template <
class ImplementationType>
579template <
class IdType>
594template <
class ImplementationType>
595template <
class IdType,
class... IdTypes>
613 for (ImplementationType *child = firstChild(); child; child = child->nextSibling()) {
615 if (child->id() ==
id) {
631template <
class ImplementationType>
647template <
class ImplementationType>
651 for (ImplementationType *sibling = nextSibling(); sibling; sibling = sibling->nextSibling()) {
652 sibling->parse(diag);
653 if (sibling->id() ==
id) {
670template <
class ImplementationType>
686template <
class ImplementationType>
690 for (ImplementationType *sibling =
static_cast<ImplementationType *
>(
this); sibling; sibling = sibling->nextSibling()) {
691 sibling->parse(diag);
692 if (sibling->id() ==
id) {
709template <
class ImplementationType>
720 return static_cast<const ImplementationType *
>(
this)->isParent();
728 return static_cast<const ImplementationType *
>(
this)->isPadding();
736 return static_cast<const ImplementationType *
>(
this)->firstChildOffset();
760 m_nextSibling =
nullptr;
761 m_firstChild =
nullptr;
782 static_cast<ImplementationType *
>(
this)->internalParse(diag);
806 static_cast<ImplementationType *
>(
this)->parse(diag);
822template <
class ImplementationType>
834 firstChild()->validateSubsequentElementStructure(diag, paddingSize, progress);
839 }
else if (paddingSize && isPadding()) {
840 *paddingSize += totalSize();
844 nextSibling()->validateSubsequentElementStructure(diag, paddingSize, progress);
851template <
class ImplementationType>
852template <
typename TargetStream>
855 copyInternal(targetStream, startOffset(), headerSize(), diag, progress);
861template <
class ImplementationType>
862template <
typename TargetStream>
865 if (std::uint32_t firstChildOffset = this->firstChildOffset()) {
866 copyInternal(targetStream, startOffset(), firstChildOffset, diag, progress);
868 copyInternal(targetStream, startOffset(), totalSize(), diag, progress);
875template <
class ImplementationType>
876template <
typename TargetStream>
879 copyInternal(targetStream, startOffset(), totalSize(), diag, progress);
888 m_buffer = std::make_unique<char[]>(totalSize());
889 container().stream().seekg(
static_cast<std::streamoff
>(startOffset()));
890 container().stream().read(m_buffer.get(),
static_cast<std::streamsize
>(totalSize()));
905template <
class ImplementationType>
906template <
typename TargetStream>
909 targetStream.write(m_buffer.get(),
static_cast<std::streamsize
>(totalSize()));
916template <
class ImplementationType>
917template <
typename TargetStream>
921 m_buffer ? copyBuffer(targetStream) : copyEntirely(targetStream, diag, progress);
940template <
class ImplementationType>
941template <
typename TargetStream>
948 }
catch (
const Failure &) {
949 throw InvalidDataException();
951 auto &stream = container().
stream();
952 stream.seekg(
static_cast<std::streamoff
>(startOffset), std::ios_base::beg);
953 CppUtilities::CopyHelper<0x10000> copyHelper;
958 copyHelper.copy(stream, targetStream, bytesToCopy);
966template <
class ImplementationType>
969 if (relativeFirstChildOffset + minimumElementSize() <= totalSize()) {
970 m_firstChild.reset(
new ImplementationType(
static_cast<ImplementationType &
>(*
this), startOffset() + relativeFirstChildOffset));
972 m_firstChild.reset();
974 return m_firstChild.get();
The AbortableProgressFeedback class provides feedback about an ongoing operation via callbacks.
bool isAborted() const
Returns whether the operation has been aborted via tryToAbort().
void stopIfAborted() const
Throws an OperationAbortedException if aborted.
void updateStepPercentageFromFraction(double stepPercentage)
The Diagnostics class is a container for DiagMessage.
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
Defines traits for the specified ImplementationType.
The GenericFileElement class helps to parse binary files which consist of an arboreal element structu...
GenericFileElement(ContainerType &container, std::uint64_t startOffset)
const ImplementationType * parent(std::uint8_t n) const
Returns the n-th parent of the element.
ImplementationType * lastChild()
Returns the last child of the element.
void copyEntirely(TargetStream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress)
Writes the entire element including all children to the specified targetStream.
void copyBuffer(TargetStream &targetStream)
Copies buffered data to targetStream.
const ContainerType & container() const
Returns the related container.
std::uint64_t startOffset() const
Returns the start offset in the related stream.
void copyHeader(TargetStream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress)
Writes the header information of the element to the specified targetStream.
std::string idToString() const
Returns a printable string representation of the element ID.
const ImplementationType * nextSibling() const
Returns the next sibling of the element.
void discardBuffer()
Discards buffered data.
GenericFileElement(ContainerType &container, std::uint64_t startOffset, std::uint64_t maxSize)
ImplementationType * siblingByIdIncludingThis(const IdentifierType &id, Diagnostics &diag)
Returns the first sibling with the specified id or the current instance if its ID equals id.
const ImplementationType * subelementByPath(Diagnostics &diag, IdType item) const
Returns the sub element for the specified path.
const std::unique_ptr< char[]> & buffer()
Returns buffered data.
const ImplementationType * firstChild() const
Returns the first child of the element.
std::uint32_t headerSize() const
Returns the header size of the element in byte.
const ImplementationType * childById(const IdentifierType &id, Diagnostics &diag) const
Returns the first child with the specified id.
bool isParent() const
Returns an indication whether this instance is a parent element.
std::uint64_t endOffset() const
Returns the offset of the first byte which doesn't belong to this element anymore.
bool isPadding() const
Returns an indication whether this instance is a padding element.
const IdentifierType & id() const
Returns the element ID.
CppUtilities::BinaryWriter & writer()
Returns the related BinaryWriter.
typename FileElementTraits< ImplementationType >::DataSizeType DataSizeType
Specifies the type used to store data sizes.
std::uint8_t level() const
Returns how deep the element is nested (0 for top-level elements, 1 for children of top-level element...
typename FileElementTraits< ImplementationType >::ContainerType ContainerType
Specifies the type of the corresponding container.
std::iostream & stream()
Returns the related stream.
const ImplementationType * siblingById(const IdentifierType &id, Diagnostics &diag) const
Returns the first sibling with the specified id.
GenericFileElement & operator=(const GenericFileElement &other)=delete
ImplementationType * childById(const IdentifierType &id, Diagnostics &diag)
Returns the first child with the specified id.
std::uint64_t firstChildOffset() const
Returns the offset of the first child (relative to the start offset of this element).
bool isParsed() const
Returns an indication whether this instance has been parsed yet.
ImplementationType * nextSibling()
Returns the next sibling of the element.
std::unique_ptr< ImplementationType > m_nextSibling
GenericFileElement(GenericFileElement &other)=delete
ImplementationType * parent()
Returns the parent of the element.
static constexpr std::uint8_t minimumElementSize()
Returns the minimum element size.
ImplementationType * denoteFirstChild(std::uint32_t offset)
Denotes the first child to start at the specified offset (relative to the start offset of this descri...
std::uint64_t m_startOffset
void copyWithoutChilds(TargetStream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress)
Writes the element without its children to the specified targetStream.
ImplementationType * firstChild()
Returns the first child of the element.
std::uint32_t sizeLength() const
Returns the length of the size denotation of the element in byte.
std::unique_ptr< ImplementationType > m_firstChild
const ImplementationType * siblingByIdIncludingThis(const IdentifierType &id, Diagnostics &diag) const
Returns the first sibling with the specified id or the current instance if its ID equals id.
const ImplementationType * lastChild() const
Returns the last child of the element.
ImplementationType * subelementByPath(Diagnostics &diag, IdType item)
Returns the sub element for the specified path.
static constexpr std::uint32_t maximumIdLengthSupported()
Returns the maximum id length supported by the class in byte.
DataSizeType dataSize() const
Returns the data size of the element in byte.
std::uint64_t totalSize() const
Returns the total size of the element.
ImplementationType * subelementByPath(Diagnostics &diag, IdType item, IdTypes... remainingPath)
Returns the sub element for the specified path.
const ImplementationType * parent() const
Returns the parent of the element.
void parse(Diagnostics &diag)
Parses the header information of the element which is read from the related stream at the start offse...
std::uint64_t relativeStartOffset() const
Returns the offset of the element in its parent or - if it is a top-level element - in the related st...
void validateSubsequentElementStructure(Diagnostics &diag, std::uint64_t *paddingSize=nullptr, AbortableProgressFeedback *progress=nullptr)
Parses (see parse()) this and all subsequent elements.
typename FileElementTraits< ImplementationType >::IdentifierType IdentifierType
Specifies the type used to store identifiers.
static constexpr std::uint32_t maximumSizeLengthSupported()
Returns the maximum size length supported by the class in byte.
ImplementationType * m_parent
std::uint64_t dataOffset() const
Returns the data offset of the element in the related stream.
GenericFileElement(const GenericFileElement &other)=delete
GenericFileElement(ImplementationType &parent, std::uint64_t startOffset)
Constructs a new sub level file element with the specified parent at the specified startOffset.
ContainerType & container()
Returns the related container.
ImplementationType * parent(std::uint8_t n)
Returns the n-th parent of the element.
void clear()
Clears the status of the element.
std::uint32_t idLength() const
Returns the length of the id denotation in byte.
std::unique_ptr< char[]> m_buffer
CppUtilities::BinaryReader & reader()
Returns the related BinaryReader.
std::uint64_t maxTotalSize() const
Returns maximum total size.
void makeBuffer()
Buffers the element (header and data).
void reparse(Diagnostics &diag)
Parses the header information of the element which is read from the related stream at the start offse...
ImplementationType * siblingById(const IdentifierType &id, Diagnostics &diag)
Returns the first sibling with the specified id.
std::uint32_t m_sizeLength
void copyPreferablyFromBuffer(TargetStream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress)
Copies buffered data to targetStream if data has been buffered; copies from input stream otherwise.
const ImplementationType * subelementByPath(Diagnostics &diag, IdType item, IdTypes... remainingPath) const
Returns the sub element for the specified path.
#define TAG_PARSER_EXPORT
Marks the symbol to be exported by the tagparser library.
Contains all classes and functions of the TagInfo library.