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 | |
44 | QT_BEGIN_NAMESPACE |
45 | |
46 | /** QBufferPrivate **/ |
47 | class QBufferPrivate : public QIODevicePrivate |
48 | { |
49 | Q_DECLARE_PUBLIC(QBuffer) |
50 | |
51 | public: |
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 |
77 | void QBufferPrivate::_q_emitSignals() |
78 | { |
79 | Q_Q(QBuffer); |
80 | emit q->bytesWritten(bytes: writtenSinceLastEmit); |
81 | writtenSinceLastEmit = 0; |
82 | emit q->readyRead(); |
83 | signalsEmitted = false; |
84 | } |
85 | #endif |
86 | |
87 | qint64 QBufferPrivate::peek(char *data, qint64 maxSize) |
88 | { |
89 | qint64 readBytes = qMin(a: maxSize, b: static_cast<qint64>(buf->size()) - pos); |
90 | memcpy(dest: data, src: buf->constData() + pos, n: readBytes); |
91 | return readBytes; |
92 | } |
93 | |
94 | QByteArray QBufferPrivate::peek(qint64 maxSize) |
95 | { |
96 | qint64 readBytes = qMin(a: maxSize, b: 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 |
152 | QBuffer::QBuffer() |
153 | : QIODevice(*new QBufferPrivate) |
154 | { |
155 | Q_D(QBuffer); |
156 | d->buf = &d->defaultBuf; |
157 | } |
158 | QBuffer::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 | */ |
173 | QBuffer::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 | */ |
197 | QBuffer::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 | |
210 | QBuffer::~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 \nullptr, 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 | |
236 | void QBuffer::setBuffer(QByteArray *byteArray) |
237 | { |
238 | Q_D(QBuffer); |
239 | if (isOpen()) { |
240 | qWarning(msg: "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 | |
258 | QByteArray &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 | |
270 | const 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 | |
285 | const 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 | */ |
299 | void QBuffer::setData(const QByteArray &data) |
300 | { |
301 | Q_D(QBuffer); |
302 | if (isOpen()) { |
303 | qWarning(msg: "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 | */ |
321 | bool 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(msg: "QBuffer::open: Buffer access not specified" ); |
329 | return false; |
330 | } |
331 | |
332 | if ((flags & Truncate) == Truncate) |
333 | d->buf->resize(size: 0); |
334 | |
335 | return QIODevice::open(mode: flags | QIODevice::Unbuffered); |
336 | } |
337 | |
338 | /*! |
339 | \reimp |
340 | */ |
341 | void QBuffer::close() |
342 | { |
343 | QIODevice::close(); |
344 | } |
345 | |
346 | /*! |
347 | \reimp |
348 | */ |
349 | qint64 QBuffer::pos() const |
350 | { |
351 | return QIODevice::pos(); |
352 | } |
353 | |
354 | /*! |
355 | \reimp |
356 | */ |
357 | qint64 QBuffer::size() const |
358 | { |
359 | Q_D(const QBuffer); |
360 | return qint64(d->buf->size()); |
361 | } |
362 | |
363 | /*! |
364 | \reimp |
365 | */ |
366 | bool QBuffer::seek(qint64 pos) |
367 | { |
368 | Q_D(QBuffer); |
369 | if (pos > d->buf->size() && isWritable()) { |
370 | if (seek(pos: d->buf->size())) { |
371 | const qint64 gapSize = pos - d->buf->size(); |
372 | if (write(data: QByteArray(gapSize, 0)) != gapSize) { |
373 | qWarning(msg: "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(msg: "QBuffer::seek: Invalid pos: %d" , int(pos)); |
381 | return false; |
382 | } |
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(c: '\n', from: 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(a: len, b: qint64(d->buf->size()) - pos())) <= 0) |
413 | return qint64(0); |
414 | memcpy(dest: data, src: d->buf->constData() + pos(), n: len); |
415 | return len; |
416 | } |
417 | |
418 | /*! |
419 | \reimp |
420 | */ |
421 | qint64 QBuffer::writeData(const char *data, qint64 len) |
422 | { |
423 | Q_D(QBuffer); |
424 | int = pos() + len - d->buf->size(); |
425 | if (extraBytes > 0) { // overflow |
426 | int newSize = d->buf->size() + extraBytes; |
427 | d->buf->resize(size: newSize); |
428 | if (d->buf->size() != newSize) { // could not resize |
429 | qWarning(msg: "QBuffer::writeData: Memory allocation error" ); |
430 | return -1; |
431 | } |
432 | } |
433 | |
434 | memcpy(dest: d->buf->data() + pos(), src: data, n: 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(obj: this, member: "_q_emitSignals" , type: Qt::QueuedConnection); |
441 | } |
442 | #endif |
443 | return len; |
444 | } |
445 | |
446 | #ifndef QT_NO_QOBJECT |
447 | /*! |
448 | \reimp |
449 | \internal |
450 | */ |
451 | void QBuffer::connectNotify(const QMetaMethod &signal) |
452 | { |
453 | static const QMetaMethod readyReadSignal = QMetaMethod::fromSignal(signal: &QBuffer::readyRead); |
454 | static const QMetaMethod bytesWrittenSignal = QMetaMethod::fromSignal(signal: &QBuffer::bytesWritten); |
455 | if (signal == readyReadSignal || signal == bytesWrittenSignal) |
456 | d_func()->signalConnectionCount++; |
457 | } |
458 | |
459 | /*! |
460 | \reimp |
461 | \internal |
462 | */ |
463 | void QBuffer::disconnectNotify(const QMetaMethod &signal) |
464 | { |
465 | if (signal.isValid()) { |
466 | static const QMetaMethod readyReadSignal = QMetaMethod::fromSignal(signal: &QBuffer::readyRead); |
467 | static const QMetaMethod bytesWrittenSignal = QMetaMethod::fromSignal(signal: &QBuffer::bytesWritten); |
468 | if (signal == readyReadSignal || signal == bytesWrittenSignal) |
469 | d_func()->signalConnectionCount--; |
470 | } else { |
471 | d_func()->signalConnectionCount = 0; |
472 | } |
473 | } |
474 | #endif |
475 | |
476 | QT_END_NAMESPACE |
477 | |
478 | #ifndef QT_NO_QOBJECT |
479 | # include "moc_qbuffer.cpp" |
480 | #endif |
481 | |
482 | |