blob: f4001d38330aea04fc3d6892ef66cdf8a5080b5b [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qppsobject_p.h"
#include "qppsobjectprivate_p.h"
#include "qppsattribute_p.h"
#include "qppsattributeprivate_p.h"
#include "qcore_unix_p.h"
#include <QObject>
#include <QSocketNotifier>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <confname.h>
#include <sys/pps.h>
QT_BEGIN_NAMESPACE
///////////////////////////////////////////////////////////////////////////////
static inline void safeAssign(bool *pointer, bool value)
{
if (pointer)
*pointer = value;
}
class QPpsMaxSize
{
public:
QPpsMaxSize()
{
int fd = qt_safe_open("/pps/.all", O_RDONLY);
if (fd == -1) {
qWarning("qppsobject.cpp: qt_safe_open failed");
value = -1;
}
// This tells us the maximum transfer size across PPS
value = ::fpathconf(fd, _PC_REC_MAX_XFER_SIZE);
qt_safe_close(fd);
}
int value;
};
Q_GLOBAL_STATIC(QPpsMaxSize, ppsMaxSize)
///////////////////////////////////////////////////////////////////////////////
//
// QPpsObjectPrivate
//
///////////////////////////////////////////////////////////////////////////////
QPpsObjectPrivate::QPpsObjectPrivate(const QString &path)
: notifier(0),
path(path),
error(EOK),
fd(-1),
readyReadEnabled(true)
{
}
QPpsAttributeMap QPpsObjectPrivate::decode(const QByteArray &rawData, bool *ok)
{
QPpsAttributeMap attributeMap;
pps_decoder_t decoder;
QByteArray mutableData(rawData);
pps_decoder_error_t error = pps_decoder_initialize(&decoder, mutableData.data());
if (error == PPS_DECODER_OK) {
// no need to check ok in this case
attributeMap = decodeObject(&decoder, ok);
} else {
qWarning("QPpsObjectPrivate::decode: pps_decoder_initialize failed");
*ok = false;
}
pps_decoder_cleanup(&decoder);
return attributeMap;
}
QVariantMap QPpsObjectPrivate::variantMapFromPpsAttributeMap(const QPpsAttributeMap &data)
{
QVariantMap variantMap;
for (QPpsAttributeMap::const_iterator it = data.constBegin(); it != data.constEnd(); ++it) {
QVariant variant = variantFromPpsAttribute(it.value());
if (!variant.isValid())
return QVariantMap();
variantMap[it.key()] = variant;
}
return variantMap;
}
QPpsAttribute::Flags QPpsObjectPrivate::readFlags(pps_decoder_t *decoder)
{
int rawFlags = pps_decoder_flags(decoder, 0);
QPpsAttribute::Flags attributeFlags;
if (rawFlags & PPS_INCOMPLETE)
attributeFlags |= QPpsAttribute::Incomplete;
if (rawFlags & PPS_DELETED)
attributeFlags |= QPpsAttribute::Deleted;
if (rawFlags & PPS_CREATED)
attributeFlags |= QPpsAttribute::Created;
if (rawFlags & PPS_TRUNCATED)
attributeFlags |= QPpsAttribute::Truncated;
if (rawFlags & PPS_PURGED)
attributeFlags |= QPpsAttribute::Purged;
return attributeFlags;
}
QPpsAttribute QPpsObjectPrivate::decodeString(pps_decoder_t *decoder)
{
const char *value = 0;
pps_decoder_error_t error = pps_decoder_get_string(decoder, 0, &value);
if (error != PPS_DECODER_OK) {
qWarning("QPpsObjectPrivate::decodeString: PPS_DECODER_GET_STRING failed");
return QPpsAttribute();
}
QPpsAttribute::Flags flags = readFlags(decoder);
return QPpsAttributePrivate::createPpsAttribute(QString::fromUtf8(value), flags);
}
QPpsAttribute QPpsObjectPrivate::decodeNumber(pps_decoder_t *decoder)
{
// In order to support more number types, we have to do something stupid because the PPS
// library won't let us work any other way. Basically, we have to probe the encoded type in
// order to try to get exactly what we want.
int64_t llValue;
double dValue;
int iValue;
QPpsAttribute::Flags flags;
if (pps_decoder_is_integer(decoder, 0)) {
pps_decoder_error_t error = pps_decoder_get_int(decoder, 0, &iValue);
switch (error) {
case PPS_DECODER_OK:
flags = readFlags(decoder);
return QPpsAttributePrivate::createPpsAttribute(iValue, flags);
case PPS_DECODER_CONVERSION_FAILED:
error = pps_decoder_get_int64(decoder, 0, &llValue);
if (error != PPS_DECODER_OK) {
qWarning("QPpsObjectPrivate::decodeNumber: failed to decode integer");
return QPpsAttribute();
}
flags = readFlags(decoder);
return QPpsAttributePrivate::createPpsAttribute(static_cast<long long>(llValue), flags);
default:
qWarning("QPpsObjectPrivate::decodeNumber: pps_decoder_get_int failed");
return QPpsAttribute();
}
} else {
pps_decoder_error_t error = pps_decoder_get_double(decoder, 0, &dValue);
if (error != PPS_DECODER_OK) {
qWarning("QPpsObjectPrivate::decodeNumber: pps_decoder_get_double failed");
return QPpsAttribute();
}
flags = readFlags(decoder);
return QPpsAttributePrivate::createPpsAttribute(dValue, flags);
}
}
QPpsAttribute QPpsObjectPrivate::decodeBool(pps_decoder_t *decoder)
{
bool value;
pps_decoder_error_t error = pps_decoder_get_bool(decoder, 0, &value);
if (error != PPS_DECODER_OK) {
qWarning("QPpsObjectPrivate::decodeBool: pps_decoder_get_bool failed");
return QPpsAttribute();
}
QPpsAttribute::Flags flags = readFlags(decoder);
return QPpsAttributePrivate::createPpsAttribute(value, flags);
}
template<typename T>
QPpsAttribute QPpsObjectPrivate::decodeNestedData(T (*decodeFunction)(pps_decoder_t *, bool *),
pps_decoder_t *decoder)
{
// We must read the flags before we push into the object,
// otherwise we'll get the flags for the first element in the object.
QPpsAttribute::Flags flags = readFlags(decoder);
if (!decoderPush(decoder))
return QPpsAttribute();
bool ok = false;
T attributeContainer = decodeFunction(decoder, &ok);
if (!ok)
return QPpsAttribute();
QPpsAttribute returnVal = QPpsAttributePrivate::createPpsAttribute(attributeContainer, flags);
if (!decoderPop(decoder))
return QPpsAttribute();
return returnVal;
}
QPpsAttribute QPpsObjectPrivate::decodeData(pps_decoder_t *decoder)
{
pps_node_type_t nodeType = pps_decoder_type(decoder, 0);
switch (nodeType) {
case PPS_TYPE_BOOL:
return decodeBool(decoder);
case PPS_TYPE_NUMBER:
return decodeNumber(decoder);
case PPS_TYPE_STRING:
return decodeString(decoder);
case PPS_TYPE_ARRAY:
return decodeNestedData(&QPpsObjectPrivate::decodeArray, decoder);
case PPS_TYPE_OBJECT:
return decodeNestedData(&QPpsObjectPrivate::decodeObject, decoder);
case PPS_TYPE_DELETED: {
// This should create an attribute with the flags set to PpsAttribute::Deleted.
// However, we need to create a valid QPpsAttribute while doing so. To do this,
// I'll create an empty map as a sentinel. Note that the readFlags() call with produce
// the correct set of flags. While I suspect that there will never be any other flags
// set in conjunction with this one, I'd rather not be surprised later.
QPpsAttributeMap emptyMap;
QPpsAttribute::Flags flags = readFlags(decoder);
QPpsAttribute returnVal = QPpsAttributePrivate::createPpsAttribute(emptyMap, flags);
return returnVal;
}
case PPS_TYPE_NULL:
case PPS_TYPE_NONE:
case PPS_TYPE_UNKNOWN:
default:
qWarning("QPpsObjectPrivate::decodeData: invalid pps_node_type");
return QPpsAttribute();
}
}
QPpsAttributeList QPpsObjectPrivate::decodeArray(pps_decoder_t *decoder, bool *ok)
{
QPpsAttributeList list;
int length = pps_decoder_length(decoder);
for (int i = 0; i < length; ++i) {
// Force movement to a specific index.
pps_decoder_error_t error = pps_decoder_goto_index(decoder, i);
if (error != PPS_DECODER_OK) {
qWarning("QPpsObjectPrivate::decodeArray: pps_decoder_goto_index failed");
*ok = false;
return QPpsAttributeList();
}
QPpsAttribute ppsAttribute = decodeData(decoder);
if (!ppsAttribute.isValid()) {
*ok = false;
return QPpsAttributeList();
}
list << ppsAttribute;
}
*ok = true;
return list;
}
QPpsAttributeMap QPpsObjectPrivate::decodeObject(pps_decoder_t *decoder, bool *ok)
{
QPpsAttributeMap map;
int length = pps_decoder_length(decoder);
for (int i = 0; i < length; ++i) {
// Force movement to a specific index.
pps_decoder_error_t error = pps_decoder_goto_index(decoder, i);
if (error != PPS_DECODER_OK) {
qWarning("QPpsObjectPrivate::decodeObject: pps_decoder_goto_index failed");
*ok = false;
return QPpsAttributeMap();
}
QString name = QString::fromUtf8(pps_decoder_name(decoder));
QPpsAttribute ppsAttribute = decodeData(decoder);
if (!ppsAttribute.isValid()) {
*ok = false;
return QPpsAttributeMap();
}
map[name] = ppsAttribute;
}
*ok = true;
return map;
}
QVariant QPpsObjectPrivate::variantFromPpsAttribute(const QPpsAttribute &attribute)
{
switch (attribute.type()) {
case QPpsAttribute::Number:
switch (attribute.toVariant().type()) {
case QVariant::Int:
return attribute.toInt();
case QVariant::LongLong:
return attribute.toLongLong();
default:
return attribute.toDouble();
}
break;
case QPpsAttribute::Bool:
return attribute.toBool();
case QPpsAttribute::String:
return attribute.toString();
case QPpsAttribute::Array: {
QVariantList variantList;
const auto attrs = attribute.toList();
for (const QPpsAttribute &attr : attrs) {
QVariant variant = variantFromPpsAttribute(attr);
if (!variant.isValid())
return QVariantList();
variantList << variant;
}
return variantList;
}
case QPpsAttribute::Object:
return variantMapFromPpsAttributeMap(attribute.toMap());
case QPpsAttribute::None:
default:
qWarning("QPpsObjectPrivate::variantFromPpsAttribute: invalid attribute parameter");
return QVariant();
}
}
QByteArray QPpsObjectPrivate::encode(const QVariantMap &ppsData, bool *ok)
{
pps_encoder_t encoder;
pps_encoder_initialize(&encoder, false);
encodeObject(&encoder, ppsData, ok);
const char *rawData = 0;
if (*ok) {
// rawData points to a memory owned by encoder.
// The memory will be freed when pps_encoder_cleanup is called.
rawData = pps_encoder_buffer(&encoder);
if (!rawData) {
qWarning("QPpsObjectPrivate::encode: pps_encoder_buffer failed");
*ok = false;
}
}
pps_encoder_cleanup(&encoder);
return QByteArray(rawData);
}
void QPpsObjectPrivate::encodeData(pps_encoder_t *encoder, const char *name, const QVariant &data,
bool *ok)
{
const char *errorFunction;
pps_encoder_error_t error = PPS_ENCODER_OK;
switch (data.type()) {
case QVariant::Bool:
error = pps_encoder_add_bool(encoder, name, data.toBool());
errorFunction = "pps_encoder_add_bool";
break;
// We want to support encoding uint even though libpps doesn't support it directly.
// We can't encode uint as an int since that will lose precision (e.g. 2^31+1 can't be
// encoded that way). However, we can convert uint to double without losing precision.
// QVariant.toDouble() conveniently takes care of the conversion for us.
case QVariant::UInt:
case QVariant::Double:
error = pps_encoder_add_double(encoder, name, data.toDouble());
errorFunction = "pps_encoder_add_double";
break;
case QVariant::Int:
error = pps_encoder_add_int(encoder, name, data.toInt());
errorFunction = "pps_encoder_add_int";
break;
case QVariant::LongLong:
error = pps_encoder_add_int64(encoder, name, data.toLongLong());
errorFunction = "pps_encoder_add_int64";
break;
case QVariant::String:
error = pps_encoder_add_string(encoder, name, data.toString().toUtf8().constData());
errorFunction = "pps_encoder_add_string";
break;
case QVariant::List:
error = pps_encoder_start_array(encoder, name);
errorFunction = "pps_encoder_start_array";
if (error == PPS_ENCODER_OK) {
encodeArray(encoder, data.toList(), ok);
error = pps_encoder_end_array(encoder);
errorFunction = "pps_encoder_end_array";
}
break;
case QVariant::Map:
error = pps_encoder_start_object(encoder, name);
errorFunction = "pps_encoder_start_object";
if (error == PPS_ENCODER_OK) {
encodeObject(encoder, data.toMap(), ok);
error = pps_encoder_end_object(encoder);
errorFunction = "pps_encoder_end_object";
}
break;
case QVariant::Invalid:
error = pps_encoder_add_null(encoder, name);
errorFunction = "pps_encoder_add_null";
break;
default:
qWarning("QPpsObjectPrivate::encodeData: the type of the parameter data is invalid");
*ok = false;
return;
}
if (error != PPS_ENCODER_OK) {
qWarning("QPpsObjectPrivate::encodeData: %s failed", errorFunction);
*ok = false;
} else {
*ok = true;
}
}
void QPpsObjectPrivate::encodeArray(pps_encoder_t *encoder, const QVariantList &data, bool *ok)
{
for (QVariantList::const_iterator it = data.constBegin(); it != data.constEnd(); ++it) {
encodeData(encoder, 0, *it, ok);
if (!(*ok))
return;
}
// if the passed data is empty, nothing went wrong and ok is set to true
*ok = true;
}
void QPpsObjectPrivate::encodeObject(pps_encoder_t *encoder, const QVariantMap &data, bool *ok)
{
for (QVariantMap::const_iterator it = data.constBegin(); it != data.constEnd(); ++it) {
encodeData(encoder, it.key().toUtf8().constData(), it.value(), ok);
if (!(*ok))
return;
}
// if the passed data is empty, nothing went wrong and ok is set to true
*ok = true;
}
///////////////////////////////////////////////////////////////////////////////
//
// QPpsObjectPrivate
//
///////////////////////////////////////////////////////////////////////////////
QPpsObject::QPpsObject(const QString &path, QObject *parent)
: QObject(*new QPpsObjectPrivate(path), parent)
{
}
QPpsObject::~QPpsObject()
{
// RAII - ensure file gets closed
if (isOpen())
close();
}
int QPpsObject::error() const
{
Q_D(const QPpsObject);
return d->error;
}
QString QPpsObject::errorString() const
{
Q_D(const QPpsObject);
return qt_error_string(d->error);
}
bool QPpsObject::isReadyReadEnabled() const
{
Q_D(const QPpsObject);
// query state of read ready signal
return d->readyReadEnabled;
}
void QPpsObject::setReadyReadEnabled(bool enable)
{
Q_D(QPpsObject);
// toggle whether socket notifier will emit a signal on read ready
d->readyReadEnabled = enable;
if (isOpen())
d->notifier->setEnabled(enable);
}
bool QPpsObject::isBlocking() const
{
Q_D(const QPpsObject);
// reset last error
d->error = EOK;
// abort if file not open
if (!isOpen()) {
d->error = EBADF;
return false;
}
// query file status flags
int flags = fcntl(d->fd, F_GETFL);
if (flags == -1) {
d->error = errno;
return false;
}
// check if non-blocking flag is unset
return ((flags & O_NONBLOCK) != O_NONBLOCK);
}
bool QPpsObject::setBlocking(bool enable)
{
Q_D(QPpsObject);
// reset last error
d->error = EOK;
// abort if file not open
if (!isOpen()) {
d->error = EBADF;
return false;
}
// query file status flags
int flags = fcntl(d->fd, F_GETFL);
if (flags == -1) {
d->error = errno;
return false;
}
// configure non-blocking flag
if (enable)
flags &= ~O_NONBLOCK;
else
flags |= O_NONBLOCK;
// update file status flags
flags = fcntl(d->fd, F_SETFL, flags);
if (flags == -1) {
d->error = errno;
return false;
}
return true;
}
bool QPpsObject::isOpen() const
{
Q_D(const QPpsObject);
return (d->fd != -1);
}
bool QPpsObject::open(QPpsObject::OpenModes mode)
{
Q_D(QPpsObject);
// reset last error
d->error = EOK;
// abort if file already open
if (isOpen()) {
d->error = EBUSY;
return false;
}
// convert pps flags to open flags
int oflags = 0;
if ((mode & QPpsObject::Publish) && (mode & QPpsObject::Subscribe))
oflags |= O_RDWR;
else if (mode & QPpsObject::Publish)
oflags |= O_WRONLY;
else if (mode & QPpsObject::Subscribe)
oflags |= O_RDONLY;
if (mode & QPpsObject::Create)
oflags |= O_CREAT | O_EXCL;
if (mode & QPpsObject::DeleteContents)
oflags |= O_TRUNC;
// open pps file
d->fd = qt_safe_open(d->path.toUtf8().data(), oflags, 0666);
if (d->fd == -1) {
d->error = errno;
return false;
}
// wire up socket notifier to know when reads are ready
d->notifier = new QSocketNotifier(d->fd, QSocketNotifier::Read, this);
d->notifier->setEnabled(d->readyReadEnabled);
QObject::connect(d->notifier, &QSocketNotifier::activated, this, &QPpsObject::readyRead);
return true;
}
bool QPpsObject::close()
{
Q_D(QPpsObject);
// reset last error
d->error = EOK;
// abort if file not open
if (!isOpen()) {
d->error = EBADF;
return false;
}
// shutdown socket notifier
delete d->notifier;
d->notifier = 0;
// close pps file
const int result = qt_safe_close(d->fd);
d->fd = -1;
// check success of operation
if (result != 0) {
d->error = errno;
return false;
}
return true;
}
QByteArray QPpsObject::read(bool *ok)
{
Q_D(QPpsObject);
// reset last error
d->error = EOK;
// abort if file not open
if (!isOpen()) {
d->error = EBADF;
safeAssign(ok, false);
return QByteArray();
}
const int maxSize = ppsMaxSize->value;
if (maxSize == -1) {
qWarning("QPpsObject::read: maxSize is equal to -1");
safeAssign(ok, false);
return QByteArray();
}
QByteArray byteArray;
byteArray.resize(maxSize); // resize doesn't initialize the data
const int result = qt_safe_read(d->fd, byteArray.data(), byteArray.size());
if (result == -1) {
d->error = errno;
qWarning() << "QPpsObject::read failed to read pps data, error " << errorString();
safeAssign(ok, false);
return QByteArray(); // Specifically return a default-constructed QByteArray.
}
if (result == 0) {
// normalize the behavior of read() when no data is ready so a pps object
// put in non-blocking mode via opening w/o wait (read returns 0) looks
// the same as a pps object put in non-blocking mode by setting O_NONBLOCK
// (read returns EAGAIN)
d->error = EAGAIN;
safeAssign(ok, false);
return QByteArray(); // Specifically return a default-constructed QByteArray.
}
// resize byte array to amount actually read
byteArray.resize(result);
safeAssign(ok, true);
return byteArray;
}
bool QPpsObject::write(const QByteArray &byteArray)
{
Q_D(QPpsObject);
// reset last error
d->error = EOK;
// abort if file not open
if (!isOpen()) {
d->error = EBADF;
return false;
}
// write entire byte array to pps file
const int result = qt_safe_write(d->fd, byteArray.data(), byteArray.size());
if (result == -1)
d->error = errno;
return (result == byteArray.size());
}
int QPpsObject::writeMessage(const QString &msg, const QVariantMap &dat)
{
// Treat empty msg as an encoding error
if (msg.isEmpty())
return -1;
bool ok;
QByteArray byteArray = encodeMessage(msg, dat, &ok);
if (!ok)
return -1;
ok = write(byteArray);
if (!ok)
return error();
return EOK;
}
int QPpsObject::writeMessage(const QString &msg, const QString &id, const QVariantMap &dat)
{
// Treat empty msg or id as an encoding error
if (msg.isEmpty() || id.isEmpty())
return -1;
bool ok;
QByteArray byteArray = encodeMessage(msg, id, dat, &ok);
if (!ok)
return -1;
ok = write(byteArray);
if (!ok)
return error();
return EOK;
}
bool QPpsObject::remove()
{
Q_D(QPpsObject);
// reset last error
d->error = EOK;
// delete pps file
const int result = unlink(d->path.toUtf8().data());
// check success of operation
if (result != 0) {
d->error = errno;
return false;
}
return true;
}
// static
QVariantMap QPpsObject::decode(const QByteArray &rawData, bool *ok)
{
QPpsAttributeMap mapData = decodeWithFlags(rawData, 0, ok);
// If *ok is false, then mapData is empty, so the resulting QVariantMap
// will also be empty, as desired.
return QPpsObjectPrivate::variantMapFromPpsAttributeMap(mapData);
}
// static
QPpsAttributeMap QPpsObject::decodeWithFlags(const QByteArray &rawData, bool *ok)
{
return QPpsObject::decodeWithFlags(rawData, 0, ok);
}
// static
QPpsAttributeMap QPpsObject::decodeWithFlags(const QByteArray &rawData,
QPpsAttribute *objectAttribute, bool *ok)
{
safeAssign(ok, true);
bool success = false;
QPpsAttributeMap mapData = QPpsObjectPrivate::decode(rawData, &success);
if (!success) {
safeAssign(ok, false);
return QPpsAttributeMap();
}
// The object name is the key of the first element, and the flags of that attribute
// give the status for the object as a whole.
if (!mapData.isEmpty() && objectAttribute) {
QString extractedName = mapData.begin().key();
QPpsAttribute topmostAttribute = mapData.begin().value();
QPpsAttribute::Flags topmostFlags = topmostAttribute.flags();
QPpsAttribute toplevelAttribute =
QPpsAttributePrivate::createPpsAttribute(extractedName, topmostFlags);
*objectAttribute = toplevelAttribute;
}
return mapData;
}
// static
QByteArray QPpsObject::encode(const QVariantMap &ppsData, bool *ok)
{
safeAssign(ok, true);
bool success = false;
QByteArray byteArray = QPpsObjectPrivate::encode(ppsData, &success);
if (!success) {
safeAssign(ok, false);
return QByteArray();
}
return byteArray;
}
// static
QByteArray QPpsObject::encodeMessage(const QString &msg, const QVariantMap &dat, bool *ok)
{
safeAssign(ok, true);
// Treat empty msg as an encoding error
if (msg.isEmpty()) {
safeAssign(ok, false);
return QByteArray();
}
QVariantMap ppsData;
ppsData[QStringLiteral("msg")] = msg;
ppsData[QStringLiteral("dat")] = dat;
return QPpsObject::encode(ppsData, ok);
}
// static
QByteArray QPpsObject::encodeMessage(const QString &msg, const QString &id, const QVariantMap &dat,
bool *ok)
{
safeAssign(ok, true);
// Treat empty msg or id as an encoding error
if (msg.isEmpty() || id.isEmpty()) {
safeAssign(ok, false);
return QByteArray();
}
QVariantMap ppsData;
ppsData[QStringLiteral("msg")] = msg;
ppsData[QStringLiteral("id")] = id;
ppsData[QStringLiteral("dat")] = dat;
return QPpsObject::encode(ppsData, ok);
}
// static
int QPpsObject::sendMessage(const QString &path, const QString &message)
{
QPpsObject pps(path);
bool ok = pps.open(QPpsObject::Publish);
if (!ok)
return pps.error();
ok = pps.write(message.toLocal8Bit());
if (!ok)
return pps.error();
return EOK;
}
// static
int QPpsObject::sendMessage(const QString &path, const QVariantMap &message)
{
QPpsObject pps(path);
bool ok = pps.open(QPpsObject::Publish);
if (!ok)
return pps.error();
QByteArray payload = QPpsObject::encode(message, &ok);
if (!ok)
return -1;
ok = pps.write(payload);
if (!ok)
return pps.error();
return EOK;
}
// static
int QPpsObject::sendMessage(const QString &path, const QString &msg, const QVariantMap &dat)
{
// Treat empty msg as an encoding error
if (msg.isEmpty())
return -1;
QPpsObject pps(path);
bool ok = pps.open(QPpsObject::Publish);
if (!ok)
return pps.error();
QByteArray payload = QPpsObject::encodeMessage(msg, dat, &ok);
if (!ok)
return -1;
ok = pps.write(payload);
if (!ok)
return pps.error();
return EOK;
}
// static
int QPpsObject::sendMessage(const QString &path, const QByteArray &ppsData)
{
QPpsObject pps(path);
bool ok = pps.open(QPpsObject::Publish);
if (!ok)
return pps.error();
ok = pps.write(ppsData);
if (!ok)
return pps.error();
return EOK;
}
QT_END_NAMESPACE