Tag Parser  9.1.3
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 "../backuphelper.h"
6 #include "../mediafileinfo.h"
7 #include "../progressfeedback.h"
8 
9 #include <c++utilities/conversion/stringbuilder.h>
10 #include <c++utilities/io/copy.h>
11 
12 #include <memory>
13 
14 using namespace std;
15 using namespace CppUtilities;
16 
17 namespace TagParser {
18 
24 const char *OggVorbisComment::typeName() const
25 {
26  switch (m_oggParams.streamFormat) {
28  return "Vorbis comment (in FLAC stream)";
30  return "Vorbis comment (in Opus stream)";
31  case GeneralMediaFormat::Theora:
32  return "Vorbis comment (in Theora stream)";
33  default:
34  return "Vorbis comment";
35  }
36 }
37 
46 OggContainer::OggContainer(MediaFileInfo &fileInfo, std::uint64_t startOffset)
48  , m_iterator(fileInfo.stream(), startOffset, fileInfo.size())
49  , m_validateChecksums(false)
50 {
51 }
52 
54 {
55 }
56 
58 {
59  m_iterator.reset();
60 }
61 
73 {
74  if (!target.tracks().empty()) {
75  // return the tag for the first matching track ID
76  for (auto &tag : m_tags) {
77  if (!tag->target().tracks().empty() && tag->target().tracks().front() == target.tracks().front() && !tag->oggParams().removed) {
78  return tag.get();
79  }
80  }
81  // not tag found -> try to re-use a tag which has been flagged as removed
82  for (auto &tag : m_tags) {
83  if (!tag->target().tracks().empty() && tag->target().tracks().front() == target.tracks().front()) {
84  tag->oggParams().removed = false;
85  return tag.get();
86  }
87  }
88  } else if (OggVorbisComment *comment = tag(0)) {
89  // no track ID specified -> just return the first tag (if one exists)
90  return comment;
91  } else if (!m_tags.empty()) {
92  // no track ID specified -> just return the first tag (try to re-use a tag which has been flagged as removed)
93  m_tags.front()->oggParams().removed = false;
94  return m_tags.front().get();
95  }
96 
97  // a new tag needs to be created
98  // -> determine an appropriate track for the tag
99  // -> just use the first Vorbis/Opus track
100  for (const auto &track : m_tracks) {
101  if (target.tracks().empty() || target.tracks().front() == track->id()) {
102  switch (track->format().general) {
105  // check whether start page has a valid value
106  if (track->startPage() < m_iterator.pages().size()) {
107  announceComment(track->startPage(), numeric_limits<size_t>::max(), false, track->format().general);
108  m_tags.back()->setTarget(target);
109  return m_tags.back().get();
110  } else {
111  // TODO: error handling?
112  }
113  break;
114  default:;
115  }
116  // TODO: allow adding tags to FLAC tracks (not really important, because a tag should always be present)
117  }
118  }
119  return nullptr;
120 }
121 
123 {
124  size_t i = 0;
125  for (const auto &tag : m_tags) {
126  if (!tag->oggParams().removed) {
127  if (index == i) {
128  return tag.get();
129  }
130  ++i;
131  }
132  }
133  return nullptr;
134 }
135 
137 {
138  size_t count = 0;
139  for (const auto &tag : m_tags) {
140  if (!tag->oggParams().removed) {
141  ++count;
142  }
143  }
144  return count;
145 }
146 
157 {
158  for (auto &existingTag : m_tags) {
159  if (static_cast<Tag *>(existingTag.get()) == tag) {
160  existingTag->removeAllFields();
161  existingTag->oggParams().removed = true;
162  return true;
163  }
164  }
165  return false;
166 }
167 
179 {
180  for (auto &existingTag : m_tags) {
181  existingTag->removeAllFields();
182  existingTag->oggParams().removed = true;
183  }
184 }
185 
187 {
188  static const string context("parsing OGG bitstream header");
189  bool pagesSkipped = false;
190 
191  // iterate through pages using OggIterator helper class
192  try {
193  // ensure iterator is setup properly
194  for (m_iterator.removeFilter(), m_iterator.reset(); m_iterator; m_iterator.nextPage()) {
195  const OggPage &page = m_iterator.currentPage();
196  if (m_validateChecksums && page.checksum() != OggPage::computeChecksum(stream(), page.startOffset())) {
197  diag.emplace_back(DiagLevel::Warning,
198  argsToString(
199  "The denoted checksum of the OGG page at ", m_iterator.currentSegmentOffset(), " does not match the computed checksum."),
200  context);
201  }
202  OggStream *stream;
203  std::uint64_t lastNewStreamOffset = 0;
204  try {
205  stream = m_tracks[m_streamsBySerialNo.at(page.streamSerialNumber())].get();
206  stream->m_size += page.dataSize();
207  } catch (const out_of_range &) {
208  // new stream serial number recognized -> add new stream
209  m_streamsBySerialNo[page.streamSerialNumber()] = m_tracks.size();
210  m_tracks.emplace_back(make_unique<OggStream>(*this, m_iterator.currentPageIndex()));
211  stream = m_tracks.back().get();
212  lastNewStreamOffset = page.startOffset();
213  }
214  if (stream->m_currentSequenceNumber != page.sequenceNumber()) {
215  if (stream->m_currentSequenceNumber) {
216  diag.emplace_back(DiagLevel::Warning, "Page is missing (page sequence number omitted).", context);
217  }
218  stream->m_currentSequenceNumber = page.sequenceNumber() + 1;
219  } else {
220  ++stream->m_currentSequenceNumber;
221  }
222 
223  // skip pages in the middle of a big file (still more than 100 MiB to parse) if no new track has been seen since the last 20 MiB
224  if (!fileInfo().isForcingFullParse() && (fileInfo().size() - page.startOffset()) > (100 * 0x100000)
225  && (page.startOffset() - lastNewStreamOffset) > (20 * 0x100000)) {
226  if (m_iterator.resyncAt(fileInfo().size() - (20 * 0x100000))) {
227  const OggPage &resyncedPage = m_iterator.currentPage();
228  // prevent warning about missing pages
229  stream->m_currentSequenceNumber = resyncedPage.sequenceNumber() + 1;
230  pagesSkipped = true;
231  diag.emplace_back(DiagLevel::Information,
232  argsToString("Pages in the middle of the file (", dataSizeToString(resyncedPage.startOffset() - page.startOffset()),
233  ") have been skipped to improve parsing speed. Hence track sizes can not be computed. Maybe not even all tracks could be "
234  "detected. Force a full parse to prevent this."),
235  context);
236  } else {
237  // abort if skipping pages didn't work
238  diag.emplace_back(DiagLevel::Critical,
239  "Unable to re-sync after skipping OGG pages in the middle of the file. Try forcing a full parse.", context);
240  return;
241  }
242  }
243  }
244  } catch (const TruncatedDataException &) {
245  // thrown when page exceeds max size
246  diag.emplace_back(DiagLevel::Critical, "The OGG file is truncated.", context);
247  } catch (const InvalidDataException &) {
248  // thrown when first 4 byte do not match capture pattern
249  diag.emplace_back(
250  DiagLevel::Critical, argsToString("Capture pattern \"OggS\" at ", m_iterator.currentSegmentOffset(), " expected."), context);
251  }
252 
253  // invalidate stream sizes in case pages have been skipped
254  if (pagesSkipped) {
255  for (auto &stream : m_tracks) {
256  stream->m_size = 0;
257  }
258  }
259 }
260 
262 {
263  // tracks needs to be parsed before because tags are stored at stream level
264  parseTracks(diag);
265  for (auto &comment : m_tags) {
266  OggParameter &params = comment->oggParams();
267  m_iterator.setPageIndex(params.firstPageIndex);
268  m_iterator.setSegmentIndex(params.firstSegmentIndex);
269  switch (params.streamFormat) {
271  comment->parse(m_iterator, VorbisCommentFlags::None, diag);
272  break;
274  // skip header (has already been detected by OggStream)
275  m_iterator.ignore(8);
277  break;
279  m_iterator.ignore(4);
281  break;
282  default:
283  diag.emplace_back(DiagLevel::Critical, "Stream format not supported.", "parsing tags from OGG streams");
284  }
285  params.lastPageIndex = m_iterator.currentPageIndex();
286  params.lastSegmentIndex = m_iterator.currentSegmentIndex();
287  }
288 }
289 
301 void OggContainer::announceComment(std::size_t pageIndex, std::size_t segmentIndex, bool lastMetaDataBlock, GeneralMediaFormat mediaFormat)
302 {
303  m_tags.emplace_back(make_unique<OggVorbisComment>());
304  m_tags.back()->oggParams().set(pageIndex, segmentIndex, lastMetaDataBlock, mediaFormat);
305 }
306 
308 {
309  static const string context("parsing OGG stream");
310  for (auto &stream : m_tracks) {
311  try { // try to parse header
312  stream->parseHeader(diag);
313  if (stream->duration() > m_duration) {
314  m_duration = stream->duration();
315  }
316  } catch (const Failure &) {
317  diag.emplace_back(DiagLevel::Critical, argsToString("Unable to parse stream at ", stream->startOffset(), '.'), context);
318  }
319  }
320 }
321 
326 void OggContainer::makeVorbisCommentSegment(stringstream &buffer, CopyHelper<65307> &copyHelper, vector<std::uint32_t> &newSegmentSizes,
328 {
329  const auto offset = buffer.tellp();
330  switch (params->streamFormat) {
332  comment->make(buffer, VorbisCommentFlags::None, diag);
333  break;
335  BE::getBytes(static_cast<std::uint64_t>(0x4F70757354616773u), copyHelper.buffer());
336  buffer.write(copyHelper.buffer(), 8);
338  break;
340  // Vorbis comment must be wrapped in "METADATA_BLOCK_HEADER"
342  header.setLast(params->lastMetaDataBlock);
344 
345  // write the header later, when the size is known
346  buffer.write(copyHelper.buffer(), 4);
347 
349 
350  // finally make the header
351  header.setDataSize(static_cast<std::uint32_t>(buffer.tellp() - offset - 4));
352  if (header.dataSize() > 0xFFFFFF) {
353  diag.emplace_back(
354  DiagLevel::Critical, "Size of Vorbis comment exceeds size limit for FLAC \"METADATA_BLOCK_HEADER\".", "making Vorbis Comment");
355  }
356  buffer.seekp(offset);
357  header.makeHeader(buffer);
358  buffer.seekp(header.dataSize(), ios_base::cur);
359  break;
360  }
361  default:;
362  }
363  newSegmentSizes.push_back(static_cast<std::uint32_t>(buffer.tellp() - offset));
364 }
365 
367 {
368  const string context("making OGG file");
369  progress.updateStep("Prepare for rewriting OGG file ...");
370  parseTags(diag); // tags need to be parsed before the file can be rewritten
371  string backupPath;
372  NativeFileStream backupStream;
373 
374  if (fileInfo().saveFilePath().empty()) {
375  // move current file to temp dir and reopen it as backupStream, recreate original file
376  try {
377  BackupHelper::createBackupFile(fileInfo().backupDirectory(), fileInfo().path(), backupPath, fileInfo().stream(), backupStream);
378  // recreate original file, define buffer variables
379  fileInfo().stream().open(BasicFileInfo::pathForOpen(fileInfo().path()), ios_base::out | ios_base::binary | ios_base::trunc);
380  } catch (const std::ios_base::failure &failure) {
381  diag.emplace_back(
382  DiagLevel::Critical, argsToString("Creation of temporary file (to rewrite the original file) failed: ", failure.what()), context);
383  throw;
384  }
385  } else {
386  // open the current file as backupStream and create a new outputStream at the specified "save file path"
387  try {
388  backupStream.exceptions(ios_base::badbit | ios_base::failbit);
389  backupStream.open(BasicFileInfo::pathForOpen(fileInfo().path()), ios_base::in | ios_base::binary);
390  fileInfo().close();
391  fileInfo().stream().open(BasicFileInfo::pathForOpen(fileInfo().saveFilePath()), ios_base::out | ios_base::binary | ios_base::trunc);
392  } catch (const std::ios_base::failure &failure) {
393  diag.emplace_back(DiagLevel::Critical, argsToString("Opening streams to write output file failed: ", failure.what()), context);
394  throw;
395  }
396  }
397 
398  try {
399  // prepare iterating comments
400  OggVorbisComment *currentComment;
401  OggParameter *currentParams;
402  auto tagIterator = m_tags.cbegin(), tagEnd = m_tags.cend();
403  if (tagIterator != tagEnd) {
404  currentParams = &(currentComment = tagIterator->get())->oggParams();
405  } else {
406  currentComment = nullptr;
407  currentParams = nullptr;
408  }
409 
410  // define misc variables
411  CopyHelper<65307> copyHelper;
412  vector<std::uint64_t> updatedPageOffsets;
413  unordered_map<std::uint32_t, std::uint32_t> pageSequenceNumberBySerialNo;
414 
415  // iterate through all pages of the original file
416  for (m_iterator.setStream(backupStream), m_iterator.removeFilter(), m_iterator.reset(); m_iterator; m_iterator.nextPage()) {
417  const OggPage &currentPage = m_iterator.currentPage();
418  const auto pageSize = currentPage.totalSize();
419  std::uint32_t &pageSequenceNumber = pageSequenceNumberBySerialNo[currentPage.streamSerialNumber()];
420  // check whether the Vorbis Comment is present in this Ogg page
421  if (currentComment && m_iterator.currentPageIndex() >= currentParams->firstPageIndex
422  && m_iterator.currentPageIndex() <= currentParams->lastPageIndex && !currentPage.segmentSizes().empty()) {
423  // page needs to be rewritten (not just copied)
424  // -> write segments to a buffer first
425  stringstream buffer(ios_base::in | ios_base::out | ios_base::binary);
426  vector<std::uint32_t> newSegmentSizes;
427  newSegmentSizes.reserve(currentPage.segmentSizes().size());
428  std::uint64_t segmentOffset = m_iterator.currentSegmentOffset();
429  vector<std::uint32_t>::size_type segmentIndex = 0;
430  for (const auto segmentSize : currentPage.segmentSizes()) {
431  if (!segmentSize) {
432  ++segmentIndex;
433  continue;
434  }
435  // check whether this segment contains the Vorbis Comment
436  if ((m_iterator.currentPageIndex() >= currentParams->firstPageIndex && segmentIndex >= currentParams->firstSegmentIndex)
437  && (m_iterator.currentPageIndex() <= currentParams->lastPageIndex && segmentIndex <= currentParams->lastSegmentIndex)) {
438  // prevent making the comment twice if it spreads over multiple pages/segments
439  if (!currentParams->removed
440  && ((m_iterator.currentPageIndex() == currentParams->firstPageIndex
441  && m_iterator.currentSegmentIndex() == currentParams->firstSegmentIndex))) {
442  makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams, diag);
443  }
444 
445  // proceed with next comment?
446  if (m_iterator.currentPageIndex() > currentParams->lastPageIndex
447  || (m_iterator.currentPageIndex() == currentParams->lastPageIndex && segmentIndex > currentParams->lastSegmentIndex)) {
448  if (++tagIterator != tagEnd) {
449  currentParams = &(currentComment = tagIterator->get())->oggParams();
450  } else {
451  currentComment = nullptr;
452  currentParams = nullptr;
453  }
454  }
455  } else {
456  // copy other segments unchanged
457  backupStream.seekg(static_cast<streamoff>(segmentOffset));
458  copyHelper.copy(backupStream, buffer, segmentSize);
459  newSegmentSizes.push_back(segmentSize);
460 
461  // check whether there is a new comment to be inserted into the current page
462  if (m_iterator.currentPageIndex() == currentParams->lastPageIndex
463  && currentParams->firstSegmentIndex == numeric_limits<size_t>::max()) {
464  if (!currentParams->removed) {
465  makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams, diag);
466  }
467  // proceed with next comment
468  if (++tagIterator != tagEnd) {
469  currentParams = &(currentComment = tagIterator->get())->oggParams();
470  } else {
471  currentComment = nullptr;
472  currentParams = nullptr;
473  }
474  }
475  }
476  segmentOffset += segmentSize;
477  ++segmentIndex;
478  }
479 
480  // write buffered data to actual stream
481  auto newSegmentSizesIterator = newSegmentSizes.cbegin(), newSegmentSizesEnd = newSegmentSizes.cend();
482  bool continuePreviousSegment = false;
483  if (newSegmentSizesIterator != newSegmentSizesEnd) {
484  std::uint32_t bytesLeft = *newSegmentSizesIterator;
485  // write pages until all data in the buffer is written
486  while (newSegmentSizesIterator != newSegmentSizesEnd) {
487  // write header
488  backupStream.seekg(static_cast<streamoff>(currentPage.startOffset()));
489  updatedPageOffsets.push_back(static_cast<std::uint64_t>(stream().tellp())); // memorize offset to update checksum later
490  copyHelper.copy(backupStream, stream(), 27); // just copy header from original file
491  // set continue flag
492  stream().seekp(-22, ios_base::cur);
493  stream().put(static_cast<char>(currentPage.headerTypeFlag() & (continuePreviousSegment ? 0xFF : 0xFE)));
494  continuePreviousSegment = true;
495  // adjust page sequence number
496  stream().seekp(12, ios_base::cur);
497  writer().writeUInt32LE(pageSequenceNumber);
498  stream().seekp(5, ios_base::cur);
499  std::int16_t segmentSizesWritten = 0; // in the current page header only
500  // write segment sizes as long as there are segment sizes to be written and
501  // the max number of segment sizes (255) is not exceeded
502  std::uint32_t currentSize = 0;
503  while (bytesLeft && segmentSizesWritten < 0xFF) {
504  while (bytesLeft >= 0xFF && segmentSizesWritten < 0xFF) {
505  stream().put(static_cast<char>(0xFF));
506  currentSize += 0xFF;
507  bytesLeft -= 0xFF;
508  ++segmentSizesWritten;
509  }
510  if (bytesLeft && segmentSizesWritten < 0xFF) {
511  // bytes left is here < 0xFF
512  stream().put(static_cast<char>(bytesLeft));
513  currentSize += bytesLeft;
514  bytesLeft = 0;
515  ++segmentSizesWritten;
516  }
517  if (!bytesLeft) {
518  // sizes for the segment have been written
519  // -> continue with next segment
520  if (++newSegmentSizesIterator != newSegmentSizesEnd) {
521  bytesLeft = *newSegmentSizesIterator;
522  continuePreviousSegment = false;
523  }
524  }
525  }
526 
527  // there are no bytes left in the current segment; remove continue flag
528  if (!bytesLeft) {
529  continuePreviousSegment = false;
530  }
531 
532  // page is full or all segment data has been covered
533  // -> write segment table size (segmentSizesWritten) and segment data
534  // -> seek back and write updated page segment number
535  stream().seekp(-1 - segmentSizesWritten, ios_base::cur);
536  stream().put(static_cast<char>(segmentSizesWritten));
537  stream().seekp(segmentSizesWritten, ios_base::cur);
538  // -> write actual page data
539  copyHelper.copy(buffer, stream(), currentSize);
540 
541  ++pageSequenceNumber;
542  }
543  }
544 
545  } else {
546  if (pageSequenceNumber != m_iterator.currentPageIndex()) {
547  // just update page sequence number
548  backupStream.seekg(static_cast<streamoff>(currentPage.startOffset()));
549  updatedPageOffsets.push_back(static_cast<std::uint64_t>(stream().tellp())); // memorize offset to update checksum later
550  copyHelper.copy(backupStream, stream(), 27);
551  stream().seekp(-9, ios_base::cur);
552  writer().writeUInt32LE(pageSequenceNumber);
553  stream().seekp(5, ios_base::cur);
554  copyHelper.copy(backupStream, stream(), pageSize - 27);
555  } else {
556  // copy page unchanged
557  backupStream.seekg(static_cast<streamoff>(currentPage.startOffset()));
558  copyHelper.copy(backupStream, stream(), pageSize);
559  }
560  ++pageSequenceNumber;
561  }
562  }
563 
564  // report new size
565  fileInfo().reportSizeChanged(static_cast<std::uint64_t>(stream().tellp()));
566 
567  // "save as path" is now the regular path
568  if (!fileInfo().saveFilePath().empty()) {
569  fileInfo().reportPathChanged(fileInfo().saveFilePath());
570  fileInfo().setSaveFilePath(string());
571  }
572 
573  // close backups stream; reopen new file as readable stream
574  backupStream.close();
575  fileInfo().close();
576  fileInfo().stream().open(fileInfo().path(), ios_base::in | ios_base::out | ios_base::binary);
577 
578  // update checksums of modified pages
579  for (auto offset : updatedPageOffsets) {
581  }
582 
583  // prevent deferring final write operations (to catch and handle possible errors here)
584  fileInfo().stream().flush();
585 
586  // clear iterator
587  m_iterator.clear(fileInfo().stream(), startOffset(), fileInfo().size());
588 
589  } catch (...) {
590  m_iterator.setStream(fileInfo().stream());
591  BackupHelper::handleFailureAfterFileModified(fileInfo(), backupPath, fileInfo().stream(), backupStream, diag, context);
592  }
593 }
594 
595 } // namespace TagParser
TagParser::OggContainer::internalParseTracks
void internalParseTracks(Diagnostics &diag) override
Internally called to parse the tracks.
Definition: oggcontainer.cpp:307
TagParser::GenericContainer< MediaFileInfo, OggVorbisComment, OggStream, OggPage >::m_tags
std::vector< std::unique_ptr< OggVorbisComment > > m_tags
Definition: genericcontainer.h:60
TagParser::OggIterator::setPageIndex
void setPageIndex(std::vector< OggPage >::size_type index)
Sets the current page index.
Definition: oggiterator.h:172
TagParser::OggContainer::reset
void reset() override
Discards all parsing results.
Definition: oggcontainer.cpp:57
TagParser::OggStream::startPage
std::size_t startPage() const
Definition: oggstream.h:34
TagParser::OggIterator::clear
void clear(std::istream &stream, std::uint64_t startOffset, std::uint64_t streamSize)
Sets the stream and related parameters and clears all available pages.
Definition: oggiterator.cpp:32
TagParser::GeneralMediaFormat
GeneralMediaFormat
The GeneralMediaFormat enum specifies the general format of media data (PCM, MPEG-4,...
Definition: mediaformat.h:29
TagParser::OggContainer::~OggContainer
~OggContainer() override
Definition: oggcontainer.cpp:53
TagParser::AbstractContainer::parseTags
void parseTags(Diagnostics &diag)
Parses the tag information if not parsed yet.
Definition: abstractcontainer.cpp:82
TagParser::AbstractContainer::parseTracks
void parseTracks(Diagnostics &diag)
Parses the tracks of the file if not parsed yet.
Definition: abstractcontainer.cpp:106
TagParser::OggPage::streamSerialNumber
std::uint32_t streamSerialNumber() const
Returns the stream serial number.
Definition: oggpage.h:155
TagParser::AbortableProgressFeedback
The AbortableProgressFeedback class provides feedback about an ongoing operation via callbacks....
Definition: progressfeedback.h:186
TagParser::FlacMetaDataBlockHeader::setType
void setType(FlacMetaDataBlockType type)
Sets the block type.
Definition: flacmetadata.h:87
TagParser::OggPage::sequenceNumber
std::uint32_t sequenceNumber() const
Returns the page sequence number.
Definition: oggpage.h:174
TagParser::OggContainer::tagCount
std::size_t tagCount() const override
Returns the number of tags attached to the container.
Definition: oggcontainer.cpp:136
TagParser::OggPage::totalSize
std::uint32_t totalSize() const
Returns the total size of the page in byte.
Definition: oggpage.h:235
TagParser::DiagLevel::Information
@ Information
TagParser::OggIterator::currentSegmentOffset
std::uint64_t currentSegmentOffset() const
Returns the start offset of the current segment in the input stream if the iterator is valid; otherwi...
Definition: oggiterator.h:202
TagParser::OggPage::checksum
std::uint32_t checksum() const
Returns the page checksum.
Definition: oggpage.h:189
TagParser::DiagLevel::Warning
@ Warning
TagParser::OggContainer::internalParseTags
void internalParseTags(Diagnostics &diag) override
Internally called to parse the tags.
Definition: oggcontainer.cpp:261
TagParser::BasicFileInfo::pathForOpen
static const char * pathForOpen(const std::string &url)
Returns removes the "file:/" prefix from url to be able to pass it to functions like open(),...
Definition: basicfileinfo.h:140
TagParser::VorbisCommentFlags::NoSignature
@ NoSignature
TagParser::Tag
The Tag class is used to store, read and write tag information.
Definition: tag.h:98
TagParser::OggPage::segmentSizes
const std::vector< std::uint32_t > & segmentSizes() const
Returns the sizes of the segments of the page in byte.
Definition: oggpage.h:209
TagParser::Diagnostics
The Diagnostics class is a container for DiagMessage.
Definition: diagnostics.h:156
TagParser::TagTarget::tracks
const IdContainerType & tracks() const
Returns the tracks.
Definition: tagtarget.h:104
TagParser
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
TagParser::OggParameter
The OggParameter struct holds the OGG parameter for a VorbisComment.
Definition: oggcontainer.h:27
TagParser::OggContainer::internalParseHeader
void internalParseHeader(Diagnostics &diag) override
Internally called to parse the header.
Definition: oggcontainer.cpp:186
TagParser::OggIterator::currentPageIndex
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:163
TagParser::OggPage::updateChecksum
static void updateChecksum(std::iostream &stream, std::uint64_t startOffset)
Updates the checksum of the page read from the specified stream at the specified startOffset.
Definition: oggpage.cpp:111
TagParser::FourccIds::Flac
@ Flac
Definition: mp4ids.h:272
TagParser::OggIterator::removeFilter
void removeFilter()
Removes a previously set filter.
Definition: oggiterator.h:252
TagParser::FlacMetaDataBlockHeader::makeHeader
void makeHeader(std::ostream &outputStream)
Writes the header to the specified outputStream.
Definition: flacmetadata.cpp:40
TagParser::OggPage::startOffset
std::uint64_t startOffset() const
Returns the start offset of the page.
Definition: oggpage.h:83
TagParser::FourccIds::Opus
@ Opus
Definition: mp4ids.h:346
TagParser::BackupHelper::handleFailureAfterFileModified
TAG_PARSER_EXPORT void handleFailureAfterFileModified(MediaFileInfo &mediaFileInfo, const std::string &backupPath, CppUtilities::NativeFileStream &outputStream, CppUtilities::NativeFileStream &backupStream, Diagnostics &diag, const std::string &context="making file")
TagParser::FlacMetaDataBlockType::VorbisComment
@ VorbisComment
TagParser::OggVorbisComment
Specialization of TagParser::VorbisComment for Vorbis comments inside an OGG stream.
Definition: oggcontainer.h:67
TagParser::GeneralMediaFormat::Opus
@ Opus
TagParser::AbstractTrack::format
MediaFormat format() const
Returns the format of the track if known; otherwise returns MediaFormat::Unknown.
Definition: abstracttrack.h:249
TagParser::OggIterator::resyncAt
bool resyncAt(std::uint64_t offset)
Fetches the next page at the specified offset.
Definition: oggiterator.cpp:237
TagParser::OggVorbisComment::oggParams
OggParameter & oggParams()
Returns the OGG parameter for the comment.
Definition: oggcontainer.h:113
TagParser::GenericContainer< MediaFileInfo, OggVorbisComment, OggStream, OggPage >::track
OggStream * track(std::size_t index) override
Definition: genericcontainer.h:175
TagParser::Failure
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
Definition: exceptions.h:11
TagParser::BackupHelper::createBackupFile
TAG_PARSER_EXPORT void createBackupFile(const std::string &backupDir, const std::string &originalPath, std::string &backupPath, CppUtilities::NativeFileStream &originalStream, CppUtilities::NativeFileStream &backupStream)
TagParser::Tag::target
const TagTarget & target() const
Returns the target of tag.
Definition: tag.h:174
TagParser::OggPage
The OggPage class is used to parse OGG pages.
Definition: oggpage.h:13
TagParser::GenericContainer
The GenericContainer class helps parsing header, track, tag and chapter information of a file.
Definition: genericcontainer.h:22
TagParser::FlacMetaDataBlockHeader::setLast
void setLast(std::uint8_t last)
Sets whether this is the last metadata block before the audio blocks.
Definition: flacmetadata.h:70
TagParser::OggContainer::removeAllTags
void removeAllTags() override
Actually just flags all tags as removed and clears all assigned fields.
Definition: oggcontainer.cpp:178
TagParser::OggContainer::removeTag
bool removeTag(Tag *tag) override
Actually just flags the specified tag as removed and clears all assigned fields.
Definition: oggcontainer.cpp:156
TagParser::BasicFileInfo::reportPathChanged
void reportPathChanged(const std::string &newPath)
Call this function to report that the path changed.
Definition: basicfileinfo.h:129
TagParser::DiagLevel::Critical
@ Critical
TagParser::GenericContainer< MediaFileInfo, OggVorbisComment, OggStream, OggPage >::m_tracks
std::vector< std::unique_ptr< OggStream > > m_tracks
Definition: genericcontainer.h:61
CppUtilities
Definition: abstractcontainer.h:15
TagParser::BasicProgressFeedback::updateStep
void updateStep(const std::string &step, std::uint8_t stepPercentage=0)
Updates the current step and invokes the first callback specified on construction.
Definition: progressfeedback.h:96
TagParser::OggPage::computeChecksum
static std::uint32_t computeChecksum(std::istream &stream, std::uint64_t startOffset)
Computes the actual checksum of the page read from the specified stream at the specified startOffset.
Definition: oggpage.cpp:74
TagParser::OggIterator::reset
void reset()
Resets the iterator to point at the first segment of the first page (matching the filter if set).
Definition: oggiterator.cpp:46
TagParser::AbstractContainer::stream
std::iostream & stream()
Returns the related stream.
Definition: abstractcontainer.h:127
TagParser::OggContainer::createTag
OggVorbisComment * createTag(const TagTarget &target) override
Creates a new tag.
Definition: oggcontainer.cpp:72
TagParser::OggParameter::firstSegmentIndex
std::size_t firstSegmentIndex
Definition: oggcontainer.h:32
TagParser::OggParameter::streamFormat
GeneralMediaFormat streamFormat
Definition: oggcontainer.h:35
TagParser::MediaFormat::general
GeneralMediaFormat general
Definition: mediaformat.h:258
CppUtilities::CopyHelper
Definition: oggcontainer.h:16
TagParser::FlacMetaDataBlockHeader::setDataSize
void setDataSize(std::uint32_t dataSize)
Sets the length in bytes of the meta data (excluding the size of the header itself).
Definition: flacmetadata.h:104
TagParser::BasicFileInfo::stream
CppUtilities::NativeFileStream & stream()
Returns the std::fstream for the current instance.
Definition: basicfileinfo.h:81
TagParser::FlacMetaDataBlockHeader
The FlacMetaDataBlockHeader class is a FLAC "METADATA_BLOCK_HEADER" parser and maker.
Definition: flacmetadata.h:28
TagParser::OggIterator::setSegmentIndex
void setSegmentIndex(std::vector< std::uint32_t >::size_type index)
Sets the current segment index.
Definition: oggiterator.h:184
TagParser::InvalidDataException
The exception that is thrown when the data to be parsed or to be made seems invalid and therefore can...
Definition: exceptions.h:25
TagParser::BasicFileInfo::reportSizeChanged
void reportSizeChanged(std::uint64_t newSize)
Call this function to report that the size changed.
Definition: basicfileinfo.h:120
TagParser::TagTarget
The TagTarget class specifies the target of a tag.
Definition: tagtarget.h:20
TagParser::TruncatedDataException
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
Definition: exceptions.h:39
TagParser::MatroskaTagIds::comment
constexpr const TAG_PARSER_EXPORT char * comment()
Definition: matroskatagid.h:309
TagParser::OggPage::headerTypeFlag
std::uint8_t headerTypeFlag() const
Returns the header type flag.
Definition: oggpage.h:102
TagParser::VorbisCommentFlags::None
@ None
TagParser::OggIterator::nextPage
void nextPage()
Increases the current position by one page.
Definition: oggiterator.cpp:63
TagParser::OggIterator::setStream
void setStream(std::istream &stream)
Sets the stream.
Definition: oggiterator.h:98
TagParser::OggIterator::currentPage
const OggPage & currentPage() const
Returns the current OGG page.
Definition: oggiterator.h:131
TagParser::MediaFileInfo::setSaveFilePath
void setSaveFilePath(const std::string &saveFilePath)
Sets the "save file path".
Definition: mediafileinfo.h:389
TagParser::AbstractTrack::id
std::uint64_t id() const
Returns the track ID if known; otherwise returns 0.
Definition: abstracttrack.h:337
TagParser::OggContainer::tag
OggVorbisComment * tag(std::size_t index) override
Returns the tag with the specified index.
Definition: oggcontainer.cpp:122
TagParser::OggIterator::currentSegmentIndex
std::vector< std::uint32_t >::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:193
TagParser::OggParameter::lastMetaDataBlock
bool lastMetaDataBlock
Definition: oggcontainer.h:36
TagParser::VorbisCommentFlags::NoFramingByte
@ NoFramingByte
TagParser::AbstractContainer::m_duration
CppUtilities::TimeSpan m_duration
Definition: abstractcontainer.h:105
TagParser::OggStream
Implementation of TagParser::AbstractTrack for OGG streams.
Definition: oggstream.h:13
TagParser::OggIterator::pages
const std::vector< OggPage > & pages() const
Returns a vector of containing the OGG pages that have been fetched yet.
Definition: oggiterator.h:122
TagParser::GenericContainer< MediaFileInfo, OggVorbisComment, OggStream, OggPage >::fileInfo
MediaFileInfo & fileInfo() const
Returns the related file info.
Definition: genericcontainer.h:113
TagParser::OggContainer::internalMakeFile
void internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress) override
Internally called to make the file.
Definition: oggcontainer.cpp:366
TagParser::OggParameter::removed
bool removed
Definition: oggcontainer.h:37
TagParser::AbstractContainer::writer
CppUtilities::BinaryWriter & writer()
Returns the related BinaryWriter.
Definition: abstractcontainer.h:161
TagParser::BasicFileInfo::close
void close()
A possibly opened std::fstream will be closed.
Definition: basicfileinfo.cpp:71
TagParser::OggParameter::firstPageIndex
std::size_t firstPageIndex
Definition: oggcontainer.h:31
TagParser::FlacMetaDataBlockHeader::dataSize
constexpr std::uint32_t dataSize() const
Returns the length in bytes of the meta data (excluding the size of the header itself).
Definition: flacmetadata.h:95
TagParser::OggParameter::lastPageIndex
std::size_t lastPageIndex
Definition: oggcontainer.h:33
TagParser::VorbisComment
Implementation of TagParser::Tag for Vorbis comments.
Definition: vorbiscomment.h:25
TagParser::MediaFileInfo
The MediaFileInfo class allows to read and write tag information providing a container/tag format ind...
Definition: mediafileinfo.h:45
TagParser::AbstractContainer::startOffset
std::uint64_t startOffset() const
Returns the start offset in the related stream.
Definition: abstractcontainer.h:145
TagParser::OggPage::dataSize
std::uint32_t dataSize() const
Returns the data size in byte.
Definition: oggpage.h:227
TagParser::OggIterator::ignore
void ignore(std::size_t count=1)
Advances the position of the next character to be read from the OGG stream by count bytes.
Definition: oggiterator.cpp:198
oggcontainer.h
TagParser::OggParameter::lastSegmentIndex
std::size_t lastSegmentIndex
Definition: oggcontainer.h:34
TagParser::GeneralMediaFormat::Vorbis
@ Vorbis