2018-03-06 23:09:15 +01:00
|
|
|
#ifndef TAG_PARSER_FIELDBASEDTAG_H
|
|
|
|
#define TAG_PARSER_FIELDBASEDTAG_H
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2015-09-06 19:57:33 +02:00
|
|
|
#include "./tag.h"
|
2015-04-22 19:22:01 +02:00
|
|
|
|
|
|
|
#include <functional>
|
2018-03-07 01:17:50 +01:00
|
|
|
#include <map>
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-06 23:09:15 +01:00
|
|
|
namespace TagParser {
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2017-03-07 00:02:59 +01:00
|
|
|
/*!
|
2018-06-03 20:38:32 +02:00
|
|
|
* \class TagParser::FieldMapBasedTagTraits
|
2017-03-07 00:02:59 +01:00
|
|
|
* \brief Defines traits for the specified \a ImplementationType.
|
|
|
|
*
|
|
|
|
* A template specialization for each FieldMapBasedTag subclass must be provided.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <typename ImplementationType> class FieldMapBasedTagTraits {
|
|
|
|
};
|
2017-03-07 00:02:59 +01:00
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
2018-06-03 20:38:32 +02:00
|
|
|
* \class TagParser::FieldMapBasedTag
|
2015-04-22 19:22:01 +02:00
|
|
|
* \brief The FieldMapBasedTag provides a generic implementation of Tag which stores
|
|
|
|
* the tag fields using std::multimap.
|
|
|
|
*
|
|
|
|
* The FieldMapBasedTag class only provides the interface and common functionality.
|
2017-03-07 01:52:26 +01:00
|
|
|
* It is meant to be subclassed using CRTP pattern.
|
2015-04-22 19:22:01 +02:00
|
|
|
*
|
2017-03-07 01:52:26 +01:00
|
|
|
* \remarks This template class is intended to be subclassed using
|
|
|
|
* with the "Curiously recurring template pattern".
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> class FieldMapBasedTag : public Tag {
|
2017-03-07 00:02:59 +01:00
|
|
|
friend class FieldMapBasedTagTraits<ImplementationType>;
|
2017-03-07 01:52:26 +01:00
|
|
|
|
|
|
|
public:
|
2018-07-11 13:19:43 +02:00
|
|
|
using FieldType = typename FieldMapBasedTagTraits<ImplementationType>::FieldType;
|
|
|
|
using IdentifierType = typename FieldMapBasedTagTraits<ImplementationType>::FieldType::IdentifierType;
|
|
|
|
using Compare = typename FieldMapBasedTagTraits<ImplementationType>::Compare;
|
2017-03-07 00:02:59 +01:00
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
FieldMapBasedTag();
|
|
|
|
|
2017-03-07 00:02:59 +01:00
|
|
|
TagType type() const;
|
|
|
|
const char *typeName() const;
|
|
|
|
TagTextEncoding proposedTextEncoding() const;
|
2017-03-07 17:16:17 +01:00
|
|
|
const TagValue &value(const IdentifierType &id) const;
|
2016-08-05 01:46:31 +02:00
|
|
|
const TagValue &value(KnownField field) const;
|
2017-03-07 17:16:17 +01:00
|
|
|
std::vector<const TagValue *> values(const IdentifierType &id) const;
|
2016-08-14 22:50:45 +02:00
|
|
|
std::vector<const TagValue *> values(KnownField field) const;
|
2017-03-07 17:16:17 +01:00
|
|
|
bool setValue(const IdentifierType &id, const TagValue &value);
|
2016-08-05 01:46:31 +02:00
|
|
|
bool setValue(KnownField field, const TagValue &value);
|
2017-03-07 17:16:17 +01:00
|
|
|
bool setValues(const IdentifierType &id, const std::vector<TagValue> &values);
|
2016-08-14 22:50:45 +02:00
|
|
|
bool setValues(KnownField field, const std::vector<TagValue> &values);
|
2016-08-05 01:46:31 +02:00
|
|
|
bool hasField(KnownField field) const;
|
2017-03-07 17:16:17 +01:00
|
|
|
bool hasField(const IdentifierType &id) const;
|
2016-08-05 01:46:31 +02:00
|
|
|
void removeAllFields();
|
2017-03-07 17:16:17 +01:00
|
|
|
const std::multimap<IdentifierType, FieldType, Compare> &fields() const;
|
|
|
|
std::multimap<IdentifierType, FieldType, Compare> &fields();
|
2016-08-05 01:46:31 +02:00
|
|
|
unsigned int fieldCount() const;
|
2017-03-07 17:16:17 +01:00
|
|
|
IdentifierType fieldId(KnownField value) const;
|
|
|
|
KnownField knownField(const IdentifierType &id) const;
|
2016-08-05 01:46:31 +02:00
|
|
|
bool supportsField(KnownField field) const;
|
2015-04-22 19:22:01 +02:00
|
|
|
using Tag::proposedDataType;
|
2017-03-07 17:16:17 +01:00
|
|
|
TagDataType proposedDataType(const IdentifierType &id) const;
|
2017-03-07 00:02:59 +01:00
|
|
|
int insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite);
|
2016-08-05 01:46:31 +02:00
|
|
|
unsigned int insertValues(const Tag &from, bool overwrite);
|
|
|
|
void ensureTextValuesAreProperlyEncoded();
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2017-03-07 01:52:26 +01:00
|
|
|
protected:
|
2018-07-11 15:53:23 +02:00
|
|
|
using CRTPBase = FieldMapBasedTag<ImplementationType>;
|
|
|
|
|
2017-03-07 17:16:17 +01:00
|
|
|
const TagValue &internallyGetValue(const IdentifierType &id) const;
|
2018-07-11 15:53:23 +02:00
|
|
|
std::vector<const TagValue *> internallyGetValues(const IdentifierType &id) const;
|
2017-03-07 17:16:17 +01:00
|
|
|
bool internallySetValue(const IdentifierType &id, const TagValue &value);
|
2018-07-11 15:53:23 +02:00
|
|
|
bool internallySetValues(const IdentifierType &id, const std::vector<TagValue> &values);
|
2017-03-07 17:16:17 +01:00
|
|
|
bool internallyHasField(const IdentifierType &id) const;
|
|
|
|
// no default implementation: IdentifierType internallyGetFieldId(KnownField field) const;
|
|
|
|
// no default implementation: KnownField internallyGetKnownField(const IdentifierType &id) const;
|
|
|
|
TagDataType internallyGetProposedDataType(const IdentifierType &id) const;
|
2017-03-07 01:52:26 +01:00
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
private:
|
2017-03-07 17:16:17 +01:00
|
|
|
std::multimap<IdentifierType, FieldType, Compare> m_fields;
|
2015-04-22 19:22:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn FieldMapBasedTag::fieldId()
|
|
|
|
* \brief Returns the ID for the specified \a field.
|
|
|
|
*
|
|
|
|
* Needs to be implemented when subclassing.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \fn FieldMapBasedTag::knownField()
|
|
|
|
* \brief Returns the field for the specified \a ID.
|
|
|
|
*
|
|
|
|
* Needs to be implemented when subclassing.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Constructs a new FieldMapBasedTag.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> FieldMapBasedTag<ImplementationType>::FieldMapBasedTag()
|
|
|
|
{
|
|
|
|
}
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> TagType FieldMapBasedTag<ImplementationType>::type() const
|
2017-03-07 00:02:59 +01:00
|
|
|
{
|
|
|
|
return ImplementationType::tagType;
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> const char *FieldMapBasedTag<ImplementationType>::typeName() const
|
2017-03-07 00:02:59 +01:00
|
|
|
{
|
|
|
|
return ImplementationType::tagName;
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> TagTextEncoding FieldMapBasedTag<ImplementationType>::proposedTextEncoding() const
|
2017-03-07 00:02:59 +01:00
|
|
|
{
|
|
|
|
return ImplementationType::defaultTextEncoding;
|
|
|
|
}
|
|
|
|
|
2017-03-07 01:52:26 +01:00
|
|
|
/*!
|
|
|
|
* \brief Default implementation for value().
|
|
|
|
* \remarks Shadow in subclass to provide custom implementation.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> const TagValue &FieldMapBasedTag<ImplementationType>::internallyGetValue(const IdentifierType &id) const
|
2017-03-07 01:52:26 +01:00
|
|
|
{
|
|
|
|
auto i = m_fields.find(id);
|
|
|
|
return i != m_fields.end() ? i->second.value() : TagValue::empty();
|
|
|
|
}
|
|
|
|
|
2018-07-11 15:53:23 +02:00
|
|
|
/*!
|
|
|
|
* \brief Default implementation for values().
|
|
|
|
* \remarks Shadow in subclass to provide custom implementation.
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
|
|
|
std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::internallyGetValues(const IdentifierType &id) const
|
|
|
|
{
|
|
|
|
auto range = m_fields.equal_range(id);
|
|
|
|
std::vector<const TagValue *> values;
|
|
|
|
for (auto i = range.first; i != range.second; ++i) {
|
|
|
|
if (!i->second.value().isEmpty()) {
|
|
|
|
values.push_back(&i->second.value());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the value of the field with the specified \a id.
|
2016-08-04 00:16:19 +02:00
|
|
|
* \sa Tag::value()
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(const IdentifierType &id) const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2017-03-07 01:52:26 +01:00
|
|
|
return static_cast<const ImplementationType *>(this)->internallyGetValue(id);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline const TagValue &FieldMapBasedTag<ImplementationType>::value(KnownField field) const
|
2016-08-04 00:16:19 +02:00
|
|
|
{
|
|
|
|
return value(fieldId(field));
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the values of the field with the specified \a id.
|
2016-08-04 00:16:19 +02:00
|
|
|
* \sa Tag::values()
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(const IdentifierType &id) const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2018-07-11 15:53:23 +02:00
|
|
|
return static_cast<const ImplementationType *>(this)->internallyGetValues(id);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline std::vector<const TagValue *> FieldMapBasedTag<ImplementationType>::values(KnownField field) const
|
2016-08-04 00:16:19 +02:00
|
|
|
{
|
2018-07-11 15:53:23 +02:00
|
|
|
return static_cast<const ImplementationType *>(this)->values(fieldId(field));
|
2016-08-04 00:16:19 +02:00
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::setValue(KnownField field, const TagValue &value)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return setValue(fieldId(field), value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2017-03-07 01:52:26 +01:00
|
|
|
* \brief Default implementation for setValue().
|
|
|
|
* \remarks Shadow in subclass to provide custom implementation.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallySetValue(const IdentifierType &id, const TagValue &value)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
auto i = m_fields.find(id);
|
2018-03-07 01:17:50 +01:00
|
|
|
if (i != m_fields.end()) { // field already exists -> set its value
|
2015-04-22 19:22:01 +02:00
|
|
|
i->second.setValue(value);
|
2018-03-07 01:17:50 +01:00
|
|
|
} else if (!value.isEmpty()) { // field doesn't exist -> create new one if value is not null
|
2017-03-07 17:16:17 +01:00
|
|
|
m_fields.insert(std::make_pair(id, FieldType(id, value)));
|
2015-04-22 19:22:01 +02:00
|
|
|
} else { // otherwise return false
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-03-07 01:52:26 +01:00
|
|
|
/*!
|
2018-07-11 15:53:23 +02:00
|
|
|
* \brief Default implementation for setValues().
|
|
|
|
* \remarks Shadow in subclass to provide custom implementation.
|
2016-08-04 00:16:19 +02:00
|
|
|
*/
|
2017-03-07 00:02:59 +01:00
|
|
|
template <class ImplementationType>
|
2018-07-11 15:53:23 +02:00
|
|
|
bool FieldMapBasedTag<ImplementationType>::internallySetValues(const FieldMapBasedTag::IdentifierType &id, const std::vector<TagValue> &values)
|
2016-08-04 00:16:19 +02:00
|
|
|
{
|
2016-11-14 22:59:19 +01:00
|
|
|
auto valuesIterator = values.cbegin();
|
2016-08-04 00:16:19 +02:00
|
|
|
auto range = m_fields.equal_range(id);
|
2017-06-14 22:46:33 +02:00
|
|
|
// iterate through all specified and all existing values
|
2018-03-07 01:17:50 +01:00
|
|
|
for (; valuesIterator != values.cend() && range.first != range.second; ++valuesIterator) {
|
2017-06-14 22:46:33 +02:00
|
|
|
// replace existing value with non-empty specified value
|
2018-03-07 01:17:50 +01:00
|
|
|
if (!valuesIterator->isEmpty()) {
|
2016-08-04 00:16:19 +02:00
|
|
|
range.first->second.setValue(*valuesIterator);
|
|
|
|
++range.first;
|
|
|
|
}
|
|
|
|
}
|
2017-06-14 22:46:33 +02:00
|
|
|
// add remaining specified values (there are more specified values than existing ones)
|
2018-03-07 01:17:50 +01:00
|
|
|
for (; valuesIterator != values.cend(); ++valuesIterator) {
|
2017-03-07 17:16:17 +01:00
|
|
|
m_fields.insert(std::make_pair(id, FieldType(id, *valuesIterator)));
|
2016-08-04 00:16:19 +02:00
|
|
|
}
|
2017-06-14 22:46:33 +02:00
|
|
|
// remove remaining existing values (there are more existing values than specified ones)
|
2018-03-07 01:17:50 +01:00
|
|
|
for (; range.first != range.second; ++range.first) {
|
2016-08-04 00:16:19 +02:00
|
|
|
range.first->second.setValue(TagValue());
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-11 15:53:23 +02:00
|
|
|
/*!
|
|
|
|
* \brief Assigns the given \a value to the field with the specified \a id.
|
|
|
|
* \sa Tag::setValue()
|
|
|
|
*/
|
|
|
|
template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValue(const IdentifierType &id, const TagParser::TagValue &value)
|
|
|
|
{
|
|
|
|
return static_cast<ImplementationType *>(this)->internallySetValue(id, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Assigns the given \a values to the field with the specified \a id.
|
|
|
|
* \remarks There might me more than one value assigned to an \a id. Whereas setValue() only alters the first value, this
|
|
|
|
* method will replace all currently assigned values with the specified \a values.
|
|
|
|
* \sa Tag::setValues()
|
|
|
|
*/
|
|
|
|
template <class ImplementationType>
|
|
|
|
bool FieldMapBasedTag<ImplementationType>::setValues(const IdentifierType &id, const std::vector<TagValue> &values)
|
|
|
|
{
|
|
|
|
return static_cast<ImplementationType *>(this)->internallySetValues(id, values);
|
|
|
|
}
|
|
|
|
|
2016-08-04 00:16:19 +02:00
|
|
|
/*!
|
|
|
|
* \brief Assigns the given \a values to the field with the specified \a id.
|
2017-03-01 18:21:00 +01:00
|
|
|
* \remarks There might me more than one value assigned to a \a field. Whereas setValue() only alters the first value, this
|
2016-08-04 00:16:19 +02:00
|
|
|
* method will replace all currently assigned values with the specified \a values.
|
2016-12-27 23:40:36 +01:00
|
|
|
* \sa Tag::setValues()
|
2016-08-04 00:16:19 +02:00
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::setValues(KnownField field, const std::vector<TagValue> &values)
|
2016-08-04 00:16:19 +02:00
|
|
|
{
|
|
|
|
return setValues(fieldId(field), values);
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(KnownField field) const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return hasField(fieldId(field));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2017-03-07 01:52:26 +01:00
|
|
|
* \brief Default implementation for hasField().
|
|
|
|
* \remarks Shadow in subclass to provide custom implementation.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> bool FieldMapBasedTag<ImplementationType>::internallyHasField(const IdentifierType &id) const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2016-11-19 14:32:37 +01:00
|
|
|
for (auto range = m_fields.equal_range(id); range.first != range.second; ++range.first) {
|
2018-03-07 01:17:50 +01:00
|
|
|
if (!range.first->second.value().isEmpty()) {
|
2016-11-19 14:32:37 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
2017-03-07 01:52:26 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns an indication whether the field with the specified \a id is present.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::hasField(const IdentifierType &id) const
|
2017-03-07 01:52:26 +01:00
|
|
|
{
|
|
|
|
return static_cast<const ImplementationType *>(this)->internallyHasField(id);
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline void FieldMapBasedTag<ImplementationType>::removeAllFields()
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
m_fields.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2016-08-04 00:16:19 +02:00
|
|
|
* \brief Returns the fields of the tag by providing direct access to the field map of the tag.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2017-03-07 00:02:59 +01:00
|
|
|
template <class ImplementationType>
|
2017-03-07 17:16:17 +01:00
|
|
|
inline auto FieldMapBasedTag<ImplementationType>::fields() const -> const std::multimap<IdentifierType, FieldType, Compare> &
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2016-08-04 00:16:19 +02:00
|
|
|
* \brief Returns the fields of the tag by providing direct access to the field map of the tag.
|
2015-04-22 19:22:01 +02:00
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline auto FieldMapBasedTag<ImplementationType>::fields() -> std::multimap<IdentifierType, FieldType, Compare> &
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
return m_fields;
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> unsigned int FieldMapBasedTag<ImplementationType>::fieldCount() const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2016-08-04 00:16:19 +02:00
|
|
|
unsigned int count = 0;
|
2018-03-07 01:17:50 +01:00
|
|
|
for (const auto &field : m_fields) {
|
|
|
|
if (!field.second.value().isEmpty()) {
|
2015-08-16 23:39:42 +02:00
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
2017-03-07 01:52:26 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns the field ID for the specified \a value.
|
|
|
|
* \remarks Must be implemented in internallyGetFieldId() when creating subclass.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType>
|
2017-03-07 17:16:17 +01:00
|
|
|
inline typename FieldMapBasedTag<ImplementationType>::IdentifierType FieldMapBasedTag<ImplementationType>::fieldId(KnownField value) const
|
2017-03-07 01:52:26 +01:00
|
|
|
{
|
|
|
|
return static_cast<const ImplementationType *>(this)->internallyGetFieldId(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the KnownField for the specified \a id.
|
|
|
|
* \remarks Must be implemented in internallyGetKnownField() when creating subclass.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline KnownField FieldMapBasedTag<ImplementationType>::knownField(const IdentifierType &id) const
|
2017-03-07 01:52:26 +01:00
|
|
|
{
|
2018-05-13 00:25:02 +02:00
|
|
|
return static_cast<const ImplementationType *>(this)->internallyGetKnownField(id);
|
2017-03-07 01:52:26 +01:00
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline bool FieldMapBasedTag<ImplementationType>::supportsField(KnownField field) const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2017-03-07 17:16:17 +01:00
|
|
|
static IdentifierType def;
|
2015-04-22 19:22:01 +02:00
|
|
|
return fieldId(field) != def;
|
|
|
|
}
|
|
|
|
|
2017-03-07 01:52:26 +01:00
|
|
|
/*!
|
|
|
|
* \brief Default implementation for proposedDataType().
|
|
|
|
* \remarks Shadow in subclass to provide custom implementation.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType>
|
2017-03-07 17:16:17 +01:00
|
|
|
inline TagDataType FieldMapBasedTag<ImplementationType>::internallyGetProposedDataType(const IdentifierType &id) const
|
2017-03-07 01:52:26 +01:00
|
|
|
{
|
|
|
|
return Tag::proposedDataType(knownField(id));
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:22:01 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the proposed data type for the field with the specified \a id.
|
|
|
|
*/
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> inline TagDataType FieldMapBasedTag<ImplementationType>::proposedDataType(const IdentifierType &id) const
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2017-03-07 01:52:26 +01:00
|
|
|
return static_cast<ImplementationType *>(this)->determineProposedDataType(id);
|
2015-04-22 19:22:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Inserts all fields \a from another tag of the same field type and compare function.
|
|
|
|
* \param from Specifies the tag the fields should be inserted from.
|
|
|
|
* \param overwrite Indicates whether existing fields should be overwritten.
|
|
|
|
* \return Returns the number of fields that have been inserted.
|
|
|
|
*/
|
2017-03-07 00:02:59 +01:00
|
|
|
template <class ImplementationType>
|
|
|
|
int FieldMapBasedTag<ImplementationType>::insertFields(const FieldMapBasedTag<ImplementationType> &from, bool overwrite)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
|
|
|
int fieldsInserted = 0;
|
2018-03-07 01:17:50 +01:00
|
|
|
for (const auto &pair : from.fields()) {
|
2017-03-07 17:16:17 +01:00
|
|
|
const FieldType &fromField = pair.second;
|
2018-03-07 01:17:50 +01:00
|
|
|
if (fromField.value().isEmpty()) {
|
2015-04-22 19:22:01 +02:00
|
|
|
continue;
|
2018-03-07 01:11:42 +01:00
|
|
|
}
|
2015-04-22 19:22:01 +02:00
|
|
|
bool fieldInserted = false;
|
|
|
|
auto range = fields().equal_range(fromField.id());
|
2018-03-07 01:17:50 +01:00
|
|
|
for (auto i = range.first; i != range.second; ++i) {
|
2017-03-07 17:16:17 +01:00
|
|
|
FieldType &ownField = i->second;
|
2018-03-07 01:17:50 +01:00
|
|
|
if ((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned() && fromField.typeInfo() == ownField.typeInfo())
|
|
|
|
|| (!fromField.isTypeInfoAssigned() && !ownField.isTypeInfoAssigned())) {
|
|
|
|
if (overwrite || ownField.value().isEmpty()) {
|
2015-04-22 19:22:01 +02:00
|
|
|
ownField = fromField;
|
|
|
|
++fieldsInserted;
|
|
|
|
}
|
|
|
|
fieldInserted = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2018-03-07 01:17:50 +01:00
|
|
|
if (!fieldInserted) {
|
2016-08-04 00:16:19 +02:00
|
|
|
fields().insert(std::make_pair(fromField.id(), fromField));
|
2015-04-22 19:22:01 +02:00
|
|
|
++fieldsInserted;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fieldsInserted;
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> unsigned int FieldMapBasedTag<ImplementationType>::insertValues(const Tag &from, bool overwrite)
|
2015-04-22 19:22:01 +02:00
|
|
|
{
|
2018-03-07 01:17:50 +01:00
|
|
|
if (type() == from.type()) {
|
2015-04-22 19:22:01 +02:00
|
|
|
// the tags are of the same type, we can insert the fields directly
|
2017-03-07 00:02:59 +01:00
|
|
|
return insertFields(static_cast<const FieldMapBasedTag<ImplementationType> &>(from), overwrite);
|
2015-04-22 19:22:01 +02:00
|
|
|
} else {
|
|
|
|
return Tag::insertValues(from, overwrite);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
template <class ImplementationType> void FieldMapBasedTag<ImplementationType>::ensureTextValuesAreProperlyEncoded()
|
2016-08-05 01:46:31 +02:00
|
|
|
{
|
2018-03-07 01:17:50 +01:00
|
|
|
for (auto &field : fields()) {
|
2016-08-05 01:46:31 +02:00
|
|
|
field.second.value().convertDataEncodingForTag(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:17:50 +01:00
|
|
|
} // namespace TagParser
|
2015-04-22 19:22:01 +02:00
|
|
|
|
2018-03-06 23:09:15 +01:00
|
|
|
#endif // TAG_PARSER_FIELDBASEDTAG_H
|