1/****************************************************************************
2**
3** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D 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 "assimphelpers.h"
41
42#include <QtCore/QFileDevice>
43#include <QtCore/QFileInfo>
44#include <QtCore/QUrl>
45#include <QtCore/QDir>
46#include <QtCore/QDebug>
47
48QT_BEGIN_NAMESPACE
49
50namespace Qt3DRender {
51namespace AssimpHelper {
52/*!
53 * \class Qt3DRender::AssimpHelper::AssimpIOStream
54 *
55 * \internal
56 *
57 * \brief Provides a custom file stream class to be used by AssimpIOSystem.
58 *
59 */
60
61/*!
62 * Builds a new AssimpIOStream instance.
63 */
64AssimpIOStream::AssimpIOStream(QIODevice *device) :
65 Assimp::IOStream(),
66 m_device(device)
67{
68 Q_ASSERT(m_device != nullptr);
69}
70
71/*!
72 * Clears an AssimpIOStream instance before deletion.
73 */
74AssimpIOStream::~AssimpIOStream()
75{
76 // Owns m_device
77 delete m_device;
78}
79
80/*!
81 * Reads at most \a pCount elements of \a pSize bytes of data into \a pvBuffer.
82 * Returns the number of bytes read or -1 if an error occurred.
83 */
84size_t AssimpIOStream::Read(void *pvBuffer, size_t pSize, size_t pCount)
85{
86 qint64 readBytes = m_device->read(data: (char *)pvBuffer, maxlen: pSize * pCount);
87 if (readBytes < 0)
88 qWarning() << Q_FUNC_INFO << " Reading failed";
89 return readBytes;
90}
91
92
93/*!
94 * Writes \a pCount elements of \a pSize bytes from \a pvBuffer.
95 * Returns the number of bytes written or -1 if an error occurred.
96 */
97size_t AssimpIOStream::Write(const void *pvBuffer, size_t pSize, size_t pCount)
98{
99 qint64 writtenBytes = m_device->write(data: (char *)pvBuffer, len: pSize * pCount);
100 if (writtenBytes < 0)
101 qWarning() << Q_FUNC_INFO << " Writing failed";
102 return writtenBytes;
103}
104
105/*!
106 * Seeks the current file descriptor to a position defined by \a pOrigin and \a pOffset
107 */
108aiReturn AssimpIOStream::Seek(size_t pOffset, aiOrigin pOrigin)
109{
110 qint64 seekPos = pOffset;
111
112 if (pOrigin == aiOrigin_CUR)
113 seekPos += m_device->pos();
114 else if (pOrigin == aiOrigin_END)
115 seekPos += m_device->size();
116
117 if (!m_device->seek(pos: seekPos)) {
118 qWarning() << Q_FUNC_INFO << " Seeking failed";
119 return aiReturn_FAILURE;
120 }
121 return aiReturn_SUCCESS;
122}
123
124/*!
125 * Returns the current position of the read/write cursor.
126 */
127size_t AssimpIOStream::Tell() const
128{
129 return m_device->pos();
130}
131
132/*!
133 * Returns the filesize;
134 */
135size_t AssimpIOStream::FileSize() const
136{
137 return m_device->size();
138}
139
140/*!
141 * Flushes the current device.
142 */
143void AssimpIOStream::Flush()
144{
145 // QIODevice has no flush method
146 if (QFileDevice *file = qobject_cast<QFileDevice *>(object: m_device))
147 file->flush();
148}
149
150/*!
151 * \class Qt3DRender::AssimpHelper::AssimpIOSystem
152 *
153 * \internal
154 *
155 * \brief Provides a custom file handler to the Assimp importer in order to handle
156 * various Qt specificities (QResources ...)
157 *
158 */
159
160static QIODevice::OpenMode openModeFromText(const char *name) noexcept
161{
162 static const struct OpenModeMapping {
163 char name[2];
164 ushort mode;
165 } openModeMapping[] = {
166 { .name: { 'r', 0 }, .mode: QIODevice::ReadOnly },
167 { .name: { 'r', '+' }, .mode: QIODevice::ReadWrite },
168 { .name: { 'w', 0 }, .mode: QIODevice::WriteOnly | QIODevice::Truncate },
169 { .name: { 'w', '+' }, .mode: QIODevice::ReadWrite | QIODevice::Truncate },
170 { .name: { 'a', 0 }, .mode: QIODevice::WriteOnly | QIODevice::Append },
171 { .name: { 'a', '+' }, .mode: QIODevice::ReadWrite | QIODevice::Append },
172 { .name: { 'w', 'b' }, .mode: QIODevice::WriteOnly },
173 { .name: { 'w', 't' }, .mode: QIODevice::WriteOnly | QIODevice::Text },
174 { .name: { 'r', 'b' }, .mode: QIODevice::ReadOnly },
175 { .name: { 'r', 't' }, .mode: QIODevice::ReadOnly | QIODevice::Text },
176 };
177
178 for (auto e : openModeMapping) {
179 if (qstrncmp(str1: e.name, str2: name, len: sizeof(OpenModeMapping::name)) == 0)
180 return static_cast<QIODevice::OpenMode>(e.mode);
181 }
182 return QIODevice::NotOpen;
183}
184
185/*!
186 * Returns true if the file located at pFile exists, false otherwise.
187 */
188bool AssimpIOSystem::Exists(const char *pFile) const
189{
190 return QFileInfo::exists(file: QString::fromUtf8(str: pFile));
191}
192
193/*!
194 * Returns the default system separator.
195 */
196char AssimpIOSystem::getOsSeparator() const
197{
198 return QDir::separator().toLatin1();
199}
200
201/*!
202 * Opens the file located at \a pFile with the opening mode
203 * specified by \a pMode.
204 */
205Assimp::IOStream *AssimpIOSystem::Open(const char *pFile, const char *pMode)
206{
207 const QString fileName(QString::fromUtf8(str: pFile));
208 const QLatin1String cleanedMode = QLatin1String{pMode}.trimmed();
209
210 if (const QIODevice::OpenMode openMode = openModeFromText(name: cleanedMode.data())) {
211 QScopedPointer<QFile> file(new QFile(fileName));
212 if (file->open(flags: openMode))
213 return new AssimpIOStream(file.take());
214 }
215 return nullptr;
216}
217
218/*!
219 * Closes the Assimp::IOStream \a pFile.
220 */
221void AssimpIOSystem::Close(Assimp::IOStream *pFile)
222{
223 // Assimp::IOStream has a virtual destructor which closes the stream
224 delete pFile;
225}
226
227} // namespace AssimpHelper
228} // namespace Qt3DRender
229
230QT_END_NAMESPACE
231

source code of qt3d/src/plugins/sceneparsers/assimp/assimphelpers.cpp