Fix parseTags() for FLAC, consider tags unsupported if container unknown
FLAC stores tags on track level. Hence we must parse the tracks here in order to parse the tags. This hasn't been taken into account when refactoring the tag editor CLI leading to https://github.com/Martchus/tageditor/issues/36. So let's handle these format specific details in the tagparser library which will now internally parse tracks when calling parseTags() on FLAC files. This also fixes the weird behavior to consider tags supported although the container format is unknown.
This commit is contained in:
parent
d856fb4c75
commit
0f0260fb77
|
@ -174,7 +174,7 @@ set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
|
|||
set(META_APP_DESCRIPTION "C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags")
|
||||
set(META_VERSION_MAJOR 7)
|
||||
set(META_VERSION_MINOR 0)
|
||||
set(META_VERSION_PATCH 0)
|
||||
set(META_VERSION_PATCH 1)
|
||||
set(META_PUBLIC_SHARED_LIB_DEPENDS c++utilities)
|
||||
set(META_PUBLIC_STATIC_LIB_DEPENDS c++utilities_static)
|
||||
set(META_PRIVATE_COMPILE_DEFINITIONS LEGACY_API)
|
||||
|
|
|
@ -150,8 +150,8 @@ MediaFileInfo::~MediaFileInfo()
|
|||
*/
|
||||
void MediaFileInfo::parseContainerFormat(Diagnostics &diag)
|
||||
{
|
||||
// skip if container format already parsed
|
||||
if (containerParsingStatus() != ParsingStatus::NotParsedYet) {
|
||||
// there's no need to read the container format twice
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -293,41 +293,49 @@ startParsingSignature:
|
|||
*/
|
||||
void MediaFileInfo::parseTracks(Diagnostics &diag)
|
||||
{
|
||||
if (tracksParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the tracks twice
|
||||
// skip if tracks already parsed
|
||||
if (tracksParsingStatus() != ParsingStatus::NotParsedYet) {
|
||||
return;
|
||||
}
|
||||
static const string context("parsing tracks");
|
||||
|
||||
try {
|
||||
// parse tracks via container object
|
||||
if (m_container) {
|
||||
m_container->parseTracks(diag);
|
||||
} else {
|
||||
switch (m_containerFormat) {
|
||||
case ContainerFormat::Adts:
|
||||
m_singleTrack = make_unique<AdtsStream>(stream(), m_containerOffset);
|
||||
break;
|
||||
case ContainerFormat::Flac:
|
||||
m_singleTrack = make_unique<FlacStream>(*this, m_containerOffset);
|
||||
break;
|
||||
case ContainerFormat::MpegAudioFrames:
|
||||
m_singleTrack = make_unique<MpegAudioFrameStream>(stream(), m_containerOffset);
|
||||
break;
|
||||
case ContainerFormat::RiffWave:
|
||||
m_singleTrack = make_unique<WaveAudioStream>(stream(), m_containerOffset);
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException();
|
||||
}
|
||||
m_singleTrack->parseHeader(diag);
|
||||
|
||||
switch (m_containerFormat) {
|
||||
case ContainerFormat::Flac:
|
||||
// FLAC streams might container padding
|
||||
m_paddingSize += static_cast<FlacStream *>(m_singleTrack.get())->paddingSize();
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
m_tracksParsingStatus = ParsingStatus::Ok;
|
||||
return;
|
||||
}
|
||||
|
||||
// parse tracks via track object for "single-track"-formats
|
||||
switch (m_containerFormat) {
|
||||
case ContainerFormat::Adts:
|
||||
m_singleTrack = make_unique<AdtsStream>(stream(), m_containerOffset);
|
||||
break;
|
||||
case ContainerFormat::Flac:
|
||||
m_singleTrack = make_unique<FlacStream>(*this, m_containerOffset);
|
||||
break;
|
||||
case ContainerFormat::MpegAudioFrames:
|
||||
m_singleTrack = make_unique<MpegAudioFrameStream>(stream(), m_containerOffset);
|
||||
break;
|
||||
case ContainerFormat::RiffWave:
|
||||
m_singleTrack = make_unique<WaveAudioStream>(stream(), m_containerOffset);
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException();
|
||||
}
|
||||
m_singleTrack->parseHeader(diag);
|
||||
|
||||
// take padding for some "single-track" formats into account
|
||||
switch (m_containerFormat) {
|
||||
case ContainerFormat::Flac:
|
||||
m_paddingSize += static_cast<FlacStream *>(m_singleTrack.get())->paddingSize();
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
|
||||
m_tracksParsingStatus = ParsingStatus::Ok;
|
||||
|
||||
} catch (const NotImplementedException &) {
|
||||
diag.emplace_back(DiagLevel::Information, "Parsing tracks is not implemented for the container format of the file.", context);
|
||||
m_tracksParsingStatus = ParsingStatus::NotSupported;
|
||||
|
@ -353,11 +361,13 @@ void MediaFileInfo::parseTracks(Diagnostics &diag)
|
|||
*/
|
||||
void MediaFileInfo::parseTags(Diagnostics &diag)
|
||||
{
|
||||
if (tagsParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the tags twice
|
||||
// skip if tags already parsed
|
||||
if (tagsParsingStatus() != ParsingStatus::NotParsedYet) {
|
||||
return;
|
||||
}
|
||||
static const string context("parsing tag");
|
||||
// check for id3v1 tag
|
||||
|
||||
// check for ID3v1 tag
|
||||
if (size() >= 128) {
|
||||
m_id3v1Tag = make_unique<Id3v1Tag>();
|
||||
try {
|
||||
|
@ -371,7 +381,8 @@ void MediaFileInfo::parseTags(Diagnostics &diag)
|
|||
diag.emplace_back(DiagLevel::Critical, "Unable to parse ID3v1 tag.", context);
|
||||
}
|
||||
}
|
||||
// the offsets of the ID3v2 tags have already been parsed when parsing the container format
|
||||
|
||||
// check for ID3v2 tags: the offsets of the ID3v2 tags have already been parsed when parsing the container format
|
||||
m_id3v2Tags.clear();
|
||||
for (const auto offset : m_actualId3v2TagOffsets) {
|
||||
auto id3v2Tag = make_unique<Id3v2Tag>();
|
||||
|
@ -387,23 +398,31 @@ void MediaFileInfo::parseTags(Diagnostics &diag)
|
|||
}
|
||||
m_id3v2Tags.emplace_back(id3v2Tag.release());
|
||||
}
|
||||
if (m_container) {
|
||||
try {
|
||||
|
||||
// check for tags in tracks (FLAC only) or via container object
|
||||
try {
|
||||
if (m_containerFormat == ContainerFormat::Flac) {
|
||||
parseTracks(diag);
|
||||
} else if (m_container) {
|
||||
m_container->parseTags(diag);
|
||||
} catch (const NotImplementedException &) {
|
||||
if (m_tagsParsingStatus == ParsingStatus::NotParsedYet) {
|
||||
// do not override parsing status from ID3 tags here
|
||||
m_tagsParsingStatus = ParsingStatus::NotSupported;
|
||||
}
|
||||
diag.emplace_back(DiagLevel::Information, "Parsing tags is not implemented for the container format of the file.", context);
|
||||
} catch (const Failure &) {
|
||||
m_tagsParsingStatus = ParsingStatus::CriticalFailure;
|
||||
diag.emplace_back(DiagLevel::Critical, "Unable to parse tag.", context);
|
||||
} else {
|
||||
throw NotImplementedException();
|
||||
}
|
||||
}
|
||||
if (m_tagsParsingStatus == ParsingStatus::NotParsedYet) {
|
||||
// do not override error status here
|
||||
m_tagsParsingStatus = ParsingStatus::Ok;
|
||||
|
||||
// set status, but do not override error/unsupported status form ID3 tags here
|
||||
if (m_tagsParsingStatus == ParsingStatus::NotParsedYet) {
|
||||
m_tagsParsingStatus = ParsingStatus::Ok;
|
||||
}
|
||||
|
||||
} catch (const NotImplementedException &) {
|
||||
// set status to not supported, but do not override parsing status from ID3 tags here
|
||||
if (m_tagsParsingStatus == ParsingStatus::NotParsedYet) {
|
||||
m_tagsParsingStatus = ParsingStatus::NotSupported;
|
||||
}
|
||||
diag.emplace_back(DiagLevel::Information, "Parsing tags is not implemented for the container format of the file.", context);
|
||||
} catch (const Failure &) {
|
||||
m_tagsParsingStatus = ParsingStatus::CriticalFailure;
|
||||
diag.emplace_back(DiagLevel::Critical, "Unable to parse tag.", context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,17 +439,19 @@ void MediaFileInfo::parseTags(Diagnostics &diag)
|
|||
*/
|
||||
void MediaFileInfo::parseChapters(Diagnostics &diag)
|
||||
{
|
||||
if (chaptersParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the chapters twice
|
||||
// skip if chapters already parsed
|
||||
if (chaptersParsingStatus() != ParsingStatus::NotParsedYet) {
|
||||
return;
|
||||
}
|
||||
static const string context("parsing chapters");
|
||||
|
||||
try {
|
||||
if (m_container) {
|
||||
m_container->parseChapters(diag);
|
||||
m_chaptersParsingStatus = ParsingStatus::Ok;
|
||||
} else {
|
||||
// parse chapters via container object
|
||||
if (!m_container) {
|
||||
throw NotImplementedException();
|
||||
}
|
||||
m_container->parseChapters(diag);
|
||||
m_chaptersParsingStatus = ParsingStatus::Ok;
|
||||
} catch (const NotImplementedException &) {
|
||||
m_chaptersParsingStatus = ParsingStatus::NotSupported;
|
||||
diag.emplace_back(DiagLevel::Information, "Parsing chapters is not implemented for the container format of the file.", context);
|
||||
|
@ -453,17 +474,19 @@ void MediaFileInfo::parseChapters(Diagnostics &diag)
|
|||
*/
|
||||
void MediaFileInfo::parseAttachments(Diagnostics &diag)
|
||||
{
|
||||
if (attachmentsParsingStatus() != ParsingStatus::NotParsedYet) { // there's no need to read the attachments twice
|
||||
// skip if attachments already parsed
|
||||
if (attachmentsParsingStatus() != ParsingStatus::NotParsedYet) {
|
||||
return;
|
||||
}
|
||||
static const string context("parsing attachments");
|
||||
|
||||
try {
|
||||
if (m_container) {
|
||||
m_container->parseAttachments(diag);
|
||||
m_attachmentsParsingStatus = ParsingStatus::Ok;
|
||||
} else {
|
||||
// parse attachments via container object
|
||||
if (!m_container) {
|
||||
throw NotImplementedException();
|
||||
}
|
||||
m_container->parseAttachments(diag);
|
||||
m_attachmentsParsingStatus = ParsingStatus::Ok;
|
||||
} catch (const NotImplementedException &) {
|
||||
m_attachmentsParsingStatus = ParsingStatus::NotSupported;
|
||||
diag.emplace_back(DiagLevel::Information, "Parsing attachments is not implemented for the container format of the file.", context);
|
||||
|
|
|
@ -92,9 +92,7 @@ void MediaFileInfoTests::testParsingUnsupportedFile()
|
|||
file.parseContainerFormat(diag);
|
||||
file.parseTags(diag);
|
||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.containerParsingStatus());
|
||||
// NOTE: parsing tags of unsupported container is actually supported: there is nothing to do
|
||||
// but maybe not what one would expect?
|
||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
|
||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.tagsParsingStatus());
|
||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
|
||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.chaptersParsingStatus());
|
||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.attachmentsParsingStatus());
|
||||
|
|
Loading…
Reference in New Issue