/* **************************************************************************** * Copyright 2019 Open Systems Development BV * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * * DEALINGS IN THE SOFTWARE. * * ***************************************************************************/ #include "qmqtt_frame.h" #include #include namespace QMQTT { Q_LOGGING_CATEGORY(frame, "qmqtt.frame") Frame::Frame() : _header(0) , _data(QByteArray()) { } Frame::Frame(const quint8 header) : _header(header) , _data(QByteArray()) { } Frame::Frame(const quint8 header, const QByteArray &data) : _header(header) , _data(data) { } Frame::Frame(const Frame& other) { _header = other._header; _data = other._data; } Frame& Frame::operator=(const Frame& other) { _header = other._header; _data = other._data; return *this; } bool Frame::operator==(const Frame& other) const { return _header == other._header && _data == other._data; } Frame::~Frame() { } quint8 Frame::header() const { return _header; } QByteArray Frame::data() const { return _data; } quint8 Frame::readChar() { char c = _data.at(0); _data.remove(0, 1); return c; } quint16 Frame::readInt() { quint8 msb = static_cast(_data.at(0)); quint8 lsb = static_cast(_data.at(1)); _data.remove(0, 2); return (msb << 8) | lsb; } QByteArray Frame::readByteArray() { quint16 len = readInt(); QByteArray data = _data.left(len); _data.remove(0, len); return data; } QString Frame::readString() { quint16 len = readInt(); QString s = QString::fromUtf8(_data.left(len)); _data.remove(0, len); return s; } void Frame::writeInt(const quint16 i) { _data.append(MSB(i)); _data.append(LSB(i)); } void Frame::writeByteArray(const QByteArray &data) { if (data.size() > (int)USHRT_MAX) { qCritical("qmqtt: Binary data size bigger than %u bytes, truncate it!", USHRT_MAX); writeInt(USHRT_MAX); _data.append(data.left(USHRT_MAX)); return; } writeInt(data.size()); _data.append(data); } void Frame::writeString(const QString &string) { QByteArray data = string.toUtf8(); if (data.size() > (int)USHRT_MAX) { qCritical("qmqtt: String size bigger than %u bytes, truncate it!", USHRT_MAX); data.resize(USHRT_MAX); } writeInt(data.size()); _data.append(data); } void Frame::writeChar(const quint8 c) { _data.append(c); } void Frame::writeRawData(const QByteArray &data) { _data.append(data); } void Frame::write(QDataStream &stream) const { QByteArray lenbuf; if (!encodeLength(lenbuf, _data.size())) { qCritical("qmqtt: Control packet bigger than 256 MB, dropped!"); return; } stream << (quint8)_header; if(_data.size() == 0) { stream << (quint8)0; return; } if (stream.writeRawData(lenbuf.data(), lenbuf.size()) != lenbuf.size()) { qCritical("qmqtt: Control packet write error!"); return; } if (stream.writeRawData(_data.data(), _data.size()) != _data.size()) { qCritical("qmqtt: Control packet write error!"); } } bool Frame::encodeLength(QByteArray &lenbuf, int length) const { lenbuf.clear(); quint8 d; do { d = length % 128; length /= 128; if (length > 0) { d |= 0x80; } lenbuf.append(d); } while (length > 0); return lenbuf.size() <= 4; } } // namespace QMQTT