Tag Parser  8.0.1
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
fieldbasedtag.h
Go to the documentation of this file.
1 #ifndef TAG_PARSER_FIELDBASEDTAG_H
2 #define TAG_PARSER_FIELDBASEDTAG_H
3 
4 #include "./tag.h"
5 
6 #include <functional>
7 #include <map>
8 
9 namespace TagParser {
10 
17 template <typename ImplementationType> class FieldMapBasedTagTraits {
18 };
19 
31 template <class ImplementationType> class FieldMapBasedTag : public Tag {
32  friend class FieldMapBasedTagTraits<ImplementationType>;
33 
34 public:
38 
40 
41  TagType type() const;
42  const char *typeName() const;
44  const TagValue &value(const IdentifierType &id) const;
45  const TagValue &value(KnownField field) const;
46  std::vector<const TagValue *> values(const IdentifierType &id) const;
47  std::vector<const TagValue *> values(KnownField field) const;
48  bool setValue(const IdentifierType &id, const TagValue &value);
49  bool setValue(KnownField field, const TagValue &value);
50  bool setValues(const IdentifierType &id, const std::vector<TagValue> &values);
51  bool setValues(KnownField field, const std::vector<TagValue> &values);
52  bool hasField(KnownField field) const;
53  bool hasField(const IdentifierType &id) const;
54  void removeAllFields();
55  const std::multimap<IdentifierType, FieldType, Compare> &fields() const;
56  std::multimap<IdentifierType, FieldType, Compare> &fields();
57  unsigned int fieldCount() const;
59  KnownField knownField(const IdentifierType &id) const;
60  bool supportsField(KnownField field) const;
63  int insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite);
64  unsigned int insertValues(const Tag &from, bool overwrite);
66 
67 protected:
69 
70  const TagValue &internallyGetValue(const IdentifierType &id) const;
71  std::vector<const TagValue *> internallyGetValues(const IdentifierType &id) const;
72  bool internallySetValue(const IdentifierType &id, const TagValue &value);
73  bool internallySetValues(const IdentifierType &id, const std::vector<TagValue> &values);
74  bool internallyHasField(const IdentifierType &id) const;
75  // no default implementation: IdentifierType internallyGetFieldId(KnownField field) const;
76  // no default implementation: KnownField internallyGetKnownField(const IdentifierType &id) const;
78 
79 private:
80  std::multimap<IdentifierType, FieldType, Compare> m_fields;
81 };
82 
100 template <class ImplementationType> FieldMapBasedTag<ImplementationType>::FieldMapBasedTag()
101 {
102 }
103 
104 template <class ImplementationType> TagType FieldMapBasedTag<ImplementationType>::type() const
105 {
106  return ImplementationType::tagType;
107 }
108 
109 template <class ImplementationType> const char *FieldMapBasedTag<ImplementationType>::typeName() const
110 {
111  return ImplementationType::tagName;
112 }
113 
115 {
116  return ImplementationType::defaultTextEncoding;
117 }
118 
123 template <class ImplementationType> const TagValue &FieldMapBasedTag<ImplementationType>::internallyGetValue(const IdentifierType &id) const
124 {
125  auto i = m_fields.find(id);
126  return i != m_fields.end() ? i->second.value() : TagValue::empty();
127 }
128 
133 template <class ImplementationType>
134 std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::internallyGetValues(const IdentifierType &id) const
135 {
136  auto range = m_fields.equal_range(id);
137  std::vector<const TagValue *> values;
138  for (auto i = range.first; i != range.second; ++i) {
139  if (!i->second.value().isEmpty()) {
140  values.push_back(&i->second.value());
141  }
142  }
143  return values;
144 }
145 
150 template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(const IdentifierType &id) const
151 {
152  return static_cast<const ImplementationType *>(this)->internallyGetValue(id);
153 }
154 
155 template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(KnownField field) const
156 {
157  return value(fieldId(field));
158 }
159 
164 template <class ImplementationType> inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(const IdentifierType &id) const
165 {
166  return static_cast<const ImplementationType *>(this)->internallyGetValues(id);
167 }
168 
169 template <class ImplementationType> inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(KnownField field) const
170 {
171  return static_cast<const ImplementationType *>(this)->values(fieldId(field));
172 }
173 
174 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::setValue(KnownField field, const TagValue &value)
175 {
176  return setValue(fieldId(field), value);
177 }
178 
183 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallySetValue(const IdentifierType &id, const TagValue &value)
184 {
185  auto i = m_fields.find(id);
186  if (i != m_fields.end()) { // field already exists -> set its value
187  i->second.setValue(value);
188  } else if (!value.isEmpty()) { // field doesn't exist -> create new one if value is not null
189  m_fields.insert(std::make_pair(id, FieldType(id, value)));
190  } else { // otherwise return false
191  return false;
192  }
193  return true;
194 }
195 
200 template <class ImplementationType>
202 {
203  auto valuesIterator = values.cbegin();
204  auto range = m_fields.equal_range(id);
205  // iterate through all specified and all existing values
206  for (; valuesIterator != values.cend() && range.first != range.second; ++valuesIterator) {
207  // replace existing value with non-empty specified value
208  if (!valuesIterator->isEmpty()) {
209  range.first->second.setValue(*valuesIterator);
210  ++range.first;
211  }
212  }
213  // add remaining specified values (there are more specified values than existing ones)
214  for (; valuesIterator != values.cend(); ++valuesIterator) {
215  m_fields.insert(std::make_pair(id, FieldType(id, *valuesIterator)));
216  }
217  // remove remaining existing values (there are more existing values than specified ones)
218  for (; range.first != range.second; ++range.first) {
219  range.first->second.setValue(TagValue());
220  }
221  return true;
222 }
223 
228 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValue(const IdentifierType &id, const TagParser::TagValue &value)
229 {
230  return static_cast<ImplementationType *>(this)->internallySetValue(id, value);
231 }
232 
239 template <class ImplementationType>
240 bool FieldMapBasedTag<ImplementationType>::setValues(const IdentifierType &id, const std::vector<TagValue> &values)
241 {
242  return static_cast<ImplementationType *>(this)->internallySetValues(id, values);
243 }
244 
251 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValues(KnownField field, const std::vector<TagValue> &values)
252 {
253  return setValues(fieldId(field), values);
254 }
255 
256 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(KnownField field) const
257 {
258  return hasField(fieldId(field));
259 }
260 
265 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallyHasField(const IdentifierType &id) const
266 {
267  for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
268  if (!range.first->second.value().isEmpty()) {
269  return true;
270  }
271  }
272  return false;
273 }
274 
278 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(const IdentifierType &id) const
279 {
280  return static_cast<const ImplementationType *>(this)->internallyHasField(id);
281 }
282 
283 template <class ImplementationType> inline void FieldMapBasedTag<ImplementationType>::removeAllFields()
284 {
285  m_fields.clear();
286 }
287 
291 template <class ImplementationType>
293 {
294  return m_fields;
295 }
296 
300 template <class ImplementationType> inline auto FieldMapBasedTag<ImplementationType>::fields() -> std::multimap<IdentifierType, FieldType, Compare> &
301 {
302  return m_fields;
303 }
304 
305 template <class ImplementationType> unsigned int FieldMapBasedTag<ImplementationType>::fieldCount() const
306 {
307  unsigned int count = 0;
308  for (const auto &field : m_fields) {
309  if (!field.second.value().isEmpty()) {
310  ++count;
311  }
312  }
313  return count;
314 }
315 
320 template <class ImplementationType>
322 {
323  return static_cast<const ImplementationType *>(this)->internallyGetFieldId(value);
324 }
325 
330 template <class ImplementationType> inline KnownField FieldMapBasedTag<ImplementationType>::knownField(const IdentifierType &id) const
331 {
332  return static_cast<const ImplementationType *>(this)->internallyGetKnownField(id);
333 }
334 
335 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::supportsField(KnownField field) const
336 {
337  static IdentifierType def;
338  return fieldId(field) != def;
339 }
340 
345 template <class ImplementationType>
347 {
348  return Tag::proposedDataType(knownField(id));
349 }
350 
354 template <class ImplementationType> inline TagDataType FieldMapBasedTag<ImplementationType>::proposedDataType(const IdentifierType &id) const
355 {
356  return static_cast<ImplementationType *>(this)->determineProposedDataType(id);
357 }
358 
365 template <class ImplementationType>
367 {
368  int fieldsInserted = 0;
369  for (const auto &pair : from.fields()) {
370  const FieldType &fromField = pair.second;
371  if (fromField.value().isEmpty()) {
372  continue;
373  }
374  bool fieldInserted = false;
375  auto range = fields().equal_range(fromField.id());
376  for (auto i = range.first; i != range.second; ++i) {
377  FieldType &ownField = i->second;
378  if ((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned() && fromField.typeInfo() == ownField.typeInfo())
379  || (!fromField.isTypeInfoAssigned() && !ownField.isTypeInfoAssigned())) {
380  if (overwrite || ownField.value().isEmpty()) {
381  ownField = fromField;
382  ++fieldsInserted;
383  }
384  fieldInserted = true;
385  continue;
386  }
387  }
388  if (!fieldInserted) {
389  fields().insert(std::make_pair(fromField.id(), fromField));
390  ++fieldsInserted;
391  }
392  }
393  return fieldsInserted;
394 }
395 
396 template <class ImplementationType> unsigned int FieldMapBasedTag<ImplementationType>::insertValues(const Tag &from, bool overwrite)
397 {
398  if (type() == from.type()) {
399  // the tags are of the same type, we can insert the fields directly
400  return insertFields(static_cast<const FieldMapBasedTag<ImplementationType> &>(from), overwrite);
401  } else {
402  return Tag::insertValues(from, overwrite);
403  }
404 }
405 
407 {
408  for (auto &field : fields()) {
409  field.second.value().convertDataEncodingForTag(this);
410  }
411 }
412 
413 } // namespace TagParser
414 
415 #endif // TAG_PARSER_FIELDBASEDTAG_H
bool supportsField(KnownField field) const
Returns an indication whether the specified field is supported by the tag.
const TagValue & internallyGetValue(const IdentifierType &id) const
Default implementation for value().
The FieldMapBasedTag provides a generic implementation of Tag which stores the tag fields using std::...
Definition: fieldbasedtag.h:31
bool internallySetValue(const IdentifierType &id, const TagValue &value)
Default implementation for setValue().
unsigned int fieldCount() const
Returns the number of present fields.
void ensureTextValuesAreProperlyEncoded()
Ensures the encoding of all assigned text values is supported by the tag by converting the character ...
bool setValues(const IdentifierType &id, const std::vector< TagValue > &values)
Assigns the given values to the field with the specified id.
The Tag class is used to store, read and write tag information.
Definition: tag.h:95
FieldMapBasedTag()
Constructs a new FieldMapBasedTag.
const TagValue & value(const IdentifierType &id) const
Returns the value of the field with the specified id.
bool hasField(KnownField field) const
Returns an indication whether the specified field is present.
bool setValue(const IdentifierType &id, const TagValue &value)
Assigns the given value to the field with the specified id.
typename FieldMapBasedTagTraits< MatroskaTag >::FieldType::IdentifierType IdentifierType
Definition: fieldbasedtag.h:36
const char * typeName() const
Returns the type name of the tag as C-style string.
STL namespace.
TagDataType
Specifies the data type.
Definition: tagvalue.h:53
TagDataType internallyGetProposedDataType(const IdentifierType &id) const
Default implementation for proposedDataType().
KnownField knownField(const IdentifierType &id) const
Returns the field for the specified ID.
std::vector< const TagValue * > values(const IdentifierType &id) const
Returns the values of the field with the specified id.
KnownField
Specifies the field.
Definition: tag.h:40
virtual TagType type() const
Returns the type of the tag as TagParser::TagType.
Definition: tag.h:136
typename FieldMapBasedTagTraits< MatroskaTag >::FieldType FieldType
Definition: fieldbasedtag.h:35
Defines traits for the specified ImplementationType.
Definition: fieldbasedtag.h:17
bool internallyHasField(const IdentifierType &id) const
Default implementation for hasField().
bool isEmpty() const
Returns an indication whether an value is assigned.
Definition: tagvalue.h:389
TagType type() const
Returns the type of the tag as TagParser::TagType.
static const TagValue & empty()
Returns an empty TagValue.
Definition: tagvalue.cpp:737
void removeAllFields()
Removes all fields from the tag.
unsigned int insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
TagDataType proposedDataType(const IdentifierType &id) const
Returns the proposed data type for the field with the specified id.
const std::multimap< IdentifierType, FieldType, Compare > & fields() const
Returns the fields of the tag by providing direct access to the field map of the tag.
int insertFields(const FieldMapBasedTag< ImplementationType > &from, bool overwrite)
Inserts all fields from another tag of the same field type and compare function.
bool internallySetValues(const IdentifierType &id, const std::vector< TagValue > &values)
Default implementation for setValues().
typename FieldMapBasedTagTraits< MatroskaTag >::Compare Compare
Definition: fieldbasedtag.h:37
virtual TagDataType proposedDataType(KnownField field) const
Returns the proposed data type for the specified field as TagDataType.
Definition: tag.h:201
IdentifierType fieldId(KnownField value) const
Returns the ID for the specified field.
The TagValue class wraps values of different types.
Definition: tagvalue.h:65
std::vector< const TagValue * > internallyGetValues(const IdentifierType &id) const
Default implementation for values().
TagType
Specifies the tag type.
Definition: tag.h:20
virtual unsigned int insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
Definition: tag.cpp:86
TagTextEncoding
Specifies the text encoding.
Definition: tagvalue.h:24
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:9
TagTextEncoding proposedTextEncoding() const
Returns the proposed text encoding.