Coverage Report

Created: 2025-08-03 06:54

/src/assimp/code/Common/BaseImporter.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
---------------------------------------------------------------------------
3
Open Asset Import Library (assimp)
4
---------------------------------------------------------------------------
5
6
Copyright (c) 2006-2025, assimp team
7
8
All rights reserved.
9
10
Redistribution and use of this software in source and binary forms,
11
with or without modification, are permitted provided that the following
12
conditions are met:
13
14
* Redistributions of source code must retain the above
15
  copyright notice, this list of conditions and the
16
  following disclaimer.
17
18
* Redistributions in binary form must reproduce the above
19
  copyright notice, this list of conditions and the
20
  following disclaimer in the documentation and/or other
21
  materials provided with the distribution.
22
23
* Neither the name of the assimp team, nor the names of its
24
  contributors may be used to endorse or promote products
25
  derived from this software without specific prior
26
  written permission of the assimp team.
27
28
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
---------------------------------------------------------------------------
40
*/
41
42
/** @file  BaseImporter.cpp
43
 *  @brief Implementation of BaseImporter
44
 */
45
46
#include "FileSystemFilter.h"
47
#include "Importer.h"
48
#include <assimp/BaseImporter.h>
49
#include <assimp/ByteSwapper.h>
50
#include <assimp/ParsingUtils.h>
51
#include <assimp/importerdesc.h>
52
#include <assimp/postprocess.h>
53
#include <assimp/scene.h>
54
#include <assimp/Importer.hpp>
55
56
#include <cctype>
57
#include <ios>
58
#include <list>
59
#include <memory>
60
#include <sstream>
61
62
namespace {
63
// Checks whether the passed string is a gcs version.
64
0
bool IsGcsVersion(const std::string &s) {
65
0
    if (s.empty()) return false;
66
0
    return std::all_of(s.cbegin(), s.cend(), [](const char c) {
67
        // gcs only permits numeric characters.
68
0
        return std::isdigit(static_cast<int>(c));
69
0
    });
70
0
}
71
72
// Removes a possible version hash from a filename, as found for example in
73
// gcs uris (e.g. `gs://bucket/model.glb#1234`), see also
74
// https://github.com/GoogleCloudPlatform/gsutil/blob/c80f329bc3c4011236c78ce8910988773b2606cb/gslib/storage_url.py#L39.
75
21.4k
std::string StripVersionHash(const std::string &filename) {
76
21.4k
    const std::string::size_type pos = filename.find_last_of('#');
77
    // Only strip if the hash is behind a possible file extension and the part
78
    // behind the hash is a version string.
79
21.4k
    if (pos != std::string::npos && pos > filename.find_last_of('.') &&
80
21.4k
        IsGcsVersion(filename.substr(pos + 1))) {
81
0
        return filename.substr(0, pos);
82
0
    }
83
21.4k
    return filename;
84
21.4k
}
85
}  // namespace
86
87
using namespace Assimp;
88
89
// ------------------------------------------------------------------------------------------------
90
// Constructor to be privately used by Importer
91
BaseImporter::BaseImporter() AI_NO_EXCEPT
92
19.8k
        : m_progress() {
93
    // empty
94
19.8k
}
95
96
184
void BaseImporter::UpdateImporterScale(Importer *pImp) {
97
184
    ai_assert(pImp != nullptr);
98
184
    ai_assert(importerScale != 0.0);
99
184
    ai_assert(fileScale != 0.0);
100
101
184
    double activeScale = importerScale * fileScale;
102
103
    // Set active scaling
104
184
    pImp->SetPropertyFloat(AI_CONFIG_APP_SCALE_KEY, static_cast<float>(activeScale));
105
106
184
    ASSIMP_LOG_DEBUG("UpdateImporterScale scale set: ", activeScale);
107
184
}
108
109
// ------------------------------------------------------------------------------------------------
110
// Imports the given file and returns the imported data.
111
354
aiScene *BaseImporter::ReadFile(Importer *pImp, const std::string &pFile, IOSystem *pIOHandler) {
112
113
354
    m_progress = pImp->GetProgressHandler();
114
354
    if (nullptr == m_progress) {
115
0
        return nullptr;
116
0
    }
117
118
354
    ai_assert(m_progress);
119
120
    // Gather configuration properties for this run
121
354
    SetupProperties(pImp);
122
123
    // Construct a file system filter to improve our success ratio at reading external files
124
354
    FileSystemFilter filter(pFile, pIOHandler);
125
126
    // create a scene object to hold the data
127
354
    std::unique_ptr<aiScene> sc(new aiScene());
128
129
    // dispatch importing
130
354
    try {
131
354
        InternReadFile(pFile, sc.get(), &filter);
132
133
        // Calculate import scale hook - required because pImp not available anywhere else
134
        // passes scale into ScaleProcess
135
354
        UpdateImporterScale(pImp);
136
137
354
    } catch( const std::exception &err ) {
138
        // extract error description
139
170
        m_ErrorText = err.what();
140
170
        ASSIMP_LOG_ERROR(err.what());
141
170
        m_Exception = std::current_exception();
142
170
        return nullptr;
143
170
    }
144
145
    // return what we gathered from the import.
146
184
    return sc.release();
147
354
}
148
149
// ------------------------------------------------------------------------------------------------
150
160
void BaseImporter::SetupProperties(const Importer *) {
151
    // the default implementation does nothing
152
160
}
153
154
// ------------------------------------------------------------------------------------------------
155
20.2k
void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
156
20.2k
    const aiImporterDesc *desc = GetInfo();
