Tag Parser  8.2.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
overallmp3.cpp
Go to the documentation of this file.
1 #include "./helper.h"
2 #include "./overall.h"
3 
4 #include "../abstracttrack.h"
5 #include "../id3/id3v1tag.h"
6 #include "../id3/id3v2tag.h"
7 #include "../mpegaudio/mpegaudioframe.h"
8 
9 #include <regex>
10 
11 namespace Mp3TestFlags {
12 enum TestFlag {
13  ForceRewring = 0x1,
16  Id3v1Only = 0x8,
18  UseId3v24 = 0x10,
19 };
20 }
21 
25 void OverallTests::checkMp3Testfile1()
26 {
27  CPPUNIT_ASSERT_EQUAL(ContainerFormat::MpegAudioFrames, m_fileInfo.containerFormat());
28  const auto tracks = m_fileInfo.tracks();
29  CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
30  for (const auto &track : tracks) {
31  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
32  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Mpeg1Audio, track->format().general);
33  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::Mpeg1Layer3), track->format().sub);
34  CPPUNIT_ASSERT_EQUAL(static_cast<uint16>(2), track->channelCount());
35  CPPUNIT_ASSERT_EQUAL(static_cast<byte>(MpegChannelMode::JointStereo), track->channelConfig());
36  CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
37  CPPUNIT_ASSERT_EQUAL(3, track->duration().seconds());
38  }
39  const auto tags = m_fileInfo.tags();
40  switch (m_tagStatus) {
42  CPPUNIT_ASSERT(m_fileInfo.id3v1Tag());
43  CPPUNIT_ASSERT_EQUAL(1_st, m_fileInfo.id3v2Tags().size());
44  CPPUNIT_ASSERT_EQUAL(2_st, tags.size());
45  for (const auto &tag : tags) {
46  CPPUNIT_ASSERT_EQUAL(4, tag->value(KnownField::TrackPosition).toPositionInSet().position());
47  CPPUNIT_ASSERT_EQUAL("1984"s, tag->value(KnownField::Year).toString());
48  switch (tag->type()) {
49  case TagType::Id3v1Tag:
50  CPPUNIT_ASSERT_EQUAL("Cohesion"s, tag->value(KnownField::Title).toString());
51  CPPUNIT_ASSERT_EQUAL("Minutemen"s, tag->value(KnownField::Artist).toString());
52  CPPUNIT_ASSERT_EQUAL("Double Nickels On The Dime"s, tag->value(KnownField::Album).toString());
53  CPPUNIT_ASSERT_EQUAL("Punk Rock"s, tag->value(KnownField::Genre).toString());
54  CPPUNIT_ASSERT_EQUAL("ExactAudioCopy v0.95b4"s, tag->value(KnownField::Comment).toString());
55  break;
56  case TagType::Id3v2Tag:
57  CPPUNIT_ASSERT_EQUAL(TagTextEncoding::Utf16LittleEndian, tag->value(KnownField::Title).dataEncoding());
58  CPPUNIT_ASSERT_EQUAL(u"Cohesion"s, tag->value(KnownField::Title).toWString());
59  CPPUNIT_ASSERT_EQUAL("Cohesion"s, tag->value(KnownField::Title).toString(TagTextEncoding::Utf8));
60  CPPUNIT_ASSERT_EQUAL(u"Minutemen"s, tag->value(KnownField::Artist).toWString());
61  CPPUNIT_ASSERT_EQUAL("Minutemen"s, tag->value(KnownField::Artist).toString(TagTextEncoding::Utf8));
62  CPPUNIT_ASSERT_EQUAL(u"Double Nickels On The Dime"s, tag->value(KnownField::Album).toWString());
63  CPPUNIT_ASSERT_EQUAL("Double Nickels On The Dime"s, tag->value(KnownField::Album).toString(TagTextEncoding::Utf8));
64  CPPUNIT_ASSERT_EQUAL(u"Punk Rock"s, tag->value(KnownField::Genre).toWString());
65  CPPUNIT_ASSERT_EQUAL("Punk Rock"s, tag->value(KnownField::Genre).toString(TagTextEncoding::Utf8));
66  CPPUNIT_ASSERT_EQUAL(u"ExactAudioCopy v0.95b4"s, tag->value(KnownField::Comment).toWString());
67  CPPUNIT_ASSERT_EQUAL("ExactAudioCopy v0.95b4"s, tag->value(KnownField::Comment).toString(TagTextEncoding::Utf8));
68  CPPUNIT_ASSERT_EQUAL(43, tag->value(KnownField::TrackPosition).toPositionInSet().total());
69  CPPUNIT_ASSERT(tag->value(KnownField::Length).toTimeSpan().isNull());
70  CPPUNIT_ASSERT(tag->value(KnownField::Lyricist).isEmpty());
71  break;
72  default:;
73  }
74  }
75  break;
77  checkMp3TestMetaData();
78  break;
79  case TagStatus::Removed:
80  CPPUNIT_ASSERT_EQUAL(0_st, tracks.size());
81  }
82 
83  CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
84 }
85 
89 void OverallTests::checkMp3Testfile2()
90 {
91  CPPUNIT_ASSERT_EQUAL(ContainerFormat::MpegAudioFrames, m_fileInfo.containerFormat());
92  const auto tracks = m_fileInfo.tracks();
93  CPPUNIT_ASSERT_EQUAL(1_st, tracks.size());
94  for (const auto &track : tracks) {
95  CPPUNIT_ASSERT_EQUAL(MediaType::Audio, track->mediaType());
96  CPPUNIT_ASSERT_EQUAL(GeneralMediaFormat::Mpeg1Audio, track->format().general);
97  CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>(SubFormats::Mpeg1Layer3), track->format().sub);
98  CPPUNIT_ASSERT_EQUAL(static_cast<uint16>(2), track->channelCount());
99  CPPUNIT_ASSERT_EQUAL(static_cast<byte>(MpegChannelMode::Stereo), track->channelConfig());
100  CPPUNIT_ASSERT_EQUAL(44100u, track->samplingFrequency());
101  CPPUNIT_ASSERT_EQUAL(20, track->duration().seconds());
102  }
103  const auto tags = m_fileInfo.tags();
104  const bool expectId3v24 = m_tagStatus == TagStatus::Original || m_mode & Mp3TestFlags::UseId3v24;
105  switch (m_tagStatus) {
106  case TagStatus::Original:
108  CPPUNIT_ASSERT(!m_fileInfo.id3v1Tag());
109  CPPUNIT_ASSERT_EQUAL(1_st, m_fileInfo.id3v2Tags().size());
110  CPPUNIT_ASSERT_EQUAL(1_st, tags.size());
111  for (const auto &tag : tags) {
112  if (tag->type() != TagType::Id3v2Tag) {
113  CPPUNIT_FAIL(argsToString("no ", tag->typeName(), " tag expected"));
114  }
115  const auto *const id3v2Tag = static_cast<const Id3v2Tag *>(tag);
116 
117  // check values as usual
118  CPPUNIT_ASSERT_EQUAL(expectId3v24 ? 4 : 3, static_cast<int>(id3v2Tag->majorVersion()));
119  CPPUNIT_ASSERT_EQUAL(
120  expectId3v24 ? TagTextEncoding::Utf8 : TagTextEncoding::Utf16LittleEndian, tag->value(KnownField::Title).dataEncoding());
121  CPPUNIT_ASSERT_EQUAL("Infinite (Original Mix)"s, tag->value(KnownField::Title).toString(TagTextEncoding::Utf8));
122  CPPUNIT_ASSERT_EQUAL("B-Front"s, tag->value(KnownField::Artist).toString(TagTextEncoding::Utf8));
123  CPPUNIT_ASSERT_EQUAL("Infinite"s, tag->value(KnownField::Album).toString(TagTextEncoding::Utf8));
124  CPPUNIT_ASSERT_EQUAL(m_tagStatus == TagStatus::TestMetaDataPresent ? "Test"s : "Hardstyle"s,
125  tag->value(KnownField::Genre).toString(TagTextEncoding::Utf8));
126  CPPUNIT_ASSERT_EQUAL("Lavf57.83.100"s, tag->value(KnownField::EncoderSettings).toString(TagTextEncoding::Utf8));
127  CPPUNIT_ASSERT_EQUAL("Roughstate"s, tag->value(KnownField::RecordLabel).toString(TagTextEncoding::Utf8));
128  CPPUNIT_ASSERT_EQUAL("2017"s, tag->value(KnownField::RecordDate).toString(TagTextEncoding::Utf8));
129  CPPUNIT_ASSERT_EQUAL(1, tag->value(KnownField::TrackPosition).toPositionInSet().position());
130  CPPUNIT_ASSERT(tag->value(KnownField::Length).toTimeSpan().isNull());
131  CPPUNIT_ASSERT(tag->value(KnownField::Lyricist).isEmpty());
132 
133  // check additional text frame values
134  const auto &fields = id3v2Tag->fields();
135  auto genreFields = fields.equal_range(Id3v2FrameIds::lGenre);
136  CPPUNIT_ASSERT_MESSAGE("genre field present"s, genreFields.first != genreFields.second);
137  const auto &genreField = genreFields.first->second;
138  const auto &additionalValues = genreField.additionalValues();
139  if (m_tagStatus == TagStatus::TestMetaDataPresent) {
140  CPPUNIT_ASSERT_EQUAL("Test"s, tag->value(KnownField::Genre).toString(TagTextEncoding::Utf8));
141  CPPUNIT_ASSERT_EQUAL(1_st, additionalValues.size());
142  CPPUNIT_ASSERT_EQUAL("Example"s, additionalValues[0].toString(TagTextEncoding::Utf8));
143  } else {
144  CPPUNIT_ASSERT_EQUAL("Hardstyle"s, tag->value(KnownField::Genre).toString(TagTextEncoding::Utf8));
145  CPPUNIT_ASSERT_EQUAL(3_st, additionalValues.size());
146  CPPUNIT_ASSERT_EQUAL("Test"s, additionalValues[0].toString(TagTextEncoding::Utf8));
147  CPPUNIT_ASSERT_EQUAL("Example"s, additionalValues[1].toString(TagTextEncoding::Utf8));
148  CPPUNIT_ASSERT_EQUAL("Hard Dance"s, additionalValues[2].toString(TagTextEncoding::Utf8));
149  }
150  CPPUNIT_ASSERT_MESSAGE("exactly one genre field present"s, ++genreFields.first == genreFields.second);
151 
152  // check whether additional text frame values are returned correctly by values()
153  const auto artists = id3v2Tag->values(KnownField::Artist);
154  CPPUNIT_ASSERT_EQUAL(m_tagStatus == TagStatus::TestMetaDataPresent ? 3_st : 2_st, artists.size());
155  CPPUNIT_ASSERT_EQUAL("B-Front"s, artists[0]->toString(TagTextEncoding::Utf8));
156  CPPUNIT_ASSERT_EQUAL("Second Artist Example"s, artists[1]->toString(TagTextEncoding::Utf8));
157  if (m_tagStatus == TagStatus::TestMetaDataPresent) {
158  CPPUNIT_ASSERT_EQUAL("3rd Artist Example"s, artists[2]->toString(TagTextEncoding::Utf8));
159  }
160 
161  const auto genres = id3v2Tag->values(KnownField::Genre);
162  if (m_tagStatus == TagStatus::TestMetaDataPresent) {
163  CPPUNIT_ASSERT_EQUAL(2_st, genres.size());
164  CPPUNIT_ASSERT_EQUAL("Test"s, genres[0]->toString(TagTextEncoding::Utf8));
165  CPPUNIT_ASSERT_EQUAL("Example"s, genres[1]->toString(TagTextEncoding::Utf8));
166  } else {
167  CPPUNIT_ASSERT_EQUAL(4_st, genres.size());
168  CPPUNIT_ASSERT_EQUAL("Hardstyle"s, genres[0]->toString(TagTextEncoding::Utf8));
169  CPPUNIT_ASSERT_EQUAL("Test"s, genres[1]->toString(TagTextEncoding::Utf8));
170  CPPUNIT_ASSERT_EQUAL("Example"s, genres[2]->toString(TagTextEncoding::Utf8));
171  CPPUNIT_ASSERT_EQUAL("Hard Dance"s, genres[3]->toString(TagTextEncoding::Utf8));
172  }
173  }
174  break;
175  case TagStatus::Removed:
176  CPPUNIT_ASSERT_EQUAL(0_st, tags.size());
177  }
178 
179  if (expectId3v24 || m_tagStatus == TagStatus::Removed) {
180  CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Information);
181  return;
182  }
183 
184  CPPUNIT_ASSERT(m_diag.level() <= DiagLevel::Warning);
185  int warningCount = 0;
186  for (const auto &msg : m_diag) {
187  if (msg.level() != DiagLevel::Warning) {
188  continue;
189  }
190  ++warningCount;
191  TESTUTILS_ASSERT_LIKE("context", "(parsing|making) (TPE1|TCON)( frame)?", msg.context());
192  TESTUTILS_ASSERT_LIKE("message",
193  "Multiple strings (found|assigned) .*"
194  "Additional (values \"Second Artist Example\" and \"3rd Artist Example\" are|"
195  "value \"Example\" is) "
196  "supposed to be ignored.",
197  msg.message());
198  }
199  CPPUNIT_ASSERT_EQUAL_MESSAGE("exactly 4 warnings present", 4, warningCount);
200 }
201 
205 void OverallTests::checkMp3TestMetaData()
206 {
207  using namespace Mp3TestFlags;
208 
209  // check whether tags are assigned according to the current test mode
210  Id3v1Tag *id3v1Tag = nullptr;
211  Id3v2Tag *id3v2Tag = nullptr;
212  if (m_mode & Id3v2AndId3v1) {
213  CPPUNIT_ASSERT(id3v1Tag = m_fileInfo.id3v1Tag());
214  CPPUNIT_ASSERT(id3v2Tag = m_fileInfo.id3v2Tags().at(0).get());
215  } else if (m_mode & Id3v1Only) {
216  CPPUNIT_ASSERT(id3v1Tag = m_fileInfo.id3v1Tag());
217  CPPUNIT_ASSERT(m_fileInfo.id3v2Tags().empty());
218  } else {
219  CPPUNIT_ASSERT(!m_fileInfo.id3v1Tag());
220  CPPUNIT_ASSERT(id3v2Tag = m_fileInfo.id3v2Tags().at(0).get());
221  }
222 
223  // check common test meta data
224  if (id3v1Tag) {
225  CPPUNIT_ASSERT_EQUAL(m_testTitle, id3v1Tag->value(KnownField::Title));
226  CPPUNIT_ASSERT_EQUAL(m_testComment.toString(), id3v1Tag->value(KnownField::Comment).toString()); // ignore encoding here
227  CPPUNIT_ASSERT_EQUAL(m_testAlbum, id3v1Tag->value(KnownField::Album));
228  CPPUNIT_ASSERT_EQUAL(m_preservedMetaData.front(), id3v1Tag->value(KnownField::Artist));
229  m_preservedMetaData.pop();
230  }
231  if (id3v2Tag) {
232  const TagValue &titleValue = id3v2Tag->value(KnownField::Title);
233  const TagValue &commentValue = id3v2Tag->value(KnownField::Comment);
234 
235  if (m_mode & UseId3v24) {
236  CPPUNIT_ASSERT_EQUAL(m_testTitle, titleValue);
237  CPPUNIT_ASSERT_EQUAL(m_testComment, commentValue);
238  CPPUNIT_ASSERT_EQUAL(m_testAlbum, id3v2Tag->value(KnownField::Album));
239  CPPUNIT_ASSERT_EQUAL(m_preservedMetaData.front(), id3v2Tag->value(KnownField::Artist));
240  // TODO: check more fields
241  } else {
242  CPPUNIT_ASSERT_EQUAL_MESSAGE("not attempted to use UTF-8 in ID3v2.3", TagTextEncoding::Utf16LittleEndian, titleValue.dataEncoding());
243  CPPUNIT_ASSERT_EQUAL(m_testTitle.toString(), titleValue.toString(TagTextEncoding::Utf8));
244  CPPUNIT_ASSERT_EQUAL_MESSAGE("not attempted to use UTF-8 in ID3v2.3", TagTextEncoding::Utf16LittleEndian, commentValue.dataEncoding());
245  CPPUNIT_ASSERT_EQUAL_MESSAGE(
246  "not attempted to use UTF-8 in ID3v2.3", TagTextEncoding::Utf16LittleEndian, commentValue.descriptionEncoding());
247  CPPUNIT_ASSERT_EQUAL(m_testComment.toString(), commentValue.toString(TagTextEncoding::Utf8));
248  CPPUNIT_ASSERT_EQUAL_MESSAGE(
249  "description is also converted to UTF-16", "s\0o\0m\0e\0 \0d\0e\0s\0c\0r\0i\0p\0t\0i\0\xf3\0n\0"s, commentValue.description());
250  CPPUNIT_ASSERT_EQUAL(m_testAlbum.toString(TagTextEncoding::Utf8), id3v2Tag->value(KnownField::Album).toString(TagTextEncoding::Utf8));
251  CPPUNIT_ASSERT_EQUAL(m_preservedMetaData.front(), id3v2Tag->value(KnownField::Artist));
252  // TODO: check more fields
253  }
254 
255  m_preservedMetaData.pop();
256  }
257 
258  // test ID3v1 specific test meta data
259  if (id3v1Tag) {
260  CPPUNIT_ASSERT_EQUAL(m_testPosition.toPositionInSet().position(), id3v1Tag->value(KnownField::TrackPosition).toPositionInSet().position());
261  }
262  // test ID3v2 specific test meta data
263  if (id3v2Tag) {
264  CPPUNIT_ASSERT_EQUAL(m_testPosition, id3v2Tag->value(KnownField::TrackPosition));
265  CPPUNIT_ASSERT_EQUAL(m_testPosition, id3v2Tag->value(KnownField::DiskPosition));
266  }
267 }
268 
272 void OverallTests::checkMp3PaddingConstraints()
273 {
274  using namespace Mp3TestFlags;
275 
276  if (!(m_mode & Id3v1Only)) {
277  if (m_mode & PaddingConstraints) {
278  if (m_mode & ForceRewring) {
279  CPPUNIT_ASSERT_EQUAL(static_cast<uint64>(4096), m_fileInfo.paddingSize());
280  } else {
281  CPPUNIT_ASSERT(m_fileInfo.paddingSize() >= 1024);
282  CPPUNIT_ASSERT(m_fileInfo.paddingSize() <= (4096 + 1024));
283  }
284  }
285  } else {
286  // adding padding is not possible if no ID3v2 tag is present
287  }
288  // TODO: check rewriting behaviour
289 }
290 
294 void OverallTests::setMp3TestMetaData1()
295 {
296  using namespace Mp3TestFlags;
297 
298  // ensure tags are assigned according to the current test mode
299  Id3v1Tag *id3v1Tag = nullptr;
300  Id3v2Tag *id3v2Tag = nullptr;
301  if (m_mode & Id3v2AndId3v1) {
302  id3v1Tag = m_fileInfo.createId3v1Tag();
303  id3v2Tag = m_fileInfo.createId3v2Tag();
304  } else if (m_mode & Id3v1Only) {
305  id3v1Tag = m_fileInfo.createId3v1Tag();
306  m_fileInfo.removeAllId3v2Tags();
307  } else {
308  m_fileInfo.removeId3v1Tag();
309  id3v2Tag = m_fileInfo.createId3v2Tag();
310  }
311  if (!(m_mode & Id3v1Only) && m_mode & UseId3v24) {
312  id3v2Tag->setVersion(4, 0);
313  }
314 
315  // assign some test meta data
316  for (Tag *const tag : initializer_list<Tag *>{ id3v1Tag, id3v2Tag }) {
317  if (!tag) {
318  continue;
319  }
320  tag->setValue(KnownField::Title, m_testTitle);
321  tag->setValue(KnownField::Comment, m_testComment);
322  tag->setValue(KnownField::Album, m_testAlbum);
323  m_preservedMetaData.push(tag->value(KnownField::Artist));
324  tag->setValue(KnownField::TrackPosition, m_testPosition);
325  tag->setValue(KnownField::DiskPosition, m_testPosition);
326  // TODO: set more fields
327  }
328 }
329 
333 void OverallTests::setMp3TestMetaData2()
334 {
335  using namespace Mp3TestFlags;
336 
337  CPPUNIT_ASSERT_EQUAL(1_st, m_fileInfo.id3v2Tags().size());
338  auto &id3v2Tag(m_fileInfo.id3v2Tags().front());
339  id3v2Tag->setVersion((m_mode & UseId3v24) ? 4 : 3, 0);
340  const auto artists = id3v2Tag->values(KnownField::Artist);
341  CPPUNIT_ASSERT_EQUAL(2_st, artists.size());
342  id3v2Tag->setValues(KnownField::Artist, { *artists[0], *artists[1], TagValue("3rd Artist Example") });
343  id3v2Tag->setValues(KnownField::Genre, { TagValue("Test"), TagValue("Example") });
344 }
345 
350 {
351  cerr << endl << "MP3 parser" << endl;
352  m_fileInfo.setForceFullParse(false);
353  m_tagStatus = TagStatus::Original;
354  parseFile(TestUtilities::testFilePath("mtx-test-data/mp3/id3-tag-and-xing-header.mp3"), &OverallTests::checkMp3Testfile1);
355  parseFile(TestUtilities::testFilePath("misc/multiple_id3v2_4_values.mp3"), &OverallTests::checkMp3Testfile2);
356 }
357 
363 {
364  // full parse is required to determine padding
365  m_fileInfo.setForceFullParse(true);
366 
367  // do the test under different conditions
368  for (m_mode = 0; m_mode != 0x20; ++m_mode) {
369  using namespace Mp3TestFlags;
370 
371  // setup test conditions
372  m_fileInfo.setForceRewrite(m_mode & ForceRewring);
373  if (m_mode & UseId3v24) {
374  if (m_mode & Id3v1Only) {
375  continue;
376  }
377  }
378  m_fileInfo.setTagPosition(ElementPosition::Keep);
379  m_fileInfo.setIndexPosition(ElementPosition::Keep);
380  m_fileInfo.setPreferredPadding(m_mode & PaddingConstraints ? 4096 : 0);
381  m_fileInfo.setMinPadding(m_mode & PaddingConstraints ? 1024 : 0);
382  m_fileInfo.setMaxPadding(m_mode & PaddingConstraints ? (4096 + 1024) : numeric_limits<size_t>::max());
383  m_fileInfo.setForceTagPosition(false);
384  m_fileInfo.setForceIndexPosition(false);
385 
386  // print test conditions
387  list<string> testConditions;
388  if (m_mode & ForceRewring) {
389  testConditions.emplace_back("forcing rewrite");
390  }
391  if (m_mode & Id3v2AndId3v1) {
392  if (m_mode & RemoveTag) {
393  testConditions.emplace_back("removing tag");
394  } else {
395  testConditions.emplace_back("ID3v1 and ID3v2");
396  }
397  } else if (m_mode & Id3v1Only) {
398  testConditions.emplace_back("ID3v1 only");
399  } else {
400  testConditions.emplace_back("ID3v2 only");
401  }
402  if (m_mode & PaddingConstraints) {
403  testConditions.emplace_back("padding constraints");
404  }
405  if (m_mode & UseId3v24) {
406  testConditions.emplace_back("use ID3v2.4");
407  }
408  cerr << endl << "MP3 maker - testmode " << m_mode << ": " << joinStrings(testConditions, ", ") << endl;
409 
410  // do actual tests
411  m_tagStatus = (m_mode & RemoveTag) ? TagStatus::Removed : TagStatus::TestMetaDataPresent;
412  makeFile(TestUtilities::workingCopyPath("mtx-test-data/mp3/id3-tag-and-xing-header.mp3"),
413  (m_mode & RemoveTag) ? &OverallTests::removeAllTags : &OverallTests::setMp3TestMetaData1, &OverallTests::checkMp3Testfile1);
414  makeFile(TestUtilities::workingCopyPath("misc/multiple_id3v2_4_values.mp3"),
415  (m_mode & RemoveTag) ? &OverallTests::removeAllTags : &OverallTests::setMp3TestMetaData2, &OverallTests::checkMp3Testfile2);
416  }
417 }
TagTextEncoding dataEncoding() const
Returns the data encoding.
Definition: tagvalue.h:538
bool setValues(const IdentifierType &id, const std::vector< TagValue > &values)
Assigns the given values to the field with the specified id.
The Tag class is used to store, read and write tag information.
Definition: tag.h:98
const TagValue & value(const IdentifierType &id) const
Returns the value of the field with the specified id.
Id3v1Tag * id3v1Tag() const
Returns a pointer to the assigned ID3v1 tag or nullptr if none is assigned.
TagTextEncoding descriptionEncoding() const
Returns the description encoding.
Definition: tagvalue.h:548
const std::string & description() const
Returns the description.
Definition: tagvalue.h:448
constexpr int32 position() const
Returns the element position of the current instance.
Definition: positioninset.h:76
const std::vector< std::unique_ptr< Id3v2Tag > > & id3v2Tags() const
Returns pointers to the assigned ID3v2 tags.
std::vector< const TagValue * > values(const IdentifierType &id) const
Returns the values of the field with the specified id.
void tags(std::vector< Tag * > &tags) const
Stores all tags assigned to the current file in the specified vector.
ContainerFormat containerFormat() const
Returns the container format of the current file.
void testMp3Making()
Tests the MP3 maker via MediaFileInfo.
Definition: overallmp3.cpp:362
DiagLevel level() const
Returns the worst diag level present in the container.
Definition: diagnostics.cpp:53
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation.
Definition: tagvalue.cpp:253
void setForceFullParse(bool forceFullParse)
Sets whether forcing a full parse is enabled.
void testMp3Parsing()
Tests the MP3 parser via MediaFileInfo.
Definition: overallmp3.cpp:349
Implementation of TagParser::Tag for ID3v2 tags.
Definition: id3v2tag.h:61
Implementation of TagParser::Tag for ID3v1 tags.
Definition: id3v1tag.h:10
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
Definition: tagvalue.h:365
std::vector< AbstractTrack * > tracks() const
Returns the tracks for the current file.
The TagValue class wraps values of different types.
Definition: tagvalue.h:65
void setVersion(byte majorVersion, byte revisionVersion)
Sets the version to the specified majorVersion and the specified revisionVersion.
Definition: id3v2tag.cpp:494
const TagValue & value(KnownField value) const override
Returns the value of the specified field.
Definition: id3v1tag.cpp:134