Martchus
7a02e8a325
* Begin type names with capital letter * Remove typedefs for implementation type * Remove useless/obsolete comments * Simplify relevant code
380 lines
13 KiB
C++
380 lines
13 KiB
C++
#ifndef MEDIA_GENERICCONTAINER_H
|
|
#define MEDIA_GENERICCONTAINER_H
|
|
|
|
#include "./abstractcontainer.h"
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <memory>
|
|
|
|
namespace Media {
|
|
|
|
/*!
|
|
* \class Media::GenericContainer
|
|
* \brief The GenericContainer class helps parsing header, track, tag and chapter information
|
|
* of a file.
|
|
*
|
|
* \tparam FileInfoType Specifies the file info class (a class derived from Media::BasicFileInfo) which is used to specify the related file.
|
|
* \tparam TagType Specifies the class which is used to deal with the tag information of the file.
|
|
* \tparam TrackType Specifies the class which is used to deal with the track of the file.
|
|
* \tparam ElementType Specifies the class which is used to deal with the elements the file consists of.
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
class TAG_PARSER_EXPORT GenericContainer : public AbstractContainer
|
|
{
|
|
friend FileInfoType;
|
|
|
|
public:
|
|
GenericContainer(FileInfoType &fileInfo, uint64 startOffset);
|
|
~GenericContainer();
|
|
|
|
void validateElementStructure(NotificationList &gatheredNotifications, uint64 *paddingSize = nullptr);
|
|
FileInfoType &fileInfo() const;
|
|
ElementType *firstElement() const;
|
|
const std::vector<std::unique_ptr<ElementType> > &additionalElements() const;
|
|
std::vector<std::unique_ptr<ElementType> > &additionalElements();
|
|
TagType *tag(std::size_t index);
|
|
std::size_t tagCount() const;
|
|
TrackType *track(std::size_t index);
|
|
TrackType *trackById(uint64 id);
|
|
std::size_t trackCount() const;
|
|
const std::vector<std::unique_ptr<TagType> > &tags() const;
|
|
std::vector<std::unique_ptr<TagType> > &tags();
|
|
const std::vector<std::unique_ptr<TrackType> > &tracks() const;
|
|
std::vector<std::unique_ptr<TrackType> > &tracks();
|
|
|
|
TagType *createTag(const TagTarget &target = TagTarget());
|
|
bool removeTag(Tag *tag);
|
|
void removeAllTags();
|
|
bool addTrack(TrackType *track);
|
|
bool removeTrack(AbstractTrack *track);
|
|
void removeAllTracks();
|
|
void reset();
|
|
|
|
typedef FileInfoType ContainerFileInfoType;
|
|
typedef TagType ContainerTagType;
|
|
typedef TrackType ContainerTrackType;
|
|
typedef ElementType ContainerElementType;
|
|
|
|
protected:
|
|
std::unique_ptr<ElementType> m_firstElement;
|
|
std::vector<std::unique_ptr<ElementType> > m_additionalElements;
|
|
std::vector<std::unique_ptr<TagType> > m_tags;
|
|
std::vector<std::unique_ptr<TrackType> > m_tracks;
|
|
|
|
private:
|
|
FileInfoType *m_fileInfo;
|
|
};
|
|
|
|
/*!
|
|
* \brief Constructs a new container for the specified \a fileInfo at the specified \a startOffset.
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
GenericContainer<FileInfoType, TagType, TrackType, ElementType>::GenericContainer(FileInfoType &fileInfo, uint64 startOffset) :
|
|
AbstractContainer(fileInfo.stream(), startOffset),
|
|
m_fileInfo(&fileInfo)
|
|
{}
|
|
|
|
/*!
|
|
* \brief Destroys the container.
|
|
*
|
|
* Destroys the reader, the writer and track, tag, chapter and attachment objects as well.
|
|
* Does NOT destroy the stream which has been specified when constructing the object.
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
GenericContainer<FileInfoType, TagType, TrackType, ElementType>::~GenericContainer()
|
|
{}
|
|
|
|
/*!
|
|
* \brief Parses all elements the file consists of.
|
|
*
|
|
* All parsing notifications will be stored in \a gatheredNotifications.
|
|
* The size of padding/void elements will be accumulated and stored in
|
|
* at \a paddingSize if it is not a null pointer.
|
|
*
|
|
* \throws Throws Failure or a derived class when a parsing error occurs.
|
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline void GenericContainer<FileInfoType, TagType, TrackType, ElementType>::validateElementStructure(NotificationList &gatheredNotifications, uint64 *paddingSize)
|
|
{
|
|
parseHeader();
|
|
if(m_firstElement) {
|
|
m_firstElement->validateSubsequentElementStructure(gatheredNotifications, paddingSize);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the related file info.
|
|
*
|
|
* The related file info has been specefied when constructing the container.
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline FileInfoType &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::fileInfo() const
|
|
{
|
|
return *m_fileInfo;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the first element of the file if available; otherwiese returns nullptr.
|
|
*
|
|
* This method gives access to the element structure of the container - the entire element tree
|
|
* can be looked up using the nextSibling() and firstChild() methods of the returned element.
|
|
*
|
|
* The header needs to be parsed before (see parseHeader()).
|
|
*
|
|
* The container keeps ownership over the returned element.
|
|
*
|
|
* \sa isHeaderParsed()
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline ElementType *GenericContainer<FileInfoType, TagType, TrackType, ElementType>::firstElement() const
|
|
{
|
|
return m_firstElement.get();
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns all available additional elements.
|
|
*
|
|
* The parser might decide to split up a file's element tree to skip irrelevant elements to achive better performance.
|
|
* This method gives access to those sub element trees. Each of the returned elements represents an independent element
|
|
* tree within the file.
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline const std::vector<std::unique_ptr<ElementType> > &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::additionalElements() const
|
|
{
|
|
return m_additionalElements;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns all available additional elements.
|
|
*
|
|
* The parser might decide to split up a file's element tree to skip irrelevant elements to achive better performance.
|
|
* This method gives access to those sub element trees. Each of the returned elements represents an independent element
|
|
* tree within the file.
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline std::vector<std::unique_ptr<ElementType> > &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::additionalElements()
|
|
{
|
|
return m_additionalElements;
|
|
}
|
|
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline TagType *GenericContainer<FileInfoType, TagType, TrackType, ElementType>::tag(std::size_t index)
|
|
{
|
|
return m_tags[index].get();
|
|
}
|
|
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline std::size_t GenericContainer<FileInfoType, TagType, TrackType, ElementType>::tagCount() const
|
|
{
|
|
return m_tags.size();
|
|
}
|
|
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline TrackType *GenericContainer<FileInfoType, TagType, TrackType, ElementType>::track(std::size_t index)
|
|
{
|
|
return m_tracks[index].get();
|
|
}
|
|
|
|
template<class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline TrackType *GenericContainer<FileInfoType, TagType, TrackType, ElementType>::trackById(uint64 id)
|
|
{
|
|
for (auto &track : m_tracks) {
|
|
if(track->id() == id) {
|
|
return track.get();
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline std::size_t GenericContainer<FileInfoType, TagType, TrackType, ElementType>::trackCount() const
|
|
{
|
|
return m_tracks.size();
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the tags of the file.
|
|
*
|
|
* The tags need to be parsed before (see parseTags()).
|
|
*
|
|
* The container keeps ownership over the returned tags.
|
|
*
|
|
* \sa areTagsParsed()
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline const std::vector<std::unique_ptr<TagType> > &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::tags() const
|
|
{
|
|
return m_tags;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the tags of the file.
|
|
*
|
|
* The tags need to be parsed before (see parseTags()).
|
|
*
|
|
* The container keeps ownership over the returned tags. Do not push or remove elements to the returned vector.
|
|
*
|
|
* \sa areTagsParsed()
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline std::vector<std::unique_ptr<TagType> > &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::tags()
|
|
{
|
|
return m_tags;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the tracks of the file.
|
|
*
|
|
* The tags need to be parsed before (see parseTracks()).
|
|
*
|
|
* The container keeps ownership over the returned tracks.
|
|
*
|
|
* \sa areTracksParsed()
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline const std::vector<std::unique_ptr<TrackType> > &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::tracks() const
|
|
{
|
|
return m_tracks;
|
|
}
|
|
|
|
/*!
|
|
* \brief Returns the tracks of the file.
|
|
*
|
|
* The tags need to be parsed before (see parseTracks()).
|
|
*
|
|
* The container keeps ownership over the returned tracks. Do not push or remove elements to the returned vector.
|
|
*
|
|
* \sa areTracksParsed()
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline std::vector<std::unique_ptr<TrackType> > &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::tracks()
|
|
{
|
|
return m_tracks;
|
|
}
|
|
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
TagType *GenericContainer<FileInfoType, TagType, TrackType, ElementType>::createTag(const TagTarget &target)
|
|
{
|
|
// check whether a tag matching the specified target is already assigned
|
|
if(!m_tags.empty()) {
|
|
if(!target.isEmpty() && m_tags.front()->supportsTarget()) {
|
|
for(auto &tag : m_tags) {
|
|
if(tag->target() == target) {
|
|
return tag.get();
|
|
}
|
|
}
|
|
} else {
|
|
return m_tags.front().get();
|
|
}
|
|
}
|
|
|
|
// a new tag must be created
|
|
m_tags.emplace_back(std::make_unique<TagType>());
|
|
auto &tag = m_tags.back();
|
|
tag->setTarget(target);
|
|
return tag.get();
|
|
}
|
|
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
bool GenericContainer<FileInfoType, TagType, TrackType, ElementType>::removeTag(Tag *tag)
|
|
{
|
|
if(auto size = m_tags.size()) {
|
|
m_tags.erase(std::remove_if(m_tags.begin(), m_tags.end(), [tag] (const std::unique_ptr<TagType> &existingTag) -> bool {
|
|
return static_cast<Tag *>(existingTag.get()) == tag;
|
|
}), m_tags.end());
|
|
return size != m_tags.size();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
inline void GenericContainer<FileInfoType, TagType, TrackType, ElementType>::removeAllTags()
|
|
{
|
|
m_tags.clear();
|
|
}
|
|
|
|
/*!
|
|
* \brief Adds the specified \a track to the container.
|
|
*
|
|
* Adding tracks might be not supported by the implementation.
|
|
* \sa supportsTrackModifications()
|
|
*
|
|
* The tracks needs to be parsed before additional tracks can be added.
|
|
* \sa areTracksParsed()
|
|
* \sa parseTracks()
|
|
*
|
|
* \remarks The container takes ownership over the specified \a track if it was possible
|
|
* to add the track. This makes adding a track from another container impossible
|
|
* without removing it from the other container first.
|
|
*
|
|
* \returns Returns an indication whether the \a track could be added.
|
|
*/
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
bool GenericContainer<FileInfoType, TagType, TrackType, ElementType>::addTrack(TrackType *track)
|
|
{
|
|
if(areTracksParsed() && supportsTrackModifications()) {
|
|
// ensure ID is unique
|
|
auto id = track->id();
|
|
ensureIdIsUnique:
|
|
for(const auto &track : m_tracks) {
|
|
if(track->id() == id) {
|
|
++id;
|
|
goto ensureIdIsUnique;
|
|
}
|
|
}
|
|
track->setId(id);
|
|
|
|
m_tracks.emplace_back(track);
|
|
return m_tracksAltered = true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
bool GenericContainer<FileInfoType, TagType, TrackType, ElementType>::removeTrack(AbstractTrack *track)
|
|
{
|
|
bool removed = false;
|
|
if(areTracksParsed() && supportsTrackModifications() && !m_tracks.empty()) {
|
|
for(auto i = m_tracks.end() - 1, begin = m_tracks.begin(); ; --i) {
|
|
if(static_cast<AbstractTrack *>(i->get()) == track) {
|
|
i->release();
|
|
m_tracks.erase(i);
|
|
removed = true;
|
|
}
|
|
if(i == begin) {
|
|
break;
|
|
}
|
|
}
|
|
if(removed) {
|
|
m_tracksAltered = true;
|
|
}
|
|
}
|
|
return removed;
|
|
}
|
|
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
void GenericContainer<FileInfoType, TagType, TrackType, ElementType>::removeAllTracks()
|
|
{
|
|
if(areTracksParsed() && supportsTrackModifications() && m_tracks.size()) {
|
|
m_tracks.clear();
|
|
m_tracksAltered = true;
|
|
}
|
|
}
|
|
|
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
|
void GenericContainer<FileInfoType, TagType, TrackType, ElementType>::reset()
|
|
{
|
|
AbstractContainer::reset();
|
|
m_firstElement.reset();
|
|
m_additionalElements.clear();
|
|
m_tracks.clear();
|
|
m_tags.clear();
|
|
}
|
|
|
|
} // namespace Media
|
|
|
|
#endif // MEDIA_GENERICCONTAINER_H
|