157
20.2k
    ai_assert(desc != nullptr);
158
159
20.2k
    const char *ext = desc->mFileExtensions;
160
20.2k
    ai_assert(ext != nullptr);
161
162
20.2k
    const char *last = ext;
163
141k
    do {
164
141k
        if (!*ext || *ext == ' ') {
165
31.6k
            extensions.insert(std::string(last, ext - last));
166
31.6k
            ai_assert(ext - last > 0);
167
31.6k
            last = ext;
168
43.0k
            while (*last == ' ') {
169
11.3k
                ++last;
170
11.3k
            }
171
31.6k
        }
172
141k
    } while (*ext++);
173
20.2k
}
174
175
// ------------------------------------------------------------------------------------------------
176
/*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem *pIOHandler,
177
        const std::string &pFile,
178
        const char **tokens,
179
        std::size_t numTokens,
180
        unsigned int searchBytes /* = 200 */,
181
        bool tokensSol /* false */,
182
3.70k
        bool noGraphBeforeTokens /* false */) {
183
3.70k
    ai_assert(nullptr != tokens);
184
3.70k
    ai_assert(0 != numTokens);
185
3.70k
    ai_assert(0 != searchBytes);
186
187
3.70k
    if (nullptr == pIOHandler) {
188
0
        return false;
189
0
    }
190
191
3.70k
    std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile));
192
3.70k
    if (pStream) {
193
        // read 200 characters from the file
194
3.70k
        std::unique_ptr<char[]> _buffer(new char[searchBytes + 1 /* for the '\0' */]);
195
3.70k
        char *buffer(_buffer.get());
196
3.70k
        const size_t read(pStream->Read(buffer, 1, searchBytes));
197
3.70k
        if (0 == read) {
198
0
            return false;
199
0
        }
200
201
667k
        for (size_t i = 0; i < read; ++i) {
202
663k
            buffer[i] = static_cast<char>(::tolower((unsigned char)buffer[i]));
203
663k
        }
204
205
        // It is not a proper handling of unicode files here ...
206
        // ehm ... but it works in most cases.
207
3.70k
        char *cur = buffer, *cur2 = buffer, *end = &buffer[read];
208
667k
        while (cur != end) {
209
663k
            if (*cur) {
210
592k
                *cur2++ = *cur;
211
592k
            }
212
663k
            ++cur;
213
663k
        }
214
3.70k
        *cur2 = '\0';
215
216
3.70k
        std::string token;
217
10.8k
        for (unsigned int i = 0; i < numTokens; ++i) {
218
7.41k
            ai_assert(nullptr != tokens[i]);
219
7.41k
            const size_t len(strlen(tokens[i]));
220
7.41k
            token.clear();
221
7.41k
            const char *ptr(tokens[i]);
222
52.0k
            for (size_t tokIdx = 0; tokIdx < len; ++tokIdx) {
223
44.5k
                token.push_back(static_cast<char>(tolower(static_cast<unsigned char>(*ptr))));
224
44.5k
                ++ptr;
225
44.5k
            }
226
7.41k
            const char *r = strstr(buffer, token.c_str());
227
7.41k
            if (!r) {
228
7.15k
                continue;
229
7.15k
            }
230
            // We need to make sure that we didn't accidentally identify the end of another token as our token,
231
            // e.g. in a previous version the "gltf " present in some gltf files was detected as "f ", or a
232
            // Blender-exported glb file containing "Khronos glTF Blender I/O " was detected as "o "
233
260
            if (noGraphBeforeTokens && (r != buffer && isgraph(static_cast<unsigned char>(r[-1])))) {
234
23
                continue;
235
23
            }
236
            // We got a match, either we don't care where it is, or it happens to
237
            // be in the beginning of the file / line
238
237
            if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
239
237
                ASSIMP_LOG_DEBUG("Found positive match for header keyword: ", tokens[i]);
240
237
                return true;
241
237
            }
242
237
        }
