Tag Parser  6.3.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
oggcontainer.cpp
Go to the documentation of this file.
1 #include "./oggcontainer.h"
2 
3 #include "../flac/flacmetadata.h"
4 
5 #include "../mediafileinfo.h"
6 #include "../backuphelper.h"
7 
8 #include <c++utilities/conversion/stringbuilder.h>
9 #include <c++utilities/io/copy.h>
10 #include <c++utilities/io/catchiofailure.h>
11 
12 #include <memory>
13 
14 using namespace std;
15 using namespace IoUtilities;
16 using namespace ConversionUtilities;
17 
18 namespace Media {
19 
25 const char *OggVorbisComment::typeName() const
26 {
27  switch(m_oggParams.streamFormat) {
29  return "Vorbis comment (in FLAC stream)";
30  case GeneralMediaFormat::Opus:
31  return "Vorbis comment (in Opus stream)";
32  case GeneralMediaFormat::Theora:
33  return "Vorbis comment (in Theora stream)";
34  default:
35  return "Vorbis comment";
36  }
37 }
38 
47 OggContainer::OggContainer(MediaFileInfo &fileInfo, uint64 startOffset) :
49  m_iterator(fileInfo.stream(), startOffset, fileInfo.size()),
50  m_validateChecksums(false)
51 {}
52 
54 {}
55 
57 {
58  m_iterator.reset();
59 }
60 
72 {
73  if(!target.tracks().empty()) {
74  // return the tag for the first matching track ID
75  for(auto &tag : m_tags) {
76  if(!tag->target().tracks().empty() && tag->target().tracks().front() == target.tracks().front() && !tag->oggParams().removed) {
77  return tag.get();
78  }
79  }
80  // not tag found -> try to re-use a tag which has been flagged as removed
81  for(auto &tag : m_tags) {
82  if(!tag->target().tracks().empty() && tag->target().tracks().front() == target.tracks().front()) {
83  tag->oggParams().removed = false;
84  return tag.get();
85  }
86  }
87  } else if(OggVorbisComment *comment = tag(0)) {
88  // no track ID specified -> just return the first tag (if one exists)
89  return comment;
90  } else if(!m_tags.empty()) {
91  // no track ID specified -> just return the first tag (try to re-use a tag which has been flagged as removed)
92  m_tags.front()->oggParams().removed = false;
93  return m_tags.front().get();
94  }
95 
96  // a new tag needs to be created
97  // -> determine an appropriate track for the tag
98  // -> just use the first Vorbis/Opus track
99  for(const auto &track : m_tracks) {
100  if(target.tracks().empty() || target.tracks().front() == track->id()) {
101  switch(track->format().general) {
104  // check whether start page has a valid value
105  if(track->startPage() < m_iterator.pages().size()) {
106  announceComment(track->startPage(), static_cast<size_t>(-1), false, track->format().general);
107  m_tags.back()->setTarget(target);
108  return m_tags.back().get();
109  } else {
110  // TODO: error handling?
111  }
112  default:
113  ;
114  }
115  // TODO: allow adding tags to FLAC tracks (not really important, because a tag should always be present)
116  }
117  }
118  return nullptr;
119 }
120 
122 {
123  size_t i = 0;
124  for(const auto &tag : m_tags) {
125  if(!tag->oggParams().removed) {
126  if(index == i) {
127  return tag.get();
128  }
129  ++i;
130  }
131  }
132  return nullptr;
133 }
134 
136 {
137  size_t count = 0;
138  for(const auto &tag : m_tags) {
139  if(!tag->oggParams().removed) {
140  ++count;
141  }
142  }
143  return count;
144 }
145 
156 {
157  for(auto &existingTag : m_tags) {
158  if(static_cast<Tag *>(existingTag.get()) == tag) {
159  existingTag->removeAllFields();
160  existingTag->oggParams().removed = true;
161  return true;
162  }
163  }
164  return false;
165 }
166 
178 {
179  for(auto &existingTag : m_tags) {
180  existingTag->removeAllFields();
181  existingTag->oggParams().removed = true;
182  }
183 }
184 
186 {
187  static const string context("parsing OGG bitstream header");
188  // iterate through pages using OggIterator helper class
189  try {
190  // ensure iterator is setup properly
191  for(m_iterator.removeFilter(), m_iterator.reset(); m_iterator; m_iterator.nextPage()) {
192  const OggPage &page = m_iterator.currentPage();
193  if(m_validateChecksums) {
194  if(page.checksum() != OggPage::computeChecksum(stream(), page.startOffset())) {
195  addNotification(NotificationType::Warning, "The denoted checksum of the OGG page at " % ConversionUtilities::numberToString(m_iterator.currentSegmentOffset()) + " does not match the computed checksum.", context);
196  }
197  }
198  OggStream *stream;
199  try {
200  stream = m_tracks[m_streamsBySerialNo.at(page.streamSerialNumber())].get();
201  } catch(const out_of_range &) {
202  // new stream serial number recognized -> add new stream
203  m_streamsBySerialNo[page.streamSerialNumber()] = m_tracks.size();
204  m_tracks.emplace_back(make_unique<OggStream>(*this, m_iterator.currentPageIndex()));
205  stream = m_tracks.back().get();
206  }
207  if(stream->m_currentSequenceNumber != page.sequenceNumber()) {
208  if(stream->m_currentSequenceNumber) {
209  addNotification(NotificationType::Warning, "Page is missing (page sequence number omitted).", context);
210  }
211  stream->m_currentSequenceNumber = page.sequenceNumber() + 1;
212  } else {
213  ++stream->m_currentSequenceNumber;
214  }
215  }
216  } catch(const TruncatedDataException &) {
217  // thrown when page exceeds max size
218  addNotification(NotificationType::Critical, "The OGG file is truncated.", context);
219  } catch(const InvalidDataException &) {
220  // thrown when first 4 byte do not match capture pattern
221  addNotification(NotificationType::Critical, "Capture pattern \"OggS\" at " % numberToString(m_iterator.currentSegmentOffset()) + " expected.", context);
222  }
223 }
224 
226 {
227  // tracks needs to be parsed before because tags are stored at stream level
228  parseTracks();
229  for(auto &comment : m_tags) {
230  OggParameter &params = comment->oggParams();
231  m_iterator.setPageIndex(params.firstPageIndex);
232  m_iterator.setSegmentIndex(params.firstSegmentIndex);
233  switch(params.streamFormat) {
235  comment->parse(m_iterator);
236  break;
238  // skip header (has already been detected by OggStream)
239  m_iterator.ignore(8);
241  break;
243  m_iterator.ignore(4);
245  break;
246  default:
247  addNotification(NotificationType::Critical, "Stream format not supported.", "parsing tags from OGG streams");
248  }
249  params.lastPageIndex = m_iterator.currentPageIndex();
250  params.lastSegmentIndex = m_iterator.currentSegmentIndex();
251  }
252 }
253 
265 void OggContainer::announceComment(std::size_t pageIndex, std::size_t segmentIndex, bool lastMetaDataBlock, GeneralMediaFormat mediaFormat)
266 {
267  m_tags.emplace_back(make_unique<OggVorbisComment>());
268  m_tags.back()->oggParams().set(pageIndex, segmentIndex, lastMetaDataBlock, mediaFormat);
269 }
270 
272 {
273  static const string context("parsing OGG stream");
274  for(auto &stream : m_tracks) {
275  try { // try to parse header
276  stream->parseHeader();
277  if(stream->duration() > m_duration) {
278  m_duration = stream->duration();
279  }
280  } catch(const Failure &) {
281  addNotification(NotificationType::Critical, "Unable to parse stream at " % numberToString(stream->startOffset()) + ".", context);
282  }
283  }
284 }
285 
290 void OggContainer::makeVorbisCommentSegment(stringstream &buffer, CopyHelper<65307> &copyHelper, vector<uint32> &newSegmentSizes, VorbisComment *comment, OggParameter *params)
291 {
292  const auto offset = buffer.tellp();
293  switch(params->streamFormat) {
295  comment->make(buffer);
296  break;
298  ConversionUtilities::BE::getBytes(0x4F70757354616773u, copyHelper.buffer());
299  buffer.write(copyHelper.buffer(), 8);
301  break;
303  // Vorbis comment must be wrapped in "METADATA_BLOCK_HEADER"
305  header.setLast(params->lastMetaDataBlock);
307 
308  // write the header later, when the size is known
309  buffer.write(copyHelper.buffer(), 4);
310 
312 
313  // finally make the header
314  header.setDataSize(buffer.tellp() - offset - 4);
315  if(header.dataSize() > 0xFFFFFF) {
316  addNotification(NotificationType::Critical, "Size of Vorbis comment exceeds size limit for FLAC \"METADATA_BLOCK_HEADER\".", "making Vorbis Comment");
317  }
318  buffer.seekp(offset);
319  header.makeHeader(buffer);
320  buffer.seekp(header.dataSize(), ios_base::cur);
321  break;
322  } default:
323  ;
324  }
325  newSegmentSizes.push_back(buffer.tellp() - offset);
326 }
327 
329 {
330  const string context("making OGG file");
331  updateStatus("Prepare for rewriting OGG file ...");
332  parseTags(); // tags need to be parsed before the file can be rewritten
333  string backupPath;
334  NativeFileStream backupStream;
335 
336  if(fileInfo().saveFilePath().empty()) {
337  // move current file to temp dir and reopen it as backupStream, recreate original file
338  try {
339  BackupHelper::createBackupFile(fileInfo().path(), backupPath, fileInfo().stream(), backupStream);
340  // recreate original file, define buffer variables
341  fileInfo().stream().open(fileInfo().path(), ios_base::out | ios_base::binary | ios_base::trunc);
342  } catch(...) {
343  const char *what = catchIoFailure();
344  addNotification(NotificationType::Critical, "Creation of temporary file (to rewrite the original file) failed.", context);
345  throwIoFailure(what);
346  }
347  } else {
348  // open the current file as backupStream and create a new outputStream at the specified "save file path"
349  try {
350  backupStream.exceptions(ios_base::badbit | ios_base::failbit);
351  backupStream.open(fileInfo().path(), ios_base::in | ios_base::binary);
352  fileInfo().close();
353  fileInfo().stream().open(fileInfo().saveFilePath(), ios_base::out | ios_base::binary | ios_base::trunc);
354  } catch(...) {
355  const char *what = catchIoFailure();
356  addNotification(NotificationType::Critical, "Opening streams to write output file failed.", context);
357  throwIoFailure(what);
358  }
359  }
360 
361  try {
362  // prepare iterating comments
363  OggVorbisComment *currentComment;
364  OggParameter *currentParams;
365  auto tagIterator = m_tags.cbegin(), tagEnd = m_tags.cend();
366  if(tagIterator != tagEnd) {
367  currentParams = &(currentComment = tagIterator->get())->oggParams();
368  } else {
369  currentComment = nullptr;
370  currentParams = nullptr;
371  }
372 
373  // define misc variables
374  CopyHelper<65307> copyHelper;
375  vector<uint64> updatedPageOffsets;
376  unordered_map<uint32, uint32> pageSequenceNumberBySerialNo;
377 
378  // iterate through all pages of the original file
379  for(m_iterator.setStream(backupStream), m_iterator.removeFilter(), m_iterator.reset(); m_iterator; m_iterator.nextPage()) {
380  const OggPage &currentPage = m_iterator.currentPage();
381  const auto pageSize = currentPage.totalSize();
382  uint32 &pageSequenceNumber = pageSequenceNumberBySerialNo[currentPage.streamSerialNumber()];
383  // check whether the Vorbis Comment is present in this Ogg page
384  if(currentComment
385  && m_iterator.currentPageIndex() >= currentParams->firstPageIndex
386  && m_iterator.currentPageIndex() <= currentParams->lastPageIndex
387  && !currentPage.segmentSizes().empty()) {
388  // page needs to be rewritten (not just copied)
389  // -> write segments to a buffer first
390  stringstream buffer(ios_base::in | ios_base::out | ios_base::binary);
391  vector<uint32> newSegmentSizes;
392  newSegmentSizes.reserve(currentPage.segmentSizes().size());
393  uint64 segmentOffset = m_iterator.currentSegmentOffset();
394  vector<uint32>::size_type segmentIndex = 0;
395  for(const auto segmentSize : currentPage.segmentSizes()) {
396  if(segmentSize) {
397  // check whether this segment contains the Vorbis Comment
398  if((m_iterator.currentPageIndex() >= currentParams->firstPageIndex && segmentIndex >= currentParams->firstSegmentIndex)
399  && (m_iterator.currentPageIndex() <= currentParams->lastPageIndex && segmentIndex <= currentParams->lastSegmentIndex)) {
400  // prevent making the comment twice if it spreads over multiple pages/segments
401  if(!currentParams->removed
402  && ((m_iterator.currentPageIndex() == currentParams->firstPageIndex
403  && m_iterator.currentSegmentIndex() == currentParams->firstSegmentIndex))) {
404  makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams);
405  }
406 
407  // proceed with next comment?
408  if(m_iterator.currentPageIndex() > currentParams->lastPageIndex
409  || (m_iterator.currentPageIndex() == currentParams->lastPageIndex && segmentIndex > currentParams->lastSegmentIndex)) {
410  if(++tagIterator != tagEnd) {
411  currentParams = &(currentComment = tagIterator->get())->oggParams();
412  } else {
413  currentComment = nullptr;
414  currentParams = nullptr;
415  }
416  }
417  } else {
418  // copy other segments unchanged
419  backupStream.seekg(segmentOffset);
420  copyHelper.copy(backupStream, buffer, segmentSize);
421  newSegmentSizes.push_back(segmentSize);
422 
423  // check whether there is a new comment to be inserted into the current page
424  if(m_iterator.currentPageIndex() == currentParams->lastPageIndex && currentParams->firstSegmentIndex == static_cast<size_t>(-1)) {
425  if(!currentParams->removed) {
426  makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams);
427  }
428  // proceed with next comment
429  if(++tagIterator != tagEnd) {
430  currentParams = &(currentComment = tagIterator->get())->oggParams();
431  } else {
432  currentComment = nullptr;
433  currentParams = nullptr;
434  }
435  }
436  }
437  segmentOffset += segmentSize;
438  }
439  ++segmentIndex;
440  }
441 
442  // write buffered data to actual stream
443  auto newSegmentSizesIterator = newSegmentSizes.cbegin(), newSegmentSizesEnd = newSegmentSizes.cend();
444  bool continuePreviousSegment = false;
445  if(newSegmentSizesIterator != newSegmentSizesEnd) {
446  uint32 bytesLeft = *newSegmentSizesIterator;
447  // write pages until all data in the buffer is written
448  while(newSegmentSizesIterator != newSegmentSizesEnd) {
449  // write header
450  backupStream.seekg(currentPage.startOffset());
451  updatedPageOffsets.push_back(stream().tellp()); // memorize offset to update checksum later
452  copyHelper.copy(backupStream, stream(), 27); // just copy header from original file
453  // set continue flag
454  stream().seekp(-22, ios_base::cur);
455  stream().put(currentPage.headerTypeFlag() & (continuePreviousSegment ? 0xFF : 0xFE));
456  continuePreviousSegment = true;
457  // adjust page sequence number
458  stream().seekp(12, ios_base::cur);
459  writer().writeUInt32LE(pageSequenceNumber);
460  stream().seekp(5, ios_base::cur);
461  int16 segmentSizesWritten = 0; // in the current page header only
462  // write segment sizes as long as there are segment sizes to be written and
463  // the max number of segment sizes (255) is not exceeded
464  uint32 currentSize = 0;
465  while(bytesLeft && segmentSizesWritten < 0xFF) {
466  while(bytesLeft >= 0xFF && segmentSizesWritten < 0xFF) {
467  stream().put(0xFF);
468  currentSize += 0xFF;
469  bytesLeft -= 0xFF;
470  ++segmentSizesWritten;
471  }
472  if(bytesLeft && segmentSizesWritten < 0xFF) {
473  // bytes left is here < 0xFF
474  stream().put(bytesLeft);
475  currentSize += bytesLeft;
476  bytesLeft = 0;
477  ++segmentSizesWritten;
478  }
479  if(!bytesLeft) {
480  // sizes for the segment have been written
481  // -> continue with next segment
482  if(++newSegmentSizesIterator != newSegmentSizesEnd) {
483  bytesLeft = *newSegmentSizesIterator;
484  continuePreviousSegment = false;
485  }
486  }
487  }
488 
489  // there are no bytes left in the current segment; remove continue flag
490  if(!bytesLeft) {
491  continuePreviousSegment = false;
492  }
493 
494  // page is full or all segment data has been covered
495  // -> write segment table size (segmentSizesWritten) and segment data
496  // -> seek back and write updated page segment number
497  stream().seekp(-1 - segmentSizesWritten, ios_base::cur);
498  stream().put(segmentSizesWritten);
499  stream().seekp(segmentSizesWritten, ios_base::cur);
500  // -> write actual page data
501  copyHelper.copy(buffer, stream(), currentSize);
502 
503  ++pageSequenceNumber;
504  }
505  }
506 
507  } else {
508  if(pageSequenceNumber != m_iterator.currentPageIndex()) {
509  // just update page sequence number
510  backupStream.seekg(currentPage.startOffset());
511  updatedPageOffsets.push_back(stream().tellp()); // memorize offset to update checksum later
512  copyHelper.copy(backupStream, stream(), 27);
513  stream().seekp(-9, ios_base::cur);
514  writer().writeUInt32LE(pageSequenceNumber);
515  stream().seekp(5, ios_base::cur);
516  copyHelper.copy(backupStream, stream(), pageSize - 27);
517  } else {
518  // copy page unchanged
519  backupStream.seekg(currentPage.startOffset());
520  copyHelper.copy(backupStream, stream(), pageSize);
521  }
522  ++pageSequenceNumber;
523  }
524  }
525 
526  // report new size
527  fileInfo().reportSizeChanged(stream().tellp());
528 
529  // "save as path" is now the regular path
530  if(!fileInfo().saveFilePath().empty()) {
531  fileInfo().reportPathChanged(fileInfo().saveFilePath());
532  fileInfo().setSaveFilePath(string());
533  }
534 
535  // close backups stream; reopen new file as readable stream
536  backupStream.close();
537  fileInfo().close();
538  fileInfo().stream().open(fileInfo().path(), ios_base::in | ios_base::out | ios_base::binary);
539 
540  // update checksums of modified pages
541  for(auto offset : updatedPageOffsets) {
543  }
544 
545  // clear iterator
546  m_iterator.clear(fileInfo().stream(), startOffset(), fileInfo().size());
547 
548  } catch(...) {
549  m_iterator.setStream(fileInfo().stream());
550  BackupHelper::handleFailureAfterFileModified(fileInfo(), backupPath, fileInfo().stream(), backupStream, context);
551  }
552 }
553 
554 }
IoUtilities::BinaryWriter & writer()
Returns the related BinaryWriter.
OggVorbisComment * createTag(const TagTarget &target)
Creates a new tag.
GeneralMediaFormat
The GeneralMediaFormat enum specifies the general format of media data (PCM, MPEG-4, PNG, ...).
Definition: mediaformat.h:29
const TagTarget & target() const
Returns the target of tag.
Definition: tag.h:245
std::vector< uint32 >::size_type currentSegmentIndex() const
Returns the index of the current segment (in the current page) if the iterator is valid; otherwise an...
Definition: oggiterator.h:183
Implementation of Media::Tag for Vorbis comments.
Definition: vorbiscomment.h:15
ChronoUtilities::TimeSpan m_duration
MediaFileInfo & fileInfo() const
Returns the related file info.
void internalParseTags()
Internally called to parse the tags.
uint32 checksum() const
Returns the page checksum.
Definition: oggpage.h:189
void removeFilter()
Removes a previously set filter.
Definition: oggiterator.h:242
void internalParseTracks()
Internally called to parse the tracks.
OggParameter & oggParams()
Returns the OGG parameter for the comment.
Definition: oggcontainer.h:111
The FlacMetaDataBlockHeader class is a FLAC "METADATA_BLOCK_HEADER" parser and maker.
Definition: flacmetadata.h:38
The GenericContainer class helps parsing header, track, tag and chapter information of a file...
uint32 sequenceNumber() const
Returns the page sequence number.
Definition: oggpage.h:174
TAG_PARSER_EXPORT void createBackupFile(const std::string &originalPath, std::string &backupPath, IoUtilities::NativeFileStream &originalStream, IoUtilities::NativeFileStream &backupStream)
GeneralMediaFormat general
Definition: mediaformat.h:270
const std::vector< OggPage > & pages() const
Returns a vector of containing the OGG pages that have been fetched yet.
Definition: oggiterator.h:120
void setPageIndex(std::vector< OggPage >::size_type index)
Sets the current page index.
Definition: oggiterator.h:162
Specialization of Media::VorbisComment for Vorbis comments inside an OGG stream.
Definition: oggcontainer.h:68
TAG_PARSER_EXPORT void handleFailureAfterFileModified(MediaFileInfo &mediaFileInfo, const std::string &backupPath, IoUtilities::NativeFileStream &outputStream, IoUtilities::NativeFileStream &backupStream, const std::string &context="making file")
STL namespace.
void ignore(std::size_t count=1)
Advances the position of the next character to be read from the OGG stream by count bytes...
void addNotification(const Notification &notification)
This protected method is meant to be called by the derived class to add a notification.
void reportPathChanged(const std::string &newPath)
Call this function to report that the path changed.
uint32 streamSerialNumber() const
Returns the stream serial number.
Definition: oggpage.h:155
uint32 totalSize() const
Returns the total size of the page in byte.
Definition: oggpage.h:227
void internalMakeFile()
Internally called to make the file.
std::size_t startPage() const
Definition: oggstream.h:33
MediaFormat format() const
Returns the format of the track if known; otherwise returns MediaFormat::Unknown. ...
The OggPage class is used to parse OGG pages.
Definition: oggpage.h:14
uint64 id() const
Returns the track ID if known; otherwise returns 0.
const IdContainerType & tracks() const
Returns the tracks.
Definition: tagtarget.h:113
std::size_t lastSegmentIndex
Definition: oggcontainer.h:36
void setSegmentIndex(std::vector< uint32 >::size_type index)
Sets the current segment index.
Definition: oggiterator.h:174
void close()
A possibly opened std::fstream will be closed.
static void updateChecksum(std::iostream &stream, uint64 startOffset)
Updates the checksum of the page read from the specified stream at the specified startOffset.
Definition: oggpage.cpp:109
IoUtilities::NativeFileStream & stream()
Returns the std::fstream for the current instance.
Definition: basicfileinfo.h:80
void setSaveFilePath(const std::string &saveFilePath)
Sets the "save file path".
GeneralMediaFormat streamFormat
Definition: oggcontainer.h:38
Contains utility classes helping to read and write streams.
uint64 startOffset() const
Returns the start offset in the related stream.
bool removeTag(Tag *tag)
Actually just flags the specified tag as removed and clears all assigned fields.
void makeHeader(std::ostream &outputStream)
Writes the header to the specified outputStream.
void parseTags()
Parses the tag information if not parsed yet.
The exception that is thrown when the data to be parsed or to be made seems invalid and therefore can...
Definition: exceptions.h:27
std::size_t firstPageIndex
Definition: oggcontainer.h:33
std::vector< OggPage >::size_type currentPageIndex() const
Returns the index of the current page if the iterator is valid; otherwise an undefined index is retur...
Definition: oggiterator.h:152
Implementation of Media::AbstractTrack for OGG streams.
Definition: oggstream.h:13
void setStream(std::istream &stream)
Sets the stream.
Definition: oggiterator.h:96
void reset()
Discards all parsing results.
The Tag class is used to store, read and write tag information.
Definition: tag.h:98
byte headerTypeFlag() const
Returns the header type flag.
Definition: oggpage.h:102
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
Definition: exceptions.h:11
uint64 currentSegmentOffset() const
Returns the start offset of the current segment in the input stream if the iterator is valid; otherwi...
Definition: oggiterator.h:192
void reportSizeChanged(uint64 newSize)
Call this function to report that the size changed.
void make(std::ostream &stream, VorbisCommentFlags flags=VorbisCommentFlags::None)
Writes tag information to the specified stream.
void reset()
Resets the iterator to point at the first segment of the first page (matching the filter if set)...
Definition: oggiterator.cpp:42
uint64 startOffset() const
Returns the start offset of the page.
Definition: oggpage.h:83
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
Definition: exceptions.h:35
The MediaFileInfo class allows to read and write tag information providing a container/tag format ind...
Definition: mediafileinfo.h:52
void internalParseHeader()
Internally called to parse the header.
OggVorbisComment * tag(std::size_t index)
Returns the tag with the specified index.
void setLast(byte last)
Sets whether this is the last metadata block before the audio blocks.
Definition: flacmetadata.h:80
const OggPage & currentPage() const
Returns the current OGG page.
Definition: oggiterator.h:129
void nextPage()
Increases the current position by one page.
Definition: oggiterator.cpp:59
static uint32 computeChecksum(std::istream &stream, uint64 startOffset)
Computes the actual checksum of the page read from the specified stream at the specified startOffset...
Definition: oggpage.cpp:75
void removeAllTags()
Actually just flags all tags as removed and clears all assigned fields.
void updateStatus(const std::string &status)
This method is meant to be called by the derived class to report updated status information.
std::size_t firstSegmentIndex
Definition: oggcontainer.h:34
The TagTarget class specifies the target of a tag.
Definition: tagtarget.h:31
Contains all classes and functions of the TagInfo library.
Definition: exceptions.h:9
The OggParameter struct holds the OGG parameter for a VorbisComment.
Definition: oggcontainer.h:28
void clear(std::istream &stream, uint64 startOffset, uint64 streamSize)
Sets the stream and related parameters and clears all available pages.
Definition: oggiterator.cpp:28
uint32 dataSize() const
Returns the length in bytes of the meta data (excluding the size of the header itself).
Definition: flacmetadata.h:105
std::iostream & stream()
Returns the related stream.
std::size_t lastPageIndex
Definition: oggcontainer.h:35
std::size_t tagCount() const
Returns the number of tags attached to the container.
void parseTracks()
Parses the tracks of the file if not parsed yet.
TAG_PARSER_EXPORT const char * comment()
const std::vector< uint32 > & segmentSizes() const
Returns the sizes of the segments of the page in byte.
Definition: oggpage.h:209
void setType(FlacMetaDataBlockType type)
Sets the block type.
Definition: flacmetadata.h:97
void setDataSize(uint32 dataSize)
Sets the length in bytes of the meta data (excluding the size of the header itself).
Definition: flacmetadata.h:114