Improve handling of targets

This commit is contained in:
Martchus 2016-05-26 01:59:22 +02:00
parent 0dc6d59240
commit 415e68972a
11 changed files with 162 additions and 42 deletions

View File

@ -1,6 +1,5 @@
#include "./matroskatag.h"
#include "./ebmlelement.h"
#include "./matroskatagid.h"
#include <map>
#include <initializer_list>
@ -157,7 +156,7 @@ void MatroskaTag::parseTargets(EbmlElement &targetsElement)
while(child) {
try {
child->parse();
} catch (Failure &) {
} catch(const Failure &) {
addNotification(NotificationType::Critical, "Unable to parse childs of Targets element.", context);
break;
}

View File

@ -2,6 +2,7 @@
#define MEDIA_MATROSKATAG_H
#include "./matroskatagfield.h"
#include "./matroskatagid.h"
#include "../fieldbasedtag.h"
@ -56,6 +57,7 @@ public:
TagTextEncoding proposedTextEncoding() const;
bool canEncodingBeUsed(TagTextEncoding encoding) const;
bool supportsTarget() const;
TagTargetLevel targetLevel() const;
std::string fieldId(KnownField field) const;
KnownField knownField(const std::string &id) const;
@ -68,17 +70,22 @@ private:
void parseTargets(EbmlElement &targetsElement);
};
inline bool MatroskaTag::supportsTarget() const
{
return true;
}
/*!
* \brief Constructs a new tag.
*/
inline MatroskaTag::MatroskaTag()
{}
inline bool MatroskaTag::supportsTarget() const
{
return true;
}
inline TagTargetLevel MatroskaTag::targetLevel() const
{
return matroskaTagTargetLevel(m_target.level());
}
inline TagType MatroskaTag::type() const
{
return TagType::MatroskaTag;

View File

@ -1,7 +1,5 @@
#include "./matroskatagid.h"
#include <string>
using namespace std;
namespace Media {
@ -10,29 +8,4 @@ namespace MatroskaTagIds {
}
/*!
* \brief Returns a string for the specified \a targetTypeValue if
* known; otherwise returns an empty string.
*/
const char *matroskaTargetTypeName(uint32 targetTypeValue)
{
if(targetTypeValue >= 70) {
return "collection";
} else if(targetTypeValue >= 60) {
return "edition, issue, volume, opus, season, sequel";
} else if(targetTypeValue >= 50) {
return "album, opera, concert, movie, episode";
} else if(targetTypeValue >= 40) {
return "part, session";
} else if(targetTypeValue >= 30) {
return "track, song, chapter";
} else if(targetTypeValue >= 20) {
return "subtrack, part, movement, scene";
} else if(targetTypeValue >= 10) {
return "shot";
} else {
return "";
}
}
} // namespace Media

View File

@ -1,8 +1,7 @@
#ifndef MEDIA_MATROSKATAGIDS_H
#define MEDIA_MATROSKATAGIDS_H
#include <c++utilities/application/global.h>
#include <c++utilities/conversion/types.h>
#include "../tagtarget.h"
namespace Media {
@ -337,7 +336,21 @@ inline LIB_EXPORT const char *termsOfUse() {
}
LIB_EXPORT const char *matroskaTargetTypeName(uint32 targetTypeValue);
/*!
* \brief Returns the general TagTargetLevel for the Matroska specific \a targetLevelValue.
*/
inline LIB_EXPORT TagTargetLevel matroskaTagTargetLevel(uint64 targetLevelValue)
{
return targetLevelValue > 70 ? TagTargetLevel::Collection : static_cast<TagTargetLevel>(targetLevelValue / 10);
}
/*!
* \brief Returns the Matroska specific target level value for the specified general \a targetLevel.
*/
inline LIB_EXPORT uint64 matroskaTagTargetLevelValue(TagTargetLevel targetLevel)
{
return static_cast<uint64>(targetLevel) * 10;
}
} // namespace Media

View File

@ -330,7 +330,7 @@ inline bool MediaFileInfo::hasId3v1Tag() const
*/
inline bool MediaFileInfo::hasId3v2Tag() const
{
return m_id3v2Tags.size();
return !m_id3v2Tags.empty();
}
/*!

View File

@ -1,4 +1,5 @@
#include "./signature.h"
#include "./matroska/matroskatagid.h"
#include <c++utilities/conversion/binaryconversion.h>
@ -482,4 +483,32 @@ const char *containerMimeType(ContainerFormat containerFormat, MediaType mediaTy
}
}
/*!
* \brief Returns the general TagTargetLevel for the specified \a container format and raw \a targetLevelValue.
*/
TagTargetLevel containerTargetLevel(ContainerFormat containerFormat, uint64 targetLevelValue)
{
switch(containerFormat) {
case ContainerFormat::Matroska:
case ContainerFormat::Webm:
return matroskaTagTargetLevel(targetLevelValue);
default:
return TagTargetLevel::Unspecified;
}
}
/*!
* \brief Returns the raw target level value for the specified \a containerFormat and general \a targetLevel.
*/
uint64 containerTargetLevelValue(ContainerFormat containerFormat, TagTargetLevel targetLevel)
{
switch(containerFormat) {
case ContainerFormat::Matroska:
case ContainerFormat::Webm:
return matroskaTagTargetLevelValue(targetLevel);
default:
return 0;
}
}
}

View File

