1 /***************************************************************************
2 * Copyright (C) 2005-2014 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include "compressor.h"
26 const qint64 maxBufferSize = 64 * 1024 * 1024; // protect us from zip bombs
28 Compressor::Compressor(QTcpSocket *socket, Compressor::CompressionLevel level, QObject *parent)
33 _level = NoCompression; // compression not implemented yet
35 connect(socket, SIGNAL(readyRead()), SLOT(readData()));
37 // It's possible that more data has already arrived during the handshake, so readyRead() wouldn't be triggered.
38 // However, we want to give RemotePeer a chance to connect to our signals, so trigger this asynchronously.
39 if (socket->bytesAvailable())
40 QTimer::singleShot(0, this, SLOT(readData()));
44 qint64 Compressor::bytesAvailable() const
46 return _readBuffer.size();
50 qint64 Compressor::read(char *data, qint64 maxSize)
53 maxSize = _readBuffer.size();
55 qint64 n = qMin(maxSize, (qint64)_readBuffer.size());
56 memcpy(data, _readBuffer.constData(), n);
58 // TODO: don't copy for every read
59 if (n == _readBuffer.size())
62 _readBuffer = _readBuffer.mid(n);
64 // If there's still data left in the socket buffer, make sure to schedule a read
65 if (_socket->bytesAvailable())
66 QTimer::singleShot(0, this, SLOT(readData()));
72 // The usual usage pattern is to write a blocksize first, followed by the actual data.
73 // By setting NoFlush, one can indicate that the write buffer should not immediately be
74 // written, which should make things a bit more efficient.
75 qint64 Compressor::write(const char *data, qint64 count, WriteBufferHint flush)
77 int pos = _writeBuffer.size();
78 _writeBuffer.resize(pos + count);
79 memcpy(_writeBuffer.data() + pos, data, count);
88 void Compressor::readData()
90 // don't try to read more data if we're already closing
91 if (_socket->state() != QAbstractSocket::ConnectedState)
94 if (!_socket->bytesAvailable() || _readBuffer.size() >= maxBufferSize)
97 if (compressionLevel() == NoCompression)
98 _readBuffer.append(_socket->read(maxBufferSize - _readBuffer.size()));
104 void Compressor::writeData()
106 if (compressionLevel() == NoCompression) {
107 _socket->write(_writeBuffer);
108 _writeBuffer.clear();
113 void Compressor::flush()
115 if (compressionLevel() == NoCompression && _socket->state() == QAbstractSocket::ConnectedState)