ollie/kde/gui/plumbmsg.cpp

171 lines
4.3 KiB
C++

/*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "plumbmsg.h"
QString PlumbMsg::lookup(const QString &name) const
{
for (const PlumbAttr &a : attr) {
if (a.name == name)
return a.value;
}
return QString();
}
void PlumbMsg::setAttr(const QString &name, const QString &value)
{
for (PlumbAttr &a : attr) {
if (a.name == name) {
a.value = value;
return;
}
}
attr.append(PlumbAttr{name, value});
}
// Quote one attribute value if it contains space, ', = or tab
static QString quoteAttrValue(const QString &v)
{
bool needsQuote = false;
for (const QChar c : v) {
if (c == QLatin1Char(' ') || c == QLatin1Char('\'')
|| c == QLatin1Char('=') || c == QLatin1Char('\t')) {
needsQuote = true;
break;
}
}
if (!needsQuote)
return v;
QString out;
out.reserve(v.size() + 2);
out.append(QLatin1Char('\''));
for (const QChar c : v) {
out.append(c);
if (c == QLatin1Char('\''))
out.append(c); // double it
}
out.append(QLatin1Char('\''));
return out;
}
QByteArray packPlumbAttr(const QList<PlumbAttr> &attr)
{
QString s;
bool first = true;
for (const PlumbAttr &a : attr) {
if (!first)
s.append(QLatin1Char(' '));
first = false;
s.append(a.name);
s.append(QLatin1Char('='));
s.append(quoteAttrValue(a.value));
}
return s.toUtf8();
}
QList<PlumbAttr> unpackPlumbAttr(const QByteArray &line)
{
QList<PlumbAttr> out;
const QString s = QString::fromUtf8(line);
int i = 0;
const int n = s.size();
while (i < n) {
while (i < n && (s[i] == QLatin1Char(' ') || s[i] == QLatin1Char('\t')))
i++;
if (i >= n)
break;
int nameStart = i;
while (i < n && s[i] != QLatin1Char('=') && s[i] != QLatin1Char(' ')
&& s[i] != QLatin1Char('\t'))
i++;
if (i >= n || s[i] != QLatin1Char('='))
break;
const QString name = s.mid(nameStart, i - nameStart);
i++; // skip '='
QString value;
bool quoting = false;
while (i < n) {
const QChar c = s[i];
if (quoting) {
if (c == QLatin1Char('\'')) {
if (i + 1 < n && s[i + 1] == QLatin1Char('\'')) {
i++;
} else {
quoting = false;
i++;
continue;
}
}
} else {
if (c == QLatin1Char(' ') || c == QLatin1Char('\t'))
break;
if (c == QLatin1Char('\'')) {
quoting = true;
i++;
continue;
}
}
value.append(c);
i++;
}
out.append(PlumbAttr{name, value});
}
return out;
}
QByteArray PlumbMsg::pack() const
{
QByteArray buf;
buf.append(src.toUtf8());
buf.append('\n');
buf.append(dst.toUtf8());
buf.append('\n');
buf.append(wdir.toUtf8());
buf.append('\n');
buf.append(type.toUtf8());
buf.append('\n');
buf.append(packPlumbAttr(attr));
buf.append('\n');
buf.append(QByteArray::number(data.size()));
buf.append('\n');
buf.append(data);
return buf;
}
bool PlumbMsg::unpack(const QByteArray &buf, PlumbMsg *out)
{
if (!out)
return false;
int pos = 0;
const int n = buf.size();
auto nextLine = [&](QByteArray *line) -> bool {
int nl = buf.indexOf('\n', pos);
if (nl < 0)
return false;
*line = buf.mid(pos, nl - pos);
pos = nl + 1;
return true;
};
QByteArray srcL, dstL, wdirL, typeL, attrL, ndataL;
if (!nextLine(&srcL) || !nextLine(&dstL) || !nextLine(&wdirL)
|| !nextLine(&typeL) || !nextLine(&attrL) || !nextLine(&ndataL))
return false;
PlumbMsg m;
m.src = QString::fromUtf8(srcL);
m.dst = QString::fromUtf8(dstL);
m.wdir = QString::fromUtf8(wdirL);
m.type = QString::fromUtf8(typeL);
m.attr = unpackPlumbAttr(attrL);
bool ok = false;
ndataL.trimmed().toInt(&ok);
if (!ok)
return false;
m.data = buf.mid(pos, n - pos);
*out = m;
return true;
}