1 #ifndef TAG_PARSER_GENERICFILEELEMENT_H
2 #define TAG_PARSER_GENERICFILEELEMENT_H
7 #include <c++utilities/io/copy.h>
10 #include <initializer_list>
66 GenericFileElement(ContainerType &container, std::uint64_t startOffset, std::uint64_t maxSize);
71 ContainerType &container();
72 const ContainerType &container()
const;
73 std::iostream &stream();
74 CppUtilities::BinaryReader &reader();
75 CppUtilities::BinaryWriter &writer();
76 std::uint64_t startOffset()
const;
77 std::uint64_t relativeStartOffset()
const;
79 std::string idToString()
const;
80 std::uint32_t idLength()
const;
81 std::uint32_t headerSize()
const;
83 std::uint32_t sizeLength()
const;
84 std::uint64_t dataOffset()
const;
85 std::uint64_t totalSize()
const;
86 std::uint64_t endOffset()
const;
87 std::uint64_t maxTotalSize()
const;
88 std::uint8_t level()
const;
89 ImplementationType *parent();
90 const ImplementationType *parent()
const;
91 ImplementationType *parent(std::uint8_t n);
92 const ImplementationType *parent(std::uint8_t n)
const;
93 ImplementationType *nextSibling();
94 const ImplementationType *nextSibling()
const;
95 ImplementationType *firstChild();
96 const ImplementationType *firstChild()
const;
97 ImplementationType *lastChild();
98 const ImplementationType *lastChild()
const;
109 bool isParent()
const;
110 bool isPadding()
const;
111 std::uint64_t firstChildOffset()
const;
112 bool isParsed()
const;
116 void validateSubsequentElementStructure(
Diagnostics &diag, std::uint64_t *paddingSize =
nullptr);
117 static constexpr std::uint32_t maximumIdLengthSupported();
118 static constexpr std::uint32_t maximumSizeLengthSupported();
119 static constexpr std::uint8_t minimumElementSize();
124 void discardBuffer();
125 void copyBuffer(std::ostream &targetStream);
127 const std::unique_ptr<char[]> &buffer();
128 ImplementationType *denoteFirstChild(std::uint32_t offset);
146 ContainerType *m_container;
157 template <
class ImplementationType>
160 : m_id(IdentifierType())
161 , m_startOffset(startOffset)
166 , m_container(&container)
168 , m_sizeUnknown(false)
170 m_maxSize = container.fileInfo().size();
171 if (m_maxSize > startOffset) {
172 m_maxSize -= startOffset;
173 stream().seekg(startOffset, std::ios_base::beg);
182 template <
class ImplementationType>
185 , m_startOffset(startOffset)
186 , m_maxSize(parent.startOffset() + parent.totalSize() - startOffset)
191 , m_container(&parent.container())
193 , m_sizeUnknown(false)
200 template <
class ImplementationType>
203 : m_id(IdentifierType())
204 , m_startOffset(startOffset)
210 , m_container(&container)
212 , m_sizeUnknown(false)
219 template <
class ImplementationType>
228 template <
class ImplementationType>
239 return m_container->
stream();
247 return m_container->
reader();
255 return m_container->
writer();
263 return m_startOffset;
271 return parent() ? startOffset() - parent()->
startOffset() : startOffset();
277 template <
class ImplementationType>
288 return static_cast<ImplementationType *>(
this)->
idToString();
306 return m_idLength + m_sizeLength;
314 template <
class ImplementationType>
335 return startOffset() + headerSize();
345 return headerSize() + dataSize();
353 return startOffset() + totalSize();
373 std::uint8_t level = 0;
374 for (
const ImplementationType *parent = m_parent; parent; ++level, parent = parent->m_parent)
409 ImplementationType *parent = static_cast<ImplementationType *>(
this);
410 for (; n && parent; --n, parent = parent->m_parent)
436 return m_nextSibling.get();
449 return m_nextSibling.get();
462 return m_firstChild.get();
475 return m_firstChild.get();
488 for (ImplementationType *child = firstChild(); child; child = child->nextSibling()) {
489 if (!child->m_nextSibling) {
518 template <
class ImplementationType>
525 return static_cast<ImplementationType *>(
this);
529 return nextSibling()->subelementByPath(diag, item);
543 template <
class ImplementationType>
553 return firstChild()->subelementByPath(diag, remainingPath);
557 return nextSibling()->subelementByPath(diag, item, remainingPath);
571 template <
class ImplementationType>
586 template <
class ImplementationType>
605 for (ImplementationType *child = firstChild(); child; child = child->nextSibling()) {
607 if (child->id() == id) {
623 template <
class ImplementationType>
639 template <
class ImplementationType>
643 for (ImplementationType *sibling = nextSibling(); sibling; sibling = sibling->nextSibling()) {
644 sibling->parse(diag);
645 if (sibling->id() == id) {
662 template <
class ImplementationType>
678 template <
class ImplementationType>
682 for (ImplementationType *sibling = static_cast<ImplementationType *>(
this); sibling; sibling = sibling->nextSibling()) {
683 sibling->parse(diag);
684 if (sibling->id() == id) {
701 template <
class ImplementationType>
712 return static_cast<const ImplementationType *>(
this)->
isParent();
720 return static_cast<const ImplementationType *>(
this)->
isPadding();
752 m_nextSibling =
nullptr;
753 m_firstChild =
nullptr;
774 static_cast<ImplementationType *>(
this)->internalParse(diag);
798 static_cast<ImplementationType *>(
this)->parse(diag);
814 template <
class ImplementationType>
822 firstChild()->validateSubsequentElementStructure(diag, paddingSize);
827 }
else if (paddingSize && isPadding()) {
828 *paddingSize += totalSize();
832 nextSibling()->validateSubsequentElementStructure(diag, paddingSize);
839 template <
class ImplementationType>
842 copyInternal(targetStream, startOffset(), headerSize(), diag, progress);
848 template <
class ImplementationType>
851 if (std::uint32_t firstChildOffset = this->firstChildOffset()) {
852 copyInternal(targetStream, startOffset(), firstChildOffset, diag, progress);
854 copyInternal(targetStream, startOffset(), totalSize(), diag, progress);
861 template <
class ImplementationType>
864 copyInternal(targetStream, startOffset(), totalSize(), diag, progress);
873 m_buffer = std::make_unique<char[]>(totalSize());
874 container().stream().seekg(startOffset());
875 container().stream().read(m_buffer.get(), totalSize());
892 targetStream.write(m_buffer.get(), totalSize());
899 template <
class ImplementationType>
903 m_buffer ? copyBuffer(targetStream) : copyEntirely(targetStream, diag, progress);
922 template <
class ImplementationType>
929 }
catch (
const Failure &) {
930 throw InvalidDataException();
932 auto &stream = container().stream();
933 stream.seekg(startOffset);
936 copyHelper.callbackCopy(stream, targetStream, bytesToCopy, std::bind(&AbortableProgressFeedback::isAborted, std::ref(progress)),
937 std::bind(&AbortableProgressFeedback::updateStepPercentageFromFraction, std::ref(progress), std::placeholders::_1));
939 copyHelper.copy(stream, targetStream, bytesToCopy);
947 template <
class ImplementationType>
950 if (relativeFirstChildOffset + minimumElementSize() <= totalSize()) {
951 m_firstChild.reset(
new ImplementationType(static_cast<ImplementationType &>(*
this), startOffset() + relativeFirstChildOffset));
953 m_firstChild.reset();
955 return m_firstChild.get();
998 #endif // TAG_PARSER_GENERICFILEELEMENT_H