Compare commits
15 Commits
master
...
experiment
Author | SHA1 | Date |
---|---|---|
Marius Kittler | 53701255ca | |
Marius Kittler | e232c907ea | |
Marius Kittler | d5613954a4 | |
Martchus | 44af199aeb | |
Martchus | b69aab0cd1 | |
Martchus | 618efe3f96 | |
Martchus | fdb23e3cd0 | |
Martchus | bf31c9e89f | |
Martchus | 4231f2679e | |
Martchus | 8109f84f38 | |
Martchus | 1814cd9bfc | |
Martchus | 0f12cf346c | |
Martchus | 86d51f1e96 | |
Martchus | 90eac982a7 | |
Martchus | 001cfc931d |
|
@ -171,8 +171,8 @@ set(META_APP_NAME "Tag Parser")
|
||||||
set(META_APP_AUTHOR "Martchus")
|
set(META_APP_AUTHOR "Martchus")
|
||||||
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
|
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_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_MAJOR 7)
|
||||||
set(META_VERSION_MINOR 5)
|
set(META_VERSION_MINOR 0)
|
||||||
set(META_VERSION_PATCH 0)
|
set(META_VERSION_PATCH 0)
|
||||||
set(META_PUBLIC_SHARED_LIB_DEPENDS c++utilities)
|
set(META_PUBLIC_SHARED_LIB_DEPENDS c++utilities)
|
||||||
set(META_PUBLIC_STATIC_LIB_DEPENDS c++utilities_static)
|
set(META_PUBLIC_STATIC_LIB_DEPENDS c++utilities_static)
|
||||||
|
|
236
fieldbasedtag.h
236
fieldbasedtag.h
|
@ -8,51 +8,75 @@
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \class Media::FieldMapBasedTagTraits
|
||||||
|
* \brief Defines traits for the specified \a ImplementationType.
|
||||||
|
*
|
||||||
|
* A template specialization for each FieldMapBasedTag subclass must be provided.
|
||||||
|
*/
|
||||||
|
template<typename ImplementationType>
|
||||||
|
class FieldMapBasedTagTraits
|
||||||
|
{};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \class Media::FieldMapBasedTag
|
* \class Media::FieldMapBasedTag
|
||||||
* \brief The FieldMapBasedTag provides a generic implementation of Tag which stores
|
* \brief The FieldMapBasedTag provides a generic implementation of Tag which stores
|
||||||
* the tag fields using std::multimap.
|
* the tag fields using std::multimap.
|
||||||
*
|
*
|
||||||
* The FieldMapBasedTag class only provides the interface and common functionality.
|
* The FieldMapBasedTag class only provides the interface and common functionality.
|
||||||
* It is meant to be subclassed.
|
* It is meant to be subclassed using CRTP pattern.
|
||||||
*
|
*
|
||||||
* \tparam FieldType Specifies the class used to store the fields. Should be a subclass
|
* \remarks This template class is intended to be subclassed using
|
||||||
* of TagField.
|
* with the "Curiously recurring template pattern".
|
||||||
*
|
|
||||||
* \tparam Compare Specifies the key comparsion function. Default is std::less.
|
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare = std::less<typename FieldType::identifierType> >
|
template <class ImplementationType>
|
||||||
class FieldMapBasedTag : public Tag
|
class FieldMapBasedTag : public Tag
|
||||||
{
|
{
|
||||||
|
friend class FieldMapBasedTagTraits<ImplementationType>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef typename FieldMapBasedTagTraits<ImplementationType>::FieldType FieldType;
|
||||||
|
typedef typename FieldMapBasedTagTraits<ImplementationType>::FieldType::IdentifierType IdentifierType;
|
||||||
|
typedef typename FieldMapBasedTagTraits<ImplementationType>::Compare Compare;
|
||||||
|
|
||||||
FieldMapBasedTag();
|
FieldMapBasedTag();
|
||||||
|
|
||||||
virtual const TagValue &value(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism
|
TagType type() const;
|
||||||
|
const char *typeName() const;
|
||||||
|
TagTextEncoding proposedTextEncoding() const;
|
||||||
|
const TagValue &value(const IdentifierType &id) const;
|
||||||
const TagValue &value(KnownField field) const;
|
const TagValue &value(KnownField field) const;
|
||||||
std::vector<const TagValue *> values(const typename FieldType::identifierType &id) const;
|
std::vector<const TagValue *> values(const IdentifierType &id) const;
|
||||||
std::vector<const TagValue *> values(KnownField field) const;
|
std::vector<const TagValue *> values(KnownField field) const;
|
||||||
virtual bool setValue(const typename FieldType::identifierType &id, const TagValue &value); // FIXME: use static polymorphism
|
bool setValue(const IdentifierType &id, const TagValue &value);
|
||||||
bool setValue(KnownField field, const TagValue &value);
|
bool setValue(KnownField field, const TagValue &value);
|
||||||
bool setValues(const typename FieldType::identifierType &id, const std::vector<TagValue> &values);
|
bool setValues(const IdentifierType &id, const std::vector<TagValue> &values);
|
||||||
bool setValues(KnownField field, const std::vector<TagValue> &values);
|
bool setValues(KnownField field, const std::vector<TagValue> &values);
|
||||||
bool hasField(KnownField field) const;
|
bool hasField(KnownField field) const;
|
||||||
virtual bool hasField(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism
|
bool hasField(const IdentifierType &id) const;
|
||||||
void removeAllFields();
|
void removeAllFields();
|
||||||
const std::multimap<typename FieldType::identifierType, FieldType, Compare> &fields() const;
|
const std::multimap<IdentifierType, FieldType, Compare> &fields() const;
|
||||||
std::multimap<typename FieldType::identifierType, FieldType, Compare> &fields();
|
std::multimap<IdentifierType, FieldType, Compare> &fields();
|
||||||
unsigned int fieldCount() const;
|
unsigned int fieldCount() const;
|
||||||
virtual typename FieldType::identifierType fieldId(KnownField value) const = 0; // FIXME: use static polymorphism
|
IdentifierType fieldId(KnownField value) const;
|
||||||
virtual KnownField knownField(const typename FieldType::identifierType &id) const = 0; // FIXME: use static polymorphism
|
KnownField knownField(const IdentifierType &id) const;
|
||||||
bool supportsField(KnownField field) const;
|
bool supportsField(KnownField field) const;
|
||||||
using Tag::proposedDataType;
|
using Tag::proposedDataType;
|
||||||
virtual TagDataType proposedDataType(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism
|
TagDataType proposedDataType(const IdentifierType &id) const;
|
||||||
int insertFields(const FieldMapBasedTag<FieldType, Compare> &from, bool overwrite);
|
int insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite);
|
||||||
unsigned int insertValues(const Tag &from, bool overwrite);
|
unsigned int insertValues(const Tag &from, bool overwrite);
|
||||||
void ensureTextValuesAreProperlyEncoded();
|
void ensureTextValuesAreProperlyEncoded();
|
||||||
typedef FieldType fieldType;
|
|
||||||
|
protected:
|
||||||
|
const TagValue &internallyGetValue(const IdentifierType &id) const;
|
||||||
|
bool internallySetValue(const IdentifierType &id, const TagValue &value);
|
||||||
|
bool internallyHasField(const IdentifierType &id) const;
|
||||||
|
// no default implementation: IdentifierType internallyGetFieldId(KnownField field) const;
|
||||||
|
// no default implementation: KnownField internallyGetKnownField(const IdentifierType &id) const;
|
||||||
|
TagDataType internallyGetProposedDataType(const IdentifierType &id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::multimap<typename FieldType::identifierType, FieldType, Compare> m_fields;
|
std::multimap<IdentifierType, FieldType, Compare> m_fields;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -72,23 +96,51 @@ private:
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new FieldMapBasedTag.
|
* \brief Constructs a new FieldMapBasedTag.
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
FieldMapBasedTag<FieldType, Compare>::FieldMapBasedTag()
|
FieldMapBasedTag<ImplementationType>::FieldMapBasedTag()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
template <class ImplementationType>
|
||||||
|
TagType FieldMapBasedTag<ImplementationType>::type() const
|
||||||
|
{
|
||||||
|
return ImplementationType::tagType;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ImplementationType>
|
||||||
|
const char *FieldMapBasedTag<ImplementationType>::typeName() const
|
||||||
|
{
|
||||||
|
return ImplementationType::tagName;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ImplementationType>
|
||||||
|
TagTextEncoding FieldMapBasedTag<ImplementationType>::proposedTextEncoding() const
|
||||||
|
{
|
||||||
|
return ImplementationType::defaultTextEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the value of the field with the specified \a id.
|
* \brief Default implementation for value().
|
||||||
* \sa Tag::value()
|
* \remarks Shadow in subclass to provide custom implementation.
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template<class ImplementationType>
|
||||||
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(const typename FieldType::identifierType &id) const
|
const TagValue &FieldMapBasedTag<ImplementationType>::internallyGetValue(const IdentifierType &id) const
|
||||||
{
|
{
|
||||||
auto i = m_fields.find(id);
|
auto i = m_fields.find(id);
|
||||||
return i != m_fields.end() ? i->second.value() : TagValue::empty();
|
return i != m_fields.end() ? i->second.value() : TagValue::empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FieldType, class Compare>
|
/*!
|
||||||
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(KnownField field) const
|
* \brief Returns the value of the field with the specified \a id.
|
||||||
|
* \sa Tag::value()
|
||||||
|
*/
|
||||||
|
template <class ImplementationType>
|
||||||
|
inline const TagValue &FieldMapBasedTag<ImplementationType>::value(const IdentifierType &id) const
|
||||||
|
{
|
||||||
|
return static_cast<const ImplementationType *>(this)->internallyGetValue(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ImplementationType>
|
||||||
|
inline const TagValue &FieldMapBasedTag<ImplementationType>::value(KnownField field) const
|
||||||
{
|
{
|
||||||
return value(fieldId(field));
|
return value(fieldId(field));
|
||||||
}
|
}
|
||||||
|
@ -97,8 +149,8 @@ inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(KnownField fi
|
||||||
* \brief Returns the values of the field with the specified \a id.
|
* \brief Returns the values of the field with the specified \a id.
|
||||||
* \sa Tag::values()
|
* \sa Tag::values()
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(const typename FieldType::identifierType &id) const
|
inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(const IdentifierType &id) const
|
||||||
{
|
{
|
||||||
auto range = m_fields.equal_range(id);
|
auto range = m_fields.equal_range(id);
|
||||||
std::vector<const TagValue *> values;
|
std::vector<const TagValue *> values;
|
||||||
|
@ -110,24 +162,24 @@ inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::value
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(KnownField field) const
|
inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(KnownField field) const
|
||||||
{
|
{
|
||||||
return values(fieldId(field));
|
return values(fieldId(field));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
inline bool FieldMapBasedTag<FieldType, Compare>::setValue(KnownField field, const TagValue &value)
|
inline bool FieldMapBasedTag<ImplementationType>::setValue(KnownField field, const TagValue &value)
|
||||||
{
|
{
|
||||||
return setValue(fieldId(field), value);
|
return setValue(fieldId(field), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Assigns the given \a value to the field with the specified \a id.
|
* \brief Default implementation for setValue().
|
||||||
* \sa Tag::setValue()
|
* \remarks Shadow in subclass to provide custom implementation.
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template<class ImplementationType>
|
||||||
bool FieldMapBasedTag<FieldType, Compare>::setValue(const typename FieldType::identifierType &id, const Media::TagValue &value)
|
bool FieldMapBasedTag<ImplementationType>::internallySetValue(const IdentifierType &id, const TagValue &value)
|
||||||
{
|
{
|
||||||
auto i = m_fields.find(id);
|
auto i = m_fields.find(id);
|
||||||
if(i != m_fields.end()) { // field already exists -> set its value
|
if(i != m_fields.end()) { // field already exists -> set its value
|
||||||
|
@ -140,14 +192,24 @@ bool FieldMapBasedTag<FieldType, Compare>::setValue(const typename FieldType::id
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Assigns the given \a value to the field with the specified \a id.
|
||||||
|
* \sa Tag::setValue()
|
||||||
|
*/
|
||||||
|
template <class ImplementationType>
|
||||||
|
bool FieldMapBasedTag<ImplementationType>::setValue(const IdentifierType &id, const Media::TagValue &value)
|
||||||
|
{
|
||||||
|
return static_cast<ImplementationType *>(this)->internallySetValue(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Assigns the given \a values to the field with the specified \a id.
|
* \brief Assigns the given \a values to the field with the specified \a id.
|
||||||
* \remarks There might me more than one value assigned to an \a id. Whereas setValue() only alters the first value, this
|
* \remarks There might me more than one value assigned to an \a id. Whereas setValue() only alters the first value, this
|
||||||
* method will replace all currently assigned values with the specified \a values.
|
* method will replace all currently assigned values with the specified \a values.
|
||||||
* \sa Tag::setValues()
|
* \sa Tag::setValues()
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
bool FieldMapBasedTag<FieldType, Compare>::setValues(const typename FieldType::identifierType &id, const std::vector<TagValue> &values)
|
bool FieldMapBasedTag<ImplementationType>::setValues(const IdentifierType &id, const std::vector<TagValue> &values)
|
||||||
{
|
{
|
||||||
auto valuesIterator = values.cbegin();
|
auto valuesIterator = values.cbegin();
|
||||||
auto range = m_fields.equal_range(id);
|
auto range = m_fields.equal_range(id);
|
||||||
|
@ -176,23 +238,24 @@ bool FieldMapBasedTag<FieldType, Compare>::setValues(const typename FieldType::i
|
||||||
* method will replace all currently assigned values with the specified \a values.
|
* method will replace all currently assigned values with the specified \a values.
|
||||||
* \sa Tag::setValues()
|
* \sa Tag::setValues()
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
bool FieldMapBasedTag<FieldType, Compare>::setValues(KnownField field, const std::vector<TagValue> &values)
|
bool FieldMapBasedTag<ImplementationType>::setValues(KnownField field, const std::vector<TagValue> &values)
|
||||||
{
|
{
|
||||||
return setValues(fieldId(field), values);
|
return setValues(fieldId(field), values);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
inline bool FieldMapBasedTag<FieldType, Compare>::hasField(KnownField field) const
|
inline bool FieldMapBasedTag<ImplementationType>::hasField(KnownField field) const
|
||||||
{
|
{
|
||||||
return hasField(fieldId(field));
|
return hasField(fieldId(field));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns an indication whether the field with the specified \a id is present.
|
* \brief Default implementation for hasField().
|
||||||
|
* \remarks Shadow in subclass to provide custom implementation.
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template<class ImplementationType>
|
||||||
inline bool FieldMapBasedTag<FieldType, Compare>::hasField(const typename FieldType::identifierType &id) const
|
bool FieldMapBasedTag<ImplementationType>::internallyHasField(const IdentifierType &id) const
|
||||||
{
|
{
|
||||||
for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
|
for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
|
||||||
if(!range.first->second.value().isEmpty()) {
|
if(!range.first->second.value().isEmpty()) {
|
||||||
|
@ -202,8 +265,17 @@ inline bool FieldMapBasedTag<FieldType, Compare>::hasField(const typename FieldT
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FieldType, class Compare>
|
/*!
|
||||||
inline void FieldMapBasedTag<FieldType, Compare>::removeAllFields()
|
* \brief Returns an indication whether the field with the specified \a id is present.
|
||||||
|
*/
|
||||||
|
template <class ImplementationType>
|
||||||
|
inline bool FieldMapBasedTag<ImplementationType>::hasField(const IdentifierType &id) const
|
||||||
|
{
|
||||||
|
return static_cast<const ImplementationType *>(this)->internallyHasField(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ImplementationType>
|
||||||
|
inline void FieldMapBasedTag<ImplementationType>::removeAllFields()
|
||||||
{
|
{
|
||||||
m_fields.clear();
|
m_fields.clear();
|
||||||
}
|
}
|
||||||
|
@ -211,8 +283,8 @@ inline void FieldMapBasedTag<FieldType, Compare>::removeAllFields()
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the fields of the tag by providing direct access to the field map of the tag.
|
* \brief Returns the fields of the tag by providing direct access to the field map of the tag.
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
inline const std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields() const
|
inline auto FieldMapBasedTag<ImplementationType>::fields() const -> const std::multimap<IdentifierType, FieldType, Compare> &
|
||||||
{
|
{
|
||||||
return m_fields;
|
return m_fields;
|
||||||
}
|
}
|
||||||
|
@ -220,14 +292,14 @@ inline const std::multimap<typename FieldType::identifierType, FieldType, Compar
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the fields of the tag by providing direct access to the field map of the tag.
|
* \brief Returns the fields of the tag by providing direct access to the field map of the tag.
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
inline std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields()
|
inline auto FieldMapBasedTag<ImplementationType>::fields() -> std::multimap<IdentifierType, FieldType, Compare> &
|
||||||
{
|
{
|
||||||
return m_fields;
|
return m_fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
unsigned int FieldMapBasedTag<FieldType, Compare>::fieldCount() const
|
unsigned int FieldMapBasedTag<ImplementationType>::fieldCount() const
|
||||||
{
|
{
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
for(const auto &field : m_fields) {
|
for(const auto &field : m_fields) {
|
||||||
|
@ -238,20 +310,50 @@ unsigned int FieldMapBasedTag<FieldType, Compare>::fieldCount() const
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FieldType, class Compare>
|
/*!
|
||||||
inline bool FieldMapBasedTag<FieldType, Compare>::supportsField(KnownField field) const
|
* \brief Returns the field ID for the specified \a value.
|
||||||
|
* \remarks Must be implemented in internallyGetFieldId() when creating subclass.
|
||||||
|
*/
|
||||||
|
template<class ImplementationType>
|
||||||
|
inline typename FieldMapBasedTag<ImplementationType>::IdentifierType FieldMapBasedTag<ImplementationType>::fieldId(KnownField value) const
|
||||||
{
|
{
|
||||||
static typename FieldType::identifierType def;
|
return static_cast<const ImplementationType *>(this)->internallyGetFieldId(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the KnownField for the specified \a id.
|
||||||
|
* \remarks Must be implemented in internallyGetKnownField() when creating subclass.
|
||||||
|
*/
|
||||||
|
template<class ImplementationType>
|
||||||
|
inline KnownField FieldMapBasedTag<ImplementationType>::knownField(const IdentifierType &id) const
|
||||||
|
{
|
||||||
|
return static_cast<FieldMapBasedTag<ImplementationType> *>(this)->internallyGetKnownField(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ImplementationType>
|
||||||
|
inline bool FieldMapBasedTag<ImplementationType>::supportsField(KnownField field) const
|
||||||
|
{
|
||||||
|
static IdentifierType def;
|
||||||
return fieldId(field) != def;
|
return fieldId(field) != def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Default implementation for proposedDataType().
|
||||||
|
* \remarks Shadow in subclass to provide custom implementation.
|
||||||
|
*/
|
||||||
|
template<class ImplementationType>
|
||||||
|
inline TagDataType FieldMapBasedTag<ImplementationType>::internallyGetProposedDataType(const IdentifierType &id) const
|
||||||
|
{
|
||||||
|
return Tag::proposedDataType(knownField(id));
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the proposed data type for the field with the specified \a id.
|
* \brief Returns the proposed data type for the field with the specified \a id.
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
inline TagDataType FieldMapBasedTag<FieldType, Compare>::proposedDataType(const typename FieldType::identifierType &id) const
|
inline TagDataType FieldMapBasedTag<ImplementationType>::proposedDataType(const IdentifierType &id) const
|
||||||
{
|
{
|
||||||
return Tag::proposedDataType(knownField(id));
|
return static_cast<ImplementationType *>(this)->determineProposedDataType(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -260,8 +362,8 @@ inline TagDataType FieldMapBasedTag<FieldType, Compare>::proposedDataType(const
|
||||||
* \param overwrite Indicates whether existing fields should be overwritten.
|
* \param overwrite Indicates whether existing fields should be overwritten.
|
||||||
* \return Returns the number of fields that have been inserted.
|
* \return Returns the number of fields that have been inserted.
|
||||||
*/
|
*/
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
int FieldMapBasedTag<FieldType, Compare>::insertFields(const FieldMapBasedTag<FieldType, Compare> &from, bool overwrite)
|
int FieldMapBasedTag<ImplementationType>::insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite)
|
||||||
{
|
{
|
||||||
int fieldsInserted = 0;
|
int fieldsInserted = 0;
|
||||||
for(const auto &pair : from.fields()) {
|
for(const auto &pair : from.fields()) {
|
||||||
|
@ -291,19 +393,19 @@ int FieldMapBasedTag<FieldType, Compare>::insertFields(const FieldMapBasedTag<Fi
|
||||||
return fieldsInserted;
|
return fieldsInserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
unsigned int FieldMapBasedTag<FieldType, Compare>::insertValues(const Tag &from, bool overwrite)
|
unsigned int FieldMapBasedTag<ImplementationType>::insertValues(const Tag &from, bool overwrite)
|
||||||
{
|
{
|
||||||
if(type() == from.type()) {
|
if(type() == from.type()) {
|
||||||
// the tags are of the same type, we can insert the fields directly
|
// the tags are of the same type, we can insert the fields directly
|
||||||
return insertFields(static_cast<const FieldMapBasedTag<FieldType, Compare> &>(from), overwrite);
|
return insertFields(static_cast<const FieldMapBasedTag<ImplementationType> &>(from), overwrite);
|
||||||
} else {
|
} else {
|
||||||
return Tag::insertValues(from, overwrite);
|
return Tag::insertValues(from, overwrite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class FieldType, class Compare>
|
template <class ImplementationType>
|
||||||
void FieldMapBasedTag<FieldType, Compare>::ensureTextValuesAreProperlyEncoded()
|
void FieldMapBasedTag<ImplementationType>::ensureTextValuesAreProperlyEncoded()
|
||||||
{
|
{
|
||||||
for(auto &field : fields()) {
|
for(auto &field : fields()) {
|
||||||
field.second.value().convertDataEncodingForTag(this);
|
field.second.value().convertDataEncodingForTag(this);
|
||||||
|
|
|
@ -52,10 +52,10 @@ public:
|
||||||
void removeAllTracks();
|
void removeAllTracks();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
typedef FileInfoType fileInfoType;
|
typedef FileInfoType ContainerFileInfoType;
|
||||||
typedef TagType tagType;
|
typedef TagType ContainerTagType;
|
||||||
typedef TrackType trackType;
|
typedef TrackType ContainerTrackType;
|
||||||
typedef ElementType elementType;
|
typedef ElementType ContainerElementType;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<ElementType> m_firstElement;
|
std::unique_ptr<ElementType> m_firstElement;
|
||||||
|
|
|
@ -108,8 +108,9 @@ class FileElementTraits
|
||||||
* \class Media::GenericFileElement
|
* \class Media::GenericFileElement
|
||||||
* \brief The GenericFileElement class helps to parse binary files which consist
|
* \brief The GenericFileElement class helps to parse binary files which consist
|
||||||
* of an arboreal element strucutre.
|
* of an arboreal element strucutre.
|
||||||
*
|
|
||||||
* \tparam ImplementationType Specifies the type of the actual implementation.
|
* \tparam ImplementationType Specifies the type of the actual implementation.
|
||||||
|
* \remarks This template class is intended to be subclassed using
|
||||||
|
* with the "Curiously recurring template pattern".
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
class TAG_PARSER_EXPORT GenericFileElement : public StatusProvider
|
class TAG_PARSER_EXPORT GenericFileElement : public StatusProvider
|
||||||
|
@ -120,61 +121,61 @@ public:
|
||||||
/*!
|
/*!
|
||||||
* \brief Specifies the type of the corresponding container.
|
* \brief Specifies the type of the corresponding container.
|
||||||
*/
|
*/
|
||||||
typedef typename FileElementTraits<ImplementationType>::containerType containerType;
|
typedef typename FileElementTraits<ImplementationType>::ContainerType ContainerType;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Specifies the type used to store identifiers.
|
* \brief Specifies the type used to store identifiers.
|
||||||
*/
|
*/
|
||||||
typedef typename FileElementTraits<ImplementationType>::identifierType identifierType;
|
typedef typename FileElementTraits<ImplementationType>::IdentifierType IdentifierType;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Specifies the type used to store data sizes.
|
* \brief Specifies the type used to store data sizes.
|
||||||
*/
|
*/
|
||||||
typedef typename FileElementTraits<ImplementationType>::dataSizeType dataSizeType;
|
typedef typename FileElementTraits<ImplementationType>::DataSizeType DataSizeType;
|
||||||
|
|
||||||
/*!
|
GenericFileElement(ContainerType &container, uint64 startOffset);
|
||||||
* \brief Specifies the type of the actual implementation.
|
GenericFileElement(ImplementationType &parent, uint64 startOffset);
|
||||||
*/
|
GenericFileElement(ContainerType &container, uint64 startOffset, uint64 maxSize);
|
||||||
typedef typename FileElementTraits<ImplementationType>::implementationType implementationType;
|
|
||||||
|
|
||||||
GenericFileElement(containerType &container, uint64 startOffset);
|
|
||||||
GenericFileElement(implementationType &parent, uint64 startOffset);
|
|
||||||
GenericFileElement(containerType &container, uint64 startOffset, uint64 maxSize);
|
|
||||||
GenericFileElement(const GenericFileElement& other) = delete;
|
GenericFileElement(const GenericFileElement& other) = delete;
|
||||||
GenericFileElement(GenericFileElement& other) = delete;
|
GenericFileElement(GenericFileElement& other) = delete;
|
||||||
GenericFileElement& operator =(const GenericFileElement& other) = delete;
|
GenericFileElement& operator =(const GenericFileElement& other) = delete;
|
||||||
|
|
||||||
containerType& container();
|
ContainerType& container();
|
||||||
const containerType& container() const;
|
const ContainerType& container() const;
|
||||||
std::iostream &stream();
|
std::iostream &stream();
|
||||||
IoUtilities::BinaryReader &reader();
|
IoUtilities::BinaryReader &reader();
|
||||||
IoUtilities::BinaryWriter &writer();
|
IoUtilities::BinaryWriter &writer();
|
||||||
uint64 startOffset() const;
|
uint64 startOffset() const;
|
||||||
uint64 relativeStartOffset() const;
|
uint64 relativeStartOffset() const;
|
||||||
const identifierType &id() const;
|
const IdentifierType &id() const;
|
||||||
std::string idToString() const;
|
std::string idToString() const;
|
||||||
uint32 idLength() const;
|
uint32 idLength() const;
|
||||||
uint32 headerSize() const;
|
uint32 headerSize() const;
|
||||||
dataSizeType dataSize() const;
|
DataSizeType dataSize() const;
|
||||||
uint32 sizeLength() const;
|
uint32 sizeLength() const;
|
||||||
uint64 dataOffset() const;
|
uint64 dataOffset() const;
|
||||||
uint64 totalSize() const;
|
uint64 totalSize() const;
|
||||||
uint64 endOffset() const;
|
uint64 endOffset() const;
|
||||||
uint64 maxTotalSize() const;
|
uint64 maxTotalSize() const;
|
||||||
implementationType* parent();
|
byte level() const;
|
||||||
const implementationType* parent() const;
|
ImplementationType* parent();
|
||||||
implementationType* nextSibling();
|
const ImplementationType* parent() const;
|
||||||
const implementationType* nextSibling() const;
|
ImplementationType* parent(byte n);
|
||||||
implementationType* firstChild();
|
const ImplementationType* parent(byte n) const;
|
||||||
const implementationType* firstChild() const;
|
ImplementationType* nextSibling();
|
||||||
implementationType* subelementByPath(const std::initializer_list<identifierType> &path);
|
const ImplementationType* nextSibling() const;
|
||||||
implementationType* subelementByPath(std::list<identifierType> &path);
|
ImplementationType* firstChild();
|
||||||
implementationType* childById(const identifierType &id);
|
const ImplementationType* firstChild() const;
|
||||||
implementationType* siblingById(const identifierType &id, bool includeThis = false);
|
ImplementationType* lastChild();
|
||||||
FileElementIterator<implementationType> begin();
|
const ImplementationType* lastChild() const;
|
||||||
FileElementIterator<implementationType> end();
|
ImplementationType* subelementByPath(const std::initializer_list<IdentifierType> &path);
|
||||||
const FileElementIterator<implementationType> begin() const;
|
ImplementationType* subelementByPath(std::list<IdentifierType> &path);
|
||||||
const FileElementIterator<implementationType> end() const;
|
ImplementationType* childById(const IdentifierType &id);
|
||||||
|
ImplementationType* siblingById(const IdentifierType &id, bool includeThis = false);
|
||||||
|
FileElementIterator<ImplementationType> begin();
|
||||||
|
FileElementIterator<ImplementationType> end();
|
||||||
|
const FileElementIterator<ImplementationType> begin() const;
|
||||||
|
const FileElementIterator<ImplementationType> end() const;
|
||||||
bool isParent() const;
|
bool isParent() const;
|
||||||
bool isPadding() const;
|
bool isPadding() const;
|
||||||
uint64 firstChildOffset() const;
|
uint64 firstChildOffset() const;
|
||||||
|
@ -194,25 +195,27 @@ public:
|
||||||
void copyBuffer(std::ostream &targetStream);
|
void copyBuffer(std::ostream &targetStream);
|
||||||
void copyPreferablyFromBuffer(std::ostream &targetStream);
|
void copyPreferablyFromBuffer(std::ostream &targetStream);
|
||||||
const std::unique_ptr<char[]> &buffer();
|
const std::unique_ptr<char[]> &buffer();
|
||||||
implementationType *denoteFirstChild(uint32 offset);
|
ImplementationType *denoteFirstChild(uint32 offset);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
identifierType m_id;
|
IdentifierType m_id;
|
||||||
uint64 m_startOffset;
|
uint64 m_startOffset;
|
||||||
uint64 m_maxSize;
|
uint64 m_maxSize;
|
||||||
uint32 m_idLength;
|
uint32 m_idLength;
|
||||||
dataSizeType m_dataSize;
|
DataSizeType m_dataSize;
|
||||||
uint32 m_sizeLength;
|
uint32 m_sizeLength;
|
||||||
implementationType* m_parent;
|
ImplementationType* m_parent;
|
||||||
std::unique_ptr<implementationType> m_nextSibling;
|
std::unique_ptr<ImplementationType> m_nextSibling;
|
||||||
std::unique_ptr<implementationType> m_firstChild;
|
std::unique_ptr<ImplementationType> m_firstChild;
|
||||||
std::unique_ptr<char[]> m_buffer;
|
std::unique_ptr<char[]> m_buffer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void copyInternal(std::ostream &targetStream, uint64 startOffset, uint64 bytesToCopy);
|
void copyInternal(std::ostream &targetStream, uint64 startOffset, uint64 bytesToCopy);
|
||||||
|
|
||||||
containerType* m_container;
|
ContainerType* m_container;
|
||||||
bool m_parsed;
|
bool m_parsed;
|
||||||
|
protected:
|
||||||
|
bool m_sizeUnknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -220,15 +223,16 @@ private:
|
||||||
* \remarks The available size is obtained using the stream of the \a container.
|
* \remarks The available size is obtained using the stream of the \a container.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::containerType &container, uint64 startOffset) :
|
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::ContainerType &container, uint64 startOffset) :
|
||||||
m_id(identifierType()),
|
m_id(IdentifierType()),
|
||||||
m_startOffset(startOffset),
|
m_startOffset(startOffset),
|
||||||
m_idLength(0),
|
m_idLength(0),
|
||||||
m_dataSize(0),
|
m_dataSize(0),
|
||||||
m_sizeLength(0),
|
m_sizeLength(0),
|
||||||
m_parent(nullptr),
|
m_parent(nullptr),
|
||||||
m_container(&container),
|
m_container(&container),
|
||||||
m_parsed(false)
|
m_parsed(false),
|
||||||
|
m_sizeUnknown(false)
|
||||||
{
|
{
|
||||||
m_maxSize = container.fileInfo().size();
|
m_maxSize = container.fileInfo().size();
|
||||||
if(m_maxSize > startOffset) {
|
if(m_maxSize > startOffset) {
|
||||||
|
@ -243,8 +247,8 @@ GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<Im
|
||||||
* \brief Constructs a new sub level file element with the specified \a parent at the specified \a startOffset.
|
* \brief Constructs a new sub level file element with the specified \a parent at the specified \a startOffset.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::implementationType &parent, uint64 startOffset) :
|
GenericFileElement<ImplementationType>::GenericFileElement(ImplementationType &parent, uint64 startOffset) :
|
||||||
m_id(identifierType()),
|
m_id(IdentifierType()),
|
||||||
m_startOffset(startOffset),
|
m_startOffset(startOffset),
|
||||||
m_maxSize(parent.startOffset() + parent.totalSize() - startOffset),
|
m_maxSize(parent.startOffset() + parent.totalSize() - startOffset),
|
||||||
m_idLength(0),
|
m_idLength(0),
|
||||||
|
@ -252,15 +256,16 @@ GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<Im
|
||||||
m_sizeLength(0),
|
m_sizeLength(0),
|
||||||
m_parent(&parent),
|
m_parent(&parent),
|
||||||
m_container(&parent.container()),
|
m_container(&parent.container()),
|
||||||
m_parsed(false)
|
m_parsed(false),
|
||||||
|
m_sizeUnknown(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new sub level file element with the specified \a container, \a startOffset and \a maxSize.
|
* \brief Constructs a new sub level file element with the specified \a container, \a startOffset and \a maxSize.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::containerType &container, uint64 startOffset, uint64 maxSize) :
|
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::ContainerType &container, uint64 startOffset, uint64 maxSize) :
|
||||||
m_id(identifierType()),
|
m_id(IdentifierType()),
|
||||||
m_startOffset(startOffset),
|
m_startOffset(startOffset),
|
||||||
m_maxSize(maxSize),
|
m_maxSize(maxSize),
|
||||||
m_idLength(0),
|
m_idLength(0),
|
||||||
|
@ -268,14 +273,15 @@ GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<Im
|
||||||
m_sizeLength(0),
|
m_sizeLength(0),
|
||||||
m_parent(nullptr),
|
m_parent(nullptr),
|
||||||
m_container(&container),
|
m_container(&container),
|
||||||
m_parsed(false)
|
m_parsed(false),
|
||||||
|
m_sizeUnknown(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the related container.
|
* \brief Returns the related container.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline typename GenericFileElement<ImplementationType>::containerType& GenericFileElement<ImplementationType>::container()
|
inline typename GenericFileElement<ImplementationType>::ContainerType& GenericFileElement<ImplementationType>::container()
|
||||||
{
|
{
|
||||||
return *m_container;
|
return *m_container;
|
||||||
}
|
}
|
||||||
|
@ -284,7 +290,7 @@ inline typename GenericFileElement<ImplementationType>::containerType& GenericFi
|
||||||
* \brief Returns the related container.
|
* \brief Returns the related container.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline const typename GenericFileElement<ImplementationType>::containerType &GenericFileElement<ImplementationType>::container() const
|
inline const typename GenericFileElement<ImplementationType>::ContainerType &GenericFileElement<ImplementationType>::container() const
|
||||||
{
|
{
|
||||||
return *m_container;
|
return *m_container;
|
||||||
}
|
}
|
||||||
|
@ -338,7 +344,7 @@ inline uint64 GenericFileElement<ImplementationType>::relativeStartOffset() cons
|
||||||
* \brief Returns the element ID.
|
* \brief Returns the element ID.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline const typename GenericFileElement<ImplementationType>::identifierType &GenericFileElement<ImplementationType>::id() const
|
inline const typename GenericFileElement<ImplementationType>::IdentifierType &GenericFileElement<ImplementationType>::id() const
|
||||||
{
|
{
|
||||||
return m_id;
|
return m_id;
|
||||||
}
|
}
|
||||||
|
@ -378,7 +384,7 @@ inline uint32 GenericFileElement<ImplementationType>::headerSize() const
|
||||||
* This is the size of the element excluding the header.
|
* This is the size of the element excluding the header.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline typename GenericFileElement<ImplementationType>::dataSizeType GenericFileElement<ImplementationType>::dataSize() const
|
inline typename GenericFileElement<ImplementationType>::DataSizeType GenericFileElement<ImplementationType>::dataSize() const
|
||||||
{
|
{
|
||||||
return m_dataSize;
|
return m_dataSize;
|
||||||
}
|
}
|
||||||
|
@ -435,6 +441,18 @@ inline uint64 GenericFileElement<ImplementationType>::maxTotalSize() const
|
||||||
return m_maxSize;
|
return m_maxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns how deep the element is nested (0 for top-level elements, 1 for children of
|
||||||
|
* top-level elements, ...).
|
||||||
|
*/
|
||||||
|
template<class ImplementationType>
|
||||||
|
byte GenericFileElement<ImplementationType>::level() const
|
||||||
|
{
|
||||||
|
byte level = 0;
|
||||||
|
for(const ImplementationType *parent = m_parent; parent; ++level, parent = parent->m_parent);
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the parent of the element.
|
* \brief Returns the parent of the element.
|
||||||
*
|
*
|
||||||
|
@ -442,7 +460,7 @@ inline uint64 GenericFileElement<ImplementationType>::maxTotalSize() const
|
||||||
* If the current element is a top level element nullptr is returned.
|
* If the current element is a top level element nullptr is returned.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::parent()
|
inline ImplementationType *GenericFileElement<ImplementationType>::parent()
|
||||||
{
|
{
|
||||||
return m_parent;
|
return m_parent;
|
||||||
}
|
}
|
||||||
|
@ -454,11 +472,37 @@ inline typename GenericFileElement<ImplementationType>::implementationType *Gene
|
||||||
* If the current element is a top level element nullptr is returned.
|
* If the current element is a top level element nullptr is returned.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline const typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::parent() const
|
inline const ImplementationType *GenericFileElement<ImplementationType>::parent() const
|
||||||
{
|
{
|
||||||
return m_parent;
|
return m_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the n-th parent of the element.
|
||||||
|
* \remarks
|
||||||
|
* - The returned element has ownership (at least indirect) over the current instance.
|
||||||
|
* - Returns nullptr if level() < \a n.
|
||||||
|
*/
|
||||||
|
template <class ImplementationType>
|
||||||
|
ImplementationType *GenericFileElement<ImplementationType>::parent(byte n)
|
||||||
|
{
|
||||||
|
ImplementationType *parent = static_cast<ImplementationType *>(this);
|
||||||
|
for(; n && parent; --n, parent = parent->m_parent);
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the n-th parent of the element.
|
||||||
|
* \remarks
|
||||||
|
* - The returned element has ownership (at least indirect) over the current instance.
|
||||||
|
* - Returns nullptr if level() < \a n.
|
||||||
|
*/
|
||||||
|
template <class ImplementationType>
|
||||||
|
inline const ImplementationType *GenericFileElement<ImplementationType>::parent(byte n) const
|
||||||
|
{
|
||||||
|
return const_cast<GenericFileElement<ImplementationType> *>(this)->parent(n);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the next sibling of the element.
|
* \brief Returns the next sibling of the element.
|
||||||
*
|
*
|
||||||
|
@ -468,7 +512,7 @@ inline const typename GenericFileElement<ImplementationType>::implementationType
|
||||||
* \remarks parse() needs to be called before.
|
* \remarks parse() needs to be called before.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::nextSibling()
|
inline ImplementationType *GenericFileElement<ImplementationType>::nextSibling()
|
||||||
{
|
{
|
||||||
return m_nextSibling.get();
|
return m_nextSibling.get();
|
||||||
}
|
}
|
||||||
|
@ -482,7 +526,7 @@ inline typename GenericFileElement<ImplementationType>::implementationType *Gene
|
||||||
* \remarks parse() needs to be called before.
|
* \remarks parse() needs to be called before.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline const typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::nextSibling() const
|
inline const ImplementationType *GenericFileElement<ImplementationType>::nextSibling() const
|
||||||
{
|
{
|
||||||
return m_nextSibling.get();
|
return m_nextSibling.get();
|
||||||
}
|
}
|
||||||
|
@ -496,7 +540,7 @@ inline const typename GenericFileElement<ImplementationType>::implementationType
|
||||||
* \remarks parse() needs to be called before.
|
* \remarks parse() needs to be called before.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::firstChild()
|
inline ImplementationType *GenericFileElement<ImplementationType>::firstChild()
|
||||||
{
|
{
|
||||||
return m_firstChild.get();
|
return m_firstChild.get();
|
||||||
}
|
}
|
||||||
|
@ -510,11 +554,44 @@ inline typename GenericFileElement<ImplementationType>::implementationType *Gene
|
||||||
* \remarks parse() needs to be called before.
|
* \remarks parse() needs to be called before.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline const typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::firstChild() const
|
inline const ImplementationType *GenericFileElement<ImplementationType>::firstChild() const
|
||||||
{
|
{
|
||||||
return m_firstChild.get();
|
return m_firstChild.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the last child of the element.
|
||||||
|
*
|
||||||
|
* The current element keeps ownership over the returned element.
|
||||||
|
* If no childs are present nullptr is returned.
|
||||||
|
*
|
||||||
|
* \remarks parse() needs to be called before.
|
||||||
|
*/
|
||||||
|
template <class ImplementationType>
|
||||||
|
inline ImplementationType *GenericFileElement<ImplementationType>::lastChild()
|
||||||
|
{
|
||||||
|
for(ImplementationType *child = firstChild(); child; child = child->nextSibling()) {
|
||||||
|
if(!child->m_nextSibling) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the last child of the element.
|
||||||
|
*
|
||||||
|
* The current element keeps ownership over the returned element.
|
||||||
|
* If no childs are present nullptr is returned.
|
||||||
|
*
|
||||||
|
* \remarks parse() needs to be called before.
|
||||||
|
*/
|
||||||
|
template <class ImplementationType>
|
||||||
|
inline const ImplementationType *GenericFileElement<ImplementationType>::lastChild() const
|
||||||
|
{
|
||||||
|
return const_cast<GenericFileElement<ImplementationType> *>(this)->lastChild();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the sub element for the specified \a path.
|
* \brief Returns the sub element for the specified \a path.
|
||||||
*
|
*
|
||||||
|
@ -525,9 +602,9 @@ inline const typename GenericFileElement<ImplementationType>::implementationType
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::subelementByPath(const std::initializer_list<identifierType> &path)
|
inline ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(const std::initializer_list<IdentifierType> &path)
|
||||||
{
|
{
|
||||||
std::list<GenericFileElement<ImplementationType>::identifierType> list(path);
|
std::list<GenericFileElement<ImplementationType>::IdentifierType> list(path);
|
||||||
return subelementByPath(list);
|
return subelementByPath(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,13 +619,13 @@ inline typename GenericFileElement<ImplementationType>::implementationType *Gene
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::subelementByPath(std::list<GenericFileElement<ImplementationType>::identifierType> &path)
|
ImplementationType *GenericFileElement<ImplementationType>::subelementByPath(std::list<IdentifierType> &path)
|
||||||
{
|
{
|
||||||
parse(); // ensure element is parsed
|
parse(); // ensure element is parsed
|
||||||
if(path.size()) {
|
if(path.size()) {
|
||||||
if(path.front() == id()) {
|
if(path.front() == id()) {
|
||||||
if(path.size() == 1) {
|
if(path.size() == 1) {
|
||||||
return static_cast<implementationType*>(this);
|
return static_cast<ImplementationType *>(this);
|
||||||
} else {
|
} else {
|
||||||
if(firstChild()) {
|
if(firstChild()) {
|
||||||
path.pop_front();
|
path.pop_front();
|
||||||
|
@ -574,10 +651,10 @@ typename GenericFileElement<ImplementationType>::implementationType *GenericFile
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::childById(const GenericFileElement<ImplementationType>::identifierType &id)
|
ImplementationType *GenericFileElement<ImplementationType>::childById(const IdentifierType &id)
|
||||||
{
|
{
|
||||||
parse(); // ensure element is parsed
|
parse(); // ensure element is parsed
|
||||||
for(implementationType *child = firstChild(); child; child = child->nextSibling()) {
|
for(ImplementationType *child = firstChild(); child; child = child->nextSibling()) {
|
||||||
child->parse();
|
child->parse();
|
||||||
if(child->id() == id) {
|
if(child->id() == id) {
|
||||||
return child;
|
return child;
|
||||||
|
@ -601,10 +678,10 @@ typename GenericFileElement<ImplementationType>::implementationType *GenericFile
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::siblingById(const GenericFileElement<ImplementationType>::identifierType &id, bool includeThis)
|
ImplementationType *GenericFileElement<ImplementationType>::siblingById(const IdentifierType &id, bool includeThis)
|
||||||
{
|
{
|
||||||
parse(); // ensure element is parsed
|
parse(); // ensure element is parsed
|
||||||
for(implementationType *sibling = includeThis ? static_cast<implementationType*>(this) : nextSibling(); sibling; sibling = sibling->nextSibling()) {
|
for(ImplementationType *sibling = includeThis ? static_cast<ImplementationType *>(this) : nextSibling(); sibling; sibling = sibling->nextSibling()) {
|
||||||
sibling->parse();
|
sibling->parse();
|
||||||
if(sibling->id() == id) {
|
if(sibling->id() == id) {
|
||||||
return sibling;
|
return sibling;
|
||||||
|
@ -617,25 +694,25 @@ typename GenericFileElement<ImplementationType>::implementationType *GenericFile
|
||||||
* \brief Returns an iterator for iterating over the element's childs.
|
* \brief Returns an iterator for iterating over the element's childs.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
FileElementIterator<typename GenericFileElement<ImplementationType>::implementationType> GenericFileElement<ImplementationType>::begin()
|
FileElementIterator<ImplementationType> GenericFileElement<ImplementationType>::begin()
|
||||||
{
|
{
|
||||||
return FileElementIterator<implementationType>(firstChild());
|
return FileElementIterator<ImplementationType>(firstChild());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns an iterator for iterating over the element's childs (constant).
|
* \brief Returns an iterator for iterating over the element's childs (constant).
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
const FileElementIterator<typename GenericFileElement<ImplementationType>::implementationType> GenericFileElement<ImplementationType>::begin() const
|
const FileElementIterator<ImplementationType> GenericFileElement<ImplementationType>::begin() const
|
||||||
{
|
{
|
||||||
return FileElementIterator<implementationType>(firstChild());
|
return FileElementIterator<ImplementationType>(firstChild());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns an invalid iterator.
|
* \brief Returns an invalid iterator.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
FileElementIterator<typename GenericFileElement<ImplementationType>::implementationType> GenericFileElement<ImplementationType>::end()
|
FileElementIterator<ImplementationType> GenericFileElement<ImplementationType>::end()
|
||||||
{
|
{
|
||||||
return FileElementIterator<ImplementationType>();
|
return FileElementIterator<ImplementationType>();
|
||||||
}
|
}
|
||||||
|
@ -644,7 +721,7 @@ FileElementIterator<typename GenericFileElement<ImplementationType>::implementat
|
||||||
* \brief Returns an invalid iterator.
|
* \brief Returns an invalid iterator.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
const FileElementIterator<typename GenericFileElement<ImplementationType>::implementationType> GenericFileElement<ImplementationType>::end() const
|
const FileElementIterator<ImplementationType> GenericFileElement<ImplementationType>::end() const
|
||||||
{
|
{
|
||||||
return FileElementIterator<ImplementationType>();
|
return FileElementIterator<ImplementationType>();
|
||||||
}
|
}
|
||||||
|
@ -694,7 +771,7 @@ inline bool GenericFileElement<ImplementationType>::isParsed() const
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
void GenericFileElement<ImplementationType>::clear()
|
void GenericFileElement<ImplementationType>::clear()
|
||||||
{
|
{
|
||||||
m_id = identifierType();
|
m_id = IdentifierType();
|
||||||
//m_startOffset = 0;
|
//m_startOffset = 0;
|
||||||
m_idLength = 0;
|
m_idLength = 0;
|
||||||
m_dataSize = 0;
|
m_dataSize = 0;
|
||||||
|
@ -905,10 +982,10 @@ void GenericFileElement<ImplementationType>::copyInternal(std::ostream &targetSt
|
||||||
* \remarks A new first child is constructed. A possibly existing subtree is invalidated.
|
* \remarks A new first child is constructed. A possibly existing subtree is invalidated.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::denoteFirstChild(uint32 relativeFirstChildOffset)
|
ImplementationType *GenericFileElement<ImplementationType>::denoteFirstChild(uint32 relativeFirstChildOffset)
|
||||||
{
|
{
|
||||||
if(relativeFirstChildOffset + minimumElementSize() <= totalSize()) {
|
if(relativeFirstChildOffset + minimumElementSize() <= totalSize()) {
|
||||||
m_firstChild.reset(new implementationType(static_cast<implementationType &>(*this), startOffset() + relativeFirstChildOffset));
|
m_firstChild.reset(new ImplementationType(static_cast<ImplementationType &>(*this), startOffset() + relativeFirstChildOffset));
|
||||||
} else {
|
} else {
|
||||||
m_firstChild.reset();
|
m_firstChild.reset();
|
||||||
}
|
}
|
||||||
|
@ -921,7 +998,7 @@ typename GenericFileElement<ImplementationType>::implementationType *GenericFile
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
constexpr uint32 GenericFileElement<ImplementationType>::maximumIdLengthSupported()
|
constexpr uint32 GenericFileElement<ImplementationType>::maximumIdLengthSupported()
|
||||||
{
|
{
|
||||||
return sizeof(identifierType);
|
return sizeof(IdentifierType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -930,7 +1007,7 @@ constexpr uint32 GenericFileElement<ImplementationType>::maximumIdLengthSupporte
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
constexpr uint32 GenericFileElement<ImplementationType>::maximumSizeLengthSupported()
|
constexpr uint32 GenericFileElement<ImplementationType>::maximumSizeLengthSupported()
|
||||||
{
|
{
|
||||||
return sizeof(dataSizeType);
|
return sizeof(DataSizeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -12,7 +12,7 @@ class TagField;
|
||||||
* \class Media::TagFieldTraits
|
* \class Media::TagFieldTraits
|
||||||
* \brief Defines traits for the specified \a ImplementationType.
|
* \brief Defines traits for the specified \a ImplementationType.
|
||||||
*
|
*
|
||||||
* A template specialization for each TagField derivat must be provided.
|
* A template specialization for each TagField subclass must be provided.
|
||||||
*/
|
*/
|
||||||
template<typename ImplementationType>
|
template<typename ImplementationType>
|
||||||
class TagFieldTraits
|
class TagFieldTraits
|
||||||
|
@ -25,25 +25,26 @@ class TagFieldTraits
|
||||||
* might be assigned as well. The usage of the type info depends on the
|
* might be assigned as well. The usage of the type info depends on the
|
||||||
* particular tag implementation.
|
* particular tag implementation.
|
||||||
*
|
*
|
||||||
* \remarks This template class is intended to be used
|
* \tparam ImplementationType Specifies the type of the actual implementation.
|
||||||
|
* \remarks This template class is intended to be subclassed using
|
||||||
* with the "Curiously recurring template pattern".
|
* with the "Curiously recurring template pattern".
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
class TAG_PARSER_EXPORT TagField
|
class TAG_PARSER_EXPORT TagField
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
friend class TagFieldTraits<ImplementationType>;
|
friend class TagFieldTraits<ImplementationType>;
|
||||||
typedef typename TagFieldTraits<ImplementationType>::implementationType implementationType;
|
|
||||||
typedef typename TagFieldTraits<ImplementationType>::identifierType identifierType;
|
public:
|
||||||
typedef typename TagFieldTraits<ImplementationType>::typeInfoType typeInfoType;
|
typedef typename TagFieldTraits<ImplementationType>::IdentifierType IdentifierType;
|
||||||
|
typedef typename TagFieldTraits<ImplementationType>::TypeInfoType TypeInfoType;
|
||||||
|
|
||||||
TagField();
|
TagField();
|
||||||
TagField(const identifierType &id, const TagValue &value);
|
TagField(const IdentifierType &id, const TagValue &value);
|
||||||
~TagField();
|
~TagField();
|
||||||
|
|
||||||
const identifierType &id() const;
|
const IdentifierType &id() const;
|
||||||
std::string idToString() const;
|
std::string idToString() const;
|
||||||
void setId(const identifierType &id);
|
void setId(const IdentifierType &id);
|
||||||
void clearId();
|
void clearId();
|
||||||
|
|
||||||
TagValue &value();
|
TagValue &value();
|
||||||
|
@ -51,8 +52,8 @@ public:
|
||||||
void setValue(const TagValue &value);
|
void setValue(const TagValue &value);
|
||||||
void clearValue();
|
void clearValue();
|
||||||
|
|
||||||
const typeInfoType &typeInfo() const;
|
const TypeInfoType &typeInfo() const;
|
||||||
void setTypeInfo(const typeInfoType &typeInfo);
|
void setTypeInfo(const TypeInfoType &typeInfo);
|
||||||
void removeTypeInfo();
|
void removeTypeInfo();
|
||||||
bool isTypeInfoAssigned() const;
|
bool isTypeInfoAssigned() const;
|
||||||
|
|
||||||
|
@ -71,9 +72,9 @@ private:
|
||||||
void cleared();
|
void cleared();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
identifierType m_id;
|
IdentifierType m_id;
|
||||||
TagValue m_value;
|
TagValue m_value;
|
||||||
typeInfoType m_typeInfo;
|
TypeInfoType m_typeInfo;
|
||||||
bool m_typeInfoAssigned;
|
bool m_typeInfoAssigned;
|
||||||
bool m_default;
|
bool m_default;
|
||||||
std::vector<ImplementationType> m_nestedFields;
|
std::vector<ImplementationType> m_nestedFields;
|
||||||
|
@ -84,9 +85,9 @@ private:
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
TagField<ImplementationType>::TagField() :
|
TagField<ImplementationType>::TagField() :
|
||||||
m_id(identifierType()),
|
m_id(IdentifierType()),
|
||||||
m_value(TagValue()),
|
m_value(TagValue()),
|
||||||
m_typeInfo(typeInfoType()),
|
m_typeInfo(TypeInfoType()),
|
||||||
m_typeInfoAssigned(false),
|
m_typeInfoAssigned(false),
|
||||||
m_default(false)
|
m_default(false)
|
||||||
{}
|
{}
|
||||||
|
@ -95,10 +96,10 @@ TagField<ImplementationType>::TagField() :
|
||||||
* \brief Constructs a new TagField with the specified \a id and \a value.
|
* \brief Constructs a new TagField with the specified \a id and \a value.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
TagField<ImplementationType>::TagField(const identifierType &id, const TagValue &value) :
|
TagField<ImplementationType>::TagField(const IdentifierType &id, const TagValue &value) :
|
||||||
m_id(id),
|
m_id(id),
|
||||||
m_value(value),
|
m_value(value),
|
||||||
m_typeInfo(typeInfoType()),
|
m_typeInfo(TypeInfoType()),
|
||||||
m_typeInfoAssigned(false),
|
m_typeInfoAssigned(false),
|
||||||
m_default(false)
|
m_default(false)
|
||||||
{}
|
{}
|
||||||
|
@ -114,7 +115,7 @@ TagField<ImplementationType>::~TagField()
|
||||||
* \brief Returns the id of the current TagField.
|
* \brief Returns the id of the current TagField.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline const typename TagField<ImplementationType>::identifierType &TagField<ImplementationType>::id() const
|
inline const typename TagField<ImplementationType>::IdentifierType &TagField<ImplementationType>::id() const
|
||||||
{
|
{
|
||||||
return m_id;
|
return m_id;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +130,7 @@ inline std::string TagField<ImplementationType>::idToString() const
|
||||||
* \brief Sets the id of the current Tag Field.
|
* \brief Sets the id of the current Tag Field.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline void TagField<ImplementationType>::setId(const identifierType &id)
|
inline void TagField<ImplementationType>::setId(const IdentifierType &id)
|
||||||
{
|
{
|
||||||
m_id = id;
|
m_id = id;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +141,7 @@ inline void TagField<ImplementationType>::setId(const identifierType &id)
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline void TagField<ImplementationType>::clearId()
|
inline void TagField<ImplementationType>::clearId()
|
||||||
{
|
{
|
||||||
m_id = identifierType();
|
m_id = IdentifierType();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -183,7 +184,7 @@ inline void TagField<ImplementationType>::clearValue()
|
||||||
* \brief Returns the type info of the current TagField.
|
* \brief Returns the type info of the current TagField.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline const typename TagField<ImplementationType>::typeInfoType &TagField<ImplementationType>::typeInfo() const
|
inline const typename TagField<ImplementationType>::TypeInfoType &TagField<ImplementationType>::typeInfo() const
|
||||||
{
|
{
|
||||||
return m_typeInfo;
|
return m_typeInfo;
|
||||||
}
|
}
|
||||||
|
@ -192,7 +193,7 @@ inline const typename TagField<ImplementationType>::typeInfoType &TagField<Imple
|
||||||
* \brief Sets the type info of the current TagField.
|
* \brief Sets the type info of the current TagField.
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline void TagField<ImplementationType>::setTypeInfo(const typeInfoType &typeInfo)
|
inline void TagField<ImplementationType>::setTypeInfo(const TypeInfoType &typeInfo)
|
||||||
{
|
{
|
||||||
m_typeInfo = typeInfo;
|
m_typeInfo = typeInfo;
|
||||||
m_typeInfoAssigned = true;
|
m_typeInfoAssigned = true;
|
||||||
|
@ -204,7 +205,7 @@ inline void TagField<ImplementationType>::setTypeInfo(const typeInfoType &typeIn
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
inline void TagField<ImplementationType>::removeTypeInfo()
|
inline void TagField<ImplementationType>::removeTypeInfo()
|
||||||
{
|
{
|
||||||
m_typeInfo = typeInfoType();
|
m_typeInfo = TypeInfoType();
|
||||||
m_typeInfoAssigned = false;
|
m_typeInfoAssigned = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +244,7 @@ void TagField<ImplementationType>::clear()
|
||||||
{
|
{
|
||||||
clearId();
|
clearId();
|
||||||
clearValue();
|
clearValue();
|
||||||
m_typeInfo = typeInfoType();
|
m_typeInfo = TypeInfoType();
|
||||||
m_typeInfoAssigned = false;
|
m_typeInfoAssigned = false;
|
||||||
m_default = true;
|
m_default = true;
|
||||||
static_cast<ImplementationType *>(this)->cleared();
|
static_cast<ImplementationType *>(this)->cleared();
|
||||||
|
|
|
@ -30,7 +30,7 @@ TagType Id3v1Tag::type() const
|
||||||
|
|
||||||
const char *Id3v1Tag::typeName() const
|
const char *Id3v1Tag::typeName() const
|
||||||
{
|
{
|
||||||
return "ID3v1 tag";
|
return tagName;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Id3v1Tag::canEncodingBeUsed(TagTextEncoding encoding) const
|
bool Id3v1Tag::canEncodingBeUsed(TagTextEncoding encoding) const
|
||||||
|
|
|
@ -12,6 +12,7 @@ public:
|
||||||
Id3v1Tag();
|
Id3v1Tag();
|
||||||
|
|
||||||
static constexpr TagType tagType = TagType::Id3v1Tag;
|
static constexpr TagType tagType = TagType::Id3v1Tag;
|
||||||
|
static constexpr const char *tagName = "ID3v1 tag";
|
||||||
TagType type() const;
|
TagType type() const;
|
||||||
const char *typeName() const;
|
const char *typeName() const;
|
||||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||||
|
|
|
@ -50,7 +50,7 @@ Id3v2Frame::Id3v2Frame() :
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new Id3v2Frame with the specified \a id, \a value, \a group and \a flag.
|
* \brief Constructs a new Id3v2Frame with the specified \a id, \a value, \a group and \a flag.
|
||||||
*/
|
*/
|
||||||
Id3v2Frame::Id3v2Frame(const identifierType &id, const TagValue &value, const byte group, const int16 flag) :
|
Id3v2Frame::Id3v2Frame(const IdentifierType &id, const TagValue &value, const byte group, const int16 flag) :
|
||||||
TagField<Id3v2Frame>(id, value),
|
TagField<Id3v2Frame>(id, value),
|
||||||
m_flag(flag),
|
m_flag(flag),
|
||||||
m_group(group),
|
m_group(group),
|
||||||
|
|
|
@ -81,20 +81,8 @@ template <>
|
||||||
class TAG_PARSER_EXPORT TagFieldTraits<Id3v2Frame>
|
class TAG_PARSER_EXPORT TagFieldTraits<Id3v2Frame>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*!
|
typedef uint32 IdentifierType;
|
||||||
* \brief Fields in an ID3 tag are identified by 32-bit unsigned integers.
|
typedef byte TypeInfoType;
|
||||||
*/
|
|
||||||
typedef uint32 identifierType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The type info is stored using bytes.
|
|
||||||
*/
|
|
||||||
typedef byte typeInfoType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The implementation type is Id3v2Frame.
|
|
||||||
*/
|
|
||||||
typedef Id3v2Frame implementationType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TAG_PARSER_EXPORT Id3v2Frame : public TagField<Id3v2Frame>, public StatusProvider
|
class TAG_PARSER_EXPORT Id3v2Frame : public TagField<Id3v2Frame>, public StatusProvider
|
||||||
|
@ -103,7 +91,7 @@ class TAG_PARSER_EXPORT Id3v2Frame : public TagField<Id3v2Frame>, public StatusP
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Id3v2Frame();
|
Id3v2Frame();
|
||||||
Id3v2Frame(const identifierType &id, const TagValue &value, const byte group = 0, const int16 flag = 0);
|
Id3v2Frame(const IdentifierType &id, const TagValue &value, const byte group = 0, const int16 flag = 0);
|
||||||
|
|
||||||
// parsing/making
|
// parsing/making
|
||||||
void parse(IoUtilities::BinaryReader &reader, const uint32 version, const uint32 maximalSize = 0);
|
void parse(IoUtilities::BinaryReader &reader, const uint32 version, const uint32 maximalSize = 0);
|
||||||
|
@ -153,8 +141,8 @@ public:
|
||||||
void makeCommentConsideringVersion(std::unique_ptr<char[]> &buffer, uint32 &bufferSize, const TagValue &comment, byte version);
|
void makeCommentConsideringVersion(std::unique_ptr<char[]> &buffer, uint32 &bufferSize, const TagValue &comment, byte version);
|
||||||
void makeComment(std::unique_ptr<char[]> &buffer, uint32 &bufferSize, const TagValue &comment);
|
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 IdentifierType fieldIdFromString(const char *idString, std::size_t idStringSize = std::string::npos);
|
||||||
static std::string fieldIdToString(identifierType id);
|
static std::string fieldIdToString(IdentifierType id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void cleared();
|
void cleared();
|
||||||
|
@ -334,7 +322,7 @@ inline bool Id3v2Frame::supportsNestedFields() const
|
||||||
/*!
|
/*!
|
||||||
* \brief Converts the specified ID string representation to an actual ID.
|
* \brief Converts the specified ID string representation to an actual ID.
|
||||||
*/
|
*/
|
||||||
inline Id3v2Frame::identifierType Id3v2Frame::fieldIdFromString(const char *idString, std::size_t idStringSize)
|
inline Id3v2Frame::IdentifierType Id3v2Frame::fieldIdFromString(const char *idString, std::size_t idStringSize)
|
||||||
{
|
{
|
||||||
switch(idStringSize != std::string::npos ? idStringSize : std::strlen(idString)) {
|
switch(idStringSize != std::string::npos ? idStringSize : std::strlen(idString)) {
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -349,7 +337,7 @@ inline Id3v2Frame::identifierType Id3v2Frame::fieldIdFromString(const char *idSt
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the string representation for the specified \a id.
|
* \brief Returns the string representation for the specified \a id.
|
||||||
*/
|
*/
|
||||||
inline std::string Id3v2Frame::fieldIdToString(Id3v2Frame::identifierType id)
|
inline std::string Id3v2Frame::fieldIdToString(Id3v2Frame::IdentifierType id)
|
||||||
{
|
{
|
||||||
return ConversionUtilities::interpretIntegerAsString<uint32>(id, Id3v2FrameIds::isLongId(id) ? 0 : 1);
|
return ConversionUtilities::interpretIntegerAsString<uint32>(id, Id3v2FrameIds::isLongId(id) ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Media {
|
||||||
* \brief Implementation of Media::Tag for ID3v2 tags.
|
* \brief Implementation of Media::Tag for ID3v2 tags.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32 Id3v2Tag::fieldId(KnownField field) const
|
Id3v2Tag::IdentifierType Id3v2Tag::internallyGetFieldId(KnownField field) const
|
||||||
{
|
{
|
||||||
using namespace Id3v2FrameIds;
|
using namespace Id3v2FrameIds;
|
||||||
if(m_majorVersion >= 3) {
|
if(m_majorVersion >= 3) {
|
||||||
|
@ -78,7 +78,7 @@ uint32 Id3v2Tag::fieldId(KnownField field) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
KnownField Id3v2Tag::knownField(const uint32 &id) const
|
KnownField Id3v2Tag::internallyGetKnownField(const IdentifierType &id) const
|
||||||
{
|
{
|
||||||
using namespace Id3v2FrameIds;
|
using namespace Id3v2FrameIds;
|
||||||
switch(id) {
|
switch(id) {
|
||||||
|
@ -125,7 +125,7 @@ KnownField Id3v2Tag::knownField(const uint32 &id) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TagDataType Id3v2Tag::proposedDataType(const uint32 &id) const
|
TagDataType Id3v2Tag::internallyGetProposedDataType(const uint32 &id) const
|
||||||
{
|
{
|
||||||
using namespace Id3v2FrameIds;
|
using namespace Id3v2FrameIds;
|
||||||
switch(id) {
|
switch(id) {
|
||||||
|
@ -147,16 +147,6 @@ TagDataType Id3v2Tag::proposedDataType(const uint32 &id) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TagValue &Id3v2Tag::value(const typename Id3v2Frame::identifierType &id) const
|
|
||||||
{
|
|
||||||
return FieldMapBasedTag<Id3v2Frame, FrameComparer>::value(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Id3v2Tag::setValue(const typename Id3v2Frame::identifierType &id, const TagValue &value)
|
|
||||||
{
|
|
||||||
return FieldMapBasedTag<Id3v2Frame, FrameComparer>::setValue(id, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Parses tag information from the specified \a stream.
|
* \brief Parses tag information from the specified \a stream.
|
||||||
*
|
*
|
||||||
|
|
|
@ -52,23 +52,29 @@ inline uint64 Id3v2TagMaker::requiredSize() const
|
||||||
return m_requiredSize;
|
return m_requiredSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
class TAG_PARSER_EXPORT Id3v2Tag : public FieldMapBasedTag<Id3v2Frame, FrameComparer>
|
/*!
|
||||||
|
* \brief Defines traits for the TagField implementation of the Id3v2Tag class.
|
||||||
|
*/
|
||||||
|
template <>
|
||||||
|
class TAG_PARSER_EXPORT FieldMapBasedTagTraits<Id3v2Tag>
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
typedef Id3v2Frame FieldType;
|
||||||
|
typedef FrameComparer Compare;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TAG_PARSER_EXPORT Id3v2Tag : public FieldMapBasedTag<Id3v2Tag>
|
||||||
|
{
|
||||||
|
friend class FieldMapBasedTag<Id3v2Tag>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Id3v2Tag();
|
Id3v2Tag();
|
||||||
|
|
||||||
static constexpr TagType tagType = TagType::Id3v2Tag;
|
static constexpr TagType tagType = TagType::Id3v2Tag;
|
||||||
TagType type() const;
|
static constexpr const char *tagName = "ID3v2 tag";
|
||||||
const char *typeName() const;
|
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf16LittleEndian;
|
||||||
TagTextEncoding proposedTextEncoding() const;
|
TagTextEncoding proposedTextEncoding() const;
|
||||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||||
uint32 fieldId(KnownField value) const;
|
|
||||||
KnownField knownField(const uint32 &id) const;
|
|
||||||
TagDataType proposedDataType(const uint32 &id) const;
|
|
||||||
using FieldMapBasedTag<Id3v2Frame, FrameComparer>::value;
|
|
||||||
const TagValue &value(const typename Id3v2Frame::identifierType &id) const;
|
|
||||||
using FieldMapBasedTag<Id3v2Frame, FrameComparer>::setValue;
|
|
||||||
bool setValue(const typename Id3v2Frame::identifierType &id, const TagValue &value);
|
|
||||||
bool supportsDescription(KnownField field) const;
|
bool supportsDescription(KnownField field) const;
|
||||||
bool supportsMimeType(KnownField field) const;
|
bool supportsMimeType(KnownField field) const;
|
||||||
|
|
||||||
|
@ -88,6 +94,11 @@ public:
|
||||||
uint32 extendedHeaderSize() const;
|
uint32 extendedHeaderSize() const;
|
||||||
uint32 paddingSize() const;
|
uint32 paddingSize() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
IdentifierType internallyGetFieldId(KnownField field) const;
|
||||||
|
KnownField internallyGetKnownField(const IdentifierType &id) const;
|
||||||
|
TagDataType internallyGetProposedDataType(const uint32 &id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
byte m_majorVersion;
|
byte m_majorVersion;
|
||||||
byte m_revisionVersion;
|
byte m_revisionVersion;
|
||||||
|
@ -109,16 +120,6 @@ inline Id3v2Tag::Id3v2Tag() :
|
||||||
m_paddingSize(0)
|
m_paddingSize(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline TagType Id3v2Tag::type() const
|
|
||||||
{
|
|
||||||
return TagType::Id3v2Tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char *Id3v2Tag::typeName() const
|
|
||||||
{
|
|
||||||
return "ID3v2 tag";
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TagTextEncoding Id3v2Tag::proposedTextEncoding() const
|
inline TagTextEncoding Id3v2Tag::proposedTextEncoding() const
|
||||||
{
|
{
|
||||||
return m_majorVersion > 3 ? TagTextEncoding::Utf8 : TagTextEncoding::Utf16LittleEndian;
|
return m_majorVersion > 3 ? TagTextEncoding::Utf8 : TagTextEncoding::Utf16LittleEndian;
|
||||||
|
|
|
@ -77,15 +77,16 @@ void EbmlElement::internalParse()
|
||||||
throw TruncatedDataException();
|
throw TruncatedDataException();
|
||||||
}
|
}
|
||||||
stream().seekg(startOffset());
|
stream().seekg(startOffset());
|
||||||
|
|
||||||
// read ID
|
// read ID
|
||||||
char buf[maximumIdLengthSupported() > maximumSizeLengthSupported() ? maximumIdLengthSupported() : maximumSizeLengthSupported()] = {0};
|
char buf[maximumIdLengthSupported() > maximumSizeLengthSupported() ? maximumIdLengthSupported() : maximumSizeLengthSupported()] = {0};
|
||||||
byte beg = static_cast<byte>(stream().peek()), mask = 0x80;
|
byte beg = static_cast<byte>(stream().peek()), mask = 0x80;
|
||||||
m_idLength = 1;
|
m_idLength = 1;
|
||||||
while(m_idLength <= GenericFileElement<implementationType>::maximumIdLengthSupported() && (beg & mask) == 0) {
|
while(m_idLength <= maximumIdLengthSupported() && (beg & mask) == 0) {
|
||||||
++m_idLength;
|
++m_idLength;
|
||||||
mask >>= 1;
|
mask >>= 1;
|
||||||
}
|
}
|
||||||
if(m_idLength > GenericFileElement<implementationType>::maximumIdLengthSupported()) {
|
if(m_idLength > maximumIdLengthSupported()) {
|
||||||
if(!skipped) {
|
if(!skipped) {
|
||||||
addNotification(NotificationType::Critical, argsToString("EBML ID length at ", startOffset(), " is not supported, trying to skip."), context);
|
addNotification(NotificationType::Critical, argsToString("EBML ID length at ", startOffset(), " is not supported, trying to skip."), context);
|
||||||
}
|
}
|
||||||
|
@ -97,22 +98,62 @@ void EbmlElement::internalParse()
|
||||||
}
|
}
|
||||||
continue; // try again
|
continue; // try again
|
||||||
}
|
}
|
||||||
reader().read(buf + (GenericFileElement<implementationType>::maximumIdLengthSupported() - m_idLength), m_idLength);
|
reader().read(buf + (maximumIdLengthSupported() - m_idLength), m_idLength);
|
||||||
m_id = BE::toUInt32(buf);
|
m_id = BE::toUInt32(buf);
|
||||||
|
|
||||||
|
// check whether this element is actually a sibling of one of its parents rather then a child
|
||||||
|
// (might be the case if the parent's size is unknown and hence assumed to be the max file size)
|
||||||
|
if(m_parent && m_parent->m_sizeUnknown) {
|
||||||
|
// check at which level in the hierarchy the element is supposed to occour using its ID
|
||||||
|
// (the only chance to find out whether the element belongs higher up in the hierarchy)
|
||||||
|
const MatroskaElementLevel supposedLevel = matroskaIdLevel(m_id);
|
||||||
|
const byte actualLevel = level();
|
||||||
|
if(actualLevel > supposedLevel) {
|
||||||
|
// the file belongs higher up in the hierarchy so find a better parent
|
||||||
|
if(EbmlElement *betterParent = m_parent->parent(actualLevel - static_cast<byte>(supposedLevel))) {
|
||||||
|
// recompute the parent size (assumption - which was rest of the available space - was wrong)
|
||||||
|
m_parent->m_dataSize = m_startOffset - m_parent->m_startOffset - m_parent->headerSize();
|
||||||
|
m_parent->m_sizeUnknown = false;
|
||||||
|
// detatch from ...
|
||||||
|
if(m_parent->firstChild() == this) {
|
||||||
|
// ... parent
|
||||||
|
m_parent->m_firstChild.release();
|
||||||
|
m_parent->m_firstChild = move(m_nextSibling);
|
||||||
|
} else {
|
||||||
|
// ... previous sibling
|
||||||
|
for(EbmlElement *sibling = m_parent->firstChild(); sibling; sibling = sibling->nextSibling()) {
|
||||||
|
if(sibling->nextSibling() == this) {
|
||||||
|
sibling->m_nextSibling.release();
|
||||||
|
sibling->m_nextSibling = move(m_nextSibling);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// insert as child of better parent
|
||||||
|
if(EbmlElement *previousSibling = betterParent->lastChild()) {
|
||||||
|
previousSibling->m_nextSibling.reset(this);
|
||||||
|
} else {
|
||||||
|
betterParent->m_firstChild.reset(this);
|
||||||
|
}
|
||||||
|
// update own reference to parent
|
||||||
|
m_parent = betterParent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// read size
|
// read size
|
||||||
beg = static_cast<byte>(stream().peek()), mask = 0x80;
|
beg = static_cast<byte>(stream().peek()), mask = 0x80;
|
||||||
m_sizeLength = 1;
|
m_sizeLength = 1;
|
||||||
if(beg == 0xFF) {
|
if((m_sizeUnknown = (beg == 0xFF))) {
|
||||||
// this indicates that the element size is unknown
|
// this indicates that the element size is unknown
|
||||||
// -> just assume the element takes the maximum available size
|
// -> just assume the element takes the maximum available size
|
||||||
m_dataSize = maxTotalSize() - headerSize();
|
m_dataSize = maxTotalSize() - headerSize();
|
||||||
} else {
|
} else {
|
||||||
while(m_sizeLength <= GenericFileElement<implementationType>::maximumSizeLengthSupported() && (beg & mask) == 0) {
|
while(m_sizeLength <= maximumSizeLengthSupported() && (beg & mask) == 0) {
|
||||||
++m_sizeLength;
|
++m_sizeLength;
|
||||||
mask >>= 1;
|
mask >>= 1;
|
||||||
}
|
}
|
||||||
if(m_sizeLength > GenericFileElement<implementationType>::maximumSizeLengthSupported()) {
|
if(m_sizeLength > maximumSizeLengthSupported()) {
|
||||||
if(!skipped) {
|
if(!skipped) {
|
||||||
addNotification(NotificationType::Critical, "EBML size length is not supported.", parsingContext());
|
addNotification(NotificationType::Critical, "EBML size length is not supported.", parsingContext());
|
||||||
}
|
}
|
||||||
|
@ -125,9 +166,10 @@ void EbmlElement::internalParse()
|
||||||
continue; // try again
|
continue; // try again
|
||||||
}
|
}
|
||||||
// read size into buffer
|
// read size into buffer
|
||||||
memset(buf, 0, sizeof(dataSizeType)); // reset buffer
|
memset(buf, 0, sizeof(DataSizeType)); // reset buffer
|
||||||
reader().read(buf + (GenericFileElement<implementationType>::maximumSizeLengthSupported() - m_sizeLength), m_sizeLength);
|
reader().read(buf + (maximumSizeLengthSupported() - m_sizeLength), m_sizeLength);
|
||||||
*(buf + (GenericFileElement<implementationType>::maximumSizeLengthSupported() - m_sizeLength)) ^= mask; // xor the first byte in buffer which has been read from the file with mask
|
// xor the first byte in buffer which has been read from the file with mask
|
||||||
|
*(buf + (maximumSizeLengthSupported() - m_sizeLength)) ^= mask;
|
||||||
m_dataSize = ConversionUtilities::BE::toUInt64(buf);
|
m_dataSize = ConversionUtilities::BE::toUInt64(buf);
|
||||||
// check if element is truncated
|
// check if element is truncated
|
||||||
if(totalSize() > maxTotalSize()) {
|
if(totalSize() > maxTotalSize()) {
|
||||||
|
@ -223,7 +265,7 @@ float64 EbmlElement::readFloat()
|
||||||
* \brief Returns the length of the specified \a id in byte.
|
* \brief Returns the length of the specified \a id in byte.
|
||||||
* \throws Throws InvalidDataException() if \a id can not be represented.
|
* \throws Throws InvalidDataException() if \a id can not be represented.
|
||||||
*/
|
*/
|
||||||
byte EbmlElement::calculateIdLength(GenericFileElement::identifierType id)
|
byte EbmlElement::calculateIdLength(GenericFileElement::IdentifierType id)
|
||||||
{
|
{
|
||||||
if(id <= 0xFF) {
|
if(id <= 0xFF) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -271,7 +313,7 @@ byte EbmlElement::calculateSizeDenotationLength(uint64 size)
|
||||||
* \returns Returns the number of bytes written to \a buff.
|
* \returns Returns the number of bytes written to \a buff.
|
||||||
* \throws Throws InvalidDataException() if \a id can not be represented.
|
* \throws Throws InvalidDataException() if \a id can not be represented.
|
||||||
*/
|
*/
|
||||||
byte EbmlElement::makeId(GenericFileElement::identifierType id, char *buff)
|
byte EbmlElement::makeId(GenericFileElement::IdentifierType id, char *buff)
|
||||||
{
|
{
|
||||||
if(id <= 0xFF) {
|
if(id <= 0xFF) {
|
||||||
*buff = static_cast<byte>(id);
|
*buff = static_cast<byte>(id);
|
||||||
|
@ -465,7 +507,7 @@ byte EbmlElement::makeUInteger(uint64 value, char *buff, byte minBytes)
|
||||||
* \param id Specifies the element ID.
|
* \param id Specifies the element ID.
|
||||||
* \param content Specifies the value of the element as unsigned integer.
|
* \param content Specifies the value of the element as unsigned integer.
|
||||||
*/
|
*/
|
||||||
void EbmlElement::makeSimpleElement(ostream &stream, identifierType id, uint64 content)
|
void EbmlElement::makeSimpleElement(ostream &stream, IdentifierType id, uint64 content)
|
||||||
{
|
{
|
||||||
char buff1[8];
|
char buff1[8];
|
||||||
char buff2[8];
|
char buff2[8];
|
||||||
|
@ -483,7 +525,7 @@ void EbmlElement::makeSimpleElement(ostream &stream, identifierType id, uint64 c
|
||||||
* \param id Specifies the element ID.
|
* \param id Specifies the element ID.
|
||||||
* \param content Specifies the value of the element as string.
|
* \param content Specifies the value of the element as string.
|
||||||
*/
|
*/
|
||||||
void EbmlElement::makeSimpleElement(std::ostream &stream, GenericFileElement::identifierType id, const std::string &content)
|
void EbmlElement::makeSimpleElement(std::ostream &stream, GenericFileElement::IdentifierType id, const std::string &content)
|
||||||
{
|
{
|
||||||
char buff1[8];
|
char buff1[8];
|
||||||
byte sizeLength = EbmlElement::makeId(id, buff1);
|
byte sizeLength = EbmlElement::makeId(id, buff1);
|
||||||
|
@ -500,7 +542,7 @@ void EbmlElement::makeSimpleElement(std::ostream &stream, GenericFileElement::id
|
||||||
* \param data Specifies the data of the element.
|
* \param data Specifies the data of the element.
|
||||||
* \param dataSize Specifies the size of \a data.
|
* \param dataSize Specifies the size of \a data.
|
||||||
*/
|
*/
|
||||||
void EbmlElement::makeSimpleElement(ostream &stream, GenericFileElement::identifierType id, const char *data, std::size_t dataSize)
|
void EbmlElement::makeSimpleElement(ostream &stream, GenericFileElement::IdentifierType id, const char *data, std::size_t dataSize)
|
||||||
{
|
{
|
||||||
char buff1[8];
|
char buff1[8];
|
||||||
byte sizeLength = EbmlElement::makeId(id, buff1);
|
byte sizeLength = EbmlElement::makeId(id, buff1);
|
||||||
|
|
|
@ -26,25 +26,9 @@ template <>
|
||||||
class TAG_PARSER_EXPORT FileElementTraits<EbmlElement>
|
class TAG_PARSER_EXPORT FileElementTraits<EbmlElement>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*!
|
typedef MatroskaContainer ContainerType;
|
||||||
* \brief The container type used to store such elements is MatroskaContainer.
|
typedef uint32 IdentifierType;
|
||||||
*/
|
typedef uint64 DataSizeType;
|
||||||
typedef MatroskaContainer containerType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The type used to store element IDs is an unsigned 32-bit integer.
|
|
||||||
*/
|
|
||||||
typedef uint32 identifierType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The type used to store element sizes is an unsigned 64-bit integer.
|
|
||||||
*/
|
|
||||||
typedef uint64 dataSizeType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The implementation type is EbmlElement.
|
|
||||||
*/
|
|
||||||
typedef EbmlElement implementationType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TAG_PARSER_EXPORT EbmlElement : public GenericFileElement<EbmlElement>
|
class TAG_PARSER_EXPORT EbmlElement : public GenericFileElement<EbmlElement>
|
||||||
|
@ -62,17 +46,17 @@ public:
|
||||||
uint64 readUInteger();
|
uint64 readUInteger();
|
||||||
float64 readFloat();
|
float64 readFloat();
|
||||||
|
|
||||||
static byte calculateIdLength(identifierType id);
|
static byte calculateIdLength(IdentifierType id);
|
||||||
static byte calculateSizeDenotationLength(uint64 size);
|
static byte calculateSizeDenotationLength(uint64 size);
|
||||||
static byte makeId(identifierType id, char *buff);
|
static byte makeId(IdentifierType id, char *buff);
|
||||||
static byte makeSizeDenotation(uint64 size, char *buff);
|
static byte makeSizeDenotation(uint64 size, char *buff);
|
||||||
static byte makeSizeDenotation(uint64 size, char *buff, byte minBytes);
|
static byte makeSizeDenotation(uint64 size, char *buff, byte minBytes);
|
||||||
static byte calculateUIntegerLength(uint64 integer);
|
static byte calculateUIntegerLength(uint64 integer);
|
||||||
static byte makeUInteger(uint64 value, char *buff);
|
static byte makeUInteger(uint64 value, char *buff);
|
||||||
static byte makeUInteger(uint64 value, char *buff, byte minBytes);
|
static byte makeUInteger(uint64 value, char *buff, byte minBytes);
|
||||||
static void makeSimpleElement(std::ostream &stream, identifierType id, uint64 content);
|
static void makeSimpleElement(std::ostream &stream, IdentifierType id, uint64 content);
|
||||||
static void makeSimpleElement(std::ostream &stream, identifierType id, const std::string &content);
|
static void makeSimpleElement(std::ostream &stream, IdentifierType id, const std::string &content);
|
||||||
static void makeSimpleElement(std::ostream &stream, GenericFileElement::identifierType id, const char *data, std::size_t dataSize);
|
static void makeSimpleElement(std::ostream &stream, IdentifierType id, const char *data, std::size_t dataSize);
|
||||||
static uint64 bytesToBeSkipped;
|
static uint64 bytesToBeSkipped;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -124,7 +124,7 @@ MatroskaAttachmentMaker::MatroskaAttachmentMaker(MatroskaAttachment &attachment)
|
||||||
}
|
}
|
||||||
if(attachment.attachedFileElement()) {
|
if(attachment.attachedFileElement()) {
|
||||||
EbmlElement *child;
|
EbmlElement *child;
|
||||||
for(auto id : initializer_list<EbmlElement::identifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
|
for(auto id : initializer_list<EbmlElement::IdentifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
|
||||||
if((child = attachment.attachedFileElement()->childById(id))) {
|
if((child = attachment.attachedFileElement()->childById(id))) {
|
||||||
m_attachedFileElementSize += child->totalSize();
|
m_attachedFileElementSize += child->totalSize();
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ void MatroskaAttachmentMaker::make(ostream &stream) const
|
||||||
EbmlElement::makeSimpleElement(stream, MatroskaIds::FileUID, attachment().id());
|
EbmlElement::makeSimpleElement(stream, MatroskaIds::FileUID, attachment().id());
|
||||||
if(attachment().attachedFileElement()) {
|
if(attachment().attachedFileElement()) {
|
||||||
EbmlElement *child;
|
EbmlElement *child;
|
||||||
for(auto id : initializer_list<EbmlElement::identifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
|
for(auto id : initializer_list<EbmlElement::IdentifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
|
||||||
if((child = attachment().attachedFileElement()->childById(id))) {
|
if((child = attachment().attachedFileElement()->childById(id))) {
|
||||||
if(child->buffer()) {
|
if(child->buffer()) {
|
||||||
child->copyBuffer(stream);
|
child->copyBuffer(stream);
|
||||||
|
@ -179,7 +179,7 @@ void MatroskaAttachmentMaker::bufferCurrentAttachments()
|
||||||
{
|
{
|
||||||
EbmlElement *child;
|
EbmlElement *child;
|
||||||
if(attachment().attachedFileElement()) {
|
if(attachment().attachedFileElement()) {
|
||||||
for(auto id : initializer_list<EbmlElement::identifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
|
for(auto id : initializer_list<EbmlElement::IdentifierType>{MatroskaIds::FileReferral, MatroskaIds::FileUsedStartTime, MatroskaIds::FileUsedEndTime}) {
|
||||||
if((child = attachment().attachedFileElement()->childById(id))) {
|
if((child = attachment().attachedFileElement()->childById(id))) {
|
||||||
child->makeBuffer();
|
child->makeBuffer();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include "./ebmlelement.h"
|
#include "./ebmlelement.h"
|
||||||
|
|
||||||
#include <map>
|
#include <unordered_map>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
|
@ -77,9 +77,9 @@ private:
|
||||||
bool updateSize(EbmlElement *element, int shift);
|
bool updateSize(EbmlElement *element, int shift);
|
||||||
|
|
||||||
EbmlElement *m_cuesElement;
|
EbmlElement *m_cuesElement;
|
||||||
std::map<EbmlElement *, MatroskaOffsetStates> m_offsets;
|
std::unordered_map<EbmlElement *, MatroskaOffsetStates> m_offsets;
|
||||||
std::map<EbmlElement *, MatroskaReferenceOffsetPair> m_relativeOffsets;
|
std::unordered_map<EbmlElement *, MatroskaReferenceOffsetPair> m_relativeOffsets;
|
||||||
std::map<EbmlElement *, uint64> m_sizes;
|
std::unordered_map<EbmlElement *, uint64> m_sizes;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -63,10 +63,10 @@ const char *matroskaIdName(uint32 matroskaId)
|
||||||
case DateUTC: return "date UTC";
|
case DateUTC: return "date UTC";
|
||||||
case SegmentUID: return "unique segment ID";
|
case SegmentUID: return "unique segment ID";
|
||||||
case SegmentFileName: return "segment file name";
|
case SegmentFileName: return "segment file name";
|
||||||
case PrevUId: return "previous unique id";
|
case PrevUID: return "previous unique id";
|
||||||
case PrevFileName: return "previous file name";
|
case PrevFileName: return "previous file name";
|
||||||
case NexUId: return "next unique ID";
|
case NexUID: return "next unique ID";
|
||||||
case NexFileName: return "next file name";
|
case NextFileName: return "next file name";
|
||||||
case Title: return "title";
|
case Title: return "title";
|
||||||
case SegmentFamily: return "segment family";
|
case SegmentFamily: return "segment family";
|
||||||
case ChapterTranslate: return "chapter translate";
|
case ChapterTranslate: return "chapter translate";
|
||||||
|
@ -184,10 +184,10 @@ const char *matroskaIdName(uint32 matroskaId)
|
||||||
// IDs in the Targets master
|
// IDs in the Targets master
|
||||||
case TargetTypeValue: return "target type value";
|
case TargetTypeValue: return "target type value";
|
||||||
case TargetType: return "target type";
|
case TargetType: return "target type";
|
||||||
case TagTrackUId: return "tag track UID";
|
case TagTrackUID: return "tag track UID";
|
||||||
case TagEditionUId: return "tag edition UID";
|
case TagEditionUID: return "tag edition UID";
|
||||||
case TagChapterUId: return "tag chapter UID";
|
case TagChapterUID: return "tag chapter UID";
|
||||||
case TagAttachmentUId: return "tag attachment UID";
|
case TagAttachmentUID: return "tag attachment UID";
|
||||||
|
|
||||||
// IDs in the Cues master
|
// IDs in the Cues master
|
||||||
case CuePoint: return "cue point";
|
case CuePoint: return "cue point";
|
||||||
|
@ -315,5 +315,156 @@ const char *matroskaIdName(uint32 matroskaId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the level at which elements with the specified \a matroskaId are supposed
|
||||||
|
* to occur in a Matroska file.
|
||||||
|
*/
|
||||||
|
MatroskaElementLevel matroskaIdLevel(uint32 matroskaId)
|
||||||
|
{
|
||||||
|
using namespace EbmlIds;
|
||||||
|
using namespace MatroskaIds;
|
||||||
|
switch(matroskaId) {
|
||||||
|
case Header:
|
||||||
|
case Segment:
|
||||||
|
return MatroskaElementLevel::TopLevel;
|
||||||
|
case SeekHead:
|
||||||
|
case SegmentInfo:
|
||||||
|
case Cluster:
|
||||||
|
case Tracks:
|
||||||
|
case Cues:
|
||||||
|
case Attachments:
|
||||||
|
case Chapters:
|
||||||
|
case Tags:
|
||||||
|
return MatroskaElementLevel::Level1;
|
||||||
|
case Seek:
|
||||||
|
case SegmentUID:
|
||||||
|
case SegmentFileName:
|
||||||
|
case PrevUID:
|
||||||
|
case PrevFileName:
|
||||||
|
case NexUID:
|
||||||
|
case NextFileName:
|
||||||
|
case SegmentFamily:
|
||||||
|
case ChapterTranslate:
|
||||||
|
case TimeCodeScale:
|
||||||
|
case Duration:
|
||||||
|
case DateUTC:
|
||||||
|
case Title:
|
||||||
|
case MuxingApp:
|
||||||
|
case WrittingApp:
|
||||||
|
case Timecode:
|
||||||
|
case SilentTracks:
|
||||||
|
case Position:
|
||||||
|
case PrevSize:
|
||||||
|
case SimpleBlock:
|
||||||
|
case BlockGroup:
|
||||||
|
case EncryptedBlock:
|
||||||
|
case TrackEntry:
|
||||||
|
case CuePoint:
|
||||||
|
case AttachedFile:
|
||||||
|
case EditionEntry:
|
||||||
|
case Tag:
|
||||||
|
return MatroskaElementLevel::Level2;
|
||||||
|
case SeekID:
|
||||||
|
case SeekPosition:
|
||||||
|
case ChapterTranslateEditionUID:
|
||||||
|
case ChapterTranslateCodec:
|
||||||
|
case ChapterTranslateID:
|
||||||
|
case SilentTrackNumber:
|
||||||
|
case BlockVirtual:
|
||||||
|
case BlockAdditions:
|
||||||
|
case BlockDuration:
|
||||||
|
case ReferencePriority:
|
||||||
|
case ReferenceBlock:
|
||||||
|
case ReferenceVirtual:
|
||||||
|
case CodecState:
|
||||||
|
case DiscardPadding:
|
||||||
|
case Slices:
|
||||||
|
case TrackNumber:
|
||||||
|
case TrackUID:
|
||||||
|
case TrackType:
|
||||||
|
case TrackFlagEnabled:
|
||||||
|
case TrackFlagDefault:
|
||||||
|
case TrackFlagForced:
|
||||||
|
case TrackFlagLacing:
|
||||||
|
case MinCache:
|
||||||
|
case MaxCache:
|
||||||
|
case DefaultDuration:
|
||||||
|
case DefaultDecodedFieldDuration:
|
||||||
|
case TrackTimeCodeScale:
|
||||||
|
case TrackOffset:
|
||||||
|
case MaxBlockAdditionId:
|
||||||
|
case TrackName:
|
||||||
|
case TrackLanguage:
|
||||||
|
case CodecID:
|
||||||
|
case CodecPrivate:
|
||||||
|
case CodecName:
|
||||||
|
case AttachmentLink:
|
||||||
|
case CodecSettings:
|
||||||
|
case CodecInfoUrl:
|
||||||
|
case CodecDownloadUrl:
|
||||||
|
case CodecDecodeAll:
|
||||||
|
case TrackOverlay:
|
||||||
|
case CodecDelay:
|
||||||
|
case SeekPreRoll:
|
||||||
|
case TrackTranslate:
|
||||||
|
case TrackVideo:
|
||||||
|
case TrackAudio:
|
||||||
|
case ContentEncodings:
|
||||||
|
case CueTime:
|
||||||
|
case CueTrackPositions:
|
||||||
|
case FileDescription:
|
||||||
|
case FileName:
|
||||||
|
case FileMimeType:
|
||||||
|
case FileData:
|
||||||
|
case FileUID:
|
||||||
|
case FileReferral:
|
||||||
|
case FileUsedStartTime:
|
||||||
|
case FileUsedEndTime:
|
||||||
|
case EditionUID:
|
||||||
|
case EditionFlagHidden:
|
||||||
|
case EditionFlagDefault:
|
||||||
|
case EditionFlagOrdered:
|
||||||
|
case Targets:
|
||||||
|
return MatroskaElementLevel::Level3;
|
||||||
|
case BlockMore:
|
||||||
|
case TimeSlice:
|
||||||
|
case ContentEncoding:
|
||||||
|
case CueTrack:
|
||||||
|
case CueClusterPosition:
|
||||||
|
case CueRelativePosition:
|
||||||
|
case CueDuration:
|
||||||
|
case CueBlockNumber:
|
||||||
|
case CueCodecState:
|
||||||
|
case CueReference:
|
||||||
|
case TargetTypeValue:
|
||||||
|
case TargetType:
|
||||||
|
case TagTrackUID:
|
||||||
|
case TagEditionUID:
|
||||||
|
case TagChapterUID:
|
||||||
|
case TagAttachmentUID:
|
||||||
|
return MatroskaElementLevel::Level4;
|
||||||
|
case BlockAddID:
|
||||||
|
case BlockAdditional:
|
||||||
|
case LaceNumber:
|
||||||
|
case FrameNumber:
|
||||||
|
case BlockAdditionID:
|
||||||
|
case Delay:
|
||||||
|
case SliceDuration:
|
||||||
|
case ReferenceFrame:
|
||||||
|
case ReferenceOffset:
|
||||||
|
case ReferenceTimeCode:
|
||||||
|
case CueRefTime:
|
||||||
|
case CueRefCluster:
|
||||||
|
case CueRefNumber:
|
||||||
|
case CueRefCodecState:
|
||||||
|
return MatroskaElementLevel::Level5;
|
||||||
|
case Void:
|
||||||
|
case Crc32:
|
||||||
|
return MatroskaElementLevel::Global;
|
||||||
|
default:
|
||||||
|
return MatroskaElementLevel::Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,10 +50,10 @@ enum SegmentInfoIds {
|
||||||
DateUTC = 0x4461,
|
DateUTC = 0x4461,
|
||||||
SegmentUID = 0x73A4,
|
SegmentUID = 0x73A4,
|
||||||
SegmentFileName = 0x7384,
|
SegmentFileName = 0x7384,
|
||||||
PrevUId = 0x3CB923,
|
PrevUID = 0x3CB923,
|
||||||
PrevFileName = 0x3C83AB,
|
PrevFileName = 0x3C83AB,
|
||||||
NexUId = 0x3EB923,
|
NexUID = 0x3EB923,
|
||||||
NexFileName = 0x3E83BB,
|
NextFileName = 0x3E83BB,
|
||||||
Title = 0x7BA9,
|
Title = 0x7BA9,
|
||||||
SegmentFamily = 0x4444,
|
SegmentFamily = 0x4444,
|
||||||
ChapterTranslate = 0x6924
|
ChapterTranslate = 0x6924
|
||||||
|
@ -261,10 +261,10 @@ enum SimpleTagIds {
|
||||||
enum TargetsIds {
|
enum TargetsIds {
|
||||||
TargetTypeValue = 0x68ca,
|
TargetTypeValue = 0x68ca,
|
||||||
TargetType = 0x63ca,
|
TargetType = 0x63ca,
|
||||||
TagTrackUId = 0x63c5,
|
TagTrackUID = 0x63c5,
|
||||||
TagEditionUId = 0x63c9,
|
TagEditionUID = 0x63c9,
|
||||||
TagChapterUId = 0x63c4,
|
TagChapterUID = 0x63c4,
|
||||||
TagAttachmentUId = 0x63c6
|
TagAttachmentUID = 0x63c6
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -489,7 +489,51 @@ enum KnownValues {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class MatroskaElementLevel : byte {
|
||||||
|
TopLevel = 0x0,
|
||||||
|
Level1,
|
||||||
|
Level2,
|
||||||
|
Level3,
|
||||||
|
Level4,
|
||||||
|
Level5,
|
||||||
|
Level6,
|
||||||
|
Global = 0xFE,
|
||||||
|
Unknown = 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr bool operator>(MatroskaElementLevel lhs, MatroskaElementLevel rhs)
|
||||||
|
{
|
||||||
|
return static_cast<byte>(lhs) < static_cast<byte>(MatroskaElementLevel::Global)
|
||||||
|
&& static_cast<byte>(rhs) < static_cast<byte>(MatroskaElementLevel::Global)
|
||||||
|
&& static_cast<byte>(lhs) > static_cast<byte>(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator>(byte lhs, MatroskaElementLevel rhs)
|
||||||
|
{
|
||||||
|
return lhs < static_cast<byte>(MatroskaElementLevel::Global)
|
||||||
|
&& static_cast<byte>(rhs) < static_cast<byte>(MatroskaElementLevel::Global)
|
||||||
|
&& static_cast<byte>(lhs) > static_cast<byte>(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator<(MatroskaElementLevel lhs, MatroskaElementLevel rhs)
|
||||||
|
{
|
||||||
|
return static_cast<byte>(lhs) < static_cast<byte>(MatroskaElementLevel::Global)
|
||||||
|
&& static_cast<byte>(rhs) < static_cast<byte>(MatroskaElementLevel::Global)
|
||||||
|
&& static_cast<byte>(lhs) < static_cast<byte>(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator>=(MatroskaElementLevel lhs, MatroskaElementLevel rhs)
|
||||||
|
{
|
||||||
|
return lhs == rhs || lhs > rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator<=(MatroskaElementLevel lhs, MatroskaElementLevel rhs)
|
||||||
|
{
|
||||||
|
return lhs == rhs || lhs < rhs;
|
||||||
|
}
|
||||||
|
|
||||||
TAG_PARSER_EXPORT const char *matroskaIdName(uint32 matroskaId);
|
TAG_PARSER_EXPORT const char *matroskaIdName(uint32 matroskaId);
|
||||||
|
TAG_PARSER_EXPORT MatroskaElementLevel matroskaIdLevel(uint32 matroskaId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,7 @@ uint64 MatroskaSeekInfo::actualSize() const
|
||||||
*
|
*
|
||||||
* \returns Returns an indication whether the actualSize() has changed.
|
* \returns Returns an indication whether the actualSize() has changed.
|
||||||
*/
|
*/
|
||||||
bool MatroskaSeekInfo::push(unsigned int index, EbmlElement::identifierType id, uint64 offset)
|
bool MatroskaSeekInfo::push(unsigned int index, EbmlElement::IdentifierType id, uint64 offset)
|
||||||
{
|
{
|
||||||
unsigned int currentIndex = 0;
|
unsigned int currentIndex = 0;
|
||||||
for(auto &entry : info()) {
|
for(auto &entry : info()) {
|
||||||
|
@ -209,7 +209,7 @@ void MatroskaSeekInfo::clear()
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns a pointer to the first pair with the specified \a offset or nullptr if no such pair could be found.
|
* \brief Returns a pointer to the first pair with the specified \a offset or nullptr if no such pair could be found.
|
||||||
*/
|
*/
|
||||||
std::pair<EbmlElement::identifierType, uint64> *MatroskaSeekInfo::findSeekInfo(std::vector<MatroskaSeekInfo> &seekInfos, uint64 offset)
|
std::pair<EbmlElement::IdentifierType, uint64> *MatroskaSeekInfo::findSeekInfo(std::vector<MatroskaSeekInfo> &seekInfos, uint64 offset)
|
||||||
{
|
{
|
||||||
for(auto &seekInfo : seekInfos) {
|
for(auto &seekInfo : seekInfos) {
|
||||||
for(auto &entry : seekInfo.info()) {
|
for(auto &entry : seekInfo.info()) {
|
||||||
|
|
|
@ -15,25 +15,25 @@ public:
|
||||||
MatroskaSeekInfo();
|
MatroskaSeekInfo();
|
||||||
|
|
||||||
EbmlElement *seekHeadElement() const;
|
EbmlElement *seekHeadElement() const;
|
||||||
const std::vector<std::pair<EbmlElement::identifierType, uint64> > &info() const;
|
const std::vector<std::pair<EbmlElement::IdentifierType, uint64> > &info() const;
|
||||||
std::vector<std::pair<EbmlElement::identifierType, uint64> > &info();
|
std::vector<std::pair<EbmlElement::IdentifierType, uint64> > &info();
|
||||||
void shift(uint64 start, int64 amount);
|
void shift(uint64 start, int64 amount);
|
||||||
void parse(EbmlElement *seekHeadElement);
|
void parse(EbmlElement *seekHeadElement);
|
||||||
void make(std::ostream &stream);
|
void make(std::ostream &stream);
|
||||||
uint64 minSize() const;
|
uint64 minSize() const;
|
||||||
uint64 maxSize() const;
|
uint64 maxSize() const;
|
||||||
uint64 actualSize() const;
|
uint64 actualSize() const;
|
||||||
bool push(unsigned int index, EbmlElement::identifierType id, uint64 offset);
|
bool push(unsigned int index, EbmlElement::IdentifierType id, uint64 offset);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
// these methods seem to be not needed anymore
|
// these methods seem to be not needed anymore
|
||||||
static std::pair<EbmlElement::identifierType, uint64> *findSeekInfo(std::vector<MatroskaSeekInfo> &seekInfos, uint64 offset);
|
static std::pair<EbmlElement::IdentifierType, uint64> *findSeekInfo(std::vector<MatroskaSeekInfo> &seekInfos, uint64 offset);
|
||||||
static bool updateSeekInfo(const std::vector<MatroskaSeekInfo> &oldSeekInfos, std::vector<MatroskaSeekInfo> &newSeekInfos, uint64 oldOffset, uint64 newOffset);
|
static bool updateSeekInfo(const std::vector<MatroskaSeekInfo> &oldSeekInfos, std::vector<MatroskaSeekInfo> &newSeekInfos, uint64 oldOffset, uint64 newOffset);
|
||||||
static bool updateSeekInfo(std::vector<MatroskaSeekInfo> &newSeekInfos, uint64 oldOffset, uint64 newOffset);
|
static bool updateSeekInfo(std::vector<MatroskaSeekInfo> &newSeekInfos, uint64 oldOffset, uint64 newOffset);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EbmlElement *m_seekHeadElement;
|
EbmlElement *m_seekHeadElement;
|
||||||
std::vector<std::pair<EbmlElement::identifierType, uint64> > m_info;
|
std::vector<std::pair<EbmlElement::IdentifierType, uint64> > m_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -55,7 +55,7 @@ inline EbmlElement *MatroskaSeekInfo::seekHeadElement() const
|
||||||
* \brief Returns the seek information gathered when the parse() method was called.
|
* \brief Returns the seek information gathered when the parse() method was called.
|
||||||
* \returns Returns the seek information as pairs of element IDs and the associated offsets (relative to the beginning of the file).
|
* \returns Returns the seek information as pairs of element IDs and the associated offsets (relative to the beginning of the file).
|
||||||
*/
|
*/
|
||||||
inline const std::vector<std::pair<EbmlElement::identifierType, uint64> > &MatroskaSeekInfo::info() const
|
inline const std::vector<std::pair<EbmlElement::IdentifierType, uint64> > &MatroskaSeekInfo::info() const
|
||||||
{
|
{
|
||||||
return m_info;
|
return m_info;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ inline const std::vector<std::pair<EbmlElement::identifierType, uint64> > &Matro
|
||||||
* \brief Returns a mutable version of the seek information gathered when the parse() method was called.
|
* \brief Returns a mutable version of the seek information gathered when the parse() method was called.
|
||||||
* \returns Returns the seek information as pairs of element IDs and the associated offsets (relative to the beginning of the file).
|
* \returns Returns the seek information as pairs of element IDs and the associated offsets (relative to the beginning of the file).
|
||||||
*/
|
*/
|
||||||
inline std::vector<std::pair<EbmlElement::identifierType, uint64> > &MatroskaSeekInfo::info()
|
inline std::vector<std::pair<EbmlElement::IdentifierType, uint64> > &MatroskaSeekInfo::info()
|
||||||
{
|
{
|
||||||
return m_info;
|
return m_info;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Media {
|
||||||
* \brief Implementation of Media::Tag for the Matroska container.
|
* \brief Implementation of Media::Tag for the Matroska container.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::string MatroskaTag::fieldId(KnownField field) const
|
MatroskaTag::IdentifierType MatroskaTag::internallyGetFieldId(KnownField field) const
|
||||||
{
|
{
|
||||||
using namespace MatroskaTagIds;
|
using namespace MatroskaTagIds;
|
||||||
switch(field) {
|
switch(field) {
|
||||||
|
@ -45,7 +45,7 @@ std::string MatroskaTag::fieldId(KnownField field) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KnownField MatroskaTag::knownField(const std::string &id) const
|
KnownField MatroskaTag::internallyGetKnownField(const IdentifierType &id) const
|
||||||
{
|
{
|
||||||
using namespace MatroskaTagIds;
|
using namespace MatroskaTagIds;
|
||||||
static const map<string, KnownField> map({
|
static const map<string, KnownField> map({
|
||||||
|
@ -178,16 +178,16 @@ void MatroskaTag::parseTargets(EbmlElement &targetsElement)
|
||||||
addNotification(NotificationType::Warning, "Targets element contains multiple TargetType elements. Surplus elements will be ignored.", context);
|
addNotification(NotificationType::Warning, "Targets element contains multiple TargetType elements. Surplus elements will be ignored.", context);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MatroskaIds::TagTrackUId:
|
case MatroskaIds::TagTrackUID:
|
||||||
m_target.tracks().emplace_back(child->readUInteger());
|
m_target.tracks().emplace_back(child->readUInteger());
|
||||||
break;
|
break;
|
||||||
case MatroskaIds::TagEditionUId:
|
case MatroskaIds::TagEditionUID:
|
||||||
m_target.editions().emplace_back(child->readUInteger());
|
m_target.editions().emplace_back(child->readUInteger());
|
||||||
break;
|
break;
|
||||||
case MatroskaIds::TagChapterUId:
|
case MatroskaIds::TagChapterUID:
|
||||||
m_target.chapters().emplace_back(child->readUInteger());
|
m_target.chapters().emplace_back(child->readUInteger());
|
||||||
break;
|
break;
|
||||||
case MatroskaIds::TagAttachmentUId:
|
case MatroskaIds::TagAttachmentUID:
|
||||||
m_target.attachments().emplace_back(child->readUInteger());
|
m_target.attachments().emplace_back(child->readUInteger());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -285,7 +285,7 @@ void MatroskaTagMaker::make(ostream &stream) const
|
||||||
}
|
}
|
||||||
// write UIDs
|
// write UIDs
|
||||||
typedef pair<uint16, vector<uint64> > p;
|
typedef pair<uint16, vector<uint64> > p;
|
||||||
for(const auto &pair : initializer_list<p>{p(MatroskaIds::TagTrackUId, t.tracks()), p(MatroskaIds::TagEditionUId, t.editions()), p(MatroskaIds::TagChapterUId, t.chapters()), p(MatroskaIds::TagAttachmentUId, t.attachments())}) {
|
for(const auto &pair : initializer_list<p>{p(MatroskaIds::TagTrackUID, t.tracks()), p(MatroskaIds::TagEditionUID, t.editions()), p(MatroskaIds::TagChapterUID, t.chapters()), p(MatroskaIds::TagAttachmentUID, t.attachments())}) {
|
||||||
if(!pair.second.empty()) {
|
if(!pair.second.empty()) {
|
||||||
BE::getBytes(pair.first, buff);
|
BE::getBytes(pair.first, buff);
|
||||||
for(auto uid : pair.second) {
|
for(auto uid : pair.second) {
|
||||||
|
|
|
@ -47,27 +47,39 @@ inline uint64 MatroskaTagMaker::requiredSize() const
|
||||||
return m_totalSize;
|
return m_totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
class TAG_PARSER_EXPORT MatroskaTag : public FieldMapBasedTag<MatroskaTagField>
|
/*!
|
||||||
|
* \brief Defines traits for the TagField implementation of the MatroskaTag class.
|
||||||
|
*/
|
||||||
|
template <>
|
||||||
|
class TAG_PARSER_EXPORT FieldMapBasedTagTraits<MatroskaTag>
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
typedef MatroskaTagField FieldType;
|
||||||
|
typedef std::less<typename FieldType::IdentifierType> Compare;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TAG_PARSER_EXPORT MatroskaTag : public FieldMapBasedTag<MatroskaTag>
|
||||||
|
{
|
||||||
|
friend class FieldMapBasedTag<MatroskaTag>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MatroskaTag();
|
MatroskaTag();
|
||||||
|
|
||||||
static constexpr TagType tagType = TagType::MatroskaTag;
|
static constexpr TagType tagType = TagType::MatroskaTag;
|
||||||
// FIXME: implement type() and typeName() in FieldMapBasedTag
|
static constexpr const char *tagName = "Matroska tag";
|
||||||
TagType type() const;
|
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
|
||||||
const char *typeName() const;
|
|
||||||
TagTextEncoding proposedTextEncoding() const;
|
|
||||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||||
bool supportsTarget() const;
|
bool supportsTarget() const;
|
||||||
TagTargetLevel targetLevel() const;
|
TagTargetLevel targetLevel() const;
|
||||||
|
|
||||||
std::string fieldId(KnownField field) const;
|
|
||||||
KnownField knownField(const std::string &id) const;
|
|
||||||
|
|
||||||
void parse(EbmlElement &tagElement);
|
void parse(EbmlElement &tagElement);
|
||||||
MatroskaTagMaker prepareMaking();
|
MatroskaTagMaker prepareMaking();
|
||||||
void make(std::ostream &stream);
|
void make(std::ostream &stream);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
IdentifierType internallyGetFieldId(KnownField field) const;
|
||||||
|
KnownField internallyGetKnownField(const IdentifierType &id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseTargets(EbmlElement &targetsElement);
|
void parseTargets(EbmlElement &targetsElement);
|
||||||
};
|
};
|
||||||
|
@ -88,21 +100,6 @@ inline TagTargetLevel MatroskaTag::targetLevel() const
|
||||||
return matroskaTagTargetLevel(m_target.level());
|
return matroskaTagTargetLevel(m_target.level());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline TagType MatroskaTag::type() const
|
|
||||||
{
|
|
||||||
return TagType::MatroskaTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char *MatroskaTag::typeName() const
|
|
||||||
{
|
|
||||||
return "Matroska tag";
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TagTextEncoding MatroskaTag::proposedTextEncoding() const
|
|
||||||
{
|
|
||||||
return TagTextEncoding::Utf8;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool MatroskaTag::canEncodingBeUsed(TagTextEncoding encoding) const
|
inline bool MatroskaTag::canEncodingBeUsed(TagTextEncoding encoding) const
|
||||||
{
|
{
|
||||||
return encoding == TagTextEncoding::Utf8;
|
return encoding == TagTextEncoding::Utf8;
|
||||||
|
|
|
@ -16,21 +16,8 @@ template <>
|
||||||
class TAG_PARSER_EXPORT TagFieldTraits<MatroskaTagField>
|
class TAG_PARSER_EXPORT TagFieldTraits<MatroskaTagField>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*!
|
typedef std::string IdentifierType;
|
||||||
* \brief Fields in a Matroska tag are identified by strings.
|
typedef std::string TypeInfoType;
|
||||||
*/
|
|
||||||
typedef std::string identifierType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The type info is stored using strings.
|
|
||||||
*/
|
|
||||||
typedef std::string typeInfoType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The implementation type is EbmlElement.
|
|
||||||
*/
|
|
||||||
typedef MatroskaTagField implementationType;
|
|
||||||
|
|
||||||
static bool supportsNestedFields();
|
static bool supportsNestedFields();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -673,7 +673,7 @@ void MediaFileInfo::applyChanges()
|
||||||
if(hasId3v2Tag()) {
|
if(hasId3v2Tag()) {
|
||||||
addNotification(NotificationType::Warning, "Assigned ID3v2 tag can't be attached and will be ignored.", context);
|
addNotification(NotificationType::Warning, "Assigned ID3v2 tag can't be attached and will be ignored.", context);
|
||||||
}
|
}
|
||||||
m_container->forwardStatusUpdateCalls(this);
|
m_container->forwardStatus(this);
|
||||||
m_tracksParsingStatus = ParsingStatus::NotParsedYet;
|
m_tracksParsingStatus = ParsingStatus::NotParsedYet;
|
||||||
m_tagsParsingStatus = ParsingStatus::NotParsedYet;
|
m_tagsParsingStatus = ParsingStatus::NotParsedYet;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -27,21 +27,21 @@ namespace Media {
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new top level atom with the specified \a container at the specified \a startOffset.
|
* \brief Constructs a new top level atom with the specified \a container at the specified \a startOffset.
|
||||||
*/
|
*/
|
||||||
Mp4Atom::Mp4Atom(GenericFileElement::containerType &container, uint64 startOffset) :
|
Mp4Atom::Mp4Atom(GenericFileElement::ContainerType &container, uint64 startOffset) :
|
||||||
GenericFileElement<Mp4Atom>(container, startOffset)
|
GenericFileElement<Mp4Atom>(container, startOffset)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new top level atom with the specified \a container at the specified \a startOffset.
|
* \brief Constructs a new top level atom with the specified \a container at the specified \a startOffset.
|
||||||
*/
|
*/
|
||||||
Mp4Atom::Mp4Atom(GenericFileElement::containerType &container, uint64 startOffset, uint64 maxSize) :
|
Mp4Atom::Mp4Atom(GenericFileElement::ContainerType &container, uint64 startOffset, uint64 maxSize) :
|
||||||
GenericFileElement<Mp4Atom>(container, startOffset, maxSize)
|
GenericFileElement<Mp4Atom>(container, startOffset, maxSize)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new sub level atom with the specified \a parent at the specified \a startOffset.
|
* \brief Constructs a new sub level atom with the specified \a parent at the specified \a startOffset.
|
||||||
*/
|
*/
|
||||||
Mp4Atom::Mp4Atom(GenericFileElement::implementationType &parent, uint64 startOffset) :
|
Mp4Atom::Mp4Atom(Mp4Atom &parent, uint64 startOffset) :
|
||||||
GenericFileElement<Mp4Atom>(parent, startOffset)
|
GenericFileElement<Mp4Atom>(parent, startOffset)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
|
@ -25,25 +25,9 @@ template <>
|
||||||
class TAG_PARSER_EXPORT FileElementTraits<Mp4Atom>
|
class TAG_PARSER_EXPORT FileElementTraits<Mp4Atom>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*!
|
typedef Mp4Container ContainerType;
|
||||||
* \brief The container type used to store such elements is Mp4Container.
|
typedef uint32 IdentifierType;
|
||||||
*/
|
typedef uint64 DataSizeType;
|
||||||
typedef Mp4Container containerType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The type used to store atom IDs is an unsigned 32-bit integer.
|
|
||||||
*/
|
|
||||||
typedef uint32 identifierType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The type used to store element sizes is an unsigned 64-bit integer.
|
|
||||||
*/
|
|
||||||
typedef uint64 dataSizeType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The implementation type is Mp4Atom.
|
|
||||||
*/
|
|
||||||
typedef Mp4Atom implementationType;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the minimal atom size which is 8 byte.
|
* \brief Returns the minimal atom size which is 8 byte.
|
||||||
|
@ -59,7 +43,7 @@ class TAG_PARSER_EXPORT Mp4Atom : public GenericFileElement<Mp4Atom>
|
||||||
friend class GenericFileElement<Mp4Atom>;
|
friend class GenericFileElement<Mp4Atom>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Mp4Atom(containerType& container, uint64 startOffset);
|
Mp4Atom(ContainerType &container, uint64 startOffset);
|
||||||
|
|
||||||
std::string idToString() const;
|
std::string idToString() const;
|
||||||
bool isParent() const;
|
bool isParent() const;
|
||||||
|
@ -72,8 +56,8 @@ public:
|
||||||
static void makeHeader(uint64 size, uint32 id, IoUtilities::BinaryWriter &writer);
|
static void makeHeader(uint64 size, uint32 id, IoUtilities::BinaryWriter &writer);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Mp4Atom(containerType& container, uint64 startOffset, uint64 maxSize);
|
Mp4Atom(ContainerType &container, uint64 startOffset, uint64 maxSize);
|
||||||
Mp4Atom(implementationType &parent, uint64 startOffset);
|
Mp4Atom(Mp4Atom &parent, uint64 startOffset);
|
||||||
|
|
||||||
void internalParse();
|
void internalParse();
|
||||||
|
|
||||||
|
@ -86,7 +70,7 @@ private:
|
||||||
*/
|
*/
|
||||||
inline std::string Mp4Atom::idToString() const
|
inline std::string Mp4Atom::idToString() const
|
||||||
{
|
{
|
||||||
auto idString = ConversionUtilities::interpretIntegerAsString<identifierType>(id());
|
auto idString = ConversionUtilities::interpretIntegerAsString<IdentifierType>(id());
|
||||||
for(char &c : idString) {
|
for(char &c : idString) {
|
||||||
if(c < ' ') {
|
if(c < ' ') {
|
||||||
c = '?';
|
c = '?';
|
||||||
|
|
|
@ -685,7 +685,7 @@ calculatePadding:
|
||||||
// update status
|
// update status
|
||||||
updateStatus("Writing atom: " + level0Atom->idToString());
|
updateStatus("Writing atom: " + level0Atom->idToString());
|
||||||
// copy atom entirely and forward status update calls
|
// copy atom entirely and forward status update calls
|
||||||
level0Atom->forwardStatusUpdateCalls(this);
|
level0Atom->forwardStatus(this);
|
||||||
level0Atom->copyEntirely(outputStream);
|
level0Atom->copyEntirely(outputStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,16 +59,16 @@ const TagValue &Mp4Tag::value(KnownField field) const
|
||||||
{
|
{
|
||||||
switch(field) {
|
switch(field) {
|
||||||
case KnownField::Genre: {
|
case KnownField::Genre: {
|
||||||
const TagValue &value = FieldMapBasedTag<fieldType>::value(Mp4TagAtomIds::Genre);
|
const TagValue &value = FieldMapBasedTag<Mp4Tag>::value(Mp4TagAtomIds::Genre);
|
||||||
if(!value.isEmpty()) {
|
if(!value.isEmpty()) {
|
||||||
return value;
|
return value;
|
||||||
} else {
|
} else {
|
||||||
return FieldMapBasedTag<fieldType>::value(Mp4TagAtomIds::PreDefinedGenre);
|
return FieldMapBasedTag<Mp4Tag>::value(Mp4TagAtomIds::PreDefinedGenre);
|
||||||
}
|
}
|
||||||
} case KnownField::EncoderSettings:
|
} case KnownField::EncoderSettings:
|
||||||
return this->value(Mp4TagExtendedMeanIds::iTunes, Mp4TagExtendedNameIds::cdec);
|
return this->value(Mp4TagExtendedMeanIds::iTunes, Mp4TagExtendedNameIds::cdec);
|
||||||
case KnownField::RecordLabel: {
|
case KnownField::RecordLabel: {
|
||||||
const TagValue &value = FieldMapBasedTag<fieldType>::value(Mp4TagAtomIds::RecordLabel);
|
const TagValue &value = FieldMapBasedTag<Mp4Tag>::value(Mp4TagAtomIds::RecordLabel);
|
||||||
if(!value.isEmpty()) {
|
if(!value.isEmpty()) {
|
||||||
return value;
|
return value;
|
||||||
} else {
|
} else {
|
||||||
|
@ -76,13 +76,13 @@ const TagValue &Mp4Tag::value(KnownField field) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return FieldMapBasedTag<fieldType>::value(field);
|
return FieldMapBasedTag<Mp4Tag>::value(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const TagValue *> Mp4Tag::values(KnownField field) const
|
std::vector<const TagValue *> Mp4Tag::values(KnownField field) const
|
||||||
{
|
{
|
||||||
auto values = FieldMapBasedTag<fieldType>::values(field);
|
auto values = FieldMapBasedTag<Mp4Tag>::values(field);
|
||||||
const Mp4ExtendedFieldId extendedId(field);
|
const Mp4ExtendedFieldId extendedId(field);
|
||||||
if(extendedId) {
|
if(extendedId) {
|
||||||
auto range = fields().equal_range(Mp4TagAtomIds::Extended);
|
auto range = fields().equal_range(Mp4TagAtomIds::Extended);
|
||||||
|
@ -119,7 +119,7 @@ const TagValue &Mp4Tag::value(const string mean, const string name) const
|
||||||
return (this->*static_cast<const TagValue &(Mp4Tag::*)(const string &, const string &) const>(&Mp4Tag::value))(mean, name);
|
return (this->*static_cast<const TagValue &(Mp4Tag::*)(const string &, const string &) const>(&Mp4Tag::value))(mean, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Mp4Tag::fieldId(KnownField field) const
|
Mp4Tag::IdentifierType Mp4Tag::internallyGetFieldId(KnownField field) const
|
||||||
{
|
{
|
||||||
using namespace Mp4TagAtomIds;
|
using namespace Mp4TagAtomIds;
|
||||||
switch(field) {
|
switch(field) {
|
||||||
|
@ -146,7 +146,7 @@ uint32 Mp4Tag::fieldId(KnownField field) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KnownField Mp4Tag::knownField(const uint32 &id) const
|
KnownField Mp4Tag::internallyGetKnownField(const IdentifierType &id) const
|
||||||
{
|
{
|
||||||
using namespace Mp4TagAtomIds;
|
using namespace Mp4TagAtomIds;
|
||||||
switch(id) {
|
switch(id) {
|
||||||
|
@ -180,10 +180,10 @@ bool Mp4Tag::setValue(KnownField field, const TagValue &value)
|
||||||
switch(value.type()) {
|
switch(value.type()) {
|
||||||
case TagDataType::StandardGenreIndex:
|
case TagDataType::StandardGenreIndex:
|
||||||
fields().erase(Mp4TagAtomIds::Genre);
|
fields().erase(Mp4TagAtomIds::Genre);
|
||||||
return FieldMapBasedTag<fieldType>::setValue(Mp4TagAtomIds::PreDefinedGenre, value);
|
return FieldMapBasedTag<Mp4Tag>::setValue(Mp4TagAtomIds::PreDefinedGenre, value);
|
||||||
default:
|
default:
|
||||||
fields().erase(Mp4TagAtomIds::PreDefinedGenre);
|
fields().erase(Mp4TagAtomIds::PreDefinedGenre);
|
||||||
return FieldMapBasedTag<fieldType>::setValue(Mp4TagAtomIds::Genre, value);
|
return FieldMapBasedTag<Mp4Tag>::setValue(Mp4TagAtomIds::Genre, value);
|
||||||
}
|
}
|
||||||
case KnownField::EncoderSettings:
|
case KnownField::EncoderSettings:
|
||||||
return setValue(Mp4TagExtendedMeanIds::iTunes, Mp4TagExtendedNameIds::cdec, value);
|
return setValue(Mp4TagExtendedMeanIds::iTunes, Mp4TagExtendedNameIds::cdec, value);
|
||||||
|
@ -193,7 +193,7 @@ bool Mp4Tag::setValue(KnownField field, const TagValue &value)
|
||||||
}
|
}
|
||||||
FALLTHROUGH;
|
FALLTHROUGH;
|
||||||
default:
|
default:
|
||||||
return FieldMapBasedTag<fieldType>::setValue(field, value);
|
return FieldMapBasedTag<Mp4Tag>::setValue(field, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ bool Mp4Tag::setValues(KnownField field, const std::vector<TagValue> &values)
|
||||||
range.first->second.setValue(TagValue());
|
range.first->second.setValue(TagValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FieldMapBasedTag<fieldType>::setValues(field, values);
|
return FieldMapBasedTag<Mp4Tag>::setValues(field, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -244,7 +244,7 @@ bool Mp4Tag::setValue(const char *mean, const char *name, const TagValue &value)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fields().insert(make_pair(Mp4TagAtomIds::Extended, fieldType(mean, name, value)));
|
fields().insert(make_pair(Mp4TagAtomIds::Extended, FieldType(mean, name, value)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,10 +260,10 @@ bool Mp4Tag::hasField(KnownField field) const
|
||||||
{
|
{
|
||||||
switch(field) {
|
switch(field) {
|
||||||
case KnownField::Genre:
|
case KnownField::Genre:
|
||||||
return FieldMapBasedTag<fieldType>::hasField(Mp4TagAtomIds::PreDefinedGenre)
|
return FieldMapBasedTag<Mp4Tag>::hasField(Mp4TagAtomIds::PreDefinedGenre)
|
||||||
|| FieldMapBasedTag<fieldType>::hasField(Mp4TagAtomIds::Genre);
|
|| FieldMapBasedTag<Mp4Tag>::hasField(Mp4TagAtomIds::Genre);
|
||||||
default:
|
default:
|
||||||
return FieldMapBasedTag<fieldType>::hasField(field);
|
return FieldMapBasedTag<Mp4Tag>::hasField(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ void Mp4Tag::parse(Mp4Atom &metaAtom)
|
||||||
child->parse();
|
child->parse();
|
||||||
tagField.invalidateNotifications();
|
tagField.invalidateNotifications();
|
||||||
tagField.reparse(*child);
|
tagField.reparse(*child);
|
||||||
fields().insert(pair<fieldType::identifierType, fieldType>(child->id(), tagField));
|
fields().emplace(child->id(), tagField);
|
||||||
} catch(const Failure &) {
|
} catch(const Failure &) {
|
||||||
}
|
}
|
||||||
addNotifications(context, *child);
|
addNotifications(context, *child);
|
||||||
|
|
54
mp4/mp4tag.h
54
mp4/mp4tag.h
|
@ -87,44 +87,59 @@ inline uint64 Mp4TagMaker::requiredSize() const
|
||||||
return m_metaSize;
|
return m_metaSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
class TAG_PARSER_EXPORT Mp4Tag : public FieldMapBasedTag<Mp4TagField>
|
/*!
|
||||||
|
* \brief Defines traits for the TagField implementation of the Mp4Tag class.
|
||||||
|
*/
|
||||||
|
template <>
|
||||||
|
class TAG_PARSER_EXPORT FieldMapBasedTagTraits<Mp4Tag>
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
typedef Mp4TagField FieldType;
|
||||||
|
typedef std::less<typename FieldType::IdentifierType> Compare;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TAG_PARSER_EXPORT Mp4Tag : public FieldMapBasedTag<Mp4Tag>
|
||||||
|
{
|
||||||
|
friend class FieldMapBasedTag<Mp4Tag>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Mp4Tag();
|
Mp4Tag();
|
||||||
|
|
||||||
static constexpr TagType tagType = TagType::Mp4Tag;
|
static constexpr TagType tagType = TagType::Mp4Tag;
|
||||||
TagType type() const;
|
static constexpr const char *tagName = "MP4/iTunes tag";
|
||||||
const char *typeName() const;
|
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
|
||||||
TagTextEncoding proposedTextEncoding() const;
|
|
||||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||||
|
|
||||||
uint32 fieldId(KnownField field) const;
|
|
||||||
KnownField knownField(const uint32 &id) const;
|
|
||||||
bool supportsField(KnownField field) const;
|
bool supportsField(KnownField field) const;
|
||||||
using FieldMapBasedTag<Mp4TagField>::value;
|
using FieldMapBasedTag<Mp4Tag>::value;
|
||||||
const TagValue &value(KnownField value) const;
|
const TagValue &value(KnownField value) const;
|
||||||
using FieldMapBasedTag<Mp4TagField>::values;
|
using FieldMapBasedTag<Mp4Tag>::values;
|
||||||
std::vector<const TagValue *> values(KnownField field) const;
|
std::vector<const TagValue *> values(KnownField field) const;
|
||||||
#ifdef LEGACY_API
|
#ifdef LEGACY_API
|
||||||
const TagValue &value(const std::string mean, const std::string name) const;
|
const TagValue &value(const std::string mean, const std::string name) const;
|
||||||
#endif
|
#endif
|
||||||
const TagValue &value(const std::string &mean, const std::string &name) const;
|
const TagValue &value(const std::string &mean, const std::string &name) const;
|
||||||
const TagValue &value(const char *mean, const char *name) const;
|
const TagValue &value(const char *mean, const char *name) const;
|
||||||
using FieldMapBasedTag<Mp4TagField>::setValue;
|
using FieldMapBasedTag<Mp4Tag>::setValue;
|
||||||
bool setValue(KnownField field, const TagValue &value);
|
bool setValue(KnownField field, const TagValue &value);
|
||||||
using FieldMapBasedTag<Mp4TagField>::setValues;
|
using FieldMapBasedTag<Mp4Tag>::setValues;
|
||||||
bool setValues(KnownField field, const std::vector<TagValue> &values);
|
bool setValues(KnownField field, const std::vector<TagValue> &values);
|
||||||
#ifdef LEGACY_API
|
#ifdef LEGACY_API
|
||||||
bool setValue(const std::string mean, const std::string name, const TagValue &value);
|
bool setValue(const std::string mean, const std::string name, const TagValue &value);
|
||||||
#endif
|
#endif
|
||||||
bool setValue(const std::string &mean, const std::string &name, const TagValue &value);
|
bool setValue(const std::string &mean, const std::string &name, const TagValue &value);
|
||||||
bool setValue(const char *mean, const char *name, const TagValue &value);
|
bool setValue(const char *mean, const char *name, const TagValue &value);
|
||||||
using FieldMapBasedTag<Mp4TagField>::hasField;
|
using FieldMapBasedTag<Mp4Tag>::hasField;
|
||||||
bool hasField(KnownField value) const;
|
bool hasField(KnownField value) const;
|
||||||
|
|
||||||
void parse(Mp4Atom &metaAtom);
|
void parse(Mp4Atom &metaAtom);
|
||||||
Mp4TagMaker prepareMaking();
|
Mp4TagMaker prepareMaking();
|
||||||
void make(std::ostream &stream);
|
void make(std::ostream &stream);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
IdentifierType internallyGetFieldId(KnownField field) const;
|
||||||
|
KnownField internallyGetKnownField(const IdentifierType &id) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -133,28 +148,13 @@ public:
|
||||||
inline Mp4Tag::Mp4Tag()
|
inline Mp4Tag::Mp4Tag()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline TagType Mp4Tag::type() const
|
|
||||||
{
|
|
||||||
return TagType::Mp4Tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char *Mp4Tag::typeName() const
|
|
||||||
{
|
|
||||||
return "MP4/iTunes tag";
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TagTextEncoding Mp4Tag::proposedTextEncoding() const
|
|
||||||
{
|
|
||||||
return TagTextEncoding::Utf8;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool Mp4Tag::supportsField(KnownField field) const
|
inline bool Mp4Tag::supportsField(KnownField field) const
|
||||||
{
|
{
|
||||||
switch(field) {
|
switch(field) {
|
||||||
case KnownField::EncoderSettings:
|
case KnownField::EncoderSettings:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return FieldMapBasedTag<Mp4TagField>::supportsField(field);
|
return FieldMapBasedTag<Mp4Tag>::supportsField(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ Mp4TagField::Mp4TagField() :
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new Mp4TagField with the specified \a id and \a value.
|
* \brief Constructs a new Mp4TagField with the specified \a id and \a value.
|
||||||
*/
|
*/
|
||||||
Mp4TagField::Mp4TagField(identifierType id, const TagValue &value) :
|
Mp4TagField::Mp4TagField(IdentifierType id, const TagValue &value) :
|
||||||
TagField<Mp4TagField>(id, value),
|
TagField<Mp4TagField>(id, value),
|
||||||
m_parsedRawDataType(RawDataType::Reserved),
|
m_parsedRawDataType(RawDataType::Reserved),
|
||||||
m_countryIndicator(0),
|
m_countryIndicator(0),
|
||||||
|
|
|
@ -57,20 +57,8 @@ template <>
|
||||||
class TAG_PARSER_EXPORT TagFieldTraits<Mp4TagField>
|
class TAG_PARSER_EXPORT TagFieldTraits<Mp4TagField>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*!
|
typedef uint32 IdentifierType;
|
||||||
* \brief Fields in a iTunes-style MP4 tag are identified by 32-bit unsigned integers.
|
typedef uint32 TypeInfoType;
|
||||||
*/
|
|
||||||
typedef uint32 identifierType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The type info is stored using 32-bit unsigned integers.
|
|
||||||
*/
|
|
||||||
typedef uint32 typeInfoType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The implementation type is Mp4TagField.
|
|
||||||
*/
|
|
||||||
typedef Mp4TagField implementationType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Mp4Atom;
|
class Mp4Atom;
|
||||||
|
@ -117,7 +105,7 @@ class TAG_PARSER_EXPORT Mp4TagField : public TagField<Mp4TagField>, public Statu
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Mp4TagField();
|
Mp4TagField();
|
||||||
Mp4TagField(identifierType id, const TagValue &value);
|
Mp4TagField(IdentifierType id, const TagValue &value);
|
||||||
Mp4TagField(const std::string &mean, const std::string &name, const TagValue &value);
|
Mp4TagField(const std::string &mean, const std::string &name, const TagValue &value);
|
||||||
|
|
||||||
void reparse(Mp4Atom &ilstChild);
|
void reparse(Mp4Atom &ilstChild);
|
||||||
|
@ -136,8 +124,8 @@ public:
|
||||||
std::vector<uint32> expectedRawDataTypes() const;
|
std::vector<uint32> expectedRawDataTypes() const;
|
||||||
uint32 appropriateRawDataType() const;
|
uint32 appropriateRawDataType() const;
|
||||||
|
|
||||||
static identifierType fieldIdFromString(const char *idString, std::size_t idStringSize = std::string::npos);
|
static IdentifierType fieldIdFromString(const char *idString, std::size_t idStringSize = std::string::npos);
|
||||||
static std::string fieldIdToString(identifierType id);
|
static std::string fieldIdToString(IdentifierType id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void cleared();
|
void cleared();
|
||||||
|
@ -227,7 +215,7 @@ inline bool Mp4TagField::supportsNestedFields() const
|
||||||
* \remarks The specified \a idString is assumed to be UTF-8 encoded. In order to get the ©-sign
|
* \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.
|
* correctly, it is converted to Latin-1.
|
||||||
*/
|
*/
|
||||||
inline Mp4TagField::identifierType Mp4TagField::fieldIdFromString(const char *idString, std::size_t idStringSize)
|
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));
|
const auto latin1 = ConversionUtilities::convertUtf8ToLatin1(idString, idStringSize != std::string::npos ? idStringSize : std::strlen(idString));
|
||||||
switch(latin1.second) {
|
switch(latin1.second) {
|
||||||
|
@ -243,7 +231,7 @@ inline Mp4TagField::identifierType Mp4TagField::fieldIdFromString(const char *id
|
||||||
* \remarks The specified \a id is considered Latin-1 encoded. In order to get the ©-sign
|
* \remarks The specified \a id is considered Latin-1 encoded. In order to get the ©-sign
|
||||||
* correctly, it is converted to UTF-8.
|
* correctly, it is converted to UTF-8.
|
||||||
*/
|
*/
|
||||||
inline std::string Mp4TagField::fieldIdToString(Mp4TagField::identifierType id)
|
inline std::string Mp4TagField::fieldIdToString(Mp4TagField::IdentifierType id)
|
||||||
{
|
{
|
||||||
const auto utf8 = ConversionUtilities::convertLatin1ToUtf8(ConversionUtilities::interpretIntegerAsString<uint32>(id).data(), 4);
|
const auto utf8 = ConversionUtilities::convertLatin1ToUtf8(ConversionUtilities::interpretIntegerAsString<uint32>(id).data(), 4);
|
||||||
return std::string(utf8.first.get(), utf8.second);
|
return std::string(utf8.first.get(), utf8.second);
|
||||||
|
|
|
@ -20,14 +20,14 @@ namespace Media {
|
||||||
* \brief Constructs a new top level descriptor with the specified \a container at the specified \a startOffset
|
* \brief Constructs a new top level descriptor with the specified \a container at the specified \a startOffset
|
||||||
* and with the specified \a maxSize.
|
* and with the specified \a maxSize.
|
||||||
*/
|
*/
|
||||||
Mpeg4Descriptor::Mpeg4Descriptor(containerType &container, uint64 startOffset, uint64 maxSize) :
|
Mpeg4Descriptor::Mpeg4Descriptor(ContainerType &container, uint64 startOffset, uint64 maxSize) :
|
||||||
GenericFileElement<Mpeg4Descriptor>(container, startOffset, maxSize)
|
GenericFileElement<Mpeg4Descriptor>(container, startOffset, maxSize)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new sub level descriptor with the specified \a parent at the specified \a startOffset.
|
* \brief Constructs a new sub level descriptor with the specified \a parent at the specified \a startOffset.
|
||||||
*/
|
*/
|
||||||
Mpeg4Descriptor::Mpeg4Descriptor(implementationType &parent, uint64 startOffset) :
|
Mpeg4Descriptor::Mpeg4Descriptor(Mpeg4Descriptor &parent, uint64 startOffset) :
|
||||||
GenericFileElement<Mpeg4Descriptor>(parent, startOffset)
|
GenericFileElement<Mpeg4Descriptor>(parent, startOffset)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -75,12 +75,12 @@ void Mpeg4Descriptor::internalParse()
|
||||||
m_dataSize = maxTotalSize(); // using max size instead
|
m_dataSize = maxTotalSize(); // using max size instead
|
||||||
}
|
}
|
||||||
m_firstChild.reset();
|
m_firstChild.reset();
|
||||||
implementationType *sibling = nullptr;
|
Mpeg4Descriptor *sibling = nullptr;
|
||||||
if(totalSize() < maxTotalSize()) {
|
if(totalSize() < maxTotalSize()) {
|
||||||
if(parent()) {
|
if(parent()) {
|
||||||
sibling = new implementationType(*(parent()), startOffset() + totalSize());
|
sibling = new Mpeg4Descriptor(*(parent()), startOffset() + totalSize());
|
||||||
} else {
|
} else {
|
||||||
sibling = new implementationType(container(), startOffset() + totalSize(), maxTotalSize() - totalSize());
|
sibling = new Mpeg4Descriptor(container(), startOffset() + totalSize(), maxTotalSize() - totalSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_nextSibling.reset(sibling);
|
m_nextSibling.reset(sibling);
|
||||||
|
|
|
@ -17,25 +17,9 @@ template <>
|
||||||
class TAG_PARSER_EXPORT FileElementTraits<Mpeg4Descriptor>
|
class TAG_PARSER_EXPORT FileElementTraits<Mpeg4Descriptor>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*!
|
typedef Mp4Container ContainerType;
|
||||||
* \brief The container type used to store such elements is Mp4Container.
|
typedef byte IdentifierType;
|
||||||
*/
|
typedef uint32 DataSizeType;
|
||||||
typedef Mp4Container containerType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The type used to store atom IDs is an unsigned 32-bit integer.
|
|
||||||
*/
|
|
||||||
typedef byte identifierType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The type used to store element sizes is an unsigned 32-bit integer.
|
|
||||||
*/
|
|
||||||
typedef uint32 dataSizeType;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief The implementation type is Mp4Atom.
|
|
||||||
*/
|
|
||||||
typedef Mpeg4Descriptor implementationType;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the minimal descriptor size which is 2 byte.
|
* \brief Returns the minimal descriptor size which is 2 byte.
|
||||||
|
@ -51,7 +35,7 @@ class TAG_PARSER_EXPORT Mpeg4Descriptor : public GenericFileElement<Mpeg4Descrip
|
||||||
friend class GenericFileElement<Mpeg4Descriptor>;
|
friend class GenericFileElement<Mpeg4Descriptor>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Mpeg4Descriptor(containerType& container, uint64 startOffset, uint64 maxSize);
|
Mpeg4Descriptor(ContainerType &container, uint64 startOffset, uint64 maxSize);
|
||||||
|
|
||||||
std::string idToString() const;
|
std::string idToString() const;
|
||||||
bool isParent() const;
|
bool isParent() const;
|
||||||
|
@ -59,7 +43,7 @@ public:
|
||||||
uint64 firstChildOffset() const;
|
uint64 firstChildOffset() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Mpeg4Descriptor(implementationType &parent, uint64 startOffset);
|
Mpeg4Descriptor(Mpeg4Descriptor &parent, uint64 startOffset);
|
||||||
|
|
||||||
void internalParse();
|
void internalParse();
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,10 @@ size_t StatusProvider::registerCallback(CallbackFunction callback)
|
||||||
*/
|
*/
|
||||||
void StatusProvider::addNotification(const Notification ¬ification)
|
void StatusProvider::addNotification(const Notification ¬ification)
|
||||||
{
|
{
|
||||||
|
if(m_forward) {
|
||||||
|
m_forward->addNotification(notification);
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_notifications.push_back(notification);
|
m_notifications.push_back(notification);
|
||||||
m_worstNotificationType |= notification.type();
|
m_worstNotificationType |= notification.type();
|
||||||
invokeCallbacks();
|
invokeCallbacks();
|
||||||
|
@ -63,6 +67,10 @@ void StatusProvider::addNotification(const Notification ¬ification)
|
||||||
*/
|
*/
|
||||||
void StatusProvider::addNotification(NotificationType type, const string &message, const string &context)
|
void StatusProvider::addNotification(NotificationType type, const string &message, const string &context)
|
||||||
{
|
{
|
||||||
|
if(m_forward) {
|
||||||
|
m_forward->addNotification(type, message, context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_notifications.emplace_back(type, message, context);
|
m_notifications.emplace_back(type, message, context);
|
||||||
m_worstNotificationType |= type;
|
m_worstNotificationType |= type;
|
||||||
invokeCallbacks();
|
invokeCallbacks();
|
||||||
|
@ -72,15 +80,19 @@ void StatusProvider::addNotification(NotificationType type, const string &messag
|
||||||
* \brief This method is meant to be called by the derived class to add all notifications \a from another
|
* \brief This method is meant to be called by the derived class to add all notifications \a from another
|
||||||
* StatusProvider instance.
|
* StatusProvider instance.
|
||||||
*/
|
*/
|
||||||
void StatusProvider::addNotifications(const StatusProvider &from)
|
/*void StatusProvider::addNotifications(const StatusProvider &from)
|
||||||
{
|
{
|
||||||
|
if(m_forward) {
|
||||||
|
m_forward->addNotifications(from);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(&from == this) {
|
if(&from == this) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_notifications.insert(m_notifications.end(), from.m_notifications.cbegin(), from.m_notifications.cend());
|
m_notifications.insert(m_notifications.end(), from.m_notifications.cbegin(), from.m_notifications.cend());
|
||||||
m_worstNotificationType |= from.worstNotificationType();
|
m_worstNotificationType |= from.worstNotificationType();
|
||||||
invokeCallbacks();
|
invokeCallbacks();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief This method is meant to be called by the derived class to add all notifications \a from another
|
* \brief This method is meant to be called by the derived class to add all notifications \a from another
|
||||||
|
@ -88,21 +100,29 @@ void StatusProvider::addNotifications(const StatusProvider &from)
|
||||||
*
|
*
|
||||||
* The specified \a higherContext is concatenated with the original context string.
|
* The specified \a higherContext is concatenated with the original context string.
|
||||||
*/
|
*/
|
||||||
void StatusProvider::addNotifications(const string &higherContext, const StatusProvider &from)
|
/*void StatusProvider::addNotifications(const string &higherContext, const StatusProvider &from)
|
||||||
{
|
{
|
||||||
|
if(m_forward) {
|
||||||
|
m_forward->addNotifications(higherContext, from);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(&from == this) {
|
if(&from == this) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(const auto ¬ification : from.m_notifications) {
|
for(const auto ¬ification : from.m_notifications) {
|
||||||
addNotification(notification.type(), notification.message(), higherContext % ',' % ' ' + notification.context());
|
addNotification(notification.type(), notification.message(), higherContext % ',' % ' ' + notification.context());
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief This method is meant to be called by the derived class to add the specified \a notifications.
|
* \brief This method is meant to be called by the derived class to add the specified \a notifications.
|
||||||
*/
|
*/
|
||||||
void StatusProvider::addNotifications(const NotificationList ¬ifications)
|
/*void StatusProvider::addNotifications(const NotificationList ¬ifications)
|
||||||
{
|
{
|
||||||
|
if(m_forward) {
|
||||||
|
m_forward->addNotifications(notifications);
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_notifications.insert(m_notifications.end(), notifications.cbegin(), notifications.cend());
|
m_notifications.insert(m_notifications.end(), notifications.cbegin(), notifications.cend());
|
||||||
if(m_worstNotificationType != Notification::worstNotificationType()) {
|
if(m_worstNotificationType != Notification::worstNotificationType()) {
|
||||||
for(const Notification ¬ification : notifications) {
|
for(const Notification ¬ification : notifications) {
|
||||||
|
@ -112,6 +132,7 @@ void StatusProvider::addNotifications(const NotificationList ¬ifications)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invokeCallbacks();
|
invokeCallbacks();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ public:
|
||||||
size_t registerCallback(CallbackFunction callback);
|
size_t registerCallback(CallbackFunction callback);
|
||||||
void unregisterCallback(size_t id);
|
void unregisterCallback(size_t id);
|
||||||
void unregisterAllCallbacks();
|
void unregisterAllCallbacks();
|
||||||
void forwardStatusUpdateCalls(StatusProvider *other = nullptr);
|
void forwardStatus(StatusProvider *other = nullptr);
|
||||||
inline StatusProvider *usedProvider();
|
StatusProvider *usedProvider();
|
||||||
void tryToAbort();
|
void tryToAbort();
|
||||||
bool isAborted() const;
|
bool isAborted() const;
|
||||||
void invalidateStatus();
|
void invalidateStatus();
|
||||||
|
@ -40,25 +40,25 @@ public:
|
||||||
void updatePercentage(double percentage);
|
void updatePercentage(double percentage);
|
||||||
void addNotification(const Notification ¬ification);
|
void addNotification(const Notification ¬ification);
|
||||||
void addNotification(NotificationType type, const std::string &message, const std::string &context);
|
void addNotification(NotificationType type, const std::string &message, const std::string &context);
|
||||||
void addNotifications(const StatusProvider &from);
|
//void addNotifications(const StatusProvider &from);
|
||||||
void addNotifications(const std::string &higherContext, const StatusProvider &from);
|
//void addNotifications(const std::string &higherContext, const StatusProvider &from);
|
||||||
void addNotifications(const NotificationList ¬ifications);
|
//void addNotifications(const NotificationList ¬ifications);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StatusProvider();
|
StatusProvider();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void invokeCallbacks();
|
void invokeCallbacks();
|
||||||
inline void updateWorstNotificationType(NotificationType notificationType);
|
void updateWorstNotificationType(NotificationType notificationType);
|
||||||
inline void transferNotifications(StatusProvider &from);
|
//void transferNotifications(StatusProvider &from);
|
||||||
|
|
||||||
NotificationList m_notifications;
|
StatusProvider *m_forward;
|
||||||
NotificationType m_worstNotificationType;
|
|
||||||
std::string m_status;
|
std::string m_status;
|
||||||
double m_percentage;
|
double m_percentage;
|
||||||
CallbackVector m_callbacks;
|
CallbackVector m_callbacks;
|
||||||
|
NotificationList m_notifications;
|
||||||
|
NotificationType m_worstNotificationType;
|
||||||
bool m_abort;
|
bool m_abort;
|
||||||
StatusProvider *m_forward;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -66,6 +66,10 @@ private:
|
||||||
*/
|
*/
|
||||||
inline void StatusProvider::updateStatus(const std::string &status)
|
inline void StatusProvider::updateStatus(const std::string &status)
|
||||||
{
|
{
|
||||||
|
if(m_forward) {
|
||||||
|
m_forward->updateStatus(status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_status = status;
|
m_status = status;
|
||||||
invokeCallbacks();
|
invokeCallbacks();
|
||||||
}
|
}
|
||||||
|
@ -77,6 +81,10 @@ inline void StatusProvider::updateStatus(const std::string &status)
|
||||||
*/
|
*/
|
||||||
inline void StatusProvider::updateStatus(const std::string &status, double percentage)
|
inline void StatusProvider::updateStatus(const std::string &status, double percentage)
|
||||||
{
|
{
|
||||||
|
if(m_forward) {
|
||||||
|
m_forward->updateStatus(status, percentage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_status = status;
|
m_status = status;
|
||||||
m_percentage = percentage;
|
m_percentage = percentage;
|
||||||
invokeCallbacks();
|
invokeCallbacks();
|
||||||
|
@ -89,6 +97,10 @@ inline void StatusProvider::updateStatus(const std::string &status, double perce
|
||||||
*/
|
*/
|
||||||
inline void StatusProvider::updatePercentage(double percentage)
|
inline void StatusProvider::updatePercentage(double percentage)
|
||||||
{
|
{
|
||||||
|
if(m_forward) {
|
||||||
|
m_forward->updatePercentage(percentage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_percentage = percentage;
|
m_percentage = percentage;
|
||||||
invokeCallbacks();
|
invokeCallbacks();
|
||||||
}
|
}
|
||||||
|
@ -96,7 +108,7 @@ inline void StatusProvider::updatePercentage(double percentage)
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the provider which callback functions will be called when the status or the percentage is updated.
|
* \brief Returns the provider which callback functions will be called when the status or the percentage is updated.
|
||||||
*
|
*
|
||||||
* The default is the current instance. This can be changed using the forwardStatusUpdateCalls() method.
|
* The default is the current instance. This can be changed using the forwardStatus() method.
|
||||||
*/
|
*/
|
||||||
inline StatusProvider *StatusProvider::usedProvider()
|
inline StatusProvider *StatusProvider::usedProvider()
|
||||||
{
|
{
|
||||||
|
@ -160,7 +172,7 @@ inline double StatusProvider::currentPercentage() const
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns an indication whether the current operation should be aborted.
|
* \brief Returns an indication whether the current operation should be aborted.
|
||||||
*
|
*
|
||||||
* This can be tested when implementing an operation that should be able to be
|
* This flag can be tested when implementing an operation that should be able to be
|
||||||
* aborted.
|
* aborted.
|
||||||
*/
|
*/
|
||||||
inline bool StatusProvider::isAborted() const
|
inline bool StatusProvider::isAborted() const
|
||||||
|
@ -192,26 +204,30 @@ inline void StatusProvider::unregisterAllCallbacks()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Forwards all status updates calls to the specified \a statusProvider.
|
* \brief Forwards all status updates calls and notifications to the specified \a statusProvider.
|
||||||
*
|
*
|
||||||
* Not the callback methods associated to the current instance will be called
|
* This basically forwards status information updates and notifications to the specified instance.
|
||||||
* to inform about status updates. Instead the callback methods associated to
|
|
||||||
* the specified instance will be called.
|
|
||||||
*
|
*
|
||||||
* The current instance is still the sender.
|
* \remarks
|
||||||
*
|
* - Any notifications will *not* be added to the current instance anymore. Instead the
|
||||||
* The current instance is considered as abortet if the specified provider is
|
* notifications will be added to the specified instance.
|
||||||
* abortet even if tryToAbort() has not been called.
|
* - The callback methods assigned to the current instance will *not* be called
|
||||||
*
|
* to inform about status updates anymore. Instead the callback methods associated to
|
||||||
* The current instance will return the status and percentage of the specified
|
* the specified instance will be called.
|
||||||
* provider if it provides no own status or percentage.
|
* - The current instance is still passed as the sender when invoking callback methods.
|
||||||
*
|
* - The current instance is also considered as aborted if the specified provider is
|
||||||
* Provide nullptr to revert to the default behaviour.
|
* aborted - even if tryToAbort() has not been called on the current instance.
|
||||||
*
|
* - The current instance will return the status and percentage of the specified
|
||||||
* \remarks Leads to endless recursion if \a statusProvider forwards (indirectly
|
* provider if it provides no own status or percentage.
|
||||||
* or directly) to the current instance.
|
* - Provide nullptr to revert to the default behaviour.
|
||||||
|
* - The methods invalidateStatus() and invalidateNotifications() are *not* forwarded.
|
||||||
|
* - The methods updateStatus() and updatePercentage() are *not* forwarded.
|
||||||
|
* - The method transferNotifications() is *not* forwarded.
|
||||||
|
* - Leads to endless recursion if \a statusProvider forwards (indirectly
|
||||||
|
* or directly) to the current instance. (So better prevent it.)
|
||||||
|
* - Set \a other to nullptr to restore the usual behaviour.
|
||||||
*/
|
*/
|
||||||
inline void StatusProvider::forwardStatusUpdateCalls(StatusProvider *other)
|
inline void StatusProvider::forwardStatus(StatusProvider *other)
|
||||||
{
|
{
|
||||||
m_forward = other;
|
m_forward = other;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +288,11 @@ inline void StatusProvider::invokeCallbacks()
|
||||||
*/
|
*/
|
||||||
inline void StatusProvider::updateWorstNotificationType(NotificationType notificationType)
|
inline void StatusProvider::updateWorstNotificationType(NotificationType notificationType)
|
||||||
{
|
{
|
||||||
if(static_cast<int>(m_worstNotificationType) < static_cast<int>(notificationType)) {
|
if(m_forward) {
|
||||||
|
m_forward->updateWorstNotificationType(notificationType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(m_worstNotificationType < notificationType) {
|
||||||
m_worstNotificationType = notificationType;
|
m_worstNotificationType = notificationType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,12 +302,14 @@ inline void StatusProvider::updateWorstNotificationType(NotificationType notific
|
||||||
* \remarks In constrast to the similar addNotifications() overload, this method does not copy the notifications. Instead
|
* \remarks In constrast to the similar addNotifications() overload, this method does not copy the notifications. Instead
|
||||||
* the notifications are transfered. It also doesn't check whether \a from is the current instance and doesn't
|
* the notifications are transfered. It also doesn't check whether \a from is the current instance and doesn't
|
||||||
* invoke callbacks.
|
* invoke callbacks.
|
||||||
|
* \deprecated This method should likely be removed after the status provider rework.
|
||||||
*/
|
*/
|
||||||
void StatusProvider::transferNotifications(StatusProvider &from)
|
/*inline void StatusProvider::transferNotifications(StatusProvider &from)
|
||||||
{
|
{
|
||||||
m_notifications.splice(m_notifications.end(), from.m_notifications);
|
m_notifications.splice(m_notifications.end(), from.m_notifications);
|
||||||
m_worstNotificationType |= from.worstNotificationType();
|
m_worstNotificationType |= from.worstNotificationType();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,8 +152,7 @@ void OverallTests::checkMkvTestfile3()
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Checks "matroska_wave1/test4.mkv".
|
* \brief Checks "matroska_wave1/test4.mkv".
|
||||||
* \remarks This file is using the EBML feature that allows Master elements to have no known size. Handling
|
* \remarks This file is using the EBML feature that allows Master elements to have no known size.
|
||||||
* such files is not supported yet.
|
|
||||||
*/
|
*/
|
||||||
void OverallTests::checkMkvTestfile4()
|
void OverallTests::checkMkvTestfile4()
|
||||||
{
|
{
|
||||||
|
|
|
@ -156,7 +156,7 @@ void UtilitiesTests::testStatusProvider()
|
||||||
|
|
||||||
// forwarding
|
// forwarding
|
||||||
TestStatusProvider forwardReceiver;
|
TestStatusProvider forwardReceiver;
|
||||||
status.forwardStatusUpdateCalls(&forwardReceiver);
|
status.forwardStatus(&forwardReceiver);
|
||||||
statusUpdateReceived = false;
|
statusUpdateReceived = false;
|
||||||
forwardReceiver.registerCallback([&status, &statusUpdateReceived] (StatusProvider &sender) {
|
forwardReceiver.registerCallback([&status, &statusUpdateReceived] (StatusProvider &sender) {
|
||||||
CPPUNIT_ASSERT(&status == &sender);
|
CPPUNIT_ASSERT(&status == &sender);
|
||||||
|
|
|
@ -29,7 +29,7 @@ const TagValue &VorbisComment::value(KnownField field) const
|
||||||
case KnownField::Vendor:
|
case KnownField::Vendor:
|
||||||
return vendor();
|
return vendor();
|
||||||
default:
|
default:
|
||||||
return FieldMapBasedTag<VorbisCommentField, CaseInsensitiveStringComparer>::value(field);
|
return FieldMapBasedTag<VorbisComment>::value(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,11 +40,11 @@ bool VorbisComment::setValue(KnownField field, const TagValue &value)
|
||||||
setVendor(value);
|
setVendor(value);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return FieldMapBasedTag<VorbisCommentField, CaseInsensitiveStringComparer>::setValue(field, value);
|
return FieldMapBasedTag<VorbisComment>::setValue(field, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string VorbisComment::fieldId(KnownField field) const
|
VorbisComment::IdentifierType VorbisComment::internallyGetFieldId(KnownField field) const
|
||||||
{
|
{
|
||||||
using namespace VorbisCommentIds;
|
using namespace VorbisCommentIds;
|
||||||
switch(field) {
|
switch(field) {
|
||||||
|
@ -70,7 +70,7 @@ string VorbisComment::fieldId(KnownField field) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KnownField VorbisComment::knownField(const string &id) const
|
KnownField VorbisComment::internallyGetKnownField(const IdentifierType &id) const
|
||||||
{
|
{
|
||||||
using namespace VorbisCommentIds;
|
using namespace VorbisCommentIds;
|
||||||
static const map<string, KnownField> fieldMap({
|
static const map<string, KnownField> fieldMap({
|
||||||
|
@ -145,7 +145,7 @@ void VorbisComment::internalParse(StreamType &stream, uint64 maxSize, VorbisComm
|
||||||
// read fields
|
// read fields
|
||||||
try {
|
try {
|
||||||
field.parse(stream, maxSize);
|
field.parse(stream, maxSize);
|
||||||
fields().insert(pair<fieldType::identifierType, fieldType>(fieldId, field));
|
fields().emplace(fieldId, field);
|
||||||
} catch(const TruncatedDataException &) {
|
} catch(const TruncatedDataException &) {
|
||||||
addNotifications(field);
|
addNotifications(field);
|
||||||
throw;
|
throw;
|
||||||
|
|
|
@ -12,21 +12,33 @@ namespace Media {
|
||||||
class OggIterator;
|
class OggIterator;
|
||||||
class VorbisComment;
|
class VorbisComment;
|
||||||
|
|
||||||
class TAG_PARSER_EXPORT VorbisComment : public FieldMapBasedTag<VorbisCommentField, CaseInsensitiveStringComparer>
|
/*!
|
||||||
|
* \brief Defines traits for the TagField implementation of the VorbisComment class.
|
||||||
|
*/
|
||||||
|
template <>
|
||||||
|
class TAG_PARSER_EXPORT FieldMapBasedTagTraits<VorbisComment>
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
typedef VorbisCommentField FieldType;
|
||||||
|
typedef CaseInsensitiveStringComparer Compare;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TAG_PARSER_EXPORT VorbisComment : public FieldMapBasedTag<VorbisComment>
|
||||||
|
{
|
||||||
|
friend class FieldMapBasedTag<VorbisComment>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VorbisComment();
|
VorbisComment();
|
||||||
|
|
||||||
static constexpr TagType tagType = TagType::VorbisComment;
|
static constexpr TagType tagType = TagType::VorbisComment;
|
||||||
TagType type() const;
|
static constexpr const char *tagName = "Vorbis comment";
|
||||||
const char *typeName() const;
|
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
|
||||||
TagTextEncoding proposedTextEncoding() const;
|
|
||||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||||
|
|
||||||
|
using FieldMapBasedTag<VorbisComment>::value;
|
||||||
const TagValue &value(KnownField field) const;
|
const TagValue &value(KnownField field) const;
|
||||||
|
using FieldMapBasedTag<VorbisComment>::setValue;
|
||||||
bool setValue(KnownField field, const TagValue &value);
|
bool setValue(KnownField field, const TagValue &value);
|
||||||
std::string fieldId(KnownField field) const;
|
|
||||||
KnownField knownField(const std::string &id) const;
|
|
||||||
|
|
||||||
void parse(OggIterator &iterator, VorbisCommentFlags flags = VorbisCommentFlags::None);
|
void parse(OggIterator &iterator, VorbisCommentFlags flags = VorbisCommentFlags::None);
|
||||||
void parse(std::istream &stream, uint64 maxSize, VorbisCommentFlags flags = VorbisCommentFlags::None);
|
void parse(std::istream &stream, uint64 maxSize, VorbisCommentFlags flags = VorbisCommentFlags::None);
|
||||||
|
@ -35,6 +47,10 @@ public:
|
||||||
const TagValue &vendor() const;
|
const TagValue &vendor() const;
|
||||||
void setVendor(const TagValue &vendor);
|
void setVendor(const TagValue &vendor);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
IdentifierType internallyGetFieldId(KnownField field) const;
|
||||||
|
KnownField internallyGetKnownField(const IdentifierType &id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<class StreamType>
|
template<class StreamType>
|
||||||
void internalParse(StreamType &stream, uint64 maxSize, VorbisCommentFlags flags);
|
void internalParse(StreamType &stream, uint64 maxSize, VorbisCommentFlags flags);
|
||||||
|
@ -49,21 +65,6 @@ private:
|
||||||
inline VorbisComment::VorbisComment()
|
inline VorbisComment::VorbisComment()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline TagType VorbisComment::type() const
|
|
||||||
{
|
|
||||||
return TagType::VorbisComment;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char *VorbisComment::typeName() const
|
|
||||||
{
|
|
||||||
return "Vorbis comment";
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TagTextEncoding VorbisComment::proposedTextEncoding() const
|
|
||||||
{
|
|
||||||
return TagTextEncoding::Utf8;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool VorbisComment::canEncodingBeUsed(TagTextEncoding encoding) const
|
inline bool VorbisComment::canEncodingBeUsed(TagTextEncoding encoding) const
|
||||||
{
|
{
|
||||||
return encoding == TagTextEncoding::Utf8;
|
return encoding == TagTextEncoding::Utf8;
|
||||||
|
|
|
@ -38,7 +38,7 @@ VorbisCommentField::VorbisCommentField()
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new Vorbis comment with the specified \a id and \a value.
|
* \brief Constructs a new Vorbis comment with the specified \a id and \a value.
|
||||||
*/
|
*/
|
||||||
VorbisCommentField::VorbisCommentField(const identifierType &id, const TagValue &value) :
|
VorbisCommentField::VorbisCommentField(const IdentifierType &id, const TagValue &value) :
|
||||||
TagField<VorbisCommentField>(id, value)
|
TagField<VorbisCommentField>(id, value)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
|
@ -41,18 +41,8 @@ template <>
|
||||||
class TAG_PARSER_EXPORT TagFieldTraits<VorbisCommentField>
|
class TAG_PARSER_EXPORT TagFieldTraits<VorbisCommentField>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*!
|
typedef std::string IdentifierType;
|
||||||
* \brief Fields in a Vorbis comment are identified by 32-bit unsigned integers.
|
typedef uint32 TypeInfoType;
|
||||||
*/
|
|
||||||
typedef std::string identifierType;
|
|
||||||
/*!
|
|
||||||
* \brief The type info is stored using 32-bit unsigned integers.
|
|
||||||
*/
|
|
||||||
typedef uint32 typeInfoType;
|
|
||||||
/*!
|
|
||||||
* \brief The implementation type is VorbisCommentField.
|
|
||||||
*/
|
|
||||||
typedef VorbisCommentField implementationType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OggIterator;
|
class OggIterator;
|
||||||
|
@ -63,7 +53,7 @@ class TAG_PARSER_EXPORT VorbisCommentField : public TagField<VorbisCommentField>
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VorbisCommentField();
|
VorbisCommentField();
|
||||||
VorbisCommentField(const identifierType &id, const TagValue &value);
|
VorbisCommentField(const IdentifierType &id, const TagValue &value);
|
||||||
|
|
||||||
void parse(OggIterator &iterator);
|
void parse(OggIterator &iterator);
|
||||||
void parse(OggIterator &iterator, uint64 &maxSize);
|
void parse(OggIterator &iterator, uint64 &maxSize);
|
||||||
|
|
Loading…
Reference in New Issue