Tag Parser: fieldbasedtag.h Source File

Tag Parser 12.5.3 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
17 template <typename ImplementationType> class FieldMapBasedTagTraits {};
18
30 template <class ImplementationType> class FieldMapBasedTag : public Tag {
31 friend class FieldMapBasedTagTraits<ImplementationType>;
32
33public:
34 using FieldType = typename FieldMapBasedTagTraits<ImplementationType>::FieldType;
35 using IdentifierType = typename FieldMapBasedTagTraits<ImplementationType>::FieldType::IdentifierType;
36 using Compare = typename FieldMapBasedTagTraits<ImplementationType>::Compare;
37
38 FieldMapBasedTag();
39
40 TagType type() const;
41 std::string_view typeName() const;
42 TagTextEncoding proposedTextEncoding() const;
43 const TagValue &value(const IdentifierType &id) const;
44 const TagValue &value(KnownField field) const;
45 std::vector<const TagValue *> values(const IdentifierType &id) const;
46 std::vector<const TagValue *> values(KnownField field) const;
47 bool setValue(const IdentifierType &id, const TagValue &value);
48 bool setValue(KnownField field, const TagValue &value);
49 bool setValues(const IdentifierType &id, const std::vector<TagValue> &values);
50 bool setValues(KnownField field, const std::vector<TagValue> &values);
51 bool hasField(KnownField field) const;
52 bool hasField(const IdentifierType &id) const;
53 void removeAllFields();
54 const std::multimap<IdentifierType, FieldType, Compare> &fields() const;
55 std::multimap<IdentifierType, FieldType, Compare> &fields();
56 std::size_t fieldCount() const;
57 IdentifierType fieldId(KnownField value) const;
58 KnownField knownField(const IdentifierType &id) const;
59 bool supportsField(KnownField field) const;
60 using Tag::proposedDataType;
61 TagDataType proposedDataType(const IdentifierType &id) const;
62 std::size_t insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite);
63 std::size_t insertValues(const Tag &from, bool overwrite);
64 void ensureTextValuesAreProperlyEncoded();
65
66protected:
67 using CRTPBase = FieldMapBasedTag<ImplementationType>;
68
69 const TagValue &internallyGetValue(const IdentifierType &id) const;
70 void internallyGetValuesFromField(const FieldType &field, std::vector<const TagValue *> &values) const;
71 std::vector<const TagValue *> internallyGetValues(const IdentifierType &id) const;
72 bool internallySetValue(const IdentifierType &id, const TagValue &value);
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;
77 TagDataType internallyGetProposedDataType(const IdentifierType &id) const;
78
79private:
80 std::multimap<IdentifierType, FieldType, Compare> m_fields;
81};
82
89
96
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> std::string_view FieldMapBasedTag<ImplementationType>::typeName() const
110{
111 return ImplementationType::tagName;
112}
113
114 template <class ImplementationType> TagTextEncoding FieldMapBasedTag<ImplementationType>::proposedTextEncoding() const
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
133template <class ImplementationType>
134 void FieldMapBasedTag<ImplementationType>::internallyGetValuesFromField(
135 const FieldMapBasedTag<ImplementationType>::FieldType &field, std::vector<const TagValue *> &values) const
136{
137 if (!field.value().isEmpty()) {
138 values.emplace_back(&field.value());
139 }
140}
141
146template <class ImplementationType>
147std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::internallyGetValues(const IdentifierType &id) const
148{
149 auto range = m_fields.equal_range(id);
150 std::vector<const TagValue *> values;
151 for (auto i = range.first; i != range.second; ++i) {
152 static_cast<const ImplementationType *>(this)->internallyGetValuesFromField(i->second, values);
153 }
154 return values;
155}
156
161 template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(const IdentifierType &id) const
162{
163 return static_cast<const ImplementationType *>(this)->internallyGetValue(id);
164}
165
166 template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(KnownField field) const
167{
168 return value(fieldId(field));
169}
170
175 template <class ImplementationType> inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(const IdentifierType &id) const
176{
177 return static_cast<const ImplementationType *>(this)->internallyGetValues(id);
178}
179
180 template <class ImplementationType> inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(KnownField field) const
181{
182 return static_cast<const ImplementationType *>(this)->values(fieldId(field));
183}
184
185 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::setValue(KnownField field, const TagValue &value)
186{
187 const auto id = fieldId(field);
188 if constexpr (std::is_arithmetic_v<IdentifierType>) {
189 if (!id) {
190 return false;
191 }
192 } else {
193 if (id.empty()) {
194 return false;
195 }
196 }
197 return setValue(id, value);
198}
199
204 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallySetValue(const IdentifierType &id, const TagValue &value)
205{
206 auto i = m_fields.find(id);
207 if (i != m_fields.end()) { // field already exists -> set its value
208 i->second.setValue(value);
209 } else if (!value.isEmpty()) { // field doesn't exist -> create new one if value is not null
210 m_fields.insert(std::make_pair(id, FieldType(id, value)));
211 } else { // otherwise return false
212 return false;
213 }
214 return true;
215}
216
221template <class ImplementationType>
222 bool FieldMapBasedTag<ImplementationType>::internallySetValues(const FieldMapBasedTag::IdentifierType &id, const std::vector<TagValue> &values)
223{
224 auto valuesIterator = values.cbegin();
225 auto range = m_fields.equal_range(id);
226 // iterate through all specified and all existing values
227 for (; valuesIterator != values.cend() && range.first != range.second; ++valuesIterator) {
228 // replace existing value with non-empty specified value
229 if (!valuesIterator->isEmpty()) {
230 auto &field = range.first->second;
231 field.clearValue();
232 field.setValue(*valuesIterator);
233 ++range.first;
234 }
235 }
236 // add remaining specified values (there are more specified values than existing ones)
237 for (; valuesIterator != values.cend(); ++valuesIterator) {
238 if (!valuesIterator->isEmpty()) {
239 m_fields.insert(std::make_pair(id, FieldType(id, *valuesIterator)));
240 }
241 }
242 // remove remaining existing values (there are more existing values than specified ones)
243 for (; range.first != range.second; ++range.first) {
244 range.first->second.clearValue();
245 }
246 return true;
247}
248
253 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValue(const IdentifierType &id, const TagParser::TagValue &value)
254{
255 return static_cast<ImplementationType *>(this)->internallySetValue(id, value);
256}
257
264template <class ImplementationType>
265 bool FieldMapBasedTag<ImplementationType>::setValues(const IdentifierType &id, const std::vector<TagValue> &values)
266{
267 return static_cast<ImplementationType *>(this)->internallySetValues(id, values);
268}
269
276 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValues(KnownField field, const std::vector<TagValue> &values)
277{
278 const auto id = fieldId(field);
279 if constexpr (std::is_arithmetic_v<IdentifierType>) {
280 if (!id) {
281 return false;
282 }
283 } else {
284 if (id.empty()) {
285 return false;
286 }
287 }
288 return setValues(id, values);
289}
290
291 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(KnownField field) const
292{
293 return hasField(fieldId(field));
294}
295
300 template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallyHasField(const IdentifierType &id) const
301{
302 for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
303 if (!range.first->second.value().isEmpty()) {
304 return true;
305 }
306 }
307 return false;
308}
309
313 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(const IdentifierType &id) const
314{
315 return static_cast<const ImplementationType *>(this)->internallyHasField(id);
316}
317
318 template <class ImplementationType> inline void FieldMapBasedTag<ImplementationType>::removeAllFields()
319{
320 m_fields.clear();
321}
322
326template <class ImplementationType>
327 inline auto FieldMapBasedTag<ImplementationType>::fields() const -> const std::multimap<IdentifierType, FieldType, Compare> &
328{
329 return m_fields;
330}
331
335 template <class ImplementationType> inline auto FieldMapBasedTag<ImplementationType>::fields() -> std::multimap<IdentifierType, FieldType, Compare> &
336{
337 return m_fields;
338}
339
340 template <class ImplementationType> std::size_t FieldMapBasedTag<ImplementationType>::fieldCount() const
341{
342 auto count = std::size_t(0);
343 for (const auto &field : m_fields) {
344 if (!field.second.value().isEmpty()) {
345 ++count;
346 }
347 }
348 return count;
349}
350
355template <class ImplementationType>
356 inline typename FieldMapBasedTag<ImplementationType>::IdentifierType FieldMapBasedTag<ImplementationType>::fieldId(KnownField value) const
357{
358 return static_cast<const ImplementationType *>(this)->internallyGetFieldId(value);
359}
360
365 template <class ImplementationType> inline KnownField FieldMapBasedTag<ImplementationType>::knownField(const IdentifierType &id) const
366{
367 return static_cast<const ImplementationType *>(this)->internallyGetKnownField(id);
368}
369
370 template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::supportsField(KnownField field) const
371{
372 static const auto def = IdentifierType();
373 return fieldId(field) != def;
374}
375
380template <class ImplementationType>
381 inline TagDataType FieldMapBasedTag<ImplementationType>::internallyGetProposedDataType(const IdentifierType &id) const
382{
383 return Tag::proposedDataType(knownField(id));
384}
385
389 template <class ImplementationType> inline TagDataType FieldMapBasedTag<ImplementationType>::proposedDataType(const IdentifierType &id) const
390{
391 return static_cast<ImplementationType *>(this)->determineProposedDataType(id);
392}
393
400template <class ImplementationType>
401std::size_t FieldMapBasedTag<ImplementationType>::insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite)
402{
403 auto fieldsInserted = std::size_t(0);
404 for (const auto &pair : from.fields()) {
405 const FieldType &fromField = pair.second;
406 if (fromField.value().isEmpty()) {
407 continue;
408 }
409 bool fieldInserted = false;
410 auto range = fields().equal_range(fromField.id());
411 for (auto i = range.first; i != range.second; ++i) {
412 FieldType &ownField = i->second;
413 if ((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned() && fromField.typeInfo() == ownField.typeInfo())
414 || (!fromField.isTypeInfoAssigned() && !ownField.isTypeInfoAssigned())) {
415 if (overwrite || ownField.value().isEmpty()) {
416 ownField = fromField;
417 ++fieldsInserted;
418 }
419 fieldInserted = true;
420 continue;
421 }
422 }
423 if (!fieldInserted) {
424 fields().insert(std::make_pair(fromField.id(), fromField));
425 ++fieldsInserted;
426 }
427 }
428 return fieldsInserted;
429}
430
431 template <class ImplementationType> std::size_t FieldMapBasedTag<ImplementationType>::insertValues(const Tag &from, bool overwrite)
432{
433 if (type() == from.type()) {
434 // the tags are of the same type, we can insert the fields directly
435 return insertFields(static_cast<const FieldMapBasedTag<ImplementationType> &>(from), overwrite);
436 } else {
437 return Tag::insertValues(from, overwrite);
438 }
439}
440
441 template <class ImplementationType> void FieldMapBasedTag<ImplementationType>::ensureTextValuesAreProperlyEncoded()
442{
443 for (auto &field : fields()) {
444 field.second.value().convertDataEncodingForTag(this);
445 }
446}
447
448} // namespace TagParser
449
450#endif // TAG_PARSER_FIELDBASEDTAG_H
TagParser::FieldMapBasedTagTraits
Defines traits for the specified ImplementationType.
Definition fieldbasedtag.h:17
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:253
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:441
TagParser::FieldMapBasedTag::hasField
bool hasField(KnownField field) const
Returns an indication whether the specified field is present.
Definition fieldbasedtag.h:291
TagParser::FieldMapBasedTag::internallyGetValues
std::vector< const TagValue * > internallyGetValues(const IdentifierType &id) const
Default implementation for values().
Definition fieldbasedtag.h:147
TagParser::FieldMapBasedTag::Compare
typename FieldMapBasedTagTraits< ImplementationType >::Compare Compare
Definition fieldbasedtag.h:36
TagParser::FieldMapBasedTag::typeName
std::string_view typeName() const
Returns the type name of the tag.
Definition fieldbasedtag.h:109
TagParser::FieldMapBasedTag::IdentifierType
typename FieldMapBasedTagTraits< ImplementationType >::FieldType::IdentifierType IdentifierType
Definition fieldbasedtag.h:35
TagParser::FieldMapBasedTag::FieldMapBasedTag
FieldMapBasedTag()
Constructs a new FieldMapBasedTag.
Definition fieldbasedtag.h:100
TagParser::FieldMapBasedTag::proposedTextEncoding
TagTextEncoding proposedTextEncoding() const
Returns the proposed text encoding.
Definition fieldbasedtag.h:114
TagParser::FieldMapBasedTag::value
const TagValue & value(const IdentifierType &id) const
Returns the value of the field with the specified id.
Definition fieldbasedtag.h:161
TagParser::FieldMapBasedTag::removeAllFields
void removeAllFields()
Removes all fields from the tag.
Definition fieldbasedtag.h:318
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:327
TagParser::FieldMapBasedTag::proposedDataType
TagDataType proposedDataType(const IdentifierType &id) const
Returns the proposed data type for the field with the specified id.
Definition fieldbasedtag.h:389
TagParser::FieldMapBasedTag::internallySetValues
bool internallySetValues(const IdentifierType &id, const std::vector< TagValue > &values)
Default implementation for setValues().
Definition fieldbasedtag.h:222
TagParser::FieldMapBasedTag::type
TagType type() const
Returns the type of the tag as TagParser::TagType.
Definition fieldbasedtag.h:104
TagParser::FieldMapBasedTag::insertFields
std::size_t insertFields(const FieldMapBasedTag< ImplementationType > &from, bool overwrite)
Inserts all fields from another tag of the same field type and compare function.
Definition fieldbasedtag.h:401
TagParser::FieldMapBasedTag::FieldType
typename FieldMapBasedTagTraits< ImplementationType >::FieldType FieldType
Definition fieldbasedtag.h:34
TagParser::FieldMapBasedTag::internallyGetProposedDataType
TagDataType internallyGetProposedDataType(const IdentifierType &id) const
Default implementation for proposedDataType().
Definition fieldbasedtag.h:381
TagParser::FieldMapBasedTag::internallyGetValuesFromField
void internallyGetValuesFromField(const FieldType &field, std::vector< const TagValue * > &values) const
Default way to gather values from a field in internallyGetValues().
Definition fieldbasedtag.h:134
TagParser::FieldMapBasedTag::knownField
KnownField knownField(const IdentifierType &id) const
Returns the field for the specified ID.
Definition fieldbasedtag.h:365
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:175
TagParser::FieldMapBasedTag::CRTPBase
FieldMapBasedTag< ImplementationType > CRTPBase
Definition fieldbasedtag.h:67
TagParser::FieldMapBasedTag::internallyGetValue
const TagValue & internallyGetValue(const IdentifierType &id) const
Default implementation for value().
Definition fieldbasedtag.h:123
TagParser::FieldMapBasedTag::internallyHasField
bool internallyHasField(const IdentifierType &id) const
Default implementation for hasField().
Definition fieldbasedtag.h:300
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:265
TagParser::FieldMapBasedTag::fieldCount
std::size_t fieldCount() const
Returns the number of present fields.
Definition fieldbasedtag.h:340
TagParser::FieldMapBasedTag::supportsField
bool supportsField(KnownField field) const
Returns an indication whether the specified field is supported by the tag.
Definition fieldbasedtag.h:370
TagParser::FieldMapBasedTag::fieldId
IdentifierType fieldId(KnownField value) const
Returns the ID for the specified field.
Definition fieldbasedtag.h:356
TagParser::FieldMapBasedTag::insertValues
std::size_t insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
Definition fieldbasedtag.h:431
TagParser::FieldMapBasedTag::internallySetValue
bool internallySetValue(const IdentifierType &id, const TagValue &value)
Default implementation for setValue().
Definition fieldbasedtag.h:204
TagParser::TagValue
The TagValue class wraps values of different types.
Definition tagvalue.h:147
TagParser::TagValue::empty
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
Definition tagvalue.cpp:1432
TagParser::TagValue::isEmpty
bool isEmpty() const
Returns whether no or an empty value is assigned.
Definition tagvalue.h:490
TagParser::Tag::insertValues
virtual std::size_t insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
Definition tag.cpp:89
TagParser::Tag::type
virtual TagType type() const
Returns the type of the tag as TagParser::TagType.
Definition tag.h:222
TagParser::Tag::proposedDataType
virtual TagDataType proposedDataType(KnownField field) const
Returns the proposed data type for the specified field as TagDataType.
Definition tag.h:292
TagParser::Tag::Tag
Tag()
Constructs a new Tag.
Definition tag.cpp:24
TagParser
Contains all classes and functions of the TagInfo library.
Definition aaccodebook.h:10
TagParser::KnownField
KnownField
Specifies the field.
Definition tag.h:37
TagParser::TagTextEncoding
TagTextEncoding
Specifies the text encoding.
Definition tagvalue.h:29
TagParser::TagType
TagType
Specifies the tag type.
Definition tagtype.h:11
TagParser::TagDataType
TagDataType
Specifies the data type.
Definition tagvalue.h:119
tag.h