Ease dealing with native field IDs

In particular, this allow conversion from native field IDs
to readible string representation and vice verca
This commit is contained in:
Martchus 2017-01-23 00:25:53 +01:00
parent c272ec315b
commit b4e167bd71
13 changed files with 127 additions and 16 deletions

View File

@ -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)

View File

@ -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<const TagValue *> values(const typename FieldType::identifierType &id) const;
std::vector<const TagValue *> 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<TagValue> &values);
bool setValues(KnownField field, const std::vector<TagValue> &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<typename FieldType::identifierType, FieldType, Compare> &fields() const;
std::multimap<typename FieldType::identifierType, FieldType, Compare> &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<FieldType, Compare> &from, bool overwrite);
unsigned int insertValues(const Tag &from, bool overwrite);
void ensureTextValuesAreProperlyEncoded();

View File

@ -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<ImplementationType>::identifierType &TagField<Imp
return m_id;
}
template<class ImplementationType>
inline std::string TagField<ImplementationType>::idToString() const
{
return ImplementationType::fieldIdToString(m_id);
}
/*!
* \brief Sets the id of the current Tag Field.
*/

View File

@ -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;

View File

@ -150,6 +150,9 @@ public:
void makePicture(std::unique_ptr<char[]> &buffer, uint32 &bufferSize, const TagValue &picture, byte typeInfo);
void makeComment(std::unique_ptr<char[]> &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<uint32>(id());
} else {
return ConversionUtilities::interpretIntegerAsString<uint32>(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<uint32>(id, Id3v2FrameIds::isLongId(id) ? 0 : 1);
}
}
#endif // ID3V2FRAME_H

View File

@ -57,6 +57,7 @@ class TAG_PARSER_EXPORT Id3v2Tag : public FieldMapBasedTag<Id3v2Frame, FrameComp
public:
Id3v2Tag();
static constexpr TagType tagType = TagType::Id3v2Tag;
TagType type() const;
const char *typeName() const;
TagTextEncoding proposedTextEncoding() const;

View File

@ -52,6 +52,8 @@ class TAG_PARSER_EXPORT MatroskaTag : public FieldMapBasedTag<MatroskaTagField>
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;

View File

@ -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.
*/

View File

@ -92,6 +92,7 @@ class TAG_PARSER_EXPORT Mp4Tag : public FieldMapBasedTag<Mp4TagField>
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<Mp4TagField>::value;
const TagValue &value(KnownField value) const;
using FieldMapBasedTag<Mp4TagField>::values;
std::vector<const TagValue *> 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<Mp4TagField>::setValue;
bool setValue(KnownField field, const TagValue &value);
using FieldMapBasedTag<Mp4TagField>::setValues;
bool setValues(KnownField field, const std::vector<TagValue> &values);
#ifdef LEGACY_API
bool setValue(const std::string mean, const std::string name, const TagValue &value);

View File

@ -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<uint32> expectedRawDataTypes = this->expectedRawDataTypes();
const vector<uint32> 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<char []> coverData = make_unique<char []>(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<Mp4TagField::identifierType>(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();

View File

@ -5,6 +5,7 @@
#include "../statusprovider.h"
#include <c++utilities/io/binarywriter.h>
#include <c++utilities/conversion/stringconversion.h>
#include <vector>
#include <sstream>
@ -135,6 +136,9 @@ public:
std::vector<uint32> 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<uint32>(id).data(), 4);
return std::string(utf8.first.get(), utf8.second);
}
}
#endif // MP4TAGATOM_H

View File

@ -17,6 +17,7 @@ class TAG_PARSER_EXPORT VorbisComment : public FieldMapBasedTag<VorbisCommentFie
public:
VorbisComment();
static constexpr TagType tagType = TagType::VorbisComment;
TagType type() const;
const char *typeName() const;
TagTextEncoding proposedTextEncoding() const;

View File

@ -72,6 +72,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();
@ -96,6 +99,24 @@ inline bool VorbisCommentField::supportsNestedFields() const
return false;
}
/*!
* \brief Converts the specified ID string representation to an actual ID.
* \remarks As Vorbis field IDs are plain text the string is just passed.
*/
inline std::string VorbisCommentField::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 Vorbis field IDs are plain text the string is just passed.
*/
inline std::string VorbisCommentField::fieldIdToString(const std::string &id)
{
return id;
}
/*!
* \brief Ensures the field is cleared.
*/