Revision control
++ // Copyright (C) 2021 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include "qiopipe.h"
++
++ #include <QtCore/private/qobject_p.h>
++ #include <QtCore/qpointer.h>
++
++ #include <QDebug>
++
++ #include <memory>
++
++ QT_BEGIN_NAMESPACE
++
++ class QPipeEndPoint : public QIODevice
++ {
++ Q_OBJECT
++
++ public:
++ bool isSequential() const override;
++ qint64 bytesAvailable() const override;
++
++ void setRemoteEndPoint(QPipeEndPoint *other);
++
++ protected:
++ qint64 readData(char *data, qint64 maxlen) override;
++ qint64 writeData(const char *data, qint64 len) override;
++
++ private:
++ QByteArray m_buffer;
++ QPointer<QPipeEndPoint> m_remoteEndPoint;
++ };
++
++ class QIOPipePrivate final : public QObjectPrivate
++ {
++ Q_DECLARE_PUBLIC(QIOPipe)
++ public:
++ QIOPipePrivate();
++ ~QIOPipePrivate() override;
++
++ std::unique_ptr<QPipeEndPoint> end1;
++ std::unique_ptr<QPipeEndPoint> end2;
++ };
++
++ QIOPipe::QIOPipe(QObject *parent) :
++ QObject(*(new QIOPipePrivate()), parent)
++ {
++ }
++
++ bool QIOPipe::open(QIODevice::OpenMode mode)
++ {
++ Q_D(QIOPipe);
++
++ if (!d->end1->open(mode))
++ return false;
++ switch (mode & QIODevice::ReadWrite) {
++ case QIODevice::WriteOnly:
++ case QIODevice::ReadOnly:
++ return d->end2->open(mode ^ QIODevice::ReadWrite);
++ default:
++ return d->end2->open(mode);
++ }
++ }
++
++ QIODevice *QIOPipe::end1() const
++ {
++ Q_D(const QIOPipe);
++ return d->end1.get();
++ }
++
++ QIODevice *QIOPipe::end2() const
++ {
++ Q_D(const QIOPipe);
++ return d->end2.get();
++ }
++
++ QIOPipePrivate::QIOPipePrivate() :
++ end1(std::make_unique<QPipeEndPoint>()),
++ end2(std::make_unique<QPipeEndPoint>())
++ {
++ end1->setRemoteEndPoint(end2.get());
++ end2->setRemoteEndPoint(end1.get());
++ }
++
++ QIOPipePrivate::~QIOPipePrivate()
++ {
++ }
++
++ bool QPipeEndPoint::isSequential() const
++ {
++ return true;
++ }
++
++ qint64 QPipeEndPoint::bytesAvailable() const
++ {
++ return m_buffer.size() + QIODevice::bytesAvailable();
++ }
++
++ void QPipeEndPoint::setRemoteEndPoint(QPipeEndPoint *other)
++ {
++ m_remoteEndPoint = other;
++ }
++
++ qint64 QPipeEndPoint::readData(char *data, qint64 maxlen)
++ {
++ maxlen = qMin(maxlen, static_cast<qint64>(m_buffer.size()));
++ if (maxlen <= 0)
++ return 0;
++
++ Q_ASSERT(maxlen > 0);
++ Q_ASSERT(maxlen <= std::numeric_limits<int>::max());
++ memcpy(data, m_buffer.data(), static_cast<size_t>(maxlen));
++ m_buffer = m_buffer.mid(static_cast<int>(maxlen));
++ return maxlen;
++ }
++
++ qint64 QPipeEndPoint::writeData(const char *data, qint64 len)
++ {
++ if (!m_remoteEndPoint)
++ return -1;
++
++ if (len <= 0)
++ return 0;
++
++ QByteArray &buffer = m_remoteEndPoint->m_buffer;
++ const qint64 prevLen = buffer.size();
++ Q_ASSERT(prevLen >= 0);
++ len = qMin(len, std::numeric_limits<int>::max() - prevLen);
++
++ if (len == 0)
++ return 0;
++
++ Q_ASSERT(len > 0);
++ Q_ASSERT(prevLen + len > 0);
++ Q_ASSERT(prevLen + len <= std::numeric_limits<int>::max());
++
++ buffer.resize(static_cast<int>(prevLen + len));
++ memcpy(buffer.data() + prevLen, data, static_cast<size_t>(len));
++ emit bytesWritten(len);
++ emit m_remoteEndPoint->readyRead();
++ return len;
++ }
++
++ QT_END_NAMESPACE
++
++ #include <qiopipe.moc>