Tag Parser 12.3.1
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
Loading...
Searching...
No Matches
matroskaattachment.cpp
Go to the documentation of this file.
2#include "./ebmlelement.h"
4#include "./matroskaid.h"
5
6#include "../mediafileinfo.h"
7
8#include <c++utilities/conversion/binaryconversion.h>
9#include <c++utilities/conversion/stringbuilder.h>
10
11#include <memory>
12
13using namespace std;
14using namespace CppUtilities;
15
16namespace TagParser {
17
30void MatroskaAttachment::parse(EbmlElement *attachedFileElement, Diagnostics &diag)
31{
32 clear();
33 static const string context("parsing \"AttachedFile\"-element");
34 m_attachedFileElement = attachedFileElement;
36 while (subElement) {
37 subElement->parse(diag);
38 switch (subElement->id()) {
40 if (description().empty()) {
41 setDescription(subElement->readString());
42 } else {
43 diag.emplace_back(DiagLevel::Warning, "Multiple \"FileDescription\"-elements found. Surplus elements will be ignored.", context);
44 }
45 break;
47 if (name().empty()) {
48 setName(subElement->readString());
49 } else {
50 diag.emplace_back(DiagLevel::Warning, "Multiple \"FileName\"-elements found. Surplus elements will be ignored.", context);
51 }
52 break;
54 if (mimeType().empty()) {
55 setMimeType(subElement->readString());
56 } else {
57 diag.emplace_back(DiagLevel::Warning, "Multiple \"FileMimeType\"-elements found. Surplus elements will be ignored.", context);
58 }
59 break;
61 if (data()) {
62 diag.emplace_back(DiagLevel::Warning, "Multiple \"FileData\"-elements found. Surplus elements will be ignored.", context);
63 } else {
64 setData(make_unique<StreamDataBlock>(std::bind(&EbmlElement::stream, subElement), subElement->dataOffset(), ios_base::beg,
65 subElement->startOffset() + subElement->totalSize(), ios_base::beg));
66 }
67 break;
69 if (id()) {
70 diag.emplace_back(DiagLevel::Warning, "Multiple \"FileUID\"-elements found. Surplus elements will be ignored.", context);
71 } else {
72 setId(subElement->readUInteger());
73 }
74 break;
78 case EbmlIds::Crc32:
79 case EbmlIds::Void:
80 break;
81 default:
82 diag.emplace_back(DiagLevel::Warning, "Unknown child element \"" % subElement->idToString() + "\" found.", context);
83 }
84 subElement = subElement->nextSibling();
85 }
86}
87
95void MatroskaAttachment::make(std::ostream &stream, Diagnostics &diag)
96{
97 if (!data() || !data()->size()) {
98 diag.emplace_back(DiagLevel::Critical, "There is no data assigned.", "making Matroska attachment");
100 }
101 prepareMaking(diag).make(stream, diag);
102}
103
115MatroskaAttachmentMaker::MatroskaAttachmentMaker(MatroskaAttachment &attachment, Diagnostics &diag)
116 : m_attachment(attachment)
117{
118 m_attachedFileElementSize = 2 + EbmlElement::calculateSizeDenotationLength(attachment.name().size()) + attachment.name().size() + 2
119 + EbmlElement::calculateSizeDenotationLength(attachment.mimeType().size()) + attachment.mimeType().size() + 2 + 1
121 if (auto dataSize = attachment.data() ? attachment.data()->size() : static_cast<std::uint64_t>(0)) {
122 m_attachedFileElementSize += 2 + EbmlElement::calculateSizeDenotationLength(dataSize) + dataSize;
123 }
124 if (!attachment.description().empty()) {
125 m_attachedFileElementSize
126 += 2 + EbmlElement::calculateSizeDenotationLength(attachment.description().size()) + attachment.description().size();
127 }
128 if (attachment.attachedFileElement()) {
129 EbmlElement *child;
130 for (auto id : initializer_list<EbmlElement::IdentifierType>{
132 if ((child = attachment.attachedFileElement()->childById(id, diag))) {
133 m_attachedFileElementSize += child->totalSize();
134 }
135 }
136 }
137 m_totalSize = 2 + EbmlElement::calculateSizeDenotationLength(m_attachedFileElementSize) + m_attachedFileElementSize;
138}
139
147void MatroskaAttachmentMaker::make(ostream &stream, Diagnostics &diag) const
148{
149 char buff[8];
150 BE::getBytes(static_cast<std::uint16_t>(MatroskaIds::AttachedFile), buff);
151 stream.write(buff, 2);
152 std::uint8_t len = EbmlElement::makeSizeDenotation(m_attachedFileElementSize, buff);
153 stream.write(buff, len);
154 // make elements
156 if (!attachment().description().empty()) {
158 }
161 if (attachment().attachedFileElement()) {
162 EbmlElement *child;
163 for (auto id : initializer_list<EbmlElement::IdentifierType>{
165 if ((child = attachment().attachedFileElement()->childById(id, diag))) {
166 if (child->buffer()) {
167 child->copyBuffer(stream);
168 } else {
169 child->copyEntirely(stream, diag, nullptr);
170 }
171 }
172 }
173 }
174 if (attachment().data() && attachment().data()->size()) {
175 BE::getBytes(static_cast<std::uint16_t>(MatroskaIds::FileData), buff);
176 stream.write(buff, 2);
177 len = EbmlElement::makeSizeDenotation(static_cast<std::uint64_t>(attachment().data()->size()), buff);
178 stream.write(buff, len);
179 attachment().data()->copyTo(stream);
180 }
181}
182
184{
185 EbmlElement *child;
186 if (attachment().attachedFileElement()) {
187 for (auto id : initializer_list<EbmlElement::IdentifierType>{
189 if ((child = attachment().attachedFileElement()->childById(id, diag))) {
190 child->makeBuffer();
191 }
192 }
193 }
194 if (attachment().data() && attachment().data()->size() && !attachment().isDataFromFile()) {
196 }
197}
198
199} // 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.
The EbmlElement class helps to parse EBML files such as Matroska files.
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.
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.
std::uint64_t startOffset() const
Returns the start offset in the related stream.
const std::unique_ptr< char[]> & buffer()
Returns buffered data.
const IdentifierType & id() const
Returns the element ID.
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...
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.
Contains all classes and functions of the TagInfo library.
Definition aaccodebook.h:10