Tag Parser 11.4.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
matroskaattachment.cpp
Go to the documentation of this file.
2#include "./ebmlelement.h"
4#include "./matroskaid.h"
5
6#include <c++utilities/conversion/binaryconversion.h>
7#include <c++utilities/conversion/stringbuilder.h>
8
9#include <memory>
10
11using namespace std;
12using namespace CppUtilities;
13
14namespace TagParser {
15
28void MatroskaAttachment::parse(EbmlElement *attachedFileElement, Diagnostics &diag)
29{
30 clear();
31 static const string context("parsing \"AttachedFile\"-element");
32 m_attachedFileElement = attachedFileElement;
34 while (subElement) {
35 subElement->parse(diag);
36 switch (subElement->id()) {
38 if (description().empty()) {
39 setDescription(subElement->readString());
40 } else {
41 diag.emplace_back(DiagLevel::Warning, "Multiple \"FileDescription\"-elements found. Surplus elements will be ignored.", context);
42 }
43 break;
45 if (name().empty()) {
46 setName(subElement->readString());
47 } else {
48 diag.emplace_back(DiagLevel::Warning, "Multiple \"FileName\"-elements found. Surplus elements will be ignored.", context);
49 }
50 break;
52 if (mimeType().empty()) {
53 setMimeType(subElement->readString());
54 } else {
55 diag.emplace_back(DiagLevel::Warning, "Multiple \"FileMimeType\"-elements found. Surplus elements will be ignored.", context);
56 }
57 break;
59 if (data()) {
60 diag.emplace_back(DiagLevel::Warning, "Multiple \"FileData\"-elements found. Surplus elements will be ignored.", context);
61 } else {
62 setData(make_unique<StreamDataBlock>(std::bind(&EbmlElement::stream, subElement), subElement->dataOffset(), ios_base::beg,
63 subElement->startOffset() + subElement->totalSize(), ios_base::beg));
64 }
65 break;
67 if (id()) {
68 diag.emplace_back(DiagLevel::Warning, "Multiple \"FileUID\"-elements found. Surplus elements will be ignored.", context);
69 } else {
70 setId(subElement->readUInteger());
71 }
72 break;
76 case EbmlIds::Crc32:
77 case EbmlIds::Void:
78 break;
79 default:
80 diag.emplace_back(DiagLevel::Warning, "Unknown child element \"" % subElement->idToString() + "\" found.", context);
81 }
82 subElement = subElement->nextSibling();
83 }
84}
85
93void MatroskaAttachment::make(std::ostream &stream, Diagnostics &diag)
94{
95 if (!data() || !data()->size()) {
96 diag.emplace_back(DiagLevel::Critical, "There is no data assigned.", "making Matroska attachment");
98 }
99 prepareMaking(diag).make(stream, diag);
100}
101
113MatroskaAttachmentMaker::MatroskaAttachmentMaker(MatroskaAttachment &attachment, Diagnostics &diag)
114 : m_attachment(attachment)
115{
116 m_attachedFileElementSize = 2 + EbmlElement::calculateSizeDenotationLength(attachment.name().size()) + attachment.name().size() + 2
117 + EbmlElement::calculateSizeDenotationLength(attachment.mimeType().size()) + attachment.mimeType().size() + 2 + 1
119 if (auto dataSize = attachment.data() ? attachment.data()->size() : static_cast<std::uint64_t>(0)) {
120 m_attachedFileElementSize += 2 + EbmlElement::calculateSizeDenotationLength(dataSize) + dataSize;
121 }
122 if (!attachment.description().empty()) {
123 m_attachedFileElementSize
124 += 2 + EbmlElement::calculateSizeDenotationLength(attachment.description().size()) + attachment.description().size();
125 }
126 if (attachment.attachedFileElement()) {
127 EbmlElement *child;
128 for (auto id : initializer_list<EbmlElement::IdentifierType>{
130 if ((child = attachment.attachedFileElement()->childById(id, diag))) {
131 m_attachedFileElementSize += child->totalSize();
132 }
133 }
134 }
135 m_totalSize = 2 + EbmlElement::calculateSizeDenotationLength(m_attachedFileElementSize) + m_attachedFileElementSize;
136}
137
145void MatroskaAttachmentMaker::make(ostream &stream, Diagnostics &diag) const
146{
147 char buff[8];
148 BE::getBytes(static_cast<std::uint16_t>(MatroskaIds::AttachedFile), buff);
149 stream.write(buff, 2);
150 std::uint8_t len = EbmlElement::makeSizeDenotation(m_attachedFileElementSize, buff);
151 stream.write(buff, len);
152 // make elements
154 if (!attachment().description().empty()) {
156 }
159 if (attachment().attachedFileElement()) {
160 EbmlElement *child;
161 for (auto id : initializer_list<EbmlElement::IdentifierType>{
163 if ((child = attachment().attachedFileElement()->childById(id, diag))) {
164 if (child->buffer()) {
165 child->copyBuffer(stream);
166 } else {
167 child->copyEntirely(stream, diag, nullptr);
168 }
169 }
170 }
171 }
172 if (attachment().data() && attachment().data()->size()) {
173 BE::getBytes(static_cast<std::uint16_t>(MatroskaIds::FileData), buff);
174 stream.write(buff, 2);
175 len = EbmlElement::makeSizeDenotation(static_cast<std::uint64_t>(attachment().data()->size()), buff);
176 stream.write(buff, len);
177 attachment().data()->copyTo(stream);
178 }
179}
180
182{
183 EbmlElement *child;
184 if (attachment().attachedFileElement()) {
185 for (auto id : initializer_list<EbmlElement::IdentifierType>{
187 if ((child = attachment().attachedFileElement()->childById(id, diag))) {
188 child->makeBuffer();
189 }
190 }
191 }
192 if (attachment().data() && attachment().data()->size() && !attachment().isDataFromFile()) {
194 }
195}
196
197} // namespace TagParser
void setDescription(std::string_view description)
Sets a description of the attachment.
void clear()
Resets the object to its initial state.
const std::string & mimeType() const
Returns the MIME-type of the attachment.
const std::string & description() const
Returns a description of the attachment.
void setData(std::unique_ptr< StreamDataBlock > &&data)
Sets the data for the attachment.
const std::string & name() const
Returns the (file) name of the attachment.
std::uint64_t id() const
Returns the ID of the attachment.
void setName(std::string_view name)
Sets the (file) name of the attachment.
void setId(std::uint64_t id)
Sets the ID of the attachment.
const StreamDataBlock * data() const
Returns a reference to the data of the attachment.
void setMimeType(std::string_view mimeType)
Sets the MIME-type of the attachment.
The Diagnostics class is a container for DiagMessage.
Definition: diagnostics.h:156
The EbmlElement class helps to parse EBML files such as Matroska files.
Definition: ebmlelement.h:32
static void makeSimpleElement(std::ostream &stream, IdentifierType id, std::uint64_t content)
Makes a simple EBML element.
static std::uint8_t calculateSizeDenotationLength(std::uint64_t size)
Returns the length of the size denotation for the specified size in byte.
std::string idToString() const
Converts the specified EBML ID to a printable string.
Definition: ebmlelement.h:71
std::string readString()
Reads the content of the element as string.
std::uint64_t readUInteger()
Reads the content of the element as unsigned integer.
static std::uint8_t makeSizeDenotation(std::uint64_t size, char *buff)
Makes the size denotation for the specified size and stores it to buff.
static std::uint8_t calculateUIntegerLength(std::uint64_t integer)
Returns the length of the specified unsigned integer in byte.
std::uint64_t startOffset() const
Returns the start offset in the related stream.
void copyEntirely(std::ostream &targetStream, Diagnostics &diag, AbortableProgressFeedback *progress)
Writes the entire element including all children to the specified targetStream.
const std::unique_ptr< char[]> & buffer()
Returns buffered data.
const IdentifierType & id() const
Returns the element ID.
std::iostream & stream()
Returns the related stream.
void copyBuffer(std::ostream &targetStream)
Copies buffered data to targetStream.
ImplementationType * childById(const IdentifierType &id, Diagnostics &diag)
Returns the first child with the specified id.
ImplementationType * nextSibling()
Returns the next sibling of the element.
ImplementationType * firstChild()
Returns the first child of the element.
std::uint64_t totalSize() const
Returns the total size 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 dataOffset() const
Returns the data offset of the element in the related stream.
void makeBuffer()
Buffers the element (header and data).
The exception that is thrown when the data to be parsed or to be made seems invalid and therefore can...
Definition: exceptions.h:25
const MatroskaAttachment & attachment() const
Returns the associated attachment.
void make(std::ostream &stream, Diagnostics &diag) const
Saves the attachment (specified when constructing the object) to the specified stream (makes an "Atta...
void bufferCurrentAttachments(Diagnostics &diag)
Implementation of TagParser::AbstractAttachment for the Matroska container.
EbmlElement * attachedFileElement() const
Returns the "AttachedFile"-element which has been specified when the parse() method has been called.
void make(std::ostream &stream, Diagnostics &diag)
Writes the attachment to the specified stream (makes an "AttachedFile"-element).
MatroskaAttachmentMaker prepareMaking(Diagnostics &diag)
Prepares making.
void parse(EbmlElement *attachedFileElement, Diagnostics &diag)
Parses attachment from the specified attachedFileElement.
void makeBuffer() const
Buffers the data block.
std::uint64_t size() const
Returns the size of the data block.
void copyTo(std::ostream &stream) const
Copies the data to the specified stream.
constexpr TAG_PARSER_EXPORT std::string_view description()
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10