243
3.70k
    }
244
245
3.47k
    return false;
246
3.70k
}
247
248
// ------------------------------------------------------------------------------------------------
249
// Simple check for file extension
250
/*static*/ bool BaseImporter::SimpleExtensionCheck(const std::string &pFile,
251
        const char *ext0,
252
        const char *ext1,
253
        const char *ext2,
254
938
        const char *ext3) {
255
938
    std::set<std::string> extensions;
256
3.75k
    for (const char* ext : {ext0, ext1, ext2, ext3}) {
257
3.75k
        if (ext == nullptr) continue;
258
1.51k
        extensions.emplace(ext);
259
1.51k
    }
260
938
    return HasExtension(pFile, extensions);
261
938
}
262
263
// ------------------------------------------------------------------------------------------------
264
// Check for file extension
265
21.1k
/*static*/ bool BaseImporter::HasExtension(const std::string &pFile, const std::set<std::string> &extensions) {
266
21.1k
    const std::string file = StripVersionHash(pFile);
267
    // CAUTION: Do not just search for the extension!
268
    // GetExtension() returns the part after the *last* dot, but some extensions
269
    // have dots inside them, e.g. ogre.mesh.xml. Compare the entire end of the
270
    // string.
271
33.1k
    for (const std::string& ext : extensions) {
272
        // Yay for C++<20 not having std::string::ends_with()
273
33.1k
        const std::string dotExt = "." + ext;
274
33.1k
        if (dotExt.length() > file.length()) continue;
275
        // Possible optimization: Fetch the lowercase filename!
276
33.1k
        if (0 == ASSIMP_stricmp(file.c_str() + file.length() - dotExt.length(), dotExt.c_str())) {
277
36
            return true;
278
36
        }
279
33.1k
    }
280
21.1k
    return false;
281
21.1k
}
282
283
// ------------------------------------------------------------------------------------------------
284
// Get file extension from path
285
295
std::string BaseImporter::GetExtension(const std::string &pFile) {
286
295
    const std::string file = StripVersionHash(pFile);
287
295
    std::string::size_type pos = file.find_last_of('.');
288
289
    // no file extension at all
290
295
    if (pos == std::string::npos) {
291
3
        return std::string();
292
3
    }
293
294
    // thanks to Andy Maloney for the hint
295
292
    std::string ret = file.substr(pos + 1);
296
292
    ret = ai_tolower(ret);
297
298
292
    return ret;
299
295
}
300
301
302
// ------------------------------------------------------------------------------------------------
303
// Check for magic bytes at the beginning of the file.
304
/* static */ bool BaseImporter::CheckMagicToken(IOSystem *pIOHandler, const std::string &pFile,
305
2.56k
        const void *_magic, std::size_t num, unsigned int offset, unsigned int size) {
306
2.56k
    ai_assert(size <= 16);
307
2.56k
    ai_assert(_magic);
308
309
2.56k
    if (!pIOHandler) {
310
0
        return false;
311
0
    }
312
2.56k
    const char *magic = reinterpret_cast<const char *>(_magic);
313
2.56k
    std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile));
