Revision control
++ // Copyright (C) 2017 Witekio.
++ // Copyright (C) 2018 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qcoapmessage_p.h"
++
++ QT_BEGIN_NAMESPACE
++
++ QCoapMessagePrivate::QCoapMessagePrivate(QCoapMessage::Type _type) :
++ type(_type)
++ {
++ }
++
++ QCoapMessagePrivate::QCoapMessagePrivate(const QCoapMessagePrivate &other) :
++ QSharedData(other),
++ version(other.version), type(other.type), messageId(other.messageId),
++ token(other.token), options(other.options), payload(other.payload)
++ {
++ }
++
++ QCoapMessagePrivate::~QCoapMessagePrivate()
++ {
++ }
++
++ QCoapMessagePrivate *QCoapMessagePrivate::clone() const
++ {
++ return new QCoapMessagePrivate(*this);
++ }
++
++ /*!
++ \class QCoapMessage
++ \inmodule QtCoap
++
++ \brief The QCoapMessage class holds information about a CoAP message that
++ can be a request or a reply.
++
++ \reentrant
++
++ It holds information such as the message type, message id, token and other
++ ancillary data.
++
++ \sa QCoapOption, QCoapReply, QCoapRequest
++ */
++
++ /*!
++ \enum QCoapMessage::Type
++
++ Indicates the type of the message.
++
++ \value Confirmable A Confirmable message. The destination
++ endpoint needs to acknowledge the
++ message.
++ \value NonConfirmable A Non-Confirmable message. The
++ destination endpoint does not need to
++ acknowledge the message.
++ \value Acknowledgment An Acknowledgment message. A message
++ sent or received in reply to a
++ Confirmable message.
++ \value Reset A Reset message. This message type is used
++ in case of errors or to stop the ongoing
++ transmission. (For example, it is used
++ to cancel an observation).
++ */
++
++ /*!
++ \fn void QCoapMessage::swap(QCoapMessage &other)
++
++ Swaps this message with \a other. This operation is very fast and never fails.
++ */
++
++ /*!
++ Constructs a new QCoapMessage.
++ */
++ QCoapMessage::QCoapMessage() :
++ d_ptr(new QCoapMessagePrivate)
++ {
++ }
++
++ /*!
++ Destroys the QCoapMessage.
++ */
++ QCoapMessage::~QCoapMessage()
++ {
++ }
++
++ /*!
++ Constructs a shallow copy of \a other.
++ */
++ QCoapMessage::QCoapMessage(const QCoapMessage &other) :
++ d_ptr(other.d_ptr)
++ {
++ }
++
++ /*!
++ \internal
++ Constructs a new QCoapMessage with \a dd as the d_ptr.
++ This constructor must be used internally when subclassing
++ the QCoapMessage class.
++ */
++ QCoapMessage::QCoapMessage(QCoapMessagePrivate &dd) :
++ d_ptr(&dd)
++ {
++ }
++
++ /*!
++ \overload
++
++ Adds the CoAP option with the given \a name and \a value.
++ */
++ void QCoapMessage::addOption(QCoapOption::OptionName name, const QByteArray &value)
++ {
++ QCoapOption option(name, value);
++ addOption(option);
++ }
++
++ /*!
++ Adds the given CoAP \a option.
++ */
++ void QCoapMessage::addOption(const QCoapOption &option)
++ {
++ Q_D(QCoapMessage);
++
++ const auto it = std::upper_bound(d->options.begin(), d->options.end(), option,
++ [](const QCoapOption &a, const QCoapOption &b) -> bool {
++ return a.name() < b.name();
++ });
++ const auto idx = std::distance(d->options.begin(), it);
++
++ // Sort options by ascending order while inserting
++ d->options.insert(idx, option);
++ }
++
++ /*!
++ Removes the given \a option.
++ */
++ void QCoapMessage::removeOption(const QCoapOption &option)
++ {
++ Q_D(QCoapMessage);
++ d->options.removeOne(option);
++ }
++
++ /*!
++ Removes all options with the given \a name.
++ The CoAP protocol allows for the same option to repeat.
++ */
++ void QCoapMessage::removeOption(QCoapOption::OptionName name)
++ {
++ Q_D(QCoapMessage);
++ auto namesMatch = [name](const QCoapOption &option) {
++ return option.name() == name;
++ };
++
++ auto &options = d->options;
++ options.erase(std::remove_if(options.begin(), options.end(), namesMatch),
++ options.end());
++ }
++
++ /*!
++ Removes all options.
++ */
++ void QCoapMessage::clearOptions()
++ {
++ Q_D(QCoapMessage);
++ d->options.clear();
++ }
++
++ /*!
++ Returns the CoAP version.
++
++ \sa setVersion()
++ */
++ quint8 QCoapMessage::version() const
++ {
++ Q_D(const QCoapMessage);
++ return d->version;
++ }
++
++ /*!
++ Returns the message type.
++
++ \sa setType()
++ */
++ QCoapMessage::Type QCoapMessage::type() const
++ {
++ Q_D(const QCoapMessage);
++ return d->type;
++ }
++
++ /*!
++ Returns the message token.
++
++ \sa setToken()
++ */
++ QByteArray QCoapMessage::token() const
++ {
++ Q_D(const QCoapMessage);
++ return d->token;
++ }
++
++ /*!
++ Returns the token length.
++ */
++ quint8 QCoapMessage::tokenLength() const
++ {
++ Q_D(const QCoapMessage);
++ return static_cast<quint8>(d->token.size());
++ }
++
++ /*!
++ Returns the message id.
++
++ \sa setMessageId()
++ */
++ quint16 QCoapMessage::messageId() const
++ {
++ Q_D(const QCoapMessage);
++ return d->messageId;
++ }
++
++ /*!
++ Returns the payload.
++
++ \sa setPayload()
++ */
++ QByteArray QCoapMessage::payload() const
++ {
++ Q_D(const QCoapMessage);
++ return d->payload;
++ }
++
++ /*!
++ Returns the option at \a index position.
++ */
++ QCoapOption QCoapMessage::optionAt(int index) const
++ {
++ Q_D(const QCoapMessage);
++ return d->options.at(index);
++ }
++
++ /*!
++ Finds and returns the first option with the given \a name.
++ If there is no such option, returns an invalid QCoapOption with an empty value.
++ */
++ QCoapOption QCoapMessage::option(QCoapOption::OptionName name) const
++ {
++ Q_D(const QCoapMessage);
++
++ auto it = d->findOption(name);
++ return it != d->options.end() ? *it : QCoapOption();
++ }
++
++ /*!
++ \internal
++
++ Finds and returns a constant iterator to the first option
++ with the given \a name.
++ If there is no such option, returns \c d->options.end().
++ */
++ QList<QCoapOption>::const_iterator
++ QCoapMessagePrivate::findOption(QCoapOption::OptionName name) const
++ {
++ return std::find_if(options.begin(), options.end(), [name](const QCoapOption &option) {
++ return option.name() == name;
++ });
++ }
++
++ /*!
++ Returns \c true if the message contains at last one option
++ with \a name.
++ */
++ bool QCoapMessage::hasOption(QCoapOption::OptionName name) const
++ {
++ Q_D(const QCoapMessage);
++ return d->findOption(name) != d->options.end();
++ }
++
++ /*!
++ Returns the list of options.
++ */
++ const QList<QCoapOption> &QCoapMessage::options() const
++ {
++ Q_D(const QCoapMessage);
++ return d->options;
++ }
++
++ /*!
++ Finds and returns the list of options with the given \a name.
++ */
++ QList<QCoapOption> QCoapMessage::options(QCoapOption::OptionName name) const
++ {
++ Q_D(const QCoapMessage);
++
++ QList<QCoapOption> result;
++ std::copy_if(d->options.cbegin(), d->options.cend(), std::back_inserter(result),
++ [name](const QCoapOption &option) {
++ return option.name() == name;
++ });
++ return result;
++ }
++
++ /*!
++ Returns the number of options.
++ */
++ int QCoapMessage::optionCount() const
++ {
++ Q_D(const QCoapMessage);
++ return d->options.size();
++ }
++
++ /*!
++ Sets the CoAP version to \a version.
++
++ \sa version()
++ */
++ void QCoapMessage::setVersion(quint8 version)
++ {
++ Q_D(QCoapMessage);
++ d->version = version;
++ }
++
++ /*!
++ Sets the message type to \a type.
++
++ \sa type()
++ */
++ void QCoapMessage::setType(const Type &type)
++ {
++ Q_D(QCoapMessage);
++ d->type = type;
++ }
++
++ /*!
++ Sets the message token to \a token.
++
++ \sa token()
++ */
++ void QCoapMessage::setToken(const QByteArray &token)
++ {
++ Q_D(QCoapMessage);
++ d->token = token;
++ }
++
++ /*!
++ Sets the message ID to \a id.
++
++ \sa messageId()
++ */
++ void QCoapMessage::setMessageId(quint16 id)
++ {
++ Q_D(QCoapMessage);
++ d->messageId = id;
++ }
++
++ /*!
++ Sets the message payload to \a payload. The payload can be represented in
++ one of the content formats defined in \l {CoAP Content-Formats Registry}.
++
++ \note CoAP supports common content formats such as XML, JSON, and so on, but
++ these are text based and consequently heavy both in payload and in processing.
++ One of the recommended content formats to use with CoAP is CBOR, which is
++ designed to be used in such contexts.
++
++ \sa payload(), QCborStreamWriter, QCborStreamReader
++ */
++ void QCoapMessage::setPayload(const QByteArray &payload)
++ {
++ Q_D(QCoapMessage);
++ d->payload = payload;
++ }
++
++ /*!
++ Sets the message options to \a options.
++ */
++ void QCoapMessage::setOptions(const QList<QCoapOption> &options)
++ {
++ Q_D(QCoapMessage);
++ d->options = options;
++ }
++
++ void QCoapMessage::swap(QCoapMessage &other) noexcept
++ {
++ qSwap(d_ptr, other.d_ptr);
++ }
++
++ /*!
++ Moves \a other into this message and returns a reference to this QCoapMessage.
++ */
++ QCoapMessage &QCoapMessage::operator=(QCoapMessage &&other) noexcept
++ {
++ swap(other);
++ return *this;
++ }
++
++ /*!
++ Copies the contents of \a other into this message.
++ Returns a reference to this QCoapMessage.
++ */
++ QCoapMessage &QCoapMessage::operator=(const QCoapMessage &other)
++ {
++ d_ptr = other.d_ptr;
++ return *this;
++ }
++
++ /*!
++ \internal
++
++ For QSharedDataPointer.
++ */
++ QCoapMessagePrivate* QCoapMessage::d_func()
++ {
++ return d_ptr.data();
++ }
++
++ /*!
++ \variable QCoapMessage::d_ptr
++ \internal
++
++ Pointer to private data structure.
++ */
++
++ QT_END_NAMESPACE