Tag Parser  6.4.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 FIELDBASEDTAG_H
2 #define FIELDBASEDTAG_H
3 
4 #include "./tag.h"
5 
6 #include <map>
7 #include <functional>
8 
9 namespace Media {
10 
24 template <class FieldType, class Compare = std::less<typename FieldType::identifierType> >
25 class FieldMapBasedTag : public Tag
26 {
27 public:
29 
30  virtual const TagValue &value(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism
31  const TagValue &value(KnownField field) const;
32  std::vector<const TagValue *> values(const typename FieldType::identifierType &id) const;
33  std::vector<const TagValue *> values(KnownField field) const;
34  virtual bool setValue(const typename FieldType::identifierType &id, const TagValue &value); // FIXME: use static polymorphism
35  bool setValue(KnownField field, const TagValue &value);
36  bool setValues(const typename FieldType::identifierType &id, const std::vector<TagValue> &values);
37  bool setValues(KnownField field, const std::vector<TagValue> &values);
38  bool hasField(KnownField field) const;
39  virtual bool hasField(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism
40  void removeAllFields();
41  const std::multimap<typename FieldType::identifierType, FieldType, Compare> &fields() const;
42  std::multimap<typename FieldType::identifierType, FieldType, Compare> &fields();
43  unsigned int fieldCount() const;
44  virtual typename FieldType::identifierType fieldId(KnownField value) const = 0; // FIXME: use static polymorphism
45  virtual KnownField knownField(const typename FieldType::identifierType &id) const = 0; // FIXME: use static polymorphism
46  bool supportsField(KnownField field) const;
48  virtual TagDataType proposedDataType(const typename FieldType::identifierType &id) const; // FIXME: use static polymorphism
49  int insertFields(const FieldMapBasedTag<FieldType, Compare> &from, bool overwrite);
50  unsigned int insertValues(const Tag &from, bool overwrite);
52  typedef FieldType fieldType;
53 
54 private:
55  std::multimap<typename FieldType::identifierType, FieldType, Compare> m_fields;
56 };
57 
75 template <class FieldType, class Compare>
77 {}
78 
83 template <class FieldType, class Compare>
84 inline const TagValue &FieldMapBasedTag<FieldType, Compare>::value(const typename FieldType::identifierType &id) const
85 {
86  auto i = m_fields.find(id);
87  return i != m_fields.end() ? i->second.value() : TagValue::empty();
88 }
89 
90 template <class FieldType, class Compare>
92 {
93  return value(fieldId(field));
94 }
95 
100 template <class FieldType, class Compare>
101 inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(const typename FieldType::identifierType &id) const
102 {
103  auto range = m_fields.equal_range(id);
104  std::vector<const TagValue *> values;
105  for(auto i = range.first; i != range.second; ++i) {
106  if(!i->second.value().isEmpty()) {
107  values.push_back(&i->second.value());
108  }
109  }
110  return values;
111 }
112 
113 template <class FieldType, class Compare>
114 inline std::vector<const TagValue *> FieldMapBasedTag<FieldType, Compare>::values(KnownField field) const
115 {
116  return values(fieldId(field));
117 }
118 
119 template <class FieldType, class Compare>
121 {
122  return setValue(fieldId(field), value);
123 }
124 
129 template <class FieldType, class Compare>
130 bool FieldMapBasedTag<FieldType, Compare>::setValue(const typename FieldType::identifierType &id, const Media::TagValue &value)
131 {
132  auto i = m_fields.find(id);
133  if(i != m_fields.end()) { // field already exists -> set its value
134  i->second.setValue(value);
135  } else if(!value.isEmpty()) { // field doesn't exist -> create new one if value is not null
136  m_fields.insert(std::make_pair(id, FieldType(id, value)));
137  } else { // otherwise return false
138  return false;
139  }
140  return true;
141 }
142 
149 template <class FieldType, class Compare>
150 bool FieldMapBasedTag<FieldType, Compare>::setValues(const typename FieldType::identifierType &id, const std::vector<TagValue> &values)
151 {
152  auto valuesIterator = values.cbegin();
153  auto range = m_fields.equal_range(id);
154  // iterate through all specified and all existing values
155  for(; valuesIterator != values.cend() && range.first != range.second; ++valuesIterator) {
156  // replace existing value with non-empty specified value
157  if(!valuesIterator->isEmpty()) {
158  range.first->second.setValue(*valuesIterator);
159  ++range.first;
160  }
161  }
162  // add remaining specified values (there are more specified values than existing ones)
163  for(; valuesIterator != values.cend(); ++valuesIterator) {
164  m_fields.insert(std::make_pair(id, FieldType(id, *valuesIterator)));
165  }
166  // remove remaining existing values (there are more existing values than specified ones)
167  for(; range.first != range.second; ++range.first) {
168  range.first->second.setValue(TagValue());
169  }
170  return true;
171 }
172 
179 template <class FieldType, class Compare>
180 bool FieldMapBasedTag<FieldType, Compare>::setValues(KnownField field, const std::vector<TagValue> &values)
181 {
182  return setValues(fieldId(field), values);
183 }
184 
185 template <class FieldType, class Compare>
187 {
188  return hasField(fieldId(field));
189 }
190 
194 template <class FieldType, class Compare>
195 inline bool FieldMapBasedTag<FieldType, Compare>::hasField(const typename FieldType::identifierType &id) const
196 {
197  for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
198  if(!range.first->second.value().isEmpty()) {
199  return true;
200  }
201  }
202  return false;
203 }
204 
205 template <class FieldType, class Compare>
207 {
208  m_fields.clear();
209 }
210 
214 template <class FieldType, class Compare>
215 inline const std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields() const
216 {
217  return m_fields;
218 }
219 
223 template <class FieldType, class Compare>
224 inline std::multimap<typename FieldType::identifierType, FieldType, Compare> &FieldMapBasedTag<FieldType, Compare>::fields()
225 {
226  return m_fields;
227 }
228 
229 template <class FieldType, class Compare>
231 {
232  unsigned int count = 0;
233  for(const auto &field : m_fields) {
234  if(!field.second.value().isEmpty()) {
235  ++count;
236  }
237  }
238  return count;
239 }
240 
241 template <class FieldType, class Compare>
243 {
244  static typename FieldType::identifierType def;
245  return fieldId(field) != def;
246 }
247 
251 template <class FieldType, class Compare>
252 inline TagDataType FieldMapBasedTag<FieldType, Compare>::proposedDataType(const typename FieldType::identifierType &id) const
253 {
254  return Tag::proposedDataType(knownField(id));
255 }
256 
263 template <class FieldType, class Compare>
265 {
266  int fieldsInserted = 0;
267  for(const auto &pair : from.fields()) {
268  const FieldType &fromField = pair.second;
269  if(fromField.value().isEmpty())
270  continue;
271  bool fieldInserted = false;
272  auto range = fields().equal_range(fromField.id());
273  for(auto i = range.first; i != range.second; ++i) {
274  FieldType &ownField = i->second;
275  if((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned()
276  && fromField.typeInfo() == ownField.typeInfo())
277  || (!fromField.isTypeInfoAssigned() && ! ownField.isTypeInfoAssigned())) {
278  if(overwrite || ownField.value().isEmpty()) {
279  ownField = fromField;
280  ++fieldsInserted;
281  }
282  fieldInserted = true;
283  continue;
284  }
285  }
286  if(!fieldInserted) {
287  fields().insert(std::make_pair(fromField.id(), fromField));
288  ++fieldsInserted;
289  }
290  }
291  return fieldsInserted;
292 }
293 
294 template <class FieldType, class Compare>
295 unsigned int FieldMapBasedTag<FieldType, Compare>::insertValues(const Tag &from, bool overwrite)
296 {
297  if(type() == from.type()) {
298  // the tags are of the same type, we can insert the fields directly
299  return insertFields(static_cast<const FieldMapBasedTag<FieldType, Compare> &>(from), overwrite);
300  } else {
301  return Tag::insertValues(from, overwrite);
302  }
303 }
304 
305 template <class FieldType, class Compare>
307 {
308  for(auto &field : fields()) {
309  field.second.value().convertDataEncodingForTag(this);
310  }
311 }
312 
313 }
314 
315 #endif // FIELDBASEDTAG_H
virtual FieldType::identifierType fieldId(KnownField value) const =0
Returns the ID for the specified field.
The TagValue class wraps values of different types.
Definition: tagvalue.h:64
bool isEmpty() const
Returns an indication whether an value is assigned.
Definition: tagvalue.h:344
FieldMapBasedTag()
Constructs a new FieldMapBasedTag.
Definition: fieldbasedtag.h:76
KnownField
Specifies the field.
Definition: tag.h:42
virtual KnownField knownField(const typename FieldType::identifierType &id) const =0
Returns the field for the specified ID.
bool setValues(const typename FieldType::identifierType &id, const std::vector< TagValue > &values)
Assigns the given values to the field with the specified id.
std::vector< const TagValue * > values(const typename FieldType::identifierType &id) const
Returns the values of the field with the specified id.
int insertFields(const FieldMapBasedTag< FieldType, Compare > &from, bool overwrite)
Inserts all fields from another tag of the same field type and compare function.
virtual bool setValue(const typename FieldType::identifierType &id, const TagValue &value)
Assigns the given value to the field with the specified id.
virtual unsigned int insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
Definition: tag.cpp:127
const std::multimap< typename FieldType::identifierType, FieldType, Compare > & fields() const
Returns the fields of the tag by providing direct access to the field map of the tag.
unsigned int insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
virtual const TagValue & value(const typename FieldType::identifierType &id) const
Returns the value of the field with the specified id.
Definition: fieldbasedtag.h:84
virtual TagType type() const
Returns the type of the tag as Media::TagType.
Definition: tag.h:154
The Tag class is used to store, read and write tag information.
Definition: tag.h:98
The FieldMapBasedTag provides a generic implementation of Tag which stores the tag fields using std::...
Definition: fieldbasedtag.h:25
bool supportsField(KnownField field) const
Returns an indication whether the specified field is supported by the tag.
void removeAllFields()
Removes all fields from the tag.
TagDataType
Specifies the data type.
Definition: tagvalue.h:51
static const TagValue & empty()
Returns an empty TagValue.
Definition: tagvalue.cpp:739
virtual TagDataType proposedDataType(KnownField field) const
Returns the proposed data type for the specified field as TagDataType.
Definition: tag.h:314
Contains all classes and functions of the TagInfo library.
Definition: exceptions.h:9
virtual TagDataType proposedDataType(const typename FieldType::identifierType &id) const
Returns the proposed data type for 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 hasField(KnownField field) const
Returns an indication whether the specified field is present.
unsigned int fieldCount() const
Returns the number of present fields.