1 /****************************************************************************
2 **
3 ** Copyright (C) 2008-2012 NVIDIA Corporation.
4 ** Copyright (C) 2019 The Qt Company Ltd.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of Qt Quick 3D.
8 **
9 ** $QT_BEGIN_LICENSE:GPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU
20 ** General Public License version 3 or (at your option) any later version
21 ** approved by the KDE Free Qt Foundation. The licenses are as published by
22 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
23 ** included in the packaging of this file. Please review the following
24 ** information to ensure the GNU General Public License requirements will
25 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
26 **
27 ** $QT_END_LICENSE$
28 **
29 ****************************************************************************/
30 
31 #include "qssgrenderinputstreamfactory_p.h"
32 
33 #include <QtQuick3DUtils/private/qssgutils_p.h>
34 
35 #include <QtCore/QDir>
36 #include <QtCore/QDirIterator>
37 #include <QtCore/QFile>
38 #include <QtCore/QFileInfo>
39 #include <QtCore/QUrl>
40 #include <QtCore/QMutexLocker>
41 
42 #include <limits>
43 
44 QT_BEGIN_NAMESPACE
45 
46 namespace {
47 class QSSGInputStream : public QFile
48 {
49 public:
QSSGInputStream(const QString & inPath)50     explicit QSSGInputStream(const QString &inPath) : QFile(inPath), m_path(inPath) {}
51     ~QSSGInputStream() override = default;
path() const52     QString path() const { return m_path; }
53 
54 private:
55     QString m_path;
56 };
57 
58 
normalizePathForQtUsage(const QString & path)59 QString normalizePathForQtUsage(const QString &path)
60 {
61     // path can be a file path or a qrc URL string.
62 
63     QString filePath = QDir::cleanPath(path);
64 
65     if (filePath.startsWith(QLatin1String("qrc:/")))
66         return filePath.mid(3);
67 
68     return filePath;
69 }
70 
71 const QString Q3DSTUDIO_TAG = QStringLiteral("qt3dstudio");
72 
73 }
74 
~QSSGInputStreamFactory()75 QSSGInputStreamFactory::~QSSGInputStreamFactory() {}
76 
QSSGInputStreamFactory()77 QSSGInputStreamFactory::QSSGInputStreamFactory()
78 {
79     // Add the top-level qrc directory
80     if (!QDir::searchPaths(Q3DSTUDIO_TAG).contains(QLatin1String(":/")))
81         QDir::addSearchPath(Q3DSTUDIO_TAG, QStringLiteral(":/"));
82 }
83 
addSearchDirectory(const QString & inDirectory)84 void QSSGInputStreamFactory::addSearchDirectory(const QString &inDirectory)
85 {
86     QMutexLocker factoryLocker(&m_mutex);
87     QString localDir = normalizePathForQtUsage(inDirectory);
88     QDir directory(localDir);
89     if (!directory.exists()) {
90         qCritical("Adding search directory: %s", inDirectory.toUtf8().constData());
91         return;
92     }
93 
94     if (!QDir::searchPaths(Q3DSTUDIO_TAG).contains(localDir))
95         QDir::addSearchPath(Q3DSTUDIO_TAG, localDir);
96 }
97 
getStreamForFile(const QString & inFilename,bool inQuiet)98 QSharedPointer<QIODevice> QSSGInputStreamFactory::getStreamForFile(const QString &inFilename, bool inQuiet)
99 {
100     QMutexLocker factoryLocker(&m_mutex);
101     QString localFile = normalizePathForQtUsage(inFilename);
102     QFileInfo fileInfo = QFileInfo(localFile);
103     QIODevice *inputStream = nullptr;
104     // Try to match the file with the search paths
105     if (!fileInfo.exists())
106         fileInfo.setFile(QStringLiteral("qt3dstudio:") + localFile);
107 
108     if (fileInfo.exists()) {
109         QSSGInputStream *file = new QSSGInputStream(fileInfo.absoluteFilePath());
110         if (file->open(QIODevice::ReadOnly))
111             inputStream = file;
112     }
113 
114     if (!inputStream && !inQuiet) {
115         // Print extensive debugging information.
116         qCritical("Failed to find file: %s", inFilename.toLatin1().data());
117         qCritical("Searched path: %s", QDir::searchPaths(Q3DSTUDIO_TAG).join(',').toLatin1().constData());
118     }
119     return QSharedPointer<QIODevice>(inputStream);
120 }
121 
getPathForFile(const QString & inFilename,QString & outFile,bool inQuiet)122 bool QSSGInputStreamFactory::getPathForFile(const QString &inFilename, QString &outFile, bool inQuiet)
123 {
124     QSharedPointer<QIODevice> theStream = getStreamForFile(inFilename, inQuiet);
125     if (theStream) {
126         QSSGInputStream *theRealStream = static_cast<QSSGInputStream *>(theStream.data());
127         outFile = theRealStream->path();
128         return true;
129     }
130     return false;
131 }
132 
133 QT_END_NAMESPACE
134