Tag Parser  6.1.1
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/io/copy.h>
9 #include <c++utilities/io/catchiofailure.h>
10 #include <c++utilities/misc/memory.h>
11 
12 using namespace std;
13 using namespace IoUtilities;
14 
15 namespace Media {
16 
22 const char *OggVorbisComment::typeName() const
23 {
24  switch(m_oggParams.streamFormat) {
26  return "Vorbis comment (in FLAC stream)";
27  case GeneralMediaFormat::Opus:
28  return "Vorbis comment (in Opus stream)";
29  case GeneralMediaFormat::Theora:
30  return "Vorbis comment (in Theora stream)";
31  default:
32  return "Vorbis comment";
33  }
34 }
35 
44 OggContainer::OggContainer(MediaFileInfo &fileInfo, uint64 startOffset) :
46  m_iterator(fileInfo.stream(), startOffset, fileInfo.size()),
47  m_validateChecksums(false)
48 {}
49 
51 {}
52 
54 {
55  m_iterator.reset();
56 }
57 
69 {
70  if(!target.tracks().empty()) {
71  // return the tag for the first matching track ID
72  for(auto &tag : m_tags) {
73  if(!tag->target().tracks().empty() && tag->target().tracks().front() == target.tracks().front() && !tag->oggParams().removed) {
74  return tag.get();
75  }
76  }
77  // not tag found -> try to re-use a tag which has been flagged as removed
78  for(auto &tag : m_tags) {
79  if(!tag->target().tracks().empty() && tag->target().tracks().front() == target.tracks().front()) {
80  tag->oggParams().removed = false;
81  return tag.get();
82  }
83  }
84  } else if(OggVorbisComment *comment = tag(0)) {
85  // no track ID specified -> just return the first tag (if one exists)
86  return comment;
87  } else if(!m_tags.empty()) {
88  // no track ID specified -> just return the first tag (try to re-use a tag which has been flagged as removed)
89  m_tags.front()->oggParams().removed = false;
90  return m_tags.front().get();
91  }
92 
93  // a new tag needs to be created
94  // -> determine an appropriate track for the tag
95  // -> just use the first Vorbis/Opus track
96  for(const auto &track : m_tracks) {
97  if(target.tracks().empty() || target.tracks().front() == track->id()) {
98  switch(track->format().general) {
101  // check whether start page has a valid value
102  if(track->startPage() < m_iterator.pages().size()) {
103  announceComment(track->startPage(), static_cast<size_t>(-1), false, track->format().general);
104  m_tags.back()->setTarget(target);
105  return m_tags.back().get();
106  } else {
107  // TODO: error handling?
108  }
109  default:
110  ;
111  }
112  // TODO: allow adding tags to FLAC tracks (not really important, because a tag should always be present)
113  }
114  }
115  return nullptr;
116 }
117 
119 {
120  size_t i = 0;
121  for(const auto &tag : m_tags) {
122  if(!tag->oggParams().removed) {
123  if(index == i) {
124  return tag.get();
125  }
126  ++i;
127  }
128  }
129  return nullptr;
130 }
131 
133 {
134  size_t count = 0;
135  for(const auto &tag : m_tags) {
136  if(!tag->oggParams().removed) {
137  ++count;
138  }
139  }
140  return count;
141 }
142 
153 {
154  for(auto &existingTag : m_tags) {
155  if(static_cast<Tag *>(existingTag.get()) == tag) {
156  existingTag->removeAllFields();
157  existingTag->oggParams().removed = true;
158  return true;
159  }
160  }
161  return false;
162 }
163 
175 {
176  for(auto &existingTag : m_tags) {
177  existingTag->removeAllFields();
178  existingTag->oggParams().removed = true;
179  }
180 }
181 
183 {
184  static const string context("parsing OGG bitstream header");
185  // iterate through pages using OggIterator helper class
186  try {
187  // ensure iterator is setup properly
188  for(m_iterator.removeFilter(), m_iterator.reset(); m_iterator; m_iterator.nextPage()) {
189  const OggPage &page = m_iterator.currentPage();
190  if(m_validateChecksums) {
191  if(page.checksum() != OggPage::computeChecksum(stream(), page.startOffset())) {
192  addNotification(NotificationType::Warning, "The denoted checksum of the OGG page at " + ConversionUtilities::numberToString(m_iterator.currentSegmentOffset()) + " does not match the computed checksum.", context);
193  }
194  }
195  OggStream *stream;
196  try {
197  stream = m_tracks[m_streamsBySerialNo.at(page.streamSerialNumber())].get();
198  } catch(const out_of_range &) {
199  // new stream serial number recognized -> add new stream
200  m_streamsBySerialNo[page.streamSerialNumber()] = m_tracks.size();
201  m_tracks.emplace_back(make_unique<OggStream>(*this, m_iterator.currentPageIndex()));
202  stream = m_tracks.back().get();
203  }
204  if(stream->m_currentSequenceNumber != page.sequenceNumber()) {
205  if(stream->m_currentSequenceNumber) {
206  addNotification(NotificationType::Warning, "Page is missing (page sequence number omitted).", context);
207  }
208  stream->m_currentSequenceNumber = page.sequenceNumber() + 1;
209  } else {
210  ++stream->m_currentSequenceNumber;
211  }
212  }
213  } catch(const TruncatedDataException &) {
214  // thrown when page exceeds max size
215  addNotification(NotificationType::Critical, "The OGG file is truncated.", context);
216  } catch(const InvalidDataException &) {
217  // thrown when first 4 byte do not match capture pattern
218  addNotification(NotificationType::Critical, "Capture pattern \"OggS\" at " + ConversionUtilities::numberToString(m_iterator.currentSegmentOffset()) + " expected.", context);
219  }
220 }
221 
223 {
224  // tracks needs to be parsed before because tags are stored at stream level
225  parseTracks();
226  for(auto &comment : m_tags) {
227  OggParameter &params = comment->oggParams();
228  m_iterator.setPageIndex(params.firstPageIndex);
229  m_iterator.setSegmentIndex(params.firstSegmentIndex);
230  switch(params.streamFormat) {
232  comment->parse(m_iterator);
233  break;
235  // skip header (has already been detected by OggStream)
236  m_iterator.ignore(8);
238  break;
240  m_iterator.ignore(4);
242  break;
243  default:
244  addNotification(NotificationType::Critical, "Stream format not supported.", "parsing tags from OGG streams");
245  }
246  params.lastPageIndex = m_iterator.currentPageIndex();
247  params.lastSegmentIndex = m_iterator.currentSegmentIndex();
248  }
249 }
250 
262 void OggContainer::announceComment(std::size_t pageIndex, std::size_t segmentIndex, bool lastMetaDataBlock, GeneralMediaFormat mediaFormat)
263 {
264  m_tags.emplace_back(make_unique<OggVorbisComment>());
265  m_tags.back()->oggParams().set(pageIndex, segmentIndex, lastMetaDataBlock, mediaFormat);
266 }
267 
269 {
270  static const string context("parsing OGG stream");
271  for(auto &stream : m_tracks) {
272  try { // try to parse header
273  stream->parseHeader();
274  if(stream->duration() > m_duration) {
275  m_duration = stream->duration();
276  }
277  } catch(const Failure &) {
278  addNotification(NotificationType::Critical, "Unable to parse stream at " + ConversionUtilities::numberToString(stream->startOffset()) + ".", context);
279  }
280  }
281 }
282 
287 void OggContainer::makeVorbisCommentSegment(stringstream &buffer, CopyHelper<65307> &copyHelper, vector<uint32> &newSegmentSizes, VorbisComment *comment, OggParameter *params)
288 {
289  const auto offset = buffer.tellp();
290  switch(params->streamFormat) {
292  comment->make(buffer);
293  break;
295  ConversionUtilities::BE::getBytes(0x4F70757354616773u, copyHelper.buffer());
296  buffer.write(copyHelper.buffer(), 8);
298  break;
300  // Vorbis comment must be wrapped in "METADATA_BLOCK_HEADER"
302  header.setLast(params->lastMetaDataBlock);
304 
305  // write the header later, when the size is known
306  buffer.write(copyHelper.buffer(), 4);
307 
309 
310  // finally make the header
311  header.setDataSize(buffer.tellp() - offset - 4);
312  if(header.dataSize() > 0xFFFFFF) {
313  addNotification(NotificationType::Critical, "Size of Vorbis comment exceeds size limit for FLAC \"METADATA_BLOCK_HEADER\".", "making Vorbis Comment");
314  }
315  buffer.seekp(offset);
316  header.makeHeader(buffer);
317  buffer.seekp(header.dataSize(), ios_base::cur);
318  break;
319  } default:
320  ;
321  }
322  newSegmentSizes.push_back(buffer.tellp() - offset);
323 }
324 
326 {
327  const string context("making OGG file");
328  updateStatus("Prepare for rewriting OGG file ...");
329  parseTags(); // tags need to be parsed before the file can be rewritten
330  string backupPath;
331  NativeFileStream backupStream;
332 
333  if(fileInfo().saveFilePath().empty()) {
334  // move current file to temp dir and reopen it as backupStream, recreate original file
335  try {
336  BackupHelper::createBackupFile(fileInfo().path(), backupPath, fileInfo().stream(), backupStream);
337  // recreate original file, define buffer variables
338  fileInfo().stream().open(fileInfo().path(), ios_base::out | ios_base::binary | ios_base::trunc);
339  } catch(...) {
340  const char *what = catchIoFailure();
341  addNotification(NotificationType::Critical, "Creation of temporary file (to rewrite the original file) failed.", context);
342  throwIoFailure(what);
343  }
344  } else {
345  // open the current file as backupStream and create a new outputStream at the specified "save file path"
346  try {
347  backupStream.exceptions(ios_base::badbit | ios_base::failbit);
348  backupStream.open(fileInfo().path(), ios_base::in | ios_base::binary);
349  fileInfo().close();
350  fileInfo().stream().open(fileInfo().saveFilePath(), ios_base::out | ios_base::binary | ios_base::trunc);
351  } catch(...) {
352  const char *what = catchIoFailure();
353  addNotification(NotificationType::Critical, "Opening streams to write output file failed.", context);
354  throwIoFailure(what);
355  }
356  }
357 
358  try {
359  // prepare iterating comments
360  OggVorbisComment *currentComment;
361  OggParameter *currentParams;
362  auto tagIterator = m_tags.cbegin(), tagEnd = m_tags.cend();
363  if(tagIterator != tagEnd) {
364  currentParams = &(currentComment = tagIterator->get())->oggParams();
365  } else {
366  currentComment = nullptr;
367  currentParams = nullptr;
368  }
369 
370  // define misc variables
371  CopyHelper<65307> copyHelper;
372  vector<uint64> updatedPageOffsets;
373  unordered_map<uint32, uint32> pageSequenceNumberBySerialNo;
374 
375  // iterate through all pages of the original file
376  for(m_iterator.setStream(backupStream), m_iterator.removeFilter(), m_iterator.reset(); m_iterator; m_iterator.nextPage()) {
377  const OggPage &currentPage = m_iterator.currentPage();
378  const auto pageSize = currentPage.totalSize();
379  uint32 &pageSequenceNumber = pageSequenceNumberBySerialNo[currentPage.streamSerialNumber()];
380  // check whether the Vorbis Comment is present in this Ogg page
381  if(currentComment
382  && m_iterator.currentPageIndex() >= currentParams->firstPageIndex
383  && m_iterator.currentPageIndex() <= currentParams->lastPageIndex
384  && !currentPage.segmentSizes().empty()) {
385  // page needs to be rewritten (not just copied)
386  // -> write segments to a buffer first
387  stringstream buffer(ios_base::in | ios_base::out | ios_base::binary);
388  vector<uint32> newSegmentSizes;
389  newSegmentSizes.reserve(currentPage.segmentSizes().size());
390  uint64 segmentOffset = m_iterator.currentSegmentOffset();
391  vector<uint32>::size_type segmentIndex = 0;
392  for(const auto segmentSize : currentPage.segmentSizes()) {
393  if(segmentSize) {
394  // check whether this segment contains the Vorbis Comment
395  if((m_iterator.currentPageIndex() >= currentParams->firstPageIndex && segmentIndex >= currentParams->firstSegmentIndex)
396  && (m_iterator.currentPageIndex() <= currentParams->lastPageIndex && segmentIndex <= currentParams->lastSegmentIndex)) {
397  // prevent making the comment twice if it spreads over multiple pages/segments
398  if(!currentParams->removed
399  && ((m_iterator.currentPageIndex() == currentParams->firstPageIndex
400  && m_iterator.currentSegmentIndex() == currentParams->firstSegmentIndex))) {
401  makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams);
402  }
403 
404  // proceed with next comment?
405  if(m_iterator.currentPageIndex() > currentParams->lastPageIndex
406  || (m_iterator.currentPageIndex() == currentParams->lastPageIndex && segmentIndex > currentParams->lastSegmentIndex)) {
407  if(++tagIterator != tagEnd) {
408  currentParams = &(currentComment = tagIterator->get())->oggParams();
409  } else {
410  currentComment = nullptr;
411  currentParams = nullptr;
412  }
413  }
414  } else {
415  // copy other segments unchanged
416  backupStream.seekg(segmentOffset);
417  copyHelper.copy(backupStream, buffer, segmentSize);
418  newSegmentSizes.push_back(segmentSize);
419 
420  // check whether there is a new comment to be inserted into the current page
421  if(m_iterator.currentPageIndex() == currentParams->lastPageIndex && currentParams->firstSegmentIndex == static_cast<size_t>(-1)) {
422  if(!currentParams->removed) {
423  makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams);
424  }
425  // proceed with next comment
426  if(++tagIterator != tagEnd) {
427  currentParams = &(currentComment = tagIterator->get())->oggParams();
428  } else {
429  currentComment = nullptr;
430  currentParams = nullptr;
431  }
432  }
433  }
434  segmentOffset += segmentSize;
435  }
436  ++segmentIndex;
437  }
438 
439  // write buffered data to actual stream
440  auto newSegmentSizesIterator = newSegmentSizes.cbegin(), newSegmentSizesEnd = newSegmentSizes.cend();
441  bool continuePreviousSegment = false;
442  if(newSegmentSizesIterator != newSegmentSizesEnd) {
443  uint32 bytesLeft = *newSegmentSizesIterator;
444  // write pages until all data in the buffer is written
445  while(newSegmentSizesIterator != newSegmentSizesEnd) {
446  // write header
447  backupStream.seekg(currentPage.startOffset());
448  updatedPageOffsets.push_back(stream().tellp()); // memorize offset to update checksum later
449  copyHelper.copy(backupStream, stream(), 27); // just copy header from original file
450  // set continue flag
451  stream().seekp(-22, ios_base::cur);
452  stream().put(currentPage.headerTypeFlag() & (continuePreviousSegment ? 0xFF : 0xFE));
453  continuePreviousSegment = true;
454  // adjust page sequence number
455  stream().seekp(12, ios_base::cur);
456  writer().writeUInt32LE(pageSequenceNumber);
457  stream().seekp(5, ios_base::cur);
458  int16 segmentSizesWritten = 0; // in the current page header only
459  // write segment sizes as long as there are segment sizes to be written and
460  // the max number of segment sizes (255) is not exceeded
461  uint32 currentSize = 0;
462  while(bytesLeft && segmentSizesWritten < 0xFF) {
463  while(bytesLeft >= 0xFF && segmentSizesWritten < 0xFF) {
464  stream().put(0xFF);
465  currentSize += 0xFF;
466  bytesLeft -= 0xFF;
467  ++segmentSizesWritten;
468  }
469  if(bytesLeft && segmentSizesWritten < 0xFF) {
470  // bytes left is here < 0xFF
471  stream().put(bytesLeft);
472  currentSize += bytesLeft;
473  bytesLeft = 0;
474  ++segmentSizesWritten;
475  }
476  if(!bytesLeft) {
477  // sizes for the segment have been written
478  // -> continue with next segment
479  if(++newSegmentSizesIterator != newSegmentSizesEnd) {
480  bytesLeft = *newSegmentSizesIterator;
481  continuePreviousSegment = false;
482  }
483  }
484  }
485 
486  // there are no bytes left in the current segment; remove continue flag
487  if(!bytesLeft) {
488  continuePreviousSegment = false;
489  }
490 
491  // page is full or all segment data has been covered
492  // -> write segment table size (segmentSizesWritten) and segment data
493  // -> seek back and write updated page segment number
494  stream().seekp(-1 - segmentSizesWritten, ios_base::cur);
495  stream().put(segmentSizesWritten);
496  stream().seekp(segmentSizesWritten, ios_base::cur);
497  // -> write actual page data
498  copyHelper.copy(buffer, stream(), currentSize);
499 
500  ++pageSequenceNumber;
501  }
502  }
503 
504  } else {
505  if(pageSequenceNumber != m_iterator.currentPageIndex()) {
506  // just update page sequence number
507  backupStream.seekg(currentPage.startOffset());
508  updatedPageOffsets.push_back(stream().tellp()); // memorize offset to update checksum later
509  copyHelper.copy(backupStream, stream(), 27);
510  stream().seekp(-9, ios_base::cur);
511  writer().writeUInt32LE(pageSequenceNumber);
512  stream().seekp(5, ios_base::cur);
513  copyHelper.copy(backupStream, stream(), pageSize - 27);
514  } else {
515  // copy page unchanged
516  backupStream.seekg(currentPage.startOffset());
517  copyHelper.copy(backupStream, stream(), pageSize);
518  }
519  ++pageSequenceNumber;
520  }
521  }
522 
523  // report new size
524  fileInfo().reportSizeChanged(stream().tellp());
525 
526  // "save as path" is now the regular path
527  if(!fileInfo().saveFilePath().empty()) {
528  fileInfo().reportPathChanged(fileInfo().saveFilePath());
529  fileInfo().setSaveFilePath(string());
530  }
531 
532  // close backups stream; reopen new file as readable stream
533  backupStream.close();
534  fileInfo().close();
535  fileInfo().stream().open(fileInfo().path(), ios_base::in | ios_base::out | ios_base::binary);
536 
537  // update checksums of modified pages
538  for(auto offset : updatedPageOffsets) {
540  }
541 
542  // clear iterator
543  m_iterator.clear(fileInfo().stream(), startOffset(), fileInfo().size());
544 
545  } catch(...) {
546  m_iterator.setStream(fileInfo().stream());
547  BackupHelper::handleFailureAfterFileModified(fileInfo(), backupPath, fileInfo().stream(), backupStream, context);
548  }
549 }
550 
551 }
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:269
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