Tag Parser  6.5.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
matroskaseekinfo.cpp
Go to the documentation of this file.
1 #include "./matroskaseekinfo.h"
2 #include "./matroskaid.h"
3 
4 #include "../exceptions.h"
5 
6 #include <c++utilities/conversion/stringbuilder.h>
7 #include <c++utilities/conversion/binaryconversion.h>
8 
9 #include <string>
10 
11 using namespace std;
12 using namespace ConversionUtilities;
13 
14 namespace Media {
15 
24 void MatroskaSeekInfo::shift(uint64 start, int64 amount)
25 {
26  for(auto &info : m_info) {
27  if(get<1>(info) >= start) {
28  get<1>(info) += amount;
29  }
30  }
31 }
32 
39 void MatroskaSeekInfo::parse(EbmlElement *seekHeadElement)
40 {
41  static const string context("parsing \"SeekHead\"-element");
42  m_seekHeadElement = seekHeadElement;
43  m_info.clear();
44  EbmlElement *seekElement = seekHeadElement->firstChild();
45  EbmlElement *seekElementChild, *seekIdElement, *seekPositionElement;
46  while(seekElement) {
47  seekElement->parse();
48  switch(seekElement->id()) {
49  case MatroskaIds::Seek:
50  seekElementChild = seekElement->firstChild();
51  seekIdElement = seekPositionElement = nullptr;
52  while(seekElementChild) {
53  seekElementChild->parse();
54  switch(seekElementChild->id()) {
56  if(seekIdElement) {
57  addNotification(NotificationType::Warning, "The \"Seek\"-element contains multiple \"SeekID\"-elements. Surplus elements will be ignored.", context);
58  }
59  seekIdElement = seekElementChild;
60  break;
62  if(seekPositionElement) {
63  addNotification(NotificationType::Warning, "The \"Seek\"-element contains multiple \"SeekPosition\"-elements. Surplus elements will be ignored.", context);
64  }
65  seekPositionElement = seekElementChild;
66  break;
67  case EbmlIds::Crc32:
68  case EbmlIds::Void:
69  break;
70  default:
71  addNotification(NotificationType::Warning, "The element \""
72  % seekElementChild->idToString()
73  + "\" within the \"Seek\" element is not a \"SeekID\"-element nor a \"SeekPosition\"-element and will be ignored.", context);
74  }
75  seekElementChild = seekElementChild->nextSibling();
76  }
77  if(seekIdElement && seekPositionElement) {
78  m_info.emplace_back(seekIdElement->readUInteger(), seekPositionElement->readUInteger());
79  } else {
80  addNotification(NotificationType::Warning, "The \"Seek\"-element does not contain a \"SeekID\"- and a \"SeekPosition\"-element.", context);
81  }
82  break;
83  case EbmlIds::Crc32:
84  case EbmlIds::Void:
85  break;
86  default:
87  addNotification(NotificationType::Warning, "The element " % seekElement->idToString() + " is not a seek element and will be ignored.", context);
88  }
89  seekElement = seekElement->nextSibling();
90  }
91  if(m_info.empty()) {
92  addNotification(NotificationType::Warning, "No seek information found.", context);
93  }
94 }
95 
102 void MatroskaSeekInfo::make(ostream &stream)
103 {
104  uint64 totalSize = 0;
105  char buff0[8];
106  char buff1[8];
107  char buff2[2];
108  byte sizeLength0, sizeLength1;
109  // calculate size
110  for(const auto &info : m_info) {
111  // "Seek" element + "SeekID" element + "SeekPosition" element
112  totalSize += 2 + 1 + (2 + 1 + EbmlElement::calculateIdLength(get<0>(info))) + (2 + 1 + EbmlElement::calculateUIntegerLength(get<1>(info)));
113  }
114  // write ID and size
115  BE::getBytes(static_cast<uint32>(MatroskaIds::SeekHead), buff0);
116  stream.write(buff0, 4);
117  sizeLength0 = EbmlElement::makeSizeDenotation(totalSize, buff0);
118  stream.write(buff0, sizeLength0);
119  // write entries
120  for(const auto &info : m_info) {
121  // make values
122  sizeLength0 = EbmlElement::makeId(get<0>(info), buff0);
123  sizeLength1 = EbmlElement::makeUInteger(get<1>(info), buff1);
124  // "Seek" header
125  BE::getBytes(static_cast<uint16>(MatroskaIds::Seek), buff2);
126  stream.write(buff2, 2);
127  stream.put(0x80 | (2 + 1 + sizeLength0 + 2 + 1 + sizeLength1));
128  // "SeekID" element
129  BE::getBytes(static_cast<uint16>(MatroskaIds::SeekID), buff2);
130  stream.write(buff2, 2);
131  stream.put(0x80 | sizeLength0);
132  stream.write(buff0, sizeLength0);
133  // "SeekPosition" element
134  BE::getBytes(static_cast<uint16>(MatroskaIds::SeekPosition), buff2);
135  stream.write(buff2, 2);
136  stream.put(0x80 | sizeLength1);
137  stream.write(buff1, sizeLength1);
138  }
139 }
140 
145 uint64 MatroskaSeekInfo::minSize() const
146 {
147  uint64 maxTotalSize = m_info.size() * (2 + 1 + 2 + 1 + 1 + 2 + 1 + 1);
148  return 4 + EbmlElement::calculateSizeDenotationLength(maxTotalSize) + maxTotalSize;
149 }
150 
155 uint64 MatroskaSeekInfo::maxSize() const
156 {
157  uint64 maxTotalSize = m_info.size() * (2 + 1 + 2 + 1 + 4 + 2 + 1 + 8);
158  return 4 + EbmlElement::calculateSizeDenotationLength(maxTotalSize) + maxTotalSize;
159 }
160 
165 uint64 MatroskaSeekInfo::actualSize() const
166 {
167  uint64 totalSize = 0;
168  for(const auto &info : m_info) {
169  // "Seek" element + "SeekID" element + "SeekPosition" element
170  totalSize += 2 + 1 + (2 + 1 + EbmlElement::calculateIdLength(get<0>(info))) + (2 + 1 + EbmlElement::calculateUIntegerLength(get<1>(info)));
171  }
172  return totalSize += 4 + EbmlElement::calculateSizeDenotationLength(totalSize);
173 }
174 
183 bool MatroskaSeekInfo::push(unsigned int index, EbmlElement::identifierType id, uint64 offset)
184 {
185  unsigned int currentIndex = 0;
186  for(auto &entry : info()) {
187  if(get<0>(entry) == id) {
188  if(index == currentIndex) {
189  bool sizeUpdated = EbmlElement::calculateUIntegerLength(get<1>(entry)) != EbmlElement::calculateUIntegerLength(offset);
190  get<1>(entry) = offset;
191  return sizeUpdated;
192  }
193  ++currentIndex;
194  }
195  }
196  info().emplace_back(id, offset);
197  return true;
198 }
199 
203 void MatroskaSeekInfo::clear()
204 {
205  m_seekHeadElement = nullptr;
206  m_info.clear();
207 }
208 
212 std::pair<EbmlElement::identifierType, uint64> *MatroskaSeekInfo::findSeekInfo(std::vector<MatroskaSeekInfo> &seekInfos, uint64 offset)
213 {
214  for(auto &seekInfo : seekInfos) {
215  for(auto &entry : seekInfo.info()) {
216  if(get<1>(entry) == offset) {
217  return &entry;
218  }
219  }
220  }
221  return nullptr;
222 }
223 
228 bool MatroskaSeekInfo::updateSeekInfo(const std::vector<MatroskaSeekInfo> &oldSeekInfos, std::vector<MatroskaSeekInfo> &newSeekInfos, uint64 oldOffset, uint64 newOffset)
229 {
230  bool updated = false;
231  auto oldIterator0 = oldSeekInfos.cbegin(), oldEnd0 = oldSeekInfos.cend();
232  auto newIterator0 = newSeekInfos.begin(), newEnd0 = newSeekInfos.end();
233  for(; oldIterator0 != oldEnd0 && newIterator0 != newEnd0; ++oldIterator0, ++newIterator0) {
234  auto oldIterator1 = oldIterator0->info().cbegin(), oldEnd1 = oldIterator0->info().cend();
235  auto newIterator1 = newIterator0->info().begin(), newEnd1 = newIterator0->info().end();
236  for(; oldIterator1 != oldEnd1 && newIterator1 != newEnd1; ++oldIterator1, ++newIterator1) {
237  if(get<1>(*oldIterator1) == oldOffset) {
238  if(get<1>(*newIterator1) != newOffset) {
239  updated = updated || (EbmlElement::calculateUIntegerLength(newOffset) != EbmlElement::calculateUIntegerLength(get<1>(*newIterator1)));
240  get<1>(*newIterator1) = newOffset;
241  }
242  }
243  }
244  }
245  return updated;
246 }
247 
252 bool MatroskaSeekInfo::updateSeekInfo(std::vector<MatroskaSeekInfo> &newSeekInfos, uint64 oldOffset, uint64 newOffset)
253 {
254  if(oldOffset == newOffset) {
255  return false;
256  }
257  bool updated = false;
258  for(auto &seekInfo : newSeekInfos) {
259  for(auto &info : seekInfo.info()) {
260  if(get<1>(info) == oldOffset) {
261  get<1>(info) = newOffset;
262  updated = true;
263  }
264  }
265  }
266  return updated;
267 }
268 
269 }
void clear()
Clears the status of the element.
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 parse()
Parses the header information of the element which is read from the related stream at the start offse...
STL namespace.
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.
Contains all classes and functions of the TagInfo library.
Definition: exceptions.h:9