Coverage Report

Created: 2026-10-28 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/Assbin/AssbinLoader.cpp
Line
Count
Source
1
/*
2
---------------------------------------------------------------------------
3
Open Asset Import Library (assimp)
4
---------------------------------------------------------------------------
5
6
Copyright (c) 2006-2026, 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  AssbinLoader.cpp
43
 *  @brief Implementation of the .assbin importer class
44
 *
45
 *  see assbin_chunks.h
46
 */
47
48
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
49
50
// internal headers
51
#include "AssbinLoader.h"
52
#include "Common/assbin_chunks.h"
53
#include <assimp/MemoryIOWrapper.h>
54
#include <assimp/anim.h>
55
#include <assimp/importerdesc.h>
56
#include <assimp/mesh.h>
57
#include <assimp/scene.h>
58
59
#include <climits>
60
#include <cstdint>
61
#include <memory>
62
#include <vector>
63
64
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
65
#include <zlib.h>
66
#else
67
#include <contrib/zlib/zlib.h>
68
#endif
69
70
using namespace Assimp;
71
72
static constexpr aiImporterDesc desc = {
73
    "Assimp Binary Importer",
74
    "Gargaj / Conspiracy",
75
    "",
76
    "",
77
    aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour,
78
    0,
79
    0,
80
    0,
81
    0,
82
    "assbin"
83
};
84
85
// -----------------------------------------------------------------------------------
86
129k
const aiImporterDesc *AssbinImporter::GetInfo() const {
87
129k
    return &desc;
88
129k
}
89
90
// -----------------------------------------------------------------------------------
91
933
bool AssbinImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
92
933
    if (pIOHandler == nullptr) {
93
0
        return false;
94
0
    }
95
96
933
    IOStream *in = pIOHandler->Open(pFile);
97
933
    if (nullptr == in) {
98
0
        return false;
99
0
    }
100
101
933
    char s[32];
102
933
    const size_t read = in->Read(s, sizeof(char), 32);
103
104
933
    pIOHandler->Close(in);
105
106
933
    if (read < 19) {
107
0
      return false;
108
0
    }
109
110
933
    return strncmp(s, "ASSIMP.binary-dump.", 19) == 0;
