Tag Parser  7.1.0
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:
68  const TagValue &internallyGetValue(const IdentifierType &id) const;
69  bool internallySetValue(const IdentifierType &id, const TagValue &value);
70  bool internallyHasField(const IdentifierType &id) const;
71  // no default implementation: IdentifierType internallyGetFieldId(KnownField field) const;
72  // no default implementation: KnownField internallyGetKnownField(const IdentifierType &id) const;
74 
75 private:
76  std::multimap<IdentifierType, FieldType, Compare> m_fields;
77 };
78 
96 template <class ImplementationType> FieldMapBasedTag<ImplementationType>::FieldMapBasedTag()
97 {
98 }
99 
100 template <class ImplementationType> TagType FieldMapBasedTag<ImplementationType>::type() const
101 {
102  return ImplementationType::tagType;
103 }
104 
105 template <class ImplementationType> const char *FieldMapBasedTag<ImplementationType>::typeName() const
106 {
107  return ImplementationType::tagName;
108 }
109 
111 {
112  return ImplementationType::defaultTextEncoding;
113 }
114 
119 template <class ImplementationType> const TagValue &FieldMapBasedTag<ImplementationType>::internallyGetValue(const IdentifierType &id) const
120 {
121  auto i = m_fields.find(id);
122  return i != m_fields.end() ? i->second.value() : TagValue::empty();
123 }
124 
129 template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(const IdentifierType &id) const
130 {
131  return static_cast<const ImplementationType *>(this)->internallyGetValue(id);
132 }
133 
134 template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(KnownField field) const
135 {
136  return value(fieldId(field));
137 }
138 
143 template <class ImplementationType> inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(const IdentifierType &id) const
144 {
145  auto range = m_fields.equal_range(id);
146  std::vector<const TagValue *> values;
147  for (auto i = range.first; i != range.second; ++i) {
148  if (!i->second.value().isEmpty()) {
149  values.push_back(&i->second.value());
150  }
151  }
152  return values;
153 }
154 
155 template <class ImplementationType> inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(KnownField field) const
156 {
157  return values(fieldId(field));
158 }
159 
160 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::setValue(KnownField field, const TagValue &value)
161 {
162  return setValue(fieldId(field), value);
163 }
164 
169 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallySetValue(const IdentifierType &id, const TagValue &value)
170 {
171  auto i = m_fields.find(id);
172  if (i != m_fields.end()) { // field already exists -> set its value
173  i->second.setValue(value);
174  } else if (!value.isEmpty()) { // field doesn't exist -> create new one if value is not null
175  m_fields.insert(std::make_pair(id, FieldType(id, value)));
176  } else { // otherwise return false
177  return false;
178  }
179  return true;
180 }
181 
186 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValue(const IdentifierType &id, const TagParser::TagValue &value)
187 {
188  return static_cast<ImplementationType *>(this)->internallySetValue(id, value);
189 }
190 
197 template <class ImplementationType>
198 bool FieldMapBasedTag<ImplementationType>::setValues(const IdentifierType &id, const std::vector<TagValue> &values)
199 {
200  auto valuesIterator = values.cbegin();
201  auto range = m_fields.equal_range(id);
202  // iterate through all specified and all existing values
203  for (; valuesIterator != values.cend() && range.first != range.second; ++valuesIterator) {
204  // replace existing value with non-empty specified value
205  if (!valuesIterator->isEmpty()) {
206  range.first->second.setValue(*valuesIterator);
207  ++range.first;
208  }
209  }
210  // add remaining specified values (there are more specified values than existing ones)
211  for (; valuesIterator != values.cend(); ++valuesIterator) {
212  m_fields.insert(std::make_pair(id, FieldType(id, *valuesIterator)));
213  }
214  // remove remaining existing values (there are more existing values than specified ones)
215  for (; range.first != range.second; ++range.first) {
216  range.first->second.setValue(TagValue());
217  }
218  return true;
219 }
220 
227 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValues(KnownField field, const std::vector<TagValue> &values)
228 {
229  return setValues(fieldId(field), values);
230 }
231 
232 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(KnownField field) const
233 {
234  return hasField(fieldId(field));
235 }
236 
241 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallyHasField(const IdentifierType &id) const
242 {
243  for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
244  if (!range.first->second.value().isEmpty()) {
245  return true;
246  }
247  }
248  return false;
249 }
250 
254 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(const IdentifierType &id) const
255 {
256  return static_cast<const ImplementationType *>(this)->internallyHasField(id);
257 }
258 
259 template <class ImplementationType> inline void FieldMapBasedTag<ImplementationType>::removeAllFields()
260 {
261  m_fields.clear();
262 }
263 
267 template <class ImplementationType>
269 {
270  return m_fields;
271 }
272 
276 template <class ImplementationType> inline auto FieldMapBasedTag<ImplementationType>::fields() -> std::multimap<IdentifierType, FieldType, Compare> &
277 {
278  return m_fields;
279 }
280 
281 template <class ImplementationType> unsigned int FieldMapBasedTag<ImplementationType>::fieldCount() const
282 {
283  unsigned int count = 0;
284  for (const auto &field : m_fields) {
285  if (!field.second.value().isEmpty()) {
286  ++count;
287  }
288  }
289  return count;
290 }
291 
296 template <class ImplementationType>
298 {
299  return static_cast<const ImplementationType *>(this)->internallyGetFieldId(value);
300 }
301 
306 template <class ImplementationType> inline KnownField FieldMapBasedTag<ImplementationType>::knownField(const IdentifierType &id) const
307 {
308  return static_cast<const ImplementationType *>(this)->internallyGetKnownField(id);
309 }
310 
311 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::supportsField(KnownField field) const
312 {
313  static IdentifierType def;
314  return fieldId(field) != def;
315 }
316 
321 template <class ImplementationType>
323 {
324  return Tag::proposedDataType(knownField(id));
325 }
326 
330 template <class ImplementationType> inline TagDataType FieldMapBasedTag<ImplementationType>::proposedDataType(const IdentifierType &id) const
331 {
332  return static_cast<ImplementationType *>(this)->determineProposedDataType(id);
333 }
334 
341 template <class ImplementationType>
343 {
344  int fieldsInserted = 0;
345  for (const auto &pair : from.fields()) {
346  const FieldType &fromField = pair.second;
347  if (fromField.value().isEmpty()) {
348  continue;
349  }
350  bool fieldInserted = false;
351  auto range = fields().equal_range(fromField.id());
352  for (auto i = range.first; i != range.second; ++i) {
353  FieldType &ownField = i->second;
354  if ((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned() && fromField.typeInfo() == ownField.typeInfo())
355  || (!fromField.isTypeInfoAssigned() && !ownField.isTypeInfoAssigned())) {
356  if (overwrite || ownField.value().isEmpty()) {
357  ownField = fromField;
358  ++fieldsInserted;
359  }
360  fieldInserted = true;
361  continue;
362  }
363  }
364  if (!fieldInserted) {
365  fields().insert(std::make_pair(fromField.id(), fromField));
366  ++fieldsInserted;
367  }
368  }
369  return fieldsInserted;
370 }
371 
372 template <class ImplementationType> unsigned int FieldMapBasedTag<ImplementationType>::insertValues(const Tag &from, bool overwrite)
373 {
374  if (type() == from.type()) {
375  // the tags are of the same type, we can insert the fields directly
376  return insertFields(static_cast<const FieldMapBasedTag<ImplementationType> &>(from), overwrite);
377  } else {
378  return Tag::insertValues(from, overwrite);
379  }
380 }
381 
383 {
384  for (auto &field : fields()) {
385  field.second.value().convertDataEncodingForTag(this);
386  }
387 }
388 
389 } // namespace TagParser
390 
391 #endif // TAG_PARSER_FIELDBASEDTAG_H
virtual TagDataType proposedDataType(KnownField field) const
Returns the proposed data type for the specified field as TagDataType.
Definition: tag.h:301
FieldMapBasedTagTraits< ImplementationType >::FieldType::IdentifierType IdentifierType
Definition: fieldbasedtag.h:36
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.
Definition: fieldbasedtag.h:96
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.
FieldMapBasedTagTraits< ImplementationType >::Compare Compare
Definition: fieldbasedtag.h:37
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:52
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
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:384
TagType type() const
Returns the type of the tag as TagParser::TagType.
static const TagValue & empty()
Returns an empty TagValue.
Definition: tagvalue.cpp:737
FieldMapBasedTagTraits< ImplementationType >::FieldType FieldType
Definition: fieldbasedtag.h:35
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.
virtual TagType type() const
Returns the type of the tag as TagParser::TagType.
Definition: tag.h:141
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.
IdentifierType fieldId(KnownField value) const
Returns the ID for the specified field.
The TagValue class wraps values of different types.
Definition: tagvalue.h:64
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:129
TagTextEncoding
Specifies the text encoding.
Definition: tagvalue.h:23
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:9
TagTextEncoding proposedTextEncoding() const
Returns the proposed text encoding.