Coverage Report

Created: 2026-05-04 07:03

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