111
933
}
112
113
// -----------------------------------------------------------------------------------
114
template <typename T>
115
0
T Read(IOStream *stream) {
116
0
    T t;
117
0
    size_t res = stream->Read(&t, sizeof(T), 1);
118
0
    if (res != 1) {
119
0
        throw DeadlyImportError("Unexpected EOF");
120
0
    }
121
0
    return t;
122
0
}
Unexecuted instantiation: float Read<float>(Assimp::IOStream*)
Unexecuted instantiation: unsigned int Read<unsigned int>(Assimp::IOStream*)
Unexecuted instantiation: double Read<double>(Assimp::IOStream*)
Unexecuted instantiation: unsigned short Read<unsigned short>(Assimp::IOStream*)
Unexecuted instantiation: bool Read<bool>(Assimp::IOStream*)
Unexecuted instantiation: int Read<int>(Assimp::IOStream*)
Unexecuted instantiation: unsigned long Read<unsigned long>(Assimp::IOStream*)
Unexecuted instantiation: aiColor3D Read<aiColor3D>(Assimp::IOStream*)
123
124
// -----------------------------------------------------------------------------------
125
0
void ReadBytes(IOStream *stream, void *out, size_t size, const char *what) {
126
0
    if (stream == nullptr) {
127
0
        throw DeadlyImportError("ASSBIN: Invalid stream");
128
0
    }
129
130
0
    if (size == 0) {
131
0
        return;
132
0
    }
133
134
0
    const size_t res = stream->Read(out, 1, size);
135
0
    if (res != size) {
136
0
        throw DeadlyImportError("ASSBIN: Unexpected EOF reading ", what);
137
0
    }
138
0
}
139
140
// -----------------------------------------------------------------------------------
141
template <>
142
0
aiVector3D Read<aiVector3D>(IOStream *stream) {
143
0
    aiVector3D v;
144
0
    v.x = Read<ai_real>(stream);
145
0
    v.y = Read<ai_real>(stream);
146
0
    v.z = Read<ai_real>(stream);
147
0
    return v;
148
0
}
149
150
// -----------------------------------------------------------------------------------
151
template <>
152
0
aiColor4D Read<aiColor4D>(IOStream *stream) {
153
0
    aiColor4D c;
154
0
    c.r = Read<ai_real>(stream);
155
0
    c.g = Read<ai_real>(stream);
156
0
    c.b = Read<ai_real>(stream);
157
0
    c.a = Read<ai_real>(stream);
158
0
    return c;
159
0
}
160
161
// -----------------------------------------------------------------------------------
162
template <>
163
0
aiQuaternion Read<aiQuaternion>(IOStream *stream) {
164
0
    aiQuaternion v;
165
0
    v.w = Read<ai_real>(stream);
166
0
    v.x = Read<ai_real>(stream);
167
0
    v.y = Read<ai_real>(stream);
168
0
    v.z = Read<ai_real>(stream);
169
0
    return v;
170
0
}
171
172
// -----------------------------------------------------------------------------------
173
template <>
174
0
aiString Read<aiString>(IOStream *stream) {
175
0
    aiString s;
176
0
    const ai_uint32 len = Read<ai_uint32>(stream);
177
0
    if (len >= AI_MAXLEN) {
178
0
        throw DeadlyImportError("ASSBIN: String length too large, potential buffer overflow attempt");
179
0
    }
180
0
    s.length = len;
181
0
    if (s.length > 0) {
182
0
        ReadBytes(stream, s.data, s.length, "string data");
183
0
    }
184
0
    s.data[s.length] = '\0';
185
186
0
    return s;
187
0
}
188
189
// -----------------------------------------------------------------------------------
190
template <>
191
0
aiVertexWeight Read<aiVertexWeight>(IOStream *stream) {
192
0
    aiVertexWeight w;
193
0
    w.mVertexId = Read<unsigned int>(stream);
194
0
    w.mWeight = Read<ai_real>(stream);
195
0
    return w;
196
0
}
197
198
// -----------------------------------------------------------------------------------
199
template <>
200
0
aiMatrix4x4 Read<aiMatrix4x4>(IOStream *stream) {
201
0
    aiMatrix4x4 m;
202
0
    for (unsigned int i = 0; i < 4; ++i) {
203
0
        for (unsigned int i2 = 0; i2 < 4; ++i2) {
204
0
            m[i][i2] = Read<ai_real>(stream);
205
0
        }
206
0
    }
207
0
    return m;
208
0
}
209
210
// -----------------------------------------------------------------------------------
211
template <>
212
0
aiVectorKey Read<aiVectorKey>(IOStream *stream) {
213
0
    aiVectorKey v;
214
0
    v.mTime = Read<double>(stream);
215
0
    v.mValue = Read<aiVector3D>(stream);
216
0
    return v;
217
0
}
218
219
// -----------------------------------------------------------------------------------
220
template <>
221
0
aiQuatKey Read<aiQuatKey>(IOStream *stream) {
222
0
    aiQuatKey v;
223
0
    v.mTime = Read<double>(stream);
224
0
    v.mValue = Read<aiQuaternion>(stream);
225
0
    return v;
226
0
}
227
228
// -----------------------------------------------------------------------------------
229
template <typename T>
230
0
void ReadArray(IOStream *stream, T *out, unsigned int size) {
231
0
    ai_assert(nullptr != stream);
232
0
    ai_assert(nullptr != out);
233
234
0
    for (unsigned int i = 0; i < size; i++) {
235
0
        out[i] = Read<T>(stream);
236
0
    }
237
0
}
Unexecuted instantiation: void ReadArray<unsigned int>(Assimp::IOStream*, unsigned int*, unsigned int)
Unexecuted instantiation: void ReadArray<aiVertexWeight>(Assimp::IOStream*, aiVertexWeight*, unsigned int)
Unexecuted instantiation: void ReadArray<aiVector3t<float> >(Assimp::IOStream*, aiVector3t<float>*, unsigned int)
Unexecuted instantiation: void ReadArray<aiColor4t<float> >(Assimp::IOStream*, aiColor4t<float>*, unsigned int)
Unexecuted instantiation: void ReadArray<aiVectorKey>(Assimp::IOStream*, aiVectorKey*, unsigned int)
Unexecuted instantiation: void ReadArray<aiQuatKey>(Assimp::IOStream*, aiQuatKey*, unsigned int)
238
239
// -----------------------------------------------------------------------------------
240
template <typename T>
241
0
void ReadBounds(IOStream *stream, T * /*p*/, unsigned int n) {
242
0
    if (stream == nullptr) {
243
0
        throw DeadlyImportError("ASSBIN: Invalid stream");
244
0
    }
245
0
    stream->Seek(sizeof(T) * n, aiOrigin_CUR);
246
0
}
Unexecuted instantiation: void ReadBounds<aiVertexWeight>(Assimp::IOStream*, aiVertexWeight*, unsigned int)
Unexecuted instantiation: void ReadBounds<aiVector3t<float> >(Assimp::IOStream*, aiVector3t<float>*, unsigned int)
Unexecuted instantiation: void ReadBounds<aiColor4t<float> >(Assimp::IOStream*, aiColor4t<float>*, unsigned int)
Unexecuted instantiation: void ReadBounds<aiVectorKey>(Assimp::IOStream*, aiVectorKey*, unsigned int)
Unexecuted instantiation: void ReadBounds<aiQuatKey>(Assimp::IOStream*, aiQuatKey*, unsigned int)
247
248
// -----------------------------------------------------------------------------------
249
0
void AssbinImporter::ReadBinaryNode(IOStream *stream, aiNode **onode, aiNode *parent) {
250
0
    if (stream == nullptr) {
251
0
        throw DeadlyImportError("ASSBIN: Invalid stream");
252
0
    }
253
254
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODE) {
255
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
256
0
    }
