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
44QT_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*/
50QIOPipePrivate::QIOPipePrivate(QIODevice *iodevice, bool proxying)
51 : m_proxying(proxying), source(iodevice)
52{
53}
54
55QIOPipePrivate::~QIOPipePrivate()
56{
57}
58
59void QIOPipePrivate::initialize()
60{
61 const QIOPipe *parentPipe = qobject_cast<QIOPipe *>(object: 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(sender: source, signal: &QIODevice::readyRead, receiverPrivate: this, slot: &QIOPipePrivate::_q_onReadyRead);
69}
70
71bool 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
82void 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(t: 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(qba: ba);
101 }
102}
103
104void 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
115void QIOPipePrivate::_q_onReadyRead()
116{
117 Q_Q(QIOPipe);
118 if (readAvailableData() && !m_proxying)
119 emit q->readyRead();
120}
121
122void QIOPipePrivate::addChildPipe(QIOPipe *childPipe)
123{
124 if (childPipes.contains(t: childPipe))
125 return;
126 childPipes.append(t: childPipe);
127}
128
129void QIOPipePrivate::removeChildPipe(QIOPipe *childPipe)
130{
131 childPipes.removeOne(t: childPipe);
132}
133
134QIOPipe::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(mode: QIODevice::ReadOnly)) {
139 qWarning() << "QIOPipe: Failed to open " << parent;
140 return;
141 }
142 open(openMode: ReadOnly);
143}
144
145QIOPipe::~QIOPipe()
146{
147
148}
149
150bool 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(msg: "Unsupported open mode");
158 return false;
159 }
160
161 return QIODevice::open(mode);
162}
163
164bool QIOPipe::isSequential() const
165{
166 return true;
167}
168
169void QIOPipe::setReadChannelCount(int count)
170{
171 Q_D(QIOPipe);
172 d->setReadChannelCount(qMax(a: count, b: 1));
173}
174
175void 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*/
191qint64 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
201qint64 QIOPipe::writeData(const char * /*data*/, qint64 /*len*/)
202{
203 qFatal(msg: "QIOPipe is a read-only device");
204 return qint64(0);
205}
206
207QT_END_NAMESPACE
208

source code of qtlocation/src/plugins/position/serialnmea/qiopipe.cpp