1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qbuffer.h"
41#include <QtCore/qmetaobject.h>
42#include "private/qiodevice_p.h"
43
44QT_BEGIN_NAMESPACE
45
46/** QBufferPrivate **/
47class QBufferPrivate : public QIODevicePrivate
48{
49 Q_DECLARE_PUBLIC(QBuffer)
50
51public:
52 QBufferPrivate()
53 : buf(nullptr)
54#ifndef QT_NO_QOBJECT
55 , writtenSinceLastEmit(0), signalConnectionCount(0), signalsEmitted(false)
56#endif
57 { }
58 ~QBufferPrivate() { }
59
60 QByteArray *buf;
61 QByteArray defaultBuf;
62
63 qint64 peek(char *data, qint64 maxSize) override;
64 QByteArray peek(qint64 maxSize) override;
65
66#ifndef QT_NO_QOBJECT
67 // private slots
68 void _q_emitSignals();
69
70 qint64 writtenSinceLastEmit;
71 int signalConnectionCount;
72 bool signalsEmitted;
73#endif
74};
75
76#ifndef QT_NO_QOBJECT
77void QBufferPrivate::_q_emitSignals()
78{
79 Q_Q(QBuffer);
80 emit q->bytesWritten(writtenSinceLastEmit);
81 writtenSinceLastEmit = 0;
82 emit q->readyRead();
83 signalsEmitted = false;
84}
85#endif
86
87qint64 QBufferPrivate::peek(char *data, qint64 maxSize)
88{
89 qint64 readBytes = qMin(maxSize, static_cast<qint64>(buf->size()) - pos);
90 memcpy(data, buf->constData() + pos, readBytes);
91 return readBytes;
92}
93
94QByteArray QBufferPrivate::peek(qint64 maxSize)
95{
96 qint64 readBytes = qMin(maxSize, static_cast<qint64>(buf->size()) - pos);
97 if (pos == 0 && maxSize >= buf->size())
98 return *buf;
99 return QByteArray(buf->constData() + pos, readBytes);
100}
101
102/*!
103 \class QBuffer
104 \inmodule QtCore
105 \reentrant
106 \brief The QBuffer class provides a QIODevice interface for a QByteArray.
107
108 \ingroup io
109
110 QBuffer allows you to access a QByteArray using the QIODevice
111 interface. The QByteArray is treated just as a standard random-accessed
112 file. Example:
113
114 \snippet buffer/buffer.cpp 0
115
116 By default, an internal QByteArray buffer is created for you when
117 you create a QBuffer. You can access this buffer directly by
118 calling buffer(). You can also use QBuffer with an existing
119 QByteArray by calling setBuffer(), or by passing your array to
120 QBuffer's constructor.
121
122 Call open() to open the buffer. Then call write() or
123 putChar() to write to the buffer, and read(), readLine(),
124 readAll(), or getChar() to read from it. size() returns the
125 current size of the buffer, and you can seek to arbitrary
126 positions in the buffer by calling seek(). When you are done with
127 accessing the buffer, call close().
128
129 The following code snippet shows how to write data to a
130 QByteArray using QDataStream and QBuffer:
131
132 \snippet buffer/buffer.cpp 1
133
134 Effectively, we convert the application's QPalette into a byte
135 array. Here's how to read the data from the QByteArray:
136
137 \snippet buffer/buffer.cpp 2
138
139 QTextStream and QDataStream also provide convenience constructors
140 that take a QByteArray and that create a QBuffer behind the
141 scenes.
142
143 QBuffer emits readyRead() when new data has arrived in the
144 buffer. By connecting to this signal, you can use QBuffer to
145 store temporary data before processing it. QBuffer also emits
146 bytesWritten() every time new data has been written to the buffer.
147
148 \sa QFile, QDataStream, QTextStream, QByteArray
149*/
150
151#ifdef QT_NO_QOBJECT
152QBuffer::QBuffer()
153 : QIODevice(*new QBufferPrivate)
154{
155 Q_D(QBuffer);
156 d->buf = &d->defaultBuf;
157}
158QBuffer::QBuffer(QByteArray *buf)
159 : QIODevice(*new QBufferPrivate)
160{
161 Q_D(QBuffer);
162 d->buf = buf ? buf : &d->defaultBuf;
163 d->defaultBuf.clear();
164}
165#else
166/*!
167 Constructs an empty buffer with the given \a parent. You can call
168 setData() to fill the buffer with data, or you can open it in
169 write mode and use write().
170
171 \sa open()
172*/
173QBuffer::QBuffer(QObject *parent)
174 : QIODevice(*new QBufferPrivate, parent)
175{
176 Q_D(QBuffer);
177 d->buf = &d->defaultBuf;
178}
179
180/*!
181 Constructs a QBuffer that uses the QByteArray pointed to by \a
182 byteArray as its internal buffer, and with the given \a parent.
183 The caller is responsible for ensuring that \a byteArray remains
184 valid until the QBuffer is destroyed, or until setBuffer() is
185 called to change the buffer. QBuffer doesn't take ownership of
186 the QByteArray.
187
188 If you open the buffer in write-only mode or read-write mode and
189 write something into the QBuffer, \a byteArray will be modified.
190
191 Example:
192
193 \snippet buffer/buffer.cpp 3
194
195 \sa open(), setBuffer(), setData()
196*/
197QBuffer::QBuffer(QByteArray *byteArray, QObject *parent)
198 : QIODevice(*new QBufferPrivate, parent)
199{
200 Q_D(QBuffer);
201 d->buf = byteArray ? byteArray : &d->defaultBuf;
202 d->defaultBuf.clear();
203}
204#endif
205
206/*!
207 Destroys the buffer.
208*/
209
210QBuffer::~QBuffer()
211{
212}
213
214/*!
215 Makes QBuffer uses the QByteArray pointed to by \a
216 byteArray as its internal buffer. The caller is responsible for
217 ensuring that \a byteArray remains valid until the QBuffer is
218 destroyed, or until setBuffer() is called to change the buffer.
219 QBuffer doesn't take ownership of the QByteArray.
220
221 Does nothing if isOpen() is true.
222
223 If you open the buffer in write-only mode or read-write mode and
224 write something into the QBuffer, \a byteArray will be modified.
225
226 Example:
227
228 \snippet buffer/buffer.cpp 4
229
230 If \a byteArray is 0, the buffer creates its own internal
231 QByteArray to work on. This byte array is initially empty.
232
233 \sa buffer(), setData(), open()
234*/
235
236void QBuffer::setBuffer(QByteArray *byteArray)
237{
238 Q_D(QBuffer);
239 if (isOpen()) {
240 qWarning("QBuffer::setBuffer: Buffer is open");
241 return;
242 }
243 if (byteArray) {
244 d->buf = byteArray;
245 } else {
246 d->buf = &d->defaultBuf;
247 }
248 d->defaultBuf.clear();
249}
250
251/*!
252 Returns a reference to the QBuffer's internal buffer. You can use
253 it to modify the QByteArray behind the QBuffer's back.
254
255 \sa setBuffer(), data()
256*/
257
258QByteArray &QBuffer::buffer()
259{
260 Q_D(QBuffer);
261 return *d->buf;
262}
263
264/*!
265 \overload
266
267 This is the same as data().
268*/
269
270const QByteArray &QBuffer::buffer() const
271{
272 Q_D(const QBuffer);
273 return *d->buf;
274}
275
276
277/*!
278 Returns the data contained in the buffer.
279
280 This is the same as buffer().
281
282 \sa setData(), setBuffer()
283*/
284
285const QByteArray &QBuffer::data() const
286{
287 Q_D(const QBuffer);
288 return *d->buf;
289}
290
291/*!
292 Sets the contents of the internal buffer to be \a data. This is
293 the same as assigning \a data to buffer().
294
295 Does nothing if isOpen() is true.
296
297 \sa setBuffer()
298*/
299void QBuffer::setData(const QByteArray &data)
300{
301 Q_D(QBuffer);
302 if (isOpen()) {
303 qWarning("QBuffer::setData: Buffer is open");
304 return;
305 }
306 *d->buf = data;
307}
308
309/*!
310 \fn void QBuffer::setData(const char *data, int size)
311
312 \overload
313
314 Sets the contents of the internal buffer to be the first \a size
315 bytes of \a data.
316*/
317
318/*!
319 \reimp
320*/
321bool QBuffer::open(OpenMode flags)
322{
323 Q_D(QBuffer);
324
325 if ((flags & (Append | Truncate)) != 0)
326 flags |= WriteOnly;
327 if ((flags & (ReadOnly | WriteOnly)) == 0) {
328 qWarning("QBuffer::open: Buffer access not specified");
329 return false;
330 }
331
332 if ((flags & Truncate) == Truncate)
333 d->buf->resize(0);
334
335 return QIODevice::open(flags | QIODevice::Unbuffered);
336}
337
338/*!
339 \reimp
340*/
341void QBuffer::close()
342{
343 QIODevice::close();
344}
345
346/*!
347 \reimp
348*/
349qint64 QBuffer::pos() const
350{
351 return QIODevice::pos();
352}
353
354/*!
355 \reimp
356*/
357qint64 QBuffer::size() const
358{
359 Q_D(const QBuffer);
360 return qint64(d->buf->size());
361}
362
363/*!
364 \reimp
365*/
366bool QBuffer::seek(qint64 pos)
367{
368 Q_D(QBuffer);
369 if (pos > d->buf->size() && isWritable()) {
370 if (seek(d->buf->size())) {
371 const qint64 gapSize = pos - d->buf->size();
372 if (write(QByteArray(gapSize, 0)) != gapSize) {
373 qWarning("QBuffer::seek: Unable to fill gap");
374 return false;
375 }
376 } else {
377 return false;
378 }
379 } else if (pos > d->buf->size() || pos < 0) {
380 qWarning("QBuffer::seek: Invalid pos: %d", int(pos));
381 return false;
382 }
383 return QIODevice::seek(pos);
384}
385
386/*!
387 \reimp
388*/
389bool QBuffer::atEnd() const
390{
391 return QIODevice::atEnd();
392}
393
394/*!
395 \reimp
396*/
397bool QBuffer::canReadLine() const
398{
399 Q_D(const QBuffer);
400 if (!isOpen())
401 return false;
402
403 return d->buf->indexOf('\n', int(pos())) != -1 || QIODevice::canReadLine();
404}
405
406/*!
407 \reimp
408*/
409qint64 QBuffer::readData(char *data, qint64 len)
410{
411 Q_D(QBuffer);
412 if ((len = qMin(len, qint64(d->buf->size()) - pos())) <= 0)
413 return qint64(0);
414 memcpy(data, d->buf->constData() + pos(), len);
415 return len;
416}
417
418/*!
419 \reimp
420*/
421qint64 QBuffer::writeData(const char *data, qint64 len)
422{
423 Q_D(QBuffer);
424 int extraBytes = pos() + len - d->buf->size();
425 if (extraBytes > 0) { // overflow
426 int newSize = d->buf->size() + extraBytes;
427 d->buf->resize(newSize);
428 if (d->buf->size() != newSize) { // could not resize
429 qWarning("QBuffer::writeData: Memory allocation error");
430 return -1;
431 }
432 }
433
434 memcpy(d->buf->data() + pos(), data, int(len));
435
436#ifndef QT_NO_QOBJECT
437 d->writtenSinceLastEmit += len;
438 if (d->signalConnectionCount && !d->signalsEmitted && !signalsBlocked()) {
439 d->signalsEmitted = true;
440 QMetaObject::invokeMethod(this, "_q_emitSignals", Qt::QueuedConnection);
441 }
442#endif
443 return len;
444}
445
446#ifndef QT_NO_QOBJECT
447/*!
448 \reimp
449 \internal
450*/
451void QBuffer::connectNotify(const QMetaMethod &signal)
452{
453 static const QMetaMethod readyReadSignal = QMetaMethod::fromSignal(&QBuffer::readyRead);
454 static const QMetaMethod bytesWrittenSignal = QMetaMethod::fromSignal(&QBuffer::bytesWritten);
455 if (signal == readyReadSignal || signal == bytesWrittenSignal)
456 d_func()->signalConnectionCount++;
457}
458
459/*!
460 \reimp
461 \internal
462*/
463void QBuffer::disconnectNotify(const QMetaMethod &signal)
464{
465 if (signal.isValid()) {
466 static const QMetaMethod readyReadSignal = QMetaMethod::fromSignal(&QBuffer::readyRead);
467 static const QMetaMethod bytesWrittenSignal = QMetaMethod::fromSignal(&QBuffer::bytesWritten);
468 if (signal == readyReadSignal || signal == bytesWrittenSignal)
469 d_func()->signalConnectionCount--;
470 } else {
471 d_func()->signalConnectionCount = 0;
472 }
473}
474#endif
475
476QT_END_NAMESPACE
477
478#ifndef QT_NO_QOBJECT
479# include "moc_qbuffer.cpp"
480#endif
481
482