257
0
    /*uint32_t size =*/Read<uint32_t>(stream);
258
259
0
    auto node = std::make_unique<aiNode>();
260
261
0
    node->mName = Read<aiString>(stream);
262
0
    node->mTransformation = Read<aiMatrix4x4>(stream);
263
0
    unsigned numChildren = Read<unsigned int>(stream);
264
0
    unsigned numMeshes = Read<unsigned int>(stream);
265
0
    unsigned int nb_metadata = Read<unsigned int>(stream);
266
267
0
    if (numMeshes > AI_MAX_ALLOC(unsigned int)) {
268
0
        throw DeadlyImportError("Assbin: Too many meshes in node, would overflow");
269
0
    }
270
0
    if (numChildren > AI_MAX_ALLOC(aiNode *)) {
271
0
        throw DeadlyImportError("Assbin: Too many children in node, would overflow");
272
0
    }
273
0
    if (nb_metadata > AI_MAX_ALLOC(aiMetadataEntry)) {
274
0
        throw DeadlyImportError("Assbin: Too many metadata properties, would overflow");
275
0
    }
276
277
0
    if (parent != nullptr) {
278
0
        node->mParent = parent;
279
0
    }
280
281
0
    if (numMeshes > 0) {
282
0
        node->mMeshes = new unsigned int[numMeshes];
283
0
        ReadArray(stream, node->mMeshes, numMeshes);
284
0
        node->mNumMeshes = numMeshes;
285
0
    }
286
287
0
    if (numChildren > 0) {
288
0
        node->mChildren = new aiNode *[numChildren]();
289
0
        for (unsigned int i = 0; i < numChildren; ++i) {
290
0
            ReadBinaryNode(stream, &node->mChildren[i], node.get());
291
0
        }
292
0
        node->mNumChildren = numChildren;
293
0
    }
294
295
0
    if (nb_metadata > 0) {
296
0
        node->mMetaData = aiMetadata::Alloc(nb_metadata);
297
0
        for (unsigned int i = 0; i < nb_metadata; ++i) {
298
0
            node->mMetaData->mKeys[i] = Read<aiString>(stream);
299
0
            node->mMetaData->mValues[i].mType = (aiMetadataType)Read<uint16_t>(stream);
300
0
            void *data = nullptr;
301
302
0
            switch (node->mMetaData->mValues[i].mType) {
303
0
            case AI_BOOL: {
304
0
                data = new bool(Read<bool>(stream));
305
0
                break;
306
0
            }
307
0
            case AI_INT32: {
308
0
                data = new int32_t(Read<int32_t>(stream));
309
0
                break;
310
0
            }
311
0
            case AI_UINT64: {
312
0
                data = new uint64_t(Read<uint64_t>(stream));
313
0
                break;
314
0
            }
315
0
            case AI_FLOAT: {
316
0
                data = new ai_real(Read<ai_real>(stream));
317
0
                break;
318
0
            }
319
0
            case AI_DOUBLE: {
320
0
                data = new double(Read<double>(stream));
321
0
                break;
322
0
            }
323
0
            case AI_AISTRING: {
324
0
                data = new aiString(Read<aiString>(stream));
325
0
                break;
326
0
            }
327
0
            case AI_AIVECTOR3D: {
328
0
                data = new aiVector3D(Read<aiVector3D>(stream));
329
0
                break;
330
0
            }
331
0
#ifndef SWIG
332
0
            case FORCE_32BIT:
333
0
#endif // SWIG
334
0
            default:
335
0
                break;
336
0
            }
337
338
0
            node->mMetaData->mValues[i].mData = data;
339
0
        }
340
0
    }
341
0
    *onode = node.release();
342
0
}
343
344
// -----------------------------------------------------------------------------------
345
0
void AssbinImporter::ReadBinaryBone(IOStream *stream, aiBone *b) {
346
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIBONE)
347
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
348
0
    /*uint32_t size =*/Read<uint32_t>(stream);
349
350
0
    b->mName = Read<aiString>(stream);
351
0
    b->mNumWeights = Read<unsigned int>(stream);
352
0
    b->mOffsetMatrix = Read<aiMatrix4x4>(stream);
