/* * 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 &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 unpackPlumbAttr(const QByteArray &line) { QList 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; }