314
2.56k
    if (pStream) {
315
316
        // skip to offset
317
2.56k
        pStream->Seek(offset, aiOrigin_SET);
318
319
        // read 'size' characters from the file
320
2.56k
        union {
321
2.56k
            char data[16];
322
2.56k
            uint16_t data_u16[8];
323
2.56k
            uint32_t data_u32[4];
324
2.56k
        };
325
2.56k
        if (size != pStream->Read(data, 1, size)) {
326
0
            return false;
327
0
        }
328
329
8.22k
        for (unsigned int i = 0; i < num; ++i) {
330
            // also check against big endian versions of tokens with size 2,4
331
            // that's just for convenience, the chance that we cause conflicts
332
            // is quite low and it can save some lines and prevent nasty bugs
333
5.74k
            if (2 == size) {
334
568
                uint16_t magic_u16;
335
568
                memcpy(&magic_u16, magic, 2);
336
568
                if (data_u16[0] == magic_u16 || data_u16[0] == ByteSwap::Swapped(magic_u16)) {
337
2
                    return true;
338
2
                }
339
5.17k
            } else if (4 == size) {
340
5.17k
                uint32_t magic_u32;
341
5.17k
                memcpy(&magic_u32, magic, 4);
342
5.17k
                if (data_u32[0] == magic_u32 || data_u32[0] == ByteSwap::Swapped(magic_u32)) {
343
79
                    return true;
344
79
                }
345
5.17k
            } else {
346
                // any length ... just compare
347
0
                if (!memcmp(magic, data, size)) {
348
0
                    return true;
349
0
                }
350
0
            }
351
5.66k
            magic += size;
352
5.66k
        }
353
2.56k
    }
354
2.48k
    return false;