353
354
0
    if (b->mNumWeights > AI_MAX_ALLOC(aiVertexWeight) || (size_t)b->mNumWeights > SIZE_MAX / sizeof(aiVertexWeight)) {
355
0
        throw DeadlyImportError("Assbin: Too many weights, would overflow");
356
0
    }
357
358
    // for the moment we write dumb min/max values for the bones, too.
359
    // maybe I'll add a better, hash-like solution later
360
0
    if (shortened) {
361
0
        ReadBounds(stream, b->mWeights, b->mNumWeights);
362
0
    } else {
363
0
        b->mWeights = new aiVertexWeight[b->mNumWeights];
364
0
        ReadArray(stream, b->mWeights, b->mNumWeights);
365
0
    }
366
0
}
367
368
// -----------------------------------------------------------------------------------
369
0
static bool fitsIntoUI16(unsigned int mNumVertices) {
370
0
    return (mNumVertices < (1u << 16));
371
0
}
372
373
// -----------------------------------------------------------------------------------
374
0
void AssbinImporter::ReadBinaryMesh(IOStream *stream, aiMesh *mesh) {
375
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMESH)
376
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
377
0
    /*uint32_t size =*/Read<uint32_t>(stream);
378
379
0
    mesh->mPrimitiveTypes = Read<unsigned int>(stream);
380
0
    mesh->mNumVertices = Read<unsigned int>(stream);
381
0
    mesh->mNumFaces = Read<unsigned int>(stream);
382
0
    mesh->mNumBones = Read<unsigned int>(stream);
383
0
    mesh->mMaterialIndex = Read<unsigned int>(stream);
384
385
0
    if (mesh->mNumVertices > AI_MAX_ALLOC(aiVector3D) || (size_t)mesh->mNumVertices > SIZE_MAX / sizeof(aiVector3D) ||
386
0
        mesh->mNumVertices > AI_MAX_ALLOC(aiColor4D) || (size_t)mesh->mNumVertices > SIZE_MAX / sizeof(aiColor4D)) {
387
0
        throw DeadlyImportError("Assbin: Too many vertices, would overflow");
388
0
    }
389
0
    if (mesh->mNumFaces > AI_MAX_ALLOC(aiFace) || (size_t)mesh->mNumFaces > SIZE_MAX / sizeof(aiFace)) {
390
0
        throw DeadlyImportError("Assbin: Too many faces, would overflow");
391
0
    }
392
0
    if (mesh->mNumBones > AI_MAX_ALLOC(aiBone *) || (size_t)mesh->mNumBones > SIZE_MAX / sizeof(aiBone *)) {
393
0
        throw DeadlyImportError("Assbin: Too many bones, would overflow");
394
0
    }
395
396
    // first of all, write bits for all existent vertex components
397
0
    unsigned int c = Read<unsigned int>(stream);
398
399
0
    if (c & ASSBIN_MESH_HAS_POSITIONS) {
400
0
        if (shortened) {
401
0
            ReadBounds(stream, mesh->mVertices, mesh->mNumVertices);
402
0
        } else {
403
0
            mesh->mVertices = new aiVector3D[mesh->mNumVertices];
404
0
            ReadArray(stream, mesh->mVertices, mesh->mNumVertices);
405
0
        }
406
0
    }
407
0
    if (c & ASSBIN_MESH_HAS_NORMALS) {
408
0
        if (shortened) {
409
0
            ReadBounds(stream, mesh->mNormals, mesh->mNumVertices);
410
0
        } else {
411
0
            mesh->mNormals = new aiVector3D[mesh->mNumVertices];
412
0
            ReadArray(stream, mesh->mNormals, mesh->mNumVertices);
413
0
        }
414
0
    }
415
0
    if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) {
416
0
        if (shortened) {
417
0
            ReadBounds(stream, mesh->mTangents, mesh->mNumVertices);
418
0
            ReadBounds(stream, mesh->mBitangents, mesh->mNumVertices);
419
0
        } else {
420
0
            mesh->mTangents = new aiVector3D[mesh->mNumVertices];
421
0
            ReadArray(stream, mesh->mTangents, mesh->mNumVertices);
422
0
            mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
423
0
            ReadArray(stream, mesh->mBitangents, mesh->mNumVertices);
424
0
        }
425
0
    }
426
0
    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) {
427
0
        if (!(c & ASSBIN_MESH_HAS_COLOR(n))) {
428
0
            break;
429
0
        }
430
431
0
        if (shortened) {
432
0
            ReadBounds(stream, mesh->mColors[n], mesh->mNumVertices);
433
0
        } else {
434
0
            mesh->mColors[n] = new aiColor4D[mesh->mNumVertices];
435
0
            ReadArray(stream, mesh->mColors[n], mesh->mNumVertices);
436
0
        }
437
0
    }
438
0
    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) {
439
0
        if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) {
440
0
            break;
441
0
        }
