1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtLocation 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 "qiopipe_p.h"
41 #include <QtCore/qmetaobject.h>
42 #include <QDebug>
43 
44 QT_BEGIN_NAMESPACE
45 
46 /*
47     proxying means do *not* emit readyRead, and instead pump data
48     into child pipes directly in a zero-copy fashion.
49 */
QIOPipePrivate(QIODevice * iodevice,bool proxying)50 QIOPipePrivate::QIOPipePrivate(QIODevice *iodevice, bool proxying)
51     :  m_proxying(proxying), source(iodevice)
52 {
53 }
54 
~QIOPipePrivate()55 QIOPipePrivate::~QIOPipePrivate()
56 {
57 }
58 
initialize()59 void QIOPipePrivate::initialize()
60 {
61     const QIOPipe *parentPipe = qobject_cast<QIOPipe *>(source);
62     if (parentPipe && parentPipe->d_func()->m_proxying) // with proxying parent,
63         return;                                                     // don't do anything
64 
65     // read available data, does not emit.
66     readAvailableData();
67     // connect readyRead to onReadyRead
68     QObjectPrivate::connect(source, &QIODevice::readyRead, this, &QIOPipePrivate::_q_onReadyRead);
69 }
70 
readAvailableData()71 bool QIOPipePrivate::readAvailableData() {
72     if (!source)
73         return false;
74     QByteArray ba = source->readAll();
75     if (!ba.size())
76         return false;
77 
78     pumpData(ba);
79     return true;
80 }
81 
pumpData(const QByteArray & ba)82 void QIOPipePrivate::pumpData(const QByteArray &ba)
83 {
84     if (m_proxying) {
85         QVector<int> toRemove;
86         for (int i = 0; i < childPipes.size(); ++i) {
87             const QPointer<QIOPipe> &cp = childPipes.at(i);
88             if (!cp) {
89                 toRemove.append(i);
90                 continue;
91             }
92             QIOPipePrivate *cpp = cp->d_func();
93             cpp->pushData(ba);
94         }
95         for (int i = toRemove.size() - 1; i >= 0; --i) {
96             childPipes.remove(i);
97         }
98     } else {
99         for (int i = 0; i < readBuffers.size(); i++)
100             readBuffers[i].append(ba);
101     }
102 }
103 
pushData(const QByteArray & ba)104 void QIOPipePrivate::pushData(const QByteArray &ba)
105 {
106     Q_Q(QIOPipe);
107     if (!ba.size())
108         return;
109 
110     pumpData(ba);
111     if (!m_proxying)
112         emit q->readyRead();
113 }
114 
_q_onReadyRead()115 void QIOPipePrivate::_q_onReadyRead()
116 {
117     Q_Q(QIOPipe);
118     if (readAvailableData() && !m_proxying)
119         emit q->readyRead();
120 }
121 
addChildPipe(QIOPipe * childPipe)122 void QIOPipePrivate::addChildPipe(QIOPipe *childPipe)
123 {
124     if (childPipes.contains(childPipe))
125         return;
126     childPipes.append(childPipe);
127 }
128 
removeChildPipe(QIOPipe * childPipe)129 void QIOPipePrivate::removeChildPipe(QIOPipe *childPipe)
130 {
131     childPipes.removeOne(childPipe);
132 }
133 
QIOPipe(QIODevice * parent,Mode mode)134 QIOPipe::QIOPipe(QIODevice *parent, Mode mode)
135     : QIODevice(*new QIOPipePrivate(parent, mode == ProxyPipe), parent)
136 {
137     this->d_func()->initialize();
138     if (!parent->isOpen() && !parent->open(QIODevice::ReadOnly)) {
139         qWarning() << "QIOPipe: Failed to open " << parent;
140         return;
141     }
142     open(ReadOnly);
143 }
144 
~QIOPipe()145 QIOPipe::~QIOPipe()
146 {
147 
148 }
149 
open(QIODevice::OpenMode mode)150 bool QIOPipe::open(QIODevice::OpenMode mode)
151 {
152     if (isOpen())
153         return true;
154 
155     static const OpenMode supportedOpenMode = ReadOnly; // Currently limit it to read only
156     if (!(mode & supportedOpenMode)) {
157         qFatal("Unsupported open mode");
158         return false;
159     }
160 
161     return QIODevice::open(mode);
162 }
163 
isSequential() const164 bool QIOPipe::isSequential() const
165 {
166     return true;
167 }
168 
setReadChannelCount(int count)169 void QIOPipe::setReadChannelCount(int count)
170 {
171     Q_D(QIOPipe);
172     d->setReadChannelCount(qMax(count, 1));
173 }
174 
addChildPipe(QIOPipe * childPipe)175 void QIOPipe::addChildPipe(QIOPipe *childPipe)
176 {
177     Q_D(QIOPipe);
178     d->addChildPipe(childPipe);
179 }
180 
181 /*!
182     \reimp
183 
184     \omit
185     This function does not really read anything, as we use QIODevicePrivate's
186     buffer. The buffer will be read inside of QIODevice before this
187     method will be called.
188     See QIODevicePrivate::read, buffer.read(data, maxSize).
189     \endomit
190 */
readData(char * data,qint64 maxlen)191 qint64 QIOPipe::readData(char *data, qint64 maxlen)
192 {
193     Q_UNUSED(data);
194     Q_UNUSED(maxlen);
195 
196     // return 0 indicating there may be more data in the future
197     // Returning -1 means no more data in the future (end of stream).
198     return qint64(0);
199 }
200 
writeData(const char *,qint64)201 qint64 QIOPipe::writeData(const char * /*data*/, qint64 /*len*/)
202 {
203     qFatal("QIOPipe is a read-only device");
204     return qint64(0);
205 }
206 
207 QT_END_NAMESPACE
208