From b4e167bd7159823efcfa4a3d3285e783d2f2a2fa Mon Sep 17 00:00:00 2001 From: Martchus Date: Mon, 23 Jan 2017 00:25:53 +0100 Subject: [PATCH] Ease dealing with native field IDs In particular, this allow conversion from native field IDs to readible string representation and vice verca --- CMakeLists.txt | 4 ++-- fieldbasedtag.h | 12 ++++++------ generictagfield.h | 7 +++++++ id3/id3v1tag.h | 1 + id3/id3v2frame.h | 33 ++++++++++++++++++++++++++++----- id3/id3v2tag.h | 1 + matroska/matroskatag.h | 2 ++ matroska/matroskatagfield.h | 21 +++++++++++++++++++++ mp4/mp4tag.h | 3 +++ mp4/mp4tagfield.cpp | 6 +++--- mp4/mp4tagfield.h | 31 +++++++++++++++++++++++++++++++ vorbis/vorbiscomment.h | 1 + vorbis/vorbiscommentfield.h | 21 +++++++++++++++++++++ 13 files changed, 127 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ab66fe3..f7aafd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,8 +159,8 @@ set(META_APP_AUTHOR "Martchus") 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 6) -set(META_VERSION_MINOR 1) -set(META_VERSION_PATCH 1) +set(META_VERSION_MINOR 2) +set(META_VERSION_PATCH 0) set(META_PUBLIC_SHARED_LIB_DEPENDS c++utilities) set(META_PUBLIC_STATIC_LIB_DEPENDS c++utilities_static) set(META_PRIVATE_COMPILE_DEFINITIONS LEGACY_API) diff --git a/fieldbasedtag.h b/fieldbasedtag.h index f5d4ef2..d310492 100644 --- a/fieldbasedtag.h +++ b/fieldbasedtag.h @@ -27,25 +27,25 @@ class FieldMapBasedTag : public Tag public: FieldMapBasedTag(); - virtual const TagValue &value(const typename FieldType::identifierType &id) const; + virtual const TagValue &value(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism const TagValue &value(KnownField field) const; std::vector values(const typename FieldType::identifierType &id) const; std::vector values(KnownField field) const; - virtual bool setValue(const typename FieldType::identifierType &id, const TagValue &value); + virtual bool setValue(const typename FieldType::identifierType &id, const TagValue &value); // FIXME: use static polymorphism bool setValue(KnownField field, const TagValue &value); bool setValues(const typename FieldType::identifierType &id, const std::vector &values); bool setValues(KnownField field, const std::vector &values); bool hasField(KnownField field) const; - virtual bool hasField(const typename FieldType::identifierType &id) const; + virtual bool hasField(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism void removeAllFields(); const std::multimap &fields() const; std::multimap &fields(); unsigned int fieldCount() const; - virtual typename FieldType::identifierType fieldId(KnownField value) const = 0; - virtual KnownField knownField(const typename FieldType::identifierType &id) const = 0; + virtual typename FieldType::identifierType fieldId(KnownField value) const = 0; // FIXME: use static polymorphism + virtual KnownField knownField(const typename FieldType::identifierType &id) const = 0; // FIXME: use static polymorphism bool supportsField(KnownField field) const; using Tag::proposedDataType; - virtual TagDataType proposedDataType(const typename FieldType::identifierType &id) const; + virtual TagDataType proposedDataType(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism int insertFields(const FieldMapBasedTag &from, bool overwrite); unsigned int insertValues(const Tag &from, bool overwrite); void ensureTextValuesAreProperlyEncoded(); diff --git a/generictagfield.h b/generictagfield.h index 6af0865..4e218aa 100644 --- a/generictagfield.h +++ b/generictagfield.h @@ -42,6 +42,7 @@ public: ~TagField(); const identifierType &id() const; + std::string idToString() const; void setId(const identifierType &id); void clearId(); @@ -118,6 +119,12 @@ inline const typename TagField::identifierType &TagField +inline std::string TagField::idToString() const +{ + return ImplementationType::fieldIdToString(m_id); +} + /*! * \brief Sets the id of the current Tag Field. */ diff --git a/id3/id3v1tag.h b/id3/id3v1tag.h index 0adad65..cde5543 100644 --- a/id3/id3v1tag.h +++ b/id3/id3v1tag.h @@ -11,6 +11,7 @@ class TAG_PARSER_EXPORT Id3v1Tag : public Tag public: Id3v1Tag(); + static constexpr TagType tagType = TagType::Id3v1Tag; TagType type() const; const char *typeName() const; bool canEncodingBeUsed(TagTextEncoding encoding) const; diff --git a/id3/id3v2frame.h b/id3/id3v2frame.h index 38b93d1..8c87d77 100644 --- a/id3/id3v2frame.h +++ b/id3/id3v2frame.h @@ -150,6 +150,9 @@ public: void makePicture(std::unique_ptr &buffer, uint32 &bufferSize, const TagValue &picture, byte typeInfo); void makeComment(std::unique_ptr &buffer, uint32 &bufferSize, const TagValue &comment); + static identifierType fieldIdFromString(const char *idString, std::size_t idStringSize = std::string::npos); + static std::string fieldIdToString(identifierType id); + protected: void cleared(); @@ -188,14 +191,11 @@ inline bool Id3v2Frame::hasPaddingReached() const /*! * \brief Returns the frame ID as string. + * \deprecated Will be removed in favour of generic idToString(). */ inline std::string Id3v2Frame::frameIdString() const { - if(Id3v2FrameIds::isLongId(id())) { - return ConversionUtilities::interpretIntegerAsString(id()); - } else { - return ConversionUtilities::interpretIntegerAsString(id(), 1); - } + return idToString(); } /*! @@ -328,6 +328,29 @@ inline bool Id3v2Frame::supportsNestedFields() const return true; } +/*! + * \brief Converts the specified ID string representation to an actual ID. + */ +inline Id3v2Frame::identifierType Id3v2Frame::fieldIdFromString(const char *idString, std::size_t idStringSize) +{ + switch(idStringSize != std::string::npos ? idStringSize : std::strlen(idString)) { + case 3: + return ConversionUtilities::BE::toUInt24(idString); + case 4: + return ConversionUtilities::BE::toUInt32(idString); + default: + throw ConversionUtilities::ConversionException("ID3v2 ID must be 3 or 4 chars"); + } +} + +/*! + * \brief Returns the string representation for the specified \a id. + */ +inline std::string Id3v2Frame::fieldIdToString(Id3v2Frame::identifierType id) +{ + return ConversionUtilities::interpretIntegerAsString(id, Id3v2FrameIds::isLongId(id) ? 0 : 1); +} + } #endif // ID3V2FRAME_H diff --git a/id3/id3v2tag.h b/id3/id3v2tag.h index f90db73..eec1331 100644 --- a/id3/id3v2tag.h +++ b/id3/id3v2tag.h @@ -57,6 +57,7 @@ class TAG_PARSER_EXPORT Id3v2Tag : public FieldMapBasedTag public: MatroskaTag(); + static constexpr TagType tagType = TagType::MatroskaTag; + // FIXME: implement type() and typeName() in FieldMapBasedTag TagType type() const; const char *typeName() const; TagTextEncoding proposedTextEncoding() const; diff --git a/matroska/matroskatagfield.h b/matroska/matroskatagfield.h index 09bcc4c..5ceaf83 100644 --- a/matroska/matroskatagfield.h +++ b/matroska/matroskatagfield.h @@ -94,6 +94,9 @@ public: bool isAdditionalTypeInfoUsed() const; bool supportsNestedFields() const; + static typename std::string fieldIdFromString(const char *idString, std::size_t idStringSize = std::string::npos); + static std::string fieldIdToString(const std::string &id); + protected: void cleared(); }; @@ -114,6 +117,24 @@ inline bool MatroskaTagField::supportsNestedFields() const return true; } +/*! + * \brief Converts the specified ID string representation to an actual ID. + * \remarks As Matroska field IDs are text strings the string is just passed. + */ +inline std::string MatroskaTagField::fieldIdFromString(const char *idString, std::size_t idStringSize) +{ + return idStringSize != std::string::npos ? std::string(idString, idStringSize) : std::string(idString); +} + +/*! + * \brief Returns the string representation for the specified \a id. + * \remarks As Matroska field IDs are text strings the string is just passed. + */ +inline std::string MatroskaTagField::fieldIdToString(const std::string &id) +{ + return id; +} + /*! * \brief Ensures the field is cleared. */ diff --git a/mp4/mp4tag.h b/mp4/mp4tag.h index 6f3b71f..c39d2d0 100644 --- a/mp4/mp4tag.h +++ b/mp4/mp4tag.h @@ -92,6 +92,7 @@ class TAG_PARSER_EXPORT Mp4Tag : public FieldMapBasedTag public: Mp4Tag(); + static constexpr TagType tagType = TagType::Mp4Tag; TagType type() const; const char *typeName() const; TagTextEncoding proposedTextEncoding() const; @@ -102,6 +103,7 @@ public: bool supportsField(KnownField field) const; using FieldMapBasedTag::value; const TagValue &value(KnownField value) const; + using FieldMapBasedTag::values; std::vector values(KnownField field) const; #ifdef LEGACY_API const TagValue &value(const std::string mean, const std::string name) const; @@ -110,6 +112,7 @@ public: const TagValue &value(const char *mean, const char *name) const; using FieldMapBasedTag::setValue; bool setValue(KnownField field, const TagValue &value); + using FieldMapBasedTag::setValues; bool setValues(KnownField field, const std::vector &values); #ifdef LEGACY_API bool setValue(const std::string mean, const std::string name, const TagValue &value); diff --git a/mp4/mp4tagfield.cpp b/mp4/mp4tagfield.cpp index 3be46c9..4222f04 100644 --- a/mp4/mp4tagfield.cpp +++ b/mp4/mp4tagfield.cpp @@ -103,7 +103,7 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild) } setTypeInfo(m_parsedRawDataType = reader.readUInt24BE()); try { // try to show warning if parsed raw data type differs from expected raw data type for this atom id - vector expectedRawDataTypes = this->expectedRawDataTypes(); + const vector expectedRawDataTypes = this->expectedRawDataTypes(); if(find(expectedRawDataTypes.cbegin(), expectedRawDataTypes.cend(), m_parsedRawDataType) == expectedRawDataTypes.cend()) { addNotification(NotificationType::Warning, "Unexpected data type indicator found.", context); } @@ -134,7 +134,7 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild) default: ; } - streamsize coverSize = dataAtom->dataSize() - 8; + const streamsize coverSize = dataAtom->dataSize() - 8; unique_ptr coverData = make_unique(coverSize); stream.read(coverData.get(), coverSize); value().assignData(move(coverData), coverSize, TagDataType::Picture); @@ -419,7 +419,7 @@ Mp4TagFieldMaker::Mp4TagFieldMaker(Mp4TagField &field) : m_field.addNotification(NotificationType::Warning, "Invalid tag atom id.", "making MP4 tag field"); throw InvalidDataException(); } - const string context("making MP4 tag field " + ConversionUtilities::interpretIntegerAsString(m_field.id())); + const string context("making MP4 tag field " + Mp4TagField::fieldIdToString(m_field.id())); if(m_field.value().isEmpty() && (!m_field.mean().empty() || !m_field.name().empty())) { m_field.addNotification(NotificationType::Critical, "No tag value assigned.", context); throw InvalidDataException(); diff --git a/mp4/mp4tagfield.h b/mp4/mp4tagfield.h index 2768e6e..63a0f90 100644 --- a/mp4/mp4tagfield.h +++ b/mp4/mp4tagfield.h @@ -5,6 +5,7 @@ #include "../statusprovider.h" #include +#include #include #include @@ -135,6 +136,9 @@ public: std::vector expectedRawDataTypes() const; uint32 appropriateRawDataType() const; + static identifierType fieldIdFromString(const char *idString, std::size_t idStringSize = std::string::npos); + static std::string fieldIdToString(identifierType id); + protected: void cleared(); @@ -218,6 +222,33 @@ inline bool Mp4TagField::supportsNestedFields() const return false; } +/*! + * \brief Converts the specified ID string representation to an actual ID. + * \remarks The specified \a idString is assumed to be UTF-8 encoded. In order to get the ©-sign + * correctly, it is converted to Latin-1. + */ +inline Mp4TagField::identifierType Mp4TagField::fieldIdFromString(const char *idString, std::size_t idStringSize) +{ + const auto latin1 = ConversionUtilities::convertUtf8ToLatin1(idString, idStringSize != std::string::npos ? idStringSize : std::strlen(idString)); + switch(latin1.second) { + case 4: + return ConversionUtilities::BE::toUInt32(latin1.first.get()); + default: + throw ConversionUtilities::ConversionException("MP4 ID must be exactly 4 chars"); + } +} + +/*! + * \brief Returns the string representation for the specified \a id. + * \remarks The specified \a id is considered Latin-1 encoded. In order to get the ©-sign + * correctly, it is converted to UTF-8. + */ +inline std::string Mp4TagField::fieldIdToString(Mp4TagField::identifierType id) +{ + const auto utf8 = ConversionUtilities::convertLatin1ToUtf8(ConversionUtilities::interpretIntegerAsString(id).data(), 4); + return std::string(utf8.first.get(), utf8.second); +} + } #endif // MP4TAGATOM_H diff --git a/vorbis/vorbiscomment.h b/vorbis/vorbiscomment.h index 6902fa9..ae9b6ee 100644 --- a/vorbis/vorbiscomment.h +++ b/vorbis/vorbiscomment.h @@ -17,6 +17,7 @@ class TAG_PARSER_EXPORT VorbisComment : public FieldMapBasedTag