Tag Parser  10.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  std::string_view 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;
55  const std::multimap<IdentifierType, FieldType, Compare> &fields() const;
56  std::multimap<IdentifierType, FieldType, Compare> &fields();
57  std::size_t fieldCount() const;
60  bool supportsField(KnownField field) const;
63  std::size_t insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite);
64  std::size_t insertValues(const Tag &from, bool overwrite);
66 
67 protected:
69 
70  const TagValue &internallyGetValue(const IdentifierType &id) const;
71  void internallyGetValuesFromField(const FieldType &field, std::vector<const TagValue *> &values) const;
72  std::vector<const TagValue *> internallyGetValues(const IdentifierType &id) const;
74  bool internallySetValues(const IdentifierType &id, const std::vector<TagValue> &values);
75  bool internallyHasField(const IdentifierType &id) const;
76  // no default implementation: IdentifierType internallyGetFieldId(KnownField field) const;
77  // no default implementation: KnownField internallyGetKnownField(const IdentifierType &id) const;
79 
80 private:
81  std::multimap<IdentifierType, FieldType, Compare> m_fields;
82 };
83 
101 template <class ImplementationType> FieldMapBasedTag<ImplementationType>::FieldMapBasedTag()
102 {
103 }
104 
105 template <class ImplementationType> TagType FieldMapBasedTag<ImplementationType>::type() const
106 {
107  return ImplementationType::tagType;
108 }
109 
110 template <class ImplementationType> std::string_view FieldMapBasedTag<ImplementationType>::typeName() const
111 {
112  return ImplementationType::tagName;
113 }
114 
116 {
117  return ImplementationType::defaultTextEncoding;
118 }
119 
124 template <class ImplementationType> const TagValue &FieldMapBasedTag<ImplementationType>::internallyGetValue(const IdentifierType &id) const
125 {
126  auto i = m_fields.find(id);
127  return i != m_fields.end() ? i->second.value() : TagValue::empty();
128 }
129 
134 template <class ImplementationType>
136  const FieldMapBasedTag<ImplementationType>::FieldType &field, std::vector<const TagValue *> &values) const
137 {
138  if (!field.value().isEmpty()) {
139  values.emplace_back(&field.value());
140  }
141 }
142 
147 template <class ImplementationType>
148 std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::internallyGetValues(const IdentifierType &id) const
149 {
150  auto range = m_fields.equal_range(id);
151  std::vector<const TagValue *> values;
152  for (auto i = range.first; i != range.second; ++i) {
153  static_cast<const ImplementationType *>(this)->internallyGetValuesFromField(i->second, values);
154  }
155  return values;
156 }
157 
162 template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(const IdentifierType &id) const
163 {
164  return static_cast<const ImplementationType *>(this)->internallyGetValue(id);
165 }
166 
167 template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(KnownField field) const
168 {
169  return value(fieldId(field));
170 }
171 
176 template <class ImplementationType> inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(const IdentifierType &id) const
177 {
178  return static_cast<const ImplementationType *>(this)->internallyGetValues(id);
179 }
180 
181 template <class ImplementationType> inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(KnownField field) const
182 {
183  return static_cast<const ImplementationType *>(this)->values(fieldId(field));
184 }
185 
186 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::setValue(KnownField field, const TagValue &value)
187 {
188  return setValue(fieldId(field), value);
189 }
190 
195 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallySetValue(const IdentifierType &id, const TagValue &value)
196 {
197  auto i = m_fields.find(id);
198  if (i != m_fields.end()) { // field already exists -> set its value
199  i->second.setValue(value);
200  } else if (!value.isEmpty()) { // field doesn't exist -> create new one if value is not null
201  m_fields.insert(std::make_pair(id, FieldType(id, value)));
202  } else { // otherwise return false
203  return false;
204  }
205  return true;
206 }
207 
212 template <class ImplementationType>
214 {
215  auto valuesIterator = values.cbegin();
216  auto range = m_fields.equal_range(id);
217  // iterate through all specified and all existing values
218  for (; valuesIterator != values.cend() && range.first != range.second; ++valuesIterator) {
219  // replace existing value with non-empty specified value
220  if (!valuesIterator->isEmpty()) {
221  auto &field = range.first->second;
222  field.clearValue();
223  field.setValue(*valuesIterator);
224  ++range.first;
225  }
226  }
227  // add remaining specified values (there are more specified values than existing ones)
228  for (; valuesIterator != values.cend(); ++valuesIterator) {
229  m_fields.insert(std::make_pair(id, FieldType(id, *valuesIterator)));
230  }
231  // remove remaining existing values (there are more existing values than specified ones)
232  for (; range.first != range.second; ++range.first) {
233  range.first->second.clearValue();
234  }
235  return true;
236 }
237 
242 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValue(const IdentifierType &id, const TagParser::TagValue &value)
243 {
244  return static_cast<ImplementationType *>(this)->internallySetValue(id, value);
245 }
246 
253 template <class ImplementationType>
254 bool FieldMapBasedTag<ImplementationType>::setValues(const IdentifierType &id, const std::vector<TagValue> &values)
255 {
256  return static_cast<ImplementationType *>(this)->internallySetValues(id, values);
257 }
258 
265 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValues(KnownField field, const std::vector<TagValue> &values)
266 {
267  return setValues(fieldId(field), values);
268 }
269 
270 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(KnownField field) const
271 {
272  return hasField(fieldId(field));
273 }
274 
279 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallyHasField(const IdentifierType &id) const
280 {
281  for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
282  if (!range.first->second.value().isEmpty()) {
283  return true;
284  }
285  }
286  return false;
287 }
288 
292 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(const IdentifierType &id) const
293 {
294  return static_cast<const ImplementationType *>(this)->internallyHasField(id);
295 }
296 
297 template <class ImplementationType> inline void FieldMapBasedTag<ImplementationType>::removeAllFields()
298 {
299  m_fields.clear();
300 }
301 
305 template <class ImplementationType>
306 inline auto FieldMapBasedTag<ImplementationType>::fields() const -> const std::multimap<IdentifierType, FieldType, Compare> &
307 {
308  return m_fields;
309 }
310 
314 template <class ImplementationType> inline auto FieldMapBasedTag<ImplementationType>::fields() -> std::multimap<IdentifierType, FieldType, Compare> &
315 {
316  return m_fields;
317 }
318 
319 template <class ImplementationType> std::size_t FieldMapBasedTag<ImplementationType>::fieldCount() const
320 {
321  auto count = std::size_t(0);
322  for (const auto &field : m_fields) {
323  if (!field.second.value().isEmpty()) {
324  ++count;
325  }
326  }
327  return count;
328 }
329 
334 template <class ImplementationType>
336 {
337  return static_cast<const ImplementationType *>(this)->internallyGetFieldId(value);
338 }
339 
344 template <class ImplementationType> inline KnownField FieldMapBasedTag<ImplementationType>::knownField(const IdentifierType &id) const
345 {
346  return static_cast<const ImplementationType *>(this)->internallyGetKnownField(id);
347 }
348 
349 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::supportsField(KnownField field) const
350 {
351  static IdentifierType def;
352  return fieldId(field) != def;
353 }
354 
359 template <class ImplementationType>
361 {
362  return Tag::proposedDataType(knownField(id));
363 }
364 
368 template <class ImplementationType> inline TagDataType FieldMapBasedTag<ImplementationType>::proposedDataType(const IdentifierType &id) const
369 {
370  return static_cast<ImplementationType *>(this)->determineProposedDataType(id);
371 }
372 
379 template <class ImplementationType>
381 {
382  auto fieldsInserted = std::size_t(0);
383  for (const auto &pair : from.fields()) {
384  const FieldType &fromField = pair.second;
385  if (fromField.value().isEmpty()) {
386  continue;
387  }
388  bool fieldInserted = false;
389  auto range = fields().equal_range(fromField.id());
390  for (auto i = range.first; i != range.second; ++i) {
391  FieldType &ownField = i->second;
392  if ((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned() && fromField.typeInfo() == ownField.typeInfo())
393  || (!fromField.isTypeInfoAssigned() && !ownField.isTypeInfoAssigned())) {
394  if (overwrite || ownField.value().isEmpty()) {
395  ownField = fromField;
396  ++fieldsInserted;
397  }
398  fieldInserted = true;
399  continue;
400  }
401  }
402  if (!fieldInserted) {
403  fields().insert(std::make_pair(fromField.id(), fromField));
404  ++fieldsInserted;
405  }
406  }
407  return fieldsInserted;
408 }
409 
410 template <class ImplementationType> std::size_t FieldMapBasedTag<ImplementationType>::insertValues(const Tag &from, bool overwrite)
411 {
412  if (type() == from.type()) {
413  // the tags are of the same type, we can insert the fields directly
414  return insertFields(static_cast<const FieldMapBasedTag<ImplementationType> &>(from), overwrite);
415  } else {
416  return Tag::insertValues(from, overwrite);
417  }
418 }
419 
421 {
422  for (auto &field : fields()) {
423  field.second.value().convertDataEncodingForTag(this);
424  }
425 }
426 
427 } // namespace TagParser
428 
429 #endif // TAG_PARSER_FIELDBASEDTAG_H
Defines traits for the specified ImplementationType.
Definition: fieldbasedtag.h:17
The FieldMapBasedTag provides a generic implementation of Tag which stores the tag fields using std::...
Definition: fieldbasedtag.h:31
bool hasField(const IdentifierType &id) const
Returns an indication whether the field with the specified id is present.
bool setValue(const IdentifierType &id, const TagValue &value)
Assigns the given value to the field with the specified id.
void ensureTextValuesAreProperlyEncoded()
Ensures the encoding of all assigned text values is supported by the tag by converting the character ...
bool setValue(KnownField field, const TagValue &value)
Assigns the given value to the specified field.
bool hasField(KnownField field) const
Returns an indication whether the specified field is present.
std::vector< const TagValue * > values(KnownField field) const
Returns the values of the specified field.
std::multimap< IdentifierType, FieldType, Compare > & fields()
Returns the fields of the tag by providing direct access to the field map of the tag.
std::vector< const TagValue * > internallyGetValues(const IdentifierType &id) const
Default implementation for values().
typename FieldMapBasedTagTraits< ImplementationType >::Compare Compare
Definition: fieldbasedtag.h:37
std::string_view typeName() const
Returns the type name of the tag as C-style string.
typename FieldMapBasedTagTraits< ImplementationType >::FieldType::IdentifierType IdentifierType
Definition: fieldbasedtag.h:36
const TagValue & value(KnownField field) const
Returns the value of the specified field.
FieldMapBasedTag()
Constructs a new FieldMapBasedTag.
TagTextEncoding proposedTextEncoding() const
Returns the proposed text encoding.
const TagValue & value(const IdentifierType &id) const
Returns the value of the field with the specified id.
void removeAllFields()
Removes all fields from the tag.
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.
TagDataType proposedDataType(const IdentifierType &id) const
Returns the proposed data type for the field with the specified id.
bool internallySetValues(const IdentifierType &id, const std::vector< TagValue > &values)
Default implementation for setValues().
TagType type() const
Returns the type of the tag as TagParser::TagType.
std::size_t insertFields(const FieldMapBasedTag< ImplementationType > &from, bool overwrite)
Inserts all fields from another tag of the same field type and compare function.
virtual TagDataType proposedDataType(KnownField field) const
Returns the proposed data type for the specified field as TagDataType.
Definition: tag.h:214
typename FieldMapBasedTagTraits< ImplementationType >::FieldType FieldType
Definition: fieldbasedtag.h:35
TagDataType internallyGetProposedDataType(const IdentifierType &id) const
Default implementation for proposedDataType().
void internallyGetValuesFromField(const FieldType &field, std::vector< const TagValue * > &values) const
Default way to gather values from a field in internallyGetValues().
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.
const TagValue & internallyGetValue(const IdentifierType &id) const
Default implementation for value().
bool internallyHasField(const IdentifierType &id) const
Default implementation for hasField().
bool setValues(const IdentifierType &id, const std::vector< TagValue > &values)
Assigns the given values to the field with the specified id.
std::size_t fieldCount() const
Returns the number of present fields.
bool supportsField(KnownField field) const
Returns an indication whether the specified field is supported by the tag.
bool setValues(KnownField field, const std::vector< TagValue > &values)
Assigns the given values to the field with the specified id.
IdentifierType fieldId(KnownField value) const
Returns the ID for the specified field.
std::size_t insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
bool internallySetValue(const IdentifierType &id, const TagValue &value)
Default implementation for setValue().
The TagValue class wraps values of different types.
Definition: tagvalue.h:95
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
Definition: tagvalue.cpp:958
bool isEmpty() const
Returns whether no or an empty value is assigned.
Definition: tagvalue.h:527
The Tag class is used to store, read and write tag information.
Definition: tag.h:108
virtual std::size_t insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
Definition: tag.cpp:86
virtual TagType type() const
Returns the type of the tag as TagParser::TagType.
Definition: tag.h:149
virtual TagDataType proposedDataType(KnownField field) const
Returns the proposed data type for the specified field as TagDataType.
Definition: tag.h:214
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
KnownField
Specifies the field.
Definition: tag.h:42
TagTextEncoding
Specifies the text encoding.
Definition: tagvalue.h:28
TagType
Specifies the tag type.
Definition: tag.h:20
TagDataType
Specifies the data type.
Definition: tagvalue.h:74