Tag Parser  10.0.1
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
matroskaattachment.cpp
Go to the documentation of this file.
1 #include "./matroskaattachment.h"
2 #include "./ebmlelement.h"
3 #include "./matroskacontainer.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 
11 using namespace std;
12 using namespace CppUtilities;
13 
14 namespace TagParser {
15 
28 void MatroskaAttachment::parse(EbmlElement *attachedFileElement, Diagnostics &diag)
29 {
30  clear();
31  static const string context("parsing \"AttachedFile\"-element");
32  m_attachedFileElement = attachedFileElement;
33  EbmlElement *subElement = attachedFileElement->firstChild();
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 
93 void 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");
97  throw InvalidDataException();
98  }
99  prepareMaking(diag).make(stream, diag);
100 }
101 
113 MatroskaAttachmentMaker::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 
145 void 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()) {
193  attachment().data()->makeBuffer();
194  }
195 }
196 
197 } // namespace TagParser
const std::string & mimeType() const
Returns the MIME-type of the attachment.
const std::string & description() const
Returns a description of 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.
const StreamDataBlock * data() const
Returns a reference to the data 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.
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 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