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:
parent
c272ec315b
commit
b4e167bd71
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue