Tag Parser 11.5.1
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
Loading...
Searching...
No Matches
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
9namespace TagParser {
10
17template <typename ImplementationType> class FieldMapBasedTagTraits {
18};
19
31template <class ImplementationType> class FieldMapBasedTag : public Tag {
32 friend class FieldMapBasedTagTraits<ImplementationType>;
33
34public:
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
67protected:
69
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
80private:
81 std::multimap<IdentifierType, FieldType, Compare> m_fields;
82};
83
102{
103}
104
105template <class ImplementationType> TagType FieldMapBasedTag<ImplementationType>::type() const
106{
107 return ImplementationType::tagType;
108}
109
110template <class ImplementationType> std::string_view FieldMapBasedTag<ImplementationType>::typeName() const
111{
112 return ImplementationType::tagName;
113}
114
116{
117 return ImplementationType::defaultTextEncoding;
118}
119
124template <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
134template <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
147template <class ImplementationType>
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
162template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(const IdentifierType &id) const
163{
164 return static_cast<const ImplementationType *>(this)->internallyGetValue(id);
165}
166
167template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(KnownField field) const
168{
169 return value(fieldId(field));
170}
171
176template <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
181template <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
186template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::setValue(KnownField field, const TagValue &value)
187{
188 const auto id = fieldId(field);
189 if constexpr (std::is_arithmetic_v<IdentifierType>) {
190 if (!id) {
191 return false;
192 }
193 } else {
194 if (id.empty()) {
195 return false;
196 }
197 }
198 return setValue(id, value);
199}
200
205template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallySetValue(const IdentifierType &id, const TagValue &value)
206{
207 auto i = m_fields.find(id);
208 if (i != m_fields.end()) { // field already exists -> set its value
209 i->second.setValue(value);
210 } else if (!value.isEmpty()) { // field doesn't exist -> create new one if value is not null
211 m_fields.insert(std::make_pair(id, FieldType(id, value)));
212 } else { // otherwise return false
213 return false;
214 }
215 return true;
216}
217
222template <class ImplementationType>
224{
225 auto valuesIterator = values.cbegin();
226 auto range = m_fields.equal_range(id);
227 // iterate through all specified and all existing values
228 for (; valuesIterator != values.cend() && range.first != range.second; ++valuesIterator) {
229 // replace existing value with non-empty specified value
230 if (!valuesIterator->isEmpty()) {
231 auto &field = range.first->second;
232 field.clearValue();
233 field.setValue(*valuesIterator);
234 ++range.first;
235 }
236 }
237 // add remaining specified values (there are more specified values than existing ones)
238 for (; valuesIterator != values.cend(); ++valuesIterator) {
239 if (!valuesIterator->isEmpty()) {
240 m_fields.insert(std::make_pair(id, FieldType(id, *valuesIterator)));
241 }
242 }
243 // remove remaining existing values (there are more existing values than specified ones)
244 for (; range.first != range.second; ++range.first) {
245 range.first->second.clearValue();
246 }
247 return true;
248}
249
254template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValue(const IdentifierType &id, const TagParser::TagValue &value)
255{
256 return static_cast<ImplementationType *>(this)->internallySetValue(id, value);
257}
258
265template <class ImplementationType>
266bool FieldMapBasedTag<ImplementationType>::setValues(const IdentifierType &id, const std::vector<TagValue> &values)
267{
268 return static_cast<ImplementationType *>(this)->internallySetValues(id, values);
269}
270
277template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValues(KnownField field, const std::vector<TagValue> &values)
278{
279 const auto id = fieldId(field);
280 if constexpr (std::is_arithmetic_v<IdentifierType>) {
281 if (!id) {
282 return false;
283 }
284 } else {
285 if (id.empty()) {
286 return false;
287 }
288 }
289 return setValues(id, values);
290}
291
292template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(KnownField field) const
293{
294 return hasField(fieldId(field));
295}
296
301template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallyHasField(const IdentifierType &id) const
302{
303 for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
304 if (!range.first->second.value().isEmpty()) {
305 return true;
306 }
307 }
308 return false;
309}
310
314template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(const IdentifierType &id) const
315{
316 return static_cast<const ImplementationType *>(this)->internallyHasField(id);
317}
318
319template <class ImplementationType> inline void FieldMapBasedTag<ImplementationType>::removeAllFields()
320{
321 m_fields.clear();
322}
323
327template <class ImplementationType>
329{
330 return m_fields;
331}
332
336template <class ImplementationType> inline auto FieldMapBasedTag<ImplementationType>::fields() -> std::multimap<IdentifierType, FieldType, Compare> &
337{
338 return m_fields;
339}
340
341template <class ImplementationType> std::size_t FieldMapBasedTag<ImplementationType>::fieldCount() const
342{
343 auto count = std::size_t(0);
344 for (const auto &field : m_fields) {
345 if (!field.second.value().isEmpty()) {
346 ++count;
347 }
348 }
349 return count;
350}
351
356template <class ImplementationType>
358{
359 return static_cast<const ImplementationType *>(this)->internallyGetFieldId(value);
360}
361
366template <class ImplementationType> inline KnownField FieldMapBasedTag<ImplementationType>::knownField(const IdentifierType &id) const
367{
368 return static_cast<const ImplementationType *>(this)->internallyGetKnownField(id);
369}
370
371template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::supportsField(KnownField field) const
372{
373 static const auto def = IdentifierType();
374 return fieldId(field) != def;
375}
376
381template <class ImplementationType>
383{
384 return Tag::proposedDataType(knownField(id));
385}
386
390template <class ImplementationType> inline TagDataType FieldMapBasedTag<ImplementationType>::proposedDataType(const IdentifierType &id) const
391{
392 return static_cast<ImplementationType *>(this)->determineProposedDataType(id);
393}
394
401template <class ImplementationType>
403{
404 auto fieldsInserted = std::size_t(0);
405 for (const auto &pair : from.fields()) {
406 const FieldType &fromField = pair.second;
407 if (fromField.value().isEmpty()) {
408 continue;
409 }
410 bool fieldInserted = false;
411 auto range = fields().equal_range(fromField.id());
412 for (auto i = range.first; i != range.second; ++i) {
413 FieldType &ownField = i->second;
414 if ((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned() && fromField.typeInfo() == ownField.typeInfo())
415 || (!fromField.isTypeInfoAssigned() && !ownField.isTypeInfoAssigned())) {
416 if (overwrite || ownField.value().isEmpty()) {
417 ownField = fromField;
418 ++fieldsInserted;
419 }
420 fieldInserted = true;
421 continue;
422 }
423 }
424 if (!fieldInserted) {
425 fields().insert(std::make_pair(fromField.id(), fromField));
426 ++fieldsInserted;
427 }
428 }
429 return fieldsInserted;
430}
431
432template <class ImplementationType> std::size_t FieldMapBasedTag<ImplementationType>::insertValues(const Tag &from, bool overwrite)
433{
434 if (type() == from.type()) {
435 // the tags are of the same type, we can insert the fields directly
436 return insertFields(static_cast<const FieldMapBasedTag<ImplementationType> &>(from), overwrite);
437 } else {
438 return Tag::insertValues(from, overwrite);
439 }
440}
441
443{
444 for (auto &field : fields()) {
445 field.second.value().convertDataEncodingForTag(this);
446 }
447}
448
449} // namespace TagParser
450
451#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.
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:143
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
Definition: tagvalue.cpp:1289
bool isEmpty() const
Returns whether no or an empty value is assigned.
Definition: tagvalue.h:617
The Tag class is used to store, read and write tag information.
Definition: tag.h:163
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:205
virtual TagDataType proposedDataType(KnownField field) const
Returns the proposed data type for the specified field as TagDataType.
Definition: tag.h:275
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
KnownField
Specifies the field.
Definition: tag.h:28
TagTextEncoding
Specifies the text encoding.
Definition: tagvalue.h:29
TagType
Specifies the tag type.
Definition: tagtype.h:11
TagDataType
Specifies the data type.
Definition: tagvalue.h:119