Tag Parser  6.1.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/misc/memory.h>
8 
9 using namespace std;
10 using namespace ConversionUtilities;
11 using namespace IoUtilities;
12 
13 namespace Media {
14 
27 void MatroskaAttachment::parse(EbmlElement *attachedFileElement)
28 {
29  clear();
30  static const string context("parsing \"AttachedFile\"-element");
31  m_attachedFileElement = attachedFileElement;
32  EbmlElement *subElement = attachedFileElement->firstChild();
33  while(subElement) {
34  subElement->parse();
35  switch(subElement->id()) {
37  if(description().empty()) {
38  setDescription(subElement->readString());
39  } else {
40  addNotification(NotificationType::Warning, "Multiple \"FileDescription\"-elements found. Surplus elements will be ignored.", context);
41  }
42  break;
44  if(name().empty()) {
45  setName(subElement->readString());
46  } else {
47  addNotification(NotificationType::Warning, "Multiple \"FileName\"-elements found. Surplus elements will be ignored.", context);
48  }
49  break;
51  if(mimeType().empty()) {
52  setMimeType(subElement->readString());
53  } else {
54  addNotification(NotificationType::Warning, "Multiple \"FileMimeType\"-elements found. Surplus elements will be ignored.", context);
55  }
56  break;
58  if(data()) {
59  addNotification(NotificationType::Warning, "Multiple \"FileData\"-elements found. Surplus elements will be ignored.", context);
60  } else {
61  setData(make_unique<StreamDataBlock>(std::bind(&EbmlElement::stream, subElement), subElement->dataOffset(), ios_base::beg, subElement->startOffset() + subElement->totalSize(), ios_base::beg));
62  }
63  break;
65  if(id()) {
66  addNotification(NotificationType::Warning, "Multiple \"FileUID\"-elements found. Surplus elements will be ignored.", context);
67  } else {
68  setId(subElement->readUInteger());
69  }
70  break;
74  case EbmlIds::Crc32:
75  case EbmlIds::Void:
76  break;
77  default:
78  addNotification(NotificationType::Warning, "Unknown child element \"" + subElement->idToString() + "\" found.", context);
79  }
80  subElement = subElement->nextSibling();
81  }
82 }
83 
91 void MatroskaAttachment::make(std::ostream &stream)
92 {
93  if(!data() || !data()->size()) {
94  addNotification(NotificationType::Critical, "There is no data assigned.", "making Matroska attachment");
95  throw InvalidDataException();
96  }
97  prepareMaking().make(stream);
98 }
99 
111 MatroskaAttachmentMaker::MatroskaAttachmentMaker(MatroskaAttachment &attachment) :
112  m_attachment(attachment)
113 {
114  m_attachedFileElementSize = 2 + EbmlElement::calculateSizeDenotationLength(attachment.name().size()) + attachment.name().size()
115  + 2 + EbmlElement::calculateSizeDenotationLength(attachment.mimeType().size()) + attachment.mimeType().size()
116  + 2 + 1 + EbmlElement::calculateUIntegerLength(attachment.id());
117  if(auto dataSize = attachment.data() ? attachment.data()->size() : static_cast<istream::pos_type>(0)) {
118  m_attachedFileElementSize += 2 + EbmlElement::calculateSizeDenotationLength(dataSize) + dataSize;
119  }
120  if(!attachment.description().empty()) {
121  m_attachedFileElementSize += 2 + EbmlElement::calculateSizeDenotationLength(attachment.description().size()) + attachment.description().size();
122  }
123  if(attachment.attachedFileElement()) {
124  EbmlElement *child;
125  for(auto id : initializer_list<EbmlElement::identifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
126  if((child = attachment.attachedFileElement()->childById(id))) {
127  m_attachedFileElementSize += child->totalSize();
128  }
129  }
130  }
131  m_totalSize = 2 + EbmlElement::calculateSizeDenotationLength(m_attachedFileElementSize) + m_attachedFileElementSize;
132 }
133 
141 void MatroskaAttachmentMaker::make(ostream &stream) const
142 {
143  char buff[8];
144  BE::getBytes(static_cast<uint16>(MatroskaIds::AttachedFile), buff);
145  stream.write(buff, 2);
146  byte len = EbmlElement::makeSizeDenotation(m_attachedFileElementSize, buff);
147  stream.write(buff, len);
148  // make elements
149  EbmlElement::makeSimpleElement(stream, MatroskaIds::FileName, attachment().name());
150  if(!attachment().description().empty()) {
151  EbmlElement::makeSimpleElement(stream, MatroskaIds::FileDescription, attachment().description());
152  }
153  EbmlElement::makeSimpleElement(stream, MatroskaIds::FileMimeType, attachment().mimeType());
154  EbmlElement::makeSimpleElement(stream, MatroskaIds::FileUID, attachment().id());
155  if(attachment().attachedFileElement()) {
156  EbmlElement *child;
157  for(auto id : initializer_list<EbmlElement::identifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
158  if((child = attachment().attachedFileElement()->childById(id))) {
159  if(child->buffer()) {
160  child->copyBuffer(stream);
161  } else {
162  child->copyEntirely(stream);
163  }
164  }
165  }
166  }
167  if(attachment().data() && attachment().data()->size()) {
168  BE::getBytes(static_cast<uint16>(MatroskaIds::FileData), buff);
169  stream.write(buff, 2);
170  len = EbmlElement::makeSizeDenotation(attachment().data()->size(), buff);
171  stream.write(buff, len);
172  attachment().data()->copyTo(stream);
173  }
174 }
175 
176 void MatroskaAttachmentMaker::bufferCurrentAttachments()
177 {
178  EbmlElement *child;
179  if(attachment().attachedFileElement()) {
180  for(auto id : initializer_list<EbmlElement::identifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
181  if((child = attachment().attachedFileElement()->childById(id))) {
182  child->makeBuffer();
183  }
184  }
185  }
186  if(attachment().data() && attachment().data()->size() && !attachment().isDataFromFile()) {
187  attachment().data()->makeBuffer();
188  }
189 }
190 
191 } // namespace Media
192 
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:90
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.