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

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 11.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department 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#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
76void 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
139QBuffer::QBuffer()
140 : QIODevice(*new QBufferPrivate)
141{
142 Q_D(QBuffer);
143 d->buf = &d->defaultBuf;
144 d->ioIndex = 0;
145}
146QBuffer::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*/
162QBuffer::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*/
187QBuffer::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
201QBuffer::~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
227void 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
250QByteArray &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
262const 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
277const 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*/
291void 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*/
314bool 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*/
340void QBuffer::close()
341{
342 QIODevice::close();
343}
344
345/*!
346 \reimp
347*/
348qint64 QBuffer::pos() const
349{
350 return QIODevice::pos();
351}
352
353/*!
354 \reimp
355*/
356qint64 QBuffer::size() const
357{
358 Q_D(const QBuffer);
359 return qint64(d->buf->size());
360}
361
362/*!
363 \reimp
364*/
365bool 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*/
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()) - 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*/
422qint64 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*/
453void QBuffer::connectNotify(const char *signal)
454{
455 if (strcmp(signal + 1, "readyRead()") == 0 || strcmp(signal + 1, "bytesWritten(qint64)"))
456 d_func()->signalConnectionCount++;
457}
458
459/*!
460 \reimp
461 \internal
462*/
463void 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
470QT_END_NAMESPACE
471
472#ifndef QT_NO_QOBJECT
473# include "moc_qbuffer.cpp"
474#endif
475
Note: See TracBrowser for help on using the repository browser.