442
443
        // write number of UV components
444
0
        mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
445
446
0
        if (shortened) {
447
0
            ReadBounds(stream, mesh->mTextureCoords[n], mesh->mNumVertices);
448
0
        } else {
449
0
            mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
450
0
            ReadArray(stream, mesh->mTextureCoords[n], mesh->mNumVertices);
451
0
        }
452
0
    }
453
454
    // write faces. There are no floating-point calculations involved
455
    // in these, so we can write a simple hash over the face data
456
    // to the dump file. We generate a single 32 Bit hash for 512 faces
457
    // using Assimp's standard hashing function.
458
0
    if (shortened) {
459
0
        Read<unsigned int>(stream);
460
0
    } else {
461
        // else write as usual
462
        // if there are less than 2^16 vertices, we can simply use 16 bit integers ...
463
0
        mesh->mFaces = new aiFace[mesh->mNumFaces];
464
0
        for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
465
0
            aiFace &f = mesh->mFaces[i];
466
467
0
            static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
468
0
            f.mNumIndices = Read<uint16_t>(stream);
469
0
            if (f.mNumIndices > AI_MAX_FACE_INDICES) {
470
0
                throw DeadlyImportError("Assbin: Too many face indices, would overflow");
471
0
            }
472
0
            f.mIndices = new unsigned int[f.mNumIndices];
473
474
0
            for (unsigned int a = 0; a < f.mNumIndices; ++a) {
475
                // Check if unsigned  short ( 16 bit  ) are big enough for the indices
476
0
                if (fitsIntoUI16(mesh->mNumVertices)) {
477
0
                    f.mIndices[a] = Read<uint16_t>(stream);
478
0
                } else {
479
0
                    f.mIndices[a] = Read<unsigned int>(stream);
480
0
                }
481
0
            }
482
0
        }
483
0
    }
484
485
    // write bones
486
0
    if (mesh->mNumBones) {
487
0
        mesh->mBones = new C_STRUCT aiBone *[mesh->mNumBones]();
488
0
        for (unsigned int a = 0; a < mesh->mNumBones; ++a) {
489
0
            mesh->mBones[a] = new aiBone();
490
0
            ReadBinaryBone(stream, mesh->mBones[a]);
491
0
        }
492
0
    }
493
0
}
494
495
// -----------------------------------------------------------------------------------
496
0
void AssbinImporter::ReadBinaryMaterialProperty(IOStream *stream, aiMaterialProperty *prop) {
497
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY)
498
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
499
0
    /*uint32_t size =*/Read<uint32_t>(stream);
500
501
0
    prop->mKey = Read<aiString>(stream);
502
0
    prop->mSemantic = Read<unsigned int>(stream);
503
0
    prop->mIndex = Read<unsigned int>(stream);
504
505
0
    prop->mDataLength = Read<unsigned int>(stream);
506
0
    prop->mType = (aiPropertyTypeInfo)Read<unsigned int>(stream);
507
508
0
    if (prop->mDataLength > AI_MAX_ALLOC(char)) {
509
0
        throw DeadlyImportError("Assbin: Material property data too large");
510
0
    }
511
512
0
    prop->mData = new char[prop->mDataLength];
513
0
    if (stream->Read(prop->mData, 1, prop->mDataLength) != prop->mDataLength) {
514
0
        throw DeadlyImportError("ASSBIN: Unexpected EOF reading material property data");
515
0
    }
516
0
}
517
518
// -----------------------------------------------------------------------------------
519
0
void AssbinImporter::ReadBinaryMaterial(IOStream *stream, aiMaterial *mat) {
520
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIAL)
521
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
522
0
    /*uint32_t size =*/Read<uint32_t>(stream);
523
524
0
    mat->mNumAllocated = mat->mNumProperties = Read<unsigned int>(stream);
525
0
    if (mat->mNumProperties) {
526
0
        if (mat->mProperties) {
527
0
            delete[] mat->mProperties;
528
0
        }
529
0
        mat->mProperties = new aiMaterialProperty *[mat->mNumProperties]();
530
0
        for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
531
0
            mat->mProperties[i] = new aiMaterialProperty();
532
0
            ReadBinaryMaterialProperty(stream, mat->mProperties[i]);
533
0
        }
534
0
    }
535
0
}
536
537
// -----------------------------------------------------------------------------------
538
0
void AssbinImporter::ReadBinaryNodeAnim(IOStream *stream, aiNodeAnim *nd) {
539
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODEANIM)
540
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
541
0
    /*uint32_t size =*/Read<uint32_t>(stream);
542
543
0
    nd->mNodeName = Read<aiString>(stream);
544
0
    nd->mNumPositionKeys = Read<unsigned int>(stream);
545
0
    nd->mNumRotationKeys = Read<unsigned int>(stream);
