source: trunk/src/corelib/io/qbuffer.cpp@ 1168

Last change on this file since 1168 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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