Compare commits

...

15 Commits

Author SHA1 Message Date
Marius Kittler 53701255ca WIP: Rework notifications 2017-11-16 17:54:42 +01:00
Marius Kittler e232c907ea status provider: Use inline not inside the class definition 2017-11-16 17:13:58 +01:00
Marius Kittler d5613954a4 Remove unnecessary cast 2017-11-16 17:12:21 +01:00
Martchus 44af199aeb Use unordered_map in MatroskaCuePositionUpdater
std::unordered_map should be faster than std::map
2017-10-30 20:48:30 +01:00
Martchus b69aab0cd1 Handle Mkv files with unknown element sizes correctly
Those elements are still assumed to fill the max available
space. However, if it turns out one "child" is more likely
a sibling, the wrong assumption is fixed.
2017-10-30 20:48:30 +01:00
Martchus 618efe3f96 Add function to determine Mkv element level by ID
Does not cover all element IDs but should be more
than sufficient for its purpose.
2017-10-30 20:48:30 +01:00
Martchus fdb23e3cd0 Add method to get last child of file element 2017-10-30 20:48:30 +01:00
Martchus bf31c9e89f Add methods to get n-th parent of file element 2017-10-30 20:48:30 +01:00
Martchus 4231f2679e Add method to determine level of file element 2017-10-30 20:48:30 +01:00
Martchus 8109f84f38 Allow specifying whether the size of an element is unknown 2017-10-30 20:48:30 +01:00
Martchus 1814cd9bfc Uniform spelling of Matroska IDs 2017-10-30 20:48:30 +01:00
Martchus 0f12cf346c Uniform/simplify typedefs in templates
* Begin type names with capital letter
* Remove typedefs for implementation type
* Remove useless/obsolete comments
* Simplify relevant code
2017-10-30 20:48:30 +01:00
Martchus 86d51f1e96 Use static polymorphism in FieldMapBasedTag 2017-10-30 20:48:30 +01:00
Martchus 90eac982a7 Restructure FieldMapBasedTag to use CRTP 2017-10-30 20:48:30 +01:00
Martchus 001cfc931d Update major version to 7 2017-10-30 20:48:30 +01:00
40 changed files with 892 additions and 538 deletions

View File

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

View File

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

View File

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

View File

@ -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);
}
/*!

View File

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

View File

@ -30,7 +30,7 @@ TagType Id3v1Tag::type() const
const char *Id3v1Tag::typeName() const
{
return "ID3v1 tag";
return tagName;
}
bool Id3v1Tag::canEncodingBeUsed(TagTextEncoding encoding) const

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
}

View File

@ -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;
};
/*!

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
};

View File

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

View File

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

View File

@ -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 = '?';

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,6 +52,10 @@ size_t StatusProvider::registerCallback(CallbackFunction callback)
*/
void StatusProvider::addNotification(const Notification &notification)
{
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 &notification)
*/
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 &notification : 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 &notifications)
/*void StatusProvider::addNotifications(const NotificationList &notifications)
{
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 &notification : notifications) {
@ -112,6 +132,7 @@ void StatusProvider::addNotifications(const NotificationList &notifications)
}
}
invokeCallbacks();
}
}*/
}

View File

@ -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 &notification);
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 &notifications);
//void addNotifications(const StatusProvider &from);
//void addNotifications(const std::string &higherContext, const StatusProvider &from);
//void addNotifications(const NotificationList &notifications);
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
* the specified instance will be called.
* This basically forwards status information updates and notifications to the specified instance.
*
* 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
* 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.
* \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 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.
* - 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();
}
}*/
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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