546
0
    nd->mNumScalingKeys = Read<unsigned int>(stream);
547
0
    nd->mPreState = (aiAnimBehaviour)Read<unsigned int>(stream);
548
0
    nd->mPostState = (aiAnimBehaviour)Read<unsigned int>(stream);
549
550
0
    if (nd->mNumPositionKeys > AI_MAX_ALLOC(aiVectorKey) || (size_t)nd->mNumPositionKeys > SIZE_MAX / sizeof(aiVectorKey)) {
551
0
        throw DeadlyImportError("Assbin: Too many position keys, would overflow");
552
0
    }
553
0
    if (nd->mNumRotationKeys > AI_MAX_ALLOC(aiQuatKey) || (size_t)nd->mNumRotationKeys > SIZE_MAX / sizeof(aiQuatKey)) {
554
0
        throw DeadlyImportError("Assbin: Too many rotation keys, would overflow");
555
0
    }
556
0
    if (nd->mNumScalingKeys > AI_MAX_ALLOC(aiVectorKey) || (size_t)nd->mNumScalingKeys > SIZE_MAX / sizeof(aiVectorKey)) {
557
0
        throw DeadlyImportError("Assbin: Too many scaling keys, would overflow");
558
0
    }
559
560
0
    if (nd->mNumPositionKeys) {
561
0
        if (shortened) {
562
0
            ReadBounds(stream, nd->mPositionKeys, nd->mNumPositionKeys);
563
0
        } else {
564
0
            nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys];
565
0
            ReadArray(stream, nd->mPositionKeys, nd->mNumPositionKeys);
566
0
        }
567
0
    }
568
0
    if (nd->mNumRotationKeys) {
569
0
        if (shortened) {
570
0
            ReadBounds(stream, nd->mRotationKeys, nd->mNumRotationKeys);
571
0
        } else {
572
0
            nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
573
0
            ReadArray(stream, nd->mRotationKeys, nd->mNumRotationKeys);
574
0
        }
575
0
    }
576
0
    if (nd->mNumScalingKeys) {
577
0
        if (shortened) {
578
0
            ReadBounds(stream, nd->mScalingKeys, nd->mNumScalingKeys);
579
0
        } else {
580
0
            nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
581
0
            ReadArray(stream, nd->mScalingKeys, nd->mNumScalingKeys);
582
0
        }
583
0
    }
584
0
}
585
586
// -----------------------------------------------------------------------------------
587
0
void AssbinImporter::ReadBinaryAnim(IOStream *stream, aiAnimation *anim) {
588
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AIANIMATION)
589
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
590
0
    /*uint32_t size =*/Read<uint32_t>(stream);
591
592
0
    anim->mName = Read<aiString>(stream);
593
0
    anim->mDuration = Read<double>(stream);
594
0
    anim->mTicksPerSecond = Read<double>(stream);
595
0
    anim->mNumChannels = Read<unsigned int>(stream);
596
597
0
    if (anim->mNumChannels > AI_MAX_ALLOC(aiNodeAnim *) || (size_t)anim->mNumChannels > SIZE_MAX / sizeof(aiNodeAnim *)) {
598
0
        throw DeadlyImportError("Assbin: Too many animation channels, would overflow");
599
0
    }
600
601
0
    if (anim->mNumChannels) {
602
0
        anim->mChannels = new aiNodeAnim *[anim->mNumChannels]();
603
0
        for (unsigned int a = 0; a < anim->mNumChannels; ++a) {
604
0
            anim->mChannels[a] = new aiNodeAnim();
605
0
            ReadBinaryNodeAnim(stream, anim->mChannels[a]);
606
0
        }
607
0
    }
608
0
}
609
610
// -----------------------------------------------------------------------------------
611
0
void AssbinImporter::ReadBinaryTexture(IOStream *stream, aiTexture *tex) {
612
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AITEXTURE) {
613
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
614
0
    }
615
0
    Read<uint32_t>(stream); // size
616
617
0
    tex->mWidth = Read<unsigned int>(stream);
618
0
    tex->mHeight = Read<unsigned int>(stream);
619
0
    ReadBytes(stream, tex->achFormatHint, HINTMAXTEXTURELEN - 1, "texture format hint");
