Tag Parser  7.0.1
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
genericcontainer.h
Go to the documentation of this file.
1 #ifndef TAG_PARSER_GENERICCONTAINER_H
2 #define TAG_PARSER_GENERICCONTAINER_H
3 
4 #include "./abstractcontainer.h"
5 
6 #include <algorithm>
7 #include <memory>
8 #include <vector>
9 
10 namespace TagParser {
11 
22 template <class FileInfoType, class TagType, class TrackType, class ElementType> class TAG_PARSER_EXPORT GenericContainer : public AbstractContainer {
23  friend FileInfoType;
24 
25 public:
26  GenericContainer(FileInfoType &fileInfo, uint64 startOffset);
27  ~GenericContainer() override;
28 
29  void validateElementStructure(Diagnostics &diag, uint64 *paddingSize = nullptr);
30  FileInfoType &fileInfo() const;
31  ElementType *firstElement() const;
32  const std::vector<std::unique_ptr<ElementType>> &additionalElements() const;
33  std::vector<std::unique_ptr<ElementType>> &additionalElements();
34  TagType *tag(std::size_t index) override;
35  std::size_t tagCount() const override;
36  TrackType *track(std::size_t index) override;
37  TrackType *trackById(uint64 id);
38  std::size_t trackCount() const override;
39  const std::vector<std::unique_ptr<TagType>> &tags() const;
40  std::vector<std::unique_ptr<TagType>> &tags();
41  const std::vector<std::unique_ptr<TrackType>> &tracks() const;
42  std::vector<std::unique_ptr<TrackType>> &tracks();
43 
44  TagType *createTag(const TagTarget &target = TagTarget()) override;
45  bool removeTag(Tag *tag) override;
46  void removeAllTags() override;
47  bool addTrack(TrackType *track);
48  bool removeTrack(AbstractTrack *track) override;
49  void removeAllTracks() override;
50  void reset() override;
51 
52  typedef FileInfoType ContainerFileInfoType;
55  typedef ElementType ContainerElementType;
56 
57 protected:
58  std::unique_ptr<ElementType> m_firstElement;
59  std::vector<std::unique_ptr<ElementType>> m_additionalElements;
60  std::vector<std::unique_ptr<TagType>> m_tags;
61  std::vector<std::unique_ptr<TrackType>> m_tracks;
62 
63 private:
64  FileInfoType *m_fileInfo;
65 };
66 
70 template <class FileInfoType, class TagType, class TrackType, class ElementType>
72  : AbstractContainer(fileInfo.stream(), startOffset)
73  , m_fileInfo(&fileInfo)
74 {
75 }
76 
83 template <class FileInfoType, class TagType, class TrackType, class ElementType>
85 {
86 }
87 
98 template <class FileInfoType, class TagType, class TrackType, class ElementType>
100 {
101  parseHeader(diag);
102  if (m_firstElement) {
103  m_firstElement->validateSubsequentElementStructure(diag, paddingSize);
104  }
105 }
106 
112 template <class FileInfoType, class TagType, class TrackType, class ElementType>
114 {
115  return *m_fileInfo;
116 }
117 
130 template <class FileInfoType, class TagType, class TrackType, class ElementType>
132 {
133  return m_firstElement.get();
134 }
135 
143 template <class FileInfoType, class TagType, class TrackType, class ElementType>
144 inline const std::vector<std::unique_ptr<ElementType>> &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::additionalElements() const
145 {
146  return m_additionalElements;
147 }
148 
156 template <class FileInfoType, class TagType, class TrackType, class ElementType>
158 {
159  return m_additionalElements;
160 }
161 
162 template <class FileInfoType, class TagType, class TrackType, class ElementType>
164 {
165  return m_tags[index].get();
166 }
167 
168 template <class FileInfoType, class TagType, class TrackType, class ElementType>
170 {
171  return m_tags.size();
172 }
173 
174 template <class FileInfoType, class TagType, class TrackType, class ElementType>
176 {
177  return m_tracks[index].get();
178 }
179 
180 template <class FileInfoType, class TagType, class TrackType, class ElementType>
182 {
183  for (auto &track : m_tracks) {
184  if (track->id() == id) {
185  return track.get();
186  }
187  }
188  return nullptr;
189 }
190 
191 template <class FileInfoType, class TagType, class TrackType, class ElementType>
193 {
194  return m_tracks.size();
195 }
196 
206 template <class FileInfoType, class TagType, class TrackType, class ElementType>
207 inline const std::vector<std::unique_ptr<TagType>> &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::tags() const
208 {
209  return m_tags;
210 }
211 
221 template <class FileInfoType, class TagType, class TrackType, class ElementType>
222 inline std::vector<std::unique_ptr<TagType>> &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::tags()
223 {
224  return m_tags;
225 }
226 
236 template <class FileInfoType, class TagType, class TrackType, class ElementType>
237 inline const std::vector<std::unique_ptr<TrackType>> &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::tracks() const
238 {
239  return m_tracks;
240 }
241 
251 template <class FileInfoType, class TagType, class TrackType, class ElementType>
252 inline std::vector<std::unique_ptr<TrackType>> &GenericContainer<FileInfoType, TagType, TrackType, ElementType>::tracks()
253 {
254  return m_tracks;
255 }
256 
257 template <class FileInfoType, class TagType, class TrackType, class ElementType>
259 {
260  // check whether a tag matching the specified target is already assigned
261  if (!m_tags.empty()) {
262  if (!target.isEmpty() && m_tags.front()->supportsTarget()) {
263  for (auto &tag : m_tags) {
264  if (tag->target() == target) {
265  return tag.get();
266  }
267  }
268  } else {
269  return m_tags.front().get();
270  }
271  }
272 
273  // a new tag must be created
274  m_tags.emplace_back(std::make_unique<TagType>());
275  auto &tag = m_tags.back();
276  tag->setTarget(target);
277  return tag.get();
278 }
279 
280 template <class FileInfoType, class TagType, class TrackType, class ElementType>
282 {
283  if (auto size = m_tags.size()) {
284  m_tags.erase(std::remove_if(m_tags.begin(), m_tags.end(),
285  [tag](const std::unique_ptr<TagType> &existingTag) -> bool { return static_cast<Tag *>(existingTag.get()) == tag; }),
286  m_tags.end());
287  return size != m_tags.size();
288  }
289  return false;
290 }
291 
292 template <class FileInfoType, class TagType, class TrackType, class ElementType>
294 {
295  m_tags.clear();
296 }
297 
314 template <class FileInfoType, class TagType, class TrackType, class ElementType>
316 {
317  if (areTracksParsed() && supportsTrackModifications()) {
318  // ensure ID is unique
319  auto id = track->id();
320  ensureIdIsUnique:
321  for (const auto &track : m_tracks) {
322  if (track->id() == id) {
323  ++id;
324  goto ensureIdIsUnique;
325  }
326  }
327  track->setId(id);
328 
329  m_tracks.emplace_back(track);
330  return m_tracksAltered = true;
331  }
332  return false;
333 }
334 
335 template <class FileInfoType, class TagType, class TrackType, class ElementType>
337 {
338  bool removed = false;
339  if (areTracksParsed() && supportsTrackModifications() && !m_tracks.empty()) {
340  for (auto i = m_tracks.end() - 1, begin = m_tracks.begin();; --i) {
341  if (static_cast<AbstractTrack *>(i->get()) == track) {
342  i->release();
343  m_tracks.erase(i);
344  removed = true;
345  }
346  if (i == begin) {
347  break;
348  }
349  }
350  if (removed) {
351  m_tracksAltered = true;
352  }
353  }
354  return removed;
355 }
356 
357 template <class FileInfoType, class TagType, class TrackType, class ElementType>
359 {
360  if (areTracksParsed() && supportsTrackModifications() && m_tracks.size()) {
361  m_tracks.clear();
362  m_tracksAltered = true;
363  }
364 }
365 
366 template <class FileInfoType, class TagType, class TrackType, class ElementType>
368 {
369  AbstractContainer::reset();
370  m_firstElement.reset();
371  m_additionalElements.clear();
372  m_tracks.clear();
373  m_tags.clear();
374 }
375 
376 } // namespace TagParser
377 
378 #endif // TAG_PARSER_GENERICCONTAINER_H
std::unique_ptr< ElementType > m_firstElement
std::vector< std::unique_ptr< ElementType > > m_additionalElements
bool isEmpty() const
Returns an indication whether the target is empty.
Definition: tagtarget.h:168
std::vector< std::unique_ptr< TrackType > > m_tracks
GenericContainer(FileInfoType &fileInfo, uint64 startOffset)
Constructs a new container for the specified fileInfo at the specified startOffset.
TagType
Specifies the tag type.
Definition: tag.h:20
#define TAG_PARSER_EXPORT
Marks the symbol to be exported by the tagparser library.
TrackType
Specifies the track type.
Definition: abstracttrack.h:28
std::vector< std::unique_ptr< TagType > > m_tags