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