620
621
0
    if (!shortened) {
622
0
        if (!tex->mHeight) {
623
0
            if (tex->mWidth > AI_MAX_ALLOC(aiTexel)) {
624
0
                throw DeadlyImportError("Assbin: Texture width too large, would overflow");
625
0
            }
626
0
            tex->pcData = new aiTexel[tex->mWidth];
627
0
            if (stream->Read(tex->pcData, 1, tex->mWidth) != tex->mWidth) {
628
0
                throw DeadlyImportError("Assbin: Unexpected EOF reading compressed texture data");
629
0
            }
630
0
        } else {
631
0
            if (tex->mWidth != 0 &&
632
0
                static_cast<size_t>(tex->mHeight) >
633
0
                    SIZE_MAX / sizeof(aiTexel) / static_cast<size_t>(tex->mWidth)) {
634
0
                throw DeadlyImportError("Assbin: Texture dimensions too large");
635
0
            }
636
637
0
            const size_t pixelCount = static_cast<size_t>(tex->mWidth) * tex->mHeight;
638
0
            const size_t byteCount = pixelCount * sizeof(aiTexel);
639
0
            tex->pcData = new aiTexel[pixelCount];
640
0
            if (stream->Read(tex->pcData, 1, byteCount) != byteCount) {
641
0
                throw DeadlyImportError("Assbin: Unexpected EOF reading texture data");
642
0
            }
643
0
        }
644
0
    }
645
0
}
646
647
// -----------------------------------------------------------------------------------
648
0
void AssbinImporter::ReadBinaryLight(IOStream *stream, aiLight *l) {
649
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AILIGHT)
650
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
651
0
    /*uint32_t size =*/Read<uint32_t>(stream);
652
653
0
    l->mName = Read<aiString>(stream);
654
0
    l->mType = (aiLightSourceType)Read<unsigned int>(stream);
655
656
0
    l->mPosition = Read<aiVector3D>(stream);
657
0
    l->mDirection = Read<aiVector3D>(stream);
658
0
    l->mUp = Read<aiVector3D>(stream);
659
660
0
    if (l->mType != aiLightSource_DIRECTIONAL) {
661
0
        l->mAttenuationConstant = Read<float>(stream);
662
0
        l->mAttenuationLinear = Read<float>(stream);
663
0
        l->mAttenuationQuadratic = Read<float>(stream);
664
0
    }
665
666
0
    l->mColorDiffuse = Read<aiColor3D>(stream);
667
0
    l->mColorSpecular = Read<aiColor3D>(stream);
668
0
    l->mColorAmbient = Read<aiColor3D>(stream);
669
670
0
    if (l->mType == aiLightSource_SPOT) {
671
0
        l->mAngleInnerCone = Read<float>(stream);
672
0
        l->mAngleOuterCone = Read<float>(stream);
673
0
    }
674
0
}
675
676
// -----------------------------------------------------------------------------------
677
0
void AssbinImporter::ReadBinaryCamera(IOStream *stream, aiCamera *cam) {
678
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AICAMERA)
679
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
680
0
    /*uint32_t size =*/Read<uint32_t>(stream);
681
682
0
    cam->mName = Read<aiString>(stream);
683
0
    cam->mPosition = Read<aiVector3D>(stream);
684
0
    cam->mLookAt = Read<aiVector3D>(stream);
685
0
    cam->mUp = Read<aiVector3D>(stream);
686
0
    cam->mHorizontalFOV = Read<float>(stream);
687
0
    cam->mClipPlaneNear = Read<float>(stream);
688
0
    cam->mClipPlaneFar = Read<float>(stream);
689
0
    cam->mAspect = Read<float>(stream);
690
0
}
691
692
// -----------------------------------------------------------------------------------
693
0
void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) {
694
0
    if (Read<uint32_t>(stream) != ASSBIN_CHUNK_AISCENE)
695
0
        throw DeadlyImportError("Magic chunk identifiers are wrong!");
696
0
    /*uint32_t size =*/Read<uint32_t>(stream);
697
698
0
    scene->mFlags = Read<unsigned int>(stream);
699
0
    scene->mNumMeshes = Read<unsigned int>(stream);
700
0
    scene->mNumMaterials = Read<unsigned int>(stream);
701
0
    scene->mNumAnimations = Read<unsigned int>(stream);
702
0
    scene->mNumTextures = Read<unsigned int>(stream);
703
0
    scene->mNumLights = Read<unsigned int>(stream);
704
0
    scene->mNumCameras = Read<unsigned int>(stream);
705
706
    // Read node graph
707
    //scene->mRootNode = new aiNode[1];
708
0
    ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)nullptr);
709
710
    // Read all meshes
711
0
    if (scene->mNumMeshes) {
712
0
        scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
713
0
        for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
714
0
            scene->mMeshes[i] = new aiMesh();
715
0
            ReadBinaryMesh(stream, scene->mMeshes[i]);
716
0
        }
717
0
    }
718
719
    // Read materials
720
0
    if (scene->mNumMaterials) {
721
0
        scene->mMaterials = new aiMaterial *[scene->mNumMaterials]();
722
0
        for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
723
0
            scene->mMaterials[i] = new aiMaterial();
724
0
            ReadBinaryMaterial(stream, scene->mMaterials[i]);
725
0
        }
726
0
    }