355
2.56k
}
356
357
#include "utf8.h"
358
359
// ------------------------------------------------------------------------------------------------
360
// Convert to UTF8 data
361
2.87k
void BaseImporter::ConvertToUTF8(std::vector<char> &data) {
362
    //ConversionResult result;
363
2.87k
    if (data.size() < 8) {
364
0
        throw DeadlyImportError("File is too small");
365
0
    }
366
367
    // UTF 8 with BOM
368
2.87k
    if ((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
369
0
        ASSIMP_LOG_DEBUG("Found UTF-8 BOM ...");
370
371
0
        std::copy(data.begin() + 3, data.end(), data.begin());
372
0
        data.resize(data.size() - 3);
373
0
        return;
374
0
    }
375
376
    // UTF 32 BE with BOM
377
2.87k
    if (*((uint32_t *)&data.front()) == 0xFFFE0000) {
378
0
        if (data.size() % sizeof(uint32_t) != 0) {
379
0
            throw DeadlyImportError("Not valid UTF-32 BE");
380
0
        }
381
382
        // swap the endianness ..
383
0
        for (uint32_t *p = (uint32_t *)&data.front(), *end = (uint32_t *)&data.back(); p <= end; ++p) {
384
0
            AI_SWAP4P(p);
385
0
        }
386
0
    }
387
388
    // UTF 32 LE with BOM
389
2.87k
    if (*((uint32_t *)&data.front()) == 0x0000FFFE) {
390
0
        if (data.size() % sizeof(uint32_t) != 0) {
391
0
            throw DeadlyImportError("Not valid UTF-32 LE");
392
0
        }
393
0
        ASSIMP_LOG_DEBUG("Found UTF-32 BOM ...");
394
395
0
        std::vector<char> output;
396
0
        auto *ptr = (uint32_t *)&data[0];
397
0
        uint32_t *end = ptr + (data.size() / sizeof(uint32_t)) + 1;
398
0
        utf8::utf32to8(ptr, end, back_inserter(output));
399
0
        return;
400
0
    }
401
402
    // UTF 16 BE with BOM
403
2.87k
    if (*((uint16_t *)&data.front()) == 0xFFFE) {
404
        // Check to ensure no overflow can happen
405
0
        if (data.size() % sizeof(uint16_t) != 0) {
406
0
            throw DeadlyImportError("Not valid UTF-16 BE");
407
0
        }
408
        // swap the endianness ..
409
0
        for (uint16_t *p = (uint16_t *)&data.front(), *end = (uint16_t *)&data.back(); p <= end; ++p) {
410
0
            ByteSwap::Swap2(p);
411
0
        }
412
0
    }
413
414
    // UTF 16 LE with BOM
415
2.87k
    if (*((uint16_t *)&data.front()) == 0xFEFF) {
416
0
        if (data.size() % sizeof(uint16_t) != 0) {
417
0
            throw DeadlyImportError("Not valid UTF-16 LE");
418
0
        }
419
0
        ASSIMP_LOG_DEBUG("Found UTF-16 BOM ...");
420
421
0
        std::vector<unsigned char> output;
422
0
        utf8::utf16to8(data.begin(), data.end(), back_inserter(output));
423
0
        return;
424
0
    }
425
2.87k
}
426
427
// ------------------------------------------------------------------------------------------------
428
// Convert to UTF8 data to ISO-8859-1
429
0
void BaseImporter::ConvertUTF8toISO8859_1(std::string &data) {
430
0
    size_t size = data.size();
431
0
    size_t i = 0, j = 0;
432
433
0
    while (i < size) {
434
0
        if ((unsigned char)data[i] < (size_t)0x80) {
435
0
            data[j] = data[i];
436
0
        } else if (i < size - 1) {
437
0
            if ((unsigned char)data[i] == 0xC2) {
438
0
                data[j] = data[++i];
439
0
            } else if ((unsigned char)data[i] == 0xC3) {
440
0
                data[j] = ((unsigned char)data[++i] + 0x40);
441
0
            } else {
442
0
                std::stringstream stream;
443
0
                stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
444
0
                ASSIMP_LOG_ERROR(stream.str());
445
446
0
                data[j++] = data[i++];
447
0
                data[j] = data[i];
448
0
            }
449
0
        } else {
450
0
            ASSIMP_LOG_ERROR("UTF8 code but only one character remaining");
451
452
0
            data[j] = data[i];
453
0
        }
454
455
0
        i++;
456
0
        j++;
457
0
    }
458
459
0
    data.resize(j);
460
0
}
461
462
// ------------------------------------------------------------------------------------------------
463
void BaseImporter::TextFileToBuffer(IOStream *stream,
464
        std::vector<char> &data,
465
2.87k
        TextFileMode mode) {
466
2.87k
    ai_assert(nullptr != stream);
467
468
2.87k
    const size_t fileSize = stream->FileSize();
469
2.87k
    if (mode == FORBID_EMPTY) {
470
557
        if (!fileSize) {
471
0
            throw DeadlyImportError("File is empty");
472
0
        }
473
557
    }
474
475
2.87k
    data.reserve(fileSize + 1);
476
2.87k
    data.resize(fileSize);
477
2.87k
    if (fileSize > 0) {
478
2.87k
        if (fileSize != stream->Read(&data[0], 1, fileSize)) {
479
0
            throw DeadlyImportError("File read error");
480
0
        }
481
482
2.87k
        ConvertToUTF8(data);
483
2.87k
    }
484
485
    // append a binary zero to simplify string parsing
486
2.87k
    data.push_back(0);
487
2.87k
}
488
489
// ------------------------------------------------------------------------------------------------
490
namespace Assimp {
491
// Represents an import request
492
struct LoadRequest {
493
    LoadRequest(const std::string &_file, unsigned int _flags, const BatchLoader::PropertyMap *_map, unsigned int _id) :
494
749
            file(_file),
495
749
            flags(_flags),
496
749
            refCnt(1),
497
749
            scene(nullptr),
498
749
            loaded(false),
499
749
            id(_id) {
500
749
        if (_map) {
501
245
            map = *_map;
502
245
        }
503
749
    }
504
505
0
    bool operator==(const std::string &f) const {
506
0
        return file == f;
507
0
    }
508
509
    const std::string file;
510
    unsigned int flags;
511
    unsigned int refCnt;
512
    aiScene *scene;
513
    bool loaded;
514
    BatchLoader::PropertyMap map;
515
    unsigned int id;
516
};
517
} // namespace Assimp
518
519
// ------------------------------------------------------------------------------------------------
520
// BatchLoader::pimpl data structure
521
struct Assimp::BatchData {
522
    BatchData(IOSystem *pIO, bool validate) :
523
76
            pIOSystem(pIO), pImporter(nullptr), next_id(0xffff), validate(validate) {
524
76
        ai_assert(nullptr != pIO);
525
526
76
        pImporter = new Importer();
527
76
        pImporter->SetIOHandler(pIO);
528
76
    }
529
530
76
    ~BatchData() {
531
76
        pImporter->SetIOHandler(nullptr); /* get pointer back into our possession */
532
76
        delete pImporter;
533
76
    }
534
535
    // IO system to be used for all imports
536
    IOSystem *pIOSystem;
537
538
    // Importer used to load all meshes
539
    Importer *pImporter;
540
541
    // List of all imports
542
    std::list<LoadRequest> requests;
543
544
    // Base path
545
    std::string pathBase;
546
547
    // Id for next item
548
    unsigned int next_id;
549
550
    // Validation enabled state
551
    bool validate;
552
};
553
554
typedef std::list<LoadRequest>::iterator LoadReqIt;
555
556
// ------------------------------------------------------------------------------------------------
557
76
BatchLoader::BatchLoader(IOSystem *pIO, bool validate) {
558
76
    ai_assert(nullptr != pIO);
559
560
76
    m_data = new BatchData(pIO, validate);
561
76
}
562
563
// ------------------------------------------------------------------------------------------------
564
76
BatchLoader::~BatchLoader() {
565
    // delete all scenes what have not been polled by the user
566
546
    for (LoadReqIt it = m_data->requests.begin(); it != m_data->requests.end(); ++it) {
567
470
        delete (*it).scene;
568
470
    }
569
76
    delete m_data;
570
76
}
571
572
// ------------------------------------------------------------------------------------------------
573
0
void BatchLoader::setValidation(bool enabled) {
574
0
    m_data->validate = enabled;
575
0
}
576
577
// ------------------------------------------------------------------------------------------------
578
0
bool BatchLoader::getValidation() const {
579
0
    return m_data->validate;
580
0
}
581
582
// ------------------------------------------------------------------------------------------------
583
unsigned int BatchLoader::AddLoadRequest(const std::string &file,
584
8.92k
        unsigned int steps /*= 0*/, const PropertyMap *map /*= nullptr*/) {
585
8.92k
    ai_assert(!file.empty());
586
587
    // check whether we have this loading request already
588
32.8k
    for (LoadReqIt it = m_data->requests.begin(); it != m_data->requests.end(); ++it) {
589
        // Call IOSystem's path comparison function here
590
32.0k
        if (m_data->pIOSystem->ComparePaths((*it).file, file)) {
591
8.20k
            if (map) {
592
1.73k
                if (!((*it).map == *map)) {
593
24
                    continue;
594
24
                }
595
6.46k
            } else if (!(*it).map.empty()) {
596
0
                continue;
597
0
            }
598
599
8.17k
            (*it).refCnt++;
600
8.17k
            return (*it).id;
601
8.20k
        }
602
32.0k
    }
603
604
    // no, we don't have it. So add it to the queue ...
605
749
    m_data->requests.emplace_back(file, steps, map, m_data->next_id);
606
749
    return m_data->next_id++;
607
8.92k
}
608
609
// ------------------------------------------------------------------------------------------------
610
2.70k
aiScene *BatchLoader::GetImport(unsigned int which) {
611
5.54k
    for (LoadReqIt it = m_data->requests.begin(); it != m_data->requests.end(); ++it) {
612
5.54k
        if ((*it).id == which && (*it).loaded) {
613
2.70k
            aiScene *sc = (*it).scene;
614
2.70k
            if (!(--(*it).refCnt)) {
615
279
                m_data->requests.erase(it);
616
279
            }
617
2.70k
            return sc;
618
2.70k
        }
619
5.54k
    }
620
0
    return nullptr;
621
2.70k
}
622
623
// ------------------------------------------------------------------------------------------------
624
25
void BatchLoader::LoadAll() {
625
    // no threaded implementation for the moment
626
306
    for (LoadReqIt it = m_data->requests.begin(); it != m_data->requests.end(); ++it) {
627
        // force validation in debug builds
628
281
        unsigned int pp = (*it).flags;
629
281
        if (m_data->validate) {
630
0
            pp |= aiProcess_ValidateDataStructure;
631
0
        }
632
633
        // setup config properties if necessary
634
281
        ImporterPimpl *pimpl = m_data->pImporter->Pimpl();
635
281
        pimpl->mFloatProperties = (*it).map.floats;
636
281
        pimpl->mIntProperties = (*it).map.ints;
637
281
        pimpl->mStringProperties = (*it).map.strings;
638
281
        pimpl->mMatrixProperties = (*it).map.matrices;
639
640
281
        if (!DefaultLogger::isNullLogger()) {
641
0
            ASSIMP_LOG_INFO("%%% BEGIN EXTERNAL FILE %%%");
642
0
            ASSIMP_LOG_INFO("File: ", (*it).file);
643
0
        }
644
281
        m_data->pImporter->ReadFile((*it).file, pp);
645
281
        (*it).scene = m_data->pImporter->GetOrphanedScene();
646
281
        (*it).loaded = true;
647
648
281
        ASSIMP_LOG_INFO("%%% END EXTERNAL FILE %%%");
649
281
    }
650
25
}