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_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
|
||||
set(META_APP_DESCRIPTION "C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags")
|
||||
set(META_VERSION_MAJOR 6)
|
||||
set(META_VERSION_MINOR 5)
|
||||
set(META_VERSION_MAJOR 7)
|
||||
set(META_VERSION_MINOR 0)
|
||||
set(META_VERSION_PATCH 0)
|
||||
set(META_PUBLIC_SHARED_LIB_DEPENDS c++utilities)
|
||||
set(META_PUBLIC_STATIC_LIB_DEPENDS c++utilities_static)
|
||||
|
|
236
fieldbasedtag.h
236
fieldbasedtag.h
|
@ -8,51 +8,75 @@
|
|||
|
||||
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
|
||||
* \brief The FieldMapBasedTag provides a generic implementation of Tag which stores
|
||||
* the tag fields using std::multimap.
|
||||
*
|
||||
* 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
|
||||
* of TagField.
|
||||
*
|
||||
* \tparam Compare Specifies the key comparsion function. Default is std::less.
|
||||
* \remarks This template class is intended to be subclassed using
|
||||
* with the "Curiously recurring template pattern".
|
||||
*/
|
||||
template <class FieldType, class Compare = std::less<typename FieldType::identifierType> >
|
||||
template <class ImplementationType>
|
||||
class FieldMapBasedTag : public Tag
|
||||
{
|
||||
friend class FieldMapBasedTagTraits<ImplementationType>;
|
||||
|
||||
public:
|
||||
typedef typename FieldMapBasedTagTraits<ImplementationType>::FieldType FieldType;
|
||||
typedef typename FieldMapBasedTagTraits<ImplementationType>::FieldType::IdentifierType IdentifierType;
|
||||
typedef typename FieldMapBasedTagTraits<ImplementationType>::Compare Compare;
|
||||
|
||||
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;
|
||||
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;
|
||||
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 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 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();
|
||||
const std::multimap<typename FieldType::identifierType, FieldType, Compare> &fields() const;
|
||||
std::multimap<typename FieldType::identifierType, FieldType, Compare> &fields();
|
||||
const std::multimap<IdentifierType, FieldType, Compare> &fields() const;
|
||||
std::multimap<IdentifierType, FieldType, Compare> &fields();
|
||||
unsigned int fieldCount() const;
|
||||
virtual typename FieldType::identifierType fieldId(KnownField value) const = 0; // FIXME: use static polymorphism
|
||||
virtual KnownField knownField(const typename FieldType::identifierType &id) const = 0; // FIXME: use static polymorphism
|
||||
IdentifierType fieldId(KnownField value) const;
|
||||
KnownField knownField(const IdentifierType &id) const;
|
||||
bool supportsField(KnownField field) const;
|
||||
using Tag::proposedDataType;
|
||||
virtual TagDataType proposedDataType(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism
|
||||
int insertFields(const FieldMapBasedTag<FieldType, Compare> &from, bool overwrite);
|
||||
TagDataType proposedDataType(const IdentifierType &id) const;
|
||||
int insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite);
|
||||
unsigned int insertValues(const Tag &from, bool overwrite);
|
||||
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:
|
||||
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.
|
||||
*/
|
||||
template <class FieldType, class Compare>
|
||||
FieldMapBasedTag<FieldType, Compare>::FieldMapBasedTag()
|
||||
template <class ImplementationType>
|
||||
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.
|
||||
* \sa Tag::value()
|
||||
* \brief Default implementation for value().
|
||||
* \remarks Shadow in subclass to provide custom implementation.
|
||||
*/
|
||||
template <class FieldType, class Compare>
|
||||
inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(const typename FieldType::identifierType &id) const
|
||||
template<class ImplementationType>
|
||||
const TagValue &FieldMapBasedTag<ImplementationType>::internallyGetValue(const IdentifierType &id) const
|
||||
{
|
||||
auto i = m_fields.find(id);
|
||||
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));
|
||||
}
|
||||
|
@ -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.
|
||||
* \sa Tag::values()
|
||||
*/
|
||||
template <class FieldType, class Compare>
|
||||
inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(const typename FieldType::identifierType &id) const
|
||||
template <class ImplementationType>
|
||||
inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(const IdentifierType &id) const
|
||||
{
|
||||
auto range = m_fields.equal_range(id);
|
||||
std::vector<const TagValue *> values;
|
||||
|
@ -110,24 +162,24 @@ inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::value
|
|||
return values;
|
||||
}
|
||||
|
||||
template <class FieldType, class Compare>
|
||||
inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(KnownField field) const
|
||||
template <class ImplementationType>
|
||||
inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(KnownField field) const
|
||||
{
|
||||
return values(fieldId(field));
|
||||
}
|
||||
|
||||
template <class FieldType, class Compare>
|
||||
inline bool FieldMapBasedTag<FieldType, Compare>::setValue(KnownField field, const TagValue &value)
|
||||
template <class ImplementationType>
|
||||
inline bool FieldMapBasedTag<ImplementationType>::setValue(KnownField field, const TagValue &value)
|
||||
{
|
||||
return setValue(fieldId(field), value);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the given \a value to the field with the specified \a id.
|
||||
* \sa Tag::setValue()
|
||||
* \brief Default implementation for setValue().
|
||||
* \remarks Shadow in subclass to provide custom implementation.
|
||||
*/
|
||||
template <class FieldType, class Compare>
|
||||
bool FieldMapBasedTag<FieldType, Compare>::setValue(const typename FieldType::identifierType &id, const Media::TagValue &value)
|
||||
template<class ImplementationType>
|
||||
bool FieldMapBasedTag<ImplementationType>::internallySetValue(const IdentifierType &id, const TagValue &value)
|
||||
{
|
||||
auto i = m_fields.find(id);
|
||||
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;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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.
|
||||
* \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.
|
||||
* \sa Tag::setValues()
|
||||
*/
|
||||
template <class FieldType, class Compare>
|
||||
bool FieldMapBasedTag<FieldType, Compare>::setValues(const typename FieldType::identifierType &id, const std::vector<TagValue> &values)
|
||||
template <class ImplementationType>
|
||||
bool FieldMapBasedTag<ImplementationType>::setValues(const IdentifierType &id, const std::vector<TagValue> &values)
|
||||
{
|
||||
auto valuesIterator = values.cbegin();
|
||||
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.
|
||||
* \sa Tag::setValues()
|
||||
*/
|
||||
template <class FieldType, class Compare>
|
||||
bool FieldMapBasedTag<FieldType, Compare>::setValues(KnownField field, const std::vector<TagValue> &values)
|
||||
template <class ImplementationType>
|
||||
bool FieldMapBasedTag<ImplementationType>::setValues(KnownField field, const std::vector<TagValue> &values)
|
||||
{
|
||||
return setValues(fieldId(field), values);
|
||||
}
|
||||
|
||||
template <class FieldType, class Compare>
|
||||
inline bool FieldMapBasedTag<FieldType, Compare>::hasField(KnownField field) const
|
||||
template <class ImplementationType>
|
||||
inline bool FieldMapBasedTag<ImplementationType>::hasField(KnownField field) const
|
||||
{
|
||||
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>
|
||||
inline bool FieldMapBasedTag<FieldType, Compare>::hasField(const typename FieldType::identifierType &id) const
|
||||
template<class ImplementationType>
|
||||
bool FieldMapBasedTag<ImplementationType>::internallyHasField(const IdentifierType &id) const
|
||||
{
|
||||
for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
|
||||
if(!range.first->second.value().isEmpty()) {
|
||||
|
@ -202,8 +265,17 @@ inline bool FieldMapBasedTag<FieldType, Compare>::hasField(const typename FieldT
|
|||
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();
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
template <class FieldType, class Compare>
|
||||
inline const std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields() const
|
||||
template <class ImplementationType>
|
||||
inline auto FieldMapBasedTag<ImplementationType>::fields() const -> const std::multimap<IdentifierType, FieldType, Compare> &
|
||||
{
|
||||
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.
|
||||
*/
|
||||
template <class FieldType, class Compare>
|
||||
inline std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields()
|
||||
template <class ImplementationType>
|
||||
inline auto FieldMapBasedTag<ImplementationType>::fields() -> std::multimap<IdentifierType, FieldType, Compare> &
|
||||
{
|
||||
return m_fields;
|
||||
}
|
||||
|
||||
template <class FieldType, class Compare>
|
||||
unsigned int FieldMapBasedTag<FieldType, Compare>::fieldCount() const
|
||||
template <class ImplementationType>
|
||||
unsigned int FieldMapBasedTag<ImplementationType>::fieldCount() const
|
||||
{
|
||||
unsigned int count = 0;
|
||||
for(const auto &field : m_fields) {
|
||||
|
@ -238,20 +310,50 @@ unsigned int FieldMapBasedTag<FieldType, Compare>::fieldCount() const
|
|||
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;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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.
|
||||
*/
|
||||
template <class FieldType, class Compare>
|
||||
inline TagDataType FieldMapBasedTag<FieldType, Compare>::proposedDataType(const typename FieldType::identifierType &id) const
|
||||
template <class ImplementationType>
|
||||
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.
|
||||
* \return Returns the number of fields that have been inserted.
|
||||
*/
|
||||
template <class FieldType, class Compare>
|
||||
int FieldMapBasedTag<FieldType, Compare>::insertFields(const FieldMapBasedTag<FieldType, Compare> &from, bool overwrite)
|
||||
template <class ImplementationType>
|
||||
int FieldMapBasedTag<ImplementationType>::insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite)
|
||||
{
|
||||
int fieldsInserted = 0;
|
||||
for(const auto &pair : from.fields()) {
|
||||
|
@ -291,19 +393,19 @@ int FieldMapBasedTag<FieldType, Compare>::insertFields(const FieldMapBasedTag<Fi
|
|||
return fieldsInserted;
|
||||
}
|
||||
|
||||
template <class FieldType, class Compare>
|
||||
unsigned int FieldMapBasedTag<FieldType, Compare>::insertValues(const Tag &from, bool overwrite)
|
||||
template <class ImplementationType>
|
||||
unsigned int FieldMapBasedTag<ImplementationType>::insertValues(const Tag &from, bool overwrite)
|
||||
{
|
||||
if(type() == from.type()) {
|
||||
// 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 {
|
||||
return Tag::insertValues(from, overwrite);
|
||||
}
|
||||
}
|
||||
|
||||
template <class FieldType, class Compare>
|
||||
void FieldMapBasedTag<FieldType, Compare>::ensureTextValuesAreProperlyEncoded()
|
||||
template <class ImplementationType>
|
||||
void FieldMapBasedTag<ImplementationType>::ensureTextValuesAreProperlyEncoded()
|
||||
{
|
||||
for(auto &field : fields()) {
|
||||
field.second.value().convertDataEncodingForTag(this);
|
||||
|
|
|
@ -52,10 +52,10 @@ public:
|
|||
void removeAllTracks();
|
||||
void reset();
|
||||
|
||||
typedef FileInfoType fileInfoType;
|
||||
typedef TagType tagType;
|
||||
typedef TrackType trackType;
|
||||
typedef ElementType elementType;
|
||||
typedef FileInfoType ContainerFileInfoType;
|
||||
typedef TagType ContainerTagType;
|
||||
typedef TrackType ContainerTrackType;
|
||||
typedef ElementType ContainerElementType;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<ElementType> m_firstElement;
|
||||
|
|
|
@ -108,8 +108,9 @@ class FileElementTraits
|
|||
* \class Media::GenericFileElement
|
||||
* \brief The GenericFileElement class helps to parse binary files which consist
|
||||
* of an arboreal element strucutre.
|
||||
*
|
||||
* \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>
|
||||
class TAG_PARSER_EXPORT GenericFileElement : public StatusProvider
|
||||
|
@ -120,61 +121,61 @@ public:
|
|||
/*!
|
||||
* \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.
|
||||
*/
|
||||
typedef typename FileElementTraits<ImplementationType>::identifierType identifierType;
|
||||
typedef typename FileElementTraits<ImplementationType>::IdentifierType IdentifierType;
|
||||
|
||||
/*!
|
||||
* \brief Specifies the type used to store data sizes.
|
||||
*/
|
||||
typedef typename FileElementTraits<ImplementationType>::dataSizeType dataSizeType;
|
||||
typedef typename FileElementTraits<ImplementationType>::DataSizeType DataSizeType;
|
||||
|
||||
/*!
|
||||
* \brief Specifies the type of the actual implementation.
|
||||
*/
|
||||
typedef typename FileElementTraits<ImplementationType>::implementationType implementationType;
|
||||
|
||||
GenericFileElement(containerType &container, uint64 startOffset);
|
||||
GenericFileElement(implementationType &parent, uint64 startOffset);
|
||||
GenericFileElement(containerType &container, uint64 startOffset, uint64 maxSize);
|
||||
GenericFileElement(ContainerType &container, uint64 startOffset);
|
||||
GenericFileElement(ImplementationType &parent, uint64 startOffset);
|
||||
GenericFileElement(ContainerType &container, uint64 startOffset, uint64 maxSize);
|
||||
GenericFileElement(const GenericFileElement& other) = delete;
|
||||
GenericFileElement(GenericFileElement& other) = delete;
|
||||
GenericFileElement& operator =(const GenericFileElement& other) = delete;
|
||||
|
||||
containerType& container();
|
||||
const containerType& container() const;
|
||||
ContainerType& container();
|
||||
const ContainerType& container() const;
|
||||
std::iostream &stream();
|
||||
IoUtilities::BinaryReader &reader();
|
||||
IoUtilities::BinaryWriter &writer();
|
||||
uint64 startOffset() const;
|
||||
uint64 relativeStartOffset() const;
|
||||
const identifierType &id() const;
|
||||
const IdentifierType &id() const;
|
||||
std::string idToString() const;
|
||||
uint32 idLength() const;
|
||||
uint32 headerSize() const;
|
||||
dataSizeType dataSize() const;
|
||||
DataSizeType dataSize() const;
|
||||
uint32 sizeLength() const;
|
||||
uint64 dataOffset() const;
|
||||
uint64 totalSize() const;
|
||||
uint64 endOffset() const;
|
||||
uint64 maxTotalSize() const;
|
||||
implementationType* parent();
|
||||
const implementationType* parent() const;
|
||||
implementationType* nextSibling();
|
||||
const implementationType* nextSibling() const;
|
||||
implementationType* firstChild();
|
||||
const implementationType* firstChild() const;
|
||||
implementationType* subelementByPath(const std::initializer_list<identifierType> &path);
|
||||
implementationType* subelementByPath(std::list<identifierType> &path);
|
||||
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;
|
||||
byte level() const;
|
||||
ImplementationType* parent();
|
||||
const ImplementationType* parent() const;
|
||||
ImplementationType* parent(byte n);
|
||||
const ImplementationType* parent(byte n) const;
|
||||
ImplementationType* nextSibling();
|
||||
const ImplementationType* nextSibling() const;
|
||||
ImplementationType* firstChild();
|
||||
const ImplementationType* firstChild() const;
|
||||
ImplementationType* lastChild();
|
||||
const ImplementationType* lastChild() const;
|
||||
ImplementationType* subelementByPath(const std::initializer_list<IdentifierType> &path);
|
||||
ImplementationType* subelementByPath(std::list<IdentifierType> &path);
|
||||
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 isPadding() const;
|
||||
uint64 firstChildOffset() const;
|
||||
|
@ -194,25 +195,27 @@ public:
|
|||
void copyBuffer(std::ostream &targetStream);
|
||||
void copyPreferablyFromBuffer(std::ostream &targetStream);
|
||||
const std::unique_ptr<char[]> &buffer();
|
||||
implementationType *denoteFirstChild(uint32 offset);
|
||||
ImplementationType *denoteFirstChild(uint32 offset);
|
||||
|
||||
protected:
|
||||
identifierType m_id;
|
||||
IdentifierType m_id;
|
||||
uint64 m_startOffset;
|
||||
uint64 m_maxSize;
|
||||
uint32 m_idLength;
|
||||
dataSizeType m_dataSize;
|
||||
DataSizeType m_dataSize;
|
||||
uint32 m_sizeLength;
|
||||
implementationType* m_parent;
|
||||
std::unique_ptr<implementationType> m_nextSibling;
|
||||
std::unique_ptr<implementationType> m_firstChild;
|
||||
ImplementationType* m_parent;
|
||||
std::unique_ptr<ImplementationType> m_nextSibling;
|
||||
std::unique_ptr<ImplementationType> m_firstChild;
|
||||
std::unique_ptr<char[]> m_buffer;
|
||||
|
||||
private:
|
||||
void copyInternal(std::ostream &targetStream, uint64 startOffset, uint64 bytesToCopy);
|
||||
|
||||
containerType* m_container;
|
||||
ContainerType* m_container;
|
||||
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.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::containerType &container, uint64 startOffset) :
|
||||
m_id(identifierType()),
|
||||
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::ContainerType &container, uint64 startOffset) :
|
||||
m_id(IdentifierType()),
|
||||
m_startOffset(startOffset),
|
||||
m_idLength(0),
|
||||
m_dataSize(0),
|
||||
m_sizeLength(0),
|
||||
m_parent(nullptr),
|
||||
m_container(&container),
|
||||
m_parsed(false)
|
||||
m_parsed(false),
|
||||
m_sizeUnknown(false)
|
||||
{
|
||||
m_maxSize = container.fileInfo().size();
|
||||
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.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::implementationType &parent, uint64 startOffset) :
|
||||
m_id(identifierType()),
|
||||
GenericFileElement<ImplementationType>::GenericFileElement(ImplementationType &parent, uint64 startOffset) :
|
||||
m_id(IdentifierType()),
|
||||
m_startOffset(startOffset),
|
||||
m_maxSize(parent.startOffset() + parent.totalSize() - startOffset),
|
||||
m_idLength(0),
|
||||
|
@ -252,15 +256,16 @@ GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<Im
|
|||
m_sizeLength(0),
|
||||
m_parent(&parent),
|
||||
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.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::containerType &container, uint64 startOffset, uint64 maxSize) :
|
||||
m_id(identifierType()),
|
||||
GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<ImplementationType>::ContainerType &container, uint64 startOffset, uint64 maxSize) :
|
||||
m_id(IdentifierType()),
|
||||
m_startOffset(startOffset),
|
||||
m_maxSize(maxSize),
|
||||
m_idLength(0),
|
||||
|
@ -268,14 +273,15 @@ GenericFileElement<ImplementationType>::GenericFileElement(GenericFileElement<Im
|
|||
m_sizeLength(0),
|
||||
m_parent(nullptr),
|
||||
m_container(&container),
|
||||
m_parsed(false)
|
||||
m_parsed(false),
|
||||
m_sizeUnknown(false)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Returns the related container.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline typename GenericFileElement<ImplementationType>::containerType& GenericFileElement<ImplementationType>::container()
|
||||
inline typename GenericFileElement<ImplementationType>::ContainerType& GenericFileElement<ImplementationType>::container()
|
||||
{
|
||||
return *m_container;
|
||||
}
|
||||
|
@ -284,7 +290,7 @@ inline typename GenericFileElement<ImplementationType>::containerType& GenericFi
|
|||
* \brief Returns the related container.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
@ -338,7 +344,7 @@ inline uint64 GenericFileElement<ImplementationType>::relativeStartOffset() cons
|
|||
* \brief Returns the element ID.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
@ -378,7 +384,7 @@ inline uint32 GenericFileElement<ImplementationType>::headerSize() const
|
|||
* This is the size of the element excluding the header.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline typename GenericFileElement<ImplementationType>::dataSizeType GenericFileElement<ImplementationType>::dataSize() const
|
||||
inline typename GenericFileElement<ImplementationType>::DataSizeType GenericFileElement<ImplementationType>::dataSize() const
|
||||
{
|
||||
return m_dataSize;
|
||||
}
|
||||
|
@ -435,6 +441,18 @@ inline uint64 GenericFileElement<ImplementationType>::maxTotalSize() const
|
|||
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.
|
||||
*
|
||||
|
@ -442,7 +460,7 @@ inline uint64 GenericFileElement<ImplementationType>::maxTotalSize() const
|
|||
* If the current element is a top level element nullptr is returned.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::parent()
|
||||
inline ImplementationType *GenericFileElement<ImplementationType>::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.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline const typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::parent() const
|
||||
inline const ImplementationType *GenericFileElement<ImplementationType>::parent() const
|
||||
{
|
||||
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.
|
||||
*
|
||||
|
@ -468,7 +512,7 @@ inline const typename GenericFileElement<ImplementationType>::implementationType
|
|||
* \remarks parse() needs to be called before.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::nextSibling()
|
||||
inline ImplementationType *GenericFileElement<ImplementationType>::nextSibling()
|
||||
{
|
||||
return m_nextSibling.get();
|
||||
}
|
||||
|
@ -482,7 +526,7 @@ inline typename GenericFileElement<ImplementationType>::implementationType *Gene
|
|||
* \remarks parse() needs to be called before.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline const typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::nextSibling() const
|
||||
inline const ImplementationType *GenericFileElement<ImplementationType>::nextSibling() const
|
||||
{
|
||||
return m_nextSibling.get();
|
||||
}
|
||||
|
@ -496,7 +540,7 @@ inline const typename GenericFileElement<ImplementationType>::implementationType
|
|||
* \remarks parse() needs to be called before.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::firstChild()
|
||||
inline ImplementationType *GenericFileElement<ImplementationType>::firstChild()
|
||||
{
|
||||
return m_firstChild.get();
|
||||
}
|
||||
|
@ -510,11 +554,44 @@ inline typename GenericFileElement<ImplementationType>::implementationType *Gene
|
|||
* \remarks parse() needs to be called before.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline const typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::firstChild() const
|
||||
inline const ImplementationType *GenericFileElement<ImplementationType>::firstChild() const
|
||||
{
|
||||
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.
|
||||
*
|
||||
|
@ -525,9 +602,9 @@ inline const typename GenericFileElement<ImplementationType>::implementationType
|
|||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -542,13 +619,13 @@ inline typename GenericFileElement<ImplementationType>::implementationType *Gene
|
|||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||
*/
|
||||
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
|
||||
if(path.size()) {
|
||||
if(path.front() == id()) {
|
||||
if(path.size() == 1) {
|
||||
return static_cast<implementationType*>(this);
|
||||
return static_cast<ImplementationType *>(this);
|
||||
} else {
|
||||
if(firstChild()) {
|
||||
path.pop_front();
|
||||
|
@ -574,10 +651,10 @@ typename GenericFileElement<ImplementationType>::implementationType *GenericFile
|
|||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||
*/
|
||||
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
|
||||
for(implementationType *child = firstChild(); child; child = child->nextSibling()) {
|
||||
for(ImplementationType *child = firstChild(); child; child = child->nextSibling()) {
|
||||
child->parse();
|
||||
if(child->id() == id) {
|
||||
return child;
|
||||
|
@ -601,10 +678,10 @@ typename GenericFileElement<ImplementationType>::implementationType *GenericFile
|
|||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||
*/
|
||||
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
|
||||
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();
|
||||
if(sibling->id() == id) {
|
||||
return sibling;
|
||||
|
@ -617,25 +694,25 @@ typename GenericFileElement<ImplementationType>::implementationType *GenericFile
|
|||
* \brief Returns an iterator for iterating over the element's childs.
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
FileElementIterator<typename GenericFileElement<ImplementationType>::implementationType> GenericFileElement<ImplementationType>::end()
|
||||
FileElementIterator<ImplementationType> GenericFileElement<ImplementationType>::end()
|
||||
{
|
||||
return FileElementIterator<ImplementationType>();
|
||||
}
|
||||
|
@ -644,7 +721,7 @@ FileElementIterator<typename GenericFileElement<ImplementationType>::implementat
|
|||
* \brief Returns an invalid iterator.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
const FileElementIterator<typename GenericFileElement<ImplementationType>::implementationType> GenericFileElement<ImplementationType>::end() const
|
||||
const FileElementIterator<ImplementationType> GenericFileElement<ImplementationType>::end() const
|
||||
{
|
||||
return FileElementIterator<ImplementationType>();
|
||||
}
|
||||
|
@ -694,7 +771,7 @@ inline bool GenericFileElement<ImplementationType>::isParsed() const
|
|||
template <class ImplementationType>
|
||||
void GenericFileElement<ImplementationType>::clear()
|
||||
{
|
||||
m_id = identifierType();
|
||||
m_id = IdentifierType();
|
||||
//m_startOffset = 0;
|
||||
m_idLength = 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.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
typename GenericFileElement<ImplementationType>::implementationType *GenericFileElement<ImplementationType>::denoteFirstChild(uint32 relativeFirstChildOffset)
|
||||
ImplementationType *GenericFileElement<ImplementationType>::denoteFirstChild(uint32 relativeFirstChildOffset)
|
||||
{
|
||||
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 {
|
||||
m_firstChild.reset();
|
||||
}
|
||||
|
@ -921,7 +998,7 @@ typename GenericFileElement<ImplementationType>::implementationType *GenericFile
|
|||
template <class ImplementationType>
|
||||
constexpr uint32 GenericFileElement<ImplementationType>::maximumIdLengthSupported()
|
||||
{
|
||||
return sizeof(identifierType);
|
||||
return sizeof(IdentifierType);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -930,7 +1007,7 @@ constexpr uint32 GenericFileElement<ImplementationType>::maximumIdLengthSupporte
|
|||
template <class ImplementationType>
|
||||
constexpr uint32 GenericFileElement<ImplementationType>::maximumSizeLengthSupported()
|
||||
{
|
||||
return sizeof(dataSizeType);
|
||||
return sizeof(DataSizeType);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -12,7 +12,7 @@ class TagField;
|
|||
* \class Media::TagFieldTraits
|
||||
* \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>
|
||||
class TagFieldTraits
|
||||
|
@ -25,25 +25,26 @@ class TagFieldTraits
|
|||
* might be assigned as well. The usage of the type info depends on the
|
||||
* 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".
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
class TAG_PARSER_EXPORT TagField
|
||||
{
|
||||
public:
|
||||
friend class TagFieldTraits<ImplementationType>;
|
||||
typedef typename TagFieldTraits<ImplementationType>::implementationType implementationType;
|
||||
typedef typename TagFieldTraits<ImplementationType>::identifierType identifierType;
|
||||
typedef typename TagFieldTraits<ImplementationType>::typeInfoType typeInfoType;
|
||||
|
||||
public:
|
||||
typedef typename TagFieldTraits<ImplementationType>::IdentifierType IdentifierType;
|
||||
typedef typename TagFieldTraits<ImplementationType>::TypeInfoType TypeInfoType;
|
||||
|
||||
TagField();
|
||||
TagField(const identifierType &id, const TagValue &value);
|
||||
TagField(const IdentifierType &id, const TagValue &value);
|
||||
~TagField();
|
||||
|
||||
const identifierType &id() const;
|
||||
const IdentifierType &id() const;
|
||||
std::string idToString() const;
|
||||
void setId(const identifierType &id);
|
||||
void setId(const IdentifierType &id);
|
||||
void clearId();
|
||||
|
||||
TagValue &value();
|
||||
|
@ -51,8 +52,8 @@ public:
|
|||
void setValue(const TagValue &value);
|
||||
void clearValue();
|
||||
|
||||
const typeInfoType &typeInfo() const;
|
||||
void setTypeInfo(const typeInfoType &typeInfo);
|
||||
const TypeInfoType &typeInfo() const;
|
||||
void setTypeInfo(const TypeInfoType &typeInfo);
|
||||
void removeTypeInfo();
|
||||
bool isTypeInfoAssigned() const;
|
||||
|
||||
|
@ -71,9 +72,9 @@ private:
|
|||
void cleared();
|
||||
|
||||
private:
|
||||
identifierType m_id;
|
||||
IdentifierType m_id;
|
||||
TagValue m_value;
|
||||
typeInfoType m_typeInfo;
|
||||
TypeInfoType m_typeInfo;
|
||||
bool m_typeInfoAssigned;
|
||||
bool m_default;
|
||||
std::vector<ImplementationType> m_nestedFields;
|
||||
|
@ -84,9 +85,9 @@ private:
|
|||
*/
|
||||
template <class ImplementationType>
|
||||
TagField<ImplementationType>::TagField() :
|
||||
m_id(identifierType()),
|
||||
m_id(IdentifierType()),
|
||||
m_value(TagValue()),
|
||||
m_typeInfo(typeInfoType()),
|
||||
m_typeInfo(TypeInfoType()),
|
||||
m_typeInfoAssigned(false),
|
||||
m_default(false)
|
||||
{}
|
||||
|
@ -95,10 +96,10 @@ TagField<ImplementationType>::TagField() :
|
|||
* \brief Constructs a new TagField with the specified \a id and \a value.
|
||||
*/
|
||||
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_value(value),
|
||||
m_typeInfo(typeInfoType()),
|
||||
m_typeInfo(TypeInfoType()),
|
||||
m_typeInfoAssigned(false),
|
||||
m_default(false)
|
||||
{}
|
||||
|
@ -114,7 +115,7 @@ TagField<ImplementationType>::~TagField()
|
|||
* \brief Returns the id of the current TagField.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
@ -129,7 +130,7 @@ inline std::string TagField<ImplementationType>::idToString() const
|
|||
* \brief Sets the id of the current Tag Field.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline void TagField<ImplementationType>::setId(const identifierType &id)
|
||||
inline void TagField<ImplementationType>::setId(const IdentifierType &id)
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
@ -140,7 +141,7 @@ inline void TagField<ImplementationType>::setId(const identifierType &id)
|
|||
template <class ImplementationType>
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
@ -192,7 +193,7 @@ inline const typename TagField<ImplementationType>::typeInfoType &TagField<Imple
|
|||
* \brief Sets the type info of the current TagField.
|
||||
*/
|
||||
template <class ImplementationType>
|
||||
inline void TagField<ImplementationType>::setTypeInfo(const typeInfoType &typeInfo)
|
||||
inline void TagField<ImplementationType>::setTypeInfo(const TypeInfoType &typeInfo)
|
||||
{
|
||||
m_typeInfo = typeInfo;
|
||||
m_typeInfoAssigned = true;
|
||||
|
@ -204,7 +205,7 @@ inline void TagField<ImplementationType>::setTypeInfo(const typeInfoType &typeIn
|
|||
template <class ImplementationType>
|
||||
inline void TagField<ImplementationType>::removeTypeInfo()
|
||||
{
|
||||
m_typeInfo = typeInfoType();
|
||||
m_typeInfo = TypeInfoType();
|
||||
m_typeInfoAssigned = false;
|
||||
}
|
||||
|
||||
|
@ -243,7 +244,7 @@ void TagField<ImplementationType>::clear()
|
|||
{
|
||||
clearId();
|
||||
clearValue();
|
||||
m_typeInfo = typeInfoType();
|
||||
m_typeInfo = TypeInfoType();
|
||||
m_typeInfoAssigned = false;
|
||||
m_default = true;
|
||||
static_cast<ImplementationType *>(this)->cleared();
|
||||
|
|
|
@ -30,7 +30,7 @@ TagType Id3v1Tag::type() const
|
|||
|
||||
const char *Id3v1Tag::typeName() const
|
||||
{
|
||||
return "ID3v1 tag";
|
||||
return tagName;
|
||||
}
|
||||
|
||||
bool Id3v1Tag::canEncodingBeUsed(TagTextEncoding encoding) const
|
||||
|
|
|
@ -12,6 +12,7 @@ public:
|
|||
Id3v1Tag();
|
||||
|
||||
static constexpr TagType tagType = TagType::Id3v1Tag;
|
||||
static constexpr const char *tagName = "ID3v1 tag";
|
||||
TagType type() const;
|
||||
const char *typeName() 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.
|
||||
*/
|
||||
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),
|
||||
m_flag(flag),
|
||||
m_group(group),
|
||||
|
|
|
@ -81,20 +81,8 @@ template <>
|
|||
class TAG_PARSER_EXPORT TagFieldTraits<Id3v2Frame>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Fields in an ID3 tag are identified by 32-bit unsigned integers.
|
||||
*/
|
||||
typedef uint32 identifierType;
|
||||
|
||||
/*!
|
||||
* \brief The type info is stored using bytes.
|
||||
*/
|
||||
typedef byte typeInfoType;
|
||||
|
||||
/*!
|
||||
* \brief The implementation type is Id3v2Frame.
|
||||
*/
|
||||
typedef Id3v2Frame implementationType;
|
||||
typedef uint32 IdentifierType;
|
||||
typedef byte TypeInfoType;
|
||||
};
|
||||
|
||||
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:
|
||||
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
|
||||
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 makeComment(std::unique_ptr<char[]> &buffer, uint32 &bufferSize, const TagValue &comment);
|
||||
|
||||
static identifierType fieldIdFromString(const char *idString, std::size_t idStringSize = std::string::npos);
|
||||
static std::string fieldIdToString(identifierType id);
|
||||
static IdentifierType fieldIdFromString(const char *idString, std::size_t idStringSize = std::string::npos);
|
||||
static std::string fieldIdToString(IdentifierType id);
|
||||
|
||||
protected:
|
||||
void cleared();
|
||||
|
@ -334,7 +322,7 @@ inline bool Id3v2Frame::supportsNestedFields() const
|
|||
/*!
|
||||
* \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)) {
|
||||
case 3:
|
||||
|
@ -349,7 +337,7 @@ inline Id3v2Frame::identifierType Id3v2Frame::fieldIdFromString(const char *idSt
|
|||
/*!
|
||||
* \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);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Media {
|
|||
* \brief Implementation of Media::Tag for ID3v2 tags.
|
||||
*/
|
||||
|
||||
uint32 Id3v2Tag::fieldId(KnownField field) const
|
||||
Id3v2Tag::IdentifierType Id3v2Tag::internallyGetFieldId(KnownField field) const
|
||||
{
|
||||
using namespace Id3v2FrameIds;
|
||||
if(m_majorVersion >= 3) {
|
||||
|
@ -78,7 +78,7 @@ uint32 Id3v2Tag::fieldId(KnownField field) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
KnownField Id3v2Tag::knownField(const uint32 &id) const
|
||||
KnownField Id3v2Tag::internallyGetKnownField(const IdentifierType &id) const
|
||||
{
|
||||
using namespace Id3v2FrameIds;
|
||||
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;
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -52,23 +52,29 @@ inline uint64 Id3v2TagMaker::requiredSize() const
|
|||
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:
|
||||
Id3v2Tag();
|
||||
|
||||
static constexpr TagType tagType = TagType::Id3v2Tag;
|
||||
TagType type() const;
|
||||
const char *typeName() const;
|
||||
static constexpr const char *tagName = "ID3v2 tag";
|
||||
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf16LittleEndian;
|
||||
TagTextEncoding proposedTextEncoding() 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 supportsMimeType(KnownField field) const;
|
||||
|
||||
|
@ -88,6 +94,11 @@ public:
|
|||
uint32 extendedHeaderSize() const;
|
||||
uint32 paddingSize() const;
|
||||
|
||||
protected:
|
||||
IdentifierType internallyGetFieldId(KnownField field) const;
|
||||
KnownField internallyGetKnownField(const IdentifierType &id) const;
|
||||
TagDataType internallyGetProposedDataType(const uint32 &id) const;
|
||||
|
||||
private:
|
||||
byte m_majorVersion;
|
||||
byte m_revisionVersion;
|
||||
|
@ -109,16 +120,6 @@ inline Id3v2Tag::Id3v2Tag() :
|
|||
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
|
||||
{
|
||||
return m_majorVersion > 3 ? TagTextEncoding::Utf8 : TagTextEncoding::Utf16LittleEndian;
|
||||
|
|
|
@ -77,15 +77,16 @@ void EbmlElement::internalParse()
|
|||
throw TruncatedDataException();
|
||||
}
|
||||
stream().seekg(startOffset());
|
||||
|
||||
// read ID
|
||||
char buf[maximumIdLengthSupported() > maximumSizeLengthSupported() ? maximumIdLengthSupported() : maximumSizeLengthSupported()] = {0};
|
||||
byte beg = static_cast<byte>(stream().peek()), mask = 0x80;
|
||||
m_idLength = 1;
|
||||
while(m_idLength <= GenericFileElement<implementationType>::maximumIdLengthSupported() && (beg & mask) == 0) {
|
||||
while(m_idLength <= maximumIdLengthSupported() && (beg & mask) == 0) {
|
||||
++m_idLength;
|
||||
mask >>= 1;
|
||||
}
|
||||
if(m_idLength > GenericFileElement<implementationType>::maximumIdLengthSupported()) {
|
||||
if(m_idLength > maximumIdLengthSupported()) {
|
||||
if(!skipped) {
|
||||
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
|
||||
}
|
||||
reader().read(buf + (GenericFileElement<implementationType>::maximumIdLengthSupported() - m_idLength), m_idLength);
|
||||
reader().read(buf + (maximumIdLengthSupported() - m_idLength), m_idLength);
|
||||
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
|
||||
beg = static_cast<byte>(stream().peek()), mask = 0x80;
|
||||
m_sizeLength = 1;
|
||||
if(beg == 0xFF) {
|
||||
if((m_sizeUnknown = (beg == 0xFF))) {
|
||||
// this indicates that the element size is unknown
|
||||
// -> just assume the element takes the maximum available size
|
||||
m_dataSize = maxTotalSize() - headerSize();
|
||||
} else {
|
||||
while(m_sizeLength <= GenericFileElement<implementationType>::maximumSizeLengthSupported() && (beg & mask) == 0) {
|
||||
while(m_sizeLength <= maximumSizeLengthSupported() && (beg & mask) == 0) {
|
||||
++m_sizeLength;
|
||||
mask >>= 1;
|
||||
}
|
||||
if(m_sizeLength > GenericFileElement<implementationType>::maximumSizeLengthSupported()) {
|
||||
if(m_sizeLength > maximumSizeLengthSupported()) {
|
||||
if(!skipped) {
|
||||
addNotification(NotificationType::Critical, "EBML size length is not supported.", parsingContext());
|
||||
}
|
||||
|
@ -125,9 +166,10 @@ void EbmlElement::internalParse()
|
|||
continue; // try again
|
||||
}
|
||||
// read size into buffer
|
||||
memset(buf, 0, sizeof(dataSizeType)); // reset buffer
|
||||
reader().read(buf + (GenericFileElement<implementationType>::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
|
||||
memset(buf, 0, sizeof(DataSizeType)); // reset buffer
|
||||
reader().read(buf + (maximumSizeLengthSupported() - m_sizeLength), m_sizeLength);
|
||||
// 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);
|
||||
// check if element is truncated
|
||||
if(totalSize() > maxTotalSize()) {
|
||||
|
@ -223,7 +265,7 @@ float64 EbmlElement::readFloat()
|
|||
* \brief Returns the length of the specified \a id in byte.
|
||||
* \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) {
|
||||
return 1;
|
||||
|
@ -271,7 +313,7 @@ byte EbmlElement::calculateSizeDenotationLength(uint64 size)
|
|||
* \returns Returns the number of bytes written to \a buff.
|
||||
* \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) {
|
||||
*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 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 buff2[8];
|
||||
|
@ -483,7 +525,7 @@ void EbmlElement::makeSimpleElement(ostream &stream, identifierType id, uint64 c
|
|||
* \param id Specifies the element ID.
|
||||
* \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];
|
||||
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 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];
|
||||
byte sizeLength = EbmlElement::makeId(id, buff1);
|
||||
|
|
|
@ -26,25 +26,9 @@ template <>
|
|||
class TAG_PARSER_EXPORT FileElementTraits<EbmlElement>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief The container type used to store such elements is MatroskaContainer.
|
||||
*/
|
||||
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;
|
||||
typedef MatroskaContainer ContainerType;
|
||||
typedef uint32 IdentifierType;
|
||||
typedef uint64 DataSizeType;
|
||||
};
|
||||
|
||||
class TAG_PARSER_EXPORT EbmlElement : public GenericFileElement<EbmlElement>
|
||||
|
@ -62,17 +46,17 @@ public:
|
|||
uint64 readUInteger();
|
||||
float64 readFloat();
|
||||
|
||||
static byte calculateIdLength(identifierType id);
|
||||
static byte calculateIdLength(IdentifierType id);
|
||||
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, byte minBytes);
|
||||
static byte calculateUIntegerLength(uint64 integer);
|
||||
static byte makeUInteger(uint64 value, char *buff);
|
||||
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, 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, uint64 content);
|
||||
static void makeSimpleElement(std::ostream &stream, IdentifierType id, const std::string &content);
|
||||
static void makeSimpleElement(std::ostream &stream, IdentifierType id, const char *data, std::size_t dataSize);
|
||||
static uint64 bytesToBeSkipped;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -124,7 +124,7 @@ MatroskaAttachmentMaker::MatroskaAttachmentMaker(MatroskaAttachment &attachment)
|
|||
}
|
||||
if(attachment.attachedFileElement()) {
|
||||
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))) {
|
||||
m_attachedFileElementSize += child->totalSize();
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ void MatroskaAttachmentMaker::make(ostream &stream) const
|
|||
EbmlElement::makeSimpleElement(stream, MatroskaIds::FileUID, attachment().id());
|
||||
if(attachment().attachedFileElement()) {
|
||||
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->buffer()) {
|
||||
child->copyBuffer(stream);
|
||||
|
@ -179,7 +179,7 @@ void MatroskaAttachmentMaker::bufferCurrentAttachments()
|
|||
{
|
||||
EbmlElement *child;
|
||||
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))) {
|
||||
child->makeBuffer();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "./ebmlelement.h"
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <ostream>
|
||||
|
||||
namespace Media {
|
||||
|
@ -77,9 +77,9 @@ private:
|
|||
bool updateSize(EbmlElement *element, int shift);
|
||||
|
||||
EbmlElement *m_cuesElement;
|
||||
std::map<EbmlElement *, MatroskaOffsetStates> m_offsets;
|
||||
std::map<EbmlElement *, MatroskaReferenceOffsetPair> m_relativeOffsets;
|
||||
std::map<EbmlElement *, uint64> m_sizes;
|
||||
std::unordered_map<EbmlElement *, MatroskaOffsetStates> m_offsets;
|
||||
std::unordered_map<EbmlElement *, MatroskaReferenceOffsetPair> m_relativeOffsets;
|
||||
std::unordered_map<EbmlElement *, uint64> m_sizes;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
@ -63,10 +63,10 @@ const char *matroskaIdName(uint32 matroskaId)
|
|||
case DateUTC: return "date UTC";
|
||||
case SegmentUID: return "unique segment ID";
|
||||
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 NexUId: return "next unique ID";
|
||||
case NexFileName: return "next file name";
|
||||
case NexUID: return "next unique ID";
|
||||
case NextFileName: return "next file name";
|
||||
case Title: return "title";
|
||||
case SegmentFamily: return "segment family";
|
||||
case ChapterTranslate: return "chapter translate";
|
||||
|
@ -184,10 +184,10 @@ const char *matroskaIdName(uint32 matroskaId)
|
|||
// IDs in the Targets master
|
||||
case TargetTypeValue: return "target type value";
|
||||
case TargetType: return "target type";
|
||||
case TagTrackUId: return "tag track UID";
|
||||
case TagEditionUId: return "tag edition UID";
|
||||
case TagChapterUId: return "tag chapter UID";
|
||||
case TagAttachmentUId: return "tag attachment UID";
|
||||
case TagTrackUID: return "tag track UID";
|
||||
case TagEditionUID: return "tag edition UID";
|
||||
case TagChapterUID: return "tag chapter UID";
|
||||
case TagAttachmentUID: return "tag attachment UID";
|
||||
|
||||
// IDs in the Cues master
|
||||
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,
|
||||
SegmentUID = 0x73A4,
|
||||
SegmentFileName = 0x7384,
|
||||
PrevUId = 0x3CB923,
|
||||
PrevUID = 0x3CB923,
|
||||
PrevFileName = 0x3C83AB,
|
||||
NexUId = 0x3EB923,
|
||||
NexFileName = 0x3E83BB,
|
||||
NexUID = 0x3EB923,
|
||||
NextFileName = 0x3E83BB,
|
||||
Title = 0x7BA9,
|
||||
SegmentFamily = 0x4444,
|
||||
ChapterTranslate = 0x6924
|
||||
|
@ -261,10 +261,10 @@ enum SimpleTagIds {
|
|||
enum TargetsIds {
|
||||
TargetTypeValue = 0x68ca,
|
||||
TargetType = 0x63ca,
|
||||
TagTrackUId = 0x63c5,
|
||||
TagEditionUId = 0x63c9,
|
||||
TagChapterUId = 0x63c4,
|
||||
TagAttachmentUId = 0x63c6
|
||||
TagTrackUID = 0x63c5,
|
||||
TagEditionUID = 0x63c9,
|
||||
TagChapterUID = 0x63c4,
|
||||
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 MatroskaElementLevel matroskaIdLevel(uint32 matroskaId);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ uint64 MatroskaSeekInfo::actualSize() const
|
|||
*
|
||||
* \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;
|
||||
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.
|
||||
*/
|
||||
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 &entry : seekInfo.info()) {
|
||||
|
|
|
@ -15,25 +15,25 @@ public:
|
|||
MatroskaSeekInfo();
|
||||
|
||||
EbmlElement *seekHeadElement() const;
|
||||
const std::vector<std::pair<EbmlElement::identifierType, uint64> > &info() const;
|
||||
std::vector<std::pair<EbmlElement::identifierType, uint64> > &info();
|
||||
const std::vector<std::pair<EbmlElement::IdentifierType, uint64> > &info() const;
|
||||
std::vector<std::pair<EbmlElement::IdentifierType, uint64> > &info();
|
||||
void shift(uint64 start, int64 amount);
|
||||
void parse(EbmlElement *seekHeadElement);
|
||||
void make(std::ostream &stream);
|
||||
uint64 minSize() const;
|
||||
uint64 maxSize() 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();
|
||||
|
||||
// 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(std::vector<MatroskaSeekInfo> &newSeekInfos, uint64 oldOffset, uint64 newOffset);
|
||||
|
||||
private:
|
||||
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.
|
||||
* \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;
|
||||
}
|
||||
|
@ -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.
|
||||
* \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;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Media {
|
|||
* \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;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case MatroskaIds::TagTrackUId:
|
||||
case MatroskaIds::TagTrackUID:
|
||||
m_target.tracks().emplace_back(child->readUInteger());
|
||||
break;
|
||||
case MatroskaIds::TagEditionUId:
|
||||
case MatroskaIds::TagEditionUID:
|
||||
m_target.editions().emplace_back(child->readUInteger());
|
||||
break;
|
||||
case MatroskaIds::TagChapterUId:
|
||||
case MatroskaIds::TagChapterUID:
|
||||
m_target.chapters().emplace_back(child->readUInteger());
|
||||
break;
|
||||
case MatroskaIds::TagAttachmentUId:
|
||||
case MatroskaIds::TagAttachmentUID:
|
||||
m_target.attachments().emplace_back(child->readUInteger());
|
||||
break;
|
||||
default:
|
||||
|
@ -285,7 +285,7 @@ void MatroskaTagMaker::make(ostream &stream) const
|
|||
}
|
||||
// write UIDs
|
||||
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()) {
|
||||
BE::getBytes(pair.first, buff);
|
||||
for(auto uid : pair.second) {
|
||||
|
|
|
@ -47,27 +47,39 @@ inline uint64 MatroskaTagMaker::requiredSize() const
|
|||
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:
|
||||
MatroskaTag();
|
||||
|
||||
static constexpr TagType tagType = TagType::MatroskaTag;
|
||||
// FIXME: implement type() and typeName() in FieldMapBasedTag
|
||||
TagType type() const;
|
||||
const char *typeName() const;
|
||||
TagTextEncoding proposedTextEncoding() const;
|
||||
static constexpr const char *tagName = "Matroska tag";
|
||||
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
|
||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||
bool supportsTarget() const;
|
||||
TagTargetLevel targetLevel() const;
|
||||
|
||||
std::string fieldId(KnownField field) const;
|
||||
KnownField knownField(const std::string &id) const;
|
||||
|
||||
void parse(EbmlElement &tagElement);
|
||||
MatroskaTagMaker prepareMaking();
|
||||
void make(std::ostream &stream);
|
||||
|
||||
protected:
|
||||
IdentifierType internallyGetFieldId(KnownField field) const;
|
||||
KnownField internallyGetKnownField(const IdentifierType &id) const;
|
||||
|
||||
private:
|
||||
void parseTargets(EbmlElement &targetsElement);
|
||||
};
|
||||
|
@ -88,21 +100,6 @@ inline TagTargetLevel MatroskaTag::targetLevel() const
|
|||
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
|
||||
{
|
||||
return encoding == TagTextEncoding::Utf8;
|
||||
|
|
|
@ -16,21 +16,8 @@ template <>
|
|||
class TAG_PARSER_EXPORT TagFieldTraits<MatroskaTagField>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Fields in a Matroska tag are identified by strings.
|
||||
*/
|
||||
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;
|
||||
|
||||
typedef std::string IdentifierType;
|
||||
typedef std::string TypeInfoType;
|
||||
static bool supportsNestedFields();
|
||||
};
|
||||
|
||||
|
|
|
@ -673,7 +673,7 @@ void MediaFileInfo::applyChanges()
|
|||
if(hasId3v2Tag()) {
|
||||
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_tagsParsingStatus = ParsingStatus::NotParsedYet;
|
||||
try {
|
||||
|
|
|
@ -27,21 +27,21 @@ namespace Media {
|
|||
/*!
|
||||
* \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)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \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)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \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)
|
||||
{}
|
||||
|
||||
|
|
|
@ -25,25 +25,9 @@ template <>
|
|||
class TAG_PARSER_EXPORT FileElementTraits<Mp4Atom>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief The container type used to store such elements is Mp4Container.
|
||||
*/
|
||||
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;
|
||||
typedef Mp4Container ContainerType;
|
||||
typedef uint32 IdentifierType;
|
||||
typedef uint64 DataSizeType;
|
||||
|
||||
/*!
|
||||
* \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>;
|
||||
|
||||
public:
|
||||
Mp4Atom(containerType& container, uint64 startOffset);
|
||||
Mp4Atom(ContainerType &container, uint64 startOffset);
|
||||
|
||||
std::string idToString() const;
|
||||
bool isParent() const;
|
||||
|
@ -72,8 +56,8 @@ public:
|
|||
static void makeHeader(uint64 size, uint32 id, IoUtilities::BinaryWriter &writer);
|
||||
|
||||
protected:
|
||||
Mp4Atom(containerType& container, uint64 startOffset, uint64 maxSize);
|
||||
Mp4Atom(implementationType &parent, uint64 startOffset);
|
||||
Mp4Atom(ContainerType &container, uint64 startOffset, uint64 maxSize);
|
||||
Mp4Atom(Mp4Atom &parent, uint64 startOffset);
|
||||
|
||||
void internalParse();
|
||||
|
||||
|
@ -86,7 +70,7 @@ private:
|
|||
*/
|
||||
inline std::string Mp4Atom::idToString() const
|
||||
{
|
||||
auto idString = ConversionUtilities::interpretIntegerAsString<identifierType>(id());
|
||||
auto idString = ConversionUtilities::interpretIntegerAsString<IdentifierType>(id());
|
||||
for(char &c : idString) {
|
||||
if(c < ' ') {
|
||||
c = '?';
|
||||
|
|
|
@ -685,7 +685,7 @@ calculatePadding:
|
|||
// update status
|
||||
updateStatus("Writing atom: " + level0Atom->idToString());
|
||||
// copy atom entirely and forward status update calls
|
||||
level0Atom->forwardStatusUpdateCalls(this);
|
||||
level0Atom->forwardStatus(this);
|
||||
level0Atom->copyEntirely(outputStream);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,16 +59,16 @@ const TagValue &Mp4Tag::value(KnownField field) const
|
|||
{
|
||||
switch(field) {
|
||||
case KnownField::Genre: {
|
||||
const TagValue &value = FieldMapBasedTag<fieldType>::value(Mp4TagAtomIds::Genre);
|
||||
const TagValue &value = FieldMapBasedTag<Mp4Tag>::value(Mp4TagAtomIds::Genre);
|
||||
if(!value.isEmpty()) {
|
||||
return value;
|
||||
} else {
|
||||
return FieldMapBasedTag<fieldType>::value(Mp4TagAtomIds::PreDefinedGenre);
|
||||
return FieldMapBasedTag<Mp4Tag>::value(Mp4TagAtomIds::PreDefinedGenre);
|
||||
}
|
||||
} case KnownField::EncoderSettings:
|
||||
return this->value(Mp4TagExtendedMeanIds::iTunes, Mp4TagExtendedNameIds::cdec);
|
||||
case KnownField::RecordLabel: {
|
||||
const TagValue &value = FieldMapBasedTag<fieldType>::value(Mp4TagAtomIds::RecordLabel);
|
||||
const TagValue &value = FieldMapBasedTag<Mp4Tag>::value(Mp4TagAtomIds::RecordLabel);
|
||||
if(!value.isEmpty()) {
|
||||
return value;
|
||||
} else {
|
||||
|
@ -76,13 +76,13 @@ const TagValue &Mp4Tag::value(KnownField field) const
|
|||
}
|
||||
}
|
||||
default:
|
||||
return FieldMapBasedTag<fieldType>::value(field);
|
||||
return FieldMapBasedTag<Mp4Tag>::value(field);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if(extendedId) {
|
||||
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);
|
||||
}
|
||||
|
||||
uint32 Mp4Tag::fieldId(KnownField field) const
|
||||
Mp4Tag::IdentifierType Mp4Tag::internallyGetFieldId(KnownField field) const
|
||||
{
|
||||
using namespace Mp4TagAtomIds;
|
||||
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;
|
||||
switch(id) {
|
||||
|
@ -180,10 +180,10 @@ bool Mp4Tag::setValue(KnownField field, const TagValue &value)
|
|||
switch(value.type()) {
|
||||
case TagDataType::StandardGenreIndex:
|
||||
fields().erase(Mp4TagAtomIds::Genre);
|
||||
return FieldMapBasedTag<fieldType>::setValue(Mp4TagAtomIds::PreDefinedGenre, value);
|
||||
return FieldMapBasedTag<Mp4Tag>::setValue(Mp4TagAtomIds::PreDefinedGenre, value);
|
||||
default:
|
||||
fields().erase(Mp4TagAtomIds::PreDefinedGenre);
|
||||
return FieldMapBasedTag<fieldType>::setValue(Mp4TagAtomIds::Genre, value);
|
||||
return FieldMapBasedTag<Mp4Tag>::setValue(Mp4TagAtomIds::Genre, value);
|
||||
}
|
||||
case KnownField::EncoderSettings:
|
||||
return setValue(Mp4TagExtendedMeanIds::iTunes, Mp4TagExtendedNameIds::cdec, value);
|
||||
|
@ -193,7 +193,7 @@ bool Mp4Tag::setValue(KnownField field, const TagValue &value)
|
|||
}
|
||||
FALLTHROUGH;
|
||||
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());
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
fields().insert(make_pair(Mp4TagAtomIds::Extended, fieldType(mean, name, value)));
|
||||
fields().insert(make_pair(Mp4TagAtomIds::Extended, FieldType(mean, name, value)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -260,10 +260,10 @@ bool Mp4Tag::hasField(KnownField field) const
|
|||
{
|
||||
switch(field) {
|
||||
case KnownField::Genre:
|
||||
return FieldMapBasedTag<fieldType>::hasField(Mp4TagAtomIds::PreDefinedGenre)
|
||||
|| FieldMapBasedTag<fieldType>::hasField(Mp4TagAtomIds::Genre);
|
||||
return FieldMapBasedTag<Mp4Tag>::hasField(Mp4TagAtomIds::PreDefinedGenre)
|
||||
|| FieldMapBasedTag<Mp4Tag>::hasField(Mp4TagAtomIds::Genre);
|
||||
default:
|
||||
return FieldMapBasedTag<fieldType>::hasField(field);
|
||||
return FieldMapBasedTag<Mp4Tag>::hasField(field);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,7 +320,7 @@ void Mp4Tag::parse(Mp4Atom &metaAtom)
|
|||
child->parse();
|
||||
tagField.invalidateNotifications();
|
||||
tagField.reparse(*child);
|
||||
fields().insert(pair<fieldType::identifierType, fieldType>(child->id(), tagField));
|
||||
fields().emplace(child->id(), tagField);
|
||||
} catch(const Failure &) {
|
||||
}
|
||||
addNotifications(context, *child);
|
||||
|
|
54
mp4/mp4tag.h
54
mp4/mp4tag.h
|
@ -87,44 +87,59 @@ inline uint64 Mp4TagMaker::requiredSize() const
|
|||
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:
|
||||
Mp4Tag();
|
||||
|
||||
static constexpr TagType tagType = TagType::Mp4Tag;
|
||||
TagType type() const;
|
||||
const char *typeName() const;
|
||||
TagTextEncoding proposedTextEncoding() const;
|
||||
static constexpr const char *tagName = "MP4/iTunes tag";
|
||||
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
|
||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||
|
||||
uint32 fieldId(KnownField field) const;
|
||||
KnownField knownField(const uint32 &id) const;
|
||||
bool supportsField(KnownField field) const;
|
||||
using FieldMapBasedTag<Mp4TagField>::value;
|
||||
using FieldMapBasedTag<Mp4Tag>::value;
|
||||
const TagValue &value(KnownField value) const;
|
||||
using FieldMapBasedTag<Mp4TagField>::values;
|
||||
using FieldMapBasedTag<Mp4Tag>::values;
|
||||
std::vector<const TagValue *> values(KnownField field) const;
|
||||
#ifdef LEGACY_API
|
||||
const TagValue &value(const std::string mean, const std::string name) const;
|
||||
#endif
|
||||
const TagValue &value(const std::string &mean, const std::string &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);
|
||||
using FieldMapBasedTag<Mp4TagField>::setValues;
|
||||
using FieldMapBasedTag<Mp4Tag>::setValues;
|
||||
bool setValues(KnownField field, const std::vector<TagValue> &values);
|
||||
#ifdef LEGACY_API
|
||||
bool setValue(const std::string mean, const std::string name, const TagValue &value);
|
||||
#endif
|
||||
bool setValue(const std::string &mean, const std::string &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;
|
||||
|
||||
void parse(Mp4Atom &metaAtom);
|
||||
Mp4TagMaker prepareMaking();
|
||||
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 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
|
||||
{
|
||||
switch(field) {
|
||||
case KnownField::EncoderSettings:
|
||||
return true;
|
||||
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.
|
||||
*/
|
||||
Mp4TagField::Mp4TagField(identifierType id, const TagValue &value) :
|
||||
Mp4TagField::Mp4TagField(IdentifierType id, const TagValue &value) :
|
||||
TagField<Mp4TagField>(id, value),
|
||||
m_parsedRawDataType(RawDataType::Reserved),
|
||||
m_countryIndicator(0),
|
||||
|
|
|
@ -57,20 +57,8 @@ template <>
|
|||
class TAG_PARSER_EXPORT TagFieldTraits<Mp4TagField>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Fields in a iTunes-style MP4 tag are identified by 32-bit unsigned integers.
|
||||
*/
|
||||
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;
|
||||
typedef uint32 IdentifierType;
|
||||
typedef uint32 TypeInfoType;
|
||||
};
|
||||
|
||||
class Mp4Atom;
|
||||
|
@ -117,7 +105,7 @@ class TAG_PARSER_EXPORT Mp4TagField : public TagField<Mp4TagField>, public Statu
|
|||
|
||||
public:
|
||||
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);
|
||||
|
||||
void reparse(Mp4Atom &ilstChild);
|
||||
|
@ -136,8 +124,8 @@ public:
|
|||
std::vector<uint32> expectedRawDataTypes() const;
|
||||
uint32 appropriateRawDataType() const;
|
||||
|
||||
static identifierType fieldIdFromString(const char *idString, std::size_t idStringSize = std::string::npos);
|
||||
static std::string fieldIdToString(identifierType id);
|
||||
static IdentifierType fieldIdFromString(const char *idString, std::size_t idStringSize = std::string::npos);
|
||||
static std::string fieldIdToString(IdentifierType id);
|
||||
|
||||
protected:
|
||||
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
|
||||
* 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));
|
||||
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
|
||||
* 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);
|
||||
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
|
||||
* 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)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \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)
|
||||
{}
|
||||
|
||||
|
@ -75,12 +75,12 @@ void Mpeg4Descriptor::internalParse()
|
|||
m_dataSize = maxTotalSize(); // using max size instead
|
||||
}
|
||||
m_firstChild.reset();
|
||||
implementationType *sibling = nullptr;
|
||||
Mpeg4Descriptor *sibling = nullptr;
|
||||
if(totalSize() < maxTotalSize()) {
|
||||
if(parent()) {
|
||||
sibling = new implementationType(*(parent()), startOffset() + totalSize());
|
||||
sibling = new Mpeg4Descriptor(*(parent()), startOffset() + totalSize());
|
||||
} else {
|
||||
sibling = new implementationType(container(), startOffset() + totalSize(), maxTotalSize() - totalSize());
|
||||
sibling = new Mpeg4Descriptor(container(), startOffset() + totalSize(), maxTotalSize() - totalSize());
|
||||
}
|
||||
}
|
||||
m_nextSibling.reset(sibling);
|
||||
|
|
|
@ -17,25 +17,9 @@ template <>
|
|||
class TAG_PARSER_EXPORT FileElementTraits<Mpeg4Descriptor>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief The container type used to store such elements is Mp4Container.
|
||||
*/
|
||||
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;
|
||||
typedef Mp4Container ContainerType;
|
||||
typedef byte IdentifierType;
|
||||
typedef uint32 DataSizeType;
|
||||
|
||||
/*!
|
||||
* \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>;
|
||||
|
||||
public:
|
||||
Mpeg4Descriptor(containerType& container, uint64 startOffset, uint64 maxSize);
|
||||
Mpeg4Descriptor(ContainerType &container, uint64 startOffset, uint64 maxSize);
|
||||
|
||||
std::string idToString() const;
|
||||
bool isParent() const;
|
||||
|
@ -59,7 +43,7 @@ public:
|
|||
uint64 firstChildOffset() const;
|
||||
|
||||
protected:
|
||||
Mpeg4Descriptor(implementationType &parent, uint64 startOffset);
|
||||
Mpeg4Descriptor(Mpeg4Descriptor &parent, uint64 startOffset);
|
||||
|
||||
void internalParse();
|
||||
|
||||
|
|
|
@ -52,6 +52,10 @@ size_t StatusProvider::registerCallback(CallbackFunction callback)
|
|||
*/
|
||||
void StatusProvider::addNotification(const Notification ¬ification)
|
||||
{
|
||||
if(m_forward) {
|
||||
m_forward->addNotification(notification);
|
||||
return;
|
||||
}
|
||||
m_notifications.push_back(notification);
|
||||
m_worstNotificationType |= notification.type();
|
||||
invokeCallbacks();
|
||||
|
@ -63,6 +67,10 @@ void StatusProvider::addNotification(const Notification ¬ification)
|
|||
*/
|
||||
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_worstNotificationType |= type;
|
||||
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
|
||||
* 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) {
|
||||
return;
|
||||
}
|
||||
m_notifications.insert(m_notifications.end(), from.m_notifications.cbegin(), from.m_notifications.cend());
|
||||
m_worstNotificationType |= from.worstNotificationType();
|
||||
invokeCallbacks();
|
||||
}
|
||||
}*/
|
||||
|
||||
/*!
|
||||
* \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.
|
||||
*/
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
for(const auto ¬ification : from.m_notifications) {
|
||||
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.
|
||||
*/
|
||||
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());
|
||||
if(m_worstNotificationType != Notification::worstNotificationType()) {
|
||||
for(const Notification ¬ification : notifications) {
|
||||
|
@ -112,6 +132,7 @@ void StatusProvider::addNotifications(const NotificationList ¬ifications)
|
|||
}
|
||||
}
|
||||
invokeCallbacks();
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ public:
|
|||
size_t registerCallback(CallbackFunction callback);
|
||||
void unregisterCallback(size_t id);
|
||||
void unregisterAllCallbacks();
|
||||
void forwardStatusUpdateCalls(StatusProvider *other = nullptr);
|
||||
inline StatusProvider *usedProvider();
|
||||
void forwardStatus(StatusProvider *other = nullptr);
|
||||
StatusProvider *usedProvider();
|
||||
void tryToAbort();
|
||||
bool isAborted() const;
|
||||
void invalidateStatus();
|
||||
|
@ -40,25 +40,25 @@ public:
|
|||
void updatePercentage(double percentage);
|
||||
void addNotification(const Notification ¬ification);
|
||||
void addNotification(NotificationType type, const std::string &message, const std::string &context);
|
||||
void addNotifications(const StatusProvider &from);
|
||||
void addNotifications(const std::string &higherContext, const StatusProvider &from);
|
||||
void addNotifications(const NotificationList ¬ifications);
|
||||
//void addNotifications(const StatusProvider &from);
|
||||
//void addNotifications(const std::string &higherContext, const StatusProvider &from);
|
||||
//void addNotifications(const NotificationList ¬ifications);
|
||||
|
||||
protected:
|
||||
StatusProvider();
|
||||
|
||||
private:
|
||||
inline void invokeCallbacks();
|
||||
inline void updateWorstNotificationType(NotificationType notificationType);
|
||||
inline void transferNotifications(StatusProvider &from);
|
||||
void invokeCallbacks();
|
||||
void updateWorstNotificationType(NotificationType notificationType);
|
||||
//void transferNotifications(StatusProvider &from);
|
||||
|
||||
NotificationList m_notifications;
|
||||
NotificationType m_worstNotificationType;
|
||||
StatusProvider *m_forward;
|
||||
std::string m_status;
|
||||
double m_percentage;
|
||||
CallbackVector m_callbacks;
|
||||
NotificationList m_notifications;
|
||||
NotificationType m_worstNotificationType;
|
||||
bool m_abort;
|
||||
StatusProvider *m_forward;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -66,6 +66,10 @@ private:
|
|||
*/
|
||||
inline void StatusProvider::updateStatus(const std::string &status)
|
||||
{
|
||||
if(m_forward) {
|
||||
m_forward->updateStatus(status);
|
||||
return;
|
||||
}
|
||||
m_status = status;
|
||||
invokeCallbacks();
|
||||
}
|
||||
|
@ -77,6 +81,10 @@ inline void StatusProvider::updateStatus(const std::string &status)
|
|||
*/
|
||||
inline void StatusProvider::updateStatus(const std::string &status, double percentage)
|
||||
{
|
||||
if(m_forward) {
|
||||
m_forward->updateStatus(status, percentage);
|
||||
return;
|
||||
}
|
||||
m_status = status;
|
||||
m_percentage = percentage;
|
||||
invokeCallbacks();
|
||||
|
@ -89,6 +97,10 @@ inline void StatusProvider::updateStatus(const std::string &status, double perce
|
|||
*/
|
||||
inline void StatusProvider::updatePercentage(double percentage)
|
||||
{
|
||||
if(m_forward) {
|
||||
m_forward->updatePercentage(percentage);
|
||||
return;
|
||||
}
|
||||
m_percentage = percentage;
|
||||
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.
|
||||
*
|
||||
* 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()
|
||||
{
|
||||
|
@ -160,7 +172,7 @@ inline double StatusProvider::currentPercentage() const
|
|||
/*!
|
||||
* \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.
|
||||
*/
|
||||
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
|
||||
* to inform about status updates. Instead the callback methods associated to
|
||||
* This basically forwards status information updates and notifications to the specified instance.
|
||||
*
|
||||
* \remarks
|
||||
* - Any notifications will *not* be added to the current instance anymore. Instead the
|
||||
* notifications will be added to the specified instance.
|
||||
* - 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 specified instance will be called.
|
||||
*
|
||||
* The current instance is still the sender.
|
||||
*
|
||||
* The current instance is considered as abortet if the specified provider is
|
||||
* abortet even if tryToAbort() has not been called.
|
||||
*
|
||||
* The current instance will return the status and percentage of the specified
|
||||
* - 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
|
||||
* aborted - even if tryToAbort() has not been called on the current instance.
|
||||
* - The current instance will return the status and percentage of the specified
|
||||
* provider if it provides no own status or percentage.
|
||||
*
|
||||
* Provide nullptr to revert to the default behaviour.
|
||||
*
|
||||
* \remarks Leads to endless recursion if \a statusProvider forwards (indirectly
|
||||
* 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;
|
||||
}
|
||||
|
@ -272,7 +288,11 @@ inline void StatusProvider::invokeCallbacks()
|
|||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
* the notifications are transfered. It also doesn't check whether \a from is the current instance and doesn't
|
||||
* 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_worstNotificationType |= from.worstNotificationType();
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -152,8 +152,7 @@ void OverallTests::checkMkvTestfile3()
|
|||
|
||||
/*!
|
||||
* \brief Checks "matroska_wave1/test4.mkv".
|
||||
* \remarks This file is using the EBML feature that allows Master elements to have no known size. Handling
|
||||
* such files is not supported yet.
|
||||
* \remarks This file is using the EBML feature that allows Master elements to have no known size.
|
||||
*/
|
||||
void OverallTests::checkMkvTestfile4()
|
||||
{
|
||||
|
|
|
@ -156,7 +156,7 @@ void UtilitiesTests::testStatusProvider()
|
|||
|
||||
// forwarding
|
||||
TestStatusProvider forwardReceiver;
|
||||
status.forwardStatusUpdateCalls(&forwardReceiver);
|
||||
status.forwardStatus(&forwardReceiver);
|
||||
statusUpdateReceived = false;
|
||||
forwardReceiver.registerCallback([&status, &statusUpdateReceived] (StatusProvider &sender) {
|
||||
CPPUNIT_ASSERT(&status == &sender);
|
||||
|
|
|
@ -29,7 +29,7 @@ const TagValue &VorbisComment::value(KnownField field) const
|
|||
case KnownField::Vendor:
|
||||
return vendor();
|
||||
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);
|
||||
return true;
|
||||
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;
|
||||
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;
|
||||
static const map<string, KnownField> fieldMap({
|
||||
|
@ -145,7 +145,7 @@ void VorbisComment::internalParse(StreamType &stream, uint64 maxSize, VorbisComm
|
|||
// read fields
|
||||
try {
|
||||
field.parse(stream, maxSize);
|
||||
fields().insert(pair<fieldType::identifierType, fieldType>(fieldId, field));
|
||||
fields().emplace(fieldId, field);
|
||||
} catch(const TruncatedDataException &) {
|
||||
addNotifications(field);
|
||||
throw;
|
||||
|
|
|
@ -12,21 +12,33 @@ namespace Media {
|
|||
class OggIterator;
|
||||
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:
|
||||
VorbisComment();
|
||||
|
||||
static constexpr TagType tagType = TagType::VorbisComment;
|
||||
TagType type() const;
|
||||
const char *typeName() const;
|
||||
TagTextEncoding proposedTextEncoding() const;
|
||||
static constexpr const char *tagName = "Vorbis comment";
|
||||
static constexpr TagTextEncoding defaultTextEncoding = TagTextEncoding::Utf8;
|
||||
bool canEncodingBeUsed(TagTextEncoding encoding) const;
|
||||
|
||||
using FieldMapBasedTag<VorbisComment>::value;
|
||||
const TagValue &value(KnownField field) const;
|
||||
using FieldMapBasedTag<VorbisComment>::setValue;
|
||||
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(std::istream &stream, uint64 maxSize, VorbisCommentFlags flags = VorbisCommentFlags::None);
|
||||
|
@ -35,6 +47,10 @@ public:
|
|||
const TagValue &vendor() const;
|
||||
void setVendor(const TagValue &vendor);
|
||||
|
||||
protected:
|
||||
IdentifierType internallyGetFieldId(KnownField field) const;
|
||||
KnownField internallyGetKnownField(const IdentifierType &id) const;
|
||||
|
||||
private:
|
||||
template<class StreamType>
|
||||
void internalParse(StreamType &stream, uint64 maxSize, VorbisCommentFlags flags);
|
||||
|
@ -49,21 +65,6 @@ private:
|
|||
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
|
||||
{
|
||||
return encoding == TagTextEncoding::Utf8;
|
||||
|
|
|
@ -38,7 +38,7 @@ VorbisCommentField::VorbisCommentField()
|
|||
/*!
|
||||
* \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)
|
||||
{}
|
||||
|
||||
|
|
|
@ -41,18 +41,8 @@ template <>
|
|||
class TAG_PARSER_EXPORT TagFieldTraits<VorbisCommentField>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Fields in a Vorbis comment are identified by 32-bit unsigned integers.
|
||||
*/
|
||||
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;
|
||||
typedef std::string IdentifierType;
|
||||
typedef uint32 TypeInfoType;
|
||||
};
|
||||
|
||||
class OggIterator;
|
||||
|
@ -63,7 +53,7 @@ class TAG_PARSER_EXPORT VorbisCommentField : public TagField<VorbisCommentField>
|
|||
|
||||
public:
|
||||
VorbisCommentField();
|
||||
VorbisCommentField(const identifierType &id, const TagValue &value);
|
||||
VorbisCommentField(const IdentifierType &id, const TagValue &value);
|
||||
|
||||
void parse(OggIterator &iterator);
|
||||
void parse(OggIterator &iterator, uint64 &maxSize);
|
||||
|
|
Loading…
Reference in New Issue