727
728
    // Read all animations
729
0
    if (scene->mNumAnimations) {
730
0
        scene->mAnimations = new aiAnimation *[scene->mNumAnimations]();
731
0
        for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
732
0
            scene->mAnimations[i] = new aiAnimation();
733
0
            ReadBinaryAnim(stream, scene->mAnimations[i]);
734
0
        }
735
0
    }
736
737
    // Read all textures
738
0
    if (scene->mNumTextures) {
739
0
        scene->mTextures = new aiTexture *[scene->mNumTextures]();
740
0
        for (unsigned int i = 0; i < scene->mNumTextures; ++i) {
741
0
            scene->mTextures[i] = new aiTexture();
742
0
            ReadBinaryTexture(stream, scene->mTextures[i]);
743
0
        }
744
0
    }
745
746
    // Read lights
747
0
    if (scene->mNumLights) {
748
0
        scene->mLights = new aiLight *[scene->mNumLights]();
749
0
        for (unsigned int i = 0; i < scene->mNumLights; ++i) {
750
0
            scene->mLights[i] = new aiLight();
751
0
            ReadBinaryLight(stream, scene->mLights[i]);
752
0
        }
753
0
    }
754
755
    // Read cameras
756
0
    if (scene->mNumCameras) {
757
0
        scene->mCameras = new aiCamera *[scene->mNumCameras]();
758
0
        for (unsigned int i = 0; i < scene->mNumCameras; ++i) {
759
0
            scene->mCameras[i] = new aiCamera();
760
0
            ReadBinaryCamera(stream, scene->mCameras[i]);
761
0
        }
762
0
    }
763
0
}
764
765
// -----------------------------------------------------------------------------------
766
0
void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
767
0
    struct IOStreamDeleter {
768
0
        IOSystem* io;
769
0
        void operator()(IOStream* s) const {
770
0
            if (s) {
771
0
                io->Close(s);
772
0
            }
773
0
        }
774
0
    };
775
776
0
    auto stream = std::unique_ptr<IOStream, IOStreamDeleter>(
777
0
        pIOHandler->Open(pFile, "rb"),
778
0
        IOStreamDeleter{pIOHandler}
779
0
    );
780
0
    if (nullptr == stream) {
781
0
        throw DeadlyImportError("ASSBIN: Could not open ", pFile);
782
0
    }
783
784
    // signature
785
0
    stream->Seek(44, aiOrigin_CUR);
786
787
0
    unsigned int versionMajor = Read<unsigned int>(stream.get());
788
0
    unsigned int versionMinor = Read<unsigned int>(stream.get());
789
0
    if (versionMinor != ASSBIN_VERSION_MINOR || versionMajor != ASSBIN_VERSION_MAJOR) {
790
0
        throw DeadlyImportError("Invalid version, data format not compatible!");
791
0
    }
792
793
0
    /*unsigned int versionRevision =*/Read<unsigned int>(stream.get());
794
0
    /*unsigned int compileFlags =*/Read<unsigned int>(stream.get());
795
796
0
    shortened = Read<uint16_t>(stream.get()) > 0;
797
0
    compressed = Read<uint16_t>(stream.get()) > 0;
798
799
0
    if (shortened) {
800
0
        throw DeadlyImportError("Shortened binaries are not supported!");
801
0
    }
802
803
0
    stream->Seek(256, aiOrigin_CUR); // original filename
804
0
    stream->Seek(128, aiOrigin_CUR); // options
805
0
    stream->Seek(64, aiOrigin_CUR); // padding
806
807
0
    if (compressed) {
808
0
        uLongf uncompressedSize = Read<uint32_t>(stream.get());
809
0
        uLongf compressedSize = static_cast<uLongf>(stream->FileSize() - stream->Tell());
810
811
0
        std::vector<unsigned char> compressedData(compressedSize);
812
0
        const size_t len = stream->Read(compressedData.data(), 1, compressedSize);
813
0
        if (len != compressedSize) {
814
0
            throw DeadlyImportError("ASSBIN: Unexpected EOF while reading compressed data");
815
0
        }
816
817
0
        std::vector<unsigned char> uncompressedData(uncompressedSize);
818
0
        const int res = uncompress(uncompressedData.data(), &uncompressedSize, compressedData.data(), (uLong)len);
819
0
        if (res != Z_OK) {
820
0
            throw DeadlyImportError("Zlib decompression failed.");
821
0
        }
822
823
0
        MemoryIOStream io(uncompressedData.data(), uncompressedSize);
824
825
0
        ReadBinaryScene(&io, pScene);
826
0
    } else {
827
0
        ReadBinaryScene(stream.get(), pScene);
828
0
    }
829
0
}
830
#endif // !! ASSIMP_BUILD_NO_ASSBIN_IMPORTER