Tag Parser  9.2.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
id3v2tag.cpp
Go to the documentation of this file.
1 #include "./id3v2tag.h"
2 #include "./id3v2frameids.h"
3 
4 #include "../diagnostics.h"
5 #include "../exceptions.h"
6 
7 #include <c++utilities/conversion/stringbuilder.h>
8 #include <c++utilities/conversion/stringconversion.h>
9 
10 #include <iostream>
11 
12 using namespace std;
13 using namespace CppUtilities;
14 
15 namespace TagParser {
16 
26 bool Id3v2Tag::supportsMultipleValues(KnownField field) const
27 {
28  switch (field) {
29  case KnownField::Album:
30  case KnownField::Artist:
31  case KnownField::Year:
32  case KnownField::RecordDate:
33  case KnownField::ReleaseDate:
34  case KnownField::Title:
35  case KnownField::Genre:
39  case KnownField::Bpm:
41  case KnownField::Length:
42  case KnownField::Language:
43  case KnownField::EncoderSettings:
48  return m_majorVersion > 3;
49  case KnownField::Rating:
51  case KnownField::Cover:
52  case KnownField::Lyrics:
53  case KnownField::SynchronizedLyrics:
54  return true;
55  default:
56  return false;
57  }
58 }
59 
60 void Id3v2Tag::ensureTextValuesAreProperlyEncoded()
61 {
62  const auto encoding = proposedTextEncoding();
63  for (auto &field : fields()) {
64  auto &value = field.second.value();
65  value.convertDataEncoding(encoding);
66  value.convertDescriptionEncoding(encoding);
67  }
68 }
69 
73 std::vector<const TagValue *> Id3v2Tag::internallyGetValues(const IdentifierType &id) const
74 {
75  auto range = fields().equal_range(id);
76  std::vector<const TagValue *> values;
77  for (auto i = range.first; i != range.second; ++i) {
78  const auto &frame(i->second);
79  if (!frame.value().isEmpty()) {
80  values.push_back(&frame.value());
81  }
82  for (const auto &value : frame.additionalValues()) {
83  values.push_back(&value);
84  }
85  }
86  return values;
87 }
88 
95 bool Id3v2Tag::internallySetValues(const IdentifierType &id, const std::vector<TagValue> &values)
96 {
97  // use default implementation for non-text frames
98  if (!Id3v2FrameIds::isTextFrame(id)) {
99  return CRTPBase::internallySetValues(id, values);
100  }
101 
102  // find existing text frame
103  auto range = fields().equal_range(id);
104  auto frameIterator = range.first;
105 
106  // use existing frame or insert new text frame
107  auto valuesIterator = values.cbegin();
108  if (frameIterator != range.second) {
109  ++range.first;
110  // add primary value to existing frame
111  if (valuesIterator != values.cend()) {
112  frameIterator->second.setValue(*valuesIterator);
113  ++valuesIterator;
114  } else {
115  frameIterator->second.value().clearDataAndMetadata();
116  }
117  } else {
118  // skip if there is no existing frame but also no values to be assigned
119  if (valuesIterator == values.cend()) {
120  return true;
121  }
122  // add primary value to new frame
123  frameIterator = fields().insert(make_pair(id, Id3v2Frame(id, *valuesIterator)));
124  ++valuesIterator;
125  }
126 
127  // add additional values to frame
128  frameIterator->second.additionalValues() = vector<TagValue>(valuesIterator, values.cend());
129 
130  // remove remaining existing values (there are more existing values than specified ones)
131  for (; range.first != range.second; ++range.first) {
132  range.first->second.setValue(TagValue());
133  }
134  return true;
135 }
136 
137 Id3v2Tag::IdentifierType Id3v2Tag::internallyGetFieldId(KnownField field) const
138 {
139  using namespace Id3v2FrameIds;
140  if (m_majorVersion >= 3) {
141  switch (field) {
142  case KnownField::Album:
143  return lAlbum;
144  case KnownField::Artist:
145  return lArtist;
146  case KnownField::Comment:
147  return lComment;
148  case KnownField::RecordDate:
149  case KnownField::Year:
150  return lRecordingTime; // (de)serializer takes to convert to/from lYear/lRecordingDates/lDate/lTime
151  case KnownField::ReleaseDate:
152  return lReleaseTime;
153  case KnownField::Title:
154  return lTitle;
155  case KnownField::Genre:
156  return lGenre;
158  return lTrackPosition;
160  return lDiskPosition;
161  case KnownField::Encoder:
162  return lEncoder;
163  case KnownField::Bpm:
164  return lBpm;
165  case KnownField::Cover:
166  return lCover;
168  return lWriter;
169  case KnownField::Length:
170  return lLength;
171  case KnownField::Language:
172  return lLanguage;
173  case KnownField::EncoderSettings:
174  return lEncoderSettings;
175  case KnownField::Lyrics:
176  return lUnsynchronizedLyrics;
177  case KnownField::SynchronizedLyrics:
178  return lSynchronizedLyrics;
182  return lRecordLabel;
184  return lComposer;
185  case KnownField::Rating:
186  return lRating;
188  return lAlbumArtist;
189  default:;
190  }
191  } else {
192  switch (field) {
193  case KnownField::Album:
194  return sAlbum;
195  case KnownField::Artist:
196  return sArtist;
197  case KnownField::Comment:
198  return sComment;
199  case KnownField::RecordDate:
200  case KnownField::Year:
201  return lRecordingTime; // (de)serializer takes to convert to/from sYear/sRecordingDates/sDate/sTime
202  case KnownField::Title:
203  return sTitle;
204  case KnownField::Genre:
205  return sGenre;
207  return sTrackPosition;
209  return sDiskPosition;
210  case KnownField::Encoder:
211  return sEncoder;
212  case KnownField::Bpm:
213  return sBpm;
214  case KnownField::Cover:
215  return sCover;
217  return sWriter;
218  case KnownField::Length:
219  return sLength;
220  case KnownField::Language:
221  return sLanguage;
222  case KnownField::EncoderSettings:
223  return sEncoderSettings;
224  case KnownField::Lyrics:
225  return sUnsynchronizedLyrics;
226  case KnownField::SynchronizedLyrics:
227  return sSynchronizedLyrics;
231  return sRecordLabel;
233  return sComposer;
234  case KnownField::Rating:
235  return sRating;
237  return sAlbumArtist;
238  default:;
239  }
240  }
241  return 0;
242 }
243 
244 KnownField Id3v2Tag::internallyGetKnownField(const IdentifierType &id) const
245 {
246  using namespace Id3v2FrameIds;
247  switch (id) {
248  case lAlbum:
249  return KnownField::Album;
250  case lArtist:
251  return KnownField::Artist;
252  case lComment:
253  return KnownField::Comment;
254  case lRecordingTime:
255  case lYear:
256  return KnownField::RecordDate;
257  case lTitle:
258  return KnownField::Title;
259  case lGenre:
260  return KnownField::Genre;
261  case lTrackPosition:
263  case lDiskPosition:
265  case lEncoder:
266  return KnownField::Encoder;
267  case lBpm:
268  return KnownField::Bpm;
269  case lCover:
270  return KnownField::Cover;
271  case lWriter:
272  return KnownField::Lyricist;
273  case lLanguage:
274  return KnownField::Language;
275  case lLength:
276  return KnownField::Length;
277  case lEncoderSettings:
278  return KnownField::EncoderSettings;
280  return KnownField::Lyrics;
281  case lSynchronizedLyrics:
282  return KnownField::SynchronizedLyrics;
283  case lAlbumArtist:
286  return KnownField::Grouping;
287  case lRecordLabel:
289  case sAlbum:
290  return KnownField::Album;
291  case sArtist:
292  return KnownField::Artist;
293  case sComment:
294  return KnownField::Comment;
295  case sYear:
296  return KnownField::RecordDate;
297  case sTitle:
298  return KnownField::Title;
299  case sGenre:
300  return KnownField::Genre;
301  case sTrackPosition:
303  case sEncoder:
304  return KnownField::Encoder;
305  case sBpm:
306  return KnownField::Bpm;
307  case sCover:
308  return KnownField::Cover;
309  case sWriter:
310  return KnownField::Lyricist;
311  case sLanguage:
312  return KnownField::Language;
313  case sLength:
314  return KnownField::Length;
315  case sEncoderSettings:
316  return KnownField::EncoderSettings;
318  return KnownField::Lyrics;
319  case sSynchronizedLyrics:
320  return KnownField::SynchronizedLyrics;
321  case sAlbumArtist:
322  return KnownField::Grouping;
323  case sRecordLabel:
325  default:
326  return KnownField::Invalid;
327  }
328 }
329 
330 TagDataType Id3v2Tag::internallyGetProposedDataType(const std::uint32_t &id) const
331 {
332  using namespace Id3v2FrameIds;
333  switch (id) {
334  case lLength:
335  case sLength:
336  return TagDataType::TimeSpan;
337  case lBpm:
338  case sBpm:
339  case lYear:
340  case sYear:
341  return TagDataType::Integer;
342  case lTrackPosition:
343  case sTrackPosition:
344  case lDiskPosition:
345  return TagDataType::PositionInSet;
346  case lCover:
347  case sCover:
348  return TagDataType::Picture;
349  default:
350  if (Id3v2FrameIds::isTextFrame(id)) {
351  return TagDataType::Text;
352  } else {
353  return TagDataType::Undefined;
354  }
355  }
356 }
357 
364 void Id3v2Tag::convertOldRecordDateFields(const std::string &diagContext, Diagnostics &diag)
365 {
366  // skip if it is a v2.4.0 tag and lRecordingTime is present
367  if (majorVersion() >= 4 && fields().find(Id3v2FrameIds::lRecordingTime) != fields().cend()) {
368  return;
369  }
370 
371  // parse values of lYear/lRecordingDates/lDate/lTime/sYear/sRecordingDates/sDate/sTime fields
372  int year = 1, month = 1, day = 1, hour = 0, minute = 0;
373  if (const auto &v = value(Id3v2FrameIds::lYear)) {
374  try {
375  year = v.toInteger();
376  } catch (const ConversionException &e) {
377  diag.emplace_back(DiagLevel::Critical, argsToString("Unable to parse year from \"TYER\" frame: ", e.what()), diagContext);
378  }
379  }
380  if (const auto &v = value(Id3v2FrameIds::lDate)) {
381  try {
382  auto str = v.toString();
383  if (str.size() != 4) {
384  throw ConversionException("format is not DDMM");
385  }
386  day = stringToNumber<unsigned short>(std::string_view(str.data() + 0, 2));
387  month = stringToNumber<unsigned short>(std::string_view(str.data() + 2, 2));
388  } catch (const ConversionException &e) {
389  diag.emplace_back(DiagLevel::Critical, argsToString("Unable to parse month and day from \"TDAT\" frame: ", e.what()), diagContext);
390  }
391  }
392  if (const auto &v = value(Id3v2FrameIds::lTime)) {
393  try {
394  auto str = v.toString();
395  if (str.size() != 4) {
396  throw ConversionException("format is not HHMM");
397  }
398  hour = stringToNumber<unsigned short>(std::string_view(str.data() + 0, 2));
399  minute = stringToNumber<unsigned short>(std::string_view(str.data() + 2, 2));
400  } catch (const ConversionException &e) {
401  diag.emplace_back(DiagLevel::Critical, argsToString("Unable to parse hour and minute from \"TIME\" frame: ", +e.what()), diagContext);
402  }
403  }
404 
405  // set the field values as DateTime
406  try {
407  setValue(Id3v2FrameIds::lRecordingTime, DateTime::fromDateAndTime(year, month, day, hour, minute));
408  } catch (const ConversionException &e) {
409  try {
410  // try to set at least the year
411  setValue(Id3v2FrameIds::lRecordingTime, DateTime::fromDate(year));
412  diag.emplace_back(DiagLevel::Critical,
413  argsToString(
414  "Unable to parse the full date of the recording. Only the 'Year' frame could be parsed; related frames failed: ", e.what()),
415  diagContext);
416  } catch (const ConversionException &) {
417  }
418  diag.emplace_back(
419  DiagLevel::Critical, argsToString("Unable to parse a valid date from the 'Year' frame and related frames: ", e.what()), diagContext);
420  }
421 }
422 
430 void Id3v2Tag::parse(istream &stream, const std::uint64_t maximalSize, Diagnostics &diag)
431 {
432  // prepare parsing
433  static const string context("parsing ID3v2 tag");
434  BinaryReader reader(&stream);
435  const auto startOffset = static_cast<std::uint64_t>(stream.tellg());
436 
437  // check whether the header is truncated
438  if (maximalSize && maximalSize < 10) {
439  diag.emplace_back(DiagLevel::Critical, "ID3v2 header is truncated (at least 10 bytes expected).", context);
440  throw TruncatedDataException();
441  }
442 
443  // read signature: ID3
444  if (reader.readUInt24BE() != 0x494433u) {
445  diag.emplace_back(DiagLevel::Critical, "Signature is invalid.", context);
446  throw InvalidDataException();
447  }
448  // read header data
449  const std::uint8_t majorVersion = reader.readByte();
450  const std::uint8_t revisionVersion = reader.readByte();
451  setVersion(majorVersion, revisionVersion);
452  m_flags = reader.readByte();
453  m_sizeExcludingHeader = reader.readSynchsafeUInt32BE();
454  m_size = 10 + m_sizeExcludingHeader;
455  if (m_sizeExcludingHeader == 0) {
456  diag.emplace_back(DiagLevel::Warning, "ID3v2 tag seems to be empty.", context);
457  return;
458  }
459 
460  // check if the version
461  if (!isVersionSupported()) {
462  diag.emplace_back(DiagLevel::Critical, "The ID3v2 tag couldn't be parsed, because its version is not supported.", context);
464  }
465 
466  // read extended header (if present)
467  if (hasExtendedHeader()) {
468  if (maximalSize && maximalSize < 14) {
469  diag.emplace_back(DiagLevel::Critical, "Extended header denoted but not present.", context);
470  throw TruncatedDataException();
471  }
472  m_extendedHeaderSize = reader.readSynchsafeUInt32BE();
473  if (m_extendedHeaderSize < 6 || m_extendedHeaderSize > m_sizeExcludingHeader || (maximalSize && maximalSize < (10 + m_extendedHeaderSize))) {
474  diag.emplace_back(DiagLevel::Critical, "Extended header is invalid/truncated.", context);
475  throw TruncatedDataException();
476  }
477  stream.seekg(m_extendedHeaderSize - 4, ios_base::cur);
478  }
479 
480  // how many bytes remain for frames and padding?
481  std::uint32_t bytesRemaining = m_sizeExcludingHeader - m_extendedHeaderSize;
482  if (maximalSize && bytesRemaining > maximalSize) {
483  bytesRemaining = static_cast<std::uint32_t>(maximalSize);
484  diag.emplace_back(DiagLevel::Critical, "Frames are truncated.", context);
485  }
486 
487  // read frames
488  auto pos = static_cast<std::uint64_t>(stream.tellg());
489  while (bytesRemaining) {
490  // seek to next frame
491  stream.seekg(static_cast<streamoff>(pos));
492  // parse frame
493  Id3v2Frame frame;
494  try {
495  frame.parse(reader, majorVersion, bytesRemaining, diag);
496  if (Id3v2FrameIds::isTextFrame(frame.id()) && fields().count(frame.id()) == 1) {
497  diag.emplace_back(DiagLevel::Warning, "The text frame " % frame.idToString() + " exists more than once.", context);
498  }
499  fields().emplace(frame.id(), move(frame));
500  } catch (const NoDataFoundException &) {
501  if (frame.hasPaddingReached()) {
502  m_paddingSize = startOffset + m_size - pos;
503  break;
504  }
505  } catch (const Failure &) {
506  }
507 
508  // calculate next frame offset
509  if (frame.totalSize() <= bytesRemaining) {
510  pos += frame.totalSize();
511  bytesRemaining -= frame.totalSize();
512  } else {
513  pos += bytesRemaining;
514  bytesRemaining = 0;
515  }
516  }
517 
518  convertOldRecordDateFields(context, diag);
519 
520  // check for extended header
521  if (!hasFooter()) {
522  return;
523  }
524  if (maximalSize && m_size + 10 < maximalSize) {
525  // the footer does not provide additional information, just check the signature
526  stream.seekg(static_cast<streamoff>(startOffset + (m_size += 10)));
527  if (reader.readUInt24LE() != 0x494433u) {
528  diag.emplace_back(DiagLevel::Critical, "Footer signature is invalid.", context);
529  }
530  // skip remaining footer
531  stream.seekg(7, ios_base::cur);
532  } else {
533  diag.emplace_back(DiagLevel::Critical, "Footer denoted but not present.", context);
534  throw TruncatedDataException();
535  }
536 }
537 
548 Id3v2TagMaker Id3v2Tag::prepareMaking(Diagnostics &diag)
549 {
550  return Id3v2TagMaker(*this, diag);
551 }
552 
560 void Id3v2Tag::make(ostream &stream, std::uint32_t padding, Diagnostics &diag)
561 {
562  prepareMaking(diag).make(stream, padding, diag);
563 }
564 
569 void Id3v2Tag::setVersion(std::uint8_t majorVersion, std::uint8_t revisionVersion)
570 {
571  m_majorVersion = majorVersion;
572  m_revisionVersion = revisionVersion;
573  m_version = argsToString('2', '.', majorVersion, '.', revisionVersion);
574 }
575 
588 bool FrameComparer::operator()(std::uint32_t lhs, std::uint32_t rhs) const
589 {
590  if (lhs == rhs) {
591  return false;
592  }
593 
594  const bool lhsLong = Id3v2FrameIds::isLongId(lhs);
595  const bool rhsLong = Id3v2FrameIds::isLongId(rhs);
596  if (lhsLong != rhsLong) {
597  if (!lhsLong) {
599  if (!lhs) {
600  return true;
601  }
602  } else if (!rhsLong) {
604  if (!rhs) {
605  return true;
606  }
607  }
608  }
609 
611  return true;
612  }
614  return false;
615  }
616  if (lhs == Id3v2FrameIds::lTitle || lhs == Id3v2FrameIds::sTitle) {
617  return true;
618  }
619  if (rhs == Id3v2FrameIds::lTitle || rhs == Id3v2FrameIds::sTitle) {
620  return false;
621  }
622 
623  const bool lhstextfield = Id3v2FrameIds::isTextFrame(lhs);
624  const bool rhstextfield = Id3v2FrameIds::isTextFrame(rhs);
625  if (lhstextfield && !rhstextfield) {
626  return true;
627  }
628  if (!lhstextfield && rhstextfield) {
629  return false;
630  }
631 
632  if (lhs == Id3v2FrameIds::lCover || lhs == Id3v2FrameIds::sCover) {
633  return false;
634  }
635  if (rhs == Id3v2FrameIds::lCover || rhs == Id3v2FrameIds::sCover) {
636  return true;
637  }
638  return lhs < rhs;
639 }
640 
651 void Id3v2Tag::removeOldRecordDateRelatedFields()
652 {
654  fields().erase(field);
655  }
656 }
657 
661 void Id3v2Tag::prepareRecordDataForMaking(const std::string &diagContext, Diagnostics &diag)
662 {
663  // get rid of lYear/lRecordingDates/lDate/lTime/sYear/sRecordingDates/sDate/sTime if writing v2.4.0 or newer
664  // note: If the tag was initially v2.3.0 or older the "old" fields have already been converted to lRecordingTime when
665  // parsing and the generic accessors propose using lRecordingTime in any case.
666  if (majorVersion() >= 4) {
667  removeOldRecordDateRelatedFields();
668  return;
669  }
670 
671  // convert lRecordingTime to old fields for v2.3.0 and older
672  const auto recordingTimeFieldIterator = fields().find(Id3v2FrameIds::lRecordingTime);
673  // -> If the auto-created lRecordingTime field (see note above) has been completely removed write the old fields as-is.
674  // This allows one to bypass this handling and set the old fields explicitely.
675  if (recordingTimeFieldIterator == fields().cend()) {
676  return;
677  }
678  // -> simply remove all old fields if lRecordingTime is set to an empty value
679  const auto &recordingTime = recordingTimeFieldIterator->second.value();
680  if (recordingTime.isEmpty()) {
681  removeOldRecordDateRelatedFields();
682  return;
683  }
684  // -> convert lRecordingTime (which is supposed to be an ISO string) to a DateTime
685  try {
686  const auto asDateTime = recordingTime.toDateTime();
687  // -> remove any existing old fields to avoid any leftovers
688  removeOldRecordDateRelatedFields();
689  // -> assign old fields from parsed DateTime
690  std::stringstream year, date, time;
691  year << std::setfill('0') << std::setw(4) << asDateTime.year();
692  setValue(Id3v2FrameIds::lYear, TagValue(year.str()));
693  date << std::setfill('0') << std::setw(2) << asDateTime.day() << std::setfill('0') << std::setw(2) << asDateTime.month();
694  setValue(Id3v2FrameIds::lDate, TagValue(date.str()));
695  time << std::setfill('0') << std::setw(2) << asDateTime.hour() << std::setfill('0') << std::setw(2) << asDateTime.minute();
696  setValue(Id3v2FrameIds::lTime, TagValue(time.str()));
697  if (asDateTime.second() || asDateTime.millisecond()) {
698  diag.emplace_back(DiagLevel::Warning,
699  "The recording time field (TRDA) has been truncated to full minutes when converting to corresponding fields for older ID3v2 "
700  "versions.",
701  diagContext);
702  }
703  } catch (const ConversionException &e) {
704  try {
705  diag.emplace_back(DiagLevel::Critical,
706  argsToString("Unable to convert recording time field (TRDA) with the value \"", recordingTime.toString(),
707  "\" to corresponding fields for older ID3v2 versions: ", e.what()),
708  diagContext);
709  } catch (const ConversionException &) {
710  diag.emplace_back(DiagLevel::Critical,
711  argsToString("Unable to convert recording time field (TRDA) to corresponding fields for older ID3v2 versions: ", e.what()),
712  diagContext);
713  }
714  }
715  // -> get rid of lRecordingTime
716  fields().erase(Id3v2FrameIds::lRecordingTime);
717 }
718 
723 Id3v2TagMaker::Id3v2TagMaker(Id3v2Tag &tag, Diagnostics &diag)
724  : m_tag(tag)
725  , m_framesSize(0)
726 {
727  static const string context("making ID3v2 tag");
728 
729  // check if version is supported
730  // (the version could have been changed using setVersion())
731  if (!tag.isVersionSupported()) {
732  diag.emplace_back(DiagLevel::Critical, "The ID3v2 tag version isn't supported.", context);
733  throw VersionNotSupportedException();
734  }
735 
736  tag.prepareRecordDataForMaking(context, diag);
737 
738  // prepare frames
739  m_maker.reserve(tag.fields().size());
740  for (auto &pair : tag.fields()) {
741  try {
742  m_maker.emplace_back(pair.second.prepareMaking(tag.majorVersion(), diag));
743  m_framesSize += m_maker.back().requiredSize();
744  } catch (const Failure &) {
745  }
746  }
747 
748  // calculate required size
749  // -> header + size of frames
750  m_requiredSize = 10 + m_framesSize;
751 }
752 
760 void Id3v2TagMaker::make(std::ostream &stream, std::uint32_t padding, Diagnostics &diag)
761 {
762  CPP_UTILITIES_UNUSED(diag)
763 
764  BinaryWriter writer(&stream);
765 
766  // write header
767  // -> signature
768  writer.writeUInt24BE(0x494433u);
769  // -> version
770  writer.writeByte(m_tag.majorVersion());
771  writer.writeByte(m_tag.revisionVersion());
772  // -> flags, but without extended header or compression bit set
773  writer.writeByte(m_tag.flags() & 0xBF);
774  // -> size (excluding header)
775  writer.writeSynchsafeUInt32BE(m_framesSize + padding);
776 
777  // write frames
778  for (auto &maker : m_maker) {
779  maker.make(writer);
780  }
781 
782  // write padding
783  for (; padding; --padding) {
784  stream.put(0);
785  }
786 }
787 
788 } // namespace TagParser
TagParser::Id3v2FrameIds::sTitle
@ sTitle
Definition: id3v2frameids.h:56
TagParser::Id3v2FrameIds::sDiskPosition
@ sDiskPosition
Definition: id3v2frameids.h:59
TagParser::Mp4TagAtomIds::Album
@ Album
Definition: mp4ids.h:86
TagParser::Id3v2TagMaker::make
void make(std::ostream &stream, std::uint32_t padding, Diagnostics &diag)
Saves the tag (specified when constructing the object) to the specified stream.
Definition: id3v2tag.cpp:760
TagParser::Id3v2FrameIds::lCover
@ lCover
Definition: id3v2frameids.h:33
TagParser::Id3v2Frame
The Id3v2Frame class is used by Id3v2Tag to store the fields.
Definition: id3v2frame.h:86
TagParser::Mp4TagAtomIds::Lyrics
@ Lyrics
Definition: mp4ids.h:105
TagParser::Mp4TagAtomIds::Encoder
@ Encoder
Definition: mp4ids.h:97
TagParser::FieldMapBasedTag< Id3v2Tag >::IdentifierType
typename FieldMapBasedTagTraits< Id3v2Tag >::FieldType::IdentifierType IdentifierType
Definition: fieldbasedtag.h:36
TagParser::Mp4TagAtomIds::Cover
@ Cover
Definition: mp4ids.h:94
TagParser::Id3v2Tag::flags
std::uint8_t flags() const
Returns the flags read from the ID3v2 header.
Definition: id3v2tag.h:186
id3v2frameids.h
TagParser::Id3v2FrameIds::lReleaseTime
@ lReleaseTime
Definition: id3v2frameids.h:24
TagParser::Id3v2FrameIds::lAlbum
@ lAlbum
Definition: id3v2frameids.h:14
TagParser::Id3v2Frame::hasPaddingReached
bool hasPaddingReached() const
Returns whether the padding has reached.
Definition: id3v2frame.h:196
TagParser::Id3v2FrameIds::isLongId
constexpr bool isLongId(std::uint32_t id)
Returns an indication whether the specified id is a long frame id.
Definition: id3v2frameids.h:86
TagParser::Diagnostics
The Diagnostics class is a container for DiagMessage.
Definition: diagnostics.h:156
TagParser::Mp4TagAtomIds::TrackPosition
@ TrackPosition
Definition: mp4ids.h:116
TagParser::Id3v2FrameIds::sTrackPosition
@ sTrackPosition
Definition: id3v2frameids.h:58
TagParser::Id3v2FrameIds::sCover
@ sCover
Definition: id3v2frameids.h:62
TagParser
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
TagParser::Id3v2FrameIds::lComment
@ lComment
Definition: id3v2frameids.h:16
TagParser::Id3v2Frame::parse
void parse(CppUtilities::BinaryReader &reader, std::uint32_t version, std::uint32_t maximalSize, Diagnostics &diag)
Parses a frame from the stream read using the specified reader.
Definition: id3v2frame.cpp:132
TagParser::Id3v2FrameIds::lTitle
@ lTitle
Definition: id3v2frameids.h:27
TagParser::Id3v2FrameIds::lTrackPosition
@ lTrackPosition
Definition: id3v2frameids.h:29
TagParser::TagField::id
const IdentifierType & id() const
Returns the id of the current TagField.
Definition: generictagfield.h:115
TagParser::Id3v2FrameIds::sRating
@ sRating
Definition: id3v2frameids.h:74
TagParser::Id3v2FrameIds::lLanguage
@ lLanguage
Definition: id3v2frameids.h:36
TagParser::Id3v2FrameIds::lRecordingTime
@ lRecordingTime
Definition: id3v2frameids.h:23
TagParser::Id3v2FrameIds::lTime
@ lTime
Definition: id3v2frameids.h:21
TagParser::Id3v2FrameIds::sYear
@ sYear
Definition: id3v2frameids.h:51
TagParser::TagDataType
TagDataType
Specifies the data type.
Definition: tagvalue.h:54
TagParser::MatroskaIds::Title
@ Title
Definition: matroskaid.h:54
TagParser::Id3v2FrameIds::lLength
@ lLength
Definition: id3v2frameids.h:35
TagParser::Id3v2FrameIds::lGenre
@ lGenre
Definition: id3v2frameids.h:28
TagParser::Id3v2FrameIds::sSynchronizedLyrics
@ sSynchronizedLyrics
Definition: id3v2frameids.h:68
TagParser::Id3v2FrameIds::sAlbum
@ sAlbum
Definition: id3v2frameids.h:48
TagParser::Mp4TagAtomIds::AlbumArtist
@ AlbumArtist
Definition: mp4ids.h:87
TagParser::Mp4TagAtomIds::Year
@ Year
Definition: mp4ids.h:122
TagParser::Failure
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
Definition: exceptions.h:11
TagParser::Id3v2FrameIds::sEncoder
@ sEncoder
Definition: id3v2frameids.h:60
TagParser::Id3v2FrameIds::isTextFrame
constexpr bool isTextFrame(std::uint32_t id)
Returns an indication whether the specified id is a text frame id.
Definition: id3v2frameids.h:102
TagParser::Id3v2FrameIds::sBpm
@ sBpm
Definition: id3v2frameids.h:61
TagParser::Id3v2Tag::majorVersion
std::uint8_t majorVersion() const
Returns the major version if known; otherwise returns 0.
Definition: id3v2tag.h:159
TagParser::Mp4TagAtomIds::Lyricist
@ Lyricist
Definition: mp4ids.h:104
TagParser::Id3v2FrameIds::sComposer
@ sComposer
Definition: id3v2frameids.h:73
TagParser::Id3v2FrameIds::sWriter
@ sWriter
Definition: id3v2frameids.h:63
TagParser::DiagLevel::Critical
@ Critical
TagParser::Id3v2FrameIds::sUniqueFileId
@ sUniqueFileId
Definition: id3v2frameids.h:72
TagParser::Id3v2FrameIds::lRecordLabel
@ lRecordLabel
Definition: id3v2frameids.h:42
TagParser::Id3v2FrameIds::sContentGroupDescription
@ sContentGroupDescription
Definition: id3v2frameids.h:70
CppUtilities
Definition: abstractcontainer.h:15
TagParser::Id3v2FrameIds::lComposer
@ lComposer
Definition: id3v2frameids.h:44
TagParser::Mp4TagAtomIds::Genre
@ Genre
Definition: mp4ids.h:101
TagParser::Id3v2FrameIds::lDiskPosition
@ lDiskPosition
Definition: id3v2frameids.h:30
TagParser::Id3v2FrameIds::sLength
@ sLength
Definition: id3v2frameids.h:64
TagParser::Mp4TagAtomIds::Rating
@ Rating
Definition: mp4ids.h:113
TagParser::Id3v2FrameIds::lWriter
@ lWriter
Definition: id3v2frameids.h:34
TagParser::Id3v2FrameIds::lAlbumArtist
@ lAlbumArtist
Definition: id3v2frameids.h:40
TagParser::Id3v2Frame::totalSize
std::uint32_t totalSize() const
Returns the total size of the frame in bytes.
Definition: id3v2frame.h:220
TagParser::Id3v2FrameIds::lDate
@ lDate
Definition: id3v2frameids.h:20
TagParser::KnownField
KnownField
Specifies the field.
Definition: tag.h:42
TagParser::Id3v2FrameIds::lUnsynchronizedLyrics
@ lUnsynchronizedLyrics
Definition: id3v2frameids.h:38
TagParser::VorbisCommentIds::date
constexpr TAG_PARSER_EXPORT const char * date()
Definition: vorbiscommentids.h:142
id3v2tag.h
TagParser::Id3v2FrameIds::sEncoderSettings
@ sEncoderSettings
Definition: id3v2frameids.h:66
TagParser::VersionNotSupportedException
The exception that is thrown when an operation fails because the detected or specified version is not...
Definition: exceptions.h:53
TagParser::Mp4TagAtomIds::Grouping
@ Grouping
Definition: mp4ids.h:102
TagParser::Id3v2FrameIds::sAlbumArtist
@ sAlbumArtist
Definition: id3v2frameids.h:69
TagParser::Id3v2FrameIds::sUnsynchronizedLyrics
@ sUnsynchronizedLyrics
Definition: id3v2frameids.h:67
TagParser::NoDataFoundException
The exception that is thrown when the data to be parsed holds no parsable information (e....
Definition: exceptions.h:18
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::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::TagValue
The TagValue class wraps values of different types. It is meant to be assigned to a tag field.
Definition: tagvalue.h:75
TagParser::Mp4TagAtomIds::Bpm
@ Bpm
Definition: mp4ids.h:89
TagParser::Id3v2FrameIds::lUniqueFileId
@ lUniqueFileId
Definition: id3v2frameids.h:43
TagParser::Id3v2FrameIds::sGenre
@ sGenre
Definition: id3v2frameids.h:57
TagParser::Id3v2FrameIds::lSynchronizedLyrics
@ lSynchronizedLyrics
Definition: id3v2frameids.h:39
TagParser::Id3v2Tag::revisionVersion
std::uint8_t revisionVersion() const
Returns the revision version if known; otherwise returns 0.
Definition: id3v2tag.h:167
TagParser::Id3v2FrameIds::lContentGroupDescription
@ lContentGroupDescription
Definition: id3v2frameids.h:41
TagParser::Id3v2FrameIds::lArtist
@ lArtist
Definition: id3v2frameids.h:15
TagParser::Id3v2FrameIds::lRating
@ lRating
Definition: id3v2frameids.h:45
TagParser::Mp4TagAtomIds::Artist
@ Artist
Definition: mp4ids.h:88
TagParser::Id3v2FrameIds::sComment
@ sComment
Definition: id3v2frameids.h:50
TagParser::Mp4TagAtomIds::RecordLabel
@ RecordLabel
Definition: mp4ids.h:114
TagParser::RawDataType::Undefined
@ Undefined
Definition: mp4tagfield.h:45
TagParser::Id3v2FrameIds::convertToLongId
TAG_PARSER_EXPORT std::uint32_t convertToLongId(std::uint32_t id)
Converts the specified short frame ID to the equivalent long frame ID.
Definition: id3v2frameids.cpp:87
TagParser::Mp4TagAtomIds::DiskPosition
@ DiskPosition
Definition: mp4ids.h:96
TagParser::Mp4TagAtomIds::Composer
@ Composer
Definition: mp4ids.h:92
TagParser::Mp4TagAtomIds::Comment
@ Comment
Definition: mp4ids.h:91
TagParser::Id3v2FrameIds::lBpm
@ lBpm
Definition: id3v2frameids.h:32
TagParser::Id3v2FrameIds::sRecordLabel
@ sRecordLabel
Definition: id3v2frameids.h:71
TagParser::TagField::idToString
std::string idToString() const
Definition: generictagfield.h:120
TagParser::Id3v2FrameIds::lEncoder
@ lEncoder
Definition: id3v2frameids.h:31
TagParser::Id3v2TagMaker
The Id3v2TagMaker class helps writing ID3v2 tags.
Definition: id3v2tag.h:18
TagParser::Id3v2FrameIds::lEncoderSettings
@ lEncoderSettings
Definition: id3v2frameids.h:37
TagParser::Id3v2FrameIds::sArtist
@ sArtist
Definition: id3v2frameids.h:49
TagParser::Id3v2FrameIds::lRecordingDates
@ lRecordingDates
Definition: id3v2frameids.h:19
TagParser::Id3v2FrameIds::sLanguage
@ sLanguage
Definition: id3v2frameids.h:65
TagParser::Id3v2FrameIds::lYear
@ lYear
Definition: id3v2frameids.h:17