#ifndef TAG_PARSER_TAG_H #define TAG_PARSER_TAG_H #include "./tagtarget.h" #include "./tagvalue.h" #include #include #include #include namespace TagParser { /*! * \brief Specifies the tag type. * * \sa Tag::type() */ enum class TagType : unsigned int { Unspecified = 0x00, /**< The tag type is unspecified. */ Id3v1Tag = 0x01, /**< The tag is a TagParser::Id3v1Tag. */ Id3v2Tag = 0x02, /**< The tag is a TagParser::Id3v2Tag. */ Mp4Tag = 0x04, /**< The tag is a TagParser::Mp4Tag. */ MatroskaTag = 0x08, /**< The tag is a TagParser::MatroskaTag. */ VorbisComment = 0x10, /**< The tag is a TagParser::VorbisComment. */ OggVorbisComment = 0x20 /**< The tag is a TagParser::OggVorbisComment. */ }; /*! * \brief Specifies the field. * * These "known" fields are used to specify a field without using * the field identifier used by the underlaying tag type. * * Not all fields are supported by all tag types (see Tag::supportsField()). * * Mapping proposed by HAK: https://wiki.hydrogenaud.io/index.php?title=Tag_Mapping * * \sa Tag::type() */ enum class KnownField : unsigned int { Invalid = std::numeric_limits::max(), /**< invalid field name, do not map this value when subclassing Tag */ Title = 0, /**< title */ Album, /**< album/collection */ Artist, /**< artist/band */ Genre, /**< genre */ Year, /**< year */ Comment, /**< comment */ Bpm, /**< beats per minute */ Bps, /**< beats per second */ Lyricist, /**< lyricist */ TrackPosition, /**< track/part number and total track/part count */ DiskPosition, /**< disk number and total disk count */ PartNumber, /**< track/part number */ TotalParts, /**< total track/part count */ Encoder, /**< encoder */ RecordDate, /**< record date */ Performers, /**< performers */ Length, /**< length */ Language, /**< language */ EncoderSettings, /**< encoder settings */ Lyrics, /**< lyrics */ SynchronizedLyrics, /**< synchronized lyrics */ Grouping, /**< grouping */ RecordLabel, /**< record label */ Cover, /**< cover */ Composer, /**< composer */ Rating, /**< rating */ Description, /**< description */ Vendor, /**< vendor */ AlbumArtist, /**< album artist */ }; /*! * \brief The first valid entry in the TagParser::KnownField enum. */ constexpr KnownField firstKnownField = KnownField::Title; /*! * \brief The last valid entry in the TagParser::KnownField enum. */ constexpr KnownField lastKnownField = KnownField::Vendor; /*! * \brief The number of valid entries in the TagParser::KnownField enum. */ constexpr unsigned int knownFieldArraySize = static_cast(lastKnownField) + 1; /*! * \brief Returns the next known field. Returns KnownField::Invalid if there is not next field. */ constexpr KnownField nextKnownField(KnownField field) { return field == lastKnownField ? KnownField::Invalid : static_cast(static_cast(field) + 1); } class TAG_PARSER_EXPORT Tag { public: virtual ~Tag(); virtual TagType type() const; virtual const char *typeName() const; std::string toString() const; virtual TagTextEncoding proposedTextEncoding() const; virtual bool canEncodingBeUsed(TagTextEncoding encoding) const; virtual const TagValue &value(KnownField field) const = 0; virtual std::vector values(KnownField field) const; virtual bool setValue(KnownField field, const TagValue &value) = 0; virtual bool setValues(KnownField field, const std::vector &values); virtual bool hasField(KnownField field) const = 0; virtual void removeAllFields() = 0; const std::string &version() const; uint32 size() const; 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; virtual bool supportsDescription(KnownField field) const; virtual bool supportsMimeType(KnownField field) const; virtual bool supportsMultipleValues(KnownField field) const; virtual unsigned int insertValues(const Tag &from, bool overwrite); virtual void ensureTextValuesAreProperlyEncoded() = 0; protected: Tag(); std::string m_version; uint32 m_size; TagTarget m_target; }; inline TagType Tag::type() const { return TagType::Unspecified; } inline const char *Tag::typeName() const { return "unspecified"; } inline TagTextEncoding Tag::proposedTextEncoding() const { return TagTextEncoding::Latin1; } inline bool Tag::canEncodingBeUsed(TagTextEncoding encoding) const { return encoding == proposedTextEncoding(); } inline const std::string &Tag::version() const { return m_version; } inline uint32 Tag::size() const { return m_size; } inline bool Tag::supportsTarget() const { return false; } inline const TagTarget &Tag::target() const { return m_target; } inline void Tag::setTarget(const TagTarget &target) { m_target = target; } inline TagTargetLevel Tag::targetLevel() const { return TagTargetLevel::Unspecified; } inline const char *Tag::targetLevelName() const { return supportsTarget() ? tagTargetLevelName(targetLevel()) : nullptr; } inline bool Tag::isTargetingLevel(TagTargetLevel tagTargetLevel) const { return !supportsTarget() || static_cast(targetLevel()) >= static_cast(tagTargetLevel); } inline std::string Tag::targetString() const { return target().toString(targetLevel()); } inline TagDataType Tag::proposedDataType(KnownField field) const { switch (field) { case KnownField::Bpm: case KnownField::Bps: case KnownField::Rating: case KnownField::PartNumber: case KnownField::TotalParts: return TagDataType::Integer; case KnownField::Cover: return TagDataType::Picture; case KnownField::Length: return TagDataType::TimeSpan; case KnownField::TrackPosition: case KnownField::DiskPosition: return TagDataType::PositionInSet; case KnownField::Genre: return TagDataType::StandardGenreIndex; default: return TagDataType::Text; } } inline bool Tag::supportsDescription(KnownField) const { return false; } inline bool Tag::supportsMimeType(KnownField) const { return false; } inline bool Tag::supportsMultipleValues(KnownField) const { return false; } } // namespace TagParser #endif // TAG_PARSER_TAG_H