Tag Parser  9.4.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;
55  const std::multimap<IdentifierType, FieldType, Compare> &fields() const;
56  std::multimap<IdentifierType, FieldType, Compare> &fields();
57  unsigned int fieldCount() 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;
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>
292 inline auto FieldMapBasedTag<ImplementationType>::fields() const -> const std::multimap<IdentifierType, FieldType, Compare> &
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
TagParser::FieldMapBasedTag::ensureTextValuesAreProperlyEncoded
void ensureTextValuesAreProperlyEncoded()
Ensures the encoding of all assigned text values is supported by the tag by converting the character ...
Definition: fieldbasedtag.h:406
TagParser::FieldMapBasedTag::proposedTextEncoding
TagTextEncoding proposedTextEncoding() const
Returns the proposed text encoding.
Definition: fieldbasedtag.h:114
TagParser::FieldMapBasedTag::FieldMapBasedTag
FieldMapBasedTag()
Constructs a new FieldMapBasedTag.
Definition: fieldbasedtag.h:100
TagParser::FieldMapBasedTag::hasField
bool hasField(KnownField field) const
Returns an indication whether the specified field is present.
Definition: fieldbasedtag.h:256
TagParser::FieldMapBasedTag::supportsField
bool supportsField(KnownField field) const
Returns an indication whether the specified field is supported by the tag.
Definition: fieldbasedtag.h:335
TagParser::FieldMapBasedTag::setValue
bool setValue(const IdentifierType &id, const TagValue &value)
Assigns the given value to the field with the specified id.
Definition: fieldbasedtag.h:228
TagParser::FieldMapBasedTag::internallyGetValue
const TagValue & internallyGetValue(const IdentifierType &id) const
Default implementation for value().
Definition: fieldbasedtag.h:123
TagParser::FieldMapBasedTag< Mp4Tag >::IdentifierType
typename FieldMapBasedTagTraits< Mp4Tag >::FieldType::IdentifierType IdentifierType
Definition: fieldbasedtag.h:36
TagParser::TagTextEncoding
TagTextEncoding
Specifies the text encoding.
Definition: tagvalue.h:25
TagParser::FieldMapBasedTag::setValues
bool setValues(const IdentifierType &id, const std::vector< TagValue > &values)
Assigns the given values to the field with the specified id.
Definition: fieldbasedtag.h:240
TagParser::FieldMapBasedTag::value
const TagValue & value(KnownField field) const
Returns the value of the specified field.
Definition: fieldbasedtag.h:155
TagParser::FieldMapBasedTag::value
const TagValue & value(const IdentifierType &id) const
Returns the value of the field with the specified id.
Definition: fieldbasedtag.h:150
TagParser::Tag::proposedDataType
virtual TagDataType proposedDataType(KnownField field) const
Returns the proposed data type for the specified field as TagDataType.
Definition: tag.h:214
TagParser::FieldMapBasedTag::values
std::vector< const TagValue * > values(const IdentifierType &id) const
Returns the values of the field with the specified id.
Definition: fieldbasedtag.h:164
TagParser::Tag
The Tag class is used to store, read and write tag information.
Definition: tag.h:108
TagParser::FieldMapBasedTag::typeName
const char * typeName() const
Returns the type name of the tag as C-style string.
Definition: fieldbasedtag.h:109
TagParser::FieldMapBasedTag< Mp4Tag >::FieldType
typename FieldMapBasedTagTraits< Mp4Tag >::FieldType FieldType
Definition: fieldbasedtag.h:35
TagParser
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
TagParser::FieldMapBasedTag::internallyGetProposedDataType
TagDataType internallyGetProposedDataType(const IdentifierType &id) const
Default implementation for proposedDataType().
Definition: fieldbasedtag.h:346
TagParser::FieldMapBasedTag::internallyHasField
bool internallyHasField(const IdentifierType &id) const
Default implementation for hasField().
Definition: fieldbasedtag.h:265
TagParser::FieldMapBasedTag::knownField
KnownField knownField(const IdentifierType &id) const
Returns the field for the specified ID.
Definition: fieldbasedtag.h:330
TagParser::TagDataType
TagDataType
Specifies the data type.
Definition: tagvalue.h:54
TagParser::TagValue::isEmpty
bool isEmpty() const
Returns whether no or an empty value is assigned.
Definition: tagvalue.h:464
TagParser::FieldMapBasedTag::removeAllFields
void removeAllFields()
Removes all fields from the tag.
Definition: fieldbasedtag.h:283
TagParser::FieldMapBasedTag::fields
std::multimap< IdentifierType, FieldType, Compare > & fields()
Returns the fields of the tag by providing direct access to the field map of the tag.
Definition: fieldbasedtag.h:300
TagParser::FieldMapBasedTag::type
TagType type() const
Returns the type of the tag as TagParser::TagType.
Definition: fieldbasedtag.h:104
TagParser::FieldMapBasedTag::values
std::vector< const TagValue * > values(KnownField field) const
Returns the values of the specified field.
Definition: fieldbasedtag.h:169
TagParser::Tag::insertValues
virtual unsigned int insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
Definition: tag.cpp:86
TagParser::FieldMapBasedTag::insertValues
unsigned int insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
Definition: fieldbasedtag.h:396
TagParser::KnownField
KnownField
Specifies the field.
Definition: tag.h:42
TagParser::FieldMapBasedTag::hasField
bool hasField(const IdentifierType &id) const
Returns an indication whether the field with the specified id is present.
Definition: fieldbasedtag.h:278
TagParser::FieldMapBasedTag::proposedDataType
TagDataType proposedDataType(const IdentifierType &id) const
Returns the proposed data type for the field with the specified id.
Definition: fieldbasedtag.h:354
TagParser::FieldMapBasedTag::fields
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.
Definition: fieldbasedtag.h:292
TagParser::FieldMapBasedTag
The FieldMapBasedTag provides a generic implementation of Tag which stores the tag fields using std::...
Definition: fieldbasedtag.h:31
TagParser::TagValue
The TagValue class wraps values of different types.
Definition: tagvalue.h:75
TagParser::FieldMapBasedTag::setValues
bool setValues(KnownField field, const std::vector< TagValue > &values)
Assigns the given values to the field with the specified id.
Definition: fieldbasedtag.h:251
TagParser::FieldMapBasedTag::insertFields
int insertFields(const FieldMapBasedTag< ImplementationType > &from, bool overwrite)
Inserts all fields from another tag of the same field type and compare function.
Definition: fieldbasedtag.h:366
TagParser::Tag::type
virtual TagType type() const
Returns the type of the tag as TagParser::TagType.
Definition: tag.h:149
TagParser::FieldMapBasedTag< Mp4Tag >::Compare
typename FieldMapBasedTagTraits< Mp4Tag >::Compare Compare
Definition: fieldbasedtag.h:37
TagParser::FieldMapBasedTag::setValue
bool setValue(KnownField field, const TagValue &value)
Assigns the given value to the specified field.
Definition: fieldbasedtag.h:174
tag.h
TagParser::FieldMapBasedTag::proposedDataType
virtual TagDataType proposedDataType(KnownField field) const
Returns the proposed data type for the specified field as TagDataType.
Definition: tag.h:214
TagParser::FieldMapBasedTag::fieldId
IdentifierType fieldId(KnownField value) const
Returns the ID for the specified field.
Definition: fieldbasedtag.h:321
TagParser::FieldMapBasedTagTraits
Defines traits for the specified ImplementationType.
Definition: fieldbasedtag.h:17
TagParser::FieldMapBasedTag::internallySetValues
bool internallySetValues(const IdentifierType &id, const std::vector< TagValue > &values)
Default implementation for setValues().
Definition: fieldbasedtag.h:201
TagParser::TagValue::empty
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
Definition: tagvalue.cpp:961
TagParser::FieldMapBasedTag::internallyGetValues
std::vector< const TagValue * > internallyGetValues(const IdentifierType &id) const
Default implementation for values().
Definition: fieldbasedtag.h:134
TagParser::TagType
TagType
Specifies the tag type.
Definition: tag.h:20
TagParser::FieldMapBasedTag::internallySetValue
bool internallySetValue(const IdentifierType &id, const TagValue &value)
Default implementation for setValue().
Definition: fieldbasedtag.h:183
TagParser::FieldMapBasedTag::fieldCount
unsigned int fieldCount() const
Returns the number of present fields.
Definition: fieldbasedtag.h:305