@ -8,6 +8,8 @@
namespace Media {
enum class TagTargetLevel : byte;
/*!
* \brief Specifies the container format.
*
@ -63,6 +65,8 @@ LIB_EXPORT const char *containerFormatName(ContainerFormat containerFormat);
LIB_EXPORT const char *containerFormatAbbreviation(ContainerFormat containerFormat, MediaType mediaType = MediaType::Unknown, unsigned int version = 0);
LIB_EXPORT const char *containerFormatSubversion(ContainerFormat containerFormat);
LIB_EXPORT const char *containerMimeType(ContainerFormat containerFormat, MediaType mediaType = MediaType::Unknown);
LIB_EXPORT TagTargetLevel containerTargetLevel(ContainerFormat containerFormat, uint64 targetLevelValue);
LIB_EXPORT uint64 containerTargetLevelValue(ContainerFormat containerFormat, TagTargetLevel targetLevel);
}

View File

@ -36,7 +36,7 @@ string Tag::toString() const
stringstream ss;
ss << typeName();
if(supportsTarget() && !target().isEmpty()) {
ss << " targeting " << target().toString();
ss << " targeting " << targetString();
}
return ss.str();
}

40
tag.h
View File

@ -115,6 +115,10 @@ public:
virtual bool supportsTarget() const;
const TagTarget &target() const;
void setTarget(const TagTarget &target);
virtual TagTargetLevel targetLevel() const;
const char *targetLevelName() const;
bool isTargetingLevel(TagTargetLevel tagTargetLevel) const;
std::string targetString() const;
virtual unsigned int fieldCount() const = 0;
virtual bool supportsField(KnownField field) const = 0;
virtual TagDataType proposedDataType(KnownField field) const;
@ -255,6 +259,42 @@ inline void Tag::setTarget(const TagTarget &target)
m_target = target;
}
/*!
* \brief Returns the name of the current tag target level.
* \remarks Returns TagTargetLevel::Unspecified if target levels are not supported by the tag.
*/
inline TagTargetLevel Tag::targetLevel() const
{
return TagTargetLevel::Unspecified;
}
/*!
* \brief Returns the name of the current target level.
* \remarks Returns nullptr if target levels are not supported by the tag.
*/
inline const char *Tag::targetLevelName() const
{
return supportsTarget() ? tagTargetLevelName(targetLevel()) : nullptr;
}
/*!
* \brief Returns whether the tag is targeting the specified \a tagTargetLevel.
* \remarks If targets are not supported by the tag it is considered targeting
* everything and hence this method returns always true in this case.
*/
inline bool Tag::isTargetingLevel(TagTargetLevel tagTargetLevel) const
{
return !supportsTarget() || static_cast<byte>(targetLevel()) >= static_cast<byte>(tagTargetLevel);
}
/*!
* \brief Returns the string representation for the assigned tag target.
*/
inline std::string Tag::targetString() const
{
return target().toString(targetLevel());
}
/*!
* \brief Returns the proposed data type for the specified \a field as TagDataType.
*

View File

@ -11,6 +11,31 @@ using namespace ConversionUtilities;
namespace Media {
/*!
* \brief Returns a string representation for the specified \a tagTargetLevel.
*/
const char *tagTargetLevelName(TagTargetLevel tagTargetLevel)
{
switch(tagTargetLevel) {
case TagTargetLevel::Shot:
return "shot";
case TagTargetLevel::Subtrack:
return "subtrack, part, movement, scene";
case TagTargetLevel::Track:
return "track, song, chapter";
case TagTargetLevel::Part:
return "part, session";
case TagTargetLevel::Album:
return "album, opera, concert, movie, episode";
case TagTargetLevel::Edition:
return "edition, issue, volume, opus, season, sequel";
case TagTargetLevel::Collection:
return "collection";
default:
return "";
}
}
/*!
* \class Media::TagTarget
* \brief The TagTarget class specifies the target of a tag.
@ -30,8 +55,9 @@ namespace Media {
/*!
* \brief Returns the string representation of the current instance.
* \remarks Uses the specified \a tagTargetLevel if no levelName() is assigned.
*/
string TagTarget::toString() const
string TagTarget::toString(TagTargetLevel tagTargetLevel) const
{
list<string> parts;
parts.emplace_back();
@ -43,7 +69,7 @@ string TagTarget::toString() const
if(!levelName().empty()) {
name = levelName();
} else {
name = matroskaTargetTypeName(this->level());
name = tagTargetLevelName(tagTargetLevel);
}
if(!name.empty()) {
if(!level.empty()) {

View File

@ -6,9 +6,27 @@
#include <string>
#include <vector>
#include <functional>
namespace Media {
/*!
* \brief The TagTargetLevel enum specifies tag target levels.
*/
enum class TagTargetLevel : unsigned char
{
Unspecified,
Shot,
Subtrack,
Track,
Part,
Album,
Edition,
Collection
};
LIB_EXPORT const char *tagTargetLevelName(TagTargetLevel tagTargetLevel);
class LIB_EXPORT TagTarget
{
public:
@ -31,7 +49,8 @@ public:
IdContainerType &attachments();
bool isEmpty() const;
void clear();
std::string toString() const;
std::string toString(const std::function<TagTargetLevel(uint64)> &tagTargetMapping) const;
std::string toString(TagTargetLevel tagTargetLevel) const;
bool operator ==(const TagTarget &other) const;
private:
@ -190,6 +209,16 @@ inline bool TagTarget::operator ==(const TagTarget &other) const
&& m_attachments == other.m_attachments;
}
/*!
* \brief Returns the string representation of the current instance.
* \remarks Uses the specified \a tagTargetMapping function to map the assigned level()
* to a TagTargetLevel if no levelName() is assigned.
*/
inline std::string TagTarget::toString(const std::function<TagTargetLevel(uint64)> &tagTargetMapping) const
{
return toString(tagTargetMapping ? tagTargetMapping(this->level()) : TagTargetLevel::Unspecified);
}
}
#endif // MEDIA_TAGTARGET_H