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