Tag Parser  6.4.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 "./matroskacontainer.h"
3 #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 
11 using namespace std;
12 using namespace ConversionUtilities;
13 using namespace IoUtilities;
14 
15 namespace Media {
16 
29 void MatroskaAttachment::parse(EbmlElement *attachedFileElement)
30 {
31  clear();
32  static const string context("parsing \"AttachedFile\"-element");
33  m_attachedFileElement = attachedFileElement;
34  EbmlElement *subElement = attachedFileElement->firstChild();
35  while(subElement) {
36  subElement->parse();
37  switch(subElement->id()) {
39  if(description().empty()) {
40  setDescription(subElement->readString());
41  } else {
42  addNotification(NotificationType::Warning, "Multiple \"FileDescription\"-elements found. Surplus elements will be ignored.", context);
43  }
44  break;
46  if(name().empty()) {
47  setName(subElement->readString());
48  } else {
49  addNotification(NotificationType::Warning, "Multiple \"FileName\"-elements found. Surplus elements will be ignored.", context);
50  }
51  break;
53  if(mimeType().empty()) {
54  setMimeType(subElement->readString());
55  } else {
56  addNotification(NotificationType::Warning, "Multiple \"FileMimeType\"-elements found. Surplus elements will be ignored.", context);
57  }
58  break;
60  if(data()) {
61  addNotification(NotificationType::Warning, "Multiple \"FileData\"-elements found. Surplus elements will be ignored.", context);
62  } else {
63  setData(make_unique<StreamDataBlock>(std::bind(&EbmlElement::stream, subElement), subElement->dataOffset(), ios_base::beg, subElement->startOffset() + subElement->totalSize(), ios_base::beg));
64  }
65  break;
67  if(id()) {
68  addNotification(NotificationType::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  addNotification(NotificationType::Warning, "Unknown child element \"" % subElement->idToString() + "\" found.", context);
81  }
82  subElement = subElement->nextSibling();
83  }
84 }
85 
93 void MatroskaAttachment::make(std::ostream &stream)
94 {
95  if(!data() || !data()->size()) {
96  addNotification(NotificationType::Critical, "There is no data assigned.", "making Matroska attachment");
97  throw InvalidDataException();
98  }
99  prepareMaking().make(stream);
100 }
101 
113 MatroskaAttachmentMaker::MatroskaAttachmentMaker(MatroskaAttachment &attachment) :
114  m_attachment(attachment)
115 {
116  m_attachedFileElementSize = 2 + EbmlElement::calculateSizeDenotationLength(attachment.name().size()) + attachment.name().size()
117  + 2 + EbmlElement::calculateSizeDenotationLength(attachment.mimeType().size()) + attachment.mimeType().size()
118  + 2 + 1 + EbmlElement::calculateUIntegerLength(attachment.id());
119  if(auto dataSize = attachment.data() ? attachment.data()->size() : static_cast<istream::pos_type>(0)) {
120  m_attachedFileElementSize += 2 + EbmlElement::calculateSizeDenotationLength(dataSize) + dataSize;
121  }
122  if(!attachment.description().empty()) {
123  m_attachedFileElementSize += 2 + EbmlElement::calculateSizeDenotationLength(attachment.description().size()) + attachment.description().size();
124  }
125  if(attachment.attachedFileElement()) {
126  EbmlElement *child;
127  for(auto id : initializer_list<EbmlElement::identifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
128  if((child = attachment.attachedFileElement()->childById(id))) {
129  m_attachedFileElementSize += child->totalSize();
130  }
131  }
132  }
133  m_totalSize = 2 + EbmlElement::calculateSizeDenotationLength(m_attachedFileElementSize) + m_attachedFileElementSize;
134 }
135 
143 void MatroskaAttachmentMaker::make(ostream &stream) const
144 {
145  char buff[8];
146  BE::getBytes(static_cast<uint16>(MatroskaIds::AttachedFile), buff);
147  stream.write(buff, 2);
148  byte len = EbmlElement::makeSizeDenotation(m_attachedFileElementSize, buff);
149  stream.write(buff, len);
150  // make elements
151  EbmlElement::makeSimpleElement(stream, MatroskaIds::FileName, attachment().name());
152  if(!attachment().description().empty()) {
153  EbmlElement::makeSimpleElement(stream, MatroskaIds::FileDescription, attachment().description());
154  }
155  EbmlElement::makeSimpleElement(stream, MatroskaIds::FileMimeType, attachment().mimeType());
156  EbmlElement::makeSimpleElement(stream, MatroskaIds::FileUID, attachment().id());
157  if(attachment().attachedFileElement()) {
158  EbmlElement *child;
159  for(auto id : initializer_list<EbmlElement::identifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
160  if((child = attachment().attachedFileElement()->childById(id))) {
161  if(child->buffer()) {
162  child->copyBuffer(stream);
163  } else {
164  child->copyEntirely(stream);
165  }
166  }
167  }
168  }
169  if(attachment().data() && attachment().data()->size()) {
170  BE::getBytes(static_cast<uint16>(MatroskaIds::FileData), buff);
171  stream.write(buff, 2);
172  len = EbmlElement::makeSizeDenotation(attachment().data()->size(), buff);
173  stream.write(buff, len);
174  attachment().data()->copyTo(stream);
175  }
176 }
177 
178 void MatroskaAttachmentMaker::bufferCurrentAttachments()
179 {
180  EbmlElement *child;
181  if(attachment().attachedFileElement()) {
182  for(auto id : initializer_list<EbmlElement::identifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
183  if((child = attachment().attachedFileElement()->childById(id))) {
184  child->makeBuffer();
185  }
186  }
187  }
188  if(attachment().data() && attachment().data()->size() && !attachment().isDataFromFile()) {
189  attachment().data()->makeBuffer();
190  }
191 }
192 
193 } // namespace Media
194 
implementationType * childById(const identifierType &id)
Returns the first child with the specified id.
uint64 startOffset() const
Returns the start offset in the related stream.
uint64 dataOffset() const
Returns the data offset of the element in the related stream.
const std::string & mimeType() const
Returns the MIME-type of the attachment.
implementationType * nextSibling()
Returns the next sibling of the element.
uint64 readUInteger()
Reads the content of the element as unsigned integer.
The EbmlElement class helps to parse EBML files such as Matroska files.
Definition: ebmlelement.h:50
void makeBuffer() const
Buffers the data block.
const StreamDataBlock * data() const
Returns a reference to the data of the attachment.
void parse()
Parses the header information of the element which is read from the related stream at the start offse...
const std::unique_ptr< char[]> & buffer()
Returns buffered data.
uint64 totalSize() const
Returns the total size of the element.
STL namespace.
Contains utility classes helping to read and write streams.
The exception that is thrown when the data to be parsed or to be made seems invalid and therefore can...
Definition: exceptions.h:27
EbmlElement * attachedFileElement() const
Returns the "AttachedFile"-element which has been specified when the parse() method has been called...
std::string readString()
Reads the content of the element as string.
std::string idToString() const
Converts the specified EBML ID to a printable string.
Definition: ebmlelement.h:91
implementationType * firstChild()
Returns the first child of the element.
const identifierType & id() const
Returns the element ID.
const std::string & description() const
Returns a description of the attachment.
void makeBuffer()
Buffers the element (header and data).
void copyEntirely(std::ostream &targetStream)
Writes the entire element including all childs to the specified targetStream.
TAG_PARSER_EXPORT const char * description()
void copyBuffer(std::ostream &targetStream)
Copies buffered data to targetStream.
const std::string & name() const
Returns the (file) name of the attachment.
uint64 id() const
Returns the ID of the attachment.
Contains all classes and functions of the TagInfo library.
Definition: exceptions.h:9
std::istream::pos_type size() const
Returns the size of the data block.
void copyTo(std::ostream &stream) const
Copies the data to the specified stream.
Implementation of Media::AbstractAttachment for the Matroska container.