1/*
2---------------------------------------------------------------------------
3Open Asset Import Library (assimp)
4---------------------------------------------------------------------------
5
6Copyright (c) 2006-2017, assimp team
7
8
9All rights reserved.
10
11Redistribution and use of this software in source and binary forms,
12with or without modification, are permitted provided that the following
13conditions are met:
14
15* Redistributions of source code must retain the above
16 copyright notice, this list of conditions and the
17 following disclaimer.
18
19* Redistributions in binary form must reproduce the above
20 copyright notice, this list of conditions and the
21 following disclaimer in the documentation and/or other
22 materials provided with the distribution.
23
24* Neither the name of the assimp team, nor the names of its
25 contributors may be used to endorse or promote products
26 derived from this software without specific prior
27 written permission of the assimp team.
28
29THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40---------------------------------------------------------------------------
41*/
42/** @file Assimp.cpp
43 * @brief Implementation of the Plain-C API
44 */
45
46#include <assimp/cimport.h>
47#include <assimp/LogStream.hpp>
48#include <assimp/DefaultLogger.hpp>
49#include <assimp/Importer.hpp>
50#include <assimp/importerdesc.h>
51#include <assimp/scene.h>
52
53#include "GenericProperty.h"
54#include "CInterfaceIOWrapper.h"
55#include "Importer.h"
56#include "Exceptional.h"
57#include "ScenePrivate.h"
58#include "BaseImporter.h"
59#include <list>
60
61// ------------------------------------------------------------------------------------------------
62#ifndef ASSIMP_BUILD_SINGLETHREADED
63# include <thread>
64# include <mutex>
65#endif
66// ------------------------------------------------------------------------------------------------
67using namespace Assimp;
68
69namespace Assimp {
70 // underlying structure for aiPropertyStore
71 typedef BatchLoader::PropertyMap PropertyMap;
72
73 /** Stores the LogStream objects for all active C log streams */
74 struct mpred {
75 bool operator () (const aiLogStream& s0, const aiLogStream& s1) const {
76 return s0.callback<s1.callback&&s0.user<s1.user;
77 }
78 };
79 typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
80
81 /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
82 typedef std::list<Assimp::LogStream*> PredefLogStreamMap;
83
84 /** Local storage of all active log streams */
85 static LogStreamMap gActiveLogStreams;
86
87 /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */
88 static PredefLogStreamMap gPredefinedStreams;
89
90 /** Error message of the last failed import process */
91 static std::string gLastErrorString;
92
93 /** Verbose logging active or not? */
94 static aiBool gVerboseLogging = false;
95
96 /** will return all registered importers. */
97 void GetImporterInstanceList(std::vector< BaseImporter* >& out);
98
99 /** will delete all registered importers. */
100 void DeleteImporterInstanceList(std::vector< BaseImporter* >& out);
101} // namespace assimp
102
103
104#ifndef ASSIMP_BUILD_SINGLETHREADED
105/** Global mutex to manage the access to the log-stream map */
106static std::mutex gLogStreamMutex;
107#endif
108
109
110// ------------------------------------------------------------------------------------------------
111// Custom LogStream implementation for the C-API
112class LogToCallbackRedirector : public LogStream {
113public:
114 explicit LogToCallbackRedirector(const aiLogStream& s)
115 : stream (s) {
116 ai_assert(NULL != s.callback);
117 }
118
119 ~LogToCallbackRedirector() {
120#ifndef ASSIMP_BUILD_SINGLETHREADED
121 std::lock_guard<std::mutex> lock(gLogStreamMutex);
122#endif
123 // (HACK) Check whether the 'stream.user' pointer points to a
124 // custom LogStream allocated by #aiGetPredefinedLogStream.
125 // In this case, we need to delete it, too. Of course, this
126 // might cause strange problems, but the chance is quite low.
127
128 PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(),
129 gPredefinedStreams.end(), (Assimp::LogStream*)stream.user);
130
131 if (it != gPredefinedStreams.end()) {
132 delete *it;
133 gPredefinedStreams.erase(it);
134 }
135 }
136
137 /** @copydoc LogStream::write */
138 void write(const char* message) {
139 stream.callback(message,stream.user);
140 }
141
142private:
143 aiLogStream stream;
144};
145
146// ------------------------------------------------------------------------------------------------
147void ReportSceneNotFoundError() {
148 DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
149 "The C-API does not accept scenes produced by the C++ API and vice versa");
150
151 ai_assert(false);
152}
153
154// ------------------------------------------------------------------------------------------------
155// Reads the given file and returns its content.
156const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) {
157 return aiImportFileEx(pFile,pFlags,NULL);
158}
159
160// ------------------------------------------------------------------------------------------------
161const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS) {
162 return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
163}
164
165// ------------------------------------------------------------------------------------------------
166const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags,
167 aiFileIO* pFS, const aiPropertyStore* props) {
168 ai_assert(NULL != pFile);
169
170 const aiScene* scene = NULL;
171 ASSIMP_BEGIN_EXCEPTION_REGION();
172
173 // create an Importer for this file
174 Assimp::Importer* imp = new Assimp::Importer();
175
176 // copy properties
177 if(props) {
178 const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
179 ImporterPimpl* pimpl = imp->Pimpl();
180 pimpl->mIntProperties = pp->ints;
181 pimpl->mFloatProperties = pp->floats;
182 pimpl->mStringProperties = pp->strings;
183 pimpl->mMatrixProperties = pp->matrices;
184 }
185 // setup a custom IO system if necessary
186 if (pFS) {
187 imp->SetIOHandler( new CIOSystemWrapper (pFS) );
188 }
189
190 // and have it read the file
191 scene = imp->ReadFile( pFile, pFlags);
192
193 // if succeeded, store the importer in the scene and keep it alive
194 if( scene) {
195 ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
196 priv->mOrigImporter = imp;
197 } else {
198 // if failed, extract error code and destroy the import
199 gLastErrorString = imp->GetErrorString();
200 delete imp;
201 }
202
203 // return imported data. If the import failed the pointer is NULL anyways
204 ASSIMP_END_EXCEPTION_REGION(const aiScene*);
205
206 return scene;
207}
208
209// ------------------------------------------------------------------------------------------------
210const aiScene* aiImportFileFromMemory(
211 const char* pBuffer,
212 unsigned int pLength,
213 unsigned int pFlags,
214 const char* pHint)
215{
216 return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL);
217}
218
219// ------------------------------------------------------------------------------------------------
220const aiScene* aiImportFileFromMemoryWithProperties(
221 const char* pBuffer,
222 unsigned int pLength,
223 unsigned int pFlags,
224 const char* pHint,
225 const aiPropertyStore* props)
226{
227 ai_assert( NULL != pBuffer );
228 ai_assert( 0 != pLength );
229
230 const aiScene* scene = NULL;
231 ASSIMP_BEGIN_EXCEPTION_REGION();
232
233 // create an Importer for this file
234 Assimp::Importer* imp = new Assimp::Importer();
235
236 // copy properties
237 if(props) {
238 const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
239 ImporterPimpl* pimpl = imp->Pimpl();
240 pimpl->mIntProperties = pp->ints;
241 pimpl->mFloatProperties = pp->floats;
242 pimpl->mStringProperties = pp->strings;
243 pimpl->mMatrixProperties = pp->matrices;
244 }
245
246 // and have it read the file from the memory buffer
247 scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint);
248
249 // if succeeded, store the importer in the scene and keep it alive
250 if( scene) {
251 ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
252 priv->mOrigImporter = imp;
253 }
254 else {
255 // if failed, extract error code and destroy the import
256 gLastErrorString = imp->GetErrorString();
257 delete imp;
258 }
259 // return imported data. If the import failed the pointer is NULL anyways
260 ASSIMP_END_EXCEPTION_REGION(const aiScene*);
261 return scene;
262}
263
264// ------------------------------------------------------------------------------------------------
265// Releases all resources associated with the given import process.
266void aiReleaseImport( const aiScene* pScene)
267{
268 if (!pScene) {
269 return;
270 }
271
272 ASSIMP_BEGIN_EXCEPTION_REGION();
273
274 // find the importer associated with this data
275 const ScenePrivateData* priv = ScenePriv(pScene);
276 if( !priv || !priv->mOrigImporter) {
277 delete pScene;
278 }
279 else {
280 // deleting the Importer also deletes the scene
281 // Note: the reason that this is not written as 'delete priv->mOrigImporter'
282 // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339)
283 Importer* importer = priv->mOrigImporter;
284 delete importer;
285 }
286
287 ASSIMP_END_EXCEPTION_REGION(void);
288}
289
290// ------------------------------------------------------------------------------------------------
291ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene,
292 unsigned int pFlags)
293{
294 const aiScene* sc = NULL;
295
296
297 ASSIMP_BEGIN_EXCEPTION_REGION();
298
299 // find the importer associated with this data
300 const ScenePrivateData* priv = ScenePriv(pScene);
301 if( !priv || !priv->mOrigImporter) {
302 ReportSceneNotFoundError();
303 return NULL;
304 }
305
306 sc = priv->mOrigImporter->ApplyPostProcessing(pFlags);
307
308 if (!sc) {
309 aiReleaseImport(pScene);
310 return NULL;
311 }
312
313 ASSIMP_END_EXCEPTION_REGION(const aiScene*);
314 return sc;
315}
316
317// ------------------------------------------------------------------------------------------------
318ASSIMP_API const aiScene *aiApplyCustomizedPostProcessing( const aiScene *scene,
319 BaseProcess* process,
320 bool requestValidation ) {
321 const aiScene* sc( NULL );
322
323 ASSIMP_BEGIN_EXCEPTION_REGION();
324
325 // find the importer associated with this data
326 const ScenePrivateData* priv = ScenePriv( scene );
327 if ( NULL == priv || NULL == priv->mOrigImporter ) {
328 ReportSceneNotFoundError();
329 return NULL;
330 }
331
332 sc = priv->mOrigImporter->ApplyCustomizedPostProcessing( process, requestValidation );
333
334 if ( !sc ) {
335 aiReleaseImport( scene );
336 return NULL;
337 }
338
339 ASSIMP_END_EXCEPTION_REGION( const aiScene* );
340
341 return sc;
342}
343
344// ------------------------------------------------------------------------------------------------
345void CallbackToLogRedirector (const char* msg, char* dt)
346{
347 ai_assert( NULL != msg );
348 ai_assert( NULL != dt );
349 LogStream* s = (LogStream*)dt;
350
351 s->write(msg);
352}
353
354// ------------------------------------------------------------------------------------------------
355ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file)
356{
357 aiLogStream sout;
358
359 ASSIMP_BEGIN_EXCEPTION_REGION();
360 LogStream* stream = LogStream::createDefaultStream(pStream,file);
361 if (!stream) {
362 sout.callback = NULL;
363 sout.user = NULL;
364 }
365 else {
366 sout.callback = &CallbackToLogRedirector;
367 sout.user = (char*)stream;
368 }
369 gPredefinedStreams.push_back(stream);
370 ASSIMP_END_EXCEPTION_REGION(aiLogStream);
371 return sout;
372}
373
374// ------------------------------------------------------------------------------------------------
375ASSIMP_API void aiAttachLogStream( const aiLogStream* stream )
376{
377 ASSIMP_BEGIN_EXCEPTION_REGION();
378
379#ifndef ASSIMP_BUILD_SINGLETHREADED
380 std::lock_guard<std::mutex> lock(gLogStreamMutex);
381#endif
382
383 LogStream* lg = new LogToCallbackRedirector(*stream);
384 gActiveLogStreams[*stream] = lg;
385
386 if (DefaultLogger::isNullLogger()) {
387 DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
388 }
389 DefaultLogger::get()->attachStream(lg);
390 ASSIMP_END_EXCEPTION_REGION(void);
391}
392
393// ------------------------------------------------------------------------------------------------
394ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
395{
396 ASSIMP_BEGIN_EXCEPTION_REGION();
397
398#ifndef ASSIMP_BUILD_SINGLETHREADED
399 std::lock_guard<std::mutex> lock(gLogStreamMutex);
400#endif
401 // find the log-stream associated with this data
402 LogStreamMap::iterator it = gActiveLogStreams.find( *stream);
403 // it should be there... else the user is playing fools with us
404 if( it == gActiveLogStreams.end()) {
405 return AI_FAILURE;
406 }
407 DefaultLogger::get()->detatchStream( it->second );
408 delete it->second;
409
410 gActiveLogStreams.erase( it);
411
412 if (gActiveLogStreams.empty()) {
413 DefaultLogger::kill();
414 }
415 ASSIMP_END_EXCEPTION_REGION(aiReturn);
416 return AI_SUCCESS;
417}
418
419// ------------------------------------------------------------------------------------------------
420ASSIMP_API void aiDetachAllLogStreams(void)
421{
422 ASSIMP_BEGIN_EXCEPTION_REGION();
423#ifndef ASSIMP_BUILD_SINGLETHREADED
424 std::lock_guard<std::mutex> lock(gLogStreamMutex);
425#endif
426 Logger *logger( DefaultLogger::get() );
427 if ( NULL == logger ) {
428 return;
429 }
430
431 for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
432 logger->detatchStream( it->second );
433 delete it->second;
434 }
435 gActiveLogStreams.clear();
436 DefaultLogger::kill();
437
438 ASSIMP_END_EXCEPTION_REGION(void);
439}
440
441// ------------------------------------------------------------------------------------------------
442ASSIMP_API void aiEnableVerboseLogging(aiBool d)
443{
444 if (!DefaultLogger::isNullLogger()) {
445 DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
446 }
447 gVerboseLogging = d;
448}
449
450// ------------------------------------------------------------------------------------------------
451// Returns the error text of the last failed import process.
452const char* aiGetErrorString()
453{
454 return gLastErrorString.c_str();
455}
456
457// -----------------------------------------------------------------------------------------------
458// Return the description of a importer given its index
459const aiImporterDesc* aiGetImportFormatDescription( size_t pIndex)
460{
461 return Importer().GetImporterInfo(pIndex);
462}
463
464// -----------------------------------------------------------------------------------------------
465// Return the number of importers
466size_t aiGetImportFormatCount(void)
467{
468 return Importer().GetImporterCount();
469}
470
471// ------------------------------------------------------------------------------------------------
472// Returns the error text of the last failed import process.
473aiBool aiIsExtensionSupported(const char* szExtension)
474{
475 ai_assert(NULL != szExtension);
476 aiBool candoit=AI_FALSE;
477 ASSIMP_BEGIN_EXCEPTION_REGION();
478
479 // FIXME: no need to create a temporary Importer instance just for that ..
480 Assimp::Importer tmp;
481 candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE;
482
483 ASSIMP_END_EXCEPTION_REGION(aiBool);
484 return candoit;
485}
486
487// ------------------------------------------------------------------------------------------------
488// Get a list of all file extensions supported by ASSIMP
489void aiGetExtensionList(aiString* szOut)
490{
491 ai_assert(NULL != szOut);
492 ASSIMP_BEGIN_EXCEPTION_REGION();
493
494 // FIXME: no need to create a temporary Importer instance just for that ..
495 Assimp::Importer tmp;
496 tmp.GetExtensionList(*szOut);
497
498 ASSIMP_END_EXCEPTION_REGION(void);
499}
500
501// ------------------------------------------------------------------------------------------------
502// Get the memory requirements for a particular import.
503void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
504 C_STRUCT aiMemoryInfo* in)
505{
506 ASSIMP_BEGIN_EXCEPTION_REGION();
507
508 // find the importer associated with this data
509 const ScenePrivateData* priv = ScenePriv(pIn);
510 if( !priv || !priv->mOrigImporter) {
511 ReportSceneNotFoundError();
512 return;
513 }
514
515 return priv->mOrigImporter->GetMemoryRequirements(*in);
516 ASSIMP_END_EXCEPTION_REGION(void);
517}
518
519// ------------------------------------------------------------------------------------------------
520ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void)
521{
522 return reinterpret_cast<aiPropertyStore*>( new PropertyMap() );
523}
524
525// ------------------------------------------------------------------------------------------------
526ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p)
527{
528 delete reinterpret_cast<PropertyMap*>(p);
529}
530
531// ------------------------------------------------------------------------------------------------
532// Importer::SetPropertyInteger
533ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value)
534{
535 ASSIMP_BEGIN_EXCEPTION_REGION();
536 PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
537 SetGenericProperty<int>(pp->ints,szName,value);
538 ASSIMP_END_EXCEPTION_REGION(void);
539}
540
541// ------------------------------------------------------------------------------------------------
542// Importer::SetPropertyFloat
543ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, ai_real value)
544{
545 ASSIMP_BEGIN_EXCEPTION_REGION();
546 PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
547 SetGenericProperty<ai_real>(pp->floats,szName,value);
548 ASSIMP_END_EXCEPTION_REGION(void);
549}
550
551// ------------------------------------------------------------------------------------------------
552// Importer::SetPropertyString
553ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName,
554 const C_STRUCT aiString* st)
555{
556 if (!st) {
557 return;
558 }
559 ASSIMP_BEGIN_EXCEPTION_REGION();
560 PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
561 SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()));
562 ASSIMP_END_EXCEPTION_REGION(void);
563}
564
565// ------------------------------------------------------------------------------------------------
566// Importer::SetPropertyMatrix
567ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName,
568 const C_STRUCT aiMatrix4x4* mat)
569{
570 if (!mat) {
571 return;
572 }
573 ASSIMP_BEGIN_EXCEPTION_REGION();
574 PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
575 SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat);
576 ASSIMP_END_EXCEPTION_REGION(void);
577}
578
579// ------------------------------------------------------------------------------------------------
580// Rotation matrix to quaternion
581ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)
582{
583 ai_assert( NULL != quat );
584 ai_assert( NULL != mat );
585 *quat = aiQuaternion(*mat);
586}
587
588// ------------------------------------------------------------------------------------------------
589// Matrix decomposition
590ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling,
591 aiQuaternion* rotation,
592 aiVector3D* position)
593{
594 ai_assert( NULL != rotation );
595 ai_assert( NULL != position );
596 ai_assert( NULL != scaling );
597 ai_assert( NULL != mat );
598 mat->Decompose(*scaling,*rotation,*position);
599}
600
601// ------------------------------------------------------------------------------------------------
602// Matrix transpose
603ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat)
604{
605 ai_assert(NULL != mat);
606 mat->Transpose();
607}
608
609// ------------------------------------------------------------------------------------------------
610ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat)
611{
612 ai_assert(NULL != mat);
613 mat->Transpose();
614}
615
616// ------------------------------------------------------------------------------------------------
617// Vector transformation
618ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec,
619 const aiMatrix3x3* mat)
620{
621 ai_assert( NULL != mat );
622 ai_assert( NULL != vec);
623 *vec *= (*mat);
624}
625
626// ------------------------------------------------------------------------------------------------
627ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec,
628 const aiMatrix4x4* mat)
629{
630 ai_assert( NULL != mat );
631 ai_assert( NULL != vec );
632
633 *vec *= (*mat);
634}
635
636// ------------------------------------------------------------------------------------------------
637// Matrix multiplication
638ASSIMP_API void aiMultiplyMatrix4(
639 aiMatrix4x4* dst,
640 const aiMatrix4x4* src)
641{
642 ai_assert( NULL != dst );
643 ai_assert( NULL != src );
644 *dst = (*dst) * (*src);
645}
646
647// ------------------------------------------------------------------------------------------------
648ASSIMP_API void aiMultiplyMatrix3(
649 aiMatrix3x3* dst,
650 const aiMatrix3x3* src)
651{
652 ai_assert( NULL != dst );
653 ai_assert( NULL != src );
654 *dst = (*dst) * (*src);
655}
656
657// ------------------------------------------------------------------------------------------------
658// Matrix identity
659ASSIMP_API void aiIdentityMatrix3(
660 aiMatrix3x3* mat)
661{
662 ai_assert(NULL != mat);
663 *mat = aiMatrix3x3();
664}
665
666// ------------------------------------------------------------------------------------------------
667ASSIMP_API void aiIdentityMatrix4(
668 aiMatrix4x4* mat)
669{
670 ai_assert(NULL != mat);
671 *mat = aiMatrix4x4();
672}
673
674// ------------------------------------------------------------------------------------------------
675ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension ) {
676 if( NULL == extension ) {
677 return NULL;
678 }
679 const aiImporterDesc *desc( NULL );
680 std::vector< BaseImporter* > out;
681 GetImporterInstanceList( out );
682 for( size_t i = 0; i < out.size(); ++i ) {
683 if( 0 == strncmp( out[ i ]->GetInfo()->mFileExtensions, extension, strlen( extension ) ) ) {
684 desc = out[ i ]->GetInfo();
685 break;
686 }
687 }
688
689 DeleteImporterInstanceList(out);
690
691 return desc;
692}
693
694// ------------------------------------------------